unit-test-client.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /*
  2. * Copyright © 2008-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <errno.h>
  22. #include <modbus.h>
  23. #include "unit-test.h"
  24. enum {
  25. TCP,
  26. TCP_PI,
  27. RTU
  28. };
  29. int main(int argc, char *argv[])
  30. {
  31. uint8_t *tab_rp_bits;
  32. uint16_t *tab_rp_registers;
  33. uint16_t *tab_rp_registers_bad;
  34. modbus_t *ctx;
  35. int i;
  36. uint8_t value;
  37. int nb_points;
  38. int rc;
  39. float real;
  40. uint32_t ireal;
  41. struct timeval old_response_timeout;
  42. struct timeval response_timeout;
  43. int use_backend;
  44. if (argc > 1) {
  45. if (strcmp(argv[1], "tcp") == 0) {
  46. use_backend = TCP;
  47. } else if (strcmp(argv[1], "tcppi") == 0) {
  48. use_backend = TCP_PI;
  49. } else if (strcmp(argv[1], "rtu") == 0) {
  50. use_backend = RTU;
  51. } else {
  52. printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus client for unit testing\n\n", argv[0]);
  53. exit(1);
  54. }
  55. } else {
  56. /* By default */
  57. use_backend = TCP;
  58. }
  59. if (use_backend == TCP) {
  60. ctx = modbus_new_tcp("127.0.0.1", 1502);
  61. } else if (use_backend == TCP_PI) {
  62. ctx = modbus_new_tcp_pi("::1", "1502");
  63. } else {
  64. ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1);
  65. }
  66. if (ctx == NULL) {
  67. fprintf(stderr, "Unable to allocate libmodbus context\n");
  68. return -1;
  69. }
  70. modbus_set_debug(ctx, TRUE);
  71. modbus_set_error_recovery(ctx,
  72. MODBUS_ERROR_RECOVERY_LINK |
  73. MODBUS_ERROR_RECOVERY_PROTOCOL);
  74. if (use_backend == RTU) {
  75. modbus_set_slave(ctx, SERVER_ID);
  76. }
  77. if (modbus_connect(ctx) == -1) {
  78. fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
  79. modbus_free(ctx);
  80. return -1;
  81. }
  82. /* Allocate and initialize the memory to store the bits */
  83. nb_points = (UT_BITS_NB > UT_INPUT_BITS_NB) ? UT_BITS_NB : UT_INPUT_BITS_NB;
  84. tab_rp_bits = (uint8_t *) malloc(nb_points * sizeof(uint8_t));
  85. memset(tab_rp_bits, 0, nb_points * sizeof(uint8_t));
  86. /* Allocate and initialize the memory to store the registers */
  87. nb_points = (UT_REGISTERS_NB > UT_INPUT_REGISTERS_NB) ?
  88. UT_REGISTERS_NB : UT_INPUT_REGISTERS_NB;
  89. tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t));
  90. memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));
  91. printf("** UNIT TESTING **\n");
  92. printf("\nTEST WRITE/READ:\n");
  93. /** COIL BITS **/
  94. /* Single */
  95. rc = modbus_write_bit(ctx, UT_BITS_ADDRESS, ON);
  96. printf("1/2 modbus_write_bit: ");
  97. if (rc == 1) {
  98. printf("OK\n");
  99. } else {
  100. printf("FAILED\n");
  101. goto close;
  102. }
  103. rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 1, tab_rp_bits);
  104. printf("2/2 modbus_read_bits: ");
  105. if (rc != 1) {
  106. printf("FAILED (nb points %d)\n", rc);
  107. goto close;
  108. }
  109. if (tab_rp_bits[0] != ON) {
  110. printf("FAILED (%0X != %0X)\n", tab_rp_bits[0], ON);
  111. goto close;
  112. }
  113. printf("OK\n");
  114. /* End single */
  115. /* Multiple bits */
  116. {
  117. uint8_t tab_value[UT_BITS_NB];
  118. modbus_set_bits_from_bytes(tab_value, 0, UT_BITS_NB, UT_BITS_TAB);
  119. rc = modbus_write_bits(ctx, UT_BITS_ADDRESS,
  120. UT_BITS_NB, tab_value);
  121. printf("1/2 modbus_write_bits: ");
  122. if (rc == UT_BITS_NB) {
  123. printf("OK\n");
  124. } else {
  125. printf("FAILED\n");
  126. goto close;
  127. }
  128. }
  129. rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_rp_bits);
  130. printf("2/2 modbus_read_bits: ");
  131. if (rc != UT_BITS_NB) {
  132. printf("FAILED (nb points %d)\n", rc);
  133. goto close;
  134. }
  135. i = 0;
  136. nb_points = UT_BITS_NB;
  137. while (nb_points > 0) {
  138. int nb_bits = (nb_points > 8) ? 8 : nb_points;
  139. value = modbus_get_byte_from_bits(tab_rp_bits, i*8, nb_bits);
  140. if (value != UT_BITS_TAB[i]) {
  141. printf("FAILED (%0X != %0X)\n", value, UT_BITS_TAB[i]);
  142. goto close;
  143. }
  144. nb_points -= nb_bits;
  145. i++;
  146. }
  147. printf("OK\n");
  148. /* End of multiple bits */
  149. /** DISCRETE INPUTS **/
  150. rc = modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS,
  151. UT_INPUT_BITS_NB, tab_rp_bits);
  152. printf("1/1 modbus_read_input_bits: ");
  153. if (rc != UT_INPUT_BITS_NB) {
  154. printf("FAILED (nb points %d)\n", rc);
  155. goto close;
  156. }
  157. i = 0;
  158. nb_points = UT_INPUT_BITS_NB;
  159. while (nb_points > 0) {
  160. int nb_bits = (nb_points > 8) ? 8 : nb_points;
  161. value = modbus_get_byte_from_bits(tab_rp_bits, i*8, nb_bits);
  162. if (value != UT_INPUT_BITS_TAB[i]) {
  163. printf("FAILED (%0X != %0X)\n", value, UT_INPUT_BITS_TAB[i]);
  164. goto close;
  165. }
  166. nb_points -= nb_bits;
  167. i++;
  168. }
  169. printf("OK\n");
  170. /** HOLDING REGISTERS **/
  171. /* Single register */
  172. rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x1234);
  173. printf("1/2 modbus_write_register: ");
  174. if (rc == 1) {
  175. printf("OK\n");
  176. } else {
  177. printf("FAILED\n");
  178. goto close;
  179. }
  180. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  181. 1, tab_rp_registers);
  182. printf("2/2 modbus_read_registers: ");
  183. if (rc != 1) {
  184. printf("FAILED (nb points %d)\n", rc);
  185. goto close;
  186. }
  187. if (tab_rp_registers[0] != 0x1234) {
  188. printf("FAILED (%0X != %0X)\n",
  189. tab_rp_registers[0], 0x1234);
  190. goto close;
  191. }
  192. printf("OK\n");
  193. /* End of single register */
  194. /* Many registers */
  195. rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS,
  196. UT_REGISTERS_NB, UT_REGISTERS_TAB);
  197. printf("1/5 modbus_write_registers: ");
  198. if (rc == UT_REGISTERS_NB) {
  199. printf("OK\n");
  200. } else {
  201. printf("FAILED\n");
  202. goto close;
  203. }
  204. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  205. UT_REGISTERS_NB, tab_rp_registers);
  206. printf("2/5 modbus_read_registers: ");
  207. if (rc != UT_REGISTERS_NB) {
  208. printf("FAILED (nb points %d)\n", rc);
  209. goto close;
  210. }
  211. for (i=0; i < UT_REGISTERS_NB; i++) {
  212. if (tab_rp_registers[i] != UT_REGISTERS_TAB[i]) {
  213. printf("FAILED (%0X != %0X)\n",
  214. tab_rp_registers[i],
  215. UT_REGISTERS_TAB[i]);
  216. goto close;
  217. }
  218. }
  219. printf("OK\n");
  220. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  221. 0, tab_rp_registers);
  222. printf("3/5 modbus_read_registers (0): ");
  223. if (rc != -1) {
  224. printf("FAILED (nb_points %d)\n", rc);
  225. goto close;
  226. }
  227. printf("OK\n");
  228. nb_points = (UT_REGISTERS_NB >
  229. UT_INPUT_REGISTERS_NB) ?
  230. UT_REGISTERS_NB : UT_INPUT_REGISTERS_NB;
  231. memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));
  232. /* Write registers to zero from tab_rp_registers and store read registers
  233. into tab_rp_registers. So the read registers must set to 0, except the
  234. first one because there is an offset of 1 register on write. */
  235. rc = modbus_write_and_read_registers(ctx,
  236. UT_REGISTERS_ADDRESS + 1,
  237. UT_REGISTERS_NB - 1,
  238. tab_rp_registers,
  239. UT_REGISTERS_ADDRESS,
  240. UT_REGISTERS_NB,
  241. tab_rp_registers);
  242. printf("4/5 modbus_write_and_read_registers: ");
  243. if (rc != UT_REGISTERS_NB) {
  244. printf("FAILED (nb points %d != %d)\n", rc, UT_REGISTERS_NB);
  245. goto close;
  246. }
  247. if (tab_rp_registers[0] != UT_REGISTERS_TAB[0]) {
  248. printf("FAILED (%0X != %0X)\n",
  249. tab_rp_registers[0], UT_REGISTERS_TAB[0]);
  250. }
  251. for (i=1; i < UT_REGISTERS_NB; i++) {
  252. if (tab_rp_registers[i] != 0) {
  253. printf("FAILED (%0X != %0X)\n",
  254. tab_rp_registers[i], 0);
  255. goto close;
  256. }
  257. }
  258. printf("OK\n");
  259. /* End of many registers */
  260. /** INPUT REGISTERS **/
  261. rc = modbus_read_input_registers(ctx, UT_INPUT_REGISTERS_ADDRESS,
  262. UT_INPUT_REGISTERS_NB,
  263. tab_rp_registers);
  264. printf("1/1 modbus_read_input_registers: ");
  265. if (rc != UT_INPUT_REGISTERS_NB) {
  266. printf("FAILED (nb points %d)\n", rc);
  267. goto close;
  268. }
  269. for (i=0; i < UT_INPUT_REGISTERS_NB; i++) {
  270. if (tab_rp_registers[i] != UT_INPUT_REGISTERS_TAB[i]) {
  271. printf("FAILED (%0X != %0X)\n",
  272. tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]);
  273. goto close;
  274. }
  275. }
  276. printf("OK\n");
  277. printf("\nTEST FLOATS\n");
  278. /** FLOAT **/
  279. printf("1/4 Set float: ");
  280. modbus_set_float(UT_REAL, tab_rp_registers);
  281. if (tab_rp_registers[1] == (UT_IREAL >> 16) &&
  282. tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) {
  283. printf("OK\n");
  284. } else {
  285. /* Avoid *((uint32_t *)tab_rp_registers)
  286. * https://github.com/stephane/libmodbus/pull/104 */
  287. ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF;
  288. ireal |= (uint32_t) tab_rp_registers[1] << 16;
  289. printf("FAILED (%x != %x)\n", ireal, UT_IREAL);
  290. goto close;
  291. }
  292. printf("2/4 Get float: ");
  293. real = modbus_get_float(tab_rp_registers);
  294. if (real == UT_REAL) {
  295. printf("OK\n");
  296. } else {
  297. printf("FAILED (%f != %f)\n", real, UT_REAL);
  298. goto close;
  299. }
  300. printf("3/4 Set float in DBCA order: ");
  301. modbus_set_float_dcba(UT_REAL, tab_rp_registers);
  302. if (tab_rp_registers[1] == (UT_IREAL_DCBA >> 16) &&
  303. tab_rp_registers[0] == (UT_IREAL_DCBA & 0xFFFF)) {
  304. printf("OK\n");
  305. } else {
  306. ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF;
  307. ireal |= (uint32_t) tab_rp_registers[1] << 16;
  308. printf("FAILED (%x != %x)\n", ireal, UT_IREAL_DCBA);
  309. goto close;
  310. }
  311. printf("4/4 Get float in DCBA order: ");
  312. real = modbus_get_float_dcba(tab_rp_registers);
  313. if (real == UT_REAL) {
  314. printf("OK\n");
  315. } else {
  316. printf("FAILED (%f != %f)\n", real, UT_REAL);
  317. goto close;
  318. }
  319. 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");
  322. /* The mapping begins at 0 and ends at address + nb_points so
  323. * the addresses are not valid. */
  324. rc = modbus_read_bits(ctx, UT_BITS_ADDRESS,
  325. UT_BITS_NB + 1, tab_rp_bits);
  326. printf("* modbus_read_bits: ");
  327. if (rc == -1 && errno == EMBXILADD) {
  328. printf("OK\n");
  329. } else {
  330. printf("FAILED\n");
  331. goto close;
  332. }
  333. rc = modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS,
  334. UT_INPUT_BITS_NB + 1, tab_rp_bits);
  335. printf("* modbus_read_input_bits: ");
  336. if (rc == -1 && errno == EMBXILADD)
  337. printf("OK\n");
  338. else {
  339. printf("FAILED\n");
  340. goto close;
  341. }
  342. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  343. UT_REGISTERS_NB + 1, tab_rp_registers);
  344. printf("* modbus_read_registers: ");
  345. if (rc == -1 && errno == EMBXILADD)
  346. printf("OK\n");
  347. else {
  348. printf("FAILED\n");
  349. goto close;
  350. }
  351. rc = modbus_read_input_registers(ctx, UT_INPUT_REGISTERS_ADDRESS,
  352. UT_INPUT_REGISTERS_NB + 1,
  353. tab_rp_registers);
  354. printf("* modbus_read_input_registers: ");
  355. if (rc == -1 && errno == EMBXILADD)
  356. printf("OK\n");
  357. else {
  358. printf("FAILED\n");
  359. goto close;
  360. }
  361. rc = modbus_write_bit(ctx, UT_BITS_ADDRESS + UT_BITS_NB, ON);
  362. printf("* modbus_write_bit: ");
  363. if (rc == -1 && errno == EMBXILADD) {
  364. printf("OK\n");
  365. } else {
  366. printf("FAILED\n");
  367. goto close;
  368. }
  369. rc = modbus_write_bits(ctx, UT_BITS_ADDRESS + UT_BITS_NB,
  370. UT_BITS_NB, tab_rp_bits);
  371. printf("* modbus_write_coils: ");
  372. if (rc == -1 && errno == EMBXILADD) {
  373. printf("OK\n");
  374. } else {
  375. printf("FAILED\n");
  376. goto close;
  377. }
  378. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB,
  379. UT_REGISTERS_NB, tab_rp_registers);
  380. printf("* modbus_write_registers: ");
  381. if (rc == -1 && errno == EMBXILADD) {
  382. printf("OK\n");
  383. } else {
  384. printf("FAILED\n");
  385. goto close;
  386. }
  387. /** TOO MANY DATA **/
  388. printf("\nTEST TOO MANY DATA ERROR:\n");
  389. rc = modbus_read_bits(ctx, UT_BITS_ADDRESS,
  390. MODBUS_MAX_READ_BITS + 1, tab_rp_bits);
  391. printf("* modbus_read_bits: ");
  392. if (rc == -1 && errno == EMBMDATA) {
  393. printf("OK\n");
  394. } else {
  395. printf("FAILED\n");
  396. goto close;
  397. }
  398. rc = modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS,
  399. MODBUS_MAX_READ_BITS + 1, tab_rp_bits);
  400. printf("* modbus_read_input_bits: ");
  401. if (rc == -1 && errno == EMBMDATA) {
  402. printf("OK\n");
  403. } else {
  404. printf("FAILED\n");
  405. goto close;
  406. }
  407. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  408. MODBUS_MAX_READ_REGISTERS + 1,
  409. tab_rp_registers);
  410. printf("* modbus_read_registers: ");
  411. if (rc == -1 && errno == EMBMDATA) {
  412. printf("OK\n");
  413. } else {
  414. printf("FAILED\n");
  415. goto close;
  416. }
  417. rc = modbus_read_input_registers(ctx, UT_INPUT_REGISTERS_ADDRESS,
  418. MODBUS_MAX_READ_REGISTERS + 1,
  419. tab_rp_registers);
  420. printf("* modbus_read_input_registers: ");
  421. if (rc == -1 && errno == EMBMDATA) {
  422. printf("OK\n");
  423. } else {
  424. printf("FAILED\n");
  425. goto close;
  426. }
  427. rc = modbus_write_bits(ctx, UT_BITS_ADDRESS,
  428. MODBUS_MAX_WRITE_BITS + 1, tab_rp_bits);
  429. printf("* modbus_write_bits: ");
  430. if (rc == -1 && errno == EMBMDATA) {
  431. printf("OK\n");
  432. } else {
  433. goto close;
  434. printf("FAILED\n");
  435. }
  436. rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS,
  437. MODBUS_MAX_WRITE_REGISTERS + 1,
  438. tab_rp_registers);
  439. printf("* modbus_write_registers: ");
  440. if (rc == -1 && errno == EMBMDATA) {
  441. printf("OK\n");
  442. } else {
  443. printf("FAILED\n");
  444. goto close;
  445. }
  446. /** SLAVE REPLY **/
  447. printf("\nTEST SLAVE REPLY:\n");
  448. modbus_set_slave(ctx, INVALID_SERVER_ID);
  449. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  450. UT_REGISTERS_NB, tab_rp_registers);
  451. if (use_backend == RTU) {
  452. const int RAW_REQ_LENGTH = 6;
  453. uint8_t raw_req[] = { INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0x01, 0x01 };
  454. /* Too many points */
  455. uint8_t raw_invalid_req[] = { INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0xFF, 0xFF };
  456. const int RAW_REP_LENGTH = 7;
  457. uint8_t raw_rep[] = { INVALID_SERVER_ID, 0x03, 0x04, 0, 0, 0, 0 };
  458. uint8_t rsp[MODBUS_RTU_MAX_ADU_LENGTH];
  459. /* No response in RTU mode */
  460. printf("1/5-A No response from slave %d: ", INVALID_SERVER_ID);
  461. if (rc == -1 && errno == ETIMEDOUT) {
  462. printf("OK\n");
  463. } else {
  464. printf("FAILED\n");
  465. goto close;
  466. }
  467. /* The slave raises a timeout on a confirmation to ignore because if an
  468. * indication for another slave is received, a confirmation must follow */
  469. /* Send a pair of indication/confirmation to the slave with a different
  470. * slave ID to simulate a communication on a RS485 bus. At first, the
  471. * slave will see the indication message then the confirmation, and it must
  472. * ignore both. */
  473. modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t));
  474. modbus_send_raw_request(ctx, raw_rep, RAW_REP_LENGTH * sizeof(uint8_t));
  475. rc = modbus_receive_confirmation(ctx, rsp);
  476. printf("1/5-B No response from slave %d on indication/confirmation messages: ",
  477. INVALID_SERVER_ID);
  478. if (rc == -1 && errno == ETIMEDOUT) {
  479. printf("OK\n");
  480. } else {
  481. printf("FAILED (%d)\n", rc);
  482. goto close;
  483. }
  484. /* Send an INVALID request for another slave */
  485. modbus_send_raw_request(ctx, raw_invalid_req, RAW_REQ_LENGTH * sizeof(uint8_t));
  486. rc = modbus_receive_confirmation(ctx, rsp);
  487. printf("1/5-C No response from slave %d with invalid request: ",
  488. INVALID_SERVER_ID);
  489. if (rc == -1 && errno == ETIMEDOUT) {
  490. printf("OK\n");
  491. } else {
  492. printf("FAILED (%d)\n", rc);
  493. goto close;
  494. }
  495. } else {
  496. /* Response in TCP mode */
  497. printf("1/4 Response from slave %d: ", INVALID_SERVER_ID);
  498. if (rc == UT_REGISTERS_NB) {
  499. printf("OK\n");
  500. } else {
  501. printf("FAILED\n");
  502. goto close;
  503. }
  504. }
  505. rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS);
  506. if (rc == -1) {
  507. printf("Invalid broacast address\n");
  508. goto close;
  509. }
  510. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  511. UT_REGISTERS_NB, tab_rp_registers);
  512. printf("2/5 Reply after a broadcast query: ");
  513. if (rc == UT_REGISTERS_NB) {
  514. printf("OK\n");
  515. } else {
  516. printf("FAILED\n");
  517. goto close;
  518. }
  519. /* Restore slave */
  520. if (use_backend == RTU) {
  521. modbus_set_slave(ctx, SERVER_ID);
  522. } else {
  523. modbus_set_slave(ctx, MODBUS_TCP_SLAVE);
  524. }
  525. printf("3/5 Report slave ID: \n");
  526. /* tab_rp_bits is used to store bytes */
  527. rc = modbus_report_slave_id(ctx, tab_rp_bits);
  528. if (rc == -1) {
  529. printf("FAILED\n");
  530. goto close;
  531. }
  532. /* Slave ID is an arbitraty number for libmodbus */
  533. if (rc > 0) {
  534. printf("OK Slave ID is %d\n", tab_rp_bits[0]);
  535. } else {
  536. printf("FAILED\n");
  537. goto close;
  538. }
  539. /* Run status indicator */
  540. if (rc > 1 && tab_rp_bits[1] == 0xFF) {
  541. printf("OK Run Status Indicator is %s\n", tab_rp_bits[1] ? "ON" : "OFF");
  542. } else {
  543. printf("FAILED\n");
  544. goto close;
  545. }
  546. /* Print additional data as string */
  547. if (rc > 2) {
  548. printf("Additional data: ");
  549. for (i=2; i < rc; i++) {
  550. printf("%c", tab_rp_bits[i]);
  551. }
  552. printf("\n");
  553. }
  554. printf("5/5 Response with an invalid TID or slave: ");
  555. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE,
  556. 1, tab_rp_registers);
  557. if (rc == -1) {
  558. printf("OK\n");
  559. } else {
  560. printf("FAILED\n");
  561. goto close;
  562. }
  563. /* Save original timeout */
  564. modbus_get_response_timeout(ctx, &old_response_timeout);
  565. /* Define a new and too short timeout */
  566. response_timeout.tv_sec = 0;
  567. response_timeout.tv_usec = 0;
  568. modbus_set_response_timeout(ctx, &response_timeout);
  569. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  570. UT_REGISTERS_NB, tab_rp_registers);
  571. printf("4/4 Too short timeout: ");
  572. if (rc == -1 && errno == ETIMEDOUT) {
  573. printf("OK\n");
  574. } else {
  575. printf("FAILED (can fail on slow systems or Windows)\n");
  576. }
  577. /* Restore original timeout */
  578. modbus_set_response_timeout(ctx, &old_response_timeout);
  579. /* A wait and flush operation is done by the error recovery code of
  580. * libmodbus */
  581. /** BAD RESPONSE **/
  582. printf("\nTEST BAD RESPONSE ERROR:\n");
  583. /* Allocate only the required space */
  584. tab_rp_registers_bad = (uint16_t *) malloc(
  585. UT_REGISTERS_NB_SPECIAL * sizeof(uint16_t));
  586. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
  587. UT_REGISTERS_NB_SPECIAL, tab_rp_registers_bad);
  588. printf("* modbus_read_registers: ");
  589. if (rc == -1 && errno == EMBBADDATA) {
  590. printf("OK\n");
  591. } else {
  592. printf("FAILED\n");
  593. goto close;
  594. }
  595. free(tab_rp_registers_bad);
  596. /** MANUAL EXCEPTION **/
  597. printf("\nTEST MANUAL EXCEPTION:\n");
  598. rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_SPECIAL,
  599. UT_REGISTERS_NB, tab_rp_registers);
  600. printf("* modbus_read_registers at special address: ");
  601. if (rc == -1 && errno == EMBXSBUSY) {
  602. printf("OK\n");
  603. } else {
  604. printf("FAILED\n");
  605. goto close;
  606. }
  607. /** RAW REQUEST */
  608. printf("\nTEST RAW REQUESTS:\n");
  609. {
  610. int j;
  611. const int RAW_REQ_LENGTH = 6;
  612. uint8_t raw_req[] = {
  613. (use_backend == RTU) ? SERVER_ID : 0xFF,
  614. 0x03, 0x00, 0x01, 0x0, 0x05,
  615. };
  616. int req_length;
  617. uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
  618. int tab_function[] = {0x01, 0x02, 0x03, 0x04};
  619. int tab_nb_max[] = {
  620. MODBUS_MAX_READ_BITS + 1,
  621. MODBUS_MAX_READ_BITS + 1,
  622. MODBUS_MAX_READ_REGISTERS + 1,
  623. MODBUS_MAX_READ_REGISTERS + 1
  624. };
  625. req_length = modbus_send_raw_request(ctx, raw_req,
  626. RAW_REQ_LENGTH * sizeof(uint8_t));
  627. printf("* modbus_send_raw_request: ");
  628. if ((use_backend == RTU && req_length == (RAW_REQ_LENGTH + 2)) ||
  629. ((use_backend == TCP || use_backend == TCP_PI) &&
  630. req_length == (RAW_REQ_LENGTH + 6))) {
  631. printf("OK\n");
  632. } else {
  633. printf("FAILED (%d)\n", req_length);
  634. goto close;
  635. }
  636. printf("* modbus_receive_confirmation: ");
  637. rc = modbus_receive_confirmation(ctx, rsp);
  638. if ((use_backend == RTU && rc == 15) ||
  639. ((use_backend == TCP || use_backend == TCP_PI) &&
  640. rc == 19)) {
  641. printf("OK\n");
  642. } else {
  643. printf("FAILED (%d)\n", rc);
  644. goto close;
  645. }
  646. /* Try to crash server with raw requests to bypass checks of client. */
  647. /* Address */
  648. raw_req[2] = 0;
  649. raw_req[3] = 0;
  650. /* Try to read more values than a response could hold for all data
  651. * types.
  652. */
  653. for (i=0; i<4; i++) {
  654. raw_req[1] = tab_function[i];
  655. for (j=0; j<2; j++) {
  656. if (j == 0) {
  657. /* Try to read zero values on first iteration */
  658. raw_req[4] = 0x00;
  659. raw_req[5] = 0x00;
  660. } else {
  661. /* Try to read max values + 1 on second iteration */
  662. raw_req[4] = (tab_nb_max[i] >> 8) & 0xFF;
  663. raw_req[5] = tab_nb_max[i] & 0xFF;
  664. }
  665. req_length = modbus_send_raw_request(ctx, raw_req,
  666. RAW_REQ_LENGTH * sizeof(uint8_t));
  667. printf("* try an exploit on function %d: ", tab_function[i]);
  668. rc = modbus_receive_confirmation(ctx, rsp);
  669. if (rc == 9 &&
  670. rsp[7] == (0x80 + tab_function[i]) &&
  671. rsp[8] == MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE) {
  672. printf("OK\n");
  673. } else {
  674. printf("FAILED\n");
  675. goto close;
  676. }
  677. }
  678. }
  679. }
  680. printf("\nALL TESTS PASS WITH SUCCESS.\n");
  681. close:
  682. /* Free the memory */
  683. free(tab_rp_bits);
  684. free(tab_rp_registers);
  685. /* Close the connection */
  686. modbus_close(ctx);
  687. modbus_free(ctx);
  688. return 0;
  689. }