rtthread工业使用_基于RTThread 的LwIP使用讲解
在RT-Thread 1.1.x系列中默認使用lwIP 1.4.0作為TCP/IP協議棧,同時為了保持原有驅動的兼容性,
對lwIP 1.4初始移植做了調整,在驅動編寫,初始化順序上可以完整兼容lwIP 1.3.2的風格。
lwip 1.4 遷移指南
一、lwip,netif架構
+-----------------------+
|? ?driver interface? ? |
|? ?? ?? ?? ?? ?? ?? ???|
|? ?struct eth_device? ?|
| +-eth_rx_ready()? ?? ?|
+---->+-link_up()? ?? ?|? ? |
|? ?| +-link_down()? ? |? ? |
|? ?+------------------|----+
+-------------+ |? ?+------------------|----+? ? +-------------------+
| driver? ?? ?| |? ?|? ?ethernetif? ???|? ? |? ? | lwip 1.4? ?? ?? ? |
|? ?? ?? ?? ? | |? ?|? ?? ?? ?? ?? ?? ?V? ? |? ? |? ?? ?? ?? ?? ?? ? |
| isr() --------+? ?|? ?rx_thread? ?? ?? ???|? ? | tcpip_thread? ?? ?|
| rx()??input??------------>tcpip_input? ?? ? |
| tx()??output
|? ?? ?? ?? ? |? ???|? ?? ?? ?? ?? ?? ?? ???|? ? |? ?? ?? ?? ?? ?? ? |
+-------------+? ???+-----------------------+? ? +-------------------+
lwip 1.4的驅動架構和1.32相比并沒有太大的變化,不過細節方面有所改動,各個模塊之間功能劃分更明確:
1、驅動部分
驅動的輸入只有一個入口,就是isr。isr接收到各種中斷以后做相應的處理,包括接收到rx包,鏈路層通斷
消息等,然后調用ethernetif.h頭文件中的各個函數來通知netif層。
驅動的另一個主要需要實現的部分是rx和tx這兩個回調函數,它是提供給ethernetif來進行鏈路層數據收發使用。
rx函數一般會被netif中的rx線程調用,然后將數據包轉發給tcpip層。
tx函數有可能被netif中的tx線程調用(lwip1.32的實現)或者直接被tcpip的enetif_linkoutput調用,來進行鏈路層
發送數據包使用。
2、ethernetif
ethernetif輸入部分包含一個線程,用來接收rx消息,以及其他鏈路層狀態消息,然后反饋給lwip。
輸出部分由上層lwip調入netif→output函數,這里有可能作為消息傳入tx線程(1.32實現)或者直接送給驅動的tx()。
3、LwIP1.4
lwip1.4 初始化流程和1.32的流程方面有所區別,具體參見下一節。
二、lwip,netif架構 初始化流程
初始化的過程包括兩個獨立的部分:驅動初始化、lwip和netif的初始化。
例如在mini2440平臺上只需要分別執行連個函數即可:
rt_hw_dm9000_init();
lwip_enetif_init();
驅動的初始化可以放在啟動第一個進程之前進行,而第二個函數需要在線程上下文中執行。
1、驅動初始化部分
a.創建eth_device的繼承結構。
b.初始化eth_device中除了netif以外的所有域(netif結構會在ethernetif初始化結束以后填充)。
c.調用rt_device_register注冊結構體。
d.注冊中斷函數。
完成這幾件事情以后可能驅動部分就已經開始工作了,但是這時候lwip部分還完全沒有初始化。
所以驅動部分還不能把消息傳遞給lwip/netif層。在這里因為eth_device的netif指針仍沒有填充,
而這個指針是驅動通向netif的橋梁,所以雖然此時驅動在工作,例如可能接收中斷已經打開了,
但是所有的包都會被丟棄,而不會傳遞到lwip去處理。
2、lwip和netif的初始化部分
lwip初始化需要遵循一定的流程,主函數是lwip_enetif_init。
在RTOS的環境下需要調用tcpip_init來初始化多線程的tcpip環境,初始化tcpip的內容就放在這個
函數的參數中tcpip_init_done_callback。之所以需要把這些函數都放在這個callback函數中的緣故
是很多函數都必須在tcpip線程中執行,以避免并發問題,例如netif_set_up之類的函數。
在tcpip_init_done_callback中初始化了ethernetif并注冊到lwip中,以上這一部分一般來說應該是應
用相關的,這里只是提供一個公共的參考流程。
在初始化的最后,enetif_init函數中先將netif→linkoutput設置成了設備驅動對應的函數,在這一點
的時候實現了從netif到驅動的連接,然后又設置了dev→netif指針,于是從驅動到netif的連接也完成
了,到此為止lwip初始化完成。 有幾點需要注意的:
a.在啟動ethernetif的時候如果是啟用了DHCP則應該調用dhcp_start,
如果啟用AUTOIP則是autoip_start,否則調用netif_set_up。
b.包括像netif_set_up,dhcp_start之類的函數,凡是在tcpip線程以外調用的時候都需要以msg發送
給tcpip線程執行的形式來執行以避免并行問題。例如,可以使用netifapi_dhcp_start替代dhcp_start,
用netifapi_netif_set_up替代netif_set_up。
但是在tcpip線程中不能調用這類函數,否則肯定會進入信號堵塞。
三、從lwip1.32升級
從lwip1.32升級到lwip1.4主要需要修改的地方有下面三個:
1、驅動修改
以dm9000的驅動為例,需要將eth_device_ready函數換成eth_rx_ready,這主要是一個語義上的改動。
同樣,驅動還可以通過調用eth_linkup,eth_linkdown之類的函數來通知netif相應的狀態消息。
-? ?? ???eth_device_ready(&(dm9000_device.parent));
+? ?? ???eth_rx_ready(&(dm9000_device.parent));
在驅動初始化函數中,原先的eth_device_init需要刪除,然后添加初始化和注冊設備驅動函數。
-? ?? ???eth_device_init(&(dm9000_device.parent), "e0");
+? ?? ???dm9000_device.parent.parent.type = RT_Device_Class_NetIf;
+? ?? ???rt_device_register(&(dm9000_device.parent.parent), "eth0", RT_DEVICE_FLAG_RDWR);
最后,添加一個函數get_eth_dev,這個函數是在ethernetif最后被lwip初始化的時候獲得設備指
針用的。對ethernetif來說必須有一個驅動與之對應,在邏輯上netif并不是驅動的一部分,而是
注冊在lwip中的一部分,它必須由lwip來初始化,由lwip來使用。
+struct eth_device * get_eth_dev(void)
+{
+? ?? ???return (struct eth_device *)&dm9000_device;
+}
2、啟動調用
目前的啟動調用流程邏輯很清楚,按順序調用下面兩個函數即可。
rt_hw_dm9000_init();??//初始化設備驅動
lwip_enetif_init();? ?//初始化lwip,并間接初始化ethnetif,最后完成ethernetif和驅動的連接。
而原先的
lwip_sys_init(void);
eth_system_device_init();
rt_hw_dm9000_init();
只有第三個函數保留,但功能上會有變化,其余兩個函數不再使用。
四、lwip netconn 函數修改
lwip1.4修改了netconn調用接口,所有函數統一返回錯誤值,例如: lwip1.32中recv函數是
struct netbuf *
netconn_recv(struct netconn *conn)
到了lwip1.4中改為
err_t
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
原先以返回值得到的netbuf改成通過參數返回,其他函數大同小異,可以此類推。
總結
以上是生活随笔為你收集整理的rtthread工业使用_基于RTThread 的LwIP使用讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP中销售发票清单功能的局限性
- 下一篇: 电路PCB制板原理图基本流程