Kaynağa Gözat

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>
Michael Heimpold 11 yıl önce
ebeveyn
işleme
52ab1bbea7
5 değiştirilmiş dosya ile 152 ekleme ve 37 silme
  1. 1 0
      doc/Makefile.am
  2. 4 1
      doc/modbus_mapping_new.txt
  3. 70 0
      doc/modbus_mapping_offset_new.txt
  4. 69 36
      src/modbus.c
  5. 8 0
      src/modbus.h

+ 1 - 0
doc/Makefile.am

@@ -12,6 +12,7 @@ TXT3 = \
         modbus_get_socket.txt \
         modbus_get_socket.txt \
         modbus_mapping_free.txt \
         modbus_mapping_free.txt \
         modbus_mapping_new.txt \
         modbus_mapping_new.txt \
+        modbus_mapping_offset_new.txt \
         modbus_mask_write_register.txt \
         modbus_mask_write_register.txt \
         modbus_new_rtu.txt \
         modbus_new_rtu.txt \
         modbus_new_tcp_pi.txt \
         modbus_new_tcp_pi.txt \

+ 4 - 1
doc/modbus_mapping_new.txt

@@ -18,6 +18,9 @@ The *modbus_mapping_new()* function shall allocate four arrays to store bits,
 input bits, registers and inputs registers. The pointers are stored in
 input bits, registers and inputs registers. The pointers are stored in
 modbus_mapping_t structure. All values of the arrays are initialized to zero.
 modbus_mapping_t structure. All values of the arrays are initialized to zero.
 
 
+This function is equivalent to a call of the _modbus_mapping_offset_new()_ function
+with all offsets set to zero.
+
 If it isn't necessary to allocate an array for a specific type of data, you can
 If it isn't necessary to allocate an array for a specific type of data, you can
 pass the zero value in argument, the associated pointer will be NULL.
 pass the zero value in argument, the associated pointer will be NULL.
 
 
@@ -40,7 +43,7 @@ EXAMPLE
 -------
 -------
 [source,c]
 [source,c]
 -------------------
 -------------------
-/* The fist value of each array is accessible from the 0 address. */
+/* The first value of each array is accessible from the 0 address. */
 mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB,
 mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB,
                                 INPUT_BITS_ADDRESS + INPUT_BITS_NB,
                                 INPUT_BITS_ADDRESS + INPUT_BITS_NB,
                                 REGISTERS_ADDRESS + REGISTERS_NB,
                                 REGISTERS_ADDRESS + REGISTERS_NB,

+ 70 - 0
doc/modbus_mapping_offset_new.txt

@@ -0,0 +1,70 @@
+modbus_mapping_offset_new(3)
+============================
+
+
+NAME
+----
+modbus_mapping_offset_new - allocate four arrays of bits and registers
+
+
+SYNOPSIS
+--------
+*modbus_mapping_t* modbus_mapping_new(int 'nb_bits', int 'offset_bits',
+                                      int 'nb_input_bits', int 'offset_input_bits',
+                                      int 'nb_registers', int 'offset_registers',
+                                      int 'nb_input_registers', int 'offset_input_registers');*
+
+
+DESCRIPTION
+-----------
+The _modbus_mapping_offset_new()_ function shall allocate four arrays to store bits,
+input bits, registers and inputs registers. The pointers are stored in
+modbus_mapping_t structure. All values of the arrays are initialized to zero.
+
+The different offsets make it possible to place the mapping at any address in
+each address space.
+
+If it isn't necessary to allocate an array for a specific type of data, you can
+pass the zero value in argument, the associated pointer will be NULL.
+
+This function is convenient to handle requests in a Modbus server/slave.
+
+
+RETURN VALUE
+------------
+The _modbus_mapping_offset_new()_ function shall return the new allocated structure if
+successful. Otherwise it shall return NULL and set errno.
+
+
+ERRORS
+------
+ENOMEM::
+Not enough memory
+
+
+EXAMPLE
+-------
+[source,c]
+-------------------
+/* The first value of each array is accessible at address 4. */
+mb_mapping = modbus_mapping_offset_new(BITS_ADDRESS + BITS_NB, 4,
+                                INPUT_BITS_ADDRESS + INPUT_BITS_NB, 4,
+                                REGISTERS_ADDRESS + REGISTERS_NB, 4,
+                                INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB, 4);
+if (mb_mapping == NULL) {
+    fprintf(stderr, "Failed to allocate the mapping: %s\n",
+            modbus_strerror(errno));
+    modbus_free(ctx);
+    return -1;
+}
+-------------------
+
+SEE ALSO
+--------
+linkmb:modbus_mapping_free[3]
+
+
+AUTHORS
+-------
+The libmodbus documentation was written by Stéphane Raimbault
+<stephane.raimbault@gmail.com>

