LWIP移植

理论

image

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, &ethernetif_init, &ethernet_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;

image

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, &ethernetif_init, &ethernet_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对收到的数据进行进一步的解析和处理。

五、TFTP传输

posted @ 2022-03-31 16:42  solonj  阅读(704)  评论(0编辑  收藏  举报