潘 可
(南京國電南自電網自動化有限公司,南京211100)
整體的變電站將由智能化一次設備和網絡化二次設備分層構建,建立在IEC61850通信規范基礎上,能夠實現變電站內智能電氣設備間信息共享和互操作的現代化變電站[1-3]。變電站內常規的二次設備全部基于標準化、模塊化的微處理機設計制造,設備之間的連接全部采用高速的網絡通信,二次設備不再出現常規功能裝置重復的I/O現場接口,通過網絡真正實現數據共享、資源其享,常規的功能裝置在這里變成了邏輯的功能模塊[4]。
為了適應越來越復雜的功能需求,二次保護設備的硬件以及軟件的復雜程度被大幅度提升。隨之帶來的后果是無可避免的提升了裝置的故障率。針對于這種狀況研發了一套調試軟件。該軟件通過基于TCP的私有通信規約與裝置進行通信。通過該軟件,現在工程服務人員可以利用友好的圖形化的人機界面從裝置處得到一系列調試所需要的信息,并可以控制裝置進行各種調試操作。在該調試工具的輔助下,當裝置出現異常時,工程服務人員可以將裝置內部的數據采集后交由技術支持人員和研發人員進行故障定位,并在分析后提供相應的修復措施。可以利用該調試工具對裝置進行一系列的操作,實現一些工程調試的工作。
該調試工具目前工作效果顯著,但由于其通信規約及功能實現較為復雜,目前僅由上層應用程序實現其通信協議并提供支持。現場工程服務人員有時會遇到應用程序無法正常啟動,或是裝置反復復位的情況。在這種情況下,由于裝置內部的應用不能正常工作,導致該調試工具因失去支持而無法工作。為了能夠適應這種應用情況,筆者在裝置的引導階段即加入該私有通信規約的支持,從而可以在應用程序無法正常啟動的情況下利用現有工具對裝置內部的數據進行采集,并進行一系列的控制操作以幫助對裝置的故障進行定位。
雖然引導程序U-Boot的功能已經演進得非常強大,但出于對代碼尺寸以及自身需要的考慮,其對以太網協議的支持一直較為“簡陋”。其所支持的以太網協議主要是一些在常規的操作系統啟動中所需要使用到的以太網協議,如TFTP、BOOTP、DHCP、DNS等,并且沒有實現對TCP/IP等較復雜協議的支持。因此,如果需要在U-Boot中實現基于TCP以太網協議的通信規約時,首先需要在U-Boot中實現TCP/IP協議棧的支持。
因為設計目標的不同,uIP與lwIP之間存在較多的差異。
uIP的設計目標以低系統資源需求為第一目標,從而犧牲了較多性能作為交換。在uIP中僅有半雙工的以太網數據包緩存區,該緩存區只能緩存一個以太網數據包,且在發送與接收之間共享。由于該單包半雙工的緩存機制,uIP的應答幀總是回復的很快,甚至快過通信對側裝置或PC的響應能力,需要在代碼和驅動程序中對該缺陷進行彌補。出于減少資源的消耗以及減少對操作系統的依賴,uIP并沒有對每一個連接建立一個線程進行,而是在每一次調用時依次處理系統中現存的連接。另外,由于uIP設計時的針對應用場景為8位和16位單片機,故其代碼針對于8位和16位特別進行了優化,從而受限于最大16位變量的存儲信息量,在該協議棧中存在著如時鐘溢出等由最大16位數據位寬所帶來的問題。
lwIP需要嵌入式系統能夠提供至少十幾KB的內存,其生成的可執行代碼最小約為40KB左右。為了能夠使得lwIP適應更多的應用場景,lwIP在實現時提供了非常靈活的配置功能,可以在實際的應用中根據需求以及嵌入式系統的資源情況進行各種功能以及性能上的權衡。lwIP實現的各種協議,如DHCP、SNMP等特性可以按照需求進行配置是否編譯進入最終的實現代碼中,系統中的緩存大小、緩存數量、內存分配方式、最大連接數量等亦可以進行配置。這些配置使得lwIP的可伸縮性比較大,在性能關鍵的應用中,lwIP可以通過使用更多的系統資源提升其性能。lwIP的設計的針對應用場景主要為32位單片機,在其實現中并未針對于8位和16位單片機進行優化,存在有大量的32位寬變量以及32位寬變量的數學運算操作。因此lwIP并不適合運行在8位和16位單片機上。
目前,uIP項目已經被合并進入Contiki項目(一個小型的嵌入式操作系統),不再進行單獨的開發。而lwIP目前正在被近30名來自不同地方的開發者共同進行開發和維護。筆者所維護和研發的二次保護設備的處理器為高性能的32位應用處理器,裝置內部的內存配置在16MB以上,而存儲設備擁有16MB以上的空間,相對于lwIP十多KB的內存以及40KB以上的存儲空間的最低需求而言,二次保護設備完全能夠支撐lwIP的資源消耗。而且移植的目標處理器為32位處理器,lwIP更適合在該種類型的處理器下工作。因此,最終筆者選擇了lwIP作為TCP/IP協議棧的移植目標。
這里的移植為無操作系統支持的移植。lwIP的可移植性非常好,開發人員只需要向lwIP描述移植目標的架構、所使用的編譯器信息、以太網數據包的發送和接收的辦法、操作系統的一些同步和通信機制等即可完成移植工作。針對于無操作系統移植而言,只需要描述前三項即可以完成移植。
lwIP對于描述信息的放置有自己的定義,對于無操作系統支持的移植,lwIP需要實現如下文件的定義:
arch/cc.h:編譯器以及處理器的相關定義。
arch/perf.h:對于函數執行時間的評估。
lwipopts.h:對lwIP的工作方式、功能選擇等的優化配置。
netif/ethernetif.c:實現以太網數據包收發的框架。
編譯器以及處理器相關的定義文件是lwIP移植的核心頭文件,將被所有的lwIP源代碼所使用,主要包含一些與編譯器和移植的目標處理器相關的定義。具體如下:
①指定目標處理器的字節序是大端(big-endian)還是小端(little-endian)。這將影響到以太網部分的數據處理方式。筆者移植的目標處理器為PowerPC?架構,目前在系統中工作于大端模式,故需要定義宏:#define BYTE_ORDER BIG_ENDIAN。
②定義各種不同位寬的變量類型以及內存指針的寬度。由于lwIP在設計時并不知道工作于何種處理器,何種編譯器下,因此所有的變量以及指向內存指針等的定義均未使用諸如int或long等通用類型,而是使用u8_t表示無符號8位寬變量,s16_t表示有符號16位寬變量等移植性好的類型。針對目標32位PowerPC處理器的類型定義如下略——編者注。
③定義各種不同位長度的變量類型在字符串打印中對應的標示符。針對于U-Boot而言,該部分的定義略——編者注。
④定義與編譯器相關的無對齊的結構定義的輔義符。在C編譯器編譯中,默認會根據當前目標處理器的位寬,自動在結構體中各變量中間或是結構體最后填充無意義的空白,從而使得各變量或整體的結構體與處理器的位寬對齊,比如32位處理器對應于4字節對齊,從而可以提高讀寫效率,或是避免出現讀寫異常。而此處定義的輔義符則是告之編譯器,此處的結構體的內部或尾部不允許添加字節對齊目的的填充。針對于GNU GCC編譯器,該部分的定義略——編者注。
⑤定義lwIP的分析信息輸出和嚴重錯誤時的行為。針對于U-Boot,該部分的定義略——編者注。
lwIP性能評估相關的定義主要用于對lwIP的核心部分進行性能評估。通過該性能評估,可以針對性地對lwIP進行優化。該部分在U-Boot內的實現略——編者注。
lwIP的配置放置在lwipopts.h中。lwIP給幾乎所有的配置項一個默認值,所以僅在實際應用需求與lwIP的默認工作方式不同時,在該文件中給出對應的配置以覆蓋lwIP的默認行為即可。lwIP共提供了257個配置項,涉及lwIP具體需要實現何種協議、實現何種接口、各具體協議的工作方式、lwIP可使用內存大小、緩存的大小及個數等。由于配置項定義非常細,使用者可以根據實際的應用需求對lwIP進行深度的定制,而并不需要對lwIP的源代碼進行任何改動。
首先,于筆者移植的目標應用場景為無操作系統場景,因為需要定義NO_SYS,從而改變lwIP內部很多地方的實現機制。其次,由于目標協議經常需要緩存4MB左右的數據包,因此為lwIP分配了8MB內存以及512個以太網包的緩存區。再次,目標處理器為32位處理器,需要設置內存對齊為4字節對應。最后,在測試中,由于目標處理器的性能較之調試工具的預期要差一些,lwIP默認的TCP協議窗口過小,經常造成調試工具認為發送超時進行重新發送,影響了整體的處理性能。這里對TCP的窗口大小以及TCP的最大段大小均進行優化。
該部分的配置略——編者注。
關于以太網數據包的收發,lwIP在netif/ethernetif.c給出了一個簡單的以太網設備的驅動框架,相應的移植工具即為將該框架中具體的收發函數進行實現。由于UBoot的關系,該部分的代碼實現相對簡單,并可以從UBoot得到很大的幫助。
實現了上述4部分的移植工作,lwIP本身的移植已經基本完成。但lwIP本身僅是一個TCP/IP協議棧,必須要依附于其他可在處理器上運行的代碼,如操作系統等,才能夠真正地運行并發揮作用。在筆者的移植中,該可運行的代碼為U-Boot的獨立應用程序。
U-Boot以跳轉表形式向獨立應用提供一系列的函數調用接口,包括有控制臺的輸出、系統復位控制、系統時間獲取、延時、環境變量讀寫、系統設備操作等[16]。
通常,一個基于U-Boot API的獨立應用的結構如圖1所示。

