1、5.4.4 EMACInit()網卡初始化工作的實際完成者.405.4.5 ethernetif_input()實現接收線程.475.4.6 low_level_input()得到一整幀資料.495.4.7 GetInputPacketLen()獲得幀長.505.4.8 EMACReadPacket()複製,從接收緩衝區到pbuf.535.4.9 EMACSendPacket()發送一幀資料.555.4.10 編譯ethernetif.c及lib_emac.c.566 ping結束LwIP的移植.576.1 編譯、鏈結整個工程.576.2 ping測試.59後記.62本文將指導讀者一步步完成L
2、wIP在ADS1.2開發環境下的移植工作,包括底層驅動的編寫。本文使用的硬體平臺是AT91SAM7X256+RTL8201BL(PHY),至於軟體平臺,讀者從本文標題即可看出。我們使用 uC/OS-II 作為底層作業系統,而LwIP的移植亦將主要圍繞uC/OS-II展開。好了,不再多說,開始吧1下載LwIP很簡單,到LwIP的官方網站即可:http:/savannah.nongnu.org/projects/lwip/。如果你不想看看其他內容(可能對你會很重要),就只是想得到源碼,好的,直接到這個地址下載:/download.savannah.nongnu.org/releases/lwip/
3、。目前官方發佈的最新版本是1.1.1,找到 lwip-1.1.1.zip,然後下載、解壓縮,第一項工作完成。2建立一個最基本的工程要想完成移植工作,我們必須要有一個包含uC/OS-II的工程才行,這一步我們就是要建立這個工程。工程建立完畢後,編譯鏈結沒有問題,那麼,第二項工作也完成了。關於如何建立一個包含uC/OS-II的ADS工程的問題,不在本文描述範圍之內,這裏不做講述。隨本筆記一同發佈的源碼文檔中LwIPPortingTest_2檔夾下包含了這個最基本工程的源碼,讀者可以直接使用。我的基本工程建立的路徑是D:workLwIPPortingTest,下文將以相對路徑進行講述,不再提供絕對路
4、徑。3把LwIP加入工程首先,在src文件夾下,建立LwIP文件夾,即:srcLwIP;然後將下載的LwIP源碼文件中api、core、include、netif文件複製到srcLwIP文件夾下,如下圖所示:圖3.1然後,用ADS打開工程檔,按照LwIP源碼檔的實際存放路徑建立LwIP的工程結構,如下圖所示:圖3.2這裏需要特別說明的是,源碼中的IP V6、SLIP及PPP部分我們沒有添加進來,主要是考慮我及大多數讀者的網路還是V4,而SLIP、PPP暫時不在我的考慮範圍之內。另外,在移植層面V6也和V4相差不多,這裏就不再講解這部分內容了。現在基礎工程結構建立完畢,可以把LwIP源碼添加進來
5、了。這一步很容易,按照檔存放路徑,將源碼檔添加到相應的工程結構下即可。源碼添加完成後的工程參見所附源碼檔的LwIPPortingTest_3文件夾。4編寫作業系統類比層相關代碼LwIP的作者為作業系統類比層提供了較為詳細的說明,檔案名為sys_arch.txt,在LwIP的doc文件夾下。我們的編寫工作根據這個說明進行。4.1 作業系統類比層移植說明中文翻譯事先聲明,之所以筆者要翻譯該文檔,主要是筆者在撰寫這篇筆記時亦沒有通讀該文檔。筆者先前使用的模擬層源碼是楊曄大俠的。為了真正弄懂LwIP,筆者決定自己重新實現LwIP的移植,本筆記是跟隨移植同步進行的,因此,翻譯的文檔也放在了這篇筆記中,使
6、讀者能夠真正瞭解筆者的移植歷程。另外再說一句,這個文檔是為LwIP 0.6+版編寫,筆者搜遍了整個LwIP官方網站,沒有發現比這更新的,筆者只好認為作業系統類比層在0.6+之後沒有任何改動,如果有誰發現了更新的,一定通知筆者,先謝謝了。好的,言歸正傳,下面就是譯文:LwIP 0.6+ sys_arch介面作者:Adam Dunkels作業系統類比層(sys_arch)存在的目的主要是為了方便LwIP的移植,它在底層作業系統和LwIP之間提供了一個介面。這樣,我們在移植LwIP到一個新的目標系統時,只需修改這個介面即可。不過,不依賴底層作業系統的支援也可以實現這個介面。sys_arch需要為Lw
7、IP提供信號量(semaphores)和郵箱(mailboxes)兩種進程間通訊方式(IPC)。如果想獲得LwIP的完整功能,sys_arch還必須支持多線程。當然,對於僅需要基本功能的用戶來說,可以不去實現多線程。LwIP以前的版本還要求sys_arch實現計時器調度,不過,從LwIP0.5開始,這一需求在更高一層實現。除了上文所述的sys_arch原始檔案需要實現的功能外,LwIP還要求用戶提供幾個頭檔,這幾個頭檔包含LwIP使用的巨集定義。下文將詳細講述sys_arch及頭文件的實現。信號量即可以是計數信號量,也可以是二值信號量LwIP都可以正常工作。郵箱用於消息傳遞,用戶即可以將其實現
8、為一個佇列,允許多條消息投遞到這個郵箱,也可以每次只允許投遞一個消息。這兩種方式LwIP都可以正常運作。不過,前者更加有效。需要用戶特別注意的是投遞到郵箱中的消息只能是一個指標。在sys_arch.h檔中,我們指定資料類型“sys_sem_t”表示信號量,“sys_mbox_t”表示郵箱。至於sys_sem_t和sys_mbox_t如何表示這兩種不同類型,LwIP沒有任何限制。以下函數必須在sys_arch中實現:- void sys_init(void)初始化sys_arch層。- sys_sem_t sys_sem_new(u8_t count)建立並返回一個新的信號量。參數count指定
9、信號量的初始狀態。- void sys_sem_free(sys_sem_t sem)釋放信號量。- void sys_sem_signal(sys_sem_t sem)發送一個信號。- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)等待指定的信號並阻塞線程。timeout參數為0,線程會一直被阻塞至收到指定的信號;非0,則線程僅被阻塞至指定的timeout時間(單位為毫秒)。在timeout參數值非0的情況下,返回值為等待指定的信號所消耗的毫秒數。如果在指定的時間內並沒有收到信號,返回值為SYS_ARCH_TIMEOUT。如果線程不
10、必再等待這個信號(也就是說,已經收到信號),返回值也可以為0。注意,LwIP實現了一個名稱與之相似的函數來調用這個函數,sys_sem_wait(),注意區別。- sys_mbox_t sys_mbox_new(void)建立一個空的郵箱。- void sys_mbox_free(sys_mbox_t mbox)釋放一個郵箱。如果釋放時郵箱中還有消息,它表明LwIP中存在一個編程錯誤,應該通知開發者(原文如此,這句話很費解。個人理解的意思是:當執行 sys_mbox_free()這個函數時,按道理郵箱中不應該再存在任何消息,如果用戶使用LwIP時發現郵箱中還存在消息,說明LwIP的開發者存在一
11、個編程錯誤,不能把郵箱中的消息全部取出並處理掉。遇到這種情況,用戶應該告訴LwIP的作者,糾正這個bug,譯注)。- void sys_mbox_post(sys_mbox_t mbox, void *msg)投遞消息“msg”到指定的郵箱“mbox”。- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void *msg, u32_t timeout)阻塞線程直至郵箱收到至少一條消息。最長阻塞時間由timeout參數指定(與sys_arch_sem_wait()函數類似)。msg是一個結果參數,用來保存郵箱中的消息指標(即*msg=ptr),它的值由這個
12、函數設置。“msg”參數有可能為空,這表明當前這條消息應該被丟棄。返回值與sys_arch_sem_wait()函數相同:等待的毫秒數或者SYS_ARCH_TIMEOUT如果時間溢出的話。LwIP實現的函數中,有一個名稱與之相似的sys_mbox_fetch(),注意區分。- struct sys_timeouts*sys_arch_timeouts(void)返回一個指向當前線程使用的sys_timeouts結構的指標。LwIP中,每一個線程都有一個timeouts鏈表,這個鏈表由sys_timeout結構組成,sys_timeouts結構則保存了指向這個鏈表的指針。這個函數由LwIP的超時
13、調度程式調用,並且不能返回一個空(NULL)值。單線程sys_arch實現中,這個函數只需簡單返回一個指標即可。這個指標指向保存在sys_arch模塊中的sys_timeouts總體變數。如果底層作業系統支援多線程並且LwIP中需要這樣的功能,那麼,下面的函數必須實現:- sys_thread_t sys_thread_new(void(*thread)(void *arg), void *arg, int prio)啟動一個由函數指標thread指定的新線程,arg將作為參數傳遞給thread()函數,prio指定這個新線程的優先順序。返回值為這個新線程的ID,ID和優先順序由底層作業系統決
14、定。- sys_prot_t sys_arch_protect(void)這是一個可選函數,它負責完成臨界區域保護並返回先前的保護狀態。該函數只有在小的臨界區域需要保護時才會被調用。基於ISR驅動的嵌入式系統可以通過禁止中斷來實現這個函數。基於任務的系統可以通過互斥量或禁止任務來實現這個函數。該函數應該支援來自於同一個任務或中斷的遞迴調用。換句話說,當該區域已經被保護,sys_arch_protect()函數依然能被調用。這時,函數的返回值會通知調用者該區域已經被保護。如果你的移植正在支援一個作業系統,sys_arch_protect()函數僅僅是一個需要。- void sys_arch_un
15、protect(sys_prot_t pval)該函數同樣是一個可選函數。它的功能就是恢復受保護區域的先前保護狀態,先前是受到保護還是沒有受到保護由參數pval指定。它與sys_arch_protect()函數配套使用,詳細資訊參看sys_arch_protect()函數。該函數的說明是按照譯者個人理解的意思翻譯,原文講述不是很清楚,如有錯誤,歡迎批評指正,譯注。-OS支援的類比層需要添加的頭檔說明-cc.h 與硬體平臺及編譯器相關的環境變數及資料類型聲明檔(一些或許應該移到sys_arch.h文件)。LwIP使用的資料類型定義u8_t, s8_t, u16_t,s16_t,u32_t,s32
16、_t,mem_ptr_t。與編譯器相關的LwIP結構體封裝巨集:PACK_STRUCT_FIELD(x)PACK_STRUCT_STRUCTPACK_STRUCT_BEGINPACK_STRUCT_END與平臺相關的調試輸出:LWIP_PLATFORM_DIAG(X) - 非故障,輸出一條提示資訊。LWIP_PLATFORM_ASSERT(x)- 故障,輸出一條故障資訊並放棄執行。“輕便的(lightweight)”同步機制:SYS_ARCH_DECL_PROTECT(x) - 聲明一個保護狀態變數。SYS_ARCH_PROTECT(x) - 進入保護模式。SYS_ARCH_UNPROTECT
17、(x) - 脫離保護模式。如果編譯器不提供memset()函數,這個檔必須包含它的定義,或者包含(include)一個定義它的文件。這個檔要麼包含一個本地系統(system-local)提供的頭檔這個檔定義了標準的*nix錯誤編碼,要麼增加一條巨集定義語句:#define LWIP_PROVIDE_ERRNO,這將使得lwip/arch.h頭檔來定義這些編碼。這些編碼被用於LwIP的各個部分。- perf.h 定義了性能測量使用的巨集,由LwIP調用,可以將其定義為一個空的宏。PERF_START - 開始測量。PERF_STOP(x) - 結束測量並記錄結果。- sys_arch.h sys_arch.c的頭文件。定義Arch(即整個移植所依賴的作業系統平臺,譯注)需要的資料類型:sys_sem_t,sys_mbox_t,sys_thread_t,以及可選類型:sys_prot_t。sys_mbox_t和sys_sem_t變數的NULL值定義:SYS_MBOX_NULL NULLSYS_SEM_NULL NULL4.2 編寫作業系統類比層4.1節已經明白的講述了如何實現sys_arch介面,我們按照這個說明完成即
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1