劉鐵華 尹俊勛
【摘要】RFID中間件是RFID系統的神經中樞。在深入研究EPCglobal后,文章借鑒EPCglobal的中間件標準ALE,提出了一種嵌入式RFID中間件設計的具體思路,以及較為詳細的數據結構設計和程序流程。該中間件結構緊湊,可以直接運行在讀寫器上,既可以為運行在讀寫器上的應用程序服務,也可以通過網絡為運行在PC上的應用程序服務。
【關鍵詞】RFID 中間件 EPC ALE 嵌入式
1 前言
傳統RFID中間件運行在PC服務器上,同時管理多臺讀寫器。讀寫器讀到的標簽,要先通過網絡返回給運行中間件的服務器,中間件對返回的標簽數據進行整理,把結果返回給客戶端,客戶端根據結果做進一步的處理。隨著RFID應用領域的擴展,這種體系結構已經不能滿足一些應用的需要,這些應用要求對讀寫器的結果進行快速、實時的處理,例如基于RFID的自動化管理、控制系統。同時,手持式讀寫器的應用越來越廣泛,卻無法使用運行在PC機上的中間件。對此,本文設計了一種嵌入式RFID中間件,該中間件遵循EPCglobal的中間件標準ALE,直接運行在讀寫器上。
2 EPCglobal ALE標準
EPC(Electronic Product Code,產品電子代碼)是美國麻省理工學院的自動識別中心(Auto-ID中心)提出的,其主要思想是為每一個參加互聯網的產品分配一個電子標簽,該標簽存儲了一個唯一的EPC碼。當產品通過閱讀器時,利用RFID技術來讀取數據,得到對應的EPC碼,再通過與互聯網相連的服務器完成相應的EPC碼的解析。EPC系統主要由EPC編碼、EPC標簽、EPC讀寫器、EPC中間件、PML(物理標記語言)服務器和ONS(對象名解析服務)服務器組成。系統協議主要由RFID通信協議、應用事件管理(ALE,Application Level Event)協議等組成。

圖1 ALE在EPCglobal體系結構中的位置
ALE是EPCglobal的中間件標準,是閱讀器模塊和客戶應用程序之間的接口協議。該協議定義了客戶可以如何過濾和整合來自讀寫器的EPC標簽,并面向不同的企業應用程序和閱讀器定義了統一的接口。這樣即使后端應用程序增加或由其他軟件取代,或者RFID讀寫器的種類有所改變,其它部件都不需要做修改。ALE的處理過程是:接收來自一個或多個數據源的EPC標簽碼;根據企業應用程序要求以一定的時間間隔整合數據,過濾重復和不感興趣的EPC碼;根據企業應用程序要求以不同的形式打包發送報告。
3 嵌入式中間件的設計
本文所述系統硬件平臺:ARM9內核、32Mbyte內存、16Mbyte Flash和10M網口。軟件系統平臺:嵌入式Linux系統。
3.1 嵌入式中間件的工作原理
依照ALE,發送到中間件的事件請求都表示為Event Circle Specification(ECSpec),它包含請求的工作方式和報表的產生方式,能夠同時處理多個事件請求。從中間件返回的數據都表示為ECReports(Event Circle Reports)。ECSpec和ECReports是兩個標準XML片斷實例,以一種結構化和統一的方式在EPC信息的讀取、存儲和傳輸過程中對其進行描述,使得對標簽信息的理解、存儲和傳送更容易。
中間件支持兩種異步模式:訂閱方式(subscribe)和輪詢方式(poll)。異步模式中客戶端可以訂閱一個事件,當事件發生時,ALE會異步地將數據交付給客戶端。中間件同時提供了一個同步模式,即立即返回模式(immediate)。
ECSpec有四種狀態:Undefined(未定義),Unrequested(未請求),Requested(請求),Active(活動)。

ECSpec的狀態轉 移圖
當ECSpec請求到達中間件時,ECSpec進入“Unrequested”狀態;ECSpec進入“Requested”狀態后,會等待中間件的處理;當ECSpec進入“Active”狀態,中間件根據ECSpec中指定的開始觸發條件,在條件滿足的情況下收集來自讀寫器的原始EPC數據,當ECSpec中指定的停止觸發條件滿足時返回查詢報告ECReports。
3.2 中間件的系統結構

