RyanW5500.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #define rlogEnable // 是否使能日志
  2. #define rlogColorEnable // 是否使能日志颜色
  3. #define rlogLevel (rlogLvlWarning) // 日志打印等级
  4. #define rlogTag "W5500" // 日志tag
  5. #include "RyanW5500Store.h"
  6. /**
  7. * @brief W5500中断回调函数
  8. *
  9. * @param argument
  10. */
  11. void RyanW5500IRQCallback(void *argument)
  12. {
  13. rt_event_send(RyanW5500Entry.W5500EventHandle, RyanW5500IRQBit);
  14. }
  15. void RyanW5500NetDevInfoUpdate(struct netdev *netdev)
  16. {
  17. uint8_t linkState = 0;
  18. wiz_NetInfo netinfo = {0};
  19. ctlnetwork(CN_GET_NETINFO, (void *)&netinfo); // 获取网络信息
  20. netdev_low_level_set_ipaddr(netdev, (const ip_addr_t *)&netinfo.ip); // 设置网络接口设备 IP 地址。
  21. netdev_low_level_set_gw(netdev, (const ip_addr_t *)&netinfo.gw); // 设置网络接口设备网关地址
  22. netdev_low_level_set_netmask(netdev, (const ip_addr_t *)&netinfo.sn); // 设置网络接口设备网络掩码地址。
  23. netdev_low_level_set_dns_server(netdev, 0, (const ip_addr_t *)&netinfo.dns); // 设置网络接口设备DNS服务器地址
  24. memcpy(netdev->hwaddr, (const void *)&netinfo.mac, netdev->hwaddr_len); // 设置mac地址
  25. // netdev_low_level_set_dhcp_status(netdev, (NETINFO_DHCP == gWIZNETINFO.dhcp) ? RT_TRUE : RT_FALSE);
  26. ctlwizchip(CW_GET_PHYLINK, &linkState);
  27. netdev_low_level_set_link_status(netdev, (PHY_LINK_ON == linkState) ? RT_TRUE : RT_FALSE);
  28. }
  29. /**
  30. * @brief 网络初始化
  31. *
  32. * @param netdev
  33. * @return int
  34. */
  35. int RyanW5500NetWorkInit(struct netdev *netdev)
  36. {
  37. uint8_t MaintainFlag = 0; // dhcp续租标志
  38. uint8_t linkState = 0;
  39. if (0 != RyanW5500Entry.netDevFlag)
  40. {
  41. // nedev用户手动设置了ip / gw / mask / dnsService
  42. if (RyanW5500Entry.netDevFlag & netDevSetDevInfo)
  43. {
  44. RyanW5500Entry.netDevFlag &= ~netDevSetDevInfo;
  45. for (uint8_t socket = 0; socket < RyanW5500MaxSocketNum; socket++)
  46. wiz_closesocket(socket);
  47. }
  48. // nedev用户使能了dhcp
  49. if (RyanW5500Entry.netDevFlag & netDevDHCPEnable)
  50. {
  51. RyanW5500Entry.netDevFlag &= ~netDevDHCPEnable;
  52. MaintainFlag = 0;
  53. gWIZNETINFO.dhcp = NETINFO_DHCP;
  54. // 模式不一样,关闭所有socket
  55. if (gWIZNETINFO.dhcp != NETINFO_DHCP)
  56. {
  57. for (uint8_t socket = 0; socket < RyanW5500MaxSocketNum; socket++)
  58. wiz_closesocket(socket);
  59. }
  60. }
  61. // nedev用户失能了dhcp
  62. if (RyanW5500Entry.netDevFlag & netDevDHCPDisable)
  63. {
  64. RyanW5500Entry.netDevFlag &= ~netDevDHCPDisable;
  65. MaintainFlag = 0;
  66. gWIZNETINFO.dhcp = NETINFO_STATIC;
  67. // ip可能不一样,直接关闭所有socket
  68. for (uint8_t socket = 0; socket < RyanW5500MaxSocketNum; socket++)
  69. wiz_closesocket(socket);
  70. }
  71. }
  72. else
  73. {
  74. // dhcp租期判断
  75. if (NETINFO_DHCP == gWIZNETINFO.dhcp)
  76. {
  77. if (getDHCPRemainLeaseTime() < 10 * 1000) // 如果租期只剩余10秒,重新获取ip
  78. {
  79. rlog_i("dhcp租期接近超时, 重新获取ip");
  80. MaintainFlag = 0;
  81. goto next;
  82. }
  83. if (getDHCPRemainLeaseTime() < (getDHCPLeaseTime() / 2)) // 超过一半就开始续租
  84. {
  85. rlog_i("dhcp续租");
  86. MaintainFlag = 1;
  87. goto next;
  88. }
  89. }
  90. ctlwizchip(CW_GET_PHYLINK, &linkState);
  91. if (PHY_LINK_ON == linkState && netdev_is_link_up(netdev)) // netdev状态和设备状态匹配,不进行下面操作
  92. return 0;
  93. if (PHY_LINK_ON == linkState) // w5500处于link状态,更新信息后就退出
  94. {
  95. rlog_d("link State: %d\r\n", linkState);
  96. RyanW5500NetDevInfoUpdate(netdev);
  97. return 0;
  98. }
  99. }
  100. next:
  101. if (NETINFO_DHCP == gWIZNETINFO.dhcp)
  102. {
  103. if (0 == MaintainFlag)
  104. {
  105. memset(gWIZNETINFO.ip, 0, 4);
  106. memset(gWIZNETINFO.sn, 0, 4);
  107. memset(gWIZNETINFO.gw, 0, 4);
  108. memset(gWIZNETINFO.dns, 0, 4);
  109. }
  110. uint32_t dhcpState = DHCP_run(MaintainFlag); // MaintainFlag续租
  111. if (dhcpState != 0)
  112. {
  113. ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO); // 从网络信息结构设置网络信息
  114. RyanW5500NetDevInfoUpdate(netdev);
  115. return -1;
  116. }
  117. }
  118. ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO); // 从网络信息结构设置网络信息
  119. for (uint8_t count = 0; count < 100; count++) // 测试link是否正常
  120. {
  121. ctlwizchip(CW_GET_PHYLINK, &linkState);
  122. if (PHY_LINK_ON == linkState)
  123. break;
  124. delay(10);
  125. }
  126. RyanW5500NetDevInfoUpdate(netdev);
  127. uint16_t ret = 0xff; // 启用所有socket通道中断
  128. ret = (ret << 8) + 0x00; // 禁用所有通用中断,不使用
  129. ctlwizchip(CW_SET_INTRMASK, (void *)&ret);
  130. for (uint8_t i = 0; i < RyanW5500MaxSocketNum; i++) // 每次联网成功都进行socket中断掩码配置
  131. setSn_IMR(i, RyanW5500SnIMR);
  132. return 0;
  133. }
  134. static void wizIntDataTask(void *parameter)
  135. {
  136. uint8_t ir = 0,
  137. sir = 0,
  138. sn_ir = 0;
  139. uint16_t intr = 0;
  140. struct netdev *netdev = (struct netdev *)parameter;
  141. platformTimer_t netWorkTimer = {0};
  142. // 检查w5500连接是否正常
  143. while (1)
  144. {
  145. RyanW5500Reset(); // 重启w5500
  146. delay(100);
  147. // 超时中断触发为retry_cnt * time_100us * 100us
  148. struct wiz_NetTimeout_t net_timeout = {
  149. .retry_cnt = 5, // 重试次数
  150. .time_100us = 2000}; // 200ms认为失败
  151. ctlnetwork(CN_SET_TIMEOUT, (void *)&net_timeout);
  152. memset(&net_timeout, 0, sizeof(struct wiz_NetTimeout_t));
  153. ctlnetwork(CN_GET_TIMEOUT, (void *)&net_timeout);
  154. if (5 == net_timeout.retry_cnt && 2000 == net_timeout.time_100us)
  155. break;
  156. rlog_e("没有监测到w5500");
  157. delay(2000);
  158. }
  159. netdev_low_level_set_status(netdev, RT_TRUE); // 设置网络接口设备状态
  160. platformTimerCutdown(&netWorkTimer, 0);
  161. while (1)
  162. {
  163. if (0 == platformTimerRemain(&netWorkTimer))
  164. {
  165. if (-1 == RyanW5500NetWorkInit(netdev))
  166. {
  167. rlog_d("网络没有连接");
  168. delay(1000);
  169. continue;
  170. }
  171. platformTimerCutdown(&netWorkTimer, 1000);
  172. }
  173. rt_event_recv(RyanW5500Entry.W5500EventHandle, RyanW5500IRQBit,
  174. RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  175. 1000, NULL);
  176. while (1)
  177. {
  178. intr = 0;
  179. ctlwizchip(CW_GET_INTERRUPT, (void *)&intr); // 获取中断状态
  180. ir = (uint8_t)intr;
  181. sir = (uint8_t)(intr >> 8);
  182. setIR(ir); // 没有使用IR中断,保险起见进行清空
  183. if (0 == sir) // 所有socket都没有中断就退出循环
  184. break;
  185. for (uint8_t socket = 0; socket < RyanW5500MaxSocketNum; socket++)
  186. {
  187. if (!(sir & (1 << socket))) // 判断是否当前socket通道中断
  188. continue;
  189. // setSIR(socket); // 清除当前socket中断 setSn_IR时w5500内部会自动清除
  190. // Sn_IR_SENDOK和Sn_IR_TIMEOUT wiz官方库有使用,这里不使用
  191. sn_ir = 0;
  192. sn_ir = getSn_IR(socket); // 获取中断类型消息
  193. setSn_IR(socket, RyanW5500SnIMR); // 清除中断类型消息
  194. if (sn_ir & Sn_IR_RECV) // 接收到了对方数据
  195. {
  196. RyanW5500RecvDataCallback(socket);
  197. rlog_d("接收到数据");
  198. }
  199. if (sn_ir & Sn_IR_DISCON) // 当接收到对方的 FIN or FIN/ACK 包时
  200. {
  201. RyanW5500CloseCallback(socket);
  202. rlog_d("断开连接");
  203. }
  204. if (sn_ir & Sn_IR_CON) // 成功与对方建立连接
  205. {
  206. rlog_d("连接成功");
  207. RyanW5500Socket *clientSock = RyanW5500GetSock(socket);
  208. if (-1 == clientSock->serviceSocket)
  209. continue;
  210. RyanW5500Socket *serviceSock = RyanW5500GetSock(clientSock->serviceSocket);
  211. if (RyanW5500SocketListen != serviceSock->state || clientSock->port != serviceSock->port)
  212. continue;
  213. RyanListenServiceAddClient(serviceSock, clientSock);
  214. }
  215. }
  216. }
  217. }
  218. }
  219. /**
  220. * @brief 初始化W5500 不应重复调用,内部没有判断
  221. *
  222. * @param netInfo
  223. * @return int
  224. */
  225. int RyanW5500Init(wiz_NetInfo *netInfo)
  226. {
  227. struct netdev *netdev = NULL;
  228. memcpy(&gWIZNETINFO, netInfo, sizeof(wiz_NetInfo));
  229. memset(&RyanW5500Entry, 0, sizeof(RyanW5500Entry));
  230. RyanW5500SpiInit(); // w5500 spi初始化
  231. reg_wizchip_cris_cbfunc(RyanW5500CriticalEnter, RyanW5500CriticalExit); // 注册临界区函数
  232. reg_wizchip_cs_cbfunc(RyanW5500CsSelect, RyanW5500CsDeselect); // 注册片选函数
  233. reg_wizchip_spi_cbfunc(RyanW5500ReadByte, RyanW5500WriteByte); // 注册读写函数
  234. reg_wizchip_spiburst_cbfunc(RyanW5500ReadBurst, RyanW5500WriteBurst); // 注册多个字节读写
  235. RyanW5500Entry.socketMutexHandle = rt_mutex_create("RyanW5500SocketMutex", RT_IPC_FLAG_FIFO);
  236. RyanW5500Entry.dnsMutexHandle = rt_mutex_create("RyanW5500DnsMutex", RT_IPC_FLAG_FIFO);
  237. RyanW5500Entry.W5500EventHandle = rt_event_create("RyanW5500Event", RT_IPC_FLAG_PRIO);
  238. RyanW5500AttachIRQ(RyanW5500IRQCallback); // 绑定w5500中断回调函数
  239. netdev = RyanW5500NetdevRegister("RyanW5500"); // W5500
  240. netdev_low_level_set_status(netdev, RT_FALSE); // 设置网络接口设备状态
  241. netdev_low_level_set_dhcp_status(netdev, (NETINFO_DHCP == gWIZNETINFO.dhcp) ? RT_TRUE : RT_FALSE); // 同步dhcp状态
  242. RyanW5500Entry.w5500TaskHandle = rt_thread_create("RyanW5500", // 线程name
  243. wizIntDataTask, // 线程入口函数
  244. (void *)netdev, // 线程入口函数参数
  245. 1536, // 线程栈大小
  246. 8, // 线程优先级
  247. 5); // 线程时间片
  248. if (RyanW5500Entry.w5500TaskHandle != NULL)
  249. rt_thread_startup(RyanW5500Entry.w5500TaskHandle);
  250. return 0;
  251. }