Commit 9a2733e7ecc2c622704753fae7fbf14521de10ea

Authored by Hannu Vuolasaho
Committed by Stéphane Raimbault
1 parent a2e16a16

New read and write registers function

src/modbus-private.h
@@ -61,6 +61,7 @@ MODBUS_BEGIN_DECLS @@ -61,6 +61,7 @@ MODBUS_BEGIN_DECLS
61 #define FC_WRITE_MULTIPLE_COILS 0x0F 61 #define FC_WRITE_MULTIPLE_COILS 0x0F
62 #define FC_WRITE_MULTIPLE_REGISTERS 0x10 62 #define FC_WRITE_MULTIPLE_REGISTERS 0x10
63 #define FC_REPORT_SLAVE_ID 0x11 63 #define FC_REPORT_SLAVE_ID 0x11
  64 +#define FC_READ_AND_WRITE_REGISTERS 0x17
64 65
65 typedef enum { RTU=0, TCP } type_com_t; 66 typedef enum { RTU=0, TCP } type_com_t;
66 67
src/modbus.c
@@ -264,6 +264,7 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req) @@ -264,6 +264,7 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req)
264 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0); 264 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
265 } 265 }
266 break; 266 break;
  267 + case FC_READ_AND_WRITE_REGISTERS:
267 case FC_READ_HOLDING_REGISTERS: 268 case FC_READ_HOLDING_REGISTERS:
268 case FC_READ_INPUT_REGISTERS: 269 case FC_READ_INPUT_REGISTERS:
269 /* Header + 2 * nb values */ 270 /* Header + 2 * nb values */
@@ -512,6 +513,8 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type) @@ -512,6 +513,8 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
512 length = 0; 513 length = 0;
513 else 514 else
514 length = 1; 515 length = 1;
  516 + } else if (function == FC_READ_AND_WRITE_REGISTERS) {
  517 + length = 9;
515 } else { 518 } else {
516 length = 0; 519 length = 0;
517 } 520 }
@@ -529,6 +532,8 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) @@ -529,6 +532,8 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg)
529 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5]; 532 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5];
530 } else if (function == FC_REPORT_SLAVE_ID) { 533 } else if (function == FC_REPORT_SLAVE_ID) {
531 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1]; 534 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1];
  535 + } else if (function == FC_READ_AND_WRITE_REGISTERS) {
  536 + length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 9];
532 } else 537 } else
533 length = 0; 538 length = 0;
534 539
@@ -789,6 +794,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -789,6 +794,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
789 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0); 794 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
790 rsp_nb_value = rsp[offset + 1]; 795 rsp_nb_value = rsp[offset + 1];
791 break; 796 break;
  797 + case FC_READ_AND_WRITE_REGISTERS:
