張世超
摘要:本文介紹矩陣通訊協(xié)議,詳解命令格式,提出使用基于Python的自動(dòng)化軟件與X-PLUS矩陣交互通訊的方法并開發(fā)實(shí)現(xiàn),達(dá)到減少操作時(shí)間,提高響應(yīng)速度,降低運(yùn)維成本,提高矩陣的功能性和易操作性的目的。
關(guān)鍵詞:Python;X-PLUS;Socket;廣播級(jí)矩陣
中圖分類號(hào):TN919 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1007-9416(2020)03-0125-03
X-PLUS是大連捷成推出的多格式、全規(guī)模的廣播級(jí)矩陣產(chǎn)品.可在一個(gè)機(jī)箱完成多種格式信號(hào)的切換調(diào)度??赏瑫r(shí)兼容大、中、小規(guī)模、并可靈活配置多種信號(hào)格式的全規(guī)模、多格式矩陣。該矩陣支持多格式混插,并具有電子切換和點(diǎn)對(duì)點(diǎn)旁通(BY-PASS)的雙切換模式[1]。矩陣功能強(qiáng)大,可控制最多128路信號(hào),很多切換通道等功能要求24小時(shí)秒級(jí)操作,單靠人工無法實(shí)現(xiàn),且上下位機(jī)之間可能距離遙遠(yuǎn)。因此其與自動(dòng)化系統(tǒng)遠(yuǎn)程通訊交互十分必要。使用矩陣提供的大連捷成協(xié)議框架可以輕松實(shí)現(xiàn)。
1 通訊簡介
與矩陣通訊時(shí),被控制的矩陣設(shè)備被看成服務(wù)端,與矩陣連接的自動(dòng)化軟件被看成客戶端。通過TCP或者UDP協(xié)議,自動(dòng)化軟件發(fā)送命令給矩陣,矩陣反饋命令執(zhí)行結(jié)果,矩陣也可以發(fā)送報(bào)告給自動(dòng)化軟件顯示自身狀態(tài)變化。
1.1 協(xié)議簡介
通訊協(xié)議框架使用大連捷成協(xié)議框架,主要分為起始、命令、數(shù)據(jù)、校驗(yàn)碼和結(jié)束五部分標(biāo)識(shí)符,協(xié)議第一個(gè)字節(jié)是SOH代表開始,第二個(gè)和第三個(gè)字節(jié)代表命令,中間n個(gè)字節(jié)是傳輸?shù)臄?shù)據(jù),數(shù)據(jù)后面兩個(gè)字節(jié)是異或校驗(yàn)碼,最后一個(gè)字節(jié)是EOT代表結(jié)束。
1.2 接口簡介
矩陣提供RJ45與RS232接口供外部自動(dòng)化軟件控制使用。RJ45接口自適應(yīng)10Mbps/100Mbps連接方式分為直連和通過集線器路由器等網(wǎng)絡(luò)設(shè)備連接,必須使用IPv4通過TCP或者UDP通訊,矩陣監(jiān)聽外部發(fā)起的請(qǐng)求,端口號(hào)為8000。RS232配置波特率19200,起始位1,數(shù)據(jù)位8,奇偶校驗(yàn)無。
1.3 命令詳解
命令主要分為上報(bào)命令和事務(wù)命令。上報(bào)命令是矩陣某些狀態(tài)發(fā)生改變,它主動(dòng)上報(bào)外部自動(dòng)化軟件。事務(wù)命令是外部自動(dòng)化軟件想要改變矩陣某設(shè)置或者獲取某狀態(tài)而發(fā)送的。當(dāng)自動(dòng)化軟件發(fā)送命令請(qǐng)求給矩陣,矩陣會(huì)應(yīng)答響應(yīng)。
命令請(qǐng)求的格式如圖1所示,由于通訊過程中使用比特流,所以傳輸時(shí)數(shù)據(jù)可以看成是一串16進(jìn)制數(shù),起始標(biāo)識(shí)符SOH就是0x01,結(jié)束標(biāo)識(shí)符EOT就是0x04,完整的請(qǐng)求或者應(yīng)答都是以這兩個(gè)標(biāo)識(shí)符開始結(jié)束的,中間不再允許出現(xiàn)0x01或者0x04,為保證命令中間部分不出現(xiàn)起始和結(jié)束標(biāo)識(shí)符,命令中間數(shù)據(jù)使用ASCII編碼轉(zhuǎn)義,當(dāng)有數(shù)據(jù)是1的時(shí)候不會(huì)寫成0x01,而是通過ASCII碼轉(zhuǎn)換,變成字符1也就是16進(jìn)制數(shù)0x31。
命令標(biāo)識(shí)符說明要做什么,例如QS是查詢矩陣規(guī)模(16進(jìn)制表示為0x51 0x53),AS是切換通道源(16進(jìn)制表示為0x41 0x53),其他更多命令參見產(chǎn)品說明書。
對(duì)于不同的命令,其后面緊跟著的數(shù)據(jù)內(nèi)容也不同,但是數(shù)據(jù)最長限制為1024字節(jié),多余的字節(jié)會(huì)被拋棄。對(duì)于QS等命令,可能后面跟隨的數(shù)據(jù)是空的,因?yàn)橹恍枰嬖V矩陣反饋規(guī)模即可,不需要其他數(shù)據(jù)。
異或校驗(yàn)碼BCC(Block Check Character),也叫信息組校驗(yàn)碼,是保證數(shù)據(jù)傳輸過程中檢查完整性的重要依據(jù),把從起始標(biāo)識(shí)符之后到校驗(yàn)碼之前的所有16進(jìn)制數(shù)經(jīng)行異或運(yùn)算,最后得到的結(jié)果再通過ASCII轉(zhuǎn)換為兩個(gè)16進(jìn)制數(shù),這有些不太好理解,舉個(gè)例子:當(dāng)需要向矩陣請(qǐng)求獲取其規(guī)模時(shí),就需要發(fā)送QS命令,因?yàn)镼S轉(zhuǎn)碼后數(shù)據(jù)是0x51 0x53,后面沒有其他數(shù)據(jù),異或校驗(yàn)碼就是 51XOR53=02,0轉(zhuǎn)換為0x30,2轉(zhuǎn)換為0x32,最后得到異或校驗(yàn)碼就是0x30 0x32。
應(yīng)答分兩種,一種格式跟命令請(qǐng)求一樣,另外一種特殊的應(yīng)答只有一個(gè)字節(jié),內(nèi)容為一個(gè)感嘆號(hào),表示立即執(zhí)行。應(yīng)答反饋?zhàn)畲蟪瑫r(shí)時(shí)間為200ms,超過此時(shí)間被認(rèn)為之前發(fā)送的命令沒有成功接收。
2 Python實(shí)現(xiàn)
在詳細(xì)了解通訊協(xié)議后就可以編寫軟件與矩陣通訊,這里選擇Python講解具體實(shí)現(xiàn)方法,因?yàn)镻ython簡單易學(xué),讓人更加專注與矩陣通訊的方法,而非研究數(shù)據(jù)結(jié)構(gòu),降低學(xué)習(xí)門檻,幫助使用者快速上手。
2.1 Socket連接
Socket又叫套接字,它是計(jì)算機(jī)之間進(jìn)行通信的一種約定或一種方式。通過它一臺(tái)計(jì)算機(jī)可以接收其他計(jì)算機(jī)的數(shù)據(jù),也可以向其他計(jì)算機(jī)發(fā)送數(shù)據(jù)[2]。我們使用Python的Socket包實(shí)現(xiàn)代碼:
import socket
class TCPClient:
def __init__(self, host='192.168.1.2', port=8000, timeout=200):
self.HOST = host
self.PORT = port
self.BUFFSIZE = 1024
self.TIMEOUT = timeout
self.ADDRESS = (self.HOST, self.PORT)
self.tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcpClientSocket.connect(self.ADDRESS)
def send(self, msg):
……
def receive(self):
……
def main():
try:
client = TCPClient()
client.send('xxxx')
client.receive()
except Exception as e:
print(e)
這是最基礎(chǔ)的連接示例,首先導(dǎo)入Socket包,創(chuàng)建一個(gè)TCPClient類, host為要連接的矩陣IP地址,port為端口號(hào),timeout是超時(shí)時(shí)間,buffsize是套接字緩存大小,socket.AF_INET表示使用IPv4, socket.SOCK_STREAM表示使用流式套接字。接著定義send函數(shù)與receive函數(shù),分別表示發(fā)送和接收數(shù)據(jù),最后在main中實(shí)例化TCPClient類的對(duì)象client,使用send和receive發(fā)送和接收數(shù)據(jù)。
2.2 封裝命令
send函數(shù)發(fā)送的數(shù)據(jù)是比特流,可以看成是一串以0x01開頭0x04結(jié)尾的16進(jìn)制數(shù),函數(shù)會(huì)自動(dòng)在發(fā)送的msg數(shù)據(jù)前后加上起始結(jié)束標(biāo)識(shí)符,同時(shí)也要計(jì)算異或校驗(yàn)碼,再把校驗(yàn)碼放再在結(jié)束標(biāo)識(shí)符前面。所以只需要把請(qǐng)求的命令和數(shù)據(jù)標(biāo)識(shí)符內(nèi)容傳入send函數(shù)的參數(shù)msg里。
def send(self, msg):
msg = msg.encode('utf-8')
bbc = self.getBBC(msg)
bbc = bytes().fromhex(hex(ord(bbc[0]))[2:]) + bytes().fromhex(hex(ord(bbc[1]))[2:])
msg = bytes().fromhex('01') + msg + bbc + bytes().fromhex('04')
self.tcpClientSocket.send(msg)
send函數(shù)首先轉(zhuǎn)換utf-8字符,然后通過getBBC函數(shù)獲取msg這串?dāng)?shù)據(jù)的校驗(yàn)碼,再把這串校驗(yàn)碼從字符串轉(zhuǎn)換成比特流,跟隨開始結(jié)束標(biāo)識(shí)符一起封裝。
def getBBC(self, checkData):
for index in range(len(checkData)):
if index == 0:
dataCheckSum = checkData[index]
else:
dataCheckSum = dataCheckSum ^ checkData[index]
dataCheckSum = hex(dataCheckSum)[2:]
if len(dataCheckSum) == 1:
return '0' + dataCheckSum
return dataCheckSum
getBBC函數(shù)根據(jù)傳入的checkData數(shù)據(jù)計(jì)算異或校驗(yàn)碼,通過循環(huán)遍歷計(jì)算得到一個(gè)16進(jìn)制數(shù),如果是個(gè)位數(shù)就再前面加上0,因?yàn)樾r?yàn)碼占用兩個(gè)字節(jié),個(gè)位數(shù)只有一個(gè)字節(jié),必須在前面加上0x30表示0,否則會(huì)被矩陣認(rèn)為是不完整數(shù)據(jù)丟棄。
2.3 解析應(yīng)答
矩陣收到命令請(qǐng)求會(huì)應(yīng)答,receive函數(shù)就是用于監(jiān)聽?wèi)?yīng)答的函數(shù)。
def receive(self):
try:
while True:
msg = self.tcpClientSocket.recv(self.BUFFSIZE)
if not msg:
break
print("接收到服務(wù)器端消息:{}".format(msg))
if len(msg) == 1 and int(hex(ord(msg.decode('utf-8')))[2:]) == 21:
print('server立即應(yīng)答' + msg.decode('utf-8'))
elif len(msg) < 6:
print('應(yīng)答不完整或不可識(shí)別')
else:
first = msg[0]
command = (msg[1:3])
data = (msg[3:-3])
checkData = command + data
checkSum = str.lower(msg[-3:-1].decode('utf-8'))
last = msg[-1]
if self.isCheck(first, last, checkData, checkSum) is False:
print("數(shù)據(jù)不完整或者校驗(yàn)失敗")
else:
……
break
except Exception as e:
print(e)
self.tcpClientSocket.close()
receive函數(shù)通過無限循環(huán)語句一直監(jiān)聽接收的數(shù)據(jù),如果收到的數(shù)據(jù)只有一個(gè)字節(jié)且內(nèi)容為0x21,對(duì)應(yīng)的是ASCII碼的感嘆號(hào),說明矩陣已經(jīng)立即執(zhí)行之前發(fā)送的命令請(qǐng)求,如果既不是0x21又小于6個(gè)字節(jié)表示數(shù)據(jù)不完整,因?yàn)槠鹗冀Y(jié)束標(biāo)識(shí)符占用2字節(jié),命令占用2字節(jié),校驗(yàn)碼占用2字節(jié),如果小于6字節(jié)說明數(shù)據(jù)不完整,當(dāng)數(shù)據(jù)大于等于6字節(jié)獲取各個(gè)字段通過isCheck函數(shù)判斷是否正確。
def isCheck(self, first, last, checkData, checkSum):
if first != 1:
return False
if last != 4:
return False
dataCheckSum = self.getBBC(checkData)
if dataCheckSum == checkSum:
return True
else:
return False
isCheck函數(shù)判斷起始結(jié)束標(biāo)識(shí)符是否正確,通過getBBC函數(shù)計(jì)算校驗(yàn)碼與獲取的校驗(yàn)碼對(duì)比是否一致,當(dāng)對(duì)比結(jié)果一致的時(shí)候isCheck函數(shù)返回True,表示通過驗(yàn)證,剩下的命令標(biāo)識(shí)符字段和數(shù)據(jù)字段就是我們需要的數(shù)據(jù)。由于各個(gè)命令跟隨的數(shù)據(jù)結(jié)構(gòu)及長度都不盡相同,全部詳細(xì)講解篇幅過大,下面舉簡單個(gè)例說明。
2.4 實(shí)例數(shù)據(jù)講解
如需要獲取矩陣規(guī)模,查詢說明得知獲取矩陣規(guī)模命令是QS,數(shù)據(jù)字段為空。所以可通過實(shí)例化類對(duì)象的send方法,即client.send('QS')。
使用Socket Tools工具模擬矩陣接收數(shù)據(jù)可以看到當(dāng)實(shí)例化對(duì)象client.send('QS')發(fā)送QS查詢矩陣規(guī)模命令時(shí),經(jīng)過封裝發(fā)送出去的數(shù)據(jù)如圖2所示可看成是一串16進(jìn)制的數(shù),以0x01開頭0x04結(jié)尾,0x51 0x53通過ASCII轉(zhuǎn)碼為QS,0x30 0x32是0x51XOR0x53得出的結(jié)果02的轉(zhuǎn)碼結(jié)果。
當(dāng)矩陣接收到QS命令會(huì)應(yīng)答,通過Python軟件運(yùn)行獲取軟件應(yīng)答數(shù)據(jù)為b\0x01SQ00000A030B000000000000000000000000032\0x04,通過軟件解析保留命令和數(shù)據(jù)字段為SQ00000A030B外加后面一串0,通過查詢說明書可知SQ是反饋QS的命令,后面的A030B是矩陣規(guī)模數(shù)據(jù),其余用0填滿保留字段長度,A表示音頻1層,0x03表示輸出端口有0到3四個(gè)輸出口,0x0B表示輸入端口有0到B十二個(gè)輸入口,所以矩陣規(guī)模為4x12。
如需要查詢上述矩陣音頻1層各端口狀態(tài),獲取矩陣通道狀態(tài)命令是QD,后面跟隨數(shù)據(jù)占3各字節(jié),前兩個(gè)字節(jié)是通道總數(shù),為00表示查詢所有通道,第三個(gè)字節(jié)為層標(biāo)示,這里只有一個(gè)音頻層,層標(biāo)示為A,所以通過對(duì)象實(shí)例發(fā)送client.send('QD00A'),最終軟件獲取矩陣應(yīng)答數(shù)據(jù)為b\0x01DQ04A0002NA0100LA0200LA0300L11\0x04,通過解析保留命令和數(shù)據(jù)字段為DQ04A0002NA0100LA0200LA0300L,通過查詢說明書可知DQ04為反饋有4個(gè)通道,A0002N表示A層1口輸出為1端口,輸入為3端口,狀態(tài)無鎖定。A0100L表示A層2口輸出為2端口,輸入為1端口,狀態(tài)鎖定。后面兩個(gè)口依此類推。
如需要切換1通道狀態(tài)為輸出口1,輸入口4,使用AS命令,數(shù)據(jù)依次為通道總數(shù)(只切換一個(gè)通道就為01)、層標(biāo)示(音頻1層標(biāo)示為A)、輸出通道(為00)、輸入通道(為03)、通道狀態(tài)(為T表示切換狀態(tài))。當(dāng)發(fā)送命令請(qǐng)求后軟件會(huì)收到矩陣應(yīng)答數(shù)據(jù)0x21,表示切換命令已經(jīng)立即執(zhí)行。
3 結(jié)語
X-PLUS矩陣功能強(qiáng)大,它提供接口供外部自動(dòng)化通訊控制,雖然通訊命令封裝解析繁瑣復(fù)雜,但是通過軟件實(shí)現(xiàn)自動(dòng)封裝解析后各種命令變得簡單易用,原本人工手動(dòng)需要數(shù)秒的操作通過自動(dòng)化軟件能在1秒內(nèi)完成,且7x24小時(shí)響應(yīng)無差錯(cuò),節(jié)約維護(hù)成本,提高響應(yīng)速度。在后期還可以用組合操作達(dá)成矩陣所不具備的功能,比如想實(shí)現(xiàn)通道輪巡功能可以讓軟件每隔幾秒自動(dòng)切換輸入端口,想實(shí)現(xiàn)信號(hào)錯(cuò)誤檢測(cè)可以讓軟件分析信號(hào),發(fā)現(xiàn)問題自動(dòng)轉(zhuǎn)換通道。由此可見,自動(dòng)化系統(tǒng)與矩陣遠(yuǎn)程通訊交互不僅節(jié)約資金,還能創(chuàng)造更多價(jià)值。
參考文獻(xiàn)
[1] X-PLUS多格式矩陣[J].世界廣播電視,2008,22(11):109.
[2] yongfutian.Socket技術(shù)詳解[EB/OL].https://www.jianshu.com/p/066d99da7cbd,2019-01-11/2020-02-10.
Abstract:This paper introduces the matrix communication protocol, explains the command format in detail, proposes the method of communication between x-plus matrix and automated software based on Python, and develops and realizes it, so as to reduce operation time, improve response speed, reduce operation and maintenance cost, and improve the functionality and operability of matrix.
Key words:Python;X-PLUS;Socket;broadcast matrix