RyanW5500Test.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <board.h>
  6. #include <rtthread.h>
  7. #include <rtdevice.h>
  8. #include <rtdbg.h>
  9. #include "ulog.h"
  10. #include "RyanW5500.h"
  11. #include "sal_socket.h"
  12. #include "sal_netdb.h"
  13. #include "netdev_ipaddr.h"
  14. #include "netdev.h"
  15. static const char *TAG = "RyanW5500Test";
  16. // 任务句柄
  17. struct netdev *ryanNetDev = NULL;
  18. void neDevStatusChangeCallback(struct netdev *netdev, enum netdev_cb_type type)
  19. {
  20. ulog_i(TAG, "w5500 nedev state: %d", type);
  21. }
  22. int w5500Start(void)
  23. {
  24. wiz_NetInfo netInfo = {0};
  25. // mac地址有48位,6字节
  26. // mac地址前3字节表示网卡制造商,由IEEE分配,称为OUI(组织唯一标识符), 后3字节,为网卡制造商分配的唯一编号
  27. // mac地址首位偶数单播,首位奇数为多播地址,多播作为设备地址是无效(第一个字节的最后一位0 单播, 1 多播)
  28. // 广播mac地址:FF-FF-FF-FF-FF-FF
  29. // 第一个字节一般为00,这里就不使用00 狗头
  30. uint8_t myMac[6] = {0x14, 0xE0, 0x81, 0x2f, 0x0c, 0x37};
  31. // stm32可以使用唯一96Bit芯片序列号
  32. // myMac[3] = *(uint8_t *)(UID_BASE + 0);
  33. // myMac[4] = *(uint8_t *)(UID_BASE + 4);
  34. // myMac[5] = *(uint8_t *)(UID_BASE + 8);
  35. memcpy(netInfo.mac, myMac, sizeof(netInfo.mac));
  36. // 用户也使用随机数来,需要支持rand函数才行
  37. // ?但操作系统启动时间几乎时恒定的,ms时钟,可能造成随机数种子相同,随机数也一样的可能性
  38. // srand(rt_tick_get()); // 设立随机数种子
  39. // myMac[3] = rand() % 254 + 0;// 生成0~254的随机数
  40. // srand(rt_tick_get()); // 设立随机数种子
  41. // myMac[4] = rand() % 254 + 0;// 生成0~254的随机数
  42. // srand(rt_tick_get()); // 设立随机数种子
  43. // myMac[5] = rand() % 254 + 0;// 生成0~254的随机数
  44. uint8_t ipStrArr[4] = {0};
  45. inet_pton(AF_INET, "192.168.3.69", &ipStrArr);
  46. memcpy(netInfo.ip, ipStrArr, 4);
  47. inet_pton(AF_INET, "255.255.252.0", &ipStrArr);
  48. memcpy(netInfo.sn, ipStrArr, 4);
  49. inet_pton(AF_INET, "192.168.1.1", &ipStrArr);
  50. memcpy(netInfo.gw, ipStrArr, 4);
  51. inet_pton(AF_INET, "114.114.114.114", &ipStrArr);
  52. memcpy(netInfo.dns, ipStrArr, 4);
  53. netInfo.dhcp = NETINFO_DHCP; // 使能dhcp
  54. RyanW5500Init(&netInfo);
  55. ryanNetDev = netdev_get_by_name("RyanW5500"); // netdev
  56. if (ryanNetDev == NULL)
  57. {
  58. ulog_e(TAG, "No device found");
  59. return;
  60. }
  61. netdev_set_default(ryanNetDev);
  62. netdev_set_status_callback(ryanNetDev, neDevStatusChangeCallback);
  63. // while (!netdev_is_link_up(ryanNetDev))
  64. // {
  65. // delay(200);
  66. // }
  67. return RT_EOK;
  68. }
  69. // TCP并发ECHO服务器
  70. void *deal_client_fun(void *arg)
  71. {
  72. int fd = *(int *)arg; // 通过arg获得已连接套接字
  73. char buf[256] = {0};
  74. // struct timeval tv = {
  75. // .tv_sec = 2,
  76. // .tv_usec = 0};
  77. // setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); // 设置接收超时
  78. while (1)
  79. {
  80. // 获取客户端请求
  81. int len = recv(fd, buf, sizeof(buf), 0);
  82. if (len <= 0)
  83. {
  84. // 下列3种表示没问题,但需要推出发送
  85. if ((errno == EAGAIN || // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
  86. errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
  87. errno == EINTR)) // 操作被信号中断
  88. {
  89. ulog_i(TAG, "接收超时...........");
  90. continue;
  91. }
  92. ulog_w(TAG, "遇到错误, 退出 socket: %d, len: %d", fd, len);
  93. close(fd);
  94. return;
  95. }
  96. // rt_kprintf("客户端的请求为:%s recv:%d\n", buf, len);
  97. send(fd, buf, len, 0); // 回应客户端
  98. }
  99. }
  100. void tcpEchoTask(void *argument)
  101. {
  102. int32_t port = (int32_t)argument;
  103. int32_t ret;
  104. uint16_t size = 0, sentsize = 0;
  105. while (1)
  106. {
  107. // 创建一个tcp监听套接字
  108. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  109. // 使用bind函数 给监听套接字 绑定固定的ip以及端口
  110. struct sockaddr_in my_addr = {
  111. .sin_family = AF_INET, // 协议族
  112. .sin_port = htons(port), // 端口号
  113. .sin_addr.s_addr = htonl(INADDR_ANY)}; // 设置地址
  114. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
  115. // 使用listen创建连接队列 主动变被动
  116. listen(sockfd, 4);
  117. while (1)
  118. {
  119. // 使用accpet函数从连接队列中 提取已完成的连接 得到已连接套接字
  120. struct sockaddr_in cli_addr;
  121. socklen_t cli_len = sizeof(cli_addr);
  122. int new_fd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);
  123. if (new_fd < 0)
  124. break;
  125. // new_fd代表的是客户端的连接 cli_addr存储是客户端的信息
  126. rt_kprintf("客户端:%s:%hu连接了服务器\n", inet_ntoa(cli_addr.sin_addr.s_addr), ntohs(cli_addr.sin_port));
  127. rt_thread_t idex = rt_thread_create("socket123123123", deal_client_fun, (void *)&new_fd, 2048, 12, 5);
  128. if (idex != NULL)
  129. rt_thread_startup(idex);
  130. }
  131. // 关闭监听套接字
  132. close(sockfd);
  133. }
  134. }
  135. void udpEchoServiceTask(void *argument)
  136. {
  137. int32_t port = (int32_t)argument;
  138. // 创建通讯的udp套接字(没有port, ip)
  139. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  140. printf("UDP套接字sockfd=%d\r\n", sockfd);
  141. // 定义一个IPv4地址结构, 存放客户端的地址信息(本地主机)
  142. struct sockaddr_in myAddr = {
  143. .sin_family = AF_INET,
  144. .sin_port = htons(port),
  145. .sin_addr.s_addr = htonl(INADDR_ANY)};
  146. // 给udp套接字 bind绑定一个固定的地址信息
  147. bind(sockfd, (struct sockaddr *)&myAddr, sizeof(myAddr));
  148. // 定义一个IPv4地址结构 存放发送者的数据
  149. struct sockaddr_in from_addr;
  150. socklen_t fromLen = sizeof(from_addr);
  151. char buf[256] = {0};
  152. while (1)
  153. {
  154. int len = recvfrom(sockfd, buf, sizeof(buf), 0,
  155. (struct sockaddr *)&from_addr, &fromLen);
  156. if (len <= 0)
  157. {
  158. // 下列3种表示没问题,但需要推出发送
  159. if ((errno == EAGAIN || // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
  160. errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
  161. errno == EINTR)) // 操作被信号中断
  162. {
  163. ulog_i(TAG, "接收超时...........");
  164. continue;
  165. }
  166. ulog_w(TAG, "遇到错误, 退出 socket: %d, len: %d", sockfd, len);
  167. break;
  168. }
  169. // printf("消息来自: %s : %hu\r\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
  170. // printf("len: %d msg:%s\r\n", len, buf);
  171. sendto(sockfd, buf, len, 0, (struct sockaddr *)&from_addr, sizeof(from_addr));
  172. memset(buf, 0, len);
  173. }
  174. // 关闭套接字
  175. close(sockfd);
  176. }
  177. void multicastEchoServiceTask(void *argument)
  178. {
  179. int32_t port = (int32_t)argument;
  180. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  181. // 让sockfd有一个固定的IP端口
  182. struct sockaddr_in my_addr = {
  183. .sin_family = AF_INET,
  184. .sin_port = htons(port),
  185. .sin_addr.s_addr = htonl(INADDR_ANY)};
  186. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
  187. // 224.0.0.1 ~ 239.255.255.254 任意一个IP地址 都代表一个多播组
  188. // 加入到多播组 224.0.0.252中
  189. struct ip_mreq mreq = {
  190. .imr_multiaddr.s_addr = inet_addr("224.1.1.1"),
  191. .imr_interface.s_addr = htonl(INADDR_ANY)};
  192. setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
  193. struct sockaddr_in from_addr = {0};
  194. socklen_t fromLen = sizeof(from_addr);
  195. char buf[256] = {0};
  196. while (1)
  197. {
  198. int len = recvfrom(sockfd, buf, sizeof(buf), 0,
  199. (struct sockaddr *)&from_addr, &fromLen);
  200. if (len <= 0)
  201. {
  202. // 下列3种表示没问题,但需要推出发送
  203. if ((errno == EAGAIN || // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
  204. errno == EWOULDBLOCK || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
  205. errno == EINTR)) // 操作被信号中断
  206. {
  207. ulog_i(TAG, "multicast, 接收超时...........");
  208. continue;
  209. }
  210. ulog_w(TAG, "multicast, 遇到错误, 退出 socket: %d, len: %d", sockfd, len);
  211. break;
  212. }
  213. printf("multicast, 消息来自: %s : %hu\r\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));
  214. printf("multicast, len: %d msg: %s\r\n", len, buf);
  215. // 默认只会发送给多播组,这是w5500硬件限制的,如果想单播回复组播收到的信息,需要重新创建socket
  216. // sendto(sockfd, "hellow", strlen("hellow"), 0, (struct sockaddr *)&from_addr, sizeof(from_addr));
  217. int sockfd2 = socket(AF_INET, SOCK_DGRAM, 0);
  218. struct sockaddr_in ser_addr = {.sin_family = AF_INET,
  219. .sin_port = from_addr.sin_port,
  220. .sin_addr.s_addr = from_addr.sin_addr.s_addr};
  221. sendto(sockfd2, buf, len, 0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
  222. close(sockfd2); // 关闭套接字
  223. memset(buf, 0, len);
  224. }
  225. close(sockfd);
  226. }
  227. static int w5500Static(int argc, char *argv[])
  228. {
  229. // 测试netDev
  230. netdev_dhcp_enabled(ryanNetDev, RT_FALSE);
  231. // 设置网卡 IP 地址
  232. uint32_t addr = inet_addr("192.168.3.69");
  233. netdev_set_ipaddr(ryanNetDev, (const ip_addr_t *)&addr);
  234. addr = inet_addr("192.168.1.1");
  235. // 设置网卡网关地址
  236. netdev_set_gw(ryanNetDev, (const ip_addr_t *)&addr);
  237. addr = inet_addr("255.255.252.0");
  238. // 设置网卡子网掩码地址
  239. netdev_set_netmask(ryanNetDev, (const ip_addr_t *)&addr);
  240. addr = inet_addr("114.114.114.114");
  241. // 设置网卡子网掩码地址
  242. netdev_set_dns_server(ryanNetDev, 0, (const ip_addr_t *)&addr);
  243. ulog_i(TAG, "w5500Static");
  244. return 0;
  245. }
  246. static int w5500Dhcp(int argc, char *argv[])
  247. {
  248. netdev_dhcp_enabled(ryanNetDev, RT_TRUE);
  249. ulog_i(TAG, "w5500Dhcp");
  250. return 0;
  251. }
  252. static int w5500UdpClient(int argc, char *argv[])
  253. {
  254. if (argc < 4)
  255. {
  256. ulog_i(TAG, "请输入udp服务器的IP, port ");
  257. return 0;
  258. }
  259. char *serviceIP = argv[2];
  260. int32_t servicePort = atoi(argv[3]);
  261. // 创建通讯的udp套接字(没有port, ip)
  262. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  263. printf("UDP套接字sockfd=%d\r\n", sockfd);
  264. // 定义一个IPv4地址结构, 存放服务器的地址信息(目标主机)
  265. struct sockaddr_in ser_addr = {
  266. .sin_family = AF_INET,
  267. .sin_port = htons(servicePort), // 将主机字节序转换成网络字节序
  268. .sin_addr.s_addr = inet_addr(serviceIP) // 将服务器ip地址转换为32位整型数据
  269. };
  270. char buf[] = "This is a udp client test message";
  271. sendto(sockfd, buf, strlen(buf),
  272. 0, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
  273. // 关闭套接字
  274. close(sockfd);
  275. return 0;
  276. }
  277. static int w5500UdpService(int argc, char *argv[])
  278. {
  279. if (argc < 3)
  280. {
  281. ulog_i(TAG, "请输入udpService的port ");
  282. return 0;
  283. }
  284. int32_t port = atoi(argv[2]);
  285. static rt_thread_t hid = NULL;
  286. if (NULL != hid)
  287. {
  288. ulog_w(TAG, "udp服务器已启动,请勿重复创建");
  289. return -1;
  290. }
  291. // 创建WIZnet SPI RX线程
  292. hid = rt_thread_create("udpService", // 线程name
  293. udpEchoServiceTask, // 线程入口函数
  294. (void *)port, // 线程入口函数参数
  295. 2048, // 线程栈大小
  296. 18, // 线程优先级
  297. 5); // 线程时间片
  298. if (NULL != hid)
  299. rt_thread_startup(hid);
  300. else
  301. ulog_w(TAG, "创建udp echo线程失败");
  302. return 0;
  303. }
  304. static int w5500TcpClient(int argc, char *argv[])
  305. {
  306. if (argc < 4)
  307. {
  308. ulog_i(TAG, "请输入tcp服务器的IP, port ");
  309. return 0;
  310. }
  311. char *serviceIP = argv[2];
  312. int32_t servicePort = atoi(argv[3]);
  313. int32_t result = 0;
  314. // 创建一个TCP套接字 SOCK_STREAM
  315. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  316. printf("sockfd = %d\n", sockfd);
  317. // bind是可选的,这里使用,纯粹为了演示
  318. // !此库w5500实现, 不推荐使用bind,使用bind会释放之前申请socket,重新申请。这是因为w5500特性造成
  319. struct sockaddr_in my_addr = {
  320. .sin_family = AF_INET,
  321. .sin_port = htons(45876),
  322. .sin_addr.s_addr = htonl(INADDR_ANY)};
  323. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
  324. // connect链接服务器
  325. struct sockaddr_in ser_addr = {
  326. .sin_family = AF_INET,
  327. .sin_port = htons(servicePort), // 服务器的端口
  328. .sin_addr.s_addr = inet_addr(serviceIP) // 服务器的IP
  329. };
  330. // 如果sockfd没有绑定固定的IP以及端口
  331. // 正常情况,在调用connect时候 系统给sockfd分配自身IP以及随机端口
  332. // 堆区此库W5500实现,是在socket时进行绑定的
  333. result = connect(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
  334. if (0 != result)
  335. {
  336. ulog_i(TAG, "connect错误, 目标ip: %s, 目标端口: %d, err code: %s", serviceIP, servicePort, strerror(errno));
  337. return -1;
  338. }
  339. char buf[] = "This is a tdp client test message";
  340. result = send(sockfd, buf, strlen(buf), 0);
  341. if (result < 0)
  342. {
  343. ulog_i(TAG, "send错误, 目标ip: %s, 目标端口: %s, err code: %s", serviceIP, servicePort, strerror(errno));
  344. return -1;
  345. }
  346. // 关闭套接字
  347. close(sockfd);
  348. return 0;
  349. }
  350. /**
  351. * @brief
  352. * !注意: 由于W5500一个socket只能listen一个连接
  353. * !RyanW5500库实现的listen多连接,原有服务器套接字不使用,
  354. * !accept时会保证服务器socket链表中有一个套接字进行listen,当有客户端连接时,返回此套接字
  355. *
  356. * @param argc
  357. * @param argv
  358. * @return int
  359. */
  360. static int w5500tcpService(int argc, char *argv[])
  361. {
  362. if (argc < 3)
  363. {
  364. ulog_i(TAG, "请输入tcpService的port ");
  365. return 0;
  366. }
  367. int32_t port = atoi(argv[2]);
  368. static rt_thread_t hid = NULL;
  369. if (NULL != hid)
  370. {
  371. ulog_w(TAG, "tcp服务器已启动,请勿重复创建");
  372. return -1;
  373. }
  374. // 创建WIZnet SPI RX线程
  375. hid = rt_thread_create("tcpService", // 线程name
  376. tcpEchoTask, // 线程入口函数
  377. (void *)port, // 线程入口函数参数
  378. 2048, // 线程栈大小
  379. 16, // 线程优先级
  380. 5); // 线程时间片
  381. if (hid != NULL)
  382. rt_thread_startup(hid);
  383. else
  384. ulog_w(TAG, "创建tcp echo线程失败");
  385. return 0;
  386. }
  387. static int w5500Broadcast(int argc, char *argv[])
  388. {
  389. if (argc < 4)
  390. {
  391. ulog_i(TAG, "请输入broadcast发送的port和消息内容 ");
  392. return 0;
  393. }
  394. int32_t port = atoi(argv[2]);
  395. char *msg = argv[3];
  396. // udp支持广播
  397. int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  398. // 让sockfd支持广播
  399. int yes = 1;
  400. setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
  401. // 发送广播地址(目的地址 是广播地址)
  402. struct sockaddr_in dst_addr = {
  403. .sin_family = AF_INET,
  404. .sin_port = htons(port),
  405. .sin_addr.s_addr = inet_addr("255.255.255.255")};
  406. sendto(sockfd, msg, strlen(msg), 0,
  407. (struct sockaddr *)&dst_addr, sizeof(dst_addr));
  408. close(sockfd);
  409. return 0;
  410. }
  411. /**
  412. * @brief
  413. * !注意:RyanW5500组播实现不支持加入多个组播组,这是由W5500硬件限制的,和tcp服务器一样。
  414. * !虽然可以通过申请多个socket, 再将数据合并实现,但考虑多组播功能并不常用,且实现较为复杂占资源,暂时没有实现多组播
  415. * !目前如果需要加入多个组播的话,就申请多个socket分别加入组播组吧
  416. *
  417. * @param argc
  418. * @param argv
  419. * @return int
  420. */
  421. static int w5500Multicast(int argc, char *argv[])
  422. {
  423. if (argc < 3)
  424. {
  425. ulog_i(TAG, "请输入multicast发送的port ");
  426. return 0;
  427. }
  428. int32_t port = atoi(argv[2]);
  429. static rt_thread_t hid = NULL;
  430. if (NULL != hid)
  431. {
  432. ulog_w(TAG, "组播echo服务器已启动,请勿重复创建");
  433. return -1;
  434. }
  435. // 创建WIZnet SPI RX线程
  436. hid = rt_thread_create("multicast", // 线程name
  437. multicastEchoServiceTask, // 线程入口函数
  438. (void *)port, // 线程入口函数参数
  439. 2048, // 线程栈大小
  440. 19, // 线程优先级
  441. 5); // 线程时间片
  442. if (hid != NULL)
  443. rt_thread_startup(hid);
  444. else
  445. ulog_w(TAG, "创建udp echo线程失败");
  446. ulog_i(TAG, "multicast 地址: %s, port: %d", "224.0.0.252", port);
  447. return 0;
  448. }
  449. static int w5500dhcpLeasetime(int argc, char *argv[])
  450. {
  451. if (RT_TRUE != netdev_is_dhcp_enabled(ryanNetDev))
  452. {
  453. ulog_i(TAG, "dhcp服务未启动, 目前处于静态ip状态");
  454. return 0;
  455. }
  456. ulog_i(TAG, "租期总时长:%d s, 剩余时长: %d s", getDHCPLeaseTime() / 1000, getDHCPRemainLeaseTime() / 1000);
  457. return 0;
  458. }
  459. static int w5500GetNetInfo(int argc, char *argv[])
  460. {
  461. uint8_t tmpstr[6] = {0};
  462. wiz_NetInfo netinfo = {0};
  463. // Display Network Information
  464. ctlwizchip(CW_GET_ID, (void *)tmpstr);
  465. ctlnetwork(CN_GET_NETINFO, (void *)&netinfo); // 获取网络信息
  466. if (NETINFO_DHCP == netinfo.dhcp)
  467. printf("\r\n=== %s NET CONF : DHCP ===\r\n", (char *)tmpstr);
  468. else
  469. printf("\r\n=== %s NET CONF : Static ===\r\n", (char *)tmpstr);
  470. printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", netinfo.mac[0], netinfo.mac[1], netinfo.mac[2],
  471. netinfo.mac[3], netinfo.mac[4], netinfo.mac[5]);
  472. printf("SIP: %d.%d.%d.%d\r\n", netinfo.ip[0], netinfo.ip[1], netinfo.ip[2], netinfo.ip[3]);
  473. printf("GAR: %d.%d.%d.%d\r\n", netinfo.gw[0], netinfo.gw[1], netinfo.gw[2], netinfo.gw[3]);
  474. printf("SUB: %d.%d.%d.%d\r\n", netinfo.sn[0], netinfo.sn[1], netinfo.sn[2], netinfo.sn[3]);
  475. printf("DNS: %d.%d.%d.%d\r\n", netinfo.dns[0], netinfo.dns[1], netinfo.dns[2], netinfo.dns[3]);
  476. printf("===========================\r\n");
  477. return 0;
  478. }
  479. static int w5500GetHostByName(int argc, char *argv[])
  480. {
  481. if (argc < 4)
  482. {
  483. ulog_i(TAG, "请版本、带解析的域名信息。 版本1使用线程安全版本, 0非线程安全版本");
  484. return 0;
  485. }
  486. uint8_t choice = atoi(argv[2]);
  487. char *nameStr = argv[3];
  488. if (0 == choice)
  489. {
  490. struct hostent *hent;
  491. hent = gethostbyname(nameStr);
  492. if (hent == NULL)
  493. {
  494. printf("ERROR: gethostbyname error for hostname: %s\n", nameStr);
  495. return 0;
  496. }
  497. printf("name: %s, addrtype: %d(AF_INET:%d), len:%d\n",
  498. hent->h_name, hent->h_addrtype, AF_INET,
  499. hent->h_length);
  500. for (uint8_t i = 0; hent->h_aliases[i]; i++)
  501. printf("alias hostname: %s\n", hent->h_aliases[i]);
  502. for (uint8_t i = 0; hent->h_addr_list[i]; i++)
  503. printf("host addr is: %s\n", inet_ntoa(*(struct in_addr *)hent->h_addr_list[i]));
  504. }
  505. else
  506. {
  507. char buf[1024];
  508. int ret;
  509. struct hostent hostinfo, *phost;
  510. if (gethostbyname_r(nameStr, &hostinfo, buf, sizeof(buf), &phost, &ret))
  511. {
  512. printf("ERROR:gethostbyname(%s) ret:%d\n", nameStr, ret);
  513. return 0;
  514. }
  515. printf("name: %s, addrtype: %d(AF_INET:%d), len:%d\n",
  516. phost->h_name, phost->h_addrtype, AF_INET,
  517. phost->h_length);
  518. for (uint8_t i = 0; hostinfo.h_aliases[i]; i++)
  519. printf("alias hostname: %s\n", hostinfo.h_aliases[i]);
  520. for (uint8_t i = 0; hostinfo.h_addr_list[i]; i++)
  521. printf("host addr is: %s\n", inet_ntoa(*((struct in_addr *)hostinfo.h_addr_list[i])));
  522. }
  523. return 0;
  524. }
  525. static int w5500GetAddrInfo(int argc, char *argv[])
  526. {
  527. if (argc < 4)
  528. {
  529. ulog_i(TAG, "请输入要解析的域名和端口");
  530. return 0;
  531. }
  532. char *nameStr = argv[2];
  533. char *namePort = argv[3];
  534. struct addrinfo *addrList = NULL,
  535. *aip;
  536. struct addrinfo hints = {0};
  537. int result = getaddrinfo(nameStr, namePort, &hints, &addrList);
  538. if (0 != result)
  539. {
  540. printf("ERROR: getaddrinfo(%s) ret:%d\n", nameStr, result);
  541. return 0;
  542. }
  543. struct sockaddr_in *sinp;
  544. const char *addr;
  545. char buf[40];
  546. for (aip = addrList; aip != NULL; aip = aip->ai_next)
  547. {
  548. sinp = (struct sockaddr_in *)aip->ai_addr;
  549. addr = inet_ntop(AF_INET, &sinp->sin_addr, buf, sizeof(buf));
  550. printf(" addr = %s, port = %d\n", addr ? addr : "unknow ", ntohs(sinp->sin_port));
  551. }
  552. if (NULL != addrList)
  553. freeaddrinfo(addrList);
  554. return 0;
  555. }
  556. /**
  557. * @brief mqtt msh命令
  558. *
  559. */
  560. struct RyanMqttCmdDes
  561. {
  562. const char *cmd;
  563. const char *explain;
  564. int (*fun)(int argc, char *argv[]);
  565. };
  566. static int w5500Help(int argc, char *argv[]);
  567. static const struct RyanMqttCmdDes cmdTab[] =
  568. {
  569. {"help", "打印帮助信息", w5500Help},
  570. {"start", "打印帮助信息", w5500Start},
  571. {"static", "设置w5500静态地址", w5500Static},
  572. {"dhcp", "设置w5500 dhcp", w5500Dhcp},
  573. {"udpClient", "w5500 udp客户端 param: ip, port", w5500UdpClient},
  574. {"udpService", "w5500 udp echo服务器 param: port", w5500UdpService},
  575. {"tcpClient", "w5500 tcp客户端 param: ip, port", w5500TcpClient},
  576. {"tcpService", "w5500 tcp 多线程echo服务器 param: port", w5500tcpService},
  577. {"broadcast", "w5500 广播 param: port, msg", w5500Broadcast},
  578. {"multicast", "w5500 多播 echo服务器 param: port", w5500Multicast},
  579. {"dhcpLease", "w5500 获取dhcp租期和剩余时间", w5500dhcpLeasetime},
  580. {"netInfo", "w5500 获取芯片内部配置信息", w5500GetNetInfo},
  581. {"gethostbyname", "w5500 根据域名解析地址信息", w5500GetHostByName},
  582. {"getaddrinfo", "w5500 根据域名获取IP等信息", w5500GetAddrInfo},
  583. };
  584. static int w5500Help(int argc, char *argv[])
  585. {
  586. for (uint8_t i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
  587. rt_kprintf("w5500 %-16s %s\r\n", cmdTab[i].cmd, cmdTab[i].explain);
  588. return 0;
  589. }
  590. static int RyanMqttMsh(int argc, char *argv[])
  591. {
  592. int32_t i = 0,
  593. result = 0;
  594. struct RyanMqttCmdDes *runCmd = NULL;
  595. if (argc == 1)
  596. {
  597. w5500Help(argc, argv);
  598. return 0;
  599. }
  600. for (i = 0; i < sizeof(cmdTab) / sizeof(cmdTab[0]); i++)
  601. {
  602. if (rt_strcmp(cmdTab[i].cmd, argv[1]) == 0)
  603. {
  604. runCmd = &cmdTab[i];
  605. break;
  606. }
  607. }
  608. if (runCmd == NULL)
  609. {
  610. w5500Help(argc, argv);
  611. return 0;
  612. }
  613. if (runCmd->fun != NULL)
  614. result = runCmd->fun(argc, argv);
  615. return 0;
  616. }
  617. #if defined(RT_USING_MSH)
  618. MSH_CMD_EXPORT_ALIAS(RyanMqttMsh, w5500, RyanMqtt command);
  619. #endif