一、lwip網卡接口ethernetif.c
ethernetif.c是lwip的網卡接口,在該接口中處理網卡的數據接收和發送,rt-thread在該接口文件中抽象了一個eth_device,管理網絡數據的收發和向內核的netdev_list添加netdev。
二、網絡設備eth_device
eth_device是rt-thread實現的ethernetif。
struct eth_device
{
/* inherit from rt_device /
struct rt_device parent;
/ network interface for lwip */
struct netif netif;
struct rt_semaphore tx_ack;
rt_uint16_t flags;
rt_uint8_t link_changed;
rt_uint8_t link_status;
/ eth device interface /
struct pbuf (*eth_rx)(rt_device_t dev);
rt_err_t (eth_tx)(rt_device_t dev, struct pbuf p);
};
netif:lwip的網絡接口。
eth_rx:底層數據接收接口。
eth_tx:底層數據發送接口。
三、網絡設備數據的接收和發送
網絡設備的接收和發送通過eth_device的eth_rx和eth_tx完成。在系統初始化時內核調用eth_system_device_init創建erx和etx兩個線程,用于處理接收和發送。
3.1 數據接收
當erx線程起來后,等待eth_rx_thread_mb,當網卡準備好或者改變網卡狀態時,往下執行,進入while(1)處理網卡接收,調用網卡注冊的eth_rx接收網卡數據,并傳遞給協議棧上層。
static void eth_rx_thread_entry(void* parameter)
{
struct eth_device* device;
while (1)
{
if (rt_mb_recv(e_rx_thread_mb, (rt_ubase_t*)&device, RT_WAITING_FOREVER) == RT_EOK)
{
struct pbuf p;
/ check link status /
if (device->link_changed)
{
int status;
rt_uint32_t level;
level = rt_hw_interrupt_disable();
status = device->link_status;
device->link_changed = 0x00;
rt_hw_interrupt_enable(level);
if (status)
netifapi_netif_set_link_up(device->netif);
else
netifapi_netif_set_link_down(device->netif);
}
/ receive all of buffer /
while (1)
{
if(device->eth_rx == RT_NULL) break;
p = device->eth_rx(&(device->parent));
if (p != RT_NULL)
{
/ notify to upper layer */
if( device->netif->input(p, device->netif) != ERR_OK )
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input errorn"));
pbuf_free(p);
p = NULL;
}
}
else break;
}
}
else
{
LWIP_ASSERT("Should not happen!n",0);
}
}
}
3.2 數據發送
當協議棧需要發送數據時,調用netif的linkoutput接口,在linkoutput中,將數據封裝成消息發送給etx線程,最終通過eth_device的eth_tx接口將數據發送出去。
static void eth_tx_thread_entry(void* parameter)
{
struct eth_tx_msg* msg;
while (1)
{
if (rt_mb_recv(e_tx_thread_mb, (rt_ubase_t*)&msg, RT_WAITING_FOREVER) == RT_EOK)
{
struct eth_device* enetif;
RT_ASSERT(msg->netif != RT_NULL);
RT_ASSERT(msg->buf != RT_NULL);
enetif = (struct eth_device*)msg->netif->state;
if (enetif != RT_NULL)
{
/* call driver's interface /
if (enetif->eth_tx(&(enetif->parent), msg->buf) != RT_EOK)
{
/ transmit eth packet failed /
}
}
/ send ACK */
rt_sem_release(&(enetif->tx_ack));
}
}
}
四、wlan設備數據的接收和發送
wlan設備的數據接收和發送是通過rt_wlan_prot完成的,rt_wlan_prot是對不同協議簇的抽象,在rt_wlan_set_mode啟動wlan設備時,最終會調用rt_wlan_prot_attach將lwip協議簇掛載到wlan設備,在掛載過程中,會根據協議簇的名稱匹配注冊的rt_wlan_prot,并調用rt_wlan_prot的register將wlan設備注冊到內核。
4.1 數據接收
在網卡的接收中斷中,調用rt_wlan_dev_transfer_prot將網卡設備接收的數據傳遞給上層處理。
rt_err_t rt_wlan_dev_transfer_prot(struct rt_wlan_device *wlan, void *buff, int len)
{
struct rt_wlan_prot *prot = wlan->prot;
if (prot != RT_NULL)
{
return prot->ops->prot_recv(wlan, buff, len);
}
return -RT_ERROR;
}
注冊到rt_wlan_prot的接收函數是rt_wlan_lwip_protocol_recv,在rt_wlan_lwip_protocol_recv中,通過lwip_prot_des獲取eth_device(netif在eth_device_init_with_flag中被注冊到eth_device),接著便可使用其中的netif的input將數據交給上層。
static rt_err_t rt_wlan_lwip_protocol_recv(struct rt_wlan_device *wlan, void *buff, int len)
{
struct eth_device *eth_dev = &((struct lwip_prot_des *)wlan->prot)->eth;//eth在rt_wlan_lwip_protocol_register中注冊
struct pbuf *p = RT_NULL;
//...省略
{
p = buff;
if ((eth_dev->netif->input(p, eth_dev->netif)) != ERR_OK)
{
return -RT_ERROR;
}
return RT_EOK;
}
//...省略
}
4.2 數據發送
當協議棧需要發送數據時,會調用rt_wlan_prot_transfer_dev將數據傳遞給wlan設備,在rt_wlan_prot_transfer_dev中,會調用wlan設備的發送接口將數據發送出去。
4.3 以w601舉例
w601的wlan驅動在driver文件夾下的drv_wifi.c。
4.3.1 數據接收
在內核需要初始化wlan的時候,調用drv_wlan_init,在tls_ethernet_data_rx_callback函數中注冊wm_ethernetif_input到wifi接收中斷,在wm_ethernetif_input中調用rt_wlan_dev_transfer_prot將接收的數據傳給協議棧上層。
4.3.2 數據發送
在drv_wifi.c中,將drv_wlan_send函數注冊到發送接口,在協議棧需要發送數據時,通過rt_wlan_prot_transfer_dev調用這個接口完成數據的發送。
static const struct rt_wlan_dev_ops ops =
{
//...省略
.wlan_recv = drv_wlan_recv,
.wlan_send = drv_wlan_send,/ 向內核注冊的發送接口 /
};
-
接收機
+關注
關注
8文章
1180瀏覽量
53412 -
WLAN技術
+關注
關注
0文章
23瀏覽量
9271 -
LwIP協議
+關注
關注
0文章
11瀏覽量
8903 -
串口中斷
+關注
關注
0文章
64瀏覽量
13862 -
RT-Thread
+關注
關注
31文章
1274瀏覽量
39940
發布評論請先 登錄
相關推薦
評論