圖1 基于U-Boot API的獨立應用結構
筆者需要基于U-Boot的獨立應用API以及lwIP協議棧實現私有的基于TCP協議。具體的獨立應用的實現結構如圖2所示。

圖2 基于U-Boot API和lwIP的獨立應用結構
要編譯獨立應用,需要首先建立獨立應用的Makefile,該文件讓編譯器了解應當如何編譯該獨立應用。U-Boot提供了該Makefile的例子,對Makefile作出修改,主要是需要給出U-Boot API兼容層、lwIP協議棧、私有協議棧、獨立應用主程序三個部分的代碼的編譯方法的描述。
針對于圖2中的Adapter部分的實現,其對應于目錄中的crt0.S、glue.c、libgenwrap.c。Main App部分,對應于獨立應用目錄中的lwip.c文件Private Protocol部分,對應于獨立應用目錄的sgview.c文件。在Makefile中添加的內容略——編者注。
圖2中的lwIP、Ethernet Driver的實現代碼被放置在src目錄,部分移植的頭文件放置于根目錄的include目錄中。而由于lwIP本身對頭文件的目錄結構有一定的要求,針對于該要求,對編譯器的頭文件路徑指定作了一定的修改:

將lwIP編譯入該獨立應用,需要在Makefile中將涉及的lwIP的文件對應的編譯目標添加進來。不用擔心添加過多的文件進入這里,如果某個文件所實現的功能在配置中被去掉,比如UDP,在編譯中該部分的代碼會被選擇編譯去掉。在這里添加該文件僅會造成預編譯的處理時間的延長,并不會實際造成最終生成的代碼的尺寸變大。具體的Makefile修改略——編者注。
U-Boot和lwIP同時定義了名為ip_hdr的結構體用來解析IP協議頭部分的信息,因此造成了重復定義的沖突。通過對lwIP定義的ip_hdr結構體進行重命名,該沖突很容易就被解決了。
其次,lwIP需要在頭文件的路徑下存在string.h以實現一系列的內存和字符串相關的操作。而U-Boot中,該頭文件位于linux子目錄下,造成了頭文件無法找到的問題。針對于這一沖突,將linux子目錄下的string.h文件利用文件系統的鏈接功能直接鏈接至頭文件的根目錄下,解決了該沖突。
至此,lwIP已經可以和U-Boot共同編譯。
lwIP針對于最底層的以太網數據包的收發功能,給出了一個基本的以太網數據收發的框架,放置于lwIP源代碼的netif/ethernetif.c中。該部分的實現極大的依賴于U-Boot提供的API接口。
U-Boot的API接口給出了一個最基本的設備的概念,目前僅支持塊存儲設備和以太網設備。在該部分的以太網設備的實現中,提供了對當前以太網設備數據收發的支持。筆者利用該API實現了lwIP的以太網設備的驅動。與具體以太網設備相關的代碼均被U-Boot所封裝起來,因此該以太網設備驅動較為通用,所有基于U-Boot的lwIP協議棧均可以使用該驅動。
利用API_DEV_ENUM接口對U-Boot中所有的設備進行獲取。對獲取到的所有設備進行查找,并得到當前的以太網設備。由于U-Boot本身的實現機制限制,UBoot在同一時間只能激活一個以太網接口,因此在UBoot中只會存在一個以太網設備。在得到以太網設備后,利用API_DEV_OPEN接口打開設備,利用API_DEV_WRITE接口發送以太網數據包,API_DEV_READ接口從以太網獲取數據包。
由于lwIP提供的以太網設備驅動框架本身的完成度已經很高,只需要在其中填入具體的數據收發等基本功能,該以太網設備驅動即可以正常工作。所有需要修改的部分在該框架中均以偽代碼的形式給出。限于篇幅,這里僅給出幾個需要修改的地方的描述:根據應用的需要對以太網設備的結構體定義進行修改;在lower_level_init中實現對lwIP的if設備的MAC地址的初始化;在lower_level_output中利用U-Boot的API實現實際的以太網設備的數據包的發送;在lower_level_input中利用U-Boot的API實現實際的以太網設備的數據包的接收;在ethernetif_init中利用U-Boot的API查找當前的以太網設備并打開,供后續使用。
在獨立應用中實現了公司的私有協議后,所有的移植及開發工作全部完成。該獨立應用需要在U-Boot啟動完成后,由U-Boot加載進入內存并執行。該功能的實現需要借由U-Boot的腳本功能實現。
U-Boot提供了環境變量執行功能。將一系列的指令以“;”為分割,順序記錄在一個環境變量中,形成一個簡單的腳本。利用U-Boot控制臺的run指令,可以自動將將該環境變量中所有的指令順序輸入U-Boot的控制臺實現自動化的工作。針對于筆者的移植工作,U-Boot從板載NOR Flash中讀取該獨立應用程序的可執行文件至內存中,并跳轉運行。該環境變量設置為:setenv lwip′cp.b$lwipaddr 40000$lwipsize;go 40000;′。
編者注:本文為期刊縮略版,全文見本刊網站www.mesnet.com.cn。
[1] 肖世杰.構建中國智能電網技術思考[J] .電力系統自動化,2009,33(9):1-4.
[2] 常康,薛峰,楊衛東等.中國智能電網基本特征及其技術進展評述[J] .電力系統自動化,2009,33(17):10-15.
[3] 吳在軍,胡敏強.基于IEC 61850標準的變電站自動化系統研究[J] .電網技術,2003,27(10):61-65.
[4] 高翔,張沛超.數字化變電站的主要特征和關鍵技術[J] .電網技術,2006,30(23):67-71,87.
[5] Booting[EB/OL] .[2013-08-19] .http://en.wikipedia.org/wiki/Bootloader#Boot_loader.
[6] The Universal Boot Loader("Das U-Boot")[EB/OL] .[2013-08-19] .http://www.denx.de/wiki/publish/U-Bootdoc/U-Bootdoc.pdf
[7] Embedded PowerPC Linux Boot Project[EB/OL] .[2013-08-19] .http://ppcboot.sourceforge.net/
[8] Git-U-Boot[EB/OL] .[2013-08-19] .git.denx.de.git/shortlog.
[9] Adam Dunkels,Full TCP/IP for 8Bit Archtectures[C]//Proceedings of the First ACM/Usenix International Conference on Mobile Systems,Applications and Services,San Francisco,May 2003.
[10] Adam Dunkels,Design &Implementation of the LWIP TCP/IP Stack[M] .Sweden:Swedish Institute of Computer Science,February 2001.
[11] uIP(micro IP)[EB/OL] .http://en.wikipedia.org/wiki/UIP_(micro_IP)[2013-08-19] .
[12] lwIP[EB/OL] .[2013-08-19] .http://en.wikipedia.org/wiki/LwIP.
[13] lwIP Wiki[EB/OL] .[2013-08-19] .http://lwip.wikia.com/wiki/LwIP_Wiki.
[14] Licensing U-Boot[EB/OL] .[2013-08-19] .
[15] GNU General Public License v2.0-GNU Project-Free Software Foundation(FSF)[EB/OL] .[2013-08-19] .http://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html.
[16] UBootStandalone[EB/OL] .[2013-08-19] http://www.denx.de/wiki/view/DULG/UBootStandalone.