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 61 #define FC_WRITE_MULTIPLE_COILS 0x0F
62 62 #define FC_WRITE_MULTIPLE_REGISTERS 0x10
63 63 #define FC_REPORT_SLAVE_ID 0x11
  64 +#define FC_READ_AND_WRITE_REGISTERS 0x17
64 65  
65 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 264 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
265 265 }
266 266 break;
  267 + case FC_READ_AND_WRITE_REGISTERS:
267 268 case FC_READ_HOLDING_REGISTERS:
268 269 case FC_READ_INPUT_REGISTERS:
269 270 /* Header + 2 * nb values */
... ... @@ -512,6 +513,8 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
512 513 length = 0;
513 514 else
514 515 length = 1;
  516 + } else if (function == FC_READ_AND_WRITE_REGISTERS) {
  517 + length = 9;
515 518 } else {
516 519 length = 0;
517 520 }
... ... @@ -529,6 +532,8 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg)
529 532 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5];
530 533 } else if (function == FC_REPORT_SLAVE_ID) {
531 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 537 } else
533 538 length = 0;
534 539  
... ... @@ -789,6 +794,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
789 794 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
790 795 rsp_nb_value = rsp[offset + 1];
791 796 break;
  797 + case FC_READ_AND_WRITE_REGISTERS:
792 798 case FC_READ_HOLDING_REGISTERS:
793 799 case FC_READ_INPUT_REGISTERS:
794 800 /* Read functions 1 value = 2 bytes */
... ... @@ -1130,6 +1136,40 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1130 1136 errno = ENOPROTOOPT;
1131 1137 return -1;
1132 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 1173 default:
1134 1174 rsp_length = response_exception(ctx, &sft,
1135 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 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 1553 /* Send a request to get the slave ID of the device (only available in serial
1449   - * communication). */
  1554 + communication). */
1450 1555 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1451 1556 {
1452 1557 int rc;
... ...
src/modbus.h
... ... @@ -182,6 +182,9 @@ int modbus_write_bit(modbus_t *ctx, int coil_addr, int state);
182 182 int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
183 183 int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
184 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 188 int modbus_report_slave_id(modbus_t *ctx, uint8_t *dest);
186 189  
187 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 143 printf("* %'d KiB/s\n", rate);
144 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 183 /* Free the memory */
147 184 free(tab_bit);
148 185 free(tab_reg);
... ...
tests/random-test-client.c
... ... @@ -56,6 +56,7 @@ int main(void)
56 56 uint8_t *tab_rq_bits;
57 57 uint8_t *tab_rp_bits;
58 58 uint16_t *tab_rq_registers;
  59 + uint16_t *tab_rw_rq_registers;
59 60 uint16_t *tab_rp_registers;
60 61  
61 62 /*
... ... @@ -88,6 +89,9 @@ int main(void)
88 89 tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
89 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 95 nb_loop = nb_fail = 0;
92 96 while (nb_loop++ < LOOP) {
93 97 for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) {
... ... @@ -96,6 +100,7 @@ int main(void)
96 100 /* Random numbers (short) */
97 101 for (i=0; i<nb; i++) {
98 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 104 tab_rq_bits[i] = tab_rq_registers[i] % 2;
100 105 }
101 106 nb = ADDRESS_END - addr;
... ... @@ -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 233 printf("Test: ");
... ...
tests/unit-test-client.c
... ... @@ -204,7 +204,7 @@ int main(void)
204 204 rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS,
205 205 UT_REGISTERS_NB_POINTS,
206 206 UT_REGISTERS_TAB);
207   - printf("1/3 modbus_write_registers: ");
  207 + printf("1/5 modbus_write_registers: ");
208 208 if (rc == UT_REGISTERS_NB_POINTS) {
209 209 printf("OK\n");
210 210 } else {
... ... @@ -215,7 +215,7 @@ int main(void)
215 215 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
216 216 UT_REGISTERS_NB_POINTS,
217 217 tab_rp_registers);
218   - printf("2/3 modbus_read_registers: ");
  218 + printf("2/5 modbus_read_registers: ");
219 219 if (rc != UT_REGISTERS_NB_POINTS) {
220 220 printf("FAILED (nb points %d)\n", rc);
221 221 goto close;
... ... @@ -233,13 +233,62 @@ int main(void)
233 233  
234 234 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
235 235 0, tab_rp_registers);
236   - printf("3/3 modbus_read_registers (0): ");
  236 + printf("3/5 modbus_read_registers (0): ");
237 237 if (rc != 0) {
238 238 printf("FAILED (nb points %d)\n", rc);
239 239 goto close;
240 240 }
241 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 292 /* End of many registers */
244 293  
245 294  
... ...