unit-test-master.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. * Copyright © 2008-2010 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. int main(void)
  25. {
  26. uint8_t *tab_rp_status;
  27. uint16_t *tab_rp_registers;
  28. uint16_t *tab_rp_registers_bad;
  29. modbus_param_t mb_param;
  30. int i;
  31. uint8_t value;
  32. int address;
  33. int nb_points;
  34. int rc;
  35. float real;
  36. struct timeval timeout_begin_old;
  37. struct timeval timeout_begin_new;
  38. /*
  39. modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, 'N', 8, 1,
  40. CLIENT_ID);
  41. */
  42. /* TCP */
  43. modbus_init_tcp(&mb_param, "127.0.0.1", 1502);
  44. modbus_set_debug(&mb_param, TRUE);
  45. if (modbus_connect(&mb_param) == -1) {
  46. fprintf(stderr, "Connection failed: %s\n",
  47. modbus_strerror(errno));
  48. return -1;
  49. }
  50. /* Allocate and initialize the memory to store the status */
  51. nb_points = (UT_COIL_STATUS_NB_POINTS > UT_INPUT_STATUS_NB_POINTS) ?
  52. UT_COIL_STATUS_NB_POINTS : UT_INPUT_STATUS_NB_POINTS;
  53. tab_rp_status = (uint8_t *) malloc(nb_points * sizeof(uint8_t));
  54. memset(tab_rp_status, 0, nb_points * sizeof(uint8_t));
  55. /* Allocate and initialize the memory to store the registers */
  56. nb_points = (UT_HOLDING_REGISTERS_NB_POINTS >
  57. UT_INPUT_REGISTERS_NB_POINTS) ?
  58. UT_HOLDING_REGISTERS_NB_POINTS : UT_INPUT_REGISTERS_NB_POINTS;
  59. tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t));
  60. memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));
  61. printf("** UNIT TESTING **\n");
  62. printf("\nTEST WRITE/READ:\n");
  63. /** COIL STATUS **/
  64. /* Single */
  65. rc = force_single_coil(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, ON);
  66. printf("1/2 force_single_coil: ");
  67. if (rc == 1) {
  68. printf("OK\n");
  69. } else {
  70. printf("FAILED\n");
  71. goto close;
  72. }
  73. rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, 1,
  74. tab_rp_status);
  75. printf("2/2 read_coil_status: ");
  76. if (rc != 1) {
  77. printf("FAILED (nb points %d)\n", rc);
  78. goto close;
  79. }
  80. if (tab_rp_status[0] != ON) {
  81. printf("FAILED (%0X = != %0X)\n", tab_rp_status[0], ON);
  82. goto close;
  83. }
  84. printf("OK\n");
  85. /* End single */
  86. /* Multiple coils */
  87. {
  88. uint8_t tab_value[UT_COIL_STATUS_NB_POINTS];
  89. set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS,
  90. UT_COIL_STATUS_TAB);
  91. rc = force_multiple_coils(&mb_param, SERVER_ID,
  92. UT_COIL_STATUS_ADDRESS,
  93. UT_COIL_STATUS_NB_POINTS,
  94. tab_value);
  95. printf("1/2 force_multiple_coils: ");
  96. if (rc == UT_COIL_STATUS_NB_POINTS) {
  97. printf("OK\n");
  98. } else {
  99. printf("FAILED\n");
  100. goto close;
  101. }
  102. }
  103. rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS,
  104. UT_COIL_STATUS_NB_POINTS, tab_rp_status);
  105. printf("2/2 read_coil_status: ");
  106. if (rc != UT_COIL_STATUS_NB_POINTS) {
  107. printf("FAILED (nb points %d)\n", rc);
  108. goto close;
  109. }
  110. i = 0;
  111. address = UT_COIL_STATUS_ADDRESS;
  112. nb_points = UT_COIL_STATUS_NB_POINTS;
  113. while (nb_points > 0) {
  114. int nb_bits = (nb_points > 8) ? 8 : nb_points;
  115. value = get_byte_from_bits(tab_rp_status, i*8, nb_bits);
  116. if (value != UT_COIL_STATUS_TAB[i]) {
  117. printf("FAILED (%0X != %0X)\n",
  118. value, UT_COIL_STATUS_TAB[i]);
  119. goto close;
  120. }
  121. nb_points -= nb_bits;
  122. i++;
  123. }
  124. printf("OK\n");
  125. /* End of multiple coils */
  126. /** INPUT STATUS **/
  127. rc = read_input_status(&mb_param, SERVER_ID, UT_INPUT_STATUS_ADDRESS,
  128. UT_INPUT_STATUS_NB_POINTS, tab_rp_status);
  129. printf("1/1 read_input_status: ");
  130. if (rc != UT_INPUT_STATUS_NB_POINTS) {
  131. printf("FAILED (nb points %d)\n", rc);
  132. goto close;
  133. }
  134. i = 0;
  135. address = UT_INPUT_STATUS_ADDRESS;
  136. nb_points = UT_INPUT_STATUS_NB_POINTS;
  137. while (nb_points > 0) {
  138. int nb_bits = (nb_points > 8) ? 8 : nb_points;
  139. value = get_byte_from_bits(tab_rp_status, i*8, nb_bits);
  140. if (value != UT_INPUT_STATUS_TAB[i]) {
  141. printf("FAILED (%0X != %0X)\n",
  142. value, UT_INPUT_STATUS_TAB[i]);
  143. goto close;
  144. }
  145. nb_points -= nb_bits;
  146. i++;
  147. }
  148. printf("OK\n");
  149. /** HOLDING REGISTERS **/
  150. /* Single register */
  151. rc = preset_single_register(&mb_param, SERVER_ID,
  152. UT_HOLDING_REGISTERS_ADDRESS, 0x1234);
  153. printf("1/2 preset_single_register: ");
  154. if (rc == 1) {
  155. printf("OK\n");
  156. } else {
  157. printf("FAILED\n");
  158. goto close;
  159. }
  160. rc = read_holding_registers(&mb_param, SERVER_ID,
  161. UT_HOLDING_REGISTERS_ADDRESS,
  162. 1, tab_rp_registers);
  163. printf("2/2 read_holding_registers: ");
  164. if (rc != 1) {
  165. printf("FAILED (nb points %d)\n", rc);
  166. goto close;
  167. }
  168. if (tab_rp_registers[0] != 0x1234) {
  169. printf("FAILED (%0X != %0X)\n",
  170. tab_rp_registers[0], 0x1234);
  171. goto close;
  172. }
  173. printf("OK\n");
  174. /* End of single register */
  175. /* Many registers */
  176. rc = preset_multiple_registers(&mb_param, SERVER_ID,
  177. UT_HOLDING_REGISTERS_ADDRESS,
  178. UT_HOLDING_REGISTERS_NB_POINTS,
  179. UT_HOLDING_REGISTERS_TAB);
  180. printf("1/2 preset_multiple_registers: ");
  181. if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
  182. printf("OK\n");
  183. } else {
  184. printf("FAILED\n");
  185. goto close;
  186. }
  187. rc = read_holding_registers(&mb_param, SERVER_ID,
  188. UT_HOLDING_REGISTERS_ADDRESS,
  189. UT_HOLDING_REGISTERS_NB_POINTS,
  190. tab_rp_registers);
  191. printf("2/2 read_holding_registers: ");
  192. if (rc != UT_HOLDING_REGISTERS_NB_POINTS) {
  193. printf("FAILED (nb points %d)\n", rc);
  194. goto close;
  195. }
  196. for (i=0; i < UT_HOLDING_REGISTERS_NB_POINTS; i++) {
  197. if (tab_rp_registers[i] != UT_HOLDING_REGISTERS_TAB[i]) {
  198. printf("FAILED (%0X != %0X)\n",
  199. tab_rp_registers[i],
  200. UT_HOLDING_REGISTERS_TAB[i]);
  201. goto close;
  202. }
  203. }
  204. printf("OK\n");
  205. /* End of many registers */
  206. /** INPUT REGISTERS **/
  207. rc = read_input_registers(&mb_param, SERVER_ID,
  208. UT_INPUT_REGISTERS_ADDRESS,
  209. UT_INPUT_REGISTERS_NB_POINTS,
  210. tab_rp_registers);
  211. printf("1/1 read_input_registers: ");
  212. if (rc != UT_INPUT_REGISTERS_NB_POINTS) {
  213. printf("FAILED (nb points %d)\n", rc);
  214. goto close;
  215. }
  216. for (i=0; i < UT_INPUT_REGISTERS_NB_POINTS; i++) {
  217. if (tab_rp_registers[i] != UT_INPUT_REGISTERS_TAB[i]) {
  218. printf("FAILED (%0X != %0X)\n",
  219. tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]);
  220. goto close;
  221. }
  222. }
  223. printf("OK\n");
  224. printf("\nTEST FLOATS\n");
  225. /** FLOAT **/
  226. printf("1/2 Write float: ");
  227. modbus_write_float(UT_REAL, tab_rp_registers);
  228. if (tab_rp_registers[1] == (UT_IREAL >> 16) &&
  229. tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) {
  230. printf("OK\n");
  231. } else {
  232. printf("FAILED (%x != %x)\n",
  233. *((uint32_t *)tab_rp_registers), UT_IREAL);
  234. goto close;
  235. }
  236. printf("2/2 Read float: ");
  237. real = modbus_read_float(tab_rp_registers);
  238. if (real == UT_REAL) {
  239. printf("OK\n");
  240. } else {
  241. printf("FAILED (%f != %f)\n", real, UT_REAL);
  242. goto close;
  243. }
  244. printf("\nAt this point, error messages doesn't mean the test has failed\n");
  245. /** ILLEGAL DATA ADDRESS **/
  246. printf("\nTEST ILLEGAL DATA ADDRESS:\n");
  247. /* The mapping begins at 0 and ending at address + nb_points so
  248. * the addresses below are not valid. */
  249. rc = read_coil_status(&mb_param, SERVER_ID,
  250. UT_COIL_STATUS_ADDRESS,
  251. UT_COIL_STATUS_NB_POINTS + 1,
  252. tab_rp_status);
  253. printf("* read_coil_status: ");
  254. if (rc == -1 && errno == EMBXILADD)
  255. printf("OK\n");
  256. else {
  257. printf("FAILED\n");
  258. goto close;
  259. }
  260. rc = read_input_status(&mb_param, SERVER_ID,
  261. UT_INPUT_STATUS_ADDRESS,
  262. UT_INPUT_STATUS_NB_POINTS + 1,
  263. tab_rp_status);
  264. printf("* read_input_status: ");
  265. if (rc == -1 && errno == EMBXILADD)
  266. printf("OK\n");
  267. else {
  268. printf("FAILED\n");
  269. goto close;
  270. }
  271. rc = read_holding_registers(&mb_param, SERVER_ID,
  272. UT_HOLDING_REGISTERS_ADDRESS,
  273. UT_HOLDING_REGISTERS_NB_POINTS + 1,
  274. tab_rp_registers);
  275. printf("* read_holding_registers: ");
  276. if (rc == -1 && errno == EMBXILADD)
  277. printf("OK\n");
  278. else {
  279. printf("FAILED\n");
  280. goto close;
  281. }
  282. rc = read_input_registers(&mb_param, SERVER_ID,
  283. UT_INPUT_REGISTERS_ADDRESS,
  284. UT_INPUT_REGISTERS_NB_POINTS + 1,
  285. tab_rp_registers);
  286. printf("* read_input_registers: ");
  287. if (rc == -1 && errno == EMBXILADD)
  288. printf("OK\n");
  289. else {
  290. printf("FAILED\n");
  291. goto close;
  292. }
  293. rc = force_single_coil(&mb_param, SERVER_ID,
  294. UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
  295. ON);
  296. printf("* force_single_coil: ");
  297. if (rc == -1 && errno == EMBXILADD) {
  298. printf("OK\n");
  299. } else {
  300. printf("FAILED\n");
  301. goto close;
  302. }
  303. rc = force_multiple_coils(&mb_param, SERVER_ID,
  304. UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
  305. UT_COIL_STATUS_NB_POINTS,
  306. tab_rp_status);
  307. printf("* force_multiple_coils: ");
  308. if (rc == -1 && errno == EMBXILADD) {
  309. printf("OK\n");
  310. } else {
  311. printf("FAILED\n");
  312. goto close;
  313. }
  314. rc = preset_multiple_registers(&mb_param, SERVER_ID,
  315. UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
  316. UT_HOLDING_REGISTERS_NB_POINTS,
  317. tab_rp_registers);
  318. printf("* preset_multiple_registers: ");
  319. if (rc == -1 && errno == EMBXILADD) {
  320. printf("OK\n");
  321. } else {
  322. printf("FAILED\n");
  323. goto close;
  324. }
  325. /** TOO MANY DATA **/
  326. printf("\nTEST TOO MANY DATA ERROR:\n");
  327. rc = read_coil_status(&mb_param, SERVER_ID,
  328. UT_COIL_STATUS_ADDRESS,
  329. MAX_STATUS + 1,
  330. tab_rp_status);
  331. printf("* read_coil_status: ");
  332. if (rc == -1 && errno == EMBMDATA) {
  333. printf("OK\n");
  334. } else {
  335. printf("FAILED\n");
  336. goto close;
  337. }
  338. rc = read_input_status(&mb_param, SERVER_ID,
  339. UT_INPUT_STATUS_ADDRESS,
  340. MAX_STATUS + 1,
  341. tab_rp_status);
  342. printf("* read_input_status: ");
  343. if (rc == -1 && errno == EMBMDATA) {
  344. printf("OK\n");
  345. } else {
  346. printf("FAILED\n");
  347. goto close;
  348. }
  349. rc = read_holding_registers(&mb_param, SERVER_ID,
  350. UT_HOLDING_REGISTERS_ADDRESS,
  351. MAX_REGISTERS + 1,
  352. tab_rp_registers);
  353. printf("* read_holding_registers: ");
  354. if (rc == -1 && errno == EMBMDATA) {
  355. printf("OK\n");
  356. } else {
  357. printf("FAILED\n");
  358. goto close;
  359. }
  360. rc = read_input_registers(&mb_param, SERVER_ID,
  361. UT_INPUT_REGISTERS_ADDRESS,
  362. MAX_REGISTERS + 1,
  363. tab_rp_registers);
  364. printf("* read_input_registers: ");
  365. if (rc == -1 && errno == EMBMDATA) {
  366. printf("OK\n");
  367. } else {
  368. printf("FAILED\n");
  369. goto close;
  370. }
  371. rc = force_multiple_coils(&mb_param, SERVER_ID,
  372. UT_COIL_STATUS_ADDRESS,
  373. MAX_STATUS + 1,
  374. tab_rp_status);
  375. printf("* force_multiple_coils: ");
  376. if (rc == -1 && errno == EMBMDATA) {
  377. printf("OK\n");
  378. } else {
  379. goto close;
  380. printf("FAILED\n");
  381. }
  382. rc = preset_multiple_registers(&mb_param, SERVER_ID,
  383. UT_HOLDING_REGISTERS_ADDRESS,
  384. MAX_REGISTERS + 1,
  385. tab_rp_registers);
  386. printf("* preset_multiple_registers: ");
  387. if (rc == -1 && errno == EMBMDATA) {
  388. printf("OK\n");
  389. } else {
  390. printf("FAILED\n");
  391. goto close;
  392. }
  393. /** SLAVE REPLY **/
  394. printf("\nTEST SLAVE REPLY:\n");
  395. rc = read_holding_registers(&mb_param, 18,
  396. UT_HOLDING_REGISTERS_ADDRESS,
  397. UT_HOLDING_REGISTERS_NB_POINTS,
  398. tab_rp_registers);
  399. printf("1/3 No or response from slave %d: ", 18);
  400. if (mb_param.type_com == RTU) {
  401. /* No response in RTU mode */
  402. if (rc == -1 && errno == ETIMEDOUT) {
  403. printf("OK\n");
  404. } else {
  405. printf("FAILED\n");
  406. goto close;
  407. }
  408. } else {
  409. /* Response in TCP mode */
  410. if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
  411. printf("OK\n");
  412. } else {
  413. printf("FAILED\n");
  414. goto close;
  415. }
  416. }
  417. rc = read_holding_registers(&mb_param, MODBUS_BROADCAST_ADDRESS,
  418. UT_HOLDING_REGISTERS_ADDRESS,
  419. UT_HOLDING_REGISTERS_NB_POINTS,
  420. tab_rp_registers);
  421. printf("2/3 Reply after a broadcast query: ");
  422. if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
  423. printf("OK\n");
  424. } else {
  425. printf("FAILED\n");
  426. goto close;
  427. }
  428. /* Save original timeout */
  429. modbus_get_timeout_begin(&mb_param, &timeout_begin_old);
  430. /* Define a new and too short timeout */
  431. timeout_begin_new.tv_sec = 0;
  432. timeout_begin_new.tv_usec = 0;
  433. modbus_set_timeout_begin(&mb_param, &timeout_begin_new);
  434. rc = read_holding_registers(&mb_param, SERVER_ID,
  435. UT_HOLDING_REGISTERS_ADDRESS,
  436. UT_HOLDING_REGISTERS_NB_POINTS,
  437. tab_rp_registers);
  438. printf("3/3 Too short timeout: ");
  439. if (rc == -1 && errno == ETIMEDOUT) {
  440. printf("OK\n");
  441. } else {
  442. printf("FAILED\n");
  443. goto close;
  444. }
  445. /* Restore original timeout */
  446. modbus_set_timeout_begin(&mb_param, &timeout_begin_old);
  447. /** BAD RESPONSE **/
  448. printf("\nTEST BAD RESPONSE ERROR:\n");
  449. /* Allocate only the required space */
  450. tab_rp_registers_bad = (uint16_t *) malloc(
  451. UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t));
  452. rc = read_holding_registers(&mb_param, SERVER_ID,
  453. UT_HOLDING_REGISTERS_ADDRESS,
  454. UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL,
  455. tab_rp_registers_bad);
  456. printf("* read_holding_registers: ");
  457. if (rc == -1 && errno == EMBBADDATA) {
  458. printf("OK\n");
  459. } else {
  460. printf("FAILED\n");
  461. goto close;
  462. }
  463. free(tab_rp_registers_bad);
  464. printf("\nALL TESTS PASS WITH SUCCESS.\n");
  465. close:
  466. /* Free the memory */
  467. free(tab_rp_status);
  468. free(tab_rp_registers);
  469. /* Close the connection */
  470. modbus_close(&mb_param);
  471. return 0;
  472. }