Commit 52ab1bbea760ed8eaca184f7d875a2f52a116d0f

Authored by Michael Heimpold
Committed by Stéphane Raimbault
1 parent 1776a350

Introduce offsets in modbus mappings

This allows to place the coils/registers at any virtual
start address, not only at address 0. This can be useful e.g.
when the server has to fulfill a specification in which
registers are expected at predefined locations.

Signed-off-by: Michael Heimpold <mhei@heimpold.de>
doc/Makefile.am
@@ -12,6 +12,7 @@ TXT3 = \ @@ -12,6 +12,7 @@ TXT3 = \
12 modbus_get_socket.txt \ 12 modbus_get_socket.txt \
13 modbus_mapping_free.txt \ 13 modbus_mapping_free.txt \
14 modbus_mapping_new.txt \ 14 modbus_mapping_new.txt \
  15 + modbus_mapping_offset_new.txt \
15 modbus_mask_write_register.txt \ 16 modbus_mask_write_register.txt \
16 modbus_new_rtu.txt \ 17 modbus_new_rtu.txt \
17 modbus_new_tcp_pi.txt \ 18 modbus_new_tcp_pi.txt \
doc/modbus_mapping_new.txt
@@ -18,6 +18,9 @@ The *modbus_mapping_new()* function shall allocate four arrays to store bits, @@ -18,6 +18,9 @@ The *modbus_mapping_new()* function shall allocate four arrays to store bits,
18 input bits, registers and inputs registers. The pointers are stored in 18 input bits, registers and inputs registers. The pointers are stored in
19 modbus_mapping_t structure. All values of the arrays are initialized to zero. 19 modbus_mapping_t structure. All values of the arrays are initialized to zero.
20 20
  21 +This function is equivalent to a call of the _modbus_mapping_offset_new()_ function
  22 +with all offsets set to zero.
  23 +
21 If it isn't necessary to allocate an array for a specific type of data, you can 24 If it isn't necessary to allocate an array for a specific type of data, you can
22 pass the zero value in argument, the associated pointer will be NULL. 25 pass the zero value in argument, the associated pointer will be NULL.
23 26
@@ -40,7 +43,7 @@ EXAMPLE @@ -40,7 +43,7 @@ EXAMPLE
40 ------- 43 -------
41 [source,c] 44 [source,c]
42 ------------------- 45 -------------------
43 -/* The fist value of each array is accessible from the 0 address. */ 46 +/* The first value of each array is accessible from the 0 address. */
44 mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB, 47 mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB,
45 INPUT_BITS_ADDRESS + INPUT_BITS_NB, 48 INPUT_BITS_ADDRESS + INPUT_BITS_NB,
46 REGISTERS_ADDRESS + REGISTERS_NB, 49 REGISTERS_ADDRESS + REGISTERS_NB,
doc/modbus_mapping_offset_new.txt 0 → 100644
  1 +modbus_mapping_offset_new(3)
  2 +============================
  3 +
  4 +
  5 +NAME
  6 +----
  7 +modbus_mapping_offset_new - allocate four arrays of bits and registers
  8 +
  9 +
  10 +SYNOPSIS
  11 +--------
  12 +*modbus_mapping_t* modbus_mapping_new(int 'nb_bits', int 'offset_bits',
  13 + int 'nb_input_bits', int 'offset_input_bits',
  14 + int 'nb_registers', int 'offset_registers',
  15 + int 'nb_input_registers', int 'offset_input_registers');*
  16 +
  17 +
  18 +DESCRIPTION
  19 +-----------
  20 +The _modbus_mapping_offset_new()_ function shall allocate four arrays to store bits,
  21 +input bits, registers and inputs registers. The pointers are stored in
  22 +modbus_mapping_t structure. All values of the arrays are initialized to zero.
  23 +
  24 +The different offsets make it possible to place the mapping at any address in
  25 +each address space.
  26 +
  27 +If it isn't necessary to allocate an array for a specific type of data, you can
  28 +pass the zero value in argument, the associated pointer will be NULL.
  29 +
  30 +This function is convenient to handle requests in a Modbus server/slave.
  31 +
  32 +
  33 +RETURN VALUE
  34 +------------
  35 +The _modbus_mapping_offset_new()_ function shall return the new allocated structure if
  36 +successful. Otherwise it shall return NULL and set errno.
  37 +
  38 +
  39 +ERRORS
  40 +------
  41 +ENOMEM::
  42 +Not enough memory
  43 +
  44 +
  45 +EXAMPLE
  46 +-------
  47 +[source,c]
  48 +-------------------
  49 +/* The first value of each array is accessible at address 4. */
  50 +mb_mapping = modbus_mapping_offset_new(BITS_ADDRESS + BITS_NB, 4,
  51 + INPUT_BITS_ADDRESS + INPUT_BITS_NB, 4,
  52 + REGISTERS_ADDRESS + REGISTERS_NB, 4,
  53 + INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB, 4);
  54 +if (mb_mapping == NULL) {
  55 + fprintf(stderr, "Failed to allocate the mapping: %s\n",
  56 + modbus_strerror(errno));
  57 + modbus_free(ctx);
  58 + return -1;
  59 +}
  60 +-------------------
  61 +
  62 +SEE ALSO
  63 +--------
  64 +linkmb:modbus_mapping_free[3]
  65 +
  66 +
  67 +AUTHORS
  68 +-------
  69 +The libmodbus documentation was written by Stéphane Raimbault
  70 +<stephane.raimbault@gmail.com>
