Commit c1e2e0b319b1f1fbbd663b2322162278bd48e4f5

Authored by Stéphane Raimbault
1 parent 81a52093

New RTU receive() to ignore confirmation from other slaves (closes #18)

- export new symbols to create specific behavior (RTU)
- the flag can't only be set by slaves
- new tests
src/modbus-private.h
@@ -68,6 +68,18 @@ typedef enum { @@ -68,6 +68,18 @@ typedef enum {
68 _MODBUS_BACKEND_TYPE_TCP 68 _MODBUS_BACKEND_TYPE_TCP
69 } modbus_bakend_type_t; 69 } modbus_bakend_type_t;
70 70
  71 +/*
  72 + * ---------- Request Indication ----------
  73 + * | Client | ---------------------->| Server |
  74 + * ---------- Confirmation Response ----------
  75 + */
  76 +typedef enum {
  77 + /* Request message on the server side */
  78 + MSG_INDICATION,
  79 + /* Request message on the client side */
  80 + MSG_CONFIRMATION
  81 +} msg_type_t;
  82 +
71 /* This structure reduces the number of params in functions and so 83 /* This structure reduces the number of params in functions and so
72 * optimizes the speed of execution (~ 37%). */ 84 * optimizes the speed of execution (~ 37%). */
73 typedef struct _sft { 85 typedef struct _sft {
@@ -88,6 +100,7 @@ typedef struct _modbus_backend { @@ -88,6 +100,7 @@ typedef struct _modbus_backend {
88 int (*prepare_response_tid) (const uint8_t *req, int *req_length); 100 int (*prepare_response_tid) (const uint8_t *req, int *req_length);
89 int (*send_msg_pre) (uint8_t *req, int req_length); 101 int (*send_msg_pre) (uint8_t *req, int req_length);
90 ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length); 102 ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
  103 + int (*receive) (modbus_t *ctx, uint8_t *req);
91 ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length); 104 ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
92 int (*check_integrity) (modbus_t *ctx, uint8_t *msg, 105 int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
93 const int msg_length); 106 const int msg_length);
@@ -114,6 +127,7 @@ struct _modbus { @@ -114,6 +127,7 @@ struct _modbus {
114 127
115 void _modbus_init_common(modbus_t *ctx); 128 void _modbus_init_common(modbus_t *ctx);
116 void _error_print(modbus_t *ctx, const char *context); 129 void _error_print(modbus_t *ctx, const char *context);
  130 +int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type);
117 131
118 #ifndef HAVE_STRLCPY 132 #ifndef HAVE_STRLCPY
119 size_t strlcpy(char *dest, const char *src, size_t dest_size); 133 size_t strlcpy(char *dest, const char *src, size_t dest_size);
src/modbus-rtu-private.h
@@ -88,6 +88,8 @@ typedef struct _modbus_rtu { @@ -88,6 +88,8 @@ typedef struct _modbus_rtu {
88 #if HAVE_DECL_TIOCM_RTS 88 #if HAVE_DECL_TIOCM_RTS
89 int rts; 89 int rts;
90 #endif 90 #endif
  91 + /* To handle many slaves on the same link */
  92 + int confirmation_to_ignore;
91 } modbus_rtu_t; 93 } modbus_rtu_t;
92 94
93 #endif /* _MODBUS_RTU_PRIVATE_H_ */ 95 #endif /* _MODBUS_RTU_PRIVATE_H_ */
src/modbus-rtu.c
@@ -309,6 +309,29 @@ ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length) @@ -309,6 +309,29 @@ ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
309 #endif 309 #endif
310 } 310 }
311 311
  312 +int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req)
  313 +{
  314 + int rc;
  315 + modbus_rtu_t *ctx_rtu = ctx->backend_data;
  316 +
  317 + if (ctx_rtu->confirmation_to_ignore) {
  318 + _modbus_receive_msg(ctx, req, MSG_CONFIRMATION);
  319 + /* Ignore errors and reset the flag */
  320 + ctx_rtu->confirmation_to_ignore = FALSE;
  321 + rc = 0;
  322 + if (ctx->debug) {
  323 + printf("Confirmation to ignore\n");
  324 + }
  325 + } else {
  326 + rc = _modbus_receive_msg(ctx, req, MSG_INDICATION);
  327 + if (rc == 0) {
  328 + /* The next expected message is a confirmation to ignore */
  329 + ctx_rtu->confirmation_to_ignore = TRUE;
  330 + }
  331 + }
  332 + return rc;
  333 +}
  334 +
312 ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) 335 ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
313 { 336 {
314 #if defined(_WIN32) 337 #if defined(_WIN32)
@@ -354,6 +377,7 @@ int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, @@ -354,6 +377,7 @@ int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg,
354 if (ctx->debug) { 377 if (ctx->debug) {
355 printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave); 378 printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave);
356 } 379 }
  380 +
