楊輝
中北大學(xué)電子與計(jì)算機(jī)科學(xué)技術(shù)學(xué)院多核實(shí)驗(yàn)室 太原 030051
基于uC/OS-II的LwIP網(wǎng)絡(luò)協(xié)議移植
楊輝
中北大學(xué)電子與計(jì)算機(jī)科學(xué)技術(shù)學(xué)院多核實(shí)驗(yàn)室 太原 030051
LwIP是一款優(yōu)秀的開(kāi)源TCP/IP協(xié)議棧,應(yīng)用各個(gè)嵌入式應(yīng)用,用于簡(jiǎn)化接入互聯(lián)網(wǎng)設(shè)備的網(wǎng)絡(luò)協(xié)議棧應(yīng)用開(kāi)發(fā)。uC/OS-II是一款優(yōu)秀的開(kāi)源嵌入式實(shí)時(shí)操作系統(tǒng)。本文深入講解了LwIP移植到uC/OS-II的方法,并進(jìn)行相應(yīng)測(cè)試。
LwIP移值;uC/OS-II;AT91SAM7
隨著互聯(lián)網(wǎng)的普及度越來(lái)越高,能夠接入互聯(lián)網(wǎng)的設(shè)備越來(lái)越多,互聯(lián)網(wǎng)已經(jīng)成為人們工作生活中不可或缺的通信渠道之一。在嵌入式操作系統(tǒng)中加入網(wǎng)絡(luò)協(xié)議棧是一項(xiàng)重要的研究?jī)?nèi)容。uC/OS-II是一款優(yōu)秀的、開(kāi)源的嵌入式實(shí)時(shí)操作系統(tǒng)內(nèi)核,實(shí)現(xiàn)了實(shí)時(shí)任務(wù)調(diào)度、任務(wù)間通信及其管理系統(tǒng)內(nèi)存,但是缺少文件系統(tǒng),圖形界面,以及網(wǎng)絡(luò)協(xié)議的支持。本文介紹了uC/OS-II嵌入式實(shí)時(shí)操作系統(tǒng)中加入LwIP網(wǎng)絡(luò)協(xié)議棧的方法,從而使得嵌入式系統(tǒng)能夠接入互聯(lián)網(wǎng)。
uC/OS II 是Labrosse設(shè)計(jì)的一款完整的、開(kāi)源的搶占式實(shí)時(shí)多任務(wù)嵌入式操作系統(tǒng)內(nèi)核。代碼絕大部分采用標(biāo)準(zhǔn)C語(yǔ)言編寫(xiě),小部分底層硬件代碼采用匯編語(yǔ)言編寫(xiě),因此具有良好的移植性及裁剪性,從8位到64位處理器,已經(jīng)成功移植到超過(guò)40種不同構(gòu)架的微處理上。uC/OS II已經(jīng)廣泛應(yīng)用在諸多領(lǐng)域,如手機(jī)、工控設(shè)備、醫(yī)療設(shè)備,甚至是飛行器等要求極高的應(yīng)用。
uC/OS II是第一個(gè)支持ARM Cortex內(nèi)核的嵌入式操作系統(tǒng),其大部分代碼是用標(biāo)準(zhǔn)C語(yǔ)言編寫(xiě),這樣對(duì)于移植工作很方便。在移植時(shí),只需要用匯編語(yǔ)言及C語(yǔ)言編寫(xiě)一些與處理器相關(guān)的代碼即可。uC/OS II代碼設(shè)計(jì)的結(jié)構(gòu)清晰,層次分明,代碼總體來(lái)說(shuō)分為三個(gè)層次:處理器無(wú)關(guān)代碼層,處理器相關(guān)代碼層,以及應(yīng)用程序相關(guān)代碼層。
LwIP是由瑞士計(jì)算機(jī)科學(xué)院Adam Dunkels等人開(kāi)發(fā)的專(zhuān)門(mén)用于嵌入式系統(tǒng)的開(kāi)源TCP/IP協(xié)議棧[1]。LwIP可以移植到操作系統(tǒng)上,也可以在無(wú)操作系統(tǒng)的情況下獨(dú)立運(yùn)行。LwIP是一種輕型的TCP/IP協(xié)議棧,在實(shí)現(xiàn)TCP/IP基本功能的基礎(chǔ)上,減少自身代碼容量,并且在運(yùn)行時(shí),減少對(duì)RAM的占用。LwIP需要20KB的RAM空間和40KB左右的ROM空間即可運(yùn)行,這樣使得 LwIP協(xié)議棧適合在低端嵌入式系統(tǒng)中使用。
LwIP協(xié)議棧的特性如下:
支持多網(wǎng)絡(luò)接口下的 IP轉(zhuǎn)發(fā);
支持 ICMP協(xié)議;
包括實(shí)驗(yàn)性擴(kuò)展的 UDP(用戶(hù)數(shù)據(jù)報(bào)協(xié)議);
包括阻塞控制、RTT估算、快速恢復(fù)和快速轉(zhuǎn)發(fā)的 TCP(傳輸控制協(xié)議);
提供專(zhuān)門(mén)的內(nèi)部回調(diào)接口(Raw API),用于提高應(yīng)用程序性能;
可選擇的 Berkeley 接口 API(多線程情況下)。
本文所用到的嵌入式操作系統(tǒng)uC/OS-II版本為V2.5.4.,本文在移植時(shí)所用到的開(kāi)發(fā)環(huán)境為RVMDK4.0。首先我們獲取LwIP代碼,只需到LwIP的官方網(wǎng)站下載。將代碼文件添加至所建立的工程中即可。LwIP協(xié)議棧在最初設(shè)計(jì)時(shí)就考慮到移植問(wèn)題,將硬件接口代碼、OS接口代碼、編譯器相關(guān)代碼獨(dú)立分開(kāi)出來(lái),放在/src/arch目錄下面。在LwIP移植到uC/OS-II中時(shí),只需修改這個(gè)目錄下的文件即可移植后的功能框圖如圖1所示。下面是具體的移植過(guò)程。
圖1 系統(tǒng)示意圖
在/src/arch/include/arch目錄下面,是關(guān)于CPU及編譯器相關(guān)的頭文件。這些文件里面定義了數(shù)據(jù)長(zhǎng)度,字高低位順序等,這些應(yīng)該與用戶(hù)實(shí)現(xiàn)uC/OS-II時(shí)定義的數(shù)據(jù)長(zhǎng)度一致。我們這里主要涉及cc.h,cpu.h,perf.h這三個(gè)文件。下面定義為:
#define BYTE_ORDER LITTLE_ENDIAN //小端存儲(chǔ)類(lèi)型
typedef unsigned char u8_t; //關(guān)于數(shù)據(jù)類(lèi)型長(zhǎng)度的定義,下同
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
注意,C語(yǔ)言的結(jié)構(gòu)體是4字節(jié)對(duì)齊的,但是在處理數(shù)據(jù)包時(shí),則是根據(jù)結(jié)構(gòu)體中不同數(shù)據(jù)長(zhǎng)度來(lái)讀取相應(yīng)數(shù)據(jù)的,所以在定義struct的時(shí)候要加上_packed關(guān)鍵字。在LwIP代碼中,結(jié)構(gòu)體中定義了幾個(gè)PACKED_FIELED_xxx宏,缺省的情況下是空的,可以在移植的時(shí)候添加不同的編譯器所對(duì)應(yīng)的_packed關(guān)鍵字。下面是對(duì)應(yīng)的宏定義代碼:
#define PACK_STRUCT_FIELD(x)x __attribute__((packed))
#define PACK_STRUCT_STRUCT__attribute__((packed))
sys_arch.[ch]文件中的內(nèi)容是與移植的操作系統(tǒng)相關(guān)的一些結(jié)構(gòu)和函數(shù),下面是相應(yīng)的移植內(nèi)容。
3.2.1 sys_sem_t信號(hào)量
LwIP在操作系統(tǒng)中需要使用相應(yīng)的信號(hào)量進(jìn)行通信,所以在sys_arch中,應(yīng)實(shí)現(xiàn)相關(guān)的信號(hào)量結(jié)構(gòu)體和處理函數(shù):
sys_ sem _send signal() //發(fā)送信號(hào)量
sys_ arch_sem _req() //請(qǐng)求信號(hào)量
在uC/OS-II中已經(jīng)實(shí)現(xiàn)了OS_EVENT信號(hào)量的各種操作,在功能上同LwIP上的幾個(gè)函數(shù)的目標(biāo)功能是完全一樣的,因此,只要把uC/OS-II的函數(shù)進(jìn)行重新封裝成上面的函數(shù)即可。
3.2.2 sys_thread_new 創(chuàng)建新線程LwIP可以是單線程運(yùn)行,即只有一個(gè)tcpip線程(tcpip_thread),負(fù)責(zé)處理所有的 tcp/ucp連接,各種網(wǎng)絡(luò)程序都通過(guò)tcpip線程與網(wǎng)絡(luò)交互。但LwIP也可以多線程運(yùn)行,以提高效率,降低編程復(fù)雜度。這時(shí)需要用戶(hù)實(shí)現(xiàn)創(chuàng)建新線程的函數(shù):
void sys_thread_new(void (* thread)(void *arg),void *arg);
在uC/OS-II中,沒(méi)有線程的概念,只有任務(wù)。它已經(jīng)提供了創(chuàng)建新任務(wù)的系統(tǒng)API調(diào)用OSTaskCreate,因此,只要把OSTaskCreate封裝一下,就可以實(shí)現(xiàn)sys_thread_new。需要注意的是,LwIP中的thread并沒(méi)有uC/OS-II中優(yōu)先級(jí)的概念,實(shí)現(xiàn)時(shí),要由用戶(hù)事先為 LwIP中創(chuàng)建的線程分配好優(yōu)先級(jí)。
3.2.3 sys_mbox_t 消息
LwIP要使用消息隊(duì)列來(lái)進(jìn)行緩沖、傳遞數(shù)據(jù)報(bào)文,因此,要在sys_arch中實(shí)現(xiàn)消息隊(duì)列結(jié)構(gòu)sys_mbox_t及其相應(yīng)的發(fā)送和獲取操作函數(shù):
sys_mbox_post() //向隊(duì)列發(fā)送消息
sys_arch_mbox_fetch() //從隊(duì)列中獲取消息
uC/OS-II同樣實(shí)現(xiàn)了消息隊(duì)列結(jié)構(gòu)OSQ及其操作,但是,uC/OS-II 沒(méi)有對(duì)消息隊(duì)列中的消息進(jìn)行管理,因此不能直接使用,必須在uC/OS-II的基礎(chǔ)上進(jìn)行重新實(shí)現(xiàn)。為了實(shí)現(xiàn)對(duì)消息的管理,我們定義一個(gè)結(jié)構(gòu)體積。
包括OS_EVENT類(lèi)型的指針(pQ)和隊(duì)列內(nèi)的消息兩部分。對(duì)隊(duì)列本身的管理利用uC/OS-II自己的 OSQ操作完成,然后使用uC/OS-II中的內(nèi)存管理模塊實(shí)現(xiàn)對(duì)消息的創(chuàng)建、使用、刪除回收,兩部分綜合起來(lái)形成了 LwIP的消息隊(duì)列功能。
LwIP可以有多個(gè)相應(yīng)的網(wǎng)絡(luò)接口,每個(gè)網(wǎng)絡(luò)接口都有一個(gè)對(duì)應(yīng)的 struct netif結(jié)構(gòu), 此netif包含了其屬性、收發(fā)函數(shù)等。LwIP中的代碼通過(guò)調(diào)用netif的函數(shù)netif->input()及netif->output()進(jìn)行以太網(wǎng)的包收發(fā)操作。我們?cè)隍?qū)動(dòng)程序中主要做的移植工作是實(shí)現(xiàn)對(duì)應(yīng)網(wǎng)絡(luò)接口的初始化、接收、發(fā)送及對(duì)應(yīng)中斷處理函數(shù)。網(wǎng)絡(luò)驅(qū)動(dòng)程序工作在IP協(xié)議模型的網(wǎng)絡(luò)接口層
LwIP協(xié)議棧需要實(shí)現(xiàn)8個(gè)外部函數(shù),這些函數(shù)都是與CPU和用戶(hù)編譯器相關(guān)的,需要用戶(hù)去實(shí)現(xiàn)。
在完成上面的移植工作后,就可以對(duì)移植代碼進(jìn)行應(yīng)用程序測(cè)試。測(cè)試工作主要為初始化LwIP協(xié)議棧,并創(chuàng)建TCP或者UDP等任務(wù)進(jìn)行測(cè)試。
正確編譯運(yùn)行后,用ping ip地址命令可以得到ICMP reply 響應(yīng)。用 telnet ip地址 7(登錄 7號(hào)端口)命令可以看到echo server 的回顯效果。說(shuō)明 ARP、ICMP、IP、TCP協(xié)議都已正確運(yùn)行,說(shuō)明網(wǎng)絡(luò)協(xié)議已經(jīng)成功移植??傊?,LwIP作為的開(kāi)源TCP/IP協(xié)議棧,在帶網(wǎng)絡(luò)嵌入式設(shè)備開(kāi)發(fā)中可以比較廣泛的的使用。
[1] 張翠, 鄧志良.LwIP協(xié)議棧在uC/OS-Ⅱ上的移植和應(yīng)用.微計(jì)算機(jī)信息.2010,23(2):43-45
[2] 胡俐蕊.基于LwIP的uC/OS-Ⅱ網(wǎng)絡(luò)應(yīng)用程序設(shè)計(jì)方法.計(jì)算機(jī)應(yīng)用與軟件.2010,19(1):145-148
10.3969/j.issn.1001-8972.2011.07.054