基于Python的X-PLUS矩阵通讯实现

2020-06-04 12:55张世超
数字技术与应用 2020年3期

张世超

摘要:本文介紹矩阵通讯协议,详解命令格式,提出使用基于Python的自动化软件与X-PLUS矩阵交互通讯的方法并开发实现,达到减少操作时间,提高响应速度,降低运维成本,提高矩阵的功能性和易操作性的目的。

关键词:Python;X-PLUS;Socket;广播级矩阵

中图分类号:TN919 文献标识码:A 文章编号:1007-9416(2020)03-0125-03

X-PLUS是大连捷成推出的多格式、全规模的广播级矩阵产品.可在一个机箱完成多种格式信号的切换调度。可同时兼容大、中、小规模、并可灵活配置多种信号格式的全规模、多格式矩阵。该矩阵支持多格式混插,并具有电子切换和点对点旁通(BY-PASS)的双切换模式[1]。矩阵功能强大,可控制最多128路信号,很多切换通道等功能要求24小时秒级操作,单靠人工无法实现,且上下位机之间可能距离遥远。因此其与自动化系统远程通讯交互十分必要。使用矩阵提供的大连捷成协议框架可以轻松实现。

1 通讯简介

与矩阵通讯时,被控制的矩阵设备被看成服务端,与矩阵连接的自动化软件被看成客户端。通过TCP或者UDP协议,自动化软件发送命令给矩阵,矩阵反馈命令执行结果,矩阵也可以发送报告给自动化软件显示自身状态变化。

1.1 协议简介

通讯协议框架使用大连捷成协议框架,主要分为起始、命令、数据、校验码和结束五部分标识符,协议第一个字节是SOH代表开始,第二个和第三个字节代表命令,中间n个字节是传输的数据,数据后面两个字节是异或校验码,最后一个字节是EOT代表结束。

1.2 接口简介

矩阵提供RJ45与RS232接口供外部自动化软件控制使用。RJ45接口自适应10Mbps/100Mbps连接方式分为直连和通过集线器路由器等网络设备连接,必须使用IPv4通过TCP或者UDP通讯,矩阵监听外部发起的请求,端口号为8000。RS232配置波特率19200,起始位1,数据位8,奇偶校验无。

1.3 命令详解

命令主要分为上报命令和事务命令。上报命令是矩阵某些状态发生改变,它主动上报外部自动化软件。事务命令是外部自动化软件想要改变矩阵某设置或者获取某状态而发送的。当自动化软件发送命令请求给矩阵,矩阵会应答响应。

命令请求的格式如图1所示,由于通讯过程中使用比特流,所以传输时数据可以看成是一串16进制数,起始标识符SOH就是0x01,结束标识符EOT就是0x04,完整的请求或者应答都是以这两个标识符开始结束的,中间不再允许出现0x01或者0x04,为保证命令中间部分不出现起始和结束标识符,命令中间数据使用ASCII编码转义,当有数据是1的时候不会写成0x01,而是通过ASCII码转换,变成字符1也就是16进制数0x31。

命令标识符说明要做什么,例如QS是查询矩阵规模(16进制表示为0x51 0x53),AS是切换通道源(16进制表示为0x41 0x53),其他更多命令参见产品说明书。

对于不同的命令,其后面紧跟着的数据内容也不同,但是数据最长限制为1024字节,多余的字节会被抛弃。对于QS等命令,可能后面跟随的数据是空的,因为只需要告诉矩阵反馈规模即可,不需要其他数据。

异或校验码BCC(Block Check Character),也叫信息组校验码,是保证数据传输过程中检查完整性的重要依据,把从起始标识符之后到校验码之前的所有16进制数经行异或运算,最后得到的结果再通过ASCII转换为两个16进制数,这有些不太好理解,举个例子:当需要向矩阵请求获取其规模时,就需要发送QS命令,因为QS转码后数据是0x51 0x53,后面没有其他数据,异或校验码就是 51XOR53=02,0转换为0x30,2转换为0x32,最后得到异或校验码就是0x30 0x32。

应答分两种,一种格式跟命令请求一样,另外一种特殊的应答只有一个字节,内容为一个感叹号,表示立即执行。应答反馈最大超时时间为200ms,超过此时间被认为之前发送的命令没有成功接收。

2 Python实现

在详细了解通讯协议后就可以编写软件与矩阵通讯,这里选择Python讲解具体实现方法,因为Python简单易学,让人更加专注与矩阵通讯的方法,而非研究数据结构,降低学习门槛,帮助使用者快速上手。

2.1 Socket连接

Socket又叫套接字,它是计算机之间进行通信的一种约定或一种方式。通过它一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据[2]。我们使用Python的Socket包实现代码:

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)

这是最基础的连接示例,首先导入Socket包,创建一个TCPClient类, host为要连接的矩阵IP地址,port为端口号,timeout是超时时间,buffsize是套接字緩存大小,socket.AF_INET表示使用IPv4, socket.SOCK_STREAM表示使用流式套接字。接着定义send函数与receive函数,分别表示发送和接收数据,最后在main中实例化TCPClient类的对象client,使用send和receive发送和接收数据。

2.2 封装命令

