RyanW5500Test.c 25 KB

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