圖3 中間件的系統結構
整個嵌入式中間件作為一個獨立的進程運行,以消息隊列作為與其它進程通信的接口。中間件的消息接收隊列與消息發送隊列,是兩個不同的消息隊列。考慮到中間件進程可能同時為多個應用進程提供服務,中間件使用固定的消息接收隊列,所有應用進程共享該消息隊列向中間件進程發消息。中間件通過某種機制與每個應用進程協商,從而獲得一個只被中間件進程與該應用進程使用的消息隊列,中間件通過該消息隊列向該應用進程發消息。換言之,中間件的消息接收隊列是固定的、唯一的,而中間件的消息發送隊列有多條,每條對應一個應用進程。這種機制,將使中間件能并行地為上層應用提供服務,大大提高中間件的效能。
中間件包含五個模塊:消息接收模塊,XML數據解析模塊,命令處理模塊,XML數據構造模塊,消息發送模塊。
其中,XML數據解析模塊基于Linux上開源的XML解析器Expat。Expat是一款基于事件、非驗證的XML解析器,快速且輕巧,適合用在系統資源相對較小的嵌入式系統。Expat被編譯成動態的鏈接庫,要實現本文所需的功能,只要用到它的五個函數:XML_ParserCreate(),XML_SetElementHandler(),XML_SetCharacterDataHandler(),XML_ParserFree(),XML_Parser()。
4 嵌入式RFID中間件的軟件實現
4.1 消息隊列設計
消息隊列是中間件與讀寫器上應用進程的通信接口。消息隊列設計的關鍵是消息結構和應用進程與中間件進層的協商機制,后者用來建立中間件到對應應用進程的消息發送隊列(對于應用進程自身來說,為消息接收隊列)。
(1)消息結構
typedef struct msg_text{
long intmsg_type;
unsigned intale_cmd;
charxml_text[MAX_SIZE];
} msg_text;
該結構體中包括三個變量:msg_type標識消息的類型,接收端可以根據該變量接收或忽略該消息;ale_cmd標識具體的指令類型,命令處理模塊根據該變量調用相應的處理函數;xml_text數組保存消息的數據。
在消息隊列的發送端調用Linux的庫函數msgget()獲得消息隊列,調用msgsnd()發送消息;在接收端調用msgget()函數獲得消息隊列,調用msgrcv()函數提取消息[1]。
(2)中間件與應用進程的協商機制
應用進程通過getpid()函數獲得自身的進程標識號,生成一個消息,把消息的ale_cmd置為0,把進程標識號寫入xml_text數組,通過中間件的消息接收隊列往中間件發消息。中間件收到ale_cmd為0的消息,知道有一個應用進程請求建立消息隊列。應用進層與中間件同時以該進程標識號作為鍵值,調用msgget()函數,獲得消息隊列標識號。
這種機制利用了系統中進程號的唯一性,以進程號作為鍵值建立消息隊列。
4.2 XML數據解析
XML數據的解析基于開源的XML解析器Expat,被編譯成共享庫,這里需要調用其函數。

圖4 XML數據解析流程
圖4為基于Expat的XML格式數據解析流程圖。p為XML_ParserCreate()函數的返回值。start、end和cdata的函數定義由Expat規定,函數體由用戶自己實現以實現其應用。當解析器遇到XML元素的開始標記就會執行start函數,遇到XML元素的結束標記就會執行end函數。具體的函數定義及細則可以參考Expat的官方文檔。
4.3 命令處理模塊
(1)命令處理模塊的數據結構
命令處理模塊是嵌入式中間件的核心,是中間件接口API的內部實現。嵌入式中間件可為網絡用戶服務,也可為讀寫器上的嵌入式應用程序服務。網絡用戶用其URL或IP地址標識,本地用戶即嵌入式應用程序用其消息接收隊列標識號標識。URL/IP地址、隊列標識號統一為URI。
在調用這個模塊之前,先在內存中創建一個全局的指針變量,指向ECSpec_t鏈表。鏈表的節點包括ECSpec數據本身和相應狀態信息及控制數據。ECSpec_t鏈表保存了中間件中所有已注冊的ECSpec的所有信息,命令處理函數的實現主要基于對該鏈表的操作。鏈表節點的結構定義如下:
typedef struct ECSpec_t_node
{
ECSpec*p_ECSpec;//指向ECSpec結構體的指針
Subscriber *firstSub;//訂閱者鏈表的頭指針
Poll*firstPoll;//查閱者鏈表的頭指針
int ECSpecState;//ECSpec的狀態
pthread_tthreadid;//工作線程標識符
pthread_mutex_tecspec_state;//互斥量,用于線程同步
pthread_cont_tecspec_con;//條件變量,用于線程同步
ECSpec_t_node*nextECSpec_t;//下一個ECSpec_t_node的指針
}ECSpec_t_node;
依照ALE,節點中的ECSpec[2]是ALE事件周期的描述,它包含了事件周期的工作方式和事件周期后報表的產生方式。
訂閱者鏈表結構如圖5:

圖5訂閱者鏈表
一個subscriber代表一個訂閱者,字符串指針uri指向訂閱者的地址(URL/IP地址或消息隊列標識符),next指針指向下一個訂閱者,ECSpec的報表發送給每一個訂閱者。最后一個訂閱者的next指針指向空。
查閱者鏈表的結構與訂閱者鏈表相似。
(2)命令處理模塊的函數定義
依照ALE,本命令處理模塊實現了九個函數。這些函數的類型定義及程序流程如下:
a)ale_define(specName:string,spec:ECSpec):void
往全局鏈表中增加一個該ECSpec_t的節點,表示向中間件“注冊”了一個ECSpec;該ECSpec增加一個工作線程,即每個ECSpec對應一個工作線程。工作線程按照ECSpec的要求開始事件周期,獲取讀寫器返回的原始標簽數據,產生報表。
b)ale_undefine(specName:string):void
根據提供的參數specName,向中間件注銷一個ECSpec,即從ECSpec_t鏈表中刪除該節點,并終止該ECSpec對應的工作線程。
c)ale_getECSpec(specName:string):ECSpec
根據提供的參數specName,在ECSpec_t鏈表中查找該ECSpec對應的節點。若該節點存在,返回該ECSpec。
d)ale_getECSpecNames():List(String)
遍歷ECSpec_t鏈表,返回中間件中注冊的所有ECSpec的名字。
e)ale_subscribe(specName:string,notificationURI:string):void
為指定的ECSpec增加一個訂閱者,即在訂閱者鏈表中插入一個新的訂閱者,并根據圖2修改ECSpec的狀態。
f)ale_unsubscribe(specName:string,notificationURI:string):void
為指定的ECSpec取消一個訂閱者,即在訂閱者鏈表中刪除指定的訂閱者,并根據圖2修改ECSpec的狀態。
g)ale_getSubscribers(specName:String):void
返回參數指定的ECSpec的所有訂閱者的URI。
h)ale_immediate(spec:ECSpec):ECReports
注冊并訂閱ECSpec,在第一個事件周期結束并返回報表后取消訂閱,注消ECSpec。
i)ale_poll(specName:string,notificationURI:string):ECReports
為指定的ECSpec增加一個查閱者,即在查閱者鏈表中插入一個新的查閱者,并改變ECSpec的狀態。在第一個事件周期結束并返回報表后取消查閱,即在查閱者鏈表中刪除該查閱者。
參考文獻
[1]Neil Matthew, Richard Stones,著. 陳健,宋健健,譯.Linux程序設計(第3版)[M]. 北京:人民郵電出版社,2007.
[2]EPCglobal Inc. The Application Level Events (ALE) Specification Version1.0[S]. http://www.epcglobalinc.org/standards/ale/ale_1_0-standard-20050915.pdf.
[3]Finkenzeller K,著. 陳大才,譯. 射頻識別(RFID)技術(第2版)[M]. 北京: 電子工業出版社,2001.
[4]孟和,趙政,薛桂香,等. EPCglobal應用層事件引擎設計與實現[J]. 計算機工程,2008(6): 12.★
【作者簡介】
劉鐵華:華南理工大學電子與信息學院碩士研究生,主要研究領域為RFID中間件。
尹俊勛:華南理工大學電子與信息學院博士生導師,主要研究領域為通信與音視頻處理。