Agile Modbus 1.1.4
Lightweight modbus protocol stack.
Loading...
Searching...
No Matches
agile_modbus.c
Go to the documentation of this file.
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
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
344 uint8_t *rsp, int rsp_length)
345{
346 int rc;
347 int rsp_length_computed;
348 const int offset = ctx->backend->header_length;
349 const int function = rsp[offset];
350
352 rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length);
353 if (rc < 0)
354 return -1;
355 }
356
357 rsp_length_computed = agile_modbus_compute_response_length_from_request(ctx, req);
358
359 /* Exception code */
360 if (function >= 0x80) {
361 if (rsp_length == (offset + 2 + (int)ctx->backend->checksum_length) && req[offset] == (rsp[offset] - 0x80))
362 return (-128 - rsp[offset + 1]);
363 else
364 return -1;
365 }
366
367 /* Check length */
368 if ((rsp_length == rsp_length_computed || rsp_length_computed == AGILE_MODBUS_MSG_LENGTH_UNDEFINED) && function < 0x80) {
369 int req_nb_value;
370 int rsp_nb_value;
371
372 /* Check function code */
373 if (function != req[offset])
374 return -1;
375
376 /* Check the number of values is corresponding to the request */
377 switch (function) {
380 /* Read functions, 8 values in a byte (nb
381 * of values in the request and byte count in
382 * the response. */
383 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
384 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
385 rsp_nb_value = rsp[offset + 1];
386 break;
387
391 /* Read functions 1 value = 2 bytes */
392 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
393 rsp_nb_value = (rsp[offset + 1] / 2);
394 break;
395
398 /* N Write functions */
399 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
400 rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
401 break;
402
404 /* Report slave ID (bytes received) */
405 req_nb_value = rsp_nb_value = rsp[offset + 1];
406 break;
407
408 default:
409 /* 1 Write functions & others */
410 req_nb_value = rsp_nb_value = 1;
411 }
412
413 if (req_nb_value == rsp_nb_value)
414 rc = rsp_nb_value;
415 else
416 rc = -1;
417 } else
418 rc = -1;
419
420 return rc;
421}
422
446{
447 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
448 if (ctx->send_bufsz < min_req_length)
449 return -1;
450
452 return -1;
453
454 int req_length = 0;
455 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_COILS, addr, nb, ctx->send_buf);
456 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
457
458 return req_length;
459}
460
461int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
462{
463 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
464 if (ctx->send_bufsz < min_req_length)
465 return -1;
466 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
467 return -1;
468
470 if (rc < 0)
471 return -1;
472
473 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
474 if (rc < 0)
475 return rc;
476
477 int i, temp, bit;
478 int pos = 0;
479 int offset;
480 int offset_end;
481 int nb;
482
483 offset = ctx->backend->header_length + 2;
484 offset_end = offset + rc;
485 nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4];
486
487 for (i = offset; i < offset_end; i++) {
488 /* Shift reg hi_byte to temp */
489 temp = ctx->read_buf[i];
490
491 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
492 dest[pos++] = (temp & bit) ? 1 : 0;
493 bit = bit << 1;
494 }
495 }
496
497 return nb;
498}
499
501{
502 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
503 if (ctx->send_bufsz < min_req_length)
504 return -1;
505
507 return -1;
508
509 int req_length = 0;
510 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, ctx->send_buf);
511 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
512
513 return req_length;
514}
515
516int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
517{
518 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
519 if (ctx->send_bufsz < min_req_length)
520 return -1;
521 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
522 return -1;
523
525 if (rc < 0)
526 return -1;
527
528 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
529 if (rc < 0)
530 return rc;
531
532 int i, temp, bit;
533 int pos = 0;
534 int offset;
535 int offset_end;
536 int nb;
537
538 offset = ctx->backend->header_length + 2;
539 offset_end = offset + rc;
540 nb = (ctx->send_buf[ctx->backend->header_length + 3] << 8) + ctx->send_buf[ctx->backend->header_length + 4];
541
542 for (i = offset; i < offset_end; i++) {
543 /* Shift reg hi_byte to temp */
544 temp = ctx->read_buf[i];
545
546 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
547 dest[pos++] = (temp & bit) ? 1 : 0;
548 bit = bit << 1;
549 }
550 }
551
552 return nb;
553}
554
556{
557 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
558 if (ctx->send_bufsz < min_req_length)
559 return -1;
560
562 return -1;
563
564 int req_length = 0;
565 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_HOLDING_REGISTERS, addr, nb, ctx->send_buf);
566 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
567
568 return req_length;
569}
570
571int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
572{
573 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
574 if (ctx->send_bufsz < min_req_length)
575 return -1;
576 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
577 return -1;
578
580 if (rc < 0)
581 return -1;
582
583 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
584 if (rc < 0)
585 return rc;
586
587 int offset;
588 int i;
589
590 offset = ctx->backend->header_length;
591 for (i = 0; i < rc; i++) {
592 /* shift reg hi_byte to temp OR with lo_byte */
593 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
594 }
595
596 return rc;
597}
598
600{
601 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
602 if (ctx->send_bufsz < min_req_length)
603 return -1;
604
606 return -1;
607
608 int req_length = 0;
609 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_READ_INPUT_REGISTERS, addr, nb, ctx->send_buf);
610 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
611
612 return req_length;
613}
614
615int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
616{
617 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
618 if (ctx->send_bufsz < min_req_length)
619 return -1;
620 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
621 return -1;
622
624 if (rc < 0)
625 return -1;
626
627 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
628 if (rc < 0)
629 return rc;
630
631 int offset;
632 int i;
633
634 offset = ctx->backend->header_length;
635 for (i = 0; i < rc; i++) {
636 /* shift reg hi_byte to temp OR with lo_byte */
637 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
638 }
639
640 return rc;
641}
642
644{
645 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
646 if (ctx->send_bufsz < min_req_length)
647 return -1;
648
649 int req_length = 0;
650 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_COIL, addr, status ? 0xFF00 : 0, ctx->send_buf);
651 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
652
653 return req_length;
654}
655
657{
658 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
659 if (ctx->send_bufsz < min_req_length)
660 return -1;
661 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
662 return -1;
663
665 if (rc < 0)
666 return -1;
667
668 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
669
670 return rc;
671}
672
673int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value)
674{
675 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
676 if (ctx->send_bufsz < min_req_length)
677 return -1;
678
679 int req_length = 0;
680 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER, addr, (int)value, ctx->send_buf);
681 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
682
683 return req_length;
684}
685
687{
688 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
689 if (ctx->send_bufsz < min_req_length)
690 return -1;
691 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
692 return -1;
693
695 if (rc < 0)
696 return -1;
697
698 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
699
700 return rc;
701}
702
703int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src)
704{
705 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
706 if (ctx->send_bufsz < min_req_length)
707 return -1;
708
710 return -1;
711
712 int i;
713 int byte_count;
714 int req_length;
715 int bit_check = 0;
716 int pos = 0;
717
718 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS, addr, nb, ctx->send_buf);
719 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
720
721 min_req_length += (1 + byte_count);
722 if (ctx->send_bufsz < min_req_length)
723 return -1;
724
725 ctx->send_buf[req_length++] = byte_count;
726 for (i = 0; i < byte_count; i++) {
727 int bit;
728
729 bit = 0x01;
730 ctx->send_buf[req_length] = 0;
731
732 while ((bit & 0xFF) && (bit_check++ < nb)) {
733 if (src[pos++])
734 ctx->send_buf[req_length] |= bit;
735 else
736 ctx->send_buf[req_length] &= ~bit;
737
738 bit = bit << 1;
739 }
740 req_length++;
741 }
742
743 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
744
745 return req_length;
746}
747
749{
750 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
751 if (ctx->send_bufsz < min_req_length)
752 return -1;
753 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
754 return -1;
755
757 if (rc < 0)
758 return -1;
759
760 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
761
762 return rc;
763}
764
765int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src)
766{
767 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
768 if (ctx->send_bufsz < min_req_length)
769 return -1;
770
772 return -1;
773
774 int i;
775 int req_length;
776 int byte_count;
777
778 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS, addr, nb, ctx->send_buf);
779 byte_count = nb * 2;
780
781 min_req_length += (1 + byte_count);
782 if (ctx->send_bufsz < min_req_length)
783 return -1;
784
785 ctx->send_buf[req_length++] = byte_count;
786 for (i = 0; i < nb; i++) {
787 ctx->send_buf[req_length++] = src[i] >> 8;
788 ctx->send_buf[req_length++] = src[i] & 0x00FF;
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_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
814{
815 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length + 2;
816 if (ctx->send_bufsz < min_req_length)
817 return -1;
818
819 int req_length = 0;
820 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_MASK_WRITE_REGISTER, addr, 0, ctx->send_buf);
821
822 /* HACKISH, count is not used */
823 req_length -= 2;
824
825 ctx->send_buf[req_length++] = and_mask >> 8;
826 ctx->send_buf[req_length++] = and_mask & 0x00ff;
827 ctx->send_buf[req_length++] = or_mask >> 8;
828 ctx->send_buf[req_length++] = or_mask & 0x00ff;
829
830 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
831
832 return req_length;
833}
834
836{
837 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
838 if (ctx->send_bufsz < min_req_length)
839 return -1;
840 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
841 return -1;
842
844 if (rc < 0)
845 return -1;
846
847 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
848
849 return rc;
850}
851
853 int write_addr, int write_nb,
854 const uint16_t *src,
855 int read_addr, int read_nb)
856{
857 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
858 if (ctx->send_bufsz < min_req_length)
859 return -1;
860
862 return -1;
863
865 return -1;
866
867 int req_length;
868 int i;
869 int byte_count;
870
871 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS, read_addr, read_nb, ctx->send_buf);
872 byte_count = write_nb * 2;
873
874 min_req_length += (5 + byte_count);
875 if (ctx->send_bufsz < min_req_length)
876 return -1;
877
878 ctx->send_buf[req_length++] = write_addr >> 8;
879 ctx->send_buf[req_length++] = write_addr & 0x00ff;
880 ctx->send_buf[req_length++] = write_nb >> 8;
881 ctx->send_buf[req_length++] = write_nb & 0x00ff;
882 ctx->send_buf[req_length++] = byte_count;
883 for (i = 0; i < write_nb; i++) {
884 ctx->send_buf[req_length++] = src[i] >> 8;
885 ctx->send_buf[req_length++] = src[i] & 0x00FF;
886 }
887
888 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
889
890 return req_length;
891}
892
894{
895 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
896 if (ctx->send_bufsz < min_req_length)
897 return -1;
898 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
899 return -1;
900
902 if (rc < 0)
903 return -1;
904
905 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
906 if (rc < 0)
907 return rc;
908
909 int offset;
910 int i;
911
912 offset = ctx->backend->header_length;
913 for (i = 0; i < rc; i++) {
914 /* shift reg hi_byte to temp OR with lo_byte */
915 dest[i] = (ctx->read_buf[offset + 2 + (i << 1)] << 8) | ctx->read_buf[offset + 3 + (i << 1)];
916 }
917
918 return rc;
919}
920
922{
923 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
924 if (ctx->send_bufsz < min_req_length)
925 return -1;
926
927 int req_length = 0;
928 req_length = ctx->backend->build_request_basis(ctx, AGILE_MODBUS_FC_REPORT_SLAVE_ID, 0, 0, ctx->send_buf);
929 /* HACKISH, addr and count are not used */
930 req_length -= 4;
931 req_length = ctx->backend->send_msg_pre(ctx->send_buf, req_length);
932
933 return req_length;
934}
935
936int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest)
937{
938 int min_req_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
939 if (ctx->send_bufsz < min_req_length)
940 return -1;
941 if ((msg_length <= 0) || (msg_length > ctx->read_bufsz))
942 return -1;
943 if (max_dest <= 0)
944 return -1;
945
947 if (rc < 0)
948 return -1;
949
950 rc = agile_modbus_check_confirmation(ctx, ctx->send_buf, ctx->read_buf, rc);
951 if (rc < 0)
952 return rc;
953
954 int i;
955 int offset;
956
957 offset = ctx->backend->header_length + 2;
958
959 /* Byte count, slave id, run indicator status and
960 additional data. Truncate copy to max_dest. */
961 for (i = 0; i < rc && i < max_dest; i++) {
962 dest[i] = ctx->read_buf[offset + i];
963 }
964
965 return rc;
966}
967
985{
986 int length;
987 const int offset = ctx->backend->header_length;
988
989 switch (req[offset]) {
992 /* Header + nb values (code from write_bits) */
993 int nb = (req[offset + 3] << 8) | req[offset + 4];
994 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
995 } break;
996
1000 /* Header + 2 * nb values */
1001 length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
1002 break;
1003
1008 length = 5;
1009 break;
1010
1012 length = 7;
1013 break;
1014
1015 default:
1016 /* The response is device specific (the header provides the
1017 length) */
1019 }
1020
1021 return offset + length + ctx->backend->checksum_length;
1022}
1023
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
1203int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict,
1204 agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length)
1205{
1206 int min_rsp_length = ctx->backend->header_length + 5 + ctx->backend->checksum_length;
1207 if (ctx->send_bufsz < min_rsp_length)
1208 return -1;
1209
1210 int req_length = agile_modbus_receive_judge(ctx, msg_length, AGILE_MODBUS_MSG_INDICATION);
1211 if (req_length < 0)
1212 return -1;
1213 if (frame_length)
1214 *frame_length = req_length;
1215
1216 int offset;
1217 int slave;
1218 int function;
1219 uint16_t address;
1220 int rsp_length = 0;
1221 int exception_code = 0;
1222 int reg_data = 0;
1224 uint8_t *req = ctx->read_buf;
1225 uint8_t *rsp = ctx->send_buf;
1226
1227 memset(rsp, 0, ctx->send_bufsz);
1228 offset = ctx->backend->header_length;
1229 slave = req[offset - 1];
1230 function = req[offset];
1231 address = (req[offset + 1] << 8) + req[offset + 2];
1232
1233 sft.slave = slave;
1234 sft.function = function;
1235 sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
1236
1237 struct agile_modbus_slave_info slave_info = {0};
1238 slave_info.sft = &sft;
1239 slave_info.rsp_length = &rsp_length;
1240 slave_info.address = address;
1241
1242 if (slave_strict) {
1243 if ((slave != ctx->slave) && (slave != AGILE_MODBUS_BROADCAST_ADDRESS))
1244 return 0;
1245 }
1246
1247 switch (function) {
1250 int nb = (req[offset + 3] << 8) + req[offset + 4];
1251 if (nb < 1 || AGILE_MODBUS_MAX_READ_BITS < nb) {
1253 break;
1254 }
1255
1256 int end_address = (int)address + nb - 1;
1257 if (end_address > 0xFFFF) {
1259 break;
1260 }
1261
1263 slave_info.nb = (nb / 8) + ((nb % 8) ? 1 : 0);
1264 rsp[rsp_length++] = slave_info.nb;
1265 slave_info.send_index = rsp_length;
1266 rsp_length += slave_info.nb;
1267 slave_info.nb = nb;
1268 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1270 break;
1271 }
1272 } break;
1273
1276 int nb = (req[offset + 3] << 8) + req[offset + 4];
1277 if (nb < 1 || AGILE_MODBUS_MAX_READ_REGISTERS < nb) {
1279 break;
1280 }
1281
1282 int end_address = (int)address + nb - 1;
1283 if (end_address > 0xFFFF) {
1285 break;
1286 }
1287
1289 slave_info.nb = nb << 1;
1290 rsp[rsp_length++] = slave_info.nb;
1291 slave_info.send_index = rsp_length;
1292 rsp_length += slave_info.nb;
1293 slave_info.nb = nb;
1294 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1296 break;
1297 }
1298 } break;
1299
1302 #if 0
1303 if (address > 0xFFFF) {
1305 break;
1306 }
1307 #endif
1308
1309 reg_data = (req[offset + 3] << 8) + req[offset + 4];
1310 if (reg_data == 0xFF00 || reg_data == 0x0)
1311 reg_data = reg_data ? 1 : 0;
1312 else {
1314 break;
1315 }
1316
1317 slave_info.buf = (uint8_t *)&reg_data;
1318 rsp_length = req_length;
1319 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1321 break;
1322 }
1323 memcpy(rsp, req, req_length);
1324 } break;
1325
1328 #if 0
1329 if (address > 0xFFFF) {
1331 break;
1332 }
1333 #endif
1334
1335 reg_data = (req[offset + 3] << 8) + req[offset + 4];
1336
1337 slave_info.buf = (uint8_t *)&reg_data;
1338 rsp_length = req_length;
1339 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1341 break;
1342 }
1343 memcpy(rsp, req, req_length);
1344 } break;
1345
1347 int nb = (req[offset + 3] << 8) + req[offset + 4];
1348 int nb_bits = req[offset + 5];
1349 if (nb < 1 || AGILE_MODBUS_MAX_WRITE_BITS < nb || nb_bits * 8 < nb) {
1351 break;
1352 }
1353
1354 int end_address = (int)address + nb - 1;
1355 if (end_address > 0xFFFF) {
1357 break;
1358 }
1359
1361 slave_info.nb = nb;
1362 slave_info.buf = &req[offset + 6];
1363 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + 4)) {
1365 break;
1366 }
1367 /* 4 to copy the bit address (2) and the quantity of bits */
1368 memcpy(rsp + rsp_length, req + rsp_length, 4);
1369 rsp_length += 4;
1370 } break;
1371
1373 int nb = (req[offset + 3] << 8) + req[offset + 4];
1374 int nb_bytes = req[offset + 5];
1375 if (nb < 1 || AGILE_MODBUS_MAX_WRITE_REGISTERS < nb || nb_bytes != nb * 2) {
1377 break;
1378 }
1379
1380 int end_address = (int)address + nb - 1;
1381 if (end_address > 0xFFFF) {
1383 break;
1384 }
1385
1387 slave_info.nb = nb;
1388 slave_info.buf = &req[offset + 6];
1389 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + 4)) {
1391 break;
1392 }
1393 /* 4 to copy the address (2) and the no. of registers */
1394 memcpy(rsp + rsp_length, req + rsp_length, 4);
1395 rsp_length += 4;
1396
1397 } break;
1398
1400 int str_len;
1401 int byte_count_pos;
1402
1403 slave_cb = NULL;
1405 /* Skip byte count for now */
1406 byte_count_pos = rsp_length++;
1407 rsp[rsp_length++] = ctx->slave;
1408 /* Run indicator status to ON */
1409 rsp[rsp_length++] = 0xFF;
1410
1411 str_len = strlen(AGILE_MODBUS_VERSION_STRING);
1412 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length + str_len)) {
1414 break;
1415 }
1416 memcpy(rsp + rsp_length, AGILE_MODBUS_VERSION_STRING, str_len);
1417 rsp_length += str_len;
1418 rsp[byte_count_pos] = rsp_length - byte_count_pos - 1;
1419 } break;
1420
1423 break;
1424
1427 #if 0
1428 if (address > 0xFFFF) {
1430 break;
1431 }
1432 #endif
1433
1434 slave_info.buf = &req[offset + 3];
1435 rsp_length = req_length;
1436 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1438 break;
1439 }
1440 memcpy(rsp, req, req_length);
1441 } break;
1442
1444 int nb = (req[offset + 3] << 8) + req[offset + 4];
1445 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
1446 int nb_write = (req[offset + 7] << 8) + req[offset + 8];
1447 int nb_write_bytes = req[offset + 9];
1448 if (nb_write < 1 || AGILE_MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
1450 nb_write_bytes != nb_write * 2) {
1452 break;
1453 }
1454
1455 int end_address = (int)address + nb - 1;
1456 int end_address_write = (int)address_write + nb_write - 1;
1457 if (end_address > 0xFFFF || end_address_write > 0xFFFF) {
1459 break;
1460 }
1461
1463 rsp[rsp_length++] = nb << 1;
1464 slave_info.buf = &req[offset + 3];
1465 slave_info.send_index = rsp_length;
1466 rsp_length += (nb << 1);
1467 if (ctx->send_bufsz < (int)(rsp_length + ctx->backend->checksum_length)) {
1469 break;
1470 }
1471 } break;
1472
1473 default: {
1474 if (slave_cb == NULL)
1476 else {
1478 slave_info.send_index = rsp_length;
1479 slave_info.buf = &req[offset + 1];
1480 slave_info.nb = req_length - offset - 1;
1481 }
1482 } break;
1483 }
1484
1485 if (exception_code)
1487 else {
1488 if (slave_cb) {
1489 int ret = slave_cb(ctx, &slave_info, slave_data);
1490
1491 if (ret < 0) {
1493 rsp_length = 0;
1494 else
1496 }
1497 }
1498 }
1499
1500 if (rsp_length) {
1502 return 0;
1503
1505 }
1506
1507 return rsp_length;
1508}
1509
Agile Modbus software package common header file.
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))
sets the data length callback function to be received after calculating the data element of the modbu...
void agile_modbus_common_init(agile_modbus_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz)
initialize modbus handle
int agile_modbus_receive_judge(agile_modbus_t *ctx, int msg_length, agile_modbus_msg_type_t msg_type)
Verify the correctness of received data.
int agile_modbus_set_slave(agile_modbus_t *ctx, int slave)
set address
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))
sets the data element length callback function to be received after calculating the function code of ...
agile_modbus_msg_type_t
Modbus received message type.
@ AGILE_MODBUS_EXCEPTION_UNKNOW
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS
@ AGILE_MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE
@ AGILE_MODBUS_BACKEND_TYPE_RTU
RTU.
@ AGILE_MODBUS_MSG_CONFIRMATION
Server-side request message.
@ AGILE_MODBUS_MSG_INDICATION
Host-side request message.
#define AGILE_MODBUS_MSG_LENGTH_UNDEFINED
The corresponding function code data length is undefined.
static int agile_modbus_receive_msg_judge(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
Check the correctness of received data.
static uint8_t agile_modbus_compute_meta_length_after_function(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type)
The length of the data element to be received after calculating the function code.
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)
The length of data to be received after calculating the data element.
int agile_modbus_serialize_write_register(agile_modbus_t *ctx, int addr, const uint16_t value)
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)
int agile_modbus_deserialize_write_and_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
int agile_modbus_deserialize_mask_write_register(agile_modbus_t *ctx, int msg_length)
int agile_modbus_deserialize_write_registers(agile_modbus_t *ctx, int msg_length)
int agile_modbus_deserialize_write_bit(agile_modbus_t *ctx, int msg_length)
int agile_modbus_serialize_read_registers(agile_modbus_t *ctx, int addr, int nb)
int agile_modbus_deserialize_read_input_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
int agile_modbus_serialize_write_bits(agile_modbus_t *ctx, int addr, int nb, const uint8_t *src)
int agile_modbus_serialize_read_bits(agile_modbus_t *ctx, int addr, int nb)
int agile_modbus_serialize_write_registers(agile_modbus_t *ctx, int addr, int nb, const uint16_t *src)
int agile_modbus_deserialize_report_slave_id(agile_modbus_t *ctx, int msg_length, int max_dest, uint8_t *dest)
int agile_modbus_deserialize_read_input_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
int agile_modbus_deserialize_read_bits(agile_modbus_t *ctx, int msg_length, uint8_t *dest)
int agile_modbus_serialize_write_bit(agile_modbus_t *ctx, int addr, int status)
int agile_modbus_deserialize_write_register(agile_modbus_t *ctx, int msg_length)
int agile_modbus_serialize_mask_write_register(agile_modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
int agile_modbus_deserialize_write_bits(agile_modbus_t *ctx, int msg_length)
int agile_modbus_serialize_read_input_registers(agile_modbus_t *ctx, int addr, int nb)
int agile_modbus_deserialize_read_registers(agile_modbus_t *ctx, int msg_length, uint16_t *dest)
int agile_modbus_serialize_report_slave_id(agile_modbus_t *ctx)
int agile_modbus_serialize_read_input_bits(agile_modbus_t *ctx, int addr, int nb)
static int agile_modbus_check_confirmation(agile_modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp_length)
Check and confirm the slave response data.
int agile_modbus_compute_response_length_from_request(agile_modbus_t *ctx, uint8_t *req)
Calculate the expected response data length.
int agile_modbus_deserialize_raw_response(agile_modbus_t *ctx, int msg_length)
parses the original response data
int agile_modbus_serialize_raw_request(agile_modbus_t *ctx, const uint8_t *raw_req, int raw_req_length)
Pack the original data into a request message.
#define AGILE_MODBUS_BROADCAST_ADDRESS
Modbus broadcast address.
#define AGILE_MODBUS_MAX_READ_BITS
#define AGILE_MODBUS_VERSION_STRING
Agile Modbus version number.
#define AGILE_MODBUS_MAX_WRITE_REGISTERS
#define AGILE_MODBUS_MAX_WRITE_BITS
#define AGILE_MODBUS_MAX_WR_WRITE_REGISTERS
#define AGILE_MODBUS_MAX_READ_REGISTERS
#define AGILE_MODBUS_MAX_WR_READ_REGISTERS
#define AGILE_MODBUS_FC_MASK_WRITE_REGISTER
#define AGILE_MODBUS_FC_READ_COILS
#define AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS
#define AGILE_MODBUS_FC_WRITE_SINGLE_COIL
#define AGILE_MODBUS_FC_READ_HOLDING_REGISTERS
#define AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS
#define AGILE_MODBUS_FC_READ_INPUT_REGISTERS
#define AGILE_MODBUS_FC_REPORT_SLAVE_ID
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS
#define AGILE_MODBUS_FC_READ_EXCEPTION_STATUS
#define AGILE_MODBUS_FC_READ_DISCRETE_INPUTS
int(* agile_modbus_slave_callback_t)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)
Slave callback function.
int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict, agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length)
slave data processing
uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index)
Read slave IO status.
void agile_modbus_slave_io_set(uint8_t *buf, int index, int status)
slave IO settings
uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index)
Read slave register data.
void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data)
slave register settings
static int agile_modbus_serialize_response_exception(agile_modbus_t *ctx, agile_modbus_sft_t *sft, int exception_code)
packaged exception response data
int(* check_integrity)(agile_modbus_t *ctx, uint8_t *msg, const int msg_length)
Check the receive data integrity interface.
int(* set_slave)(agile_modbus_t *ctx, int slave)
Set address interface.
int(* pre_check_confirmation)(agile_modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length)
Pre-check confirmation interface.
int(* build_response_basis)(agile_modbus_sft_t *sft, uint8_t *rsp)
Build a basic response message interface.
uint32_t header_length
Header length, excluding function code.
uint32_t backend_type
Backend type.
int(* send_msg_pre)(uint8_t *req, int req_length)
Pre-send data interface.
int(* prepare_response_tid)(const uint8_t *req, int *req_length)
Prepare response interface.
int(* build_request_basis)(agile_modbus_t *ctx, int function, int addr, int nb, uint8_t *req)
Build a basic request message interface.
uint32_t checksum_length
Check data length.
contains the modbus header parameter structure
int slave
slave address
int t_id
Transaction identifier.
int function
function code
Agile Modbus slave information structure.
uint8_t * buf
Data fields required for different function codes.
int send_index
Current index of sending buffer.
agile_modbus_sft_t * sft
sft structure pointer
int address
Register address.
int * rsp_length
Response data length pointer.
Agile Modbus structure.
int(* compute_data_length_after_meta)(agile_modbus_t *ctx, uint8_t *msg, int msg_length, agile_modbus_msg_type_t msg_type)
Customized calculation data length interface.
uint8_t(* compute_meta_length_after_function)(agile_modbus_t *ctx, int function, agile_modbus_msg_type_t msg_type)
Customized calculation data element length interface.
int send_bufsz
Send buffer size.
uint8_t * send_buf
Send buffer.
uint8_t * read_buf
Receive buffer.
const agile_modbus_backend_t * backend
Backend interface.
int slave
slave address
int read_bufsz
Receive buffer size.