LWIP移植
理论
https://www.cnblogs.com/alan666/p/8312144.html
void lwip_init(void)
LWIP协议栈初始化,不用动。
//注册网卡 dw_gmac_netif ,进行网卡底层初始化low_level_init,
//绑定底层 low_level_output;
void ethernetif_config(void)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
/* IP address default setting */
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255 , 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
/* add the network interface */
netif_add(&dw_gmac_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&dw_gmac_netif);
netif_set_up(&dw_gmac_netif);
printf("dw_gmac_netif=%08x\r\n",&dw_gmac_netif);
printf("ip_addr=%08x\r\n",dw_gmac_netif.ip_addr);
printf("netmask=%08x\r\n",dw_gmac_netif.netmask);
printf("gw=%08x\r\n",dw_gmac_netif.gw);
}
void
ethernetif_input(struct netif *netif)
//调用底层 low_level_output;
ethernetif_input ->
p = low_level_input(netif);
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
case ETHTYPE_IP:
case ETHTYPE_ARP:
if (netif->input(p, netif)!=ERR_OK) //调用etharp.c里的ethnet_input函数
ethernet_input ->
switch (htons(ethhdr->type)) { //不同协议调用不同函数 arp 0x0806 IP 0x0800
case ETHTYPE_IP:
#if ETHARP_TRUST_IP_MAC //如果使能了arp更新缓冲功能
etharp_ip_input(netif, p); //更新arp列表
#endif /* ETHARP_TRUST_IP_MAC */
ip_input(p, netif); //ip协议,调用IP处理函数
break;
case ETHTYPE_ARP:
etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); //arp协议,调用arp处理函数
break;
ip_input ->
iphdr = p->payload; //获取数据
switch (iphdr->nexthdr) {
case IP_PROTO_UDP:
udp_input(p, inp);
break;
case IP_PROTO_TCP:
tcp_input(p, inp);
break;
case IP_PROTO_ICMP:
icmp_input(p, inp);
break;
icmp_input ->
switch (type) {
case ICMP_ER:
break;
case ICMP_ECHO:
break;
一、下载lwip
可以到网上找一个下载,或者拷贝被人移植好的工程里的LWIP文件夹。
二、添加到KEIL工程
1、将文件夹拷贝到KEIL工程中。
2、添加Lwip/api等group,如下
3、为每个group添加对应.c文件,并添加头文件引用目录
三、函数更改
1 void lwip_init(void)
该函数为lwip接口函数,在main函数中直接调用该函数即可。
2 void ethernetif_config(void)
void ethernetif_config(void)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
/* IP address default setting */
IP4_ADDR(&ipaddr, 192, 168, 0, 20);
IP4_ADDR(&netmask, 255, 255 , 255, 0);
IP4_ADDR(&gw, 192, 168, 0, 1);
/* add the network interface */
netif_add(&DM9000_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&DM9000_netif);
netif_set_up(&DM9000_netif);
}
该接口函数中,IP可以自定义设计;DM9000_netif为网络接口对象全局变量;
其中的err_t ethernetif_init(struct netif *netif)函数会调用low_level_init函数:
3 static void low_level_init(struct netif *netif)
static void
low_level_init(struct netif *netif)
{
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = default_enetaddr[0];
netif->hwaddr[1] = default_enetaddr[1];
netif->hwaddr[2] = default_enetaddr[2];
netif->hwaddr[3] = default_enetaddr[3];
netif->hwaddr[4] = default_enetaddr[4];
netif->hwaddr[5] = default_enetaddr[5];
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
/* Do whatever else is needed to initialize interface. */
DM9000_Init();
}
该函数中的MAC地址default_enetaddr可以自定义,DM9000_Init()函数为底层GMAC和PHY的初始化函数,需替换为我们自己的初始化函数。
4、low_level_output
需将low_level_output中的发送函数替换为我们的发送函数。
5、low_level_input
需将low_level_input中的接收函数替换为我们的接收函数。
6、ethernetif_input(&DM9000_netif)
完成以上工作后,只需在main函数中循环调用或者在接收中断中调用ethernetif_input(&DM9000_netif)函数,即可实现对网络数据的接收。
四、TCP客户端通信
1、建立一个TCP控制块,进行初始化,并绑定端口和accept_callback回调函数。
程序中绑定的端口是虚拟的,网上看到的一个比喻是:“端口是该计算机逻辑通讯接口,不同的应用程序用不同的端口,就像你家里的各个不同的房间,卧室用来睡觉,餐厅用来吃饭。”
就比如我们的板子设定69端口用于TFTP传输,80端口用于TCP通信。
int start_tcp_server()
{
struct tcp_pcb *pcb;
err_t err;
unsigned port = 6001;
/* create new TCP PCB structure */
pcb = tcp_new();
if (!pcb) {
printf("Error creating PCB. Out of Memory\n\r");
return -1;
}
/* bind to specified @port */
err = tcp_bind(pcb, IP_ADDR_ANY, port);
if (err != ERR_OK) {
printf("Unable to bind to port %d: err = %d\n\r", port, err);
return -2;
}
/* we do not need any arguments to callback functions */
tcp_arg(pcb, NULL);
/* listen for connections */
pcb = tcp_listen(pcb);
if (!pcb) {
printf("Out of memory while tcp_listen\n\r");
return -3;
}
/* specify callback to use for incoming connections */
tcp_accept(pcb, accept_callback);
printf("\r\n-----TCP echo server started @ port %d-----\n\r", port);
return 0;
}
经过以上流程,我们就建立了一个TCP server,当ethernetif_input(&DM9000_netif)收到网络数据,并且IP、端口等与我们板子一致时,就会调用回调函数accept_callback对收到的数据进行进一步的解析和处理。