LwIP实例代码分析
2019-07-13 20:47发布
生成海报
//开发环境IAR
int APP_Main(void)
{
#if C_USE_MCU_STM32F4xx
/* Ethernet configuration --------------------------------------*/
Ethernet_Initial();
while(1)
{
Ethernet_Handler();
}
#endif /*end C_USE_MCU_STM32F4xx */
}
/** @param netif: the network interface//网络接口*/
void Ethernet_Initial(void)
{
/* config the Ethernet Reset Pin*///配置以太网复位引脚
Ethernet_Reset_Config();
/* config the Ethernet Link interrupt*///配置以太网链路中断
Ethernet_Config();
/* Initilaize the LwIP stack */ //初始化LwIP堆栈
lwip_init();
//netif_remove(&gnetif);
/* Configure the Network interface */ //配置网络接口
Netif_Config();
/* Notify user about the network interface config *///通知用户有关网络接口配置
User_notification(&gnetif);
/*Connects to the TCP echo server*///连接到TCP echo服务器
tcp_echoclient_connect();
}
void Ethernet_Reset_Config(void)
{
GPIO_Set_Mode(ETHERNET_RST_CTRL_PORT,ETHERNET_RST_CTRL_PIN,GPIO_MODE_OUTPUT_PP, GPIO_NOPULL); //PA4
GPIO_RESET(ETHERNET_RST_CTRL_PORT, ETHERNET_RST_CTRL_PIN);
delay_cycles_ms(1);
GPIO_SET(ETHERNET_RST_CTRL_PORT, ETHERNET_RST_CTRL_PIN);
delay_cycles_ms(10);
}
void Ethernet_Config(void)
{
//congig the ETH_INT 需要配置,断网自动联网机制
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable PX.x to IT mode: Ethernet Link interrupt */
ETHERNET_MII_INT_CLK_ENABLE();
GPIO_InitStructure.Pin = ETHERNET_MII_INT_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStructure.Pull = GPIO_NOPULL ;
HAL_GPIO_Init(ETHERNET_MII_INT_PORT, &GPIO_InitStructure); //PB9
/* Enable EXTI Line interrupt for ETH MII pin */
HAL_NVIC_SetPriority(ETHERNET_MII_INT_IRQ , 0x5, 0x0);
HAL_NVIC_EnableIRQ(ETHERNET_MII_INT_IRQ);
}
void lwip_init(void)
{
stats_init();
mem_init();//将堆归零并初始化start,end和free-free
memp_init();//将memp_memory划分为每个池类型的链接列表。
pbuf_init();//初始化pbuf模块
netif_init();// 网络接口 netif
udp_init();//清除UDP PCB列表。
tcp_init();//清除TCP PCB列表并清除一些内部定时器。注:在这个初始化函数之后,你必须按预先确定的每个周期内调用 tcp_fasttmr() 和 tcp_slowtmr()函数。
sys_timeouts_init();//初始化lwip超时时间限制
}
void Netif_Config(void)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
uint8_t temp_addr[4];
//自动获取IP
if(g_Config.Ethernet.DHCP[0] == 0x01)
{
ipaddr.addr = 0;
netmask.addr = 0;
gw.addr = 0;
}else{
//IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
if(F_Conver_IP_Addr(g_Config.Ethernet.LocalIP, temp_addr))
{
IP4_ADDR(&ipaddr, temp_addr[0], temp_addr[1], temp_addr[2], temp_addr[3]);
}else{//格式错误使用默认参数
IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
}
//IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
if(F_Conver_IP_Addr(g_Config.Ethernet.NetMask, temp_addr))
{
IP4_ADDR(&netmask, temp_addr[0], temp_addr[1], temp_addr[2], temp_addr[3]);
}else{//格式错误使用默认参数
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
}
//IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
if(F_Conver_IP_Addr(g_Config.Ethernet.GateWay, temp_addr))
{
IP4_ADDR(&gw, temp_addr[0], temp_addr[1], temp_addr[2], temp_addr[3]);
}else{//格式错误使用默认参数
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
}
}
/* Add the network interface */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);//注册默认网络接口
if (netif_is_link_up(&gnetif))
{
/* Creates a new DHCP client for this interface on the first call.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.*/
if(g_Config.Ethernet.DHCP[0] == 0x01)
{
dhcp_start(&gnetif);
}
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status */
netif_set_link_callback(&gnetif, ethernetif_update_config);
}
void tcp_echoclient_connect(void)
{
struct ip_addr DestIPaddr;
uint8_t temp_addr[4];
if(echoclient_pcb != NULL)
{//只创建一个TCP Client
tcp_echoclient_connection_close(echoclient_pcb, echoclient_es);
tcp_pcb_remove(&tcp_active_pcbs, echoclient_pcb);
memp_free(MEMP_TCP_PCB, echoclient_pcb);
echoclient_pcb = NULL;
echoclient_es = NULL;
}
echoclient_pcb = tcp_new();
if (echoclient_pcb != NULL)
{//new an echoclient_pcb Success
//IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
if(F_Conver_IP_Addr(g_Config.Net.Server1_IP, temp_addr))
{
IP4_ADDR(&DestIPaddr, temp_addr[0], temp_addr[1], temp_addr[2], temp_addr[3]);
}else{//格式错误使用默认参数
IP4_ADDR(&DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3);
}
/* connect to destination address/port */
//tcp_connect(echoclient_pcb,&DestIPaddr,DEST_PORT,tcp_echoclient_connected);
tcp_connect(echoclient_pcb, &DestIPaddr,(uint16_t)F_Conver_PORT_Addr(g_Config.Net.Server1_Port),
tcp_echoclient_connected);
}
else
{//new an echoclient_pcb fail
/* deallocate the pcb */
memp_free(MEMP_TCP_PCB, echoclient_pcb);
}
}
void Ethernet_Handler(void)
{
/* Check TCP Connect */
Check_TCP_Client_Connect();//检查客户端是否与服务器相连
/* Read a received packet from the Ethernet buffers and send it
to the lwIP for handling */ //从以太网缓冲区读取接收到的数据包并发送到lwIP进行处理
ethernetif_input(&gnetif);
/* Handle timeouts *///超时处理
sys_check_timeouts();
//LwIP定时处理任务(心跳、收发)
LwIP_Periodic_Handle(Ethernet_LocalTime);
}
struct tcp_pcb *Check_TCP_Client_Connect(void)
{//检查客户端是否与服务器相连
struct tcp_pcb *cpcb = NULL;
err_t err;
cpcb = tcp_active_pcbs;
if(cpcb != NULL)//
{//设备连接成功
g_TCPLinkClient_Timeout = 300;
if( g_TCPLinkCheck_Cnt == 0 )
{//超时未收到数据
tcp_echoclient_connect();//重新连接
g_TCPLinkCheck_Cnt = 100;
//g_TCPLinkCheck_Cnt = g_EthTcp_Proto.HeartInterval_Set+60; //断网检测时间
}else{
}
return cpcb;
}else{//连接断开或者未连接
//-----------------------------------------
if((g_TCPLinkConnect_flag == 0) && (g_TCPLinkCheck_Cnt == 0))
{
tcp_echoclient_connect();//重新连接
g_TCPLinkCheck_Cnt = 20;//60;
}else if(g_TCPLinkConnect_flag == 1) {
/* send data */
//通过发送一组数据来侦测remote 是否断开
//sprintf((char*)data, "message %d", (int)message_count);
sprintf((char*)data, "");
err = tcp_write(cpcb, data, strlen((char*)data), TCP_WRITE_FLAG_MORE);//ecoh 数据
if(err == ERR_OK)
{//server 意外断开,而client 没有侦测到,重新连接
g_TCPLinkCheck_Cnt = 5;
g_TCPLinkConnect_flag = 0;
}
else
{//server 意外断开,重新连接
g_TCPLinkCheck_Cnt = 15;
g_TCPLinkConnect_flag = 0;
}
}
return cpcb;
}
}
/**
* @brief This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
当数据包准备好被读取时,应调用此函数
*来自界面。 它使用函数low_level_input()
*应该处理来自网络的实际字节接收
*界面。 然后确定接收分组的类型
*调用适当的输入函数。
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ethernetif_input(struct netif *netif)
{
err_t err;
struct pbuf *p;
/* move received packet into a new pbuf */ / *将收到的数据包移动到新的pbuf * /
p = low_level_input(netif);
/* no packet could be read, silently ignore this *// *无法读取数据包,默默忽略此* /
if (p == NULL) return;
/* entry point to the LwIP stack */ / * LwIP堆栈的入口点* /
err = netif->input(p, netif);
if (err != ERR_OK)//输入错误
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error
"));
pbuf_free(p);
p = NULL;
}
}
/ **
* @brief LwIP定期任务
* @param localtime当前的LocalTime值
* @retval没有
* /
void LwIP_Periodic_Handle(__ IO uint32_t localtime)
{
/ *每250毫秒TCP周期性过程* /
if(localtime - TCPTimer> = TCP_TMR_INTERVAL)
{
TCPTimer = localtime;
tcp_tmr();
}
/ *每5秒ARP周期进程* /
if((localtime - ARPTimer)> = ARP_TMR_INTERVAL)
{
ARPTimer = localtime;
etharp_tmr();
}
if(g_Config.Ethernet.DHCP [0] == 0x01)
{
/ *每500ms精细DHCP定期进程* /
if(localtime - DHCPfineTimer> = DHCP_FINE_TIMER_MSECS)
{
DHCPfineTimer = localtime;
dhcp_fine_tmr();
if((DHCP_state!= DHCP_ADDRESS_ASSIGNED)&&(DHCP_state!= DHCP_TIMEOUT))
{
/ *切换LED1以指示DHCP正在进行的过程* /
// STM_EVAL_LEDToggle(LED1);
/ *进程DHCP状态机* /
LwIP_DHCP_Process_Handle();
}
}
/ * DHCP每60秒进行一次粗略周期过程* /
if(localtime - DHCPcoarseTimer> = DHCP_COARSE_TIMER_MSECS)
{
DHCPcoarseTimer = localtime;
dhcp_coarse_tmr();
}
}
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