+ 69 - 36
src/modbus.c

@@ -706,6 +706,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
     switch (function) {
     switch (function) {
     case MODBUS_FC_READ_COILS: {
     case MODBUS_FC_READ_COILS: {
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_bits;
 
 
         if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
         if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
@@ -718,10 +719,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_bits) {
+        } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in read_bits\n",
                 fprintf(stderr, "Illegal data address 0x%0X in read_bits\n",
-                        address + nb);
+                        address < mb_mapping->offset_bits ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
@@ -729,7 +730,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         } else {
         } else {
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
             rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
-            rsp_length = response_io_status(address, nb,
+            rsp_length = response_io_status(addr, nb,
                                             mb_mapping->tab_bits,
                                             mb_mapping->tab_bits,
                                             rsp, rsp_length);
                                             rsp, rsp_length);
         }
         }
@@ -739,6 +740,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         /* Similar to coil status (but too many arguments to use a
         /* Similar to coil status (but too many arguments to use a
          * function) */
          * function) */
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_input_bits;
 
 
         if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
         if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
@@ -751,10 +753,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_input_bits) {
+        } else if (address < mb_mapping->offset_input_bits || (addr + nb) > mb_mapping->nb_input_bits) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n",
                 fprintf(stderr, "Illegal data address 0x%0X in read_input_bits\n",
-                        address + nb);
+                        address < mb_mapping->offset_input_bits ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
@@ -762,7 +764,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         } else {
         } else {
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
             rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
-            rsp_length = response_io_status(address, nb,
+            rsp_length = response_io_status(addr, nb,
                                             mb_mapping->tab_input_bits,
                                             mb_mapping->tab_input_bits,
                                             rsp, rsp_length);
                                             rsp, rsp_length);
         }
         }
@@ -770,6 +772,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         break;
         break;
     case MODBUS_FC_READ_HOLDING_REGISTERS: {
     case MODBUS_FC_READ_HOLDING_REGISTERS: {
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_registers;
 
 
         if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
         if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
@@ -782,10 +785,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_registers) {
+        } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in read_registers\n",
                 fprintf(stderr, "Illegal data address 0x%0X in read_registers\n",
-                        address + nb);
+                        address < mb_mapping->offset_registers ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
@@ -795,7 +798,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
 
 
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp[rsp_length++] = nb << 1;
             rsp[rsp_length++] = nb << 1;
-            for (i = address; i < address + nb; i++) {
+            for (i = addr; i < addr + nb; i++) {
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
             }
             }
@@ -806,6 +809,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         /* Similar to holding registers (but too many arguments to use a
         /* Similar to holding registers (but too many arguments to use a
          * function) */
          * function) */
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_input_registers;
 
 
         if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
         if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
@@ -818,10 +822,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_input_registers) {
+        } else if (address < mb_mapping->offset_input_registers || (addr + nb) > mb_mapping->nb_input_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n",
                 fprintf(stderr, "Illegal data address 0x%0X in read_input_registers\n",
-                        address + nb);
+                        address < mb_mapping->offset_input_registers ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
@@ -831,15 +835,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
 
 
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp[rsp_length++] = nb << 1;
             rsp[rsp_length++] = nb << 1;
-            for (i = address; i < address + nb; i++) {
+            for (i = addr; i < addr + nb; i++) {
                 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF;
                 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] & 0xFF;
             }
             }
         }
         }
     }
     }
         break;
         break;
