Reputation: 87
I am receiving some data from a device over a TCP socket. I have the specifications for the structure, but don't know how to use this to unpack it. I'm assuming this means writing a formatting string for the struct.unpack
function, but I am having trouble figuring that out given the specs from the manufacturer. Each of these 32-bit pieces is a "DWORD", but I'm not sure how to interpret that, and pull out the relevant bits:
The status header is a 22x32bit (88 bytes) structure of mixed data types that precedes and provides information about the data being transferred. The following table shows the relevant members of the structure. The shaded member fields are reserved for future expansion, used internally for instrument monitoring and controls, or simply not yet implemented.
Here are two sample structures:
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'
Upvotes: 1
Views: 1359
Reputation: 127260
This should get you started. Unpack the received bytes using struct.unpack
, then do some parsing for fields that are represented by less than 1 byte of data.
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
I assumed big endian since this is coming over TCP, but that might be wrong. If all the data looks off, try using <
for little endian. Or if you're unlucky some values might be one while some are the other, in which case you'll have to split this into multiple unpacks. You'll also have to further process these values, as I'm sure some of them aren't supposed to be interpreted as ints.
The unpack format can be shortened to
(all, those, variables) = unpack('>6B9H2BH3I2HIH2B10H4I', data)
but I don't think it's as clear.
Upvotes: 2