LwIP例項程式碼分析
阿新 • • 發佈:2018-11-04
//開發環境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\n")); 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(); } }