💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
在无操作性移植的时候,我们的网卡收发数据就是单纯的收发数据,ethernetif\_input()函数就是处理接收网卡数据的,但是使用了操作系统的话,我们一般将接收数据独立成为一个网卡接收线程,这样子在收到数据的时候才去处理数据,然后递交给内核线程,所以我们只需要稍作修改即可,将函数转换成线程就行了,并且在初始化网卡的时候创建网卡接收线程。当然,我们也能将发送函数独立成一个线程,我们暂时没有必要去处理它,此处只创建一个网卡接收线程,具体见代码清单 8‑4。 ``` 1 void ethernetif_input(void *pParams) 2 { 3 struct netif *netif; 4 struct pbuf *p = NULL; 5 netif = (struct netif*) pParams; 6 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); 7 8 while (1) 9 { 10 if (xSemaphoreTake( s_xSemaphore, portMAX_DELAY ) == pdTRUE) 11 { 12 /* move received packet into a new pbuf */ 13 taskENTER_CRITICAL(); 14 p = low_level_input(netif); 15 taskEXIT_CRITICAL(); 16 /* points to packet payload, which starts with an Ethernet header */ 17 if (p != NULL) 18 { 19 taskENTER_CRITICAL(); 20 /* full packet send to tcpip_thread to process */ 21 if (netif->input(p, netif) != ERR_OK) 22 { 23 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); 24 pbuf_free(p); 25 p = NULL; 26 } 27 taskEXIT_CRITICAL(); 28 } 29 } 30 } 31 } ``` 在网卡接收线程中需要留意一下以下内容:网卡接收线程是需要通过信号量机制去接收数据的,一般来说我们都是使用中断的方式去获取网络数据包,当产生中断的时候,我们一般不会在中断中处理数据,而是告诉对应的线程去处理,也就是我们的网卡接收线程去处理数据,那么就会通过信号量进行同步,当网卡接收到了数据就会产生中断释放一个信号量,然后线程从阻塞中恢复,去获取网卡的数据并且向上层递交。 当然我们还需要在中断中对网卡底层进行编写,具体见代码清单 8‑5 ``` 1 void ETH_IRQHandler(void) 2 { 3 uint32_t ulReturn; 4 /* 进入临界段,临界段可以嵌套 */ 5 ulReturn = taskENTER_CRITICAL_FROM_ISR(); 6 7 HAL_ETH_IRQHandler(&heth); 8 9 /* 退出临界段 */ 10 taskEXIT_CRITICAL_FROM_ISR( ulReturn ); 11 } 12 13 14 extern xSemaphoreHandle s_xSemaphore; 15 void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) 16 { 17 // LED2_TOGGLE; 18 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; 19 xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken ); 20 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 21 } ``` 此外我们还需要在网卡初始化的时候创建网卡接收线程与对应的信号量,网卡初始化函数还是low\_level\_init()函数,并且初始化的其他信息都未修改,只是添加了线程与信号量的创建,具体见代码清单 8‑6加粗部分。 ``` 1 static void low_level_init(struct netif *netif) 2 { 3 HAL_StatusTypeDef hal_eth_init_status; 4 5 //初始化bsp—eth 6 hal_eth_init_status = Bsp_Eth_Init(); 7 8 if (hal_eth_init_status == HAL_OK) 9 { 10 /* Set netif link flag */ 11 netif->flags |= NETIF_FLAG_LINK_UP; 12 } 13 14 #if LWIP_ARP || LWIP_ETHERNET 15 16 /* set MAC hardware address length */ 17 netif->hwaddr_len = ETH_HWADDR_LEN; 18 19 /* set MAC hardware address */ 20 netif->hwaddr[0] = heth.Init.MACAddr[0]; 21 netif->hwaddr[1] = heth.Init.MACAddr[1]; 22 netif->hwaddr[2] = heth.Init.MACAddr[2]; 23 netif->hwaddr[3] = heth.Init.MACAddr[3]; 24 netif->hwaddr[4] = heth.Init.MACAddr[4]; 25 netif->hwaddr[5] = heth.Init.MACAddr[5]; 26 27 /* maximum transfer unit */ 28 netif->mtu = NETIF_MTU; 29 30 /* Accept broadcast address and ARP traffic */ 31 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ 32 #if LWIP_ARP 33 netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; 34 #else 35 netif->flags |= NETIF_FLAG_BROADCAST; 36 #endif /* LWIP_ARP */ 37 38 /* USER CODE BEGIN PHY_PRE_CONFIG */ 39 40 s_xSemaphore = xSemaphoreCreateCounting(40,0); 41 42 /* create the task that handles the ETH_MAC */ 43 sys_thread_new("ETHIN", 44 ethernetif_input, /* 任务入口函数 */ 45 netif, /* 任务入口函数参数 */ 46 NETIF_IN_TASK_STACK_SIZE,/* 任务栈大小 */ 47 NETIF_IN_TASK_PRIORITY); /* 任务的优先级 */ 48 49 #endif /* LWIP_ARP || LWIP_ETHERNET */ 50 51 /* Enable MAC and DMA transmission and reception */ 52 HAL_ETH_Start(&heth); 53 } ```