test_modbus_tcp_slave.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #include "stdio.h"
  2. #include "string.h"
  3. #include "board.h"
  4. #include <rtthread.h>
  5. #include "small_modbus.h"
  6. #include "board_virtualIO.h"
  7. //从机回调函数,当从机接收到主机的请求(数据校验和地址功能码已经解析完),在这个回调函数内填充数据,返回数据的长度即可
  8. static int test_modbus_tcp_slave_callback(small_modbus_t *smb, int function_code, int addr, int num, void *read_write_data)
  9. {
  10. int rc = 0;
  11. switch (function_code)
  12. {
  13. case MODBUS_FC_READ_HOLDING_COILS: //读取保持线圈,1bit代表一个线圈
  14. {
  15. if ((0 <= addr) && (addr < 10000)) //地址映射,地址从0开始
  16. {
  17. rc = vio_read_hold_coils(addr, num, read_write_data); // vio操作
  18. }
  19. }
  20. break;
  21. case MODBUS_FC_READ_INPUTS_COILS: //读取只读线圈,1bit代表一个线圈
  22. {
  23. if ((10000 <= addr) && (addr < 20000)) //地址映射,地址从10000开始
  24. {
  25. addr = addr - 10000;
  26. rc = vio_read_input_coils(addr, num, read_write_data); // vio操作
  27. }
  28. }
  29. break;
  30. case MODBUS_FC_READ_HOLDING_REGISTERS: //读取保持寄存器,16bit代表一个寄存器
  31. {
  32. if ((40000 <= addr) && (addr < 50000)) //地址映射,地址从40000开始
  33. {
  34. addr = addr - 40000;
  35. rc = vio_read_hold_regs(addr, num, read_write_data); // vio操作
  36. }
  37. }
  38. break;
  39. case MODBUS_FC_READ_INPUT_REGISTERS: //读取输入寄存器,16bit代表一个寄存器
  40. {
  41. if ((30000 <= addr) && (addr < 40000)) //地址映射,地址从30000开始
  42. {
  43. addr = addr - 30000;
  44. rc = vio_read_input_regs(addr, num, read_write_data); // vio操作
  45. }
  46. }
  47. break;
  48. case MODBUS_FC_WRITE_SINGLE_COIL: //写单个线圈,1bit代表一个线圈
  49. case MODBUS_FC_WRITE_MULTIPLE_COILS: //写线圈,1bit代表一个线圈
  50. {
  51. if ((0 <= addr) && (addr < 10000)) //地址映射,地址从0开始
  52. {
  53. rc = vio_write_hold_coils(addr, num, read_write_data); // vio操作
  54. }
  55. }
  56. break;
  57. case MODBUS_FC_WRITE_SINGLE_REGISTER: //写单个寄存器,16bit代表一个寄存器
  58. case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: //写寄存器,16bit代表一个寄存器
  59. {
  60. if ((40000 <= addr) && (addr < 50000)) //地址映射,地址从40000开始
  61. {
  62. addr = addr - 40000;
  63. rc = vio_write_hold_regs(addr, num, read_write_data); // vio操作
  64. }
  65. }
  66. break;
  67. }
  68. if (rc < 0)
  69. {
  70. // MODBUS_PRINTF("callback fail %d\n",rc);
  71. }
  72. return rc;
  73. }
  74. static small_modbus_t modbus_tcp_slave = {0};
  75. //#define MODBUS_PRINTF(...)
  76. //#define MODBUS_PRINTF(...) modbus_debug((&modbus_tcp_slave),__VA_ARGS__)
  77. #define MODBUS_PRINTF(...) modbus_debug_info((&modbus_tcp_slave), __VA_ARGS__)
  78. //是否使用多路socket,多路socket需要posix select支持
  79. #define MODBUS_TCP_SLAVE_MULTIPLEWAY_SOCKET
  80. #ifndef MODBUS_TCP_SLAVE_MULTIPLEWAY_SOCKET
  81. static void test_modbus_tcp_slave_thread(void *param)
  82. {
  83. int rc = 0;
  84. int count = 0;
  85. small_modbus_t *smb_slave = param;
  86. modbus_init(smb_slave, MODBUS_CORE_TCP,
  87. modbus_port_rtsocket_create(MODBUS_DEVICE_SLAVE, "0.0.0.0", "502")); // init modbus TCP mode
  88. modbus_set_slave(smb_slave, 1); // set slave addr
  89. rt_kprintf("modbus slave addr:%d\n", 1);
  90. int server_socket = -1;
  91. int client_socket = -1;
  92. while (1)
  93. {
  94. server_socket = modbus_tcp_listen(smb_slave, 1); //
  95. MODBUS_PRINTF("modbus_tcp_listen:%d\n", server_socket);
  96. while (1)
  97. {
  98. client_socket = modbus_tcp_accept(smb_slave, server_socket);
  99. MODBUS_PRINTF("modbus_tcp_accept:%d\n", client_socket);
  100. modbus_tcp_set_socket(smb_slave, client_socket); // set client_socket
  101. while (modbus_tcp_status(smb_slave) == MODBUS_OK)
  102. {
  103. rc = modbus_slave_wait_handle(smb_slave, test_modbus_tcp_slave_callback, MODBUS_WAIT_FOREVER);
  104. if (rc > 0)
  105. {
  106. count++;
  107. }
  108. else
  109. {
  110. if (rc == MODBUS_ERROR_READ)
  111. {
  112. break; // disconnect
  113. }
  114. modbus_error_recovery(smb_slave);
  115. }
  116. }
  117. MODBUS_PRINTF("modbus_disconnect client :%d\n", client_socket);
  118. modbus_tcp_set_socket(smb_slave, client_socket); // set client_socket
  119. modbus_tcp_disconnect(smb_slave); // disconnect client_socket
  120. client_socket = -1;
  121. }
  122. MODBUS_PRINTF("modbus_disconnect server :%d\n", server_socket);
  123. modbus_tcp_set_socket(smb_slave, server_socket); // set server_socket
  124. modbus_tcp_disconnect(smb_slave); // disconnect server_socket
  125. server_socket = -1;
  126. }
  127. }
  128. #else
  129. #ifdef RT_USING_POSIX
  130. #include <stdio.h>
  131. #include <stdlib.h>
  132. #include <string.h>
  133. #include <ctype.h>
  134. #include <netdb.h>
  135. #include <sys/socket.h>
  136. #include <sys/time.h>
  137. #include <sys/errno.h>
  138. #include <sys/ioctl.h>
  139. //最大连接数量
  140. #define MAX_CLIENT_NUM 3
  141. static void test_modbus_tcp_slave_thread(void *param)
  142. {
  143. int rc = 0;
  144. int count = 0;
  145. small_modbus_t *smb_slave = param;
  146. modbus_init(smb_slave, MODBUS_CORE_TCP,
  147. modbus_port_rtsocket_create(MODBUS_DEVICE_SLAVE, "0.0.0.0", "502")); // init modbus TCP mode
  148. modbus_set_slave(smb_slave, 1); // set slave addr
  149. rt_kprintf("modbus slave addr:%d\n", 1);
  150. int max_fd = -1;
  151. int server_socket = -1;
  152. int client_socket[MAX_CLIENT_NUM] = {-1};
  153. fd_set readset;
  154. struct timeval select_timeout;
  155. select_timeout.tv_sec = 1;
  156. select_timeout.tv_usec = 0;
  157. for (int i = 0; i < MAX_CLIENT_NUM; i++)
  158. {
  159. client_socket[i] = -1;
  160. }
  161. while (1)
  162. {
  163. server_socket = modbus_tcp_listen(smb_slave, MAX_CLIENT_NUM); //
  164. MODBUS_PRINTF("modbus_tcp_listen:%d\n", server_socket);
  165. while (1)
  166. {
  167. max_fd = -1;
  168. FD_ZERO(&readset);
  169. FD_SET(server_socket, &readset);
  170. if (max_fd < server_socket)
  171. {
  172. max_fd = server_socket;
  173. }
  174. for (int i = 0; i < MAX_CLIENT_NUM; i++)
  175. {
  176. if (client_socket[i] >= 0)
  177. {
  178. FD_SET(client_socket[i], &readset);
  179. if (max_fd < client_socket[i])
  180. max_fd = client_socket[i];
  181. }
  182. }
  183. rc = select(max_fd + 1, &readset, RT_NULL, RT_NULL, &select_timeout);
  184. if (rc < 0)
  185. {
  186. MODBUS_PRINTF("modbus_tcp_select:%d\n", rc);
  187. // goto _mbtcp_restart;
  188. break;
  189. }
  190. else if (rc > 0)
  191. {
  192. if (FD_ISSET(server_socket, &readset))
  193. {
  194. int client_sock_fd = modbus_tcp_accept(smb_slave, server_socket);
  195. MODBUS_PRINTF("modbus_tcp_accept:%d\n", client_sock_fd);
  196. if (client_sock_fd >= 0)
  197. {
  198. int index = -1;
  199. for (int i = 0; i < MAX_CLIENT_NUM; i++)
  200. {
  201. if (client_socket[i] < 0)
  202. {
  203. index = i;
  204. break;
  205. }
  206. }
  207. if (index >= 0)
  208. {
  209. client_socket[index] = client_sock_fd;
  210. }
  211. else
  212. {
  213. MODBUS_PRINTF("modbus client max :%d close:%d\n", MAX_CLIENT_NUM, client_sock_fd);
  214. modbus_tcp_set_socket(smb_slave, client_sock_fd); // set server_socket
  215. modbus_tcp_disconnect(smb_slave); // disconnect server_socket
  216. }
  217. }
  218. }
  219. for (int i = 0; i < MAX_CLIENT_NUM; i++)
  220. {
  221. if (client_socket[i] >= 0)
  222. {
  223. if (FD_ISSET(client_socket[i], &readset))
  224. {
  225. modbus_tcp_set_socket(smb_slave, client_socket[i]);
  226. rc = modbus_slave_wait_handle(smb_slave, test_modbus_tcp_slave_callback, MODBUS_WAIT_FOREVER);
  227. if (rc > 0)
  228. {
  229. count++;
  230. }
  231. else
  232. {
  233. if (rc == MODBUS_ERROR_READ)
  234. {
  235. MODBUS_PRINTF("modbus_disconnect client :%d\n", client_socket[i]);
  236. modbus_tcp_set_socket(smb_slave, client_socket[i]); // set client_socket
  237. modbus_tcp_disconnect(smb_slave); // disconnect client_socket
  238. client_socket[i] = -1;
  239. }
  240. modbus_error_recovery(smb_slave);
  241. }
  242. }
  243. }
  244. } // for
  245. }
  246. } // while
  247. for (int i = 0; i < MAX_CLIENT_NUM; i++)
  248. {
  249. if (client_socket[i] >= 0)
  250. {
  251. MODBUS_PRINTF("modbus_disconnect client :%d\n", client_socket[i]);
  252. modbus_tcp_set_socket(smb_slave, client_socket[i]); // set server_socket
  253. modbus_tcp_disconnect(smb_slave); // disconnect server_socket
  254. client_socket[i] = -1;
  255. }
  256. }
  257. MODBUS_PRINTF("modbus_disconnect server :%d\n", server_socket);
  258. modbus_tcp_set_socket(smb_slave, server_socket); // set server_socket
  259. modbus_tcp_disconnect(smb_slave); // disconnect server_socket
  260. server_socket = -1;
  261. }
  262. }
  263. #endif
  264. #endif
  265. int test_modbus_tcp_slave(void)
  266. {
  267. rt_thread_t tid;
  268. tid = rt_thread_create("slave", test_modbus_tcp_slave_thread, &modbus_tcp_slave, 2048, 20, 10);
  269. if (tid != RT_NULL)
  270. rt_thread_startup(tid);
  271. return 0;
  272. }
  273. // msh命令行启动
  274. #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
  275. #include <finsh.h>
  276. MSH_CMD_EXPORT(test_modbus_tcp_slave, test modbus_tcp_slave);
  277. #endif