用Python解包数据结构
我从一个设备那里通过TCP套接字接收一些数据。我有这个数据结构的说明,但不知道怎么用它来解包。我猜这意味着要为struct.unpack
函数写一个格式字符串,但根据制造商提供的说明,我有点搞不清楚。每个32位的数据块叫做“DWORD”,但我不太确定该怎么理解它,并提取出相关的部分:
状态头是一个22个32位(88字节)的混合数据类型结构,它在传输数据之前提供信息。下面的表格展示了这个结构的相关成员。阴影部分的字段是为将来扩展保留的,内部用于仪器监控和控制,或者是尚未实现的。
这里有两个示例结构:
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 个回答
这段话是告诉你如何开始处理接收到的数据。你需要用 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)
但我觉得这样不太清晰。