lwip是一套强大的tcpip库,对于低性能单片机类的设备中非常适合,可以方便的让设备在任何底层通信中使用tcpip传输协议。
通过lwip,可以实现uart传tcpip,lora等传tcpip等。下面就给大家介绍下如何实现无操作系统情况下对ethernet驱动的移植:
1、先去github下载lwip源码:传送门。这里下载lwip-STABLE-2_1_3_RELEASE版本。
2、解压,将src下的api、core、netif、include复制到自己的工程中去,不需要其他额外文件。
3、修改自己的工程管理工具将自己的main.c文件以及上面文件夹中的api、core、netif中包含的c文件都添加到工程中编译。
4、修改自己的工程管理工具让include变为编译头文件路径。
5、在自己的编译头文件路径中添加lwipopts.h、arch/cc.h与arch/cc.c文件。
6、在lwipopts.h中添加特定的宏,如#define NO_SYS 1
#ifndef LWIP_HDR_LWIPOPTS_H #define LWIP_HDR_LWIPOPTS_H // #define LWIP_DEBUG 1 #define MEM_ALIGNMENT 4 #define NO_SYS 1 #define SYS_LIGHTWEIGHT_PROT 0 #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 #define LWIP_ETHERNET 1 #define LWIP_ARP 1 #define LWIP_DHCP 1 #define LWIP_AUTOIP 0 #define LWIP_IGMP 1 #define LWIP_DNS 1 #define MEM_SIZE 4096 #define TCP_SND_QUEUELEN 6 #define TCP_SNDLOWAT 1002 #define PBUF_POOL_SIZE 5 #endif
7、实现u32_t sys_now(void)函数
不同的芯片实现方式不同,这里返回的是毫秒时间。linux可以用如下方式模拟:
u32_t sys_now(void) { struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); return 1000 * tp.tv_sec + tp.tv_nsec / 1000; }
8、定义LWIP_RAND()方法
不同的芯片实现方式不同,这里返回的是毫秒时间。linux可以用如下方式模拟:
#define LWIP_RAND() ((u32_t)rand())
到此,移植完毕。下面介绍如何使用:
1、执行初始化函数
ip4_addr_t addr; ip4_addr_t netmask; ip4_addr_t gw; IP4_ADDR(&addr, 192, 168, 37, 84); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 37, 1); lwip_init(); netif_add(&netif, &addr, &netmask, &gw, &netif, eth_init, netif_input); netif_set_default(&netif); netif_set_up(&netif); netif_set_link_up(&netif); ip4_addr_t dns; IP4_ADDR(&dns, 114, 114, 114, 114); dns_setserver(0, &dns);
其中eth_init是初始化函数,
static err_t eth_init(struct netif *netif) { netif->name[0] = 'w'; netif->name[1] = 'f'; netif->output = etharp_output; netif->linkoutput = low_tap_output; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; netif->hwaddr[0] = 0x00; netif->hwaddr[1] = 0x23; netif->hwaddr[2] = 0xC1; netif->hwaddr[3] = 0xDE; netif->hwaddr[4] = 0xD0; netif->hwaddr[5] = 0x0D; netif->hwaddr_len = 6; return ERR_OK; }
上诉代码就是实现了lwip的基本移植,上面代码配置了一个ip为192.168.37.84,mask为255.255.255.0,gateway为192.168.37.1,dns为114.114.114.114的网卡,该网卡的mac为00:23:c1:de:d0:d0。
初始化代码中的low_tap_output是底层发送函数,需要根据不同的芯片进行修改。
static err_t low_tap_output(struct netif *netif, struct pbuf *p) { char buff[1518]; int len = 0; for (struct pbuf *q = p; q != NULL; q = q->next) { memcpy(buff + len, q->payload, q->len); len += q->len; } write(tapfd, buff, len); // 底层发送函数 return ERR_OK; }
还有需要创建两个线程,一个是循环调用sys_check_timeouts()。另一个是接收物理端发过来的数据包。
void *checktimeout() { while (1) { usleep(100000); sys_check_timeouts(); } } void *low_tap_input() { unsigned char buff[1518]; while (1) { ssize_t len = read(tapfd, buff, 1518); // 接收底层物理数据 if (len < 0) { continue; } struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p == NULL) { continue; } pbuf_take(p, buff, len); netif.input(p, &netif); // p在netif_input内已经释放了,无需再调用pbuf_free(p) } return NULL; }
到此就可以尝试ping一下了。
文章作者:沃航科技