2 * Copyright © Stéphane Raimbault <stephane.raimbault@gmail.com>
4 * SPDX-License-Identifier: BSD-3-Clause
14 #include "unit-test.h"
16 const int EXCEPTION_RC
= 2;
24 int test_server(modbus_t
*ctx
, int use_backend
);
25 int send_crafted_request(modbus_t
*ctx
, int function
,
26 uint8_t *req
, int req_size
,
27 uint16_t max_value
, uint16_t bytes
,
28 int backend_length
, int backend_offset
);
29 int equal_dword(uint16_t *tab_reg
, const uint32_t value
);
30 int is_memory_equal(const void *s1
, const void *s2
, size_t size
);
32 #define BUG_REPORT(_cond, _format, _args ...) \
33 printf("\nLine %d: assertion error for '%s': " _format "\n", __LINE__, # _cond, ## _args)
35 #define ASSERT_TRUE(_cond, _format, __args...) { \
39 BUG_REPORT(_cond, _format, ## __args); \
44 int is_memory_equal(const void *s1
, const void *s2
, size_t size
)
46 return (memcmp(s1
, s2
, size
) == 0);
49 int equal_dword(uint16_t *tab_reg
, const uint32_t value
) {
50 return ((tab_reg
[0] == (value
>> 16)) && (tab_reg
[1] == (value
& 0xFFFF)));
53 int main(int argc
, char *argv
[])
55 const int NB_REPORT_SLAVE_ID
= 10;
56 uint8_t *tab_rp_bits
= NULL
;
57 uint16_t *tab_rp_registers
= NULL
;
58 uint16_t *tab_rp_registers_bad
= NULL
;
65 uint32_t old_response_to_sec
;
66 uint32_t old_response_to_usec
;
67 uint32_t new_response_to_sec
;
68 uint32_t new_response_to_usec
;
69 uint32_t old_byte_to_sec
;
70 uint32_t old_byte_to_usec
;
76 if (strcmp(argv
[1], "tcp") == 0) {
78 } else if (strcmp(argv
[1], "tcppi") == 0) {
80 } else if (strcmp(argv
[1], "rtu") == 0) {
83 printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus client for unit testing\n\n", argv
[0]);
91 if (use_backend
== TCP
) {
92 ctx
= modbus_new_tcp("127.0.0.1", 1502);
93 } else if (use_backend
== TCP_PI
) {
94 ctx
= modbus_new_tcp_pi("::1", "1502");
96 ctx
= modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1);
99 fprintf(stderr
, "Unable to allocate libmodbus context\n");
102 modbus_set_debug(ctx
, TRUE
);
103 modbus_set_error_recovery(ctx
,
104 MODBUS_ERROR_RECOVERY_LINK
|
105 MODBUS_ERROR_RECOVERY_PROTOCOL
);
107 if (use_backend
== RTU
) {
108 modbus_set_slave(ctx
, SERVER_ID
);
111 modbus_get_response_timeout(ctx
, &old_response_to_sec
, &old_response_to_usec
);
112 if (modbus_connect(ctx
) == -1) {
113 fprintf(stderr
, "Connection failed: %s\n", modbus_strerror(errno
));
118 /* Allocate and initialize the memory to store the bits */
119 nb_points
= (UT_BITS_NB
> UT_INPUT_BITS_NB
) ? UT_BITS_NB
: UT_INPUT_BITS_NB
;
120 tab_rp_bits
= (uint8_t *) malloc(nb_points
* sizeof(uint8_t));
121 memset(tab_rp_bits
, 0, nb_points
* sizeof(uint8_t));
123 /* Allocate and initialize the memory to store the registers */
124 nb_points
= (UT_REGISTERS_NB
> UT_INPUT_REGISTERS_NB
) ?
125 UT_REGISTERS_NB
: UT_INPUT_REGISTERS_NB
;
126 tab_rp_registers
= (uint16_t *) malloc(nb_points
* sizeof(uint16_t));
127 memset(tab_rp_registers
, 0, nb_points
* sizeof(uint16_t));
129 printf("** UNIT TESTING **\n");
131 printf("1/1 No response timeout modification on connect: ");
132 modbus_get_response_timeout(ctx
, &new_response_to_sec
, &new_response_to_usec
);
133 ASSERT_TRUE(old_response_to_sec
== new_response_to_sec
&&
134 old_response_to_usec
== new_response_to_usec
, "");
136 printf("\nTEST WRITE/READ:\n");
141 rc
= modbus_write_bit(ctx
, UT_BITS_ADDRESS
, ON
);
142 printf("1/2 modbus_write_bit: ");
143 ASSERT_TRUE(rc
== 1, "");
145 rc
= modbus_read_bits(ctx
, UT_BITS_ADDRESS
, 1, tab_rp_bits
);
146 printf("2/2 modbus_read_bits: ");
147 ASSERT_TRUE(rc
== 1, "FAILED (nb points %d)\n", rc
);
148 ASSERT_TRUE(tab_rp_bits
[0] == ON
, "FAILED (%0X != %0X)\n",
155 uint8_t tab_value
[UT_BITS_NB
];
157 modbus_set_bits_from_bytes(tab_value
, 0, UT_BITS_NB
, UT_BITS_TAB
);
158 rc
= modbus_write_bits(ctx
, UT_BITS_ADDRESS
, UT_BITS_NB
, tab_value
);
159 printf("1/2 modbus_write_bits: ");
160 ASSERT_TRUE(rc
== UT_BITS_NB
, "");
163 rc
= modbus_read_bits(ctx
, UT_BITS_ADDRESS
, UT_BITS_NB
, tab_rp_bits
);
164 printf("2/2 modbus_read_bits: ");
165 ASSERT_TRUE(rc
== UT_BITS_NB
, "FAILED (nb points %d)\n", rc
);
168 nb_points
= UT_BITS_NB
;
169 while (nb_points
> 0) {
170 int nb_bits
= (nb_points
> 8) ? 8 : nb_points
;
172 value
= modbus_get_byte_from_bits(tab_rp_bits
, i
*8, nb_bits
);
173 ASSERT_TRUE(value
== UT_BITS_TAB
[i
], "FAILED (%0X != %0X)\n",
174 value
, UT_BITS_TAB
[i
]);
176 nb_points
-= nb_bits
;
180 /* End of multiple bits */
182 /** DISCRETE INPUTS **/
183 rc
= modbus_read_input_bits(ctx
, UT_INPUT_BITS_ADDRESS
,
184 UT_INPUT_BITS_NB
, tab_rp_bits
);
185 printf("1/1 modbus_read_input_bits: ");
186 ASSERT_TRUE(rc
== UT_INPUT_BITS_NB
, "FAILED (nb points %d)\n", rc
);
189 nb_points
= UT_INPUT_BITS_NB
;
190 while (nb_points
> 0) {
191 int nb_bits
= (nb_points
> 8) ? 8 : nb_points
;
192 value
= modbus_get_byte_from_bits(tab_rp_bits
, i
*8, nb_bits
);
193 ASSERT_TRUE(value
== UT_INPUT_BITS_TAB
[i
], "FAILED (%0X != %0X)\n",
194 value
, UT_INPUT_BITS_TAB
[i
]);
196 nb_points
-= nb_bits
;
201 /** HOLDING REGISTERS **/
203 /* Single register */
204 rc
= modbus_write_register(ctx
, UT_REGISTERS_ADDRESS
, 0x1234);
205 printf("1/2 modbus_write_register: ");
206 ASSERT_TRUE(rc
== 1, "");
208 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
209 1, tab_rp_registers
);
210 printf("2/2 modbus_read_registers: ");
211 ASSERT_TRUE(rc
== 1, "FAILED (nb points %d)\n", rc
);
212 ASSERT_TRUE(tab_rp_registers
[0] == 0x1234, "FAILED (%0X != %0X)\n",
213 tab_rp_registers
[0], 0x1234);
214 /* End of single register */
217 rc
= modbus_write_registers(ctx
, UT_REGISTERS_ADDRESS
,
218 UT_REGISTERS_NB
, UT_REGISTERS_TAB
);
219 printf("1/5 modbus_write_registers: ");
220 ASSERT_TRUE(rc
== UT_REGISTERS_NB
, "");
222 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
223 UT_REGISTERS_NB
, tab_rp_registers
);
224 printf("2/5 modbus_read_registers: ");
225 ASSERT_TRUE(rc
== UT_REGISTERS_NB
, "FAILED (nb points %d)\n", rc
);
227 for (i
=0; i
< UT_REGISTERS_NB
; i
++) {
228 ASSERT_TRUE(tab_rp_registers
[i
] == UT_REGISTERS_TAB
[i
],
229 "FAILED (%0X != %0X)\n",
230 tab_rp_registers
[i
], UT_REGISTERS_TAB
[i
]);
233 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
234 0, tab_rp_registers
);
235 printf("3/5 modbus_read_registers (0): ");
236 ASSERT_TRUE(rc
== -1, "FAILED (nb_points %d)\n", rc
);
238 nb_points
= (UT_REGISTERS_NB
>
239 UT_INPUT_REGISTERS_NB
) ?
240 UT_REGISTERS_NB
: UT_INPUT_REGISTERS_NB
;
241 memset(tab_rp_registers
, 0, nb_points
* sizeof(uint16_t));
243 /* Write registers to zero from tab_rp_registers and store read registers
244 into tab_rp_registers. So the read registers must set to 0, except the
245 first one because there is an offset of 1 register on write. */
246 rc
= modbus_write_and_read_registers(ctx
,
247 UT_REGISTERS_ADDRESS
+ 1,
250 UT_REGISTERS_ADDRESS
,
253 printf("4/5 modbus_write_and_read_registers: ");
254 ASSERT_TRUE(rc
== UT_REGISTERS_NB
, "FAILED (nb points %d != %d)\n",
255 rc
, UT_REGISTERS_NB
);
257 ASSERT_TRUE(tab_rp_registers
[0] == UT_REGISTERS_TAB
[0],
258 "FAILED (%0X != %0X)\n",
259 tab_rp_registers
[0], UT_REGISTERS_TAB
[0]);
261 for (i
=1; i
< UT_REGISTERS_NB
; i
++) {
262 ASSERT_TRUE(tab_rp_registers
[i
] == 0, "FAILED (%0X != %0X)\n",
263 tab_rp_registers
[i
], 0);
266 /* End of many registers */
269 /** INPUT REGISTERS **/
270 rc
= modbus_read_input_registers(ctx
, UT_INPUT_REGISTERS_ADDRESS
,
271 UT_INPUT_REGISTERS_NB
,
273 printf("1/1 modbus_read_input_registers: ");
274 ASSERT_TRUE(rc
== UT_INPUT_REGISTERS_NB
, "FAILED (nb points %d)\n", rc
);
276 for (i
=0; i
< UT_INPUT_REGISTERS_NB
; i
++) {
277 ASSERT_TRUE(tab_rp_registers
[i
] == UT_INPUT_REGISTERS_TAB
[i
],
278 "FAILED (%0X != %0X)\n",
279 tab_rp_registers
[i
], UT_INPUT_REGISTERS_TAB
[i
]);
283 printf("1/1 Write mask: ");
284 rc
= modbus_write_register(ctx
, UT_REGISTERS_ADDRESS
, 0x12);
285 rc
= modbus_mask_write_register(ctx
, UT_REGISTERS_ADDRESS
, 0xF2, 0x25);
286 ASSERT_TRUE(rc
!= -1, "FAILED (%x == -1)\n", rc
);
287 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
, 1, tab_rp_registers
);
288 ASSERT_TRUE(tab_rp_registers
[0] == 0x17,
289 "FAILED (%0X != %0X)\n",
290 tab_rp_registers
[0], 0x17);
292 printf("\nTEST FLOATS\n");
294 printf("1/4 Set/get float ABCD: ");
295 modbus_set_float_abcd(UT_REAL
, tab_rp_registers
);
296 ASSERT_TRUE(is_memory_equal(tab_rp_registers
, UT_IREAL_ABCD_SET
, 4), "FAILED Set float ABCD");
297 real
= modbus_get_float_abcd(UT_IREAL_ABCD_GET
);
298 ASSERT_TRUE(real
== UT_REAL
, "FAILED (%f != %f)\n", real
, UT_REAL
);
300 printf("2/4 Set/get float DCBA: ");
301 modbus_set_float_dcba(UT_REAL
, tab_rp_registers
);
302 ASSERT_TRUE(is_memory_equal(tab_rp_registers
, UT_IREAL_DCBA_SET
, 4), "FAILED Set float DCBA");
303 real
= modbus_get_float_dcba(UT_IREAL_DCBA_GET
);
304 ASSERT_TRUE(real
== UT_REAL
, "FAILED (%f != %f)\n", real
, UT_REAL
);
306 printf("3/4 Set/get float BADC: ");
307 modbus_set_float_badc(UT_REAL
, tab_rp_registers
);
308 ASSERT_TRUE(is_memory_equal(tab_rp_registers
, UT_IREAL_BADC_SET
, 4), "FAILED Set float BADC");
309 real
= modbus_get_float_badc(UT_IREAL_BADC_GET
);
310 ASSERT_TRUE(real
== UT_REAL
, "FAILED (%f != %f)\n", real
, UT_REAL
);
312 printf("4/4 Set/get float CDAB: ");
313 modbus_set_float_cdab(UT_REAL
, tab_rp_registers
);
314 ASSERT_TRUE(is_memory_equal(tab_rp_registers
, UT_IREAL_CDAB_SET
, 4), "FAILED Set float CDAB");
315 real
= modbus_get_float_cdab(UT_IREAL_CDAB_GET
);
316 ASSERT_TRUE(real
== UT_REAL
, "FAILED (%f != %f)\n", real
, UT_REAL
);
318 printf("\nAt this point, error messages doesn't mean the test has failed\n");
320 /** ILLEGAL DATA ADDRESS **/
321 printf("\nTEST ILLEGAL DATA ADDRESS:\n");
323 /* The mapping begins at the defined addresses and ends at address +
324 * nb_points so these addresses are not valid. */
326 rc
= modbus_read_bits(ctx
, 0, 1, tab_rp_bits
);
327 printf("* modbus_read_bits (0): ");
328 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
330 rc
= modbus_read_bits(ctx
, UT_BITS_ADDRESS
, UT_BITS_NB
+ 1, tab_rp_bits
);
331 printf("* modbus_read_bits (max): ");
332 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
334 rc
= modbus_read_input_bits(ctx
, 0, 1, tab_rp_bits
);
335 printf("* modbus_read_input_bits (0): ");
336 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
338 rc
= modbus_read_input_bits(ctx
, UT_INPUT_BITS_ADDRESS
,
339 UT_INPUT_BITS_NB
+ 1, tab_rp_bits
);
340 printf("* modbus_read_input_bits (max): ");
341 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
343 rc
= modbus_read_registers(ctx
, 0, 1, tab_rp_registers
);
344 printf("* modbus_read_registers (0): ");
345 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
347 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
348 UT_REGISTERS_NB_MAX
+ 1, tab_rp_registers
);
349 printf("* modbus_read_registers (max): ");
350 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
352 rc
= modbus_read_input_registers(ctx
, 0, 1, tab_rp_registers
);
353 printf("* modbus_read_input_registers (0): ");
354 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
356 rc
= modbus_read_input_registers(ctx
, UT_INPUT_REGISTERS_ADDRESS
,
357 UT_INPUT_REGISTERS_NB
+ 1,
359 printf("* modbus_read_input_registers (max): ");
360 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
362 rc
= modbus_write_bit(ctx
, 0, ON
);
363 printf("* modbus_write_bit (0): ");
364 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
366 rc
= modbus_write_bit(ctx
, UT_BITS_ADDRESS
+ UT_BITS_NB
, ON
);
367 printf("* modbus_write_bit (max): ");
368 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
370 rc
= modbus_write_bits(ctx
, 0, 1, tab_rp_bits
);
371 printf("* modbus_write_coils (0): ");
372 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
374 rc
= modbus_write_bits(ctx
, UT_BITS_ADDRESS
+ UT_BITS_NB
,
375 UT_BITS_NB
, tab_rp_bits
);
376 printf("* modbus_write_coils (max): ");
377 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
379 rc
= modbus_write_register(ctx
, 0, tab_rp_registers
[0]);
380 printf("* modbus_write_register (0): ");
381 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
383 rc
= modbus_write_register(ctx
, UT_REGISTERS_ADDRESS
+ UT_REGISTERS_NB_MAX
,
384 tab_rp_registers
[0]);
385 printf("* modbus_write_register (max): ");
386 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
388 rc
= modbus_write_registers(ctx
, 0, 1, tab_rp_registers
);
389 printf("* modbus_write_registers (0): ");
390 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
392 rc
= modbus_write_registers(ctx
, UT_REGISTERS_ADDRESS
+ UT_REGISTERS_NB_MAX
,
393 UT_REGISTERS_NB
, tab_rp_registers
);
394 printf("* modbus_write_registers (max): ");
395 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
397 rc
= modbus_mask_write_register(ctx
, 0, 0xF2, 0x25);
398 printf("* modbus_mask_write_registers (0): ");
399 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
401 rc
= modbus_mask_write_register(ctx
, UT_REGISTERS_ADDRESS
+ UT_REGISTERS_NB_MAX
,
403 printf("* modbus_mask_write_registers (max): ");
404 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
406 rc
= modbus_write_and_read_registers(ctx
, 0, 1, tab_rp_registers
, 0, 1, tab_rp_registers
);
407 printf("* modbus_write_and_read_registers (0): ");
408 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
410 rc
= modbus_write_and_read_registers(ctx
,
411 UT_REGISTERS_ADDRESS
+ UT_REGISTERS_NB_MAX
,
412 UT_REGISTERS_NB
, tab_rp_registers
,
413 UT_REGISTERS_ADDRESS
+ UT_REGISTERS_NB_MAX
,
414 UT_REGISTERS_NB
, tab_rp_registers
);
415 printf("* modbus_write_and_read_registers (max): ");
416 ASSERT_TRUE(rc
== -1 && errno
== EMBXILADD
, "");
418 /** TOO MANY DATA **/
419 printf("\nTEST TOO MANY DATA ERROR:\n");
421 rc
= modbus_read_bits(ctx
, UT_BITS_ADDRESS
,
422 MODBUS_MAX_READ_BITS
+ 1, tab_rp_bits
);
423 printf("* modbus_read_bits: ");
424 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
426 rc
= modbus_read_input_bits(ctx
, UT_INPUT_BITS_ADDRESS
,
427 MODBUS_MAX_READ_BITS
+ 1, tab_rp_bits
);
428 printf("* modbus_read_input_bits: ");
429 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
431 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
432 MODBUS_MAX_READ_REGISTERS
+ 1,
434 printf("* modbus_read_registers: ");
435 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
437 rc
= modbus_read_input_registers(ctx
, UT_INPUT_REGISTERS_ADDRESS
,
438 MODBUS_MAX_READ_REGISTERS
+ 1,
440 printf("* modbus_read_input_registers: ");
441 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
443 rc
= modbus_write_bits(ctx
, UT_BITS_ADDRESS
,
444 MODBUS_MAX_WRITE_BITS
+ 1, tab_rp_bits
);
445 printf("* modbus_write_bits: ");
446 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
448 rc
= modbus_write_registers(ctx
, UT_REGISTERS_ADDRESS
,
449 MODBUS_MAX_WRITE_REGISTERS
+ 1,
451 printf("* modbus_write_registers: ");
452 ASSERT_TRUE(rc
== -1 && errno
== EMBMDATA
, "");
455 old_slave
= modbus_get_slave(ctx
);
457 printf("\nTEST SLAVE REPLY:\n");
458 modbus_set_slave(ctx
, INVALID_SERVER_ID
);
459 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
460 UT_REGISTERS_NB
, tab_rp_registers
);
461 if (use_backend
== RTU
) {
462 const int RAW_REQ_LENGTH
= 6;
463 uint8_t raw_req
[] = { INVALID_SERVER_ID
, 0x03, 0x00, 0x01, 0x01, 0x01 };
464 /* Too many points */
465 uint8_t raw_invalid_req
[] = { INVALID_SERVER_ID
, 0x03, 0x00, 0x01, 0xFF, 0xFF };
466 const int RAW_RSP_LENGTH
= 7;
467 uint8_t raw_rsp
[] = { INVALID_SERVER_ID
, 0x03, 0x04, 0, 0, 0, 0 };
468 uint8_t rsp
[MODBUS_RTU_MAX_ADU_LENGTH
];
470 /* No response in RTU mode */
471 printf("1-A/3 No response from slave %d: ", INVALID_SERVER_ID
);
472 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
474 /* The slave raises a timeout on a confirmation to ignore because if an
475 * indication for another slave is received, a confirmation must follow */
478 /* Send a pair of indication/confirmation to the slave with a different
479 * slave ID to simulate a communication on a RS485 bus. At first, the
480 * slave will see the indication message then the confirmation, and it must
482 modbus_send_raw_request(ctx
, raw_req
, RAW_REQ_LENGTH
* sizeof(uint8_t));
483 modbus_send_raw_request(ctx
, raw_rsp
, RAW_RSP_LENGTH
* sizeof(uint8_t));
484 rc
= modbus_receive_confirmation(ctx
, rsp
);
486 printf("1-B/3 No response from slave %d on indication/confirmation messages: ",
488 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
490 /* Send an INVALID request for another slave */
491 modbus_send_raw_request(ctx
, raw_invalid_req
, RAW_REQ_LENGTH
* sizeof(uint8_t));
492 rc
= modbus_receive_confirmation(ctx
, rsp
);
494 printf("1-C/3 No response from slave %d with invalid request: ",
496 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
498 rc
= modbus_set_slave(ctx
, MODBUS_BROADCAST_ADDRESS
);
499 ASSERT_TRUE(rc
== 0, "Invalid broadcast address");
501 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
502 UT_REGISTERS_NB
, tab_rp_registers
);
503 printf("2/3 No reply after a broadcast query: ");
504 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
506 /* Response in TCP mode */
507 printf("1/3 Response from slave %d: ", INVALID_SERVER_ID
);
508 ASSERT_TRUE(rc
== UT_REGISTERS_NB
, "");
510 rc
= modbus_set_slave(ctx
, MODBUS_BROADCAST_ADDRESS
);
511 ASSERT_TRUE(rc
== 0, "Invalid broacast address");
513 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
514 UT_REGISTERS_NB
, tab_rp_registers
);
515 printf("2/3 Reply after a query with unit id == 0: ");
516 ASSERT_TRUE(rc
== UT_REGISTERS_NB
, "");
520 modbus_set_slave(ctx
, old_slave
);
522 printf("3/3 Response with an invalid TID or slave: ");
523 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE
,
524 1, tab_rp_registers
);
525 ASSERT_TRUE(rc
== -1, "");
527 printf("1/2 Report slave ID truncated: \n");
528 /* Set a marker to ensure limit is respected */
529 tab_rp_bits
[NB_REPORT_SLAVE_ID
- 1] = 42;
530 rc
= modbus_report_slave_id(ctx
, NB_REPORT_SLAVE_ID
- 1, tab_rp_bits
);
531 /* Return the size required (response size) but respects the defined limit */
532 ASSERT_TRUE(rc
== NB_REPORT_SLAVE_ID
&&
533 tab_rp_bits
[NB_REPORT_SLAVE_ID
- 1] == 42,
534 "Return is rc %d (%d) and marker is %d (42)",
535 rc
, NB_REPORT_SLAVE_ID
, tab_rp_bits
[NB_REPORT_SLAVE_ID
- 1]);
537 printf("2/2 Report slave ID: \n");
538 /* tab_rp_bits is used to store bytes */
539 rc
= modbus_report_slave_id(ctx
, NB_REPORT_SLAVE_ID
, tab_rp_bits
);
540 ASSERT_TRUE(rc
== NB_REPORT_SLAVE_ID
, "");
542 /* Slave ID is an arbitrary number for libmodbus */
543 ASSERT_TRUE(rc
> 0, "");
545 /* Run status indicator is ON */
546 ASSERT_TRUE(rc
> 1 && tab_rp_bits
[1] == 0xFF, "");
548 /* Print additional data as string */
550 printf("Additional data: ");
551 for (i
=2; i
< rc
; i
++) {
552 printf("%c", tab_rp_bits
[i
]);
557 /* Save original timeout */
558 modbus_get_response_timeout(ctx
, &old_response_to_sec
, &old_response_to_usec
);
559 modbus_get_byte_timeout(ctx
, &old_byte_to_sec
, &old_byte_to_usec
);
561 rc
= modbus_set_response_timeout(ctx
, 0, 0);
562 printf("1/6 Invalid response timeout (zero): ");
563 ASSERT_TRUE(rc
== -1 && errno
== EINVAL
, "");
565 rc
= modbus_set_response_timeout(ctx
, 0, 1000000);
566 printf("2/6 Invalid response timeout (too large us): ");
567 ASSERT_TRUE(rc
== -1 && errno
== EINVAL
, "");
569 rc
= modbus_set_byte_timeout(ctx
, 0, 1000000);
570 printf("3/6 Invalid byte timeout (too large us): ");
571 ASSERT_TRUE(rc
== -1 && errno
== EINVAL
, "");
573 modbus_set_response_timeout(ctx
, 0, 1);
574 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
575 UT_REGISTERS_NB
, tab_rp_registers
);
576 printf("4/6 1us response timeout: ");
577 if (rc
== -1 && errno
== ETIMEDOUT
) {
580 printf("FAILED (can fail on some platforms)\n");
583 /* A wait and flush operation is done by the error recovery code of
584 * libmodbus but after a sleep of current response timeout
585 * so 0 can be too short!
587 usleep(old_response_to_sec
* 1000000 + old_response_to_usec
);
590 /* Trigger a special behaviour on server to wait for 0.5 second before
591 * replying whereas allowed timeout is 0.2 second */
592 modbus_set_response_timeout(ctx
, 0, 200000);
593 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_SLEEP_500_MS
,
594 1, tab_rp_registers
);
595 printf("5/6 Too short response timeout (0.2s < 0.5s): ");
596 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
598 /* Wait for reply (0.2 + 0.4 > 0.5 s) and flush before continue */
602 modbus_set_response_timeout(ctx
, 0, 600000);
603 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_SLEEP_500_MS
,
604 1, tab_rp_registers
);
605 printf("6/6 Adequate response timeout (0.6s > 0.5s): ");
606 ASSERT_TRUE(rc
== 1, "");
608 /* Disable the byte timeout.
609 The full response must be available in the 600ms interval */
610 modbus_set_byte_timeout(ctx
, 0, 0);
611 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_SLEEP_500_MS
,
612 1, tab_rp_registers
);
613 printf("7/7 Disable byte timeout: ");
614 ASSERT_TRUE(rc
== 1, "");
616 /* Restore original response timeout */
617 modbus_set_response_timeout(ctx
, old_response_to_sec
,
618 old_response_to_usec
);
620 if (use_backend
== TCP
) {
621 /* The test server is only able to test byte timeouts with the TCP
624 /* Timeout of 3ms between bytes */
625 modbus_set_byte_timeout(ctx
, 0, 3000);
626 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS
,
627 1, tab_rp_registers
);
628 printf("1/2 Too small byte timeout (3ms < 5ms): ");
629 ASSERT_TRUE(rc
== -1 && errno
== ETIMEDOUT
, "");
631 /* Wait remaining bytes before flushing */
635 /* Timeout of 7ms between bytes */
636 modbus_set_byte_timeout(ctx
, 0, 7000);
637 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS
,
638 1, tab_rp_registers
);
639 printf("2/2 Adapted byte timeout (7ms > 5ms): ");
640 ASSERT_TRUE(rc
== 1, "");
643 /* Restore original byte timeout */
644 modbus_set_byte_timeout(ctx
, old_byte_to_sec
, old_byte_to_usec
);
647 printf("\nTEST BAD RESPONSE ERROR:\n");
649 /* Allocate only the required space */
650 tab_rp_registers_bad
= (uint16_t *) malloc(
651 UT_REGISTERS_NB_SPECIAL
* sizeof(uint16_t));
653 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS
,
654 UT_REGISTERS_NB_SPECIAL
, tab_rp_registers_bad
);
655 printf("* modbus_read_registers: ");
656 ASSERT_TRUE(rc
== -1 && errno
== EMBBADDATA
, "");
657 free(tab_rp_registers_bad
);
659 /** MANUAL EXCEPTION **/
660 printf("\nTEST MANUAL EXCEPTION:\n");
661 rc
= modbus_read_registers(ctx
, UT_REGISTERS_ADDRESS_SPECIAL
,
662 UT_REGISTERS_NB
, tab_rp_registers
);
664 printf("* modbus_read_registers at special address: ");
665 ASSERT_TRUE(rc
== -1 && errno
== EMBXSBUSY
, "");
667 /** Run a few tests to challenge the server code **/
668 if (test_server(ctx
, use_backend
) == -1) {
676 /* Test init functions */
677 printf("\nTEST INVALID INITIALIZATION:\n");
678 ctx
= modbus_new_rtu(NULL
, 1, 'A', 0, 0);
679 ASSERT_TRUE(ctx
== NULL
&& errno
== EINVAL
, "");
681 ctx
= modbus_new_rtu("/dev/dummy", 0, 'A', 0, 0);
682 ASSERT_TRUE(ctx
== NULL
&& errno
== EINVAL
, "");
684 printf("\nALL TESTS PASS WITH SUCCESS.\n");
688 /* Free the memory */
690 free(tab_rp_registers
);
692 /* Close the connection */
696 return (success
) ? 0 : -1;
699 /* Send crafted requests to test server resilience
700 and ensure proper exceptions are returned. */
701 int test_server(modbus_t
*ctx
, int use_backend
)
706 const int READ_RAW_REQ_LEN
= 6;
707 const int slave
= (use_backend
== RTU
) ? SERVER_ID
: MODBUS_TCP_SLAVE
;
708 uint8_t read_raw_req
[] = {
710 /* function, address, 5 values */
711 MODBUS_FC_READ_HOLDING_REGISTERS
,
712 UT_REGISTERS_ADDRESS
>> 8, UT_REGISTERS_ADDRESS
& 0xFF,
715 /* Write and read registers request */
716 const int RW_RAW_REQ_LEN
= 13;
717 uint8_t rw_raw_req
[] = {
719 /* function, addr to read, nb to read */
720 MODBUS_FC_WRITE_AND_READ_REGISTERS
,
722 UT_REGISTERS_ADDRESS
>> 8, UT_REGISTERS_ADDRESS
& 0xFF,
723 (MODBUS_MAX_WR_READ_REGISTERS
+ 1) >> 8,
724 (MODBUS_MAX_WR_READ_REGISTERS
+ 1) & 0xFF,
728 /* Write byte count */
730 /* One data to write... */
733 const int WRITE_RAW_REQ_LEN
= 13;
734 uint8_t write_raw_req
[] = {
736 /* function will be set in the loop */
737 MODBUS_FC_WRITE_MULTIPLE_REGISTERS
,
739 UT_REGISTERS_ADDRESS
>> 8, UT_REGISTERS_ADDRESS
& 0xFF,
740 /* 3 values, 6 bytes */
742 /* Dummy data to write */
743 0x02, 0x2B, 0x00, 0x01, 0x00, 0x64
745 const int INVALID_FC
= 0x42;
746 const int INVALID_FC_REQ_LEN
= 6;
747 uint8_t invalid_fc_raw_req
[] = {
748 slave
, 0x42, 0x00, 0x00, 0x00, 0x00
752 uint8_t rsp
[MODBUS_TCP_MAX_ADU_LENGTH
];
753 int tab_read_function
[] = {
754 MODBUS_FC_READ_COILS
,
755 MODBUS_FC_READ_DISCRETE_INPUTS
,
756 MODBUS_FC_READ_HOLDING_REGISTERS
,
757 MODBUS_FC_READ_INPUT_REGISTERS
759 int tab_read_nb_max
[] = {
760 MODBUS_MAX_READ_BITS
+ 1,
761 MODBUS_MAX_READ_BITS
+ 1,
762 MODBUS_MAX_READ_REGISTERS
+ 1,
763 MODBUS_MAX_READ_REGISTERS
+ 1
768 if (use_backend
== RTU
) {
776 printf("\nTEST RAW REQUESTS:\n");
778 uint32_t old_response_to_sec
;
779 uint32_t old_response_to_usec
;
781 /* This requests can generate flushes server side so we need a higher
782 * response timeout than the server. The server uses the defined response
783 * timeout to sleep before flushing.
784 * The old timeouts are restored at the end.
786 modbus_get_response_timeout(ctx
, &old_response_to_sec
, &old_response_to_usec
);
787 modbus_set_response_timeout(ctx
, 0, 600000);
789 int old_s
= modbus_get_socket(ctx
);
790 modbus_set_socket(ctx
, -1);
791 rc
= modbus_receive(ctx
, rsp
);
792 modbus_set_socket(ctx
, old_s
);
793 printf("* modbus_receive with invalid socket: ");
794 ASSERT_TRUE(rc
== -1, "FAILED (%d)\n", rc
);
796 req_length
= modbus_send_raw_request(ctx
, read_raw_req
, READ_RAW_REQ_LEN
);
797 printf("* modbus_send_raw_request: ");
798 ASSERT_TRUE(req_length
== (backend_length
+ 5), "FAILED (%d)\n", req_length
);
800 printf("* modbus_receive_confirmation: ");
801 rc
= modbus_receive_confirmation(ctx
, rsp
);
802 ASSERT_TRUE(rc
== (backend_length
+ 12), "FAILED (%d)\n", rc
);
804 /* Try to read more values than a response could hold for all data
806 for (i
=0; i
<4; i
++) {
807 rc
= send_crafted_request(ctx
, tab_read_function
[i
],
808 read_raw_req
, READ_RAW_REQ_LEN
,
809 tab_read_nb_max
[i
], 0,
810 backend_length
, backend_offset
);
815 rc
= send_crafted_request(ctx
, MODBUS_FC_WRITE_AND_READ_REGISTERS
,
816 rw_raw_req
, RW_RAW_REQ_LEN
,
817 MODBUS_MAX_WR_READ_REGISTERS
+ 1, 0,
818 backend_length
, backend_offset
);
822 rc
= send_crafted_request(ctx
, MODBUS_FC_WRITE_MULTIPLE_REGISTERS
,
823 write_raw_req
, WRITE_RAW_REQ_LEN
,
824 MODBUS_MAX_WRITE_REGISTERS
+ 1, 6,
825 backend_length
, backend_offset
);
829 rc
= send_crafted_request(ctx
, MODBUS_FC_WRITE_MULTIPLE_COILS
,
830 write_raw_req
, WRITE_RAW_REQ_LEN
,
831 MODBUS_MAX_WRITE_BITS
+ 1, 6,
832 backend_length
, backend_offset
);
836 /* Modbus write multiple registers with large number of values but a set a
837 small number of bytes in requests (not nb * 2 as usual). */
838 rc
= send_crafted_request(ctx
, MODBUS_FC_WRITE_MULTIPLE_REGISTERS
,
839 write_raw_req
, WRITE_RAW_REQ_LEN
,
840 MODBUS_MAX_WRITE_REGISTERS
, 6,
841 backend_length
, backend_offset
);
845 rc
= send_crafted_request(ctx
, MODBUS_FC_WRITE_MULTIPLE_COILS
,
846 write_raw_req
, WRITE_RAW_REQ_LEN
,
847 MODBUS_MAX_WRITE_BITS
, 6,
848 backend_length
, backend_offset
);
852 /* Test invalid function code */
853 modbus_send_raw_request(ctx
, invalid_fc_raw_req
, INVALID_FC_REQ_LEN
* sizeof(uint8_t));
854 rc
= modbus_receive_confirmation(ctx
, rsp
);
855 printf("Return an exception on unknown function code: ");
856 ASSERT_TRUE(rc
== (backend_length
+ EXCEPTION_RC
) &&
857 rsp
[backend_offset
] == (0x80 + INVALID_FC
), "")
859 modbus_set_response_timeout(ctx
, old_response_to_sec
, old_response_to_usec
);
862 modbus_set_response_timeout(ctx
, old_response_to_sec
, old_response_to_usec
);
867 int send_crafted_request(modbus_t
*ctx
, int function
,
868 uint8_t *req
, int req_len
,
869 uint16_t max_value
, uint16_t bytes
,
870 int backend_length
, int backend_offset
)
872 uint8_t rsp
[MODBUS_TCP_MAX_ADU_LENGTH
];
875 for (j
=0; j
<2; j
++) {
880 /* Try to read or write zero values on first iteration */
888 /* Try to read or write max values + 1 on second iteration */
889 req
[4] = (max_value
>> 8) & 0xFF;
890 req
[5] = max_value
& 0xFF;
892 /* Write query (nb values * 2 to convert in bytes for registers) */
897 modbus_send_raw_request(ctx
, req
, req_len
* sizeof(uint8_t));
899 printf("* try function 0x%X: %s 0 values: ", function
, bytes
? "write": "read");
901 printf("* try function 0x%X: %s %d values: ", function
, bytes
? "write": "read",
904 rc
= modbus_receive_confirmation(ctx
, rsp
);
905 ASSERT_TRUE(rc
== (backend_length
+ EXCEPTION_RC
) &&
906 rsp
[backend_offset
] == (0x80 + function
) &&
907 rsp
[backend_offset
+ 1] == MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE
, "");