潘 可
(南京國電南自電網(wǎng)自動化有限公司,南京211100)
整體的變電站將由智能化一次設(shè)備和網(wǎng)絡(luò)化二次設(shè)備分層構(gòu)建,建立在IEC61850通信規(guī)范基礎(chǔ)上,能夠?qū)崿F(xiàn)變電站內(nèi)智能電氣設(shè)備間信息共享和互操作的現(xiàn)代化變電站[1-3]。變電站內(nèi)常規(guī)的二次設(shè)備全部基于標(biāo)準(zhǔn)化、模塊化的微處理機(jī)設(shè)計制造,設(shè)備之間的連接全部采用高速的網(wǎng)絡(luò)通信,二次設(shè)備不再出現(xiàn)常規(guī)功能裝置重復(fù)的I/O現(xiàn)場接口,通過網(wǎng)絡(luò)真正實現(xiàn)數(shù)據(jù)共享、資源其享,常規(guī)的功能裝置在這里變成了邏輯的功能模塊[4]。
為了適應(yīng)越來越復(fù)雜的功能需求,二次保護(hù)設(shè)備的硬件以及軟件的復(fù)雜程度被大幅度提升。隨之帶來的后果是無可避免的提升了裝置的故障率。針對于這種狀況研發(fā)了一套調(diào)試軟件。該軟件通過基于TCP的私有通信規(guī)約與裝置進(jìn)行通信。通過該軟件,現(xiàn)在工程服務(wù)人員可以利用友好的圖形化的人機(jī)界面從裝置處得到一系列調(diào)試所需要的信息,并可以控制裝置進(jìn)行各種調(diào)試操作。在該調(diào)試工具的輔助下,當(dāng)裝置出現(xiàn)異常時,工程服務(wù)人員可以將裝置內(nèi)部的數(shù)據(jù)采集后交由技術(shù)支持人員和研發(fā)人員進(jìn)行故障定位,并在分析后提供相應(yīng)的修復(fù)措施??梢岳迷撜{(diào)試工具對裝置進(jìn)行一系列的操作,實現(xiàn)一些工程調(diào)試的工作。
該調(diào)試工具目前工作效果顯著,但由于其通信規(guī)約及功能實現(xiàn)較為復(fù)雜,目前僅由上層應(yīng)用程序?qū)崿F(xiàn)其通信協(xié)議并提供支持?,F(xiàn)場工程服務(wù)人員有時會遇到應(yīng)用程序無法正常啟動,或是裝置反復(fù)復(fù)位的情況。在這種情況下,由于裝置內(nèi)部的應(yīng)用不能正常工作,導(dǎo)致該調(diào)試工具因失去支持而無法工作。為了能夠適應(yīng)這種應(yīng)用情況,筆者在裝置的引導(dǎo)階段即加入該私有通信規(guī)約的支持,從而可以在應(yīng)用程序無法正常啟動的情況下利用現(xiàn)有工具對裝置內(nèi)部的數(shù)據(jù)進(jìn)行采集,并進(jìn)行一系列的控制操作以幫助對裝置的故障進(jìn)行定位。
雖然引導(dǎo)程序U-Boot的功能已經(jīng)演進(jìn)得非常強(qiáng)大,但出于對代碼尺寸以及自身需要的考慮,其對以太網(wǎng)協(xié)議的支持一直較為“簡陋”。其所支持的以太網(wǎng)協(xié)議主要是一些在常規(guī)的操作系統(tǒng)啟動中所需要使用到的以太網(wǎng)協(xié)議,如TFTP、BOOTP、DHCP、DNS等,并且沒有實現(xiàn)對TCP/IP等較復(fù)雜協(xié)議的支持。因此,如果需要在U-Boot中實現(xiàn)基于TCP以太網(wǎng)協(xié)議的通信規(guī)約時,首先需要在U-Boot中實現(xiàn)TCP/IP協(xié)議棧的支持。
因為設(shè)計目標(biāo)的不同,uIP與lwIP之間存在較多的差異。
uIP的設(shè)計目標(biāo)以低系統(tǒng)資源需求為第一目標(biāo),從而犧牲了較多性能作為交換。在uIP中僅有半雙工的以太網(wǎng)數(shù)據(jù)包緩存區(qū),該緩存區(qū)只能緩存一個以太網(wǎng)數(shù)據(jù)包,且在發(fā)送與接收之間共享。由于該單包半雙工的緩存機(jī)制,uIP的應(yīng)答幀總是回復(fù)的很快,甚至快過通信對側(cè)裝置或PC的響應(yīng)能力,需要在代碼和驅(qū)動程序中對該缺陷進(jìn)行彌補(bǔ)。出于減少資源的消耗以及減少對操作系統(tǒng)的依賴,uIP并沒有對每一個連接建立一個線程進(jìn)行,而是在每一次調(diào)用時依次處理系統(tǒng)中現(xiàn)存的連接。另外,由于uIP設(shè)計時的針對應(yīng)用場景為8位和16位單片機(jī),故其代碼針對于8位和16位特別進(jìn)行了優(yōu)化,從而受限于最大16位變量的存儲信息量,在該協(xié)議棧中存在著如時鐘溢出等由最大16位數(shù)據(jù)位寬所帶來的問題。
lwIP需要嵌入式系統(tǒng)能夠提供至少十幾KB的內(nèi)存,其生成的可執(zhí)行代碼最小約為40KB左右。為了能夠使得lwIP適應(yīng)更多的應(yīng)用場景,lwIP在實現(xiàn)時提供了非常靈活的配置功能,可以在實際的應(yīng)用中根據(jù)需求以及嵌入式系統(tǒng)的資源情況進(jìn)行各種功能以及性能上的權(quán)衡。lwIP實現(xiàn)的各種協(xié)議,如DHCP、SNMP等特性可以按照需求進(jìn)行配置是否編譯進(jìn)入最終的實現(xiàn)代碼中,系統(tǒng)中的緩存大小、緩存數(shù)量、內(nèi)存分配方式、最大連接數(shù)量等亦可以進(jìn)行配置。這些配置使得lwIP的可伸縮性比較大,在性能關(guān)鍵的應(yīng)用中,lwIP可以通過使用更多的系統(tǒng)資源提升其性能。lwIP的設(shè)計的針對應(yīng)用場景主要為32位單片機(jī),在其實現(xiàn)中并未針對于8位和16位單片機(jī)進(jìn)行優(yōu)化,存在有大量的32位寬變量以及32位寬變量的數(shù)學(xué)運(yùn)算操作。因此lwIP并不適合運(yùn)行在8位和16位單片機(jī)上。
目前,uIP項目已經(jīng)被合并進(jìn)入Contiki項目(一個小型的嵌入式操作系統(tǒng)),不再進(jìn)行單獨(dú)的開發(fā)。而lwIP目前正在被近30名來自不同地方的開發(fā)者共同進(jìn)行開發(fā)和維護(hù)。筆者所維護(hù)和研發(fā)的二次保護(hù)設(shè)備的處理器為高性能的32位應(yīng)用處理器,裝置內(nèi)部的內(nèi)存配置在16MB以上,而存儲設(shè)備擁有16MB以上的空間,相對于lwIP十多KB的內(nèi)存以及40KB以上的存儲空間的最低需求而言,二次保護(hù)設(shè)備完全能夠支撐lwIP的資源消耗。而且移植的目標(biāo)處理器為32位處理器,lwIP更適合在該種類型的處理器下工作。因此,最終筆者選擇了lwIP作為TCP/IP協(xié)議棧的移植目標(biāo)。
這里的移植為無操作系統(tǒng)支持的移植。lwIP的可移植性非常好,開發(fā)人員只需要向lwIP描述移植目標(biāo)的架構(gòu)、所使用的編譯器信息、以太網(wǎng)數(shù)據(jù)包的發(fā)送和接收的辦法、操作系統(tǒng)的一些同步和通信機(jī)制等即可完成移植工作。針對于無操作系統(tǒng)移植而言,只需要描述前三項即可以完成移植。
lwIP對于描述信息的放置有自己的定義,對于無操作系統(tǒng)支持的移植,lwIP需要實現(xiàn)如下文件的定義:
arch/cc.h:編譯器以及處理器的相關(guān)定義。
arch/perf.h:對于函數(shù)執(zhí)行時間的評估。
lwipopts.h:對lwIP的工作方式、功能選擇等的優(yōu)化配置。
netif/ethernetif.c:實現(xiàn)以太網(wǎng)數(shù)據(jù)包收發(fā)的框架。
編譯器以及處理器相關(guān)的定義文件是lwIP移植的核心頭文件,將被所有的lwIP源代碼所使用,主要包含一些與編譯器和移植的目標(biāo)處理器相關(guān)的定義。具體如下:
①指定目標(biāo)處理器的字節(jié)序是大端(big-endian)還是小端(little-endian)。這將影響到以太網(wǎng)部分的數(shù)據(jù)處理方式。筆者移植的目標(biāo)處理器為PowerPC?架構(gòu),目前在系統(tǒng)中工作于大端模式,故需要定義宏:#define BYTE_ORDER BIG_ENDIAN。
②定義各種不同位寬的變量類型以及內(nèi)存指針的寬度。由于lwIP在設(shè)計時并不知道工作于何種處理器,何種編譯器下,因此所有的變量以及指向內(nèi)存指針等的定義均未使用諸如int或long等通用類型,而是使用u8_t表示無符號8位寬變量,s16_t表示有符號16位寬變量等移植性好的類型。針對目標(biāo)32位PowerPC處理器的類型定義如下略——編者注。
③定義各種不同位長度的變量類型在字符串打印中對應(yīng)的標(biāo)示符。針對于U-Boot而言,該部分的定義略——編者注。
④定義與編譯器相關(guān)的無對齊的結(jié)構(gòu)定義的輔義符。在C編譯器編譯中,默認(rèn)會根據(jù)當(dāng)前目標(biāo)處理器的位寬,自動在結(jié)構(gòu)體中各變量中間或是結(jié)構(gòu)體最后填充無意義的空白,從而使得各變量或整體的結(jié)構(gòu)體與處理器的位寬對齊,比如32位處理器對應(yīng)于4字節(jié)對齊,從而可以提高讀寫效率,或是避免出現(xiàn)讀寫異常。而此處定義的輔義符則是告之編譯器,此處的結(jié)構(gòu)體的內(nèi)部或尾部不允許添加字節(jié)對齊目的的填充。針對于GNU GCC編譯器,該部分的定義略——編者注。
⑤定義lwIP的分析信息輸出和嚴(yán)重錯誤時的行為。針對于U-Boot,該部分的定義略——編者注。
lwIP性能評估相關(guān)的定義主要用于對lwIP的核心部分進(jìn)行性能評估。通過該性能評估,可以針對性地對lwIP進(jìn)行優(yōu)化。該部分在U-Boot內(nèi)的實現(xiàn)略——編者注。
lwIP的配置放置在lwipopts.h中。lwIP給幾乎所有的配置項一個默認(rèn)值,所以僅在實際應(yīng)用需求與lwIP的默認(rèn)工作方式不同時,在該文件中給出對應(yīng)的配置以覆蓋lwIP的默認(rèn)行為即可。lwIP共提供了257個配置項,涉及l(fā)wIP具體需要實現(xiàn)何種協(xié)議、實現(xiàn)何種接口、各具體協(xié)議的工作方式、lwIP可使用內(nèi)存大小、緩存的大小及個數(shù)等。由于配置項定義非常細(xì),使用者可以根據(jù)實際的應(yīng)用需求對lwIP進(jìn)行深度的定制,而并不需要對lwIP的源代碼進(jìn)行任何改動。
首先,于筆者移植的目標(biāo)應(yīng)用場景為無操作系統(tǒng)場景,因為需要定義NO_SYS,從而改變lwIP內(nèi)部很多地方的實現(xiàn)機(jī)制。其次,由于目標(biāo)協(xié)議經(jīng)常需要緩存4MB左右的數(shù)據(jù)包,因此為lwIP分配了8MB內(nèi)存以及512個以太網(wǎng)包的緩存區(qū)。再次,目標(biāo)處理器為32位處理器,需要設(shè)置內(nèi)存對齊為4字節(jié)對應(yīng)。最后,在測試中,由于目標(biāo)處理器的性能較之調(diào)試工具的預(yù)期要差一些,lwIP默認(rèn)的TCP協(xié)議窗口過小,經(jīng)常造成調(diào)試工具認(rèn)為發(fā)送超時進(jìn)行重新發(fā)送,影響了整體的處理性能。這里對TCP的窗口大小以及TCP的最大段大小均進(jìn)行優(yōu)化。
該部分的配置略——編者注。
關(guān)于以太網(wǎng)數(shù)據(jù)包的收發(fā),lwIP在netif/ethernetif.c給出了一個簡單的以太網(wǎng)設(shè)備的驅(qū)動框架,相應(yīng)的移植工具即為將該框架中具體的收發(fā)函數(shù)進(jìn)行實現(xiàn)。由于UBoot的關(guān)系,該部分的代碼實現(xiàn)相對簡單,并可以從UBoot得到很大的幫助。
實現(xiàn)了上述4部分的移植工作,lwIP本身的移植已經(jīng)基本完成。但lwIP本身僅是一個TCP/IP協(xié)議棧,必須要依附于其他可在處理器上運(yùn)行的代碼,如操作系統(tǒng)等,才能夠真正地運(yùn)行并發(fā)揮作用。在筆者的移植中,該可運(yùn)行的代碼為U-Boot的獨(dú)立應(yīng)用程序。
U-Boot以跳轉(zhuǎn)表形式向獨(dú)立應(yīng)用提供一系列的函數(shù)調(diào)用接口,包括有控制臺的輸出、系統(tǒng)復(fù)位控制、系統(tǒng)時間獲取、延時、環(huán)境變量讀寫、系統(tǒng)設(shè)備操作等[16]。
通常,一個基于U-Boot API的獨(dú)立應(yīng)用的結(jié)構(gòu)如圖1所示。
圖1 基于U-Boot API的獨(dú)立應(yīng)用結(jié)構(gòu)
筆者需要基于U-Boot的獨(dú)立應(yīng)用API以及l(fā)wIP協(xié)議棧實現(xiàn)私有的基于TCP協(xié)議。具體的獨(dú)立應(yīng)用的實現(xiàn)結(jié)構(gòu)如圖2所示。
圖2 基于U-Boot API和lwIP的獨(dú)立應(yīng)用結(jié)構(gòu)
要編譯獨(dú)立應(yīng)用,需要首先建立獨(dú)立應(yīng)用的Makefile,該文件讓編譯器了解應(yīng)當(dāng)如何編譯該獨(dú)立應(yīng)用。U-Boot提供了該Makefile的例子,對Makefile作出修改,主要是需要給出U-Boot API兼容層、lwIP協(xié)議棧、私有協(xié)議棧、獨(dú)立應(yīng)用主程序三個部分的代碼的編譯方法的描述。
針對于圖2中的Adapter部分的實現(xiàn),其對應(yīng)于目錄中的crt0.S、glue.c、libgenwrap.c。Main App部分,對應(yīng)于獨(dú)立應(yīng)用目錄中的lwip.c文件Private Protocol部分,對應(yīng)于獨(dú)立應(yīng)用目錄的sgview.c文件。在Makefile中添加的內(nèi)容略——編者注。
圖2中的lwIP、Ethernet Driver的實現(xiàn)代碼被放置在src目錄,部分移植的頭文件放置于根目錄的include目錄中。而由于lwIP本身對頭文件的目錄結(jié)構(gòu)有一定的要求,針對于該要求,對編譯器的頭文件路徑指定作了一定的修改:
將lwIP編譯入該獨(dú)立應(yīng)用,需要在Makefile中將涉及的lwIP的文件對應(yīng)的編譯目標(biāo)添加進(jìn)來。不用擔(dān)心添加過多的文件進(jìn)入這里,如果某個文件所實現(xiàn)的功能在配置中被去掉,比如UDP,在編譯中該部分的代碼會被選擇編譯去掉。在這里添加該文件僅會造成預(yù)編譯的處理時間的延長,并不會實際造成最終生成的代碼的尺寸變大。具體的Makefile修改略——編者注。
U-Boot和lwIP同時定義了名為ip_h(yuǎn)dr的結(jié)構(gòu)體用來解析IP協(xié)議頭部分的信息,因此造成了重復(fù)定義的沖突。通過對lwIP定義的ip_h(yuǎn)dr結(jié)構(gòu)體進(jìn)行重命名,該沖突很容易就被解決了。
其次,lwIP需要在頭文件的路徑下存在string.h以實現(xiàn)一系列的內(nèi)存和字符串相關(guān)的操作。而U-Boot中,該頭文件位于linux子目錄下,造成了頭文件無法找到的問題。針對于這一沖突,將linux子目錄下的string.h文件利用文件系統(tǒng)的鏈接功能直接鏈接至頭文件的根目錄下,解決了該沖突。
至此,lwIP已經(jīng)可以和U-Boot共同編譯。
lwIP針對于最底層的以太網(wǎng)數(shù)據(jù)包的收發(fā)功能,給出了一個基本的以太網(wǎng)數(shù)據(jù)收發(fā)的框架,放置于lwIP源代碼的netif/ethernetif.c中。該部分的實現(xiàn)極大的依賴于U-Boot提供的API接口。
U-Boot的API接口給出了一個最基本的設(shè)備的概念,目前僅支持塊存儲設(shè)備和以太網(wǎng)設(shè)備。在該部分的以太網(wǎng)設(shè)備的實現(xiàn)中,提供了對當(dāng)前以太網(wǎng)設(shè)備數(shù)據(jù)收發(fā)的支持。筆者利用該API實現(xiàn)了lwIP的以太網(wǎng)設(shè)備的驅(qū)動。與具體以太網(wǎng)設(shè)備相關(guān)的代碼均被U-Boot所封裝起來,因此該以太網(wǎng)設(shè)備驅(qū)動較為通用,所有基于U-Boot的lwIP協(xié)議棧均可以使用該驅(qū)動。
利用API_DEV_ENUM接口對U-Boot中所有的設(shè)備進(jìn)行獲取。對獲取到的所有設(shè)備進(jìn)行查找,并得到當(dāng)前的以太網(wǎng)設(shè)備。由于U-Boot本身的實現(xiàn)機(jī)制限制,UBoot在同一時間只能激活一個以太網(wǎng)接口,因此在UBoot中只會存在一個以太網(wǎng)設(shè)備。在得到以太網(wǎng)設(shè)備后,利用API_DEV_OPEN接口打開設(shè)備,利用API_DEV_WRITE接口發(fā)送以太網(wǎng)數(shù)據(jù)包,API_DEV_READ接口從以太網(wǎng)獲取數(shù)據(jù)包。
由于lwIP提供的以太網(wǎng)設(shè)備驅(qū)動框架本身的完成度已經(jīng)很高,只需要在其中填入具體的數(shù)據(jù)收發(fā)等基本功能,該以太網(wǎng)設(shè)備驅(qū)動即可以正常工作。所有需要修改的部分在該框架中均以偽代碼的形式給出。限于篇幅,這里僅給出幾個需要修改的地方的描述:根據(jù)應(yīng)用的需要對以太網(wǎng)設(shè)備的結(jié)構(gòu)體定義進(jìn)行修改;在lower_level_init中實現(xiàn)對lwIP的if設(shè)備的MAC地址的初始化;在lower_level_output中利用U-Boot的API實現(xiàn)實際的以太網(wǎng)設(shè)備的數(shù)據(jù)包的發(fā)送;在lower_level_input中利用U-Boot的API實現(xiàn)實際的以太網(wǎng)設(shè)備的數(shù)據(jù)包的接收;在ethernetif_init中利用U-Boot的API查找當(dāng)前的以太網(wǎng)設(shè)備并打開,供后續(xù)使用。
在獨(dú)立應(yīng)用中實現(xiàn)了公司的私有協(xié)議后,所有的移植及開發(fā)工作全部完成。該獨(dú)立應(yīng)用需要在U-Boot啟動完成后,由U-Boot加載進(jìn)入內(nèi)存并執(zhí)行。該功能的實現(xiàn)需要借由U-Boot的腳本功能實現(xiàn)。
U-Boot提供了環(huán)境變量執(zhí)行功能。將一系列的指令以“;”為分割,順序記錄在一個環(huán)境變量中,形成一個簡單的腳本。利用U-Boot控制臺的run指令,可以自動將將該環(huán)境變量中所有的指令順序輸入U-Boot的控制臺實現(xiàn)自動化的工作。針對于筆者的移植工作,U-Boot從板載NOR Flash中讀取該獨(dú)立應(yīng)用程序的可執(zhí)行文件至內(nèi)存中,并跳轉(zhuǎn)運(yùn)行。該環(huán)境變量設(shè)置為:setenv lwip′cp.b$lwipaddr 40000$lwipsize;go 40000;′。
編者注:本文為期刊縮略版,全文見本刊網(wǎng)站www.mesnet.com.cn。
[1] 肖世杰.構(gòu)建中國智能電網(wǎng)技術(shù)思考[J] .電力系統(tǒng)自動化,2009,33(9):1-4.
[2] ???,薛峰,楊衛(wèi)東等.中國智能電網(wǎng)基本特征及其技術(shù)進(jìn)展評述[J] .電力系統(tǒng)自動化,2009,33(17):10-15.
[3] 吳在軍,胡敏強(qiáng).基于IEC 61850標(biāo)準(zhǔn)的變電站自動化系統(tǒng)研究[J] .電網(wǎng)技術(shù),2003,27(10):61-65.
[4] 高翔,張沛超.數(shù)字化變電站的主要特征和關(guān)鍵技術(shù)[J] .電網(wǎng)技術(shù),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,F(xiàn)ull 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,F(xiàn)ebruary 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.