send函数发送的数据是比特流,可以看成是一串以0x01开头0x04结尾的16进制数,函数会自动在发送的msg数据前后加上起始结束标识符,同时也要计算异或校验码,再把校验码放再在结束标识符前面。所以只需要把请求的命令和数据标识符内容传入send函数的参数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函数首先转换utf-8字符,然后通过getBBC函数获取msg这串数据的校验码,再把这串校验码从字符串转换成比特流,跟随开始结束标识符一起封装。

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函数根据传入的checkData数据计算异或校验码,通过循环遍历计算得到一个16进制数,如果是个位数就再前面加上0,因为校验码占用两个字节,个位数只有一个字节,必须在前面加上0x30表示0,否则会被矩阵认为是不完整数据丢弃。

2.3 解析应答

矩阵收到命令请求会应答,receive函数就是用于监听应答的函数。

def receive(self):

try:

while True:

msg = self.tcpClientSocket.recv(self.BUFFSIZE)

if not msg:

break

print("接收到服务器端消息:{}".format(msg))

if len(msg) == 1 and int(hex(ord(msg.decode('utf-8')))[2:]) == 21:

print('server立即应答' + msg.decode('utf-8'))

elif len(msg) < 6:

print('应答不完整或不可识别')

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("数据不完整或者校验失败")

else:

……

break

except Exception as e:

print(e)

self.tcpClientSocket.close()

receive函数通过无限循环语句一直监听接收的数据,如果收到的数据只有一个字节且内容为0x21,对应的是ASCII码的感叹号,说明矩阵已经立即执行之前发送的命令请求,如果既不是0x21又小于6个字节表示数据不完整,因为起始结束标识符占用2字节,命令占用2字节,校验码占用2字节,如果小于6字节说明数据不完整,当数据大于等于6字节获取各个字段通过isCheck函数判断是否正确。

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函數判断起始结束标识符是否正确,通过getBBC函数计算校验码与获取的校验码对比是否一致,当对比结果一致的时候isCheck函数返回True,表示通过验证,剩下的命令标识符字段和数据字段就是我们需要的数据。由于各个命令跟随的数据结构及长度都不尽相同,全部详细讲解篇幅过大,下面举简单个例说明。

2.4 实例数据讲解

如需要获取矩阵规模,查询说明得知获取矩阵规模命令是QS,数据字段为空。所以可通过实例化类对象的send方法,即client.send('QS')。

使用Socket Tools工具模拟矩阵接收数据可以看到当实例化对象client.send('QS')发送QS查询矩阵规模命令时,经过封装发送出去的数据如图2所示可看成是一串16进制的数,以0x01开头0x04结尾,0x51 0x53通过ASCII转码为QS,0x30 0x32是0x51XOR0x53得出的结果02的转码结果。

当矩阵接收到QS命令会应答,通过Python软件运行获取软件应答数据为b\0x01SQ00000A030B000000000000000000000000032\0x04,通过软件解析保留命令和数据字段为SQ00000A030B外加后面一串0,通过查询说明书可知SQ是反馈QS的命令,后面的A030B是矩阵规模数据,其余用0填满保留字段长度,A表示音频1层,0x03表示输出端口有0到3四个输出口,0x0B表示输入端口有0到B十二个输入口,所以矩阵规模为4x12。

如需要查询上述矩阵音频1层各端口状态,获取矩阵通道状态命令是QD,后面跟随数据占3各字节,前两个字节是通道总数,为00表示查询所有通道,第三个字节为层标示,这里只有一个音频层,层标示为A,所以通过对象实例发送client.send('QD00A'),最终软件获取矩阵应答数据为b\0x01DQ04A0002NA0100LA0200LA0300L11\0x04,通过解析保留命令和数据字段为DQ04A0002NA0100LA0200LA0300L,通过查询说明书可知DQ04为反馈有4个通道,A0002N表示A层1口输出为1端口,输入为3端口,状态无锁定。A0100L表示A层2口输出为2端口,输入为1端口,状态锁定。后面两个口依此类推。

如需要切换1通道状态为输出口1,输入口4,使用AS命令,数据依次为通道总数(只切换一个通道就为01)、层标示(音频1层标示为A)、输出通道(为00)、输入通道(为03)、通道状态(为T表示切换状态)。当发送命令请求后软件会收到矩阵应答数据0x21,表示切换命令已经立即执行。

3 结语

X-PLUS矩阵功能强大,它提供接口供外部自动化通讯控制,虽然通讯命令封装解析繁琐复杂,但是通过软件实现自动封装解析后各种命令变得简单易用,原本人工手动需要数秒的操作通过自动化软件能在1秒内完成,且7x24小时响应无差错,节约维护成本,提高响应速度。在后期还可以用组合操作达成矩阵所不具备的功能,比如想实现通道轮巡功能可以让软件每隔几秒自动切换输入端口,想实现信号错误检测可以让软件分析信号,发现问题自动转换通道。由此可见,自动化系统与矩阵远程通讯交互不仅节约资金,还能创造更多价值。

参考文献

[1] X-PLUS多格式矩阵[J].世界广播电视,2008,22(11):109.

[2] yongfutian.Socket技术详解[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