792 case FC_READ_HOLDING_REGISTERS: 798 case FC_READ_HOLDING_REGISTERS:
793 case FC_READ_INPUT_REGISTERS: 799 case FC_READ_INPUT_REGISTERS:
794 /* Read functions 1 value = 2 bytes */ 800 /* Read functions 1 value = 2 bytes */
@@ -1130,6 +1136,40 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1130,6 +1136,40 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1130 errno = ENOPROTOOPT; 1136 errno = ENOPROTOOPT;
1131 return -1; 1137 return -1;
1132 break; 1138 break;
  1139 +
  1140 + case FC_READ_AND_WRITE_REGISTERS: {
  1141 + int nb = (req[offset + 3] << 8) + req[offset + 4];
  1142 + uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
  1143 + int nb_write = (req[offset + 7] << 8) + req[offset + 8];
  1144 +
  1145 + if ((address + nb) > mb_mapping->nb_registers &&
  1146 + (address_write + nb_write) > mb_mapping->nb_registers) {
  1147 + if (ctx->debug) {
  1148 + fprintf(stderr,
  1149 + "Illegal data read address %0X or write address %0X in read_and_write_registers\n",
  1150 + address + nb, address_write + nb_write);
  1151 + }
  1152 + rsp_length = response_exception(ctx, &sft,
  1153 + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
  1154 + } else {
  1155 + int i, j;
  1156 + rsp_length = build_response_basis(ctx, &sft, rsp);
  1157 + rsp[rsp_length++] = nb << 1;
  1158 +
  1159 + for (i = address; i < address + nb; i++) {
  1160 + rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
  1161 + rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
  1162 + }
  1163 +
  1164 + /* 10 and 11 = first value */
  1165 + for (i = address_write, j = 10; i < address_write + nb_write; i++, j += 2) {
  1166 + mb_mapping->tab_registers[i] =
  1167 + (req[offset + j] << 8) + req[offset + j + 1];
  1168 + }
  1169 + }
  1170 + }
  1171 + break;
  1172 +
1133 default: 1173 default:
1134 rsp_length = response_exception(ctx, &sft, 1174 rsp_length = response_exception(ctx, &sft,
1135 MODBUS_EXCEPTION_ILLEGAL_FUNCTION, 1175 MODBUS_EXCEPTION_ILLEGAL_FUNCTION,
@@ -1445,8 +1485,73 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data @@ -1445,8 +1485,73 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data
1445 return rc; 1485 return rc;
1446 } 1486 }
1447 1487
  1488 +/* Read multiple registers from remote device to dest array and write multiple
  1489 + registers to remote device from data array. */
  1490 +int modbus_read_and_write_holding_registers(modbus_t *ctx,
  1491 + int read_addr, int read_nb, uint16_t *dest,
  1492 + int write_addr, int write_nb, const uint16_t *data)
  1493 +{
  1494 + int rc;
  1495 + int req_length;
  1496 + int i;
  1497 + int byte_count;
  1498 + uint8_t req[MAX_MESSAGE_LENGTH];
  1499 + uint8_t rsp[MAX_MESSAGE_LENGTH];
  1500 +
  1501 + if (read_nb > MODBUS_MAX_READ_REGISTERS) {
  1502 + if (ctx->debug) {
  1503 + fprintf(stderr,
  1504 + "ERROR Too many holding registers requested (%d > %d)\n",
  1505 + read_nb, MODBUS_MAX_READ_REGISTERS);
  1506 + }
  1507 + errno = EMBMDATA;
  1508 + return -1;
  1509 + }
  1510 +
  1511 + if (write_nb > MODBUS_MAX_RW_WRITE_REGISTERS) {
  1512 + if (ctx->debug) {
  1513 + fprintf(stderr,
  1514 + "ERROR Too many holding registers wrote (%d > %d)\n",
  1515 + write_nb, MODBUS_MAX_RW_WRITE_REGISTERS);
  1516 + }
  1517 + errno = EMBMDATA;
  1518 + return -1;
  1519 + }
  1520 + req_length = build_request_basis(ctx, FC_READ_AND_WRITE_REGISTERS,
  1521 + read_addr, read_nb, req);
  1522 +
  1523 + req[req_length++] = write_addr >> 8;
  1524 + req[req_length++] = write_addr & 0x00ff;
  1525 + req[req_length++] = write_nb >> 8;
  1526 + req[req_length++] = write_nb & 0x00ff;
  1527 + byte_count = write_nb * 2;
  1528 + req[req_length++] = byte_count;
  1529 +
  1530 + for (i = 0; i < write_nb; i++) {
  1531 + req[req_length++] = data[i] >> 8;
  1532 + req[req_length++] = data[i] & 0x00FF;
  1533 + }
  1534 +
  1535 + rc = send_msg(ctx, req, req_length);
  1536 + if (rc > 0) {
  1537 + int offset;
  1538 +
  1539 + rc = receive_msg_req(ctx, req, rsp);
  1540 + offset = TAB_HEADER_LENGTH[ctx->type_com];
  1541 +
  1542 + /* If rc is negative, the loop is jumped ! */
  1543 + for (i = 0; i < rc; i++) {
  1544 + /* shift reg hi_byte to temp OR with lo_byte */
  1545 + dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
  1546 + rsp[offset + 3 + (i << 1)];
  1547 + }
  1548 + }
  1549 +
  1550 + return rc;
  1551 +}
  1552 +
1448 /* Send a request to get the slave ID of the device (only available in serial 1553 /* Send a request to get the slave ID of the device (only available in serial
1449 - * communication). */ 1554 + communication). */
1450 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) 1555 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1451 { 1556 {
1452 int rc; 1557 int rc;
src/modbus.h
@@ -182,6 +182,9 @@ int modbus_write_bit(modbus_t *ctx, int coil_addr, int state); @@ -182,6 +182,9 @@ int modbus_write_bit(modbus_t *ctx, int coil_addr, int state);
182 int modbus_write_register(modbus_t *ctx, int reg_addr, int value); 182 int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
183 int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data); 183 int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
184 int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data); 184 int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
  185 +int modbus_read_and_write_holding_registers(modbus_t *ctx, int read_addr,
  186 + int read_nb, uint16_t *dest, int write_addr,
  187 + int write_nb, const uint16_t *data);
