C

lwIP学习(一)

IP,Udp

Views:  times Updated on October 25, 2022 Posted by elmagnifico on September 21, 2022

Foreword

IwIP,直接看MTK的demo好像挺简单的,实际一用,发现不是这么回事,而且感觉API非常多,各种地方使用的都乱七八糟的。还是看官方文档学习一下具体是怎么使用的。

IwIP

API

  • Callback API

lwIP大部分API都是基于Callback的形式设计的,只要定义好需要处理的事件,后续在对应的Callback中一一回应就行了。Callback类型的API自然也不能在IRQ里调用。

  • raw API

同时,他也有对应的裸板API,或者说非CallBack类型的API,主要是节省内存空间,而且不需要操作系统,就可以直接使用。

  • sequential API

顺序API,主要是给底层调用协议栈使用的,阻塞式的

  • socket API

基于sequential API而来的,BSD风格的,由于存在复制数据等层层包装,效率低一些

  • Netconn API

基于sequential API,主要是线程安全,复制数据比socket API稍微少一点,可以从其他线程调用

  • NETIF API

这个主要是用于处理多网口的应用,平常应该不会有这个问题

一般来说,开发主要使用Callback API或者是 sequential API

UDP

Callback/Socket API

以udp开头的api,基本都是Callback API

UDP由于本身比较简单,所以他的接口相对TCP来说也简单了很多

struct udp_pcb *udp_new(void)

创建一个pcb,只有绑定到本地或者连接到远端地址才生效

void udp_remove(struct udp_pcb *pcb)

移除一个pcb

err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
                 u16_t port)

绑定到本地,监听所有需要设置ip为IP_ADDR_ANY

err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
                    u16_t port)

连接远端地址,实际不会发送任何数据到远端

udp_disconnect(struct udp_pcb *pcb)

断开远端连接

udp_send(struct udp_pcb *pcb, struct pbuf *p)

发送对应的数据

udp_recv(struct udp_pcb *pcb,
                void (* recv)(void *arg, struct udp_pcb *upcb,
                                         struct pbuf *p,
                                         ip_addr_t *addr,
                                         u16_t port),
                              void *recv_arg)

设置接收数据的回调

阻塞与非阻塞

如果使用直接进行传输的接口,可能还会有阻塞和非阻塞的问题

uint32_t mode1 = 1;
ioctlsocket(s,FIONBIO,&mode1);//非阻塞
mode1 = 0;
ioctlsocket(s,FIONBIO,&mode1);//阻塞

或者在接收或者发送的时候使用MSG_DONTWAIT表示非阻塞,0表示阻塞

rlen = lwip_recv(dmd_udp_sock, rcv_buf, sizeof(rcv_buf) - 1,MSG_DONTWAIT);
lwip_send(dmd_udp_sock, mav_send_bytes, sizeof(mav_send_count),MSG_DONTWAIT);

这里遇到一点问题,mt793x的lwip_socket_demo,udp client应该是写错了,用上面的api会出现直接卡死,收不到任何数据的情况

实际不建议直接使用lwip开头的API,除非你真的知道你在干什么

demo

参考如下,略作修改

https://github.com/54zorb/stm32-lwip

#include "stm32f4xx_hal.h"
#include "lwip.h"
#include "udp.h"
#include "string.h"

/* 定义端口号 */
#define UDP_REMOTE_PORT    8881 /* 远端端口 */
#define UDP_LOCAL_PORT     8880 /* 本地端口 */

/* udp控制块 */
static struct udp_pcb *upcb;

/******************************************************************************
 * 描述  : 接收回调函数
 * 参数  : -
 * 返回  : 无
******************************************************************************/
static void udp_receive_callback(void *arg, struct udp_pcb *upcb,
    struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
    uint32_t i;
    
    /* 数据回传 */
//    udp_send(upcb, p);
//    udp_sendto(upcb, p, addr, port);
    
    /* 打印接收到的数据 */
    printf("get msg from %d:%d:%d:%d port:%d:\r\n",
        *((uint8_t *)&addr->addr), *((uint8_t *)&addr->addr + 1),
        *((uint8_t *)&addr->addr + 2), *((uint8_t *)&addr->addr + 3), port);
    
    if (p != NULL)
    {
        struct pbuf *ptmp = p;
        
        while(ptmp != NULL)
        {
            for (i = 0; i < p->len; i++)
            {
                printf("%c", *((char *)p->payload + i));
            }
            
            ptmp = p->next;
        }
        
        printf("\r\n");
    }
    
    /* 释放缓冲区数据 */
    pbuf_free(p);
}

/******************************************************************************
 * 描述  : 发送udp数据
 * 参数  : (in)pData 发送数据的指针
 * 返回  : 无
******************************************************************************/
void udp_client_send(uint8_t *pData,uint16_t len)
{
    struct pbuf *p;
    
    /* 分配缓冲区空间 */
    p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL);
    
    if (p != NULL)
    {
        /* 填充缓冲区数据 */
        pbuf_take(p, pData, len);

        /* 发送udp数据 */
        udp_send(upcb, p);

        /* 释放缓冲区空间 */
        pbuf_free(p);
    }
}

/******************************************************************************
 * 描述  : 创建udp客户端
 * 参数  : 无
 * 返回  : 无
******************************************************************************/
void udp_client_init(void)
{
    ip_addr_t serverIP;
    err_t err;

    IP4_ADDR(&serverIP, 192, 168, 2, 194);

    /* 创建udp控制块 */
    upcb = udp_new();

    if (upcb!=NULL)
    {
        /* 配置本地端口 */
        upcb->local_port = UDP_LOCAL_PORT;
        
        /* 配置服务器IP和端口 */
        err= udp_connect(upcb, &serverIP, UDP_REMOTE_PORT);

        if (err == ERR_OK)
        {
            /* 注册接收回调函数 */
            udp_recv(upcb, udp_receive_callback, NULL);
            
            /* 发送udp数据 */
            udp_client_send("udp client connected");
            
            printf("udp client connected\r\n");
        }
        else
        {
            udp_remove(upcb);
            
            printf("can not connect udp pcb\r\n");
        }
    }
}

Summary

暂时先这样

Quote

https://www.nongnu.org/lwip/2_0_x/raw_api.html