Python解析具有固定格式的串行十六进制字符串

时间:2014-10-06 20:38:23

标签: python parsing serialization serial-port pyserial

我通过串行与一个简单的设备成功通信,使用特定的请求数据包,并收到固定格式的返回数据包。我从python开始,所以我可以在多个设备上使用它,我只是真的习惯了PHP / C.

例如,我将以下内容发送为十六进制:

12 05 0b 03 1f

作为回报我得到

12 05 0b 03 1f 12 1D A0 03 18 00 22 00 00 CA D4 4F 00 00 22 D6 99 18 00 70 80 00 80 00 06 06 00 00 D9

我知道数据包的构造方式,前5个字节是发送的数据。接下来的3个字节是ID,包长度和响应代码。它在我的代码中对此进行了评论:

import serial, time

ser = serial.Serial(port='COM1', baudrate=9600, timeout=0, parity=serial.PARITY_EVEN,      stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)

while True:
    # Send The Request - 0x12 0x05 0x0B 0x03 0x1F
    ser.write("\x12\x05\x0B\x03\x1F")
    # Clear first 5 bytes (Original Request is Returned)    
    ser.read(5)

    # Response Header (3 bytes)
    # - ID (Always 12)
    # - Packet Length (inc these three)
    # - General Response (a0 = Success, a1 = Busy, ff = Bad Command)
    ResponseHeader = ser.read(3).encode('hex')
    PacketLength = int(ResponseHeader[2:4],16)
    if ResponseHeader[4:6] == "a0":
        # Response Success
        ResponseData = ser.read(PacketLength).encode('hex')
        # Read First Two Bytes        
        Data1 = int(ResponseData[0:4],16)
        print Data1
    else:
        # Clear The Buffer
        RemainingBuffer = ser.inWaiting()
        ser.read(RemainingBuffer)

time.sleep(0.12)

为了保持现在的简单,我只是试图读取实际响应的前两个字节(ResponseData),它应该给我十六进制0318.然后我想输出十进制= 792。该程序旨在连续循环运行。

数据包中的一些变量是一个字节,有些是两个字节。虽然到目前为止我只是收到一个错误:

ValueError: invalid literal for int() with base 16: ''

我猜这是由于我设置的数据/变量的格式,所以不确定我是否以正确的方式进行此操作。我只想以字节形式读取返回的HEX数据,并能够在单独的级别上访问它们,因此我可以根据需要格式化/输出它们。

有更好的方法吗?非常感谢。

2 个答案:

答案 0 :(得分:0)

我建议使用struct模块读取二进制数据,而不是使用字符串函数将其重新编码为十六进制并尝试解析十六进制字符串。

答案 1 :(得分:0)

正如您的代码现在所示,您通过线路发送二进制(非十六进制)数据,并从设备接收二进制(非十六进制)数据。然后将二进制数据转换为十六进制,只将再次转换为Python变量。

让我们使用struct.unpack

跳过额外的转化步骤
# UNTESTED
import struct
...
while True:
    # Send The Request - 0x12 0x05 0x0B 0x03 0x1F
    ser.write("\x12\x05\x0B\x03\x1F")
    # Clear first 5 bytes (Original Request is Returned)    
    ser.read(5)

    # Response Header (3 bytes)
    # - ID (Always 12)
    # - Packet Length (inc these three)
    # - General Response (a0 = Success, a1 = Busy, ff = Bad Command)
    ResponseHeader = ser.read(3)
    ID,PacketLength,Response = struct.unpack("!BBB", ResponseHeader)
    if Response == 0xa0:
        # Response Success
        ResponseData = ser.read(PacketLength)
        # Read First Two Bytes        
        Data1 = struct.unpack("!H", ResponseData[0:2])
        print Data1
    else:
        # Clear The Buffer
        RemainingBuffer = ser.inWaiting()
        ser.read(RemainingBuffer)