GD32F407之LWIP的移植和UDP_TCPC测试

[复制链接]
8032|17
 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层 |阅读模式
LWIP的移植

1、Lwip内核文件的移植参考正点原子的STM32F407无操作系统的移植,如图工程文件目录结构

2846464c0f6c65984d.png

添加arch文件

由于不使用RTOS实时系统所以,(cc.h、cpu.h、perf.h、sys_arch.h、sys_arch.c)基本不使用,所以也没有正点原子里面的Lwip_Arch文件夹,只是简单地实现了获取时间函数sys_now();代码在lwip_comm.c中。


 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层
添加LWIP通用文件

Lwip_App为通用文件夹,里面包含五个文件夹lwip_comm (lwip_comm.c、lwip_comm.h是LWIP源码和前面的以太网驱动库结合起来的桥梁。lwipopts.h是用来剪裁和配置LWIP的文件)、tcp_client_demo、tcp_server_demo、udp_demo、web_server_demo,后面这四个是网络应用的功能函数,lwip_comm.h里面定义了本机MAC地址,远端主机IP地址,本机IP地址,子网掩码,默认网关和是否使用DHCP
1602364c0f6e4063da.png
 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层
LWIP的剪裁和配置

在LWIP的源码中有一个opt.h的文件,这个文件就是剪裁和配置LWIP的,不过最好不要在这个文件里面修改,我们可以在其他的文件中定义来覆盖opt.h里面的定义,所以前面提过的LWIP->Lwip_App->Lwip_comm里面的lwipopt.h就是重新定义来剪裁配置LWIP的

5897564c0f6f616991.png
 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层
 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层
 楼主| qsrg51 发表于 2023-7-26 18:35 | 显示全部楼层
到这简单LWIP移植就OK了(详细参考正点原子),为了验证是否有效下面我们做UDP和TCP通信来验证
 楼主| qsrg51 发表于 2023-7-26 18:36 | 显示全部楼层
UDP接口编程
对于UDP的协议可以网上参考,主要说明一下LWIP中的UDP协议函数(参考正点原子STM32F407LWIP开发手册)在LWIP的源码中有udp.c和udp.h两个和UDP有关的函数(lwip-1.4.1\src\core)

Udp.c中与UDP报文处理有关的函数之间关系图

1021564c0f71d51f3b.png
 楼主| qsrg51 发表于 2023-7-26 18:36 | 显示全部楼层
Lwip的RAW_API编程方式是基于回调机制的,当我们初始化应用的时候我们必须为内核中的不同事件注册相应的回调函数,当事件发生的时候这些回调函数就会被调用,部分函数说明

6128564c0f72e719c5.png
 楼主| qsrg51 发表于 2023-7-26 18:36 | 显示全部楼层