185 int modbus_report_slave_id(modbus_t *ctx, uint8_t *dest); 188 int modbus_report_slave_id(modbus_t *ctx, uint8_t *dest);
186 189
187 modbus_mapping_t* modbus_mapping_new(int nb_coil_status, int nb_input_status, 190 modbus_mapping_t* modbus_mapping_new(int nb_coil_status, int nb_input_status,
tests/bandwidth-client.c
@@ -143,6 +143,43 @@ int main(void) @@ -143,6 +143,43 @@ int main(void)
143 printf("* %'d KiB/s\n", rate); 143 printf("* %'d KiB/s\n", rate);
144 printf("\n"); 144 printf("\n");
145 145
  146 + printf("READ AND WRITE REGISTERS\n\n");
  147 +
  148 + nb_points = MODBUS_MAX_RW_WRITE_REGISTERS;
  149 + start = gettime_ms();
  150 + for (i=0; i<NB_LOOPS; i++) {
  151 + rc = modbus_read_and_write_holding_registers(ctx, 0, nb_points, tab_reg,0, nb_points, tab_reg);
  152 + if (rc == -1) {
  153 + fprintf(stderr, "%s\n", modbus_strerror(errno));
  154 + return -1;
  155 + }
  156 + }
  157 + end = gettime_ms();
  158 + elapsed = end - start;
  159 +
  160 + rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start);
  161 + printf("Transfert rate in points/seconds:\n");
  162 + printf("* %'d registers/s\n", rate);
  163 + printf("\n");
  164 +
  165 + bytes = NB_LOOPS * nb_points * sizeof(uint16_t);
  166 + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
  167 + printf("Values:\n");
  168 + printf("* %d x %d values\n", NB_LOOPS, nb_points);
  169 + printf("* %.3f ms for %d bytes\n", elapsed, bytes);
  170 + printf("* %'d KiB/s\n", rate);
  171 + printf("\n");
  172 +
  173 + /* TCP:Query and reponse header and values */
  174 + bytes = 12 + 9 + (nb_points * sizeof(uint16_t));
  175 + printf("Values and TCP Modbus overhead:\n");
  176 + printf("* %d x %d bytes\n", NB_LOOPS, bytes);
  177 + bytes = NB_LOOPS * bytes;
  178 + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
  179 + printf("* %.3f ms for %d bytes\n", elapsed, bytes);
  180 + printf("* %'d KiB/s\n", rate);
  181 + printf("\n");
  182 +
146 /* Free the memory */ 183 /* Free the memory */
147 free(tab_bit); 184 free(tab_bit);
148 free(tab_reg); 185 free(tab_reg);
tests/random-test-client.c
@@ -56,6 +56,7 @@ int main(void) @@ -56,6 +56,7 @@ int main(void)
56 uint8_t *tab_rq_bits; 56 uint8_t *tab_rq_bits;
57 uint8_t *tab_rp_bits; 57 uint8_t *tab_rp_bits;
58 uint16_t *tab_rq_registers; 58 uint16_t *tab_rq_registers;
  59 + uint16_t *tab_rw_rq_registers;
59 uint16_t *tab_rp_registers; 60 uint16_t *tab_rp_registers;
60 61
61 /* 62 /*
@@ -88,6 +89,9 @@ int main(void) @@ -88,6 +89,9 @@ int main(void)
88 tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); 89 tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
89 memset(tab_rp_registers, 0, nb * sizeof(uint16_t)); 90 memset(tab_rp_registers, 0, nb * sizeof(uint16_t));
90 91
  92 + tab_rw_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
  93 + memset(tab_rw_rq_registers, 0, nb * sizeof(uint16_t));
  94 +
91 nb_loop = nb_fail = 0; 95 nb_loop = nb_fail = 0;
92 while (nb_loop++ < LOOP) { 96 while (nb_loop++ < LOOP) {
93 for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) { 97 for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) {
@@ -96,6 +100,7 @@ int main(void) @@ -96,6 +100,7 @@ int main(void)
96 /* Random numbers (short) */ 100 /* Random numbers (short) */
97 for (i=0; i<nb; i++) { 101 for (i=0; i<nb; i++) {
98 tab_rq_registers[i] = (uint16_t) (65535.0*rand() / (RAND_MAX + 1.0)); 102 tab_rq_registers[i] = (uint16_t) (65535.0*rand() / (RAND_MAX + 1.0));
  103 + tab_rw_rq_registers[i] = ~tab_rq_registers[i];
99 tab_rq_bits[i] = tab_rq_registers[i] % 2; 104 tab_rq_bits[i] = tab_rq_registers[i] % 2;
100 } 105 }
101 nb = ADDRESS_END - addr; 106 nb = ADDRESS_END - addr;
@@ -188,7 +193,41 @@ int main(void) @@ -188,7 +193,41 @@ int main(void)
188 } 193 }
189 } 194 }
190 } 195 }
  196 + /* R/W MULTIPLE REGISTERS*/
  197 + rc = modbus_read_and_write_holding_registers(ctx, addr, nb, tab_rp_registers,
  198 + addr, nb, tab_rw_rq_registers);
  199 + if (rc != nb) {
  200 + printf("ERROR modbus_read_and_write_registers (%d)\n", rc);
  201 + printf("Address = %d, nb = %d\n", addr, nb);
  202 + nb_fail++;
  203 + } else {
  204 + for (i=0; i<nb; i++) {
  205 + if (tab_rq_registers[i] != tab_rp_registers[i]) {
  206 + printf("ERROR modbus_read_and_write_registers READ\n");
  207 + printf("Address = %d, value %d (0x%X) != %d (0x%X)\n",
  208 + addr, tab_rq_registers[i], tab_rq_registers[i],
  209 + tab_rp_registers[i], tab_rp_registers[i]);
  210 + nb_fail++;
  211 + }
  212 + }
191 213
  214 + rc = modbus_read_registers(ctx, addr, nb, tab_rp_registers);
  215 + if (rc != nb) {
  216 + printf("ERROR modbus_read_registers (%d)\n", rc);
  217 + printf("Address = %d, nb = %d\n", addr, nb);
  218 + nb_fail++;
  219 + } else {
  220 + for (i=0; i<nb; i++) {
  221 + if (tab_rw_rq_registers[i] != tab_rp_registers[i]) {
  222 + printf("ERROR modbus_read_and_write_registers WRITE\n");
  223 + printf("Address = %d, value %d (0x%X) != %d (0x%X)\n",
  224 + addr, tab_rw_rq_registers[i], tab_rw_rq_registers[i],
  225 + tab_rp_registers[i], tab_rp_registers[i]);
  226 + nb_fail++;
  227 + }
  228 + }
  229 + }
  230 + }
