Agile Modbus 1.1.1
Lightweight modbus protocol stack.
agile_modbus.c
浏览该文件的文档.
1
39#include "agile_modbus.h"
40#include <string.h>
41
49#define AGILE_MODBUS_MSG_LENGTH_UNDEFINED -1
89{
90 int length;
91
92 if (msg_type == AGILE_MODBUS_MSG_INDICATION) {
94 length = 4;
95 } else if (function == AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS ||
97 length = 5;
98 } else if (function == AGILE_MODBUS_FC_MASK_WRITE_REGISTER) {
99 length = 6;
100 } else if (function == AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS) {
101 length = 9;
102 } else {
103 /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */
104 length = 0;
106 length = ctx->compute_meta_length_after_function(ctx, function, msg_type);
107 }
108 } else {
109 /* MSG_CONFIRMATION */
110 switch (function) {
117 length = 1;
118 break;
119
124 length = 4;
125 break;
126
128 length = 6;
129 break;
130
131 default:
132 length = 1;
134 length = ctx->compute_meta_length_after_function(ctx, function, msg_type);
135 }
136 }
137
138 return length;
139}
140
177static int agile_modbus_compute_data_length_after_meta(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
178{
179 int function = msg[ctx->backend->header_length];
180 int length;
181
182 if (msg_type == AGILE_MODBUS_MSG_INDICATION) {
183 switch (function) {
186 length = msg[ctx->backend->header_length + 5];
187 break;
188
190 length = msg[ctx->backend->header_length + 9];
191 break;
192
193 default:
194 length = 0;
196 length = ctx->compute_data_length_after_meta(ctx, msg, msg_length, msg_type);
197 }
198 } else {
199 /* MSG_CONFIRMATION */
200 if (function <= AGILE_MODBUS_FC_READ_INPUT_REGISTERS ||
203 length = msg[ctx->backend->header_length + 1];
204 } else {
205 length = 0;
207 length = ctx->compute_data_length_after_meta(ctx, msg, msg_length, msg_type);
208 }
209 }
210
211 length += ctx->backend->checksum_length;
212
213 return length;
214}
215
224static int agile_modbus_receive_msg_judge(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
225{
226 int remain_len = msg_length;
227
228 remain_len -= (ctx->backend->header_length + 1);
229 if (remain_len < 0)
230 return -1;
231 remain_len -= agile_modbus_compute_meta_length_after_function(ctx, msg[ctx->backend->header_length], msg_type);
232 if (remain_len < 0)
233 return -1;
234 remain_len -= agile_modbus_compute_data_length_after_meta(ctx, msg, msg_length, msg_type);
235 if (remain_len < 0)
236 return -1;
237
238 return ctx->backend->check_integrity(ctx, msg, msg_length - remain_len);
239}
240
257void agile_modbus_common_init(agile_modbus_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz)
258{
259 memset(ctx, 0, sizeof(agile_modbus_t));
260 ctx->slave = -1;
261 ctx->send_buf = send_buf;
262 ctx->send_bufsz = send_bufsz;
263 ctx->read_buf = read_buf;
264 ctx->read_bufsz = read_bufsz;
265}
266
274{
275 return ctx->backend->set_slave(ctx, slave);
276}
277
285 uint8_t (*cb)(agile_modbus_t *ctx, int function,
286 agile_modbus_msg_type_t msg_type))
287{
289}
290
298 int (*cb)(agile_modbus_t *ctx, uint8_t *msg,
299 int msg_length, agile_modbus_msg_type_t msg_type))
300{
302}
303
313{
314 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
315 return -1;
316
317 int rc = agile_modbus_receive_msg_judge(ctx, ctx->read_buf, msg_length, msg_type);
318
319 return rc;
320}
321
343{
344 int length;
345 const int offset = ctx->backend->header_length;
346
347 switch (req[offset]) {
350 /* Header + nb values (code from write_bits) */
351 int nb = (req[offset + 3] << 8) | req[offset + 4];
352 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
353 } break;
354
358 /* Header + 2 * nb values */
359 length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
360 break;
361
366 length = 5;
367 break;
368
370 length = 7;
371 break;
372
373 default:
374 /* The response is device specific (the header provides the
375 length) */
377 }
378
379 return offset + length + ctx->backend->checksum_length;
380}
381
392 uint8_t *rsp, int rsp_length)
393{
394 int rc;
395 int rsp_length_computed;
396 const int offset = ctx->backend->header_length;
397 const int function = rsp[offset];
398
400 rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length);
401 if (rc < 0)
402 return -1;
403 }
404
405 rsp_length_computed = agile_modbus_compute_response_length_from_request(ctx, req);
406
407 /* Exception code */
408 if (function >= 0x80) {
409 if (rsp_length == (offset + 2 + (int)ctx->backend->checksum_length) && req[offset] == (rsp[offset] - 0x80))
410 return (-128 - rsp[offset + 1]);
411 else
412 return -1;
413 }
414
415 /* Check length */
416 if ((rsp_length == rsp_length_computed || rsp_length_computed == AGILE_MODBUS_MSG_LENGTH_UNDEFINED) && function < 0x80) {
417 int req_nb_value;
418 int rsp_nb_value;
419
420 /* Check function code */
421 if (function != req[offset])
422 return -1;
423
424 /* Check the number of values is corresponding to the request */
425 switch (function) {
428 /* Read functions, 8 values in a byte (nb
429 * of values in the request and byte count in
430 * the response. */
431 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
432 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
433 rsp_nb_value = rsp[offset + 1];
434 break;
435
439 /* Read functions 1 value = 2 bytes */
440 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
441 rsp_nb_value = (rsp[offset + 1] / 2);
442 break;
443
446 /* N Write functions */
447 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
448 rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
449 break;
450
452 /* Report slave ID (bytes received) */
453 req_nb_value = rsp_nb_value = rsp[offset + 1];
454 break;
455
456 default:
457 /* 1 Write functions & others */
458 req_nb_value = rsp_nb_value = 1;
459 }
460
461 if (req_nb_value == rsp_nb_value)
462 rc = rsp_nb_value;
463 else
464 rc = -1;
465 } else
466 rc = -1;
467
468 return rc;
469}
470
494{
495 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
496 if (ctx->send_bufsz < min_req_length)
497 return -1;
498
500 return -1;
501
502 int req_length = 0;
503 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_COILS, addr, nb, ctx->send_buf);
504 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
505
506 return req_length;
507}
508
509int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
510{
511 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
512 if (ctx->send_bufsz < min_req_length)
513 return -1;
514 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
515 return -1;
516
518 if (rc < 0)
519 return -1;
520
521 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
522 if (rc < 0)
523 return rc;
524
525 int i, temp, bit;
526 int pos = 0;
527 int offset;
528 int offset_end;
529 int nb;
530
531 offset = ctx->backend->header_length + 2;
532 offset_end = offset + rc;
533 nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4];
534
535 for (i = offset; i < offset_end; i++) {
536 /* Shift reg hi_byte to temp */
537 temp = ctx->read_buf[i];
538
539 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
540 dest[pos++] = (temp & bit) ? 1 : 0;
541 bit = bit << 1;
542 }
543 }
544
545 return nb;
546}
547
549{
550 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
551 if (ctx->send_bufsz < min_req_length)
552 return -1;
553
555 return -1;
556
557 int req_length = 0;
558 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, ctx->send_buf);
559 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
560
561 return req_length;
562}
563
564int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
565{
566 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
567 if (ctx->send_bufsz < min_req_length)
568 return -1;
569 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
570 return -1;
571
573 if (rc < 0)
574 return -1;
575
576 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
577 if (rc < 0)
578 return rc;
579
580 int i, temp, bit;
581 int pos = 0;
582 int offset;
583 int offset_end;
584 int nb;
585
586 offset = ctx->backend->header_length + 2;
587 offset_end = offset + rc;
588 nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4];
589
590 for (i = offset; i < offset_end; i++) {
591 /* Shift reg hi_byte to temp */
592 temp = ctx->read_buf[i];
593
594 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
595 dest[pos++] = (temp & bit) ? 1 : 0;
596 bit = bit << 1;
597 }
598 }
599
600 return nb;
601}
602
604{
605 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
606 if (ctx->send_bufsz < min_req_length)
607 return -1;
608
610 return -1;
611
612 int req_length = 0;
613 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_HOLDING_REGISTERS, addr, nb, ctx->send_buf);
614 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
615
616 return req_length;
617}
618
619int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
620{
621 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
622 if (ctx->send_bufsz < min_req_length)
623 return -1;
624 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
625 return -1;
626
628 if (rc < 0)
629 return -1;
630
631 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
632 if (rc < 0)
633 return rc;
634
635 int offset;
636 int i;
637
638 offset = ctx->backend->header_length;
639 for (i = 0; i < rc; i++) {
640 /* shift reg hi_byte to temp OR with lo_byte */
641 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
642 }
643
644 return rc;
645}
646
648{
649 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
650 if (ctx->send_bufsz < min_req_length)
651 return -1;
652
654 return -1;
655
656 int req_length = 0;
657 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_INPUT_REGISTERS, addr, nb, ctx->send_buf);
658 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
659
660 return req_length;
661}
662
663int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
664{
665 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
666 if (ctx->send_bufsz < min_req_length)
667 return -1;
668 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
669 return -1;
670
672 if (rc < 0)
673 return -1;
674
675 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
676 if (rc < 0)
677 return rc;
678
679 int offset;
680 int i;
681
682 offset = ctx->backend->header_length;
683 for (i = 0; i < rc; i++) {
684 /* shift reg hi_byte to temp OR with lo_byte */
685 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
686 }
687
688 return rc;
689}
690
692{
693 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
694 if (ctx->send_bufsz < min_req_length)
695 return -1;
696
697 int req_length = 0;
698 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_COIL, addr, status ? 0xFF00 : 0, ctx->send_buf);
699 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
700
701 return req_length;
702}
703
705{
706 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
707 if (ctx->send_bufsz < min_req_length)
708 return -1;
709 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
710 return -1;
711
713 if (rc < 0)
714 return -1;
715
716 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
717
718 return rc;
719}
720
721int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value)
722{
723 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
724 if (ctx->send_bufsz < min_req_length)
725 return -1;
726
727 int req_length = 0;
728 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER, addr, (int)value, ctx->send_buf);
729 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
730
731 return req_length;
732}
733
735{
736 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
737 if (ctx->send_bufsz < min_req_length)
738 return -1;
739 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
740 return -1;
741
743 if (rc < 0)
744 return -1;
745
746 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
747
748 return rc;
749}
750
751int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src)
752{
753 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
754 if (ctx->send_bufsz < min_req_length)
755 return -1;
756
758 return -1;
759
760 int i;
761 int byte_count;
762 int req_length;
763 int bit_check = 0;
764 int pos = 0;
765
766 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS, addr, nb, ctx->send_buf);
767 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
768
769 min_req_length += (1 + byte_count);
770 if (ctx->send_bufsz < min_req_length)
771 return -1;
772
773 ctx->send_buf[req_length++] = byte_count;
774 for (i = 0; i < byte_count; i++) {
775 int bit;
776
777 bit = 0x01;
778 ctx->send_buf[req_length] = 0;
779
780 while ((bit & 0xFF) && (bit_check++ < nb)) {
781 if (src[pos++])
782 ctx->send_buf[req_length] |= bit;
783 else
784 ctx->send_buf[req_length] &= ~bit;
785
786 bit = bit << 1;
787 }
788 req_length++;
789 }
790
791 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
792
793 return req_length;
794}
795
797{
798 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
799 if (ctx->send_bufsz < min_req_length)
800 return -1;
801 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
802 return -1;
803
805 if (rc < 0)
806 return -1;
807
808 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
809
810 return rc;
811}
812
813int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src)
814{
815 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
816 if (ctx->send_bufsz < min_req_length)
817 return -1;
818
820 return -1;
821
822 int i;
823 int req_length;
824 int byte_count;
825
826 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS, addr, nb, ctx->send_buf);
827 byte_count = nb * 2;
828
829 min_req_length += (1 + byte_count);
830 if (ctx->send_bufsz < min_req_length)
831 return -1;
832
833 ctx->send_buf[req_length++] = byte_count;
834 for (i = 0; i < nb; i++) {
835 ctx->send_buf[req_length++] = src[i] >> 8;
836 ctx->send_buf[req_length++] = src[i] & 0x00FF;
837 }
838
839 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
840
841 return req_length;
842}
843
845{
846 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
847 if (ctx->send_bufsz < min_req_length)
848 return -1;
849 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
850 return -1;
851
853 if (rc < 0)
854 return -1;
855
856 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
857
858 return rc;
859}
860
861int agile_modbus_serialize_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
862{
863 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length + 2;
864 if (ctx->send_bufsz < min_req_length)
865 return -1;
866
867 int req_length = 0;
868 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_MASK_WRITE_REGISTER, addr, 0, ctx->send_buf);
869
870 /* HACKISH, count is not used */
871 req_length -= 2;
872
873 ctx->send_buf[req_length++] = and_mask >> 8;
874 ctx->send_buf[req_length++] = and_mask & 0x00ff;
875 ctx->send_buf[req_length++] = or_mask >> 8;
876 ctx->send_buf[req_length++] = or_mask & 0x00ff;
877
878 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
879
880 return req_length;
881}
882
884{
885 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
886 if (ctx->send_bufsz < min_req_length)
887 return -1;
888 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
889 return -1;
890
892 if (rc < 0)
893 return -1;
894
895 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
896
897 return rc;
898}
899
901 int write_addr, int write_nb,
902 const uint16_t *src,
903 int read_addr, int read_nb)
904{
905 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
906 if (ctx->send_bufsz < min_req_length)
907 return -1;
908
910 return -1;
911
913 return -1;
914
915 int req_length;
916 int i;
917 int byte_count;
918
919 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS, read_addr, read_nb, ctx->send_buf);
920 byte_count = write_nb * 2;
921
922 min_req_length += (5 + byte_count);
923 if (ctx->send_bufsz < min_req_length)
924 return -1;
925
926 ctx->send_buf[req_length++] = write_addr >> 8;
927 ctx->send_buf[req_length++] = write_addr & 0x00ff;
928 ctx->send_buf[req_length++] = write_nb >> 8;
929 ctx->send_buf[req_length++] = write_nb & 0x00ff;
930 ctx->send_buf[req_length++] = byte_count;
931 for (i = 0; i < write_nb; i++) {
932 ctx->send_buf[req_length++] = src[i] >> 8;
933 ctx->send_buf[req_length++] = src[i] & 0x00FF;
934 }
935
936 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
937
938 return req_length;
939}
940
942{
943 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
944 if (ctx->send_bufsz < min_req_length)
945 return -1;
946 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
947 return -1;
948
950 if (rc < 0)
951 return -1;
952
953 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
954 if (rc < 0)
955 return rc;
956
957 int offset;
958 int i;
959
960 offset = ctx->backend->header_length;
961 for (i = 0; i < rc; i++) {
962 /* shift reg hi_byte to temp OR with lo_byte */
963 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
964 }
965
966 return rc;
967}
968
970{
971 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
972 if (ctx->send_bufsz < min_req_length)
973 return -1;
974
975 int req_length = 0;
976 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_REPORT_SLAVE_ID, 0, 0, ctx->send_buf);
977 /* HACKISH, addr and count are not used */
978 req_length -= 4;
979 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
980
981 return req_length;
982}
983
984int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest)
985{
986 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
987 if (ctx->send_bufsz < min_req_length)
988 return -1;
989 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
990 return -1;
991 if (max_dest <= 0)
992 return -1;
993
995 if (rc < 0)
996 return -1;
997
998 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
999 if (rc < 0)
1000 return rc;
1001
1002 int i;
1003 int offset;
1004
1005 offset = ctx->backend->header_length + 2;
1006
1007 /* Byte count, slave id, run indicator status and
1008 additional data. Truncate copy to max_dest. */
1009 for (i = 0; i < rc && i < max_dest; i++) {
1010 dest[i] = ctx->read_buf[offset + i];
1011 }
1012
1013 return rc;
1014}
1015
1031int agile_modbus_serialize_raw_request(agile_modbus_t *ctx, const uint8_t *raw_req, int raw_req_length)
1032{
1033 if (raw_req_length < 2) {
1034 /* The raw request must contain function and slave at least and
1035 must not be longer than the maximum pdu length plus the slave
1036 address. */
1037
1038 return -1;
1039 }
1040
1041 int min_req_length = ctx->backend->header_length + 1 + ctx->backend->checksum_length + raw_req_length - 2;
1042 if (ctx->send_bufsz < min_req_length)
1043 return -1;
1044
1046 int req_length;
1047
1048 sft.slave = raw_req[0];
1049 sft.function = raw_req[1];
1050 /* The t_id is left to zero */
1051 sft.t_id = 0;
1052 /* This response function only set the header so it's convenient here */
1053 req_length = ctx->backend->build_response_basis(&sft, ctx->send_buf);
1054
1055 if (raw_req_length > 2) {
1056 /* Copy data after function code */
1057 memcpy(ctx->send_buf + req_length, raw_req + 2, raw_req_length - 2);
1058 req_length += raw_req_length - 2;
1059 }
1060
1061 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
1062
1063 return req_length;
1064}
1065
1074{
1075 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
1076 if (ctx->send_bufsz < min_req_length)
1077 return -1;
1078 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
1079 return -1;
1080
1082 if (rc < 0)
1083 return -1;
1084
1085 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
1086
1087 return rc;
1088}
1089
1114{
1115 int rsp_length;
1116
1117 /* Build exception response */
1118 sft->function = sft->function + 0x80;
1119 rsp_length = ctx->backend->build_response_basis(sft, ctx->send_buf);
1120 ctx->send_buf[rsp_length++] = exception_code;
1121
1122 return rsp_length;
1123}
1124
1139void agile_modbus_slave_io_set(uint8_t *buf, int index, int status)
1140{
1141 int offset = index / 8;
1142 int shift = index % 8;
1143
1144 if (status)
1145 buf[offset] |= (0x01 << shift);
1146 else
1147 buf[offset] &= ~(0x01 << shift);
1148}
1149
1156uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index)
1157{
1158 int offset = index / 8;
1159 int shift = index % 8;
1160
1161 uint8_t status = (buf[offset] & (0x01 << shift)) ? 1 : 0;
1162
1163 return status;
1164}
1165
1172void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data)
1173{
1174 buf[index * 2] = data >> 8;
1175 buf[index * 2 + 1] = data & 0xFF;
1176}
1177
1184uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index)
1185{
1186 uint16_t data = (buf[index * 2] << 8) + buf[index * 2 + 1];
1187
1188 return data;
1189}
1190
1202int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict,
1203 agile_modbus_slave_callback_t slave_cb, int *frame_length)
1204{
1205 int min_rsp_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
1206 if (ctx->send_bufsz < min_rsp_length)
1207 return -1;
1208
1209 int req_length = agile_modbus_receive_judge(ctx, msg_length, AGILE_MODBUS_MSG_INDICATION);
1210 if (req_length < 0)
1211 return -1;
1212 if (frame_length)
1213 *frame_length = req_length;
1214
1215 int offset;
1216 int slave;
1217 int function;
1218 uint16_t address;
1219 int rsp_length = 0;
1220 int exception_code = 0;
1222 uint8_t *req = ctx->read_buf;
1223 uint8_t *rsp = ctx->send_buf;
1224
1225 memset(rsp, 0, ctx->send_bufsz);
1226 offset = ctx->backend->header_length;
1227 slave = req[offset - 1];
1228 function = req[offset];
1229 address = (req[offset + 1] << 8) + req[offset + 2];
1230
1231 sft.slave = slave;
1232 sft.function = function;
1233 sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
1234
1235 struct agile_modbus_slave_info slave_info = {0};
1236 slave_info.sft = &sft;
1237 slave_info.rsp_length = &rsp_length;
1238 slave_info.address = address;
1239
1240 if (slave_strict) {
1241 if ((slave != ctx->slave) && (slave != AGILE_MODBUS_BROADCAST_ADDRESS))
1242 return 0;
1243 }
1244
1245 switch (function) {
1248 int nb = (req[offset + 3] << 8) + req[offset + 4];
1249 if (nb < 1 || AGILE_MODBUS_MAX_READ_BITS < nb) {
1251 break;
1252 }
1253
1254 int end_address = (int)address + nb - 1;
1255 if (end_address > 0xFFFF) {
1257 break;
1258 }
1259
1261 slave_info.nb = (nb / 8) + ((nb % 8) ? 1 : 0);
1262 rsp[rsp_length++] = slave_info.nb;
1263 slave_info.send_index = rsp_length;
1264 rsp_length += slave_info.nb;
1265 slave_info.nb = nb;
1266 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1268 break;
1269 }
1270 } break;
1271
1274 int nb = (req[offset + 3] << 8) + req[offset + 4];
1275 if (nb < 1 || AGILE_MODBUS_MAX_READ_REGISTERS < nb) {
1277 break;
1278 }
1279
1280 int end_address = (int)address + nb - 1;
1281 if (end_address > 0xFFFF) {
1283 break;
1284 }
1285
1287 slave_info.nb = nb << 1;
1288 rsp[rsp_length++] = slave_info.nb;
1289 slave_info.send_index = rsp_length;
1290 rsp_length += slave_info.nb;
1291 slave_info.nb = nb;
1292 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1294 break;
1295 }
1296 } break;
1297
1299 if (address > 0xFFFF) {
1301 break;
1302 }
1303
1304 int data = (req[offset + 3] << 8) + req[offset + 4];
1305 if (data == 0xFF00 || data == 0x0)
1306 data = data ? 1 : 0;
1307 else {
1309 break;
1310 }
1311
1312 slave_info.buf = (uint8_t *)&data;
1313 rsp_length = req_length;
1314 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1316 break;
1317 }
1318 memcpy(rsp, req, req_length);
1319 } break;
1320
1322 if (address > 0xFFFF) {
1324 break;
1325 }
1326
1327 int data = (req[offset + 3] << 8) + req[offset + 4];
1328
1329 slave_info.buf = (uint8_t *)&data;
1330 rsp_length = req_length;
1331 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1333 break;
1334 }
1335 memcpy(rsp, req, req_length);
1336 } break;
1337
1339 int nb = (req[offset + 3] << 8) + req[offset + 4];
1340 int nb_bits = req[offset + 5];
1341 if (nb < 1 || AGILE_MODBUS_MAX_WRITE_BITS < nb || nb_bits * 8 < nb) {
1343 break;
1344 }
1345
1346 int end_address = (int)address + nb - 1;
1347 if (end_address > 0xFFFF) {
1349 break;
1350 }
1351
1353 slave_info.nb = nb;
1354 slave_info.buf = &req[offset + 6];
1355 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length + 4)) {
1357 break;
1358 }
1359 /* 4 to copy the bit address (2) and the quantity of bits */
1360 memcpy(rsp + rsp_length, req + rsp_length, 4);
1361 rsp_length += 4;
1362 } break;
1363
1365 int nb = (req[offset + 3] << 8) + req[offset + 4];
1366 int nb_bytes = req[offset + 5];
1367 if (nb < 1 || AGILE_MODBUS_MAX_WRITE_REGISTERS < nb || nb_bytes != nb * 2) {
1369 break;
1370 }
1371
1372 int end_address = (int)address + nb - 1;
1373 if (end_address > 0xFFFF) {
1375 break;
1376 }
1377
1379 slave_info.nb = nb;
1380 slave_info.buf = &req[offset + 6];
1381 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length + 4)) {
1383 break;
1384 }
1385 /* 4 to copy the address (2) and the no. of registers */
1386 memcpy(rsp + rsp_length, req + rsp_length, 4);
1387 rsp_length += 4;
1388
1389 } break;
1390
1392 int str_len;
1393 int byte_count_pos;
1394
1395 slave_cb = NULL;
1397 /* Skip byte count for now */
1398 byte_count_pos = rsp_length++;
1399 rsp[rsp_length++] = ctx->slave;
1400 /* Run indicator status to ON */
1401 rsp[rsp_length++] = 0xFF;
1402
1403 str_len = strlen(AGILE_MODBUS_VERSION_STRING);
1404 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length + str_len)) {
1406 break;
1407 }
1408 memcpy(rsp + rsp_length, AGILE_MODBUS_VERSION_STRING, str_len);
1409 rsp_length += str_len;
1410 rsp[byte_count_pos] = rsp_length - byte_count_pos - 1;
1411 } break;
1412
1415 break;
1416
1418 if (address > 0xFFFF) {
1420 break;
1421 }
1422
1423 slave_info.buf = &req[offset + 3];
1424 rsp_length = req_length;
1425 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1427 break;
1428 }
1429 memcpy(rsp, req, req_length);
1430 } break;
1431
1433 int nb = (req[offset + 3] << 8) + req[offset + 4];
1434 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
1435 int nb_write = (req[offset + 7] << 8) + req[offset + 8];
1436 int nb_write_bytes = req[offset + 9];
1437 if (nb_write < 1 || AGILE_MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
1439 nb_write_bytes != nb_write * 2) {
1441 break;
1442 }
1443
1444 int end_address = (int)address + nb - 1;
1445 int end_address_write = (int)address_write + nb_write - 1;
1446 if (end_address > 0xFFFF || end_address_write > 0xFFFF) {
1448 break;
1449 }
1450
1452 rsp[rsp_length++] = nb << 1;
1453 slave_info.buf = &req[offset + 3];
1454 slave_info.send_index = rsp_length;
1455 rsp_length += (nb << 1);
1456 if (ctx->send_bufsz < (rsp_length + ctx->backend->checksum_length)) {
1458 break;
1459 }
1460 } break;
1461
1462 default: {
1463 if (slave_cb == NULL)
1465 else {
1467 slave_info.send_index = rsp_length;
1468 slave_info.buf = &req[offset + 1];
1469 slave_info.nb = req_length - offset - 1;
1470 }
1471 } break;
1472 }
1473
1474 if (exception_code)
1476 else {
1477 if (slave_cb) {
1478 int ret = slave_cb(ctx, &slave_info);
1479
1480 if (ret < 0) {
1482 rsp_length = 0;
1483 else
1485 }
1486 }
1487 }
1488
1489 if (rsp_length) {
1491 return 0;
1492
1494 }
1495
1496 return rsp_length;
1497}
1498
Agile Modbus 软件包通用头文件
void agile_modbus_set_compute_data_length_after_meta_cb(agile_modbus_t *ctx, int(*cb)(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type))
设置 modbus 对象的计算数据元之后要接收的数据长度回调函数
Definition: agile_modbus.c:297
void agile_modbus_common_init(agile_modbus_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz)
初始化 modbus 句柄
Definition: agile_modbus.c:257
int agile_modbus_receive_judge(agile_modbus_t *ctx, int msg_length, agile_modbus_msg_type_t msg_type)
校验接收数据正确性
Definition: agile_modbus.c:312
int agile_modbus_set_slave(agile_modbus_t *ctx, int slave)
设置地址
Definition: agile_modbus.c:273
void agile_modbus_set_compute_meta_length_after_function_cb(agile_modbus_t *ctx, uint8_t(*cb)(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type))
设置 modbus 对象的计算功能码后要接收的数据元长度回调函数
Definition: agile_modbus.c:284
agile_modbus_msg_type_t
Modbus 收到消息类型
Definition: agile_modbus.h:165
@ AGILE_MODBUS_EXCEPTION_UNKNOW
Definition: agile_modbus.h:144
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION
Definition: agile_modbus.h:133
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE
Definition: agile_modbus.h:135
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS
Definition: agile_modbus.h:134
@ AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE
Definition: agile_modbus.h:139
@ AGILE_MODBUS_BACKEND_TYPE_RTU
RTU
Definition: agile_modbus.h:151
@ AGILE_MODBUS_MSG_CONFIRMATION
服务器端的请求消息
Definition: agile_modbus.h:167
@ AGILE_MODBUS_MSG_INDICATION
主机端的请求消息
Definition: agile_modbus.h:166
#define AGILE_MODBUS_MSG_LENGTH_UNDEFINED
对应功能码数据长度未定义
Definition: agile_modbus.c:49
static int agile_modbus_receive_msg_judge(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
检验接收数据正确性
Definition: agile_modbus.c:224
static uint8_t agile_modbus_compute_meta_length_after_function(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type)
计算功能码后要接收的数据元长度
Definition: agile_modbus.c:88
static int agile_modbus_compute_data_length_after_meta(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
计算数据元之后要接收的数据长度
Definition: agile_modbus.c:177
int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value)
Definition: agile_modbus.c:721
int agile_modbus_serialize_write_and_read_registers(agile_modbus_t *ctx, int write_addr, int write_nb, const uint16_t *src, int read_addr, int read_nb)
Definition: agile_modbus.c:900
int agile_modbus_deserialize_write_and_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
Definition: agile_modbus.c:941
int agile_modbus_deserialize_mask_write_register(agile_modbus_t *ctx, int msg_length)
Definition: agile_modbus.c:883
int agile_modbus_deserialize_write_registers(agile_modbus_t *ctx, int msg_length)
Definition: agile_modbus.c:844
int agile_modbus_deserialize_write_bit(agile_modbus_t *ctx, int msg_length)
Definition: agile_modbus.c:704
int agile_modbus_serialize_read_registers(agile_modbus_t *ctx, int addr, int nb)
Definition: agile_modbus.c:603
int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
Definition: agile_modbus.c:564
int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src)
Definition: agile_modbus.c:751
int agile_modbus_serialize_read_bits(agile_modbus_t *ctx, int addr, int nb)
Definition: agile_modbus.c:493
int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src)
Definition: agile_modbus.c:813
int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest)
Definition: agile_modbus.c:984
int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
Definition: agile_modbus.c:663
int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
Definition: agile_modbus.c:509
int agile_modbus_serialize_write_bit(agile_modbus_t *ctx, int addr, int status)
Definition: agile_modbus.c:691
int agile_modbus_deserialize_write_register(agile_modbus_t *ctx, int msg_length)
Definition: agile_modbus.c:734
int agile_modbus_serialize_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
Definition: agile_modbus.c:861
int agile_modbus_deserialize_write_bits(agile_modbus_t *ctx, int msg_length)
Definition: agile_modbus.c:796
int agile_modbus_serialize_read_input_registers(agile_modbus_t *ctx, int addr, int nb)
Definition: agile_modbus.c:647
int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
Definition: agile_modbus.c:619
int agile_modbus_serialize_report_slave_id(agile_modbus_t *ctx)
Definition: agile_modbus.c:969
int agile_modbus_serialize_read_input_bits(agile_modbus_t *ctx, int addr, int nb)
Definition: agile_modbus.c:548
static int agile_modbus_check_confirmation(agile_modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp_length)
检查确认从机响应的数据
Definition: agile_modbus.c:391
static int agile_modbus_compute_response_length_from_request(agile_modbus_t *ctx, uint8_t *req)
计算预期响应数据长度
Definition: agile_modbus.c:342
int agile_modbus_deserialize_raw_response(agile_modbus_t *ctx, int msg_length)
解析响应原始数据
int agile_modbus_serialize_raw_request(agile_modbus_t *ctx, const uint8_t *raw_req, int raw_req_length)
将原始数据打包成请求报文
#define AGILE_MODBUS_BROADCAST_ADDRESS
Modbus 广播地址
Definition: agile_modbus.h:55
#define AGILE_MODBUS_MAX_READ_BITS
Definition: agile_modbus.h:67
#define AGILE_MODBUS_VERSION_STRING
Agile Modbus 版本号
Definition: agile_modbus.h:53
#define AGILE_MODBUS_MAX_WRITE_REGISTERS
Definition: agile_modbus.h:86
#define AGILE_MODBUS_MAX_WRITE_BITS
Definition: agile_modbus.h:68
#define AGILE_MODBUS_MAX_WR_WRITE_REGISTERS
Definition: agile_modbus.h:87
#define AGILE_MODBUS_MAX_READ_REGISTERS
Definition: agile_modbus.h:85
#define AGILE_MODBUS_MAX_WR_READ_REGISTERS
Definition: agile_modbus.h:88
#define AGILE_MODBUS_FC_MASK_WRITE_REGISTER
Definition: agile_modbus.h:44
#define AGILE_MODBUS_FC_READ_COILS
Definition: agile_modbus.h:34
#define AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER
Definition: agile_modbus.h:39
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS
Definition: agile_modbus.h:41
#define AGILE_MODBUS_FC_WRITE_SINGLE_COIL
Definition: agile_modbus.h:38
#define AGILE_MODBUS_FC_READ_HOLDING_REGISTERS
Definition: agile_modbus.h:36
#define AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS
Definition: agile_modbus.h:45
#define AGILE_MODBUS_FC_READ_INPUT_REGISTERS
Definition: agile_modbus.h:37
#define AGILE_MODBUS_FC_REPORT_SLAVE_ID
Definition: agile_modbus.h:43
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS
Definition: agile_modbus.h:42
#define AGILE_MODBUS_FC_READ_EXCEPTION_STATUS
Definition: agile_modbus.h:40
#define AGILE_MODBUS_FC_READ_DISCRETE_INPUTS
Definition: agile_modbus.h:35
int(* agile_modbus_slave_callback_t)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info)
从机回调函数
Definition: agile_modbus.h:250
int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict, agile_modbus_slave_callback_t slave_cb, int *frame_length)
从机数据处理
uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index)
读取从机 IO 状态
void agile_modbus_slave_io_set(uint8_t *buf, int index, int status)
从机 IO 设置
uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index)
读取从机寄存器数据
void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data)
从机寄存器设置
static int agile_modbus_serialize_response_exception(agile_modbus_t *ctx, agile_modbus_sft_t *sft, int exception_code)
打包异常响应数据
int(* check_integrity)(agile_modbus_t *ctx, uint8_t *msg, const int msg_length)
检查接收数据完整性接口
Definition: agile_modbus.h:195
int(* set_slave)(agile_modbus_t *ctx, int slave)
设置地址接口
Definition: agile_modbus.h:189
int(* pre_check_confirmation)(agile_modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length)
预检查确认接口
Definition: agile_modbus.h:196
int(* build_response_basis)(agile_modbus_sft_t *sft, uint8_t *rsp)
构建基础响应报文接口
Definition: agile_modbus.h:192
uint32_t header_length
头部长度,不包含功能码
Definition: agile_modbus.h:186
uint32_t backend_type
后端类型
Definition: agile_modbus.h:185
int(* send_msg_pre)(uint8_t *req, int req_length)
预发送数据接口
Definition: agile_modbus.h:194
int(* prepare_response_tid)(const uint8_t *req, int *req_length)
准备响应接口
Definition: agile_modbus.h:193
int(* build_request_basis)(agile_modbus_t *ctx, int function, int addr, int nb, uint8_t *req)
构建基础请求报文接口
Definition: agile_modbus.h:190
uint32_t checksum_length
校验数据长度
Definition: agile_modbus.h:187
包含 modbus 头部参数结构体
Definition: agile_modbus.h:173
int slave
从机地址
Definition: agile_modbus.h:174
int t_id
事务标识符
Definition: agile_modbus.h:176
int function
功能码
Definition: agile_modbus.h:175
Agile Modbus 从机信息结构体
Definition: agile_modbus.h:232
uint8_t * buf
不同功能码需要使用的数据域
Definition: agile_modbus.h:237
int send_index
发送缓冲区当前索引
Definition: agile_modbus.h:238
agile_modbus_sft_t * sft
sft 结构体指针
Definition: agile_modbus.h:233
int address
寄存器地址
Definition: agile_modbus.h:235
int * rsp_length
响应数据长度指针
Definition: agile_modbus.h:234
Agile Modbus 结构体
Definition: agile_modbus.h:203
int(* compute_data_length_after_meta)(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
自定义计算数据长度接口
Definition: agile_modbus.h:211
uint8_t(* compute_meta_length_after_function)(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type)
自定义计算数据元长度接口
Definition: agile_modbus.h:209
int send_bufsz
发送缓冲区大小
Definition: agile_modbus.h:206
uint8_t * send_buf
发送缓冲区
Definition: agile_modbus.h:205
uint8_t * read_buf
接收缓冲区
Definition: agile_modbus.h:207
const agile_modbus_backend_t * backend
后端接口
Definition: agile_modbus.h:213
int slave
从机地址
Definition: agile_modbus.h:204
int read_bufsz
接收缓冲区大小
Definition: agile_modbus.h:208