RyanW5500Ping.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #define rlogEnable // 是否使能日志
  2. #define rlogColorEnable // 是否使能日志颜色
  3. #define rlogLevel (rlogLvlWarning) // 日志打印等级
  4. #define rlogTag "W5500Ping" // 日志tag
  5. #include "RyanW5500Store.h"
  6. #define Sn_PROTO(ch) (0x001408 + (ch << 5))
  7. #define WIZ_PING_DATA_LEN 32
  8. #define WIZ_PING_HEAD_LEN 8
  9. #define WIZ_PING_PORT 3000
  10. #define WIZ_PING_REQUEST 8
  11. #define WIZ_PING_REPLY 0
  12. #define WIZ_PING_CODE 0
  13. #define WIZ_PING_DELAY (1000)
  14. #define WIZ_PING_TIMEOUT (2000)
  15. struct wiz_ping_msg
  16. {
  17. uint8_t type; // 0 - Ping Reply, 8 - Ping Request
  18. uint8_t code; // Always 0
  19. uint16_t check_sum; // Check sum
  20. uint16_t id; // Identification
  21. uint16_t seq_num; // Sequence Number
  22. int8_t data[WIZ_PING_DATA_LEN]; // Ping Data : 1452 = IP RAW MTU - sizeof(type+code+check_sum+id+seq_num)
  23. };
  24. /**
  25. * @brief 计算字符串校验值
  26. *
  27. * @param src
  28. * @param len
  29. * @return uint16_t
  30. */
  31. static uint16_t wiz_checksum(uint8_t *src, uint32_t len)
  32. {
  33. uint16_t sum = 0,
  34. tsum = 0,
  35. i = 0,
  36. j = 0;
  37. uint32_t lsum = 0;
  38. j = len >> 1;
  39. lsum = 0;
  40. for (i = 0; i < j; i++)
  41. {
  42. tsum = src[i * 2];
  43. tsum = tsum << 8;
  44. tsum += src[i * 2 + 1];
  45. lsum += tsum;
  46. }
  47. if (len % 2)
  48. {
  49. tsum = src[i * 2];
  50. lsum += (tsum << 8);
  51. }
  52. sum = lsum;
  53. sum = ~(sum + (lsum >> 16));
  54. return (uint16_t)sum;
  55. }
  56. static int wiz_ping_request(int socket)
  57. {
  58. uint16_t tmp_checksum = 0;
  59. int idx = 0,
  60. send_len = 0;
  61. struct wiz_ping_msg ping_req = {0};
  62. // 设置请求ping消息对象
  63. ping_req.type = WIZ_PING_REQUEST;
  64. ping_req.code = WIZ_PING_CODE;
  65. ping_req.id = htons(rand() % 0xffff);
  66. ping_req.seq_num = htons(rand() % 0xffff);
  67. for (idx = 0; idx < WIZ_PING_DATA_LEN; idx++)
  68. ping_req.data[idx] = (idx) % 8;
  69. ping_req.check_sum = 0;
  70. // 计算请求ping消息校验值
  71. tmp_checksum = wiz_checksum((uint8_t *)&ping_req, sizeof(ping_req));
  72. ping_req.check_sum = htons(tmp_checksum);
  73. // 发送请求ping消息
  74. send_len = wiz_send(socket, &ping_req, sizeof(ping_req), 0);
  75. if (send_len != sizeof(ping_req))
  76. return -1;
  77. return send_len - WIZ_PING_HEAD_LEN;
  78. }
  79. static int wiz_ping_reply(int socket, struct sockaddr *from)
  80. {
  81. uint8_t recv_buf[WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN + 1] = {0};
  82. uint16_t tmp_checksum = 0;
  83. int recv_len = 0,
  84. idx = 0;
  85. struct wiz_ping_msg ping_rep = {0};
  86. platformTimer_t pingReplyTimer = {0};
  87. platformTimerCutdown(&pingReplyTimer, WIZ_PING_TIMEOUT);
  88. while (1)
  89. {
  90. if (0 == platformTimerRemain(&pingReplyTimer))
  91. return -1;
  92. struct sockaddr *sin = (struct sockaddr *)from;
  93. socklen_t addr_len = sizeof(struct sockaddr_in);
  94. recv_len = wiz_recvfrom(socket, recv_buf, WIZ_PING_HEAD_LEN + WIZ_PING_DATA_LEN, 0, sin, &addr_len);
  95. if (recv_len < 0)
  96. return -1;
  97. break;
  98. }
  99. switch (recv_buf[0])
  100. {
  101. case WIZ_PING_REPLY:
  102. ping_rep.type = recv_buf[0];
  103. ping_rep.code = recv_buf[1];
  104. ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
  105. ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
  106. ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
  107. for (idx = 0; idx < recv_len - 8; idx++)
  108. ping_rep.data[idx] = recv_buf[8 + idx];
  109. tmp_checksum = ~wiz_checksum(recv_buf, recv_len);
  110. if (tmp_checksum != 0xffff)
  111. return -2;
  112. break;
  113. case WIZ_PING_REQUEST:
  114. ping_rep.code = recv_buf[1];
  115. ping_rep.type = recv_buf[2];
  116. ping_rep.check_sum = (recv_buf[3] << 8) + recv_buf[2];
  117. ping_rep.id = (recv_buf[5] << 8) + recv_buf[4];
  118. ping_rep.seq_num = (recv_buf[7] << 8) + recv_buf[6];
  119. for (idx = 0; idx < recv_len - 8; idx++)
  120. ping_rep.data[idx] = recv_buf[8 + idx];
  121. tmp_checksum = ping_rep.check_sum;
  122. ping_rep.check_sum = 0;
  123. if (tmp_checksum != ping_rep.check_sum)
  124. return -2;
  125. break;
  126. default:
  127. rlog_w("unknown ping receive message.");
  128. return -1;
  129. }
  130. return recv_len - WIZ_PING_HEAD_LEN;
  131. }
  132. int RyanW5500Ping(struct netdev *netdev, const char *host, size_t data_len, uint32_t times, struct netdev_ping_resp *ping_resp)
  133. {
  134. int result = 0,
  135. socket = 0;
  136. struct hostent *hostent = NULL;
  137. hostent = wiz_gethostbyname(host);
  138. if (NULL == hostent || NULL == hostent->h_addr_list[0])
  139. {
  140. rlog_w("hostent is NULL.");
  141. return -RT_FALSE;
  142. }
  143. struct in_addr serviceAddr = *(struct in_addr *)hostent->h_addr_list[0];
  144. // SOCK_RAW == Sn_MR_IPRAW == 3
  145. socket = wiz_socket(AF_WIZ, SOCK_RAW, 0);
  146. if (socket < 0)
  147. {
  148. rlog_w("create ping socket(%d) failed.", socket);
  149. return -1;
  150. }
  151. // 设置套接字ICMP协议
  152. IINCHIP_WRITE(Sn_PROTO(socket), IPPROTO_ICMP);
  153. struct timeval timeout = {.tv_sec = times / RT_TICK_PER_SECOND,
  154. .tv_usec = times % RT_TICK_PER_SECOND * 1000000 / RT_TICK_PER_SECOND};
  155. // 设置接收和发送超时选项
  156. wiz_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
  157. wiz_setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
  158. struct sockaddr_in server_addr = {.sin_family = AF_WIZ,
  159. .sin_port = htons(WIZ_PING_PORT),
  160. .sin_addr = serviceAddr};
  161. if (wiz_connect(socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  162. {
  163. wiz_closesocket(socket);
  164. return -1;
  165. }
  166. result = wiz_ping_request(socket);
  167. platformTimer_t pingTimer = {0};
  168. platformTimerCutdown(&pingTimer, 0xffff);
  169. if (result > 0)
  170. {
  171. result = wiz_ping_reply(socket, (struct sockaddr *)&server_addr);
  172. ping_resp->ip_addr.addr = serviceAddr.s_addr;
  173. ping_resp->ticks = 0xffff - platformTimerRemain(&pingTimer);
  174. ping_resp->data_len = data_len;
  175. int optlen = sizeof(ping_resp->ttl);
  176. wiz_getsockopt(socket, IPPROTO_IP, IP_TTL, &ping_resp->ttl, (socklen_t *)&optlen);
  177. }
  178. wiz_closesocket(socket);
  179. return result;
  180. }