192 } 231 }
193 232
194 printf("Test: "); 233 printf("Test: ");
tests/unit-test-client.c
@@ -204,7 +204,7 @@ int main(void) @@ -204,7 +204,7 @@ int main(void)
204 rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS, 204 rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS,
205 UT_REGISTERS_NB_POINTS, 205 UT_REGISTERS_NB_POINTS,
206 UT_REGISTERS_TAB); 206 UT_REGISTERS_TAB);
207 - printf("1/3 modbus_write_registers: "); 207 + printf("1/5 modbus_write_registers: ");
208 if (rc == UT_REGISTERS_NB_POINTS) { 208 if (rc == UT_REGISTERS_NB_POINTS) {
209 printf("OK\n"); 209 printf("OK\n");
210 } else { 210 } else {
@@ -215,7 +215,7 @@ int main(void) @@ -215,7 +215,7 @@ int main(void)
215 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 215 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
216 UT_REGISTERS_NB_POINTS, 216 UT_REGISTERS_NB_POINTS,
217 tab_rp_registers); 217 tab_rp_registers);
218 - printf("2/3 modbus_read_registers: "); 218 + printf("2/5 modbus_read_registers: ");
219 if (rc != UT_REGISTERS_NB_POINTS) { 219 if (rc != UT_REGISTERS_NB_POINTS) {
220 printf("FAILED (nb points %d)\n", rc); 220 printf("FAILED (nb points %d)\n", rc);
221 goto close; 221 goto close;
@@ -233,13 +233,62 @@ int main(void) @@ -233,13 +233,62 @@ int main(void)
233 233
234 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 234 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
235 0, tab_rp_registers); 235 0, tab_rp_registers);
236 - printf("3/3 modbus_read_registers (0): "); 236 + printf("3/5 modbus_read_registers (0): ");
237 if (rc != 0) { 237 if (rc != 0) {
238 printf("FAILED (nb points %d)\n", rc); 238 printf("FAILED (nb points %d)\n", rc);
239 goto close; 239 goto close;
240 } 240 }
241 printf("OK\n"); 241 printf("OK\n");
242 242
  243 + nb_points = (UT_REGISTERS_NB_POINTS >
  244 + UT_INPUT_REGISTERS_NB_POINTS) ?
  245 + UT_REGISTERS_NB_POINTS : UT_INPUT_REGISTERS_NB_POINTS;
  246 + memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));
  247 +
  248 + /* Write registers to zero from tab_rp_registers and read registers to
  249 + tab_rp_registers. They should be same as UT_REGISTERS_TAB. */
  250 + rc = modbus_read_and_write_holding_registers(ctx,
  251 + UT_REGISTERS_ADDRESS,
  252 + UT_REGISTERS_NB_POINTS,
  253 + tab_rp_registers,
  254 + UT_REGISTERS_ADDRESS,
  255 + UT_REGISTERS_NB_POINTS,
  256 + tab_rp_registers);
  257 + printf("4/5 modbus_read_and_write_registers, read part: ");
  258 + if (rc != UT_REGISTERS_NB_POINTS) {
  259 + printf("FAILED (nb points %d)\n", rc);
  260 + goto close;
  261 + }
  262 +
  263 + for (i=0; i < UT_REGISTERS_NB_POINTS; i++) {
  264 + if (tab_rp_registers[i] != UT_REGISTERS_TAB[i]) {
  265 + printf("FAILED (%0X != %0X)\n",
  266 + tab_rp_registers[i],
  267 + UT_REGISTERS_TAB[i]);
  268 + goto close;
  269 + }
  270 + }
  271 + printf("OK\n");
  272 +
  273 + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  274 + UT_REGISTERS_NB_POINTS,
  275 + tab_rp_registers);
  276 + printf("5/5 modbus_read_and_write_registers, write part: ");
  277 + if (rc != UT_REGISTERS_NB_POINTS) {
  278 + printf("FAILED (nb points %d)\n", rc);
  279 + goto close;
  280 + }
  281 +
  282 + for (i=0; i < UT_REGISTERS_NB_POINTS; i++) {
  283 + if (tab_rp_registers[i] != 0) {
  284 + printf("FAILED (%0X != %0X)\n",
  285 + tab_rp_registers[i],
  286 + UT_REGISTERS_TAB[i]);
  287 + goto close;
  288 + }
  289 + }
  290 + printf("OK\n");
  291 +
243 /* End of many registers */ 292 /* End of many registers */
244 293
245 294