-    case MODBUS_FC_WRITE_SINGLE_COIL:
-        if (address >= mb_mapping->nb_bits) {
+    case MODBUS_FC_WRITE_SINGLE_COIL: {
+        int addr = address - mb_mapping->offset_bits;
+
+        if (address < mb_mapping->offset_bits || addr >= mb_mapping->nb_bits) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr,
                 fprintf(stderr,
                         "Illegal data address 0x%0X in write_bit\n",
                         "Illegal data address 0x%0X in write_bit\n",
@@ -852,7 +858,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             int data = (req[offset + 3] << 8) + req[offset + 4];
             int data = (req[offset + 3] << 8) + req[offset + 4];
 
 
             if (data == 0xFF00 || data == 0x0) {
             if (data == 0xFF00 || data == 0x0) {
-                mb_mapping->tab_bits[address] = (data) ? ON : OFF;
+                mb_mapping->tab_bits[addr] = (data) ? ON : OFF;
                 memcpy(rsp, req, req_length);
                 memcpy(rsp, req, req_length);
                 rsp_length = req_length;
                 rsp_length = req_length;
             } else {
             } else {
@@ -866,9 +872,12 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
                     MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                     MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
             }
             }
         }
         }
+    }
         break;
         break;
-    case MODBUS_FC_WRITE_SINGLE_REGISTER:
-        if (address >= mb_mapping->nb_registers) {
+    case MODBUS_FC_WRITE_SINGLE_REGISTER: {
+        int addr = address - mb_mapping->offset_registers;
+
+        if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
                 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
                         address);
                         address);
@@ -879,13 +888,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         } else {
         } else {
             int data = (req[offset + 3] << 8) + req[offset + 4];
             int data = (req[offset + 3] << 8) + req[offset + 4];
 
 
-            mb_mapping->tab_registers[address] = data;
+            mb_mapping->tab_registers[addr] = data;
             memcpy(rsp, req, req_length);
             memcpy(rsp, req, req_length);
             rsp_length = req_length;
             rsp_length = req_length;
         }
         }
+    }
         break;
         break;
     case MODBUS_FC_WRITE_MULTIPLE_COILS: {
     case MODBUS_FC_WRITE_MULTIPLE_COILS: {
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_bits;
 
 
         if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) {
         if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
@@ -901,17 +912,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_bits) {
+        } else if (address < mb_mapping->offset_bits || (addr + nb) > mb_mapping->nb_bits) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in write_bits\n",
                 fprintf(stderr, "Illegal data address 0x%0X in write_bits\n",
-                        address + nb);
+                        address < mb_mapping->offset_bits ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
         } else {
         } else {
             /* 6 = byte count */
             /* 6 = byte count */
-            modbus_set_bits_from_bytes(mb_mapping->tab_bits, address, nb, &req[offset + 6]);
+            modbus_set_bits_from_bytes(mb_mapping->tab_bits, addr, nb, &req[offset + 6]);
 
 
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             rsp_length = ctx->backend->build_response_basis(&sft, rsp);
             /* 4 to copy the bit address (2) and the quantity of bits */
             /* 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,
         break;
         break;
     case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: {
     case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: {
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
+        int addr = address - mb_mapping->offset_registers;
+
         if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) {
         if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr,
                 fprintf(stderr,
@@ -936,17 +949,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_registers) {
+        } else if (address < mb_mapping->offset_registers || (addr + nb) > mb_mapping->nb_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in write_registers\n",
                 fprintf(stderr, "Illegal data address 0x%0X in write_registers\n",
-                        address + nb);
+                        address < mb_mapping->offset_registers ? address : address + nb);
             }
             }
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
         } else {
         } else {
             int i, j;
             int i, j;
-            for (i = address, j = 6; i < address + nb; i++, j += 2) {
+            for (i = addr, j = 6; i < addr + nb; i++, j += 2) {
                 /* 6 and 7 = first value */
                 /* 6 and 7 = first value */
                 mb_mapping->tab_registers[i] =
                 mb_mapping->tab_registers[i] =
                     (req[offset + j] << 8) + req[offset + j + 1];
                     (req[offset + j] << 8) + req[offset + j + 1];
@@ -983,8 +996,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
         errno = ENOPROTOOPT;
         errno = ENOPROTOOPT;
         return -1;
         return -1;
         break;
         break;
-    case MODBUS_FC_MASK_WRITE_REGISTER:
-        if (address >= mb_mapping->nb_registers) {
+    case MODBUS_FC_MASK_WRITE_REGISTER: {
+        int addr = address - mb_mapping->offset_registers;
+
+        if (address < mb_mapping->offset_registers || addr >= mb_mapping->nb_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
                 fprintf(stderr, "Illegal data address 0x%0X in write_register\n",
                         address);
                         address);
@@ -993,21 +1008,24 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
         } else {
         } else {
-            uint16_t data = mb_mapping->tab_registers[address];
+            uint16_t data = mb_mapping->tab_registers[addr];
             uint16_t and = (req[offset + 3] << 8) + req[offset + 4];
             uint16_t and = (req[offset + 3] << 8) + req[offset + 4];
             uint16_t or = (req[offset + 5] << 8) + req[offset + 6];
             uint16_t or = (req[offset + 5] << 8) + req[offset + 6];
 
 
             data = (data & and) | (or & (~and));
             data = (data & and) | (or & (~and));
-            mb_mapping->tab_registers[address] = data;
+            mb_mapping->tab_registers[addr] = data;
             memcpy(rsp, req, req_length);
             memcpy(rsp, req, req_length);
             rsp_length = req_length;
             rsp_length = req_length;
         }
         }
+    }
         break;
         break;
     case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
     case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         int nb = (req[offset + 3] << 8) + req[offset + 4];
         uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
         uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
         int nb_write = (req[offset + 7] << 8) + req[offset + 8];
         int nb_write = (req[offset + 7] << 8) + req[offset + 8];
         int nb_write_bytes = req[offset + 9];
         int nb_write_bytes = req[offset + 9];