我们简单做一个demo来测试UPD客户端数据传输功能
  1. #define UDP_DEMO_PORT 8090     //本地端口

  2. uint8_t udp_demo_recvbuf[100]; //UDP接收数据缓冲区
  3. uint8_t udp_demo_sendbuf[50];  //UDP发送数据内容缓冲区
  4. uint8_t UdpRecelen=0;
  5. /******************************************************************************
  6. * 描述  : 创建udp客户端
  7. * 参数  : 无
  8. * 返回  : 无
  9. ******************************************************************************/
  10. void udp_echo_init(void)
  11. {
  12.     struct udp_pcb *udp_client_pcb;  
  13.   
  14.     /* 为udp客户端分配一个udp_pcb结构体 */
  15.     udp_client_pcb = udp_new();
  16.        
  17.     /* 绑定本地端号和IP地址 */
  18.     udp_bind(udp_client_pcb, IP_ADDR_ANY, UDP_DEMO_PORT);
  19.        
  20.     /* 注册接收回调函数 */
  21.     udp_recv(udp_client_pcb,udp_demo_recv,NULL);
  22. }
  23. /******************************************************************************
  24. * 描述  : 接收回调函数
  25. * 参数  : -
  26. * 返回  : 无
  27. ******************************************************************************/
  28. void udp_demo_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
  29. {
  30.     uint32_t data_len = 0;
  31.     struct pbuf *q;
  32.        
  33.     if(p!=NULL){       
  34.         memset(udp_demo_recvbuf,0,UDP_DEMO_RX_BUFSIZE);
  35.                
  36.         /* 遍历整个pbuf链表 */
  37.         for(q=p;q!=NULL;q=q->next){
  38.             //判断要拷贝到UDP_DEMO_RX_BUFSIZE中的数据是否大于
  39.             //UDP_DEMO_RX_BUFSIZE的剩余空间,如果大于
  40.             //的话就只拷贝UDP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据
  41.             if(q->len > (UDP_DEMO_RX_BUFSIZE-data_len)){
  42.                 memcpy(udp_demo_recvbuf+data_len,q->payload,(UDP_DEMO_RX_BUFSIZE- data_len));
  43.             }            
  44.             else memcpy(udp_demo_recvbuf+data_len,q->payload,q->len);
  45.             
  46.             data_len += q->len;         
  47.             if(data_len > UDP_DEMO_RX_BUFSIZE) break;
  48.         }
  49.         /* 接收的数据长度 */
  50.         UdpRecelen = data_len;
  51.                
  52.         /* 记录远端主机的IP地址 */
  53.         upcb->remote_ip=*addr;                
  54.         /* 记录远端主机的端口号 */
  55.         upcb->remote_port=port;                 

  56.         /* 接收数据处理函数 */
  57.         UDP_ReceData_Handler(upcb,UdpRecelen);
  58.                
  59.         /* 释放缓冲区数据 */
  60.         pbuf_free(p);
  61.     }
  62. }
  63. /******************************************************************************
  64. * 描述  : 发送udp数据
  65. * 参数  :
  66. * 返回  : 无
  67. ******************************************************************************/
  68. void udp_demo_senddata(struct udp_pcb *upcb,uint8_t *sendbuf)
  69. {
  70.     struct pbuf *ptr;
  71.        
  72.     /* 分配缓冲区空间 */
  73.     ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)sendbuf),PBUF_POOL);
  74.        
  75.     if(ptr){
  76.         /* 填充缓冲区数据 */
  77.         ptr->payload=(void*)sendbuf;
  78.                
  79.         /* 发送udp数据 */
  80.         udp_send(upcb,ptr);
  81.                
  82.         /* 释放缓冲区空间 */
  83.         pbuf_free(ptr);
  84.     }
  85. }
  86. /******************************************************************************
  87. * 描述  : udp数据处理函数
  88. * 参数  :
  89. * 返回  : 无
  90. ******************************************************************************/

  91. void UDP_ReceData_Handler(upcb,UdpRecelen)
  92. {
  93.     /* 将接收到的数据再转发出去 */
  94.     udp_demo_senddata(upcb,udp_demo_recvbuf);
  95.        
  96.     /* 也可以做一些判断,在做自己的功能 */
  97.     /* 发送 0x2a 0x01 数据*/
  98.     if(UdpRecelen>=2){
  99.         if((0x01 == udp_demo_recvbuf[1]) && (0x2a==udp_demo_recvbuf[0])){
  100.             //Read BMC version
  101.             printf("Hello LWIP UDP demo");
  102.         }
  103.         memset(udp_demo_sendbuf,0,UDP_DEMO_RX_BUFSIZE);
  104.         UdpRecelen = 0;
  105.     }else{
  106.         UdpRecelen = 0 ;
  107.     }
  108. }
 楼主| qsrg51 发表于 2023-7-26 18:37 | 显示全部楼层
TCP接口编程
对于TCP的协议可以网上参考,主要说明一下LWIP中的TCP协议函数(参考正点原子STM32F407LWIP开发手册)

在LWIP的源码中有tcp.c,tcp.h,tcp_in.c和tcp_out.c函数和TCP有关(lwip-1.4.1\src\core)

TCP层中函数关系图:

2993364c0f7596a61a.png
 楼主| qsrg51 发表于 2023-7-26 18:37 | 显示全部楼层