src/modbus.c
@@ -706,6 +706,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -706,6 +706,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
706 switch (function) { 706 switch (function) {
707 case MODBUS_FC_READ_COILS: { 707 case MODBUS_FC_READ_COILS: {
708 int nb = (req[offset + 3] << 8) + req[offset + 4]; 708 int nb = (req[offset + 3] << 8) + req[offset + 4];
  709 + int addr = address - mb_mapping->offset_bits;
709 710
710 if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { 711 if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
711 if (ctx->debug) { 712 if (ctx->debug) {
@@ -718,10 +719,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -718,10 +719,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
718 rsp_length = response_exception( 719 rsp_length = response_exception(
719 ctx, &sft, 720 ctx, &sft,
720 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 721 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
721 - } else if ((address + nb) > mb_mapping->nb_bits) { 722 + } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) {
722 if (ctx->debug) { 723 if (ctx->debug) {
723 fprintf(stderr, "Illegal data address 0x%0X in read_bits\n", 724 fprintf(stderr, "Illegal data address 0x%0X in read_bits\n",
724 - address + nb); 725 + address < mb_mapping->offset_bits ? address : address + nb);
725 } 726 }
726 rsp_length = response_exception( 727 rsp_length = response_exception(
727 ctx, &sft, 728 ctx, &sft,
@@ -729,7 +730,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -729,7 +730,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
729 } else { 730 } else {
730 rsp_length = ctx->backend->build_response_basis(&sft, rsp); 731 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
731 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 732 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
732 - rsp_length = response_io_status(address, nb, 733 + rsp_length = response_io_status(addr, nb,
733 mb_mapping->tab_bits, 734 mb_mapping->tab_bits,
734 rsp, rsp_length); 735 rsp, rsp_length);
735 } 736 }
@@ -739,6 +740,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -739,6 +740,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
739 /* Similar to coil status (but too many arguments to use a 740 /* Similar to coil status (but too many arguments to use a
740 * function) */ 741 * function) */
741 int nb = (req[offset + 3] << 8) + req[offset + 4]; 742 int nb = (req[offset + 3] << 8) + req[offset + 4];
  743 + int addr = address - mb_mapping->offset_input_bits;
742 744
743 if (nb < 1 || MODBUS_MAX_READ_BITS < nb) { 745 if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
744 if (ctx->debug) { 746 if (ctx->debug) {
@@ -751,10 +753,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -751,10 +753,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
751 rsp_length = response_exception( 753 rsp_length = response_exception(
752 ctx, &sft, 754 ctx, &sft,
753 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 755 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
754 - } else if ((address + nb) > mb_mapping->nb_input_bits) { 756 + } else if (address < mb_mapping->offset_input_bits || (addr + nb) > mb_mapping->nb_input_bits) {
755 if (ctx->debug) { 757 if (ctx->debug) {
756 fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n", 758 fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n",
757 - address + nb); 759 + address < mb_mapping->offset_input_bits ? address : address + nb);
758 } 760 }
759 rsp_length = response_exception( 761 rsp_length = response_exception(
760 ctx, &sft, 762 ctx, &sft,
@@ -762,7 +764,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -762,7 +764,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
762 } else { 764 } else {
763 rsp_length = ctx->backend->build_response_basis(&sft, rsp); 765 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
764 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 766 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
765 - rsp_length = response_io_status(address, nb, 767 + rsp_length = response_io_status(addr, nb,
766 mb_mapping->tab_input_bits, 768 mb_mapping->tab_input_bits,
767 rsp, rsp_length); 769 rsp, rsp_length);
768 } 770 }
@@ -770,6 +772,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -770,6 +772,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
770 break; 772 break;
771 case MODBUS_FC_READ_HOLDING_REGISTERS: { 773 case MODBUS_FC_READ_HOLDING_REGISTERS: {
772 int nb = (req[offset + 3] << 8) + req[offset + 4]; 774 int nb = (req[offset + 3] << 8) + req[offset + 4];
  775 + int addr = address - mb_mapping->offset_registers;
773 776
774 if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { 777 if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
775 if (ctx->debug) { 778 if (ctx->debug) {
@@ -782,10 +785,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -782,10 +785,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
782 rsp_length = response_exception( 785 rsp_length = response_exception(
783 ctx, &sft, 786 ctx, &sft,
784 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 787 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
785 - } else if ((address + nb) > mb_mapping->nb_registers) { 788 + } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) {
786 if (ctx->debug) { 789 if (ctx->debug) {
787 fprintf(stderr, "Illegal data address 0x%0X in read_registers\n", 790 fprintf(stderr, "Illegal data address 0x%0X in read_registers\n",
788 - address + nb); 791 + address < mb_mapping->offset_registers ? address : address + nb);
789 } 792 }
790 rsp_length = response_exception( 793 rsp_length = response_exception(
791 ctx, &sft, 794 ctx, &sft,
@@ -795,7 +798,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -795,7 +798,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
795 798
796 rsp_length = ctx->backend->build_response_basis(&sft, rsp); 799 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
797 rsp[rsp_length++] = nb << 1; 800 rsp[rsp_length++] = nb << 1;
798 - for (i = address; i < address + nb; i++) { 801 + for (i = addr; i < addr + nb; i++) {
799 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; 802 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
800 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; 803 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
801 } 804 }
@@ -806,6 +809,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -806,6 +809,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
806 /* Similar to holding registers (but too many arguments to use a 809 /* Similar to holding registers (but too many arguments to use a
807 * function) */ 810 * function) */
808 int nb = (req[offset + 3] << 8) + req[offset + 4]; 811 int nb = (req[offset + 3] << 8) + req[offset + 4];
  812 + int addr = address - mb_mapping->offset_input_registers;
809 813
810 if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) { 814 if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
811 if (ctx->debug) { 815 if (ctx->debug) {
@@ -818,10 +822,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -818,10 +822,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
818 rsp_length = response_exception( 822 rsp_length = response_exception(
819 ctx, &sft, 823 ctx, &sft,
820 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 824 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
821 - } else if ((address + nb) > mb_mapping->nb_input_registers) { 825 + } else if (address < mb_mapping->offset_input_registers || (addr + nb) > mb_mapping->nb_input_registers) {
822 if (ctx->debug) { 826 if (ctx->debug) {
823 fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n", 827 fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n",
824 - address + nb); 828 + address < mb_mapping->offset_input_registers ? address : address + nb);
825 } 829 }
826 rsp_length = response_exception( 830 rsp_length = response_exception(
827 ctx, &sft, 831 ctx, &sft,
@@ -831,15 +835,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -831,15 +835,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
831 835
832 rsp_length = ctx->backend->build_response_basis(&sft, rsp); 836 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
833 rsp[rsp_length++] = nb << 1; 837 rsp[rsp_length++] = nb << 1;
834 - for (i = address; i < address + nb; i++) { 838 + for (i = addr; i < addr + nb; i++) {
835 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8; 839 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8;
836 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; 840 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF;
837 } 841 }
838 } 842 }
839 } 843 }
840 break; 844 break;
841 - case MODBUS_FC_WRITE_SINGLE_COIL:  
842 - if (address >= mb_mapping->nb_bits) { 845 + case MODBUS_FC_WRITE_SINGLE_COIL: {
  846 + int addr = address - mb_mapping->offset_bits;
  847 +
  848 + if (address < mb_mapping->offset_bits || addr >= mb_mapping->nb_bits) {
843 if (ctx->debug) { 849 if (ctx->debug) {
844 fprintf(stderr, 850 fprintf(stderr,
845 "Illegal data address 0x%0X in write_bit\n", 851 "Illegal data address 0x%0X in write_bit\n",
@@ -852,7 +858,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -852,7 +858,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
852 int data = (req[offset + 3] << 8) + req[offset + 4]; 858 int data = (req[offset + 3] << 8) + req[offset + 4];
853 859
854 if (data == 0xFF00 || data == 0x0) { 860 if (data == 0xFF00 || data == 0x0) {
855 - mb_mapping->tab_bits[address] = (data) ? ON : OFF; 861 + mb_mapping->tab_bits[addr] = (data) ? ON : OFF;
856 memcpy(rsp, req, req_length); 862 memcpy(rsp, req, req_length);
857 rsp_length = req_length; 863 rsp_length = req_length;
858 } else { 864 } else {
@@ -866,9 +872,12 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -866,9 +872,12 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
866 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 872 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
867 } 873 }
868 } 874 }
  875 + }
869 break; 876 break;
870 - case MODBUS_FC_WRITE_SINGLE_REGISTER:  
871 - if (address >= mb_mapping->nb_registers) { 877 + case MODBUS_FC_WRITE_SINGLE_REGISTER: {
  878 + int addr = address - mb_mapping->offset_registers;
  879 +
  880 + if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) {
872 if (ctx->debug) { 881 if (ctx->debug) {
873 fprintf(stderr, "Illegal data address 0x%0X in write_register\n", 882 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
874 address); 883 address);
@@ -879,13 +888,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -879,13 +888,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
879 } else { 888 } else {
880 int data = (req[offset + 3] << 8) + req[offset + 4]; 889 int data = (req[offset + 3] << 8) + req[offset + 4];
881 890
882 - mb_mapping->tab_registers[address] = data; 891 + mb_mapping->tab_registers[addr] = data;
883 memcpy(rsp, req, req_length); 892 memcpy(rsp, req, req_length);
884 rsp_length = req_length; 893 rsp_length = req_length;
885 } 894 }
  895 + }
886 break; 896 break;
887 case MODBUS_FC_WRITE_MULTIPLE_COILS: { 897 case MODBUS_FC_WRITE_MULTIPLE_COILS: {
888 int nb = (req[offset + 3] << 8) + req[offset + 4]; 898 int nb = (req[offset + 3] << 8) + req[offset + 4];
  899 + int addr = address - mb_mapping->offset_bits;
889 900
890 if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) { 901 if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) {
891 if (ctx->debug) { 902 if (ctx->debug) {
@@ -901,17 +912,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -901,17 +912,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
901 rsp_length = response_exception( 912 rsp_length = response_exception(
902 ctx, &sft, 913 ctx, &sft,
903 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 914 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
904 - } else if ((address + nb) > mb_mapping->nb_bits) { 915 + } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) {
905 if (ctx->debug) { 916 if (ctx->debug) {
906 fprintf(stderr, "Illegal data address 0x%0X in write_bits\n", 917 fprintf(stderr, "Illegal data address 0x%0X in write_bits\n",
907 - address + nb); 918 + address < mb_mapping->offset_bits ? address : address + nb);
908 } 919 }
909 rsp_length = response_exception( 920 rsp_length = response_exception(
910 ctx, &sft, 921 ctx, &sft,
911 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 922 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
912 } else { 923 } else {
913 /* 6 = byte count */ 924 /* 6 = byte count */
914 - modbus_set_bits_from_bytes(mb_mapping->tab_bits, address, nb, &req[offset + 6]); 925 + modbus_set_bits_from_bytes(mb_mapping->tab_bits, addr, nb, &req[offset + 6]);
915 926
916 rsp_length = ctx->backend->build_response_basis(&sft, rsp); 927 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
917 /* 4 to copy the bit address (2) and the quantity of bits */ 928 /* 4 to copy the bit address (2) and the quantity of bits */
@@ -922,6 +933,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -922,6 +933,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
922 break; 933 break;
923 case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: { 934 case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: {
924 int nb = (req[offset + 3] << 8) + req[offset + 4]; 935 int nb = (req[offset + 3] << 8) + req[offset + 4];
  936 + int addr = address - mb_mapping->offset_registers;
  937 +
925 if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) { 938 if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) {
926 if (ctx->debug) { 939 if (ctx->debug) {
927 fprintf(stderr, 940 fprintf(stderr,
@@ -936,17 +949,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -936,17 +949,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
936 rsp_length = response_exception( 949 rsp_length = response_exception(
937 ctx, &sft, 950 ctx, &sft,
938 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 951 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
939 - } else if ((address + nb) > mb_mapping->nb_registers) { 952 + } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) {
940 if (ctx->debug) { 953 if (ctx->debug) {
941 fprintf(stderr, "Illegal data address 0x%0X in write_registers\n", 954 fprintf(stderr, "Illegal data address 0x%0X in write_registers\n",
942 - address + nb); 955 + address < mb_mapping->offset_registers ? address : address + nb);
943 } 956 }
944 rsp_length = response_exception( 957 rsp_length = response_exception(
945 ctx, &sft, 958 ctx, &sft,
946 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 959 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
947 } else { 960 } else {
948 int i, j; 961 int i, j;
949 - for (i = address, j = 6; i < address + nb; i++, j += 2) { 962 + for (i = addr, j = 6; i < addr + nb; i++, j += 2) {
950 /* 6 and 7 = first value */ 963 /* 6 and 7 = first value */
951 mb_mapping->tab_registers[i] = 964 mb_mapping->tab_registers[i] =
952 (req[offset + j] << 8) + req[offset + j + 1]; 965 (req[offset + j] << 8) + req[offset + j + 1];
@@ -983,8 +996,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -983,8 +996,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
983 errno = ENOPROTOOPT; 996 errno = ENOPROTOOPT;
984 return -1; 997 return -1;
985 break; 998 break;
986 - case MODBUS_FC_MASK_WRITE_REGISTER:  
987 - if (address >= mb_mapping->nb_registers) { 999 + case MODBUS_FC_MASK_WRITE_REGISTER: {
  1000 + int addr = address - mb_mapping->offset_registers;
  1001 +
  1002 + if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) {
988 if (ctx->debug) { 1003 if (ctx->debug) {
989 fprintf(stderr, "Illegal data address 0x%0X in write_register\n", 1004 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
990 address); 1005 address);
@@ -993,21 +1008,24 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -993,21 +1008,24 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
993 ctx, &sft, 1008 ctx, &sft,
994 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 1009 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
995 } else { 1010 } else {
996 - uint16_t data = mb_mapping->tab_registers[address]; 1011 + uint16_t data = mb_mapping->tab_registers[addr];
997 uint16_t and = (req[offset + 3] << 8) + req[offset + 4]; 1012 uint16_t and = (req[offset + 3] << 8) + req[offset + 4];
998 uint16_t or = (req[offset + 5] << 8) + req[offset + 6]; 1013 uint16_t or = (req[offset + 5] << 8) + req[offset + 6];
999 1014
1000 data = (data & and) | (or & (~and)); 1015 data = (data & and) | (or & (~and));
1001 - mb_mapping->tab_registers[address] = data; 1016 + mb_mapping->tab_registers[addr] = data;
1002 memcpy(rsp, req, req_length); 1017 memcpy(rsp, req, req_length);
1003 rsp_length = req_length; 1018 rsp_length = req_length;
1004 } 1019 }
  1020 + }
1005 break; 1021 break;
1006 case MODBUS_FC_WRITE_AND_READ_REGISTERS: { 1022 case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
1007 int nb = (req[offset + 3] << 8) + req[offset + 4]; 1023 int nb = (req[offset + 3] << 8) + req[offset + 4];
1008 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; 1024 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
1009 int nb_write = (req[offset + 7] << 8) + req[offset + 8]; 1025 int nb_write = (req[offset + 7] << 8) + req[offset + 8];
1010 int nb_write_bytes = req[offset + 9]; 1026 int nb_write_bytes = req[offset + 9];
  1027 + int addr = address - mb_mapping->offset_registers;
  1028 + int addr_write = address_write - mb_mapping->offset_registers;
1011 1029
1012 if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write || 1030 if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
1013 nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb || 1031 nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb ||
@@ -1023,12 +1041,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1023,12 +1041,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1023 rsp_length = response_exception( 1041 rsp_length = response_exception(
1024 ctx, &sft, 1042 ctx, &sft,
1025 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp); 1043 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
1026 - } else if ((address + nb) > mb_mapping->nb_registers ||  
1027 - (address_write + nb_write) > mb_mapping->nb_registers) { 1044 + } else if (address < mb_mapping->offset_registers ||
  1045 + (addr + nb) > mb_mapping->nb_registers ||
  1046 + address_write < mb_mapping->offset_registers ||
  1047 + (addr_write + nb_write) > mb_mapping->nb_registers) {
1028 if (ctx->debug) { 1048 if (ctx->debug) {
1029 fprintf(stderr, 1049 fprintf(stderr,
1030 "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n", 1050 "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n",
1031 - address + nb, address_write + nb_write); 1051 + address < mb_mapping->offset_registers ? address : address + nb,
  1052 + address_write < mb_mapping->offset_registers ? address_write : address_write + nb_write);
1032 } 1053 }
1033 rsp_length = response_exception(ctx, &sft, 1054 rsp_length = response_exception(ctx, &sft,
1034 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 1055 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
@@ -1039,13 +1060,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1039,13 +1060,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1039 1060
1040 /* Write first. 1061 /* Write first.
1041 10 and 11 are the offset of the first values to write */ 1062 10 and 11 are the offset of the first values to write */
1042 - for (i = address_write, j = 10; i < address_write + nb_write; i++, j += 2) { 1063 + for (i = addr_write, j = 10; i < addr_write + nb_write; i++, j += 2) {
1043 mb_mapping->tab_registers[i] = 1064 mb_mapping->tab_registers[i] =
1044 (req[offset + j] << 8) + req[offset + j + 1]; 1065 (req[offset + j] << 8) + req[offset + j + 1];
1045 } 1066 }
1046 1067
1047 /* and read the data for the response */ 1068 /* and read the data for the response */
1048 - for (i = address; i < address + nb; i++) { 1069 + for (i = addr; i < addr + nb; i++) {
1049 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; 1070 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
1050 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; 1071 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
1051 } 1072 }
@@ -1786,10 +1807,12 @@ int modbus_set_debug(modbus_t *ctx, int flag) @@ -1786,10 +1807,12 @@ int modbus_set_debug(modbus_t *ctx, int flag)
1786 /* Allocates 4 arrays to store bits, input bits, registers and inputs 1807 /* Allocates 4 arrays to store bits, input bits, registers and inputs
1787 registers. The pointers are stored in modbus_mapping structure. 1808 registers. The pointers are stored in modbus_mapping structure.
1788 1809
1789 - The modbus_mapping_new() function shall return the new allocated structure if 1810 + The modbus_mapping_offset_new() function shall return the new allocated structure if
1790 successful. Otherwise it shall return NULL and set errno to ENOMEM. */ 1811 successful. Otherwise it shall return NULL and set errno to ENOMEM. */
1791 -modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,  
1792 - int nb_registers, int nb_input_registers) 1812 +modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits,
  1813 + int nb_input_bits, int offset_input_bits,
  1814 + int nb_registers, int offset_registers,
  1815 + int nb_input_registers, int offset_input_registers)
1793 { 1816 {
1794 modbus_mapping_t *mb_mapping; 1817 modbus_mapping_t *mb_mapping;
1795 1818
@@ -1800,6 +1823,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, @@ -1800,6 +1823,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1800 1823
1801 /* 0X */ 1824 /* 0X */
1802 mb_mapping->nb_bits = nb_bits; 1825 mb_mapping->nb_bits = nb_bits;
  1826 + mb_mapping->offset_bits = offset_bits;
1803 if (nb_bits == 0) { 1827 if (nb_bits == 0) {
1804 mb_mapping->tab_bits = NULL; 1828 mb_mapping->tab_bits = NULL;
1805 } else { 1829 } else {
@@ -1815,6 +1839,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, @@ -1815,6 +1839,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1815 1839
1816 /* 1X */ 1840 /* 1X */
1817 mb_mapping->nb_input_bits = nb_input_bits; 1841 mb_mapping->nb_input_bits = nb_input_bits;
  1842 + mb_mapping->offset_input_bits = offset_input_bits;
1818 if (nb_input_bits == 0) { 1843 if (nb_input_bits == 0) {
1819 mb_mapping->tab_input_bits = NULL; 1844 mb_mapping->tab_input_bits = NULL;
1820 } else { 1845 } else {
@@ -1830,6 +1855,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, @@ -1830,6 +1855,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1830 1855
1831 /* 4X */ 1856 /* 4X */
1832 mb_mapping->nb_registers = nb_registers; 1857 mb_mapping->nb_registers = nb_registers;
  1858 + mb_mapping->offset_registers = offset_registers;
1833 if (nb_registers == 0) { 1859 if (nb_registers == 0) {
1834 mb_mapping->tab_registers = NULL; 1860 mb_mapping->tab_registers = NULL;
1835 } else { 1861 } else {
@@ -1846,6 +1872,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, @@ -1846,6 +1872,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1846 1872
1847 /* 3X */ 1873 /* 3X */
1848 mb_mapping->nb_input_registers = nb_input_registers; 1874 mb_mapping->nb_input_registers = nb_input_registers;
  1875 + mb_mapping->offset_input_registers = offset_input_registers;
1849 if (nb_input_registers == 0) { 1876 if (nb_input_registers == 0) {
1850 mb_mapping->tab_input_registers = NULL; 1877 mb_mapping->tab_input_registers = NULL;
1851 } else { 1878 } else {
@@ -1865,6 +1892,12 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, @@ -1865,6 +1892,12 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1865 return mb_mapping; 1892 return mb_mapping;
1866 } 1893 }
1867 1894
  1895 +modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
  1896 + int nb_registers, int nb_input_registers)
  1897 +{
  1898 + return modbus_mapping_offset_new(nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers, 0);
  1899 +}
  1900 +
1868 /* Frees the 4 arrays */ 1901 /* Frees the 4 arrays */
1869 void modbus_mapping_free(modbus_mapping_t *mb_mapping) 1902 void modbus_mapping_free(modbus_mapping_t *mb_mapping)
1870 { 1903 {
src/modbus.h
@@ -156,9 +156,13 @@ typedef struct _modbus modbus_t; @@ -156,9 +156,13 @@ typedef struct _modbus modbus_t;
156 156
157 typedef struct { 157 typedef struct {
158 int nb_bits; 158 int nb_bits;
  159 + int offset_bits;
159 int nb_input_bits; 160 int nb_input_bits;
  161 + int offset_input_bits;
160 int nb_input_registers; 162 int nb_input_registers;
  163 + int offset_input_registers;
161 int nb_registers; 164 int nb_registers;
  165 + int offset_registers;
162 uint8_t *tab_bits; 166 uint8_t *tab_bits;
163 uint8_t *tab_input_bits; 167 uint8_t *tab_input_bits;
164 uint16_t *tab_input_registers; 168 uint16_t *tab_input_registers;
@@ -209,6 +213,10 @@ MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, in @@ -209,6 +213,10 @@ MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, in
209 uint16_t *dest); 213 uint16_t *dest);
210 MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); 214 MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
211 215
  216 +MODBUS_API modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits,
  217 + int nb_input_bits, int offset_input_bits,
  218 + int nb_registers, int offset_registers,
  219 + int nb_input_registers, int offset_input_registers);
212 MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, 220 MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
213 int nb_registers, int nb_input_registers); 221 int nb_registers, int nb_input_registers);
214 MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); 222 MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);