357 return 0; 381 return 0;
358 } 382 }
359 383
@@ -368,6 +392,7 @@ int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, @@ -368,6 +392,7 @@ int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg,
368 fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n", 392 fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",
369 crc_received, crc_calculated); 393 crc_received, crc_calculated);
370 } 394 }
  395 +
371 if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { 396 if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
372 _modbus_rtu_flush(ctx); 397 _modbus_rtu_flush(ctx);
373 } 398 }
@@ -970,6 +995,7 @@ const modbus_backend_t _modbus_rtu_backend = { @@ -970,6 +995,7 @@ const modbus_backend_t _modbus_rtu_backend = {
970 _modbus_rtu_prepare_response_tid, 995 _modbus_rtu_prepare_response_tid,
971 _modbus_rtu_send_msg_pre, 996 _modbus_rtu_send_msg_pre,
972 _modbus_rtu_send, 997 _modbus_rtu_send,
  998 + _modbus_rtu_receive,
973 _modbus_rtu_recv, 999 _modbus_rtu_recv,
974 _modbus_rtu_check_integrity, 1000 _modbus_rtu_check_integrity,
975 _modbus_rtu_pre_check_confirmation, 1001 _modbus_rtu_pre_check_confirmation,
@@ -1032,5 +1058,7 @@ modbus_t* modbus_new_rtu(const char *device, @@ -1032,5 +1058,7 @@ modbus_t* modbus_new_rtu(const char *device,
1032 ctx_rtu->rts = MODBUS_RTU_RTS_NONE; 1058 ctx_rtu->rts = MODBUS_RTU_RTS_NONE;
1033 #endif 1059 #endif
1034 1060
  1061 + ctx_rtu->confirmation_to_ignore = FALSE;
  1062 +
1035 return ctx; 1063 return ctx;
1036 } 1064 }
src/modbus-tcp.c
@@ -178,6 +178,10 @@ ssize_t _modbus_tcp_send(modbus_t *ctx, const uint8_t *req, int req_length) @@ -178,6 +178,10 @@ ssize_t _modbus_tcp_send(modbus_t *ctx, const uint8_t *req, int req_length)
178 return send(ctx->s, (const char*)req, req_length, MSG_NOSIGNAL); 178 return send(ctx->s, (const char*)req, req_length, MSG_NOSIGNAL);
179 } 179 }
180 180
  181 +int _modbus_tcp_receive(modbus_t *ctx, uint8_t *req) {
  182 + return _modbus_receive_msg(ctx, req, MSG_INDICATION);
  183 +}
  184 +
181 ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) { 185 ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) {
182 return recv(ctx->s, (char *)rsp, rsp_length, 0); 186 return recv(ctx->s, (char *)rsp, rsp_length, 0);
183 } 187 }
@@ -597,6 +601,7 @@ const modbus_backend_t _modbus_tcp_backend = { @@ -597,6 +601,7 @@ const modbus_backend_t _modbus_tcp_backend = {
597 _modbus_tcp_prepare_response_tid, 601 _modbus_tcp_prepare_response_tid,
598 _modbus_tcp_send_msg_pre, 602 _modbus_tcp_send_msg_pre,
599 _modbus_tcp_send, 603 _modbus_tcp_send,
  604 + _modbus_tcp_receive,
600 _modbus_tcp_recv, 605 _modbus_tcp_recv,
601 _modbus_tcp_check_integrity, 606 _modbus_tcp_check_integrity,
602 _modbus_tcp_pre_check_confirmation, 607 _modbus_tcp_pre_check_confirmation,
@@ -618,6 +623,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = { @@ -618,6 +623,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = {
618 _modbus_tcp_prepare_response_tid, 623 _modbus_tcp_prepare_response_tid,
619 _modbus_tcp_send_msg_pre, 624 _modbus_tcp_send_msg_pre,
620 _modbus_tcp_send, 625 _modbus_tcp_send,
  626 + _modbus_tcp_receive,
621 _modbus_tcp_recv, 627 _modbus_tcp_recv,
622 _modbus_tcp_check_integrity, 628 _modbus_tcp_check_integrity,
623 _modbus_tcp_pre_check_confirmation, 629 _modbus_tcp_pre_check_confirmation,
src/modbus.c
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 #include <errno.h> 26 #include <errno.h>
27 #include <limits.h> 27 #include <limits.h>
28 #include <time.h> 28 #include <time.h>
  29 +#include <unistd.h>
29 30
30 #include <config.h> 31 #include <config.h>
31 32
@@ -233,17 +234,10 @@ int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length) @@ -233,17 +234,10 @@ int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length)
233 } 234 }
234 235
235 /* 236 /*
236 - ---------- Request Indication ----------  
237 - | Client | ---------------------->| Server |  
238 - ---------- Confirmation Response ----------  
239 -*/  
240 -  
241 -typedef enum {  
242 - /* Request message on the server side */  
243 - MSG_INDICATION,  
244 - /* Request message on the client side */  
245 - MSG_CONFIRMATION  
246 -} msg_type_t; 237 + * ---------- Request Indication ----------
  238 + * | Client | ---------------------->| Server |
  239 + * ---------- Confirmation Response ----------
  240 + */
