用Python解包数据结构

1 投票
1 回答
1270 浏览
提问于 2025-04-28 07:03

我从一个设备那里通过TCP套接字接收一些数据。我有这个数据结构的说明,但不知道怎么用它来解包。我猜这意味着要为struct.unpack函数写一个格式字符串,但根据制造商提供的说明,我有点搞不清楚。每个32位的数据块叫做“DWORD”,但我不太确定该怎么理解它,并提取出相关的部分:

状态头是一个22个32位(88字节)的混合数据类型结构,它在传输数据之前提供信息。下面的表格展示了这个结构的相关成员。阴影部分的字段是为将来扩展保留的,内部用于仪器监控和控制,或者是尚未实现的。

Imgur Imgur

这里有两个示例结构:

b'\x08\x04i!\x13\x02\x00\x1f\x00\x00\x80\x0c\x01\x00p\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\x9e\x00\x00\x85\x9e\x01\x00:B\x04\x00\x08\xf4DT\x01\x00k\x01\xdc\x8c\x00\x00c\x03X\x00\x9eR\xa4QTV\xf0U\xd0\x83\xd0\x83\xd0\x83\xd0\x83\x01\x00\x00\x00@B\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

b'\x08Ti!\x1a\x02\x00\x1f\x00\x00x\x0c\x01\x00p\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\x91\x00\x00\xd5\x91\x01\x00`y\x00\x00\x05\xf4DT\x01\x00\xbb\x00\xdb\x8c\x00\x00c\x03X\x00\x9eR\xa4QTV\xf0U\xd0\x83\xd0\x83\xd0\x83\xd0\x83\x01\x00\x00\x00@B\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

暂无标签

1 个回答

2

这段话是告诉你如何开始处理接收到的数据。你需要用 struct.unpack 来解压这些字节,然后对一些用不到1个字节表示的字段进行解析。

from struct import unpack

# data recieved, 88 random bytes for example purpose
data = b'\xdb[\x91wdI\t\xef\xc6c\xde\x14\xac\x1e\x08\x10.f\xc0\xbd\xfd\xa15\x8cP\x101\xed\xc5\xd9\x98X\xb5\xc2\x00Z\xd2\xb9\xb0Xa\x04\xfa\xb8\xceA\x94_7\xc7\xde\t\xf2kX\x9d2\xc3\x84\xb3\x19\x8e\xf5\x99\xc3\xba\x08\xaa0$\x17\xfbd\xbb\x7f\xfd&\xf5\x1aU\t`\x11@zD\xce\xff'

# unpack the struct into variables
(
    abcde, fw_ver, cur_layer, fs_radix,  # 0 needs parse
    fghij, knpl, fbg_thermistor,  # 1 needs parse
    tx_ambient_temp, reserved2,  # 2
    num_ffpi_peaks, num_fbg_peaks,  # 3
    num_dut2_peaks, num_dut1_peaks,  # 4
    num_dut4_peaks, num_dut3_peaks,  # 5
    reserved7, qr, acq_counter3,  # 6 needs parse
    serial_number,  # 7
    kernel_timestamp_microseconds,  # 8
    kernel_timestamp_seconds,  # 9
    kernel_src_buffer, kernel_buffers,  # 10
    error_and_kernel_rt_loc0,  # 11 needs parse
    header_length, header_ver, buffers,  # 12
    dut2_gain, dut1_gain,  # 13
    dut4_gain, dut3_gain,  # 14
    dut2_noise_thresh, dut1_noise_thresh,  # 15
    dut4_noise_thresh, dut3_noise_thresh,  # 16
    hw_clk_div, peak_data_rate_div,  # 17
    granularity,  # 18
    reserved4,  # 19
    starting_lambda,  # 20
    ending_lambda  # 21
) = unpack(
    '>'  # big endian
    'BBBB'  # 0 needs parse
    'BBH'  # 1 needs parse
    'HH'  # 2
    'HH'  # 3
    'HH'  # 4
    'HH'  # 5
    'BBH'  # 6 needs parse
    'I'  # 7
    'I'  # 8
    'I'  # 9
    'HH'  # 10
    'I'  # 11 needs parse
    'HBB'  # 12
    'HH'  # 13
    'HH'  # 14
    'HH'  # 15
    'HH'  # 16
    'HH'  # 17
    'I'  # 18
    'I'  # 19
    'I'  # 20
    'I',  # 21
    data
)

# 0 parse abcde
acq_triggered = bool(abcde & 0x80)
calibration_fault = bool(abcde & 0x40)
start_of_frame = bool(abcde & 0x20)
primary_fan_state = bool(abcde & 0x10)
secondary_fan_state = bool(abcde & 0x08)
s0_mux_state = bool(abcde & 0x04)
s1_mux_state = bool(abcde & 0x02)
s2_mux_state = bool(abcde & 0x01)

# 1 parse fghij
xfer_type = fghij >> 4
soa_therm_limit = bool(fghij & 0x08)
soa_current_limit = bool(fghij & 0x04)
tec_over_temp = bool(fghij & 0x02)
tec_under_temp = bool(fghij & 0x01)

# 1 parse knpl
operating_mode = knpl >> 6
triggering_mode = (knpl & 0x30) >> 4
sm041_mux_level = (knpl & 0x0c) >> 2
sw_position = knpl & 0x03

# 6 parse qr
nrz_command = qr >> 5
reserved6 = qr & 0x1f

# 11 parse
error = error_and_kernel_rt_loc0 >> 24
kernel_rt_loc0 = error_and_kernel_rt_loc0 & 0xffffff

我假设数据是大端格式,因为它是通过TCP传输过来的,但这可能不对。如果你发现数据看起来不对劲,可以试试用 < 来表示小端格式。或者如果运气不好,有些值可能是一个格式而有些是另一个格式,这样的话你就得把这些数据分开来解压。你还需要进一步处理这些值,因为我相信其中一些并不应该被当作整数来解释。


解压格式可以简化为

(all, those, variables) = unpack('>6B9H2BH3I2HIH2B10H4I', data)

但我觉得这样不太清晰。

撰写回答