LWIP提供的TCP函数
1432864c0f78024e0f.png
 楼主| qsrg51 发表于 2023-7-26 18:38 | 显示全部楼层
我们简单做一个demo来测试TCP服务端数据传输功能
  1. /******************************************************************************
  2. * 描述  : 创建tcp服务器
  3. * 参数  : 无
  4. * 返回  : 无
  5. ******************************************************************************/
  6. void Tcp_Server_Init(void)
  7. {
  8.     struct tcp_pcb *tcp_server_pcb;

  9.     /* 为tcp服务器分配一个tcp_pcb结构体    */
  10.     tcp_server_pcb = tcp_new();

  11.     /* 绑定本地端号和IP地址 */
  12.     tcp_bind(tcp_server_pcb, IP_ADDR_ANY, 80);

  13.     /* 监听之前创建的结构体tcp_server_pcb */
  14.     tcp_server_pcb = tcp_listen(tcp_server_pcb);

  15.     /* 初始化结构体接收回调函数 */
  16.     tcp_accept(tcp_server_pcb, tcp_server_accept);
  17. }
  18. /******************************************************************************
  19. * 描述  : 客户端接入回调函数
  20. * 参数  : -
  21. * 返回  : -
  22. ******************************************************************************/
  23. static err_t tcp_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
  24. {
  25.     /* 确认监听与连接 */
  26.     tcp_arg(pcb, mem_calloc(sizeof(struct name), 1));

  27.     /* 发送一个建立连接的字符串 */
  28.     tcp_write(pcb, "hello my dream \n\r",strlen("hello my dream \n\r  "), 1);

  29.     /* 配置接收回调函数 */
  30.     tcp_recv(pcb, tcp_server_recv);

  31.     return ERR_OK;
  32. }

  33. /******************************************************************************
  34. * 描述  : 接收回调函数
  35. * 参数  : -
  36. * 返回  : -
  37. ******************************************************************************/
  38. static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *tcp_recv_pbuf, err_t err)
  39. {
  40.     struct pbuf *tcp_send_pbuf;
  41.     struct name *name = (struct name *)arg;

  42.     if (tcp_recv_pbuf != NULL)
  43.     {
  44.         /* 扩大收发数据的窗口 */
  45.         tcp_recved(pcb, tcp_recv_pbuf->tot_len);

  46.         if (!name)
  47.         {
  48.             pbuf_free(tcp_recv_pbuf);
  49.             return ERR_ARG;
  50.         }

  51.         /* 将接收的数据拷贝给发送结构体 */
  52.         tcp_send_pbuf = tcp_recv_pbuf;

  53.         /* 换行 */
  54.         tcp_write(pcb, "\r\n", strlen("\r\n"), 1);
  55.         /* 将接收到的数据再转发出去 */
  56.         tcp_write(pcb, tcp_send_pbuf->payload, tcp_send_pbuf->len, 1);

  57.         pbuf_free(tcp_recv_pbuf);
  58.     }
  59.     else if (err == ERR_OK)
  60.     {
  61.         /* 释放内存 */
  62.         mem_free(name);
  63.         return tcp_close(pcb);
  64.     }

  65.     return ERR_OK;
  66. }
 楼主| qsrg51 发表于 2023-7-26 18:38 | 显示全部楼层
这里只是简单的介绍了一下LWIP的UDP和TCP,对于整个LWIP还是非常的复杂,如果想继续深入了解LWIP可以翻看LWIP的源码---
sfd123 发表于 2024-2-3 16:05 | 显示全部楼层
谢谢分享,已收藏,我也正准备搞搞!
申小林一号 发表于 2024-4-30 16:39 | 显示全部楼层
非常不错的帖子,值得推广扩散!!!
kmnqhaha 发表于 2024-4-30 17:29 | 显示全部楼层
简单实现获取时间函数sys_now();代码在lwip_comm.c中
埃娃 发表于 2024-5-15 23:54 | 显示全部楼层
裸机实现的吗
sfd123 发表于 2024-5-16 10:00 | 显示全部楼层
楼主 有没有  更新一个 lwip2.x的啊?好像结构和1.4不太一样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

444

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部