+        int addr = address - mb_mapping->offset_registers;
+        int addr_write = address_write - mb_mapping->offset_registers;
 
 
         if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
         if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
             nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb ||
             nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb ||
@@ -1023,12 +1041,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
             rsp_length = response_exception(
             rsp_length = response_exception(
                 ctx, &sft,
                 ctx, &sft,
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
                 MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp);
-        } else if ((address + nb) > mb_mapping->nb_registers ||
-                   (address_write + nb_write) > mb_mapping->nb_registers) {
+        } else if (address < mb_mapping->offset_registers ||
+                   (addr + nb) > mb_mapping->nb_registers ||
+                   address_write < mb_mapping->offset_registers ||
+                   (addr_write + nb_write) > mb_mapping->nb_registers) {
             if (ctx->debug) {
             if (ctx->debug) {
                 fprintf(stderr,
                 fprintf(stderr,
                         "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n",
                         "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n",
-                        address + nb, address_write + nb_write);
+                        address < mb_mapping->offset_registers ? address : address + nb,
+                        address_write < mb_mapping->offset_registers ? address_write : address_write + nb_write);
             }
             }
             rsp_length = response_exception(ctx, &sft,
             rsp_length = response_exception(ctx, &sft,
                                             MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
                                             MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
@@ -1039,13 +1060,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
 
 
             /* Write first.
             /* Write first.
                10 and 11 are the offset of the first values to write */
                10 and 11 are the offset of the first values to write */
-            for (i = address_write, j = 10; i < address_write + nb_write; i++, j += 2) {
+            for (i = addr_write, j = 10; i < addr_write + nb_write; i++, j += 2) {
                 mb_mapping->tab_registers[i] =
                 mb_mapping->tab_registers[i] =
                     (req[offset + j] << 8) + req[offset + j + 1];
                     (req[offset + j] << 8) + req[offset + j + 1];
             }
             }
 
 
             /* and read the data for the response */
             /* and read the data for the response */
-            for (i = address; i < address + nb; i++) {
+            for (i = addr; i < addr + nb; i++) {
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
                 rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
             }
             }
@@ -1786,10 +1807,12 @@ int modbus_set_debug(modbus_t *ctx, int flag)
 /* Allocates 4 arrays to store bits, input bits, registers and inputs
 /* Allocates 4 arrays to store bits, input bits, registers and inputs
    registers. The pointers are stored in modbus_mapping structure.
    registers. The pointers are stored in modbus_mapping structure.
 
 
-   The modbus_mapping_new() function shall return the new allocated structure if
+   The modbus_mapping_offset_new() function shall return the new allocated structure if
    successful. Otherwise it shall return NULL and set errno to ENOMEM. */
    successful. Otherwise it shall return NULL and set errno to ENOMEM. */
-modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
-                                     int nb_registers, int nb_input_registers)
+modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits,
+                                            int nb_input_bits, int offset_input_bits,
+                                            int nb_registers, int offset_registers,
+                                            int nb_input_registers, int offset_input_registers)
 {
 {
     modbus_mapping_t *mb_mapping;
     modbus_mapping_t *mb_mapping;
 
 
@@ -1800,6 +1823,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
 
 
     /* 0X */
     /* 0X */
     mb_mapping->nb_bits = nb_bits;
     mb_mapping->nb_bits = nb_bits;
+    mb_mapping->offset_bits = offset_bits;
     if (nb_bits == 0) {
     if (nb_bits == 0) {
         mb_mapping->tab_bits = NULL;
         mb_mapping->tab_bits = NULL;
     } else {
     } else {
@@ -1815,6 +1839,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
 
 
     /* 1X */
     /* 1X */
     mb_mapping->nb_input_bits = nb_input_bits;
     mb_mapping->nb_input_bits = nb_input_bits;
+    mb_mapping->offset_input_bits = offset_input_bits;
     if (nb_input_bits == 0) {
     if (nb_input_bits == 0) {
         mb_mapping->tab_input_bits = NULL;
         mb_mapping->tab_input_bits = NULL;
     } else {
     } else {
@@ -1830,6 +1855,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
 
 
     /* 4X */
     /* 4X */
     mb_mapping->nb_registers = nb_registers;
     mb_mapping->nb_registers = nb_registers;
+    mb_mapping->offset_registers = offset_registers;
     if (nb_registers == 0) {
     if (nb_registers == 0) {
         mb_mapping->tab_registers = NULL;
         mb_mapping->tab_registers = NULL;
     } else {
     } else {
@@ -1846,6 +1872,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
 
 
     /* 3X */
     /* 3X */
     mb_mapping->nb_input_registers = nb_input_registers;
     mb_mapping->nb_input_registers = nb_input_registers;
+    mb_mapping->offset_input_registers = offset_input_registers;
     if (nb_input_registers == 0) {
     if (nb_input_registers == 0) {
         mb_mapping->tab_input_registers = NULL;
         mb_mapping->tab_input_registers = NULL;
     } else {
     } else {
@@ -1865,6 +1892,12 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
     return mb_mapping;
     return mb_mapping;
 }
 }
 
 
+modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
+                                     int nb_registers, int nb_input_registers)
+{
+    return modbus_mapping_offset_new(nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers, 0);
+}
+
 /* Frees the 4 arrays */
 /* Frees the 4 arrays */
 void modbus_mapping_free(modbus_mapping_t *mb_mapping)
 void modbus_mapping_free(modbus_mapping_t *mb_mapping)
 {
 {

+ 8 - 0
src/modbus.h

@@ -156,9 +156,13 @@ typedef struct _modbus modbus_t;
 
 
 typedef struct {
 typedef struct {
     int nb_bits;
     int nb_bits;
+    int offset_bits;
     int nb_input_bits;
     int nb_input_bits;
+    int offset_input_bits;
     int nb_input_registers;
     int nb_input_registers;
+    int offset_input_registers;
     int nb_registers;
     int nb_registers;
+    int offset_registers;
     uint8_t *tab_bits;
     uint8_t *tab_bits;
     uint8_t *tab_input_bits;
     uint8_t *tab_input_bits;
     uint16_t *tab_input_registers;
     uint16_t *tab_input_registers;
@@ -209,6 +213,10 @@ MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, in
                                                uint16_t *dest);
                                                uint16_t *dest);
 MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
 MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
 
 
+MODBUS_API modbus_mapping_t* modbus_mapping_offset_new(int nb_bits, int offset_bits,
+                                            int nb_input_bits, int offset_input_bits,
+                                            int nb_registers, int offset_registers,
+                                            int nb_input_registers, int offset_input_registers);
 MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
 MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
                                             int nb_registers, int nb_input_registers);
                                             int nb_registers, int nb_input_registers);
 MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);