247 241
248 /* Computes the length to read after the function received */ 242 /* Computes the length to read after the function received */
249 static uint8_t compute_meta_length_after_function(int function, 243 static uint8_t compute_meta_length_after_function(int function,
@@ -329,7 +323,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, @@ -329,7 +323,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg,
329 - read() or recv() error codes 323 - read() or recv() error codes
330 */ 324 */
331 325
332 -static int receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) 326 +int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
333 { 327 {
334 int rc; 328 int rc;
335 fd_set rfds; 329 fd_set rfds;
@@ -462,7 +456,7 @@ static int receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) @@ -462,7 +456,7 @@ static int receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
462 /* Receive the request from a modbus master */ 456 /* Receive the request from a modbus master */
463 int modbus_receive(modbus_t *ctx, uint8_t *req) 457 int modbus_receive(modbus_t *ctx, uint8_t *req)
464 { 458 {
465 - return receive_msg(ctx, req, MSG_INDICATION); 459 + return ctx->backend->receive(ctx, req);
466 } 460 }
467 461
468 /* Receives the confirmation. 462 /* Receives the confirmation.
@@ -475,7 +469,7 @@ int modbus_receive(modbus_t *ctx, uint8_t *req) @@ -475,7 +469,7 @@ int modbus_receive(modbus_t *ctx, uint8_t *req)
475 */ 469 */
476 int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp) 470 int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp)
477 { 471 {
478 - return receive_msg(ctx, rsp, MSG_CONFIRMATION); 472 + return _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
479 } 473 }
480 474
481 static int check_confirmation(modbus_t *ctx, uint8_t *req, 475 static int check_confirmation(modbus_t *ctx, uint8_t *req,
@@ -965,7 +959,7 @@ static int read_io_status(modbus_t *ctx, int function, @@ -965,7 +959,7 @@ static int read_io_status(modbus_t *ctx, int function,
965 int offset; 959 int offset;
966 int offset_end; 960 int offset_end;
967 961
968 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 962 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
969 if (rc == -1) 963 if (rc == -1)
970 return -1; 964 return -1;
971 965
@@ -1064,7 +1058,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, @@ -1064,7 +1058,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1064 int offset; 1058 int offset;
1065 int i; 1059 int i;
1066 1060
1067 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1061 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1068 if (rc == -1) 1062 if (rc == -1)
1069 return -1; 1063 return -1;
1070 1064
@@ -1140,7 +1134,7 @@ static int write_single(modbus_t *ctx, int function, int addr, int value) @@ -1140,7 +1134,7 @@ static int write_single(modbus_t *ctx, int function, int addr, int value)
1140 /* Used by write_bit and write_register */ 1134 /* Used by write_bit and write_register */
1141 uint8_t rsp[_MIN_REQ_LENGTH]; 1135 uint8_t rsp[_MIN_REQ_LENGTH];
1142 1136
1143 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1137 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1144 if (rc == -1) 1138 if (rc == -1)
1145 return -1; 1139 return -1;
1146 1140
@@ -1211,7 +1205,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src) @@ -1211,7 +1205,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src)
1211 if (rc > 0) { 1205 if (rc > 0) {
1212 uint8_t rsp[MAX_MESSAGE_LENGTH]; 1206 uint8_t rsp[MAX_MESSAGE_LENGTH];
1213 1207
1214 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1208 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1215 if (rc == -1) 1209 if (rc == -1)
1216 return -1; 1210 return -1;
1217 1211
@@ -1257,7 +1251,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) @@ -1257,7 +1251,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
1257 if (rc > 0) { 1251 if (rc > 0) {
1258 uint8_t rsp[MAX_MESSAGE_LENGTH]; 1252 uint8_t rsp[MAX_MESSAGE_LENGTH];
1259 1253
1260 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1254 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1261 if (rc == -1) 1255 if (rc == -1)
1262 return -1; 1256 return -1;
1263 1257
@@ -1320,7 +1314,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, @@ -1320,7 +1314,7 @@ int modbus_write_and_read_registers(modbus_t *ctx,
1320 if (rc > 0) { 1314 if (rc > 0) {
1321 int offset; 1315 int offset;
1322 1316
1323 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1317 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1324 if (rc == -1) 1318 if (rc == -1)
1325 return -1; 1319 return -1;
1326 1320
@@ -1361,7 +1355,7 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *dest) @@ -1361,7 +1355,7 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *dest)
1361 int offset; 1355 int offset;
1362 uint8_t rsp[MAX_MESSAGE_LENGTH]; 1356 uint8_t rsp[MAX_MESSAGE_LENGTH];
1363 1357
1364 - rc = receive_msg(ctx, rsp, MSG_CONFIRMATION); 1358 + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1365 if (rc == -1) 1359 if (rc == -1)
1366 return -1; 1360 return -1;
1367 1361
tests/unit-test-client.c
@@ -491,8 +491,12 @@ int main(int argc, char *argv[]) @@ -491,8 +491,12 @@ int main(int argc, char *argv[])
491 UT_REGISTERS_NB, tab_rp_registers); 491 UT_REGISTERS_NB, tab_rp_registers);
492 if (use_backend == RTU) { 492 if (use_backend == RTU) {
493 const int RAW_REQ_LENGTH = 6; 493 const int RAW_REQ_LENGTH = 6;
494 - uint8_t raw_req[] = { INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0xFF, 0xFF };  
495 - uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; 494 + uint8_t raw_req[] = { INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0x01, 0x01 };
  495 + /* Too many points */
  496 + uint8_t raw_invalid_req[] = { INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0xFF, 0xFF };
  497 + const int RAW_REP_LENGTH = 7;
  498 + uint8_t raw_rep[] = { INVALID_SERVER_ID, 0x03, 0x04, 0, 0, 0, 0 };
  499 + uint8_t rsp[MODBUS_RTU_MAX_ADU_LENGTH];
496 500
497 /* No response in RTU mode */ 501 /* No response in RTU mode */
498 printf("1/5-A No response from slave %d: ", INVALID_SERVER_ID); 502 printf("1/5-A No response from slave %d: ", INVALID_SERVER_ID);
@@ -504,12 +508,19 @@ int main(int argc, char *argv[]) @@ -504,12 +508,19 @@ int main(int argc, char *argv[])
504 goto close; 508 goto close;
505 } 509 }
506 510
507 - /* Send an invalid query with a wrong slave ID */  
508 - modbus_send_raw_request(ctx, raw_req,  
509 - RAW_REQ_LENGTH * sizeof(uint8_t)); 511 + /* The slave raises a timeout on a confirmation to ignore because if an
  512 + * indication for another slave is received, a confirmation must follow */
  513 +
  514 +
  515 + /* Send a pair of indication/confimration to the slave with a different
  516 + * slave ID to simulate a communication on a RS485 bus. At first, the
  517 + * slave will see the indication message then the confirmation, and it must
  518 + * ignore both. */
  519 + modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t));
  520 + modbus_send_raw_request(ctx, raw_rep, RAW_REP_LENGTH * sizeof(uint8_t));
510 rc = modbus_receive_confirmation(ctx, rsp); 521 rc = modbus_receive_confirmation(ctx, rsp);
511 522
512 - printf("1/5-B No response from slave %d with invalid request: ", 523 + printf("1/5-B No response from slave %d on indication/confirmation messages: ",
513 INVALID_SERVER_ID); 524 INVALID_SERVER_ID);
514 525
515 if (rc == -1 && errno == ETIMEDOUT) { 526 if (rc == -1 && errno == ETIMEDOUT) {
@@ -519,9 +530,22 @@ int main(int argc, char *argv[]) @@ -519,9 +530,22 @@ int main(int argc, char *argv[])
519 goto close; 530 goto close;
520 } 531 }
521 532
  533 + /* Send an INVALID request for another slave */
  534 + modbus_send_raw_request(ctx, raw_invalid_req, RAW_REQ_LENGTH * sizeof(uint8_t));
  535 + rc = modbus_receive_confirmation(ctx, rsp);
  536 +
  537 + printf("1/5-C No response from slave %d with invalid request: ",
  538 + INVALID_SERVER_ID);
  539 +
  540 + if (rc == -1 && errno == ETIMEDOUT) {
  541 + printf("OK\n");
  542 + } else {
  543 + printf("FAILED (%d)\n", rc);
  544 + goto close;
  545 + }
522 } else { 546 } else {
523 /* Response in TCP mode */ 547 /* Response in TCP mode */
524 - printf("1/4 Response from slave %d: ", 18); 548 + printf("1/4 Response from slave %d: ", INVALID_SERVER_ID);
525 549
526 if (rc == UT_REGISTERS_NB) { 550 if (rc == UT_REGISTERS_NB) {
527 printf("OK\n"); 551 printf("OK\n");