將電子表格轉換為 XML 文檔是 Microsoft® Office Excel® 和 OpenOffice.org Calc 的當前版本的內置功能,這個功能不是為了吸引眼球,它對嵌入式系統的開發和測試尤其有用。
常用縮寫詞
CLI:命令行界面
DOM:文檔對象模型
SQL:結構化查詢語言
TCP/IP:傳輸控制協議/互聯網協議
XML:可擴展標記語言
嵌入式系統開發人員需要一種方法來生成一些測試場景,以便驗證一個設計原型或者首次樣品。但是,生成這些場景的成本應該保持到最小。同樣的要求也適用於創建經濟高效的開發環境,以便使用很小的內存 “足跡” 執行專業的固件生成。
這裡討論的方法使用 OpenOffice.org Calc、XML 和一個 PHP 腳本來創建一個免費的測試場景或固件開發環境。這種方法通過一個生成 Modbus 命令測試場景的示例來演示。
將電子表格轉換為 XML 文檔
與 Excel 一樣,OpenOffice.org Calc 能夠生成通過兩種格式(任取其一)來表示電子表格的 XML 文檔。Microsoft Office Excel 2003 XML 生成 XML (.xml) 文件,而 OpenOffice.org Calc flat XML 生成 FODS (.fods) 文件。作為一個示例,MovIESchedule.xls 這個電子表格用於顯示本地電影院中的一個電影列表的安排。 圖 1 展示了電子表格的內容。
圖 1. 電影安排電子表格
查看原圖(大圖)
接下來,一個包含測試場景規范的序列的電子表格將由一個通過 PHP CLI 執行的 PHP 腳本轉換為對等的二進制格式。清單 1 展示了電子表格 XML 文檔(Excel 2003 格式)的一部分,該部分用於描述電子表格內容。
清單 1. 電影安排 XML 文檔
<ss:Worksheet ss:Name="MovIEs">
<Table ss:StyleID="ta1">
<Column ss:Width="127.8144"/>
<Column ss:Width="127.0512"/>
<Column ss:Width="191.34"/>
<Row ss:Height="14.2848">
<Cell>
<Data ss:Type="String">Title</Data>
</Cell>
<Cell>
<Data ss:Type="String">Theater</Data>
</Cell>
<Cell>
<Data ss:Type="String">Schedule</Data>
</Cell>
</Row>
<Row ss:Height="14.2848">
<Cell>
<Data ss:Type="String">Avatar</Data>
</Cell>
<Cell>
<Data ss:Type="String">Criterion</Data>
</Cell>
<Cell>
<Data ss:Type="String">3:00 PM, 7:00 PM,
10:30 PM</Data>
</Cell>
</Row>
<Row ss:Height="14.2848">
<Cell>
<Data ss:Type="String">Surrogates</Data>
</Cell>
<Cell>
<Data ss:Type="String">Palace</Data>
</Cell>
<Cell>
<Data ss:Type="String">5:00 PM, 8:00 PM,
11:00 PM</Data>
</Cell>
</Row>
</Table>
<x:WorksheetOptions/>
</ss:Worksheet>
使用 PHP 將 XML 文檔轉換為 blob
電子表格的 XML 文檔如何變成二進制代碼?那是一個 PHP 腳本的作用所在,該腳本使用一些類分別完成以下功能:
通過 PHP DOM 類遍歷 XML 文檔。
將被遍歷的元素的內容轉換為一組作為數組存儲的中介表示。
通過使用一個轉換數據庫將中介表示轉換為目標二進制表。
將生成的二進制代碼存儲為轉換數據庫中的一個 blob。
XML 文檔遍歷和 “內容到中介” 表示轉換是特定於域的。也就是說,它們已針對所使用的電子表格的結構進行定制。例如,一個協議測試電子表格將擁有兩個已針對特定的協議進行定制的類。轉換數據庫包含兩個表:一個是轉換引用表,用於將中介 “代碼” 映射到一個對應的二進制序列;另一個是二進制序列表,用於存儲與輸入 XML 電子表格文檔對應的二進制序列。
示例:構建一個 Modbus 測試場景序列
為了便於說明,需要創建一個電子表格,用於指定一個 Modbus 命令序列。這個命令序列用作一個測試場景,測試通過一個串行接口 —RS-232 或 RS485 — 與一個設備的串行通信。這個 OpenOffice.org Calc 電子表格的工作簿 — ModbusExample.ods — 包含兩個工作表。Modbus 是一個 “主-從” 應用程序級協議,也就是說,它獨立於支持一個主設備和一組從設備之間的通信的底層網絡的類型。它通常用於串行通信網絡,盡管也有一些設備在 TCP/IP 下運行。
底層網絡包的數據或消息區域封裝了一個請求命令,它請求設備中包含設備信號數據的寄存器的內容。該請求命令的格式如下:
[Device address][Request command][Start register][End register]
[Device address] 是 Modbus 設備地址(1-255),長度為一個字節。[Request command] 的長度也是一個字節,它的值基於正被尋址的寄存器的類型設置。讀取寄存器的值:
1 = Coil(事件指示器:長度為一個位)
2 = Status(事件指示器:長度為一個位)
3 = Hold(內部設備信號值:4 字節浮點值或 2 字節整數值)
4 = Input(設備輸入信號值:4 字節浮點值或 2 字節整數值)
其他命令也能夠寫入寄存器,但 Read 訪問命令的使用頻率通常更高。[Start register] 和 [End register] 的長度都是兩字節,用於提供其值被請求的寄存器地址的范圍。
圖 2. 設備通信設置
查看原圖(大圖)
返回到示例電子表格工作簿,第一個工作表 — 圖 2 中的 Comm — 使用以下參數提供用於訪問測試設備的串行通信設置。
Address。測試設備的 Modbus 網絡地址。
type。用於與測試設備通信的協議;僅用於文檔目的。
Interface。用於鏈接測試設備和主機的電纜連接器的物理類型。
Baud。主機和測試設備之間的通信數據傳輸速度。
Data。一個通信包中的數據位數。
Parity。主機和測試設備之間的通信的奇偶校驗設置。
Stop。主機和測試設備之間的通信的停止位數。
第二個工作表 Scenario(見 圖 3)指定:
Register type。正被尋址的 Modbus 寄存器的類型(input、hold、coil、status)。
Start Register。一個寄存器測試范圍中的起始 Modbus 寄存器地址。
End Register。一個寄存器測試范圍中的結束 Modbus 寄存器地址。
type。來自一個寄存器范圍的預期響應值的數據類型。這些單元的內容將被轉換為預期響應值的預期字節數。Int 被轉換為 2 而 float 被轉換為 4。位被轉換為以下公式:
Number of bytes =int((Number of bits + 1) / 8) + 1
其中,int([arg]) 是 [arg] 的值的整數部分。
Min。一個 Modbus 響應包中的任何寄存器值的最小有效值。
Max。一個 Modbus 響應包中的任何寄存器值的最大有效值。
圖 3. Modbus 請求場景
查看原圖(大圖)
PHP 腳本 ProtoConvert.PHP將電子表格 XML 文檔轉換為一個二進制命令序列。對於上述電子表格中的每一行,通過 Modbus 請求包檢索請求的寄存器范圍,並根據它們對應的有效值范圍驗證 Modbus 響應包中的寄存器值。這個腳本基於以下 5 個類:
SupportDB。建立一個到支持數據庫的連接,提供一些訪問方法來查詢和更新數據庫。這個腳本中使用的數據庫包是 MySQL,但是您可以使用其他數據庫包,比如 IBM® DB2® 或 PostgreSQL。
XMLWorkbook。提取電子表格 XML 文檔文件的內容。
CommSheet。從對應的 XML 文檔提取電子表格的 Comm 工作表部分的內容。
ScenariOSheet。從對應的 XML 文檔提取電子表格的 Scenario 工作表部分的內容。
ModbusReqSet。從 Comm 和 Scenario 工作表生成一個可執行命令序列。
使用這些類背後的驅動邏輯基本上如下所示:
建立一個到支持數據庫 ProtoTransDB 的連接,數據庫的元數據如 清單 2 所示。
清單 2. 轉換數據庫元數據
#
# Protocol test translation support database schema
#
#
DROP DATABASE IF EXISTS ProtoTransDB;
CREATE DATABASE ProtoTransDB;
USE ProtoTransDB;
#
# Repository of translated protocol test sequences
#
# NOTES -
#
# (1) TestID = test sequence ID consisting of:
#
# 1. <TestSpec> = Name of the test sequence
# specification spreadsheet
# 2. <TestStored> = Time stamp when test sequence
# was translated
#
# stored in the format <TestSpec>_<TestStored>
#
# (2) TestSequence = executable test sequence
#
# (3) The contents of TestSequence consists of
# a sequence of commands as follows:
#
# <set_comm>
# <request_1>
# <response_1_verify>
# ....................
# <request_N>
# <response_N_verify>
#
# where,
# <set_comm> = communication port configuration
# consisting of the following:
#
# 1. test sequence command (0x0A)
# 2. interface type (0x01 = RS232,
# 0x02 = RS485 2 wire,
# 0x03 = RS485 4 wire)
# 3. baud rate (2 bytes)
# 4. number of data bytes (1 byte)
# 5. parity (0x00 = none,
# 0x01 = odd,
# 0x02 = even)
# 6. number of stop bits (1 byte)
#
# <request_i> = register value request consisting of the following
#
# 1. register requested command (0x0B)
# 2. Modbus register request command (6 bytes):
# Device address (1 byte)
# Register read command (1 byte)
# Start register (2 bytes)
# End register (2 bytes)
#
# <response_i_verify> = register value response verification rule
# for preceding request consisting of the following:
#
# 1. verification rule command (0x0C)
# 2. Bytes per value (Int = 0x02, Float = 0x04, Bit = 0x00)
# 3. Total number of value bytes (2 bytes,
# Bytes per value *
# (End register - Start register + 1))
# 4. Valid minimum for each register value (2 bytes)
# 5. Valid maximum for each register value (2 bytes)
#
CREATE TABLE TestScenario
(
TestID VARCHAR(50) NOT NULL,
TestSequence BLOB,
PRIMARY KEY (TestID ASC)
);
提取電子表格 XML 文檔的內容。
提取 XML 文檔的 Comm 工作表的內容。
提取 XML 文檔的 Scenario 工作表的內容。
將 Comm 和 Scenario 工作表的內容轉換為一個可執行命令序列,該命令序列針對一個通過 Modbus 協議通信的設備定義一個測試序列。
使用以下命令運行這個 PHP 腳本:
php ProtoConvert.PHP <database_Access> <XML_doc>
其中,<database_Access> 是包含數據庫連接參數的文件的完整路徑名,<XML_doc> 是包含表示 Modbus 測試序列電子表格的 XML 文檔的文件的完整路徑名。
如果步驟 1 到 4 中出現失敗,那麼後續步驟將不能執行。清單 2 還包含作為一個 blob 存儲在數據庫中的測試序列命令的說明。本例中的數據庫只包含一個表來存儲測試序列,因為轉換引用信息被嵌入到 PHP 腳本中。
圖 2 和 圖 3 中展示的 Modbus 電子表格的測試序列位於 清單 3 中。這個序列實際上是一個持續的字節流(16 進制值)。但是,為了強調它的組件,我們根據 清單 2 中的元數據注釋描述的測試序列結構將其分解為它的一些組件,以 16 進制值顯示。
清單 3. 測試命令的樣例序列
0A 01 2580 08 00 01
0B 02 04 0136 0136
0C 02 0002 0000 0190
0B 02 03 01C2 01C4
0C 02 0006 0014 015E
0B 02 03 0212 0217
0C 02 000C 0000 0064
0B 02 01 011D 0122
0C 00 0001 0000 0001
以 0A 開頭的命令指示了串行通信配置設置。以 0B 和 0C 開頭的後續命令對分別是請求和驗證規則命令,用於提取和檢查從測試設備上的 Modbus 寄存器提取的值。
運行時環境包含一個主計算機,它通過自身與一個測試設備之間的串行線纜連接到該測試設備。這個主機運行一個測試序列命令解釋器,該解釋器以如下方式執行每條命令:
串口設置(0A)。將連接主機的串口設置為接受測試的設備。
寄存器地址請求(0B)。通過標准的 Modbus 命令請求測試設備上的 Modbus 寄存器的內容。
驗證規則(0C)。針對有效值限制測試由前面的寄存器地址請求返回的值。
測試序列命令解釋器還對每條命令的響應進行日志記錄,以備後續分析所需。
結束語
通過使用 OpenOffice.org Calc 的 XML 文檔生成功能、PHP 的 DOM 遍歷功能以及一個 blob 表示數據庫,可以將電子表格中的測試場景規范成功轉換為一個測試命令序列。但這種技術的用途還不止這些。
在 ModbusExample.ods 電子表格示例中,您將一個規范有效地轉換為一個命令序列。使用適當的電子表格結構,可以構建其他類似的 “規范到命令” 序列轉換工具,比如:
基於 “輸入-輸出” 規范的批生產控制序列生成器;
從設備規范生成的自動測試設備程序生成;
帶有精簡指令集的設備的固件生成。
本文示例源代碼或素材下載