使用 Python3 中的结构记录解析串行数据
Parsing serial data with a Structure Record in Python3
我正在尝试解析通过串行端口从监视器接收到的数据。我已经成功地在 Python 中编写了一个脚本,以字节字符串的形式从监视器中检索数据,并根据 ISO3309 标准进行了必要的数据转换,最后执行了校验和以确保数据完整性。下面是提取的数据。
[198, 2, 40, 4, 0, 0, 131, 35, 158, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 22, 1, 1, 44, 2, 4, 189, 189, 255, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 131, 35, 158, 94, 51, 58, 0, 0, 0, 18, 2, 128, 10, 129, 1, 128, 1, 128, 1, 128, 1, 0, 0, 0, 1, 0, 2, 128, 2, 128, 2, 128, 1, 128, 1, 0, 0, 0, 2, 0, 2, 128, 2, 128, 2, 128, 1, 128, 0, 0, 0, 0, 11, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 3, 0, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 3, 1, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 11, 0, 4, 128, 3, 0, 0, 0, 12, 0, 4, 128, 0, 0, 0, 0, 13, 0, 1, 128, 0, 0, 0, 0, 14, 0, 1, 128, 3, 0, 0, 0, 0, 0, 1, 128, 2, 128, 2, 128, 1, 128, 7, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 203, 29, 3, 0, 0, 0, 0, 0, 41, 8, 41, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 11, 0, 1, 128, 1, 128, 1, 128, 1, 128, 32, 0, 0, 0, 0, 0, 1, 128, 1, 128, 255, 141, 2, 128, 1, 128, 1, 128, 0, 0, 0, 0, 173, 1, 1, 128, 0, 0, 0, 0, 13, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 14, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 65, 0, 131, 35, 158, 94, 0, 0, 0, 0, 18, 2, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 0, 0, 1, 128, 1, 128, 4, 128, 1, 128, 1, 128, 1, 128, 73, 13, 0, 0, 176, 192, 0, 0, 226, 1, 0, 0, 198, 2, 0, 0, 240, 127, 170, 1, 0, 0, 0, 0, 9, 49, 28, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 3, 0, 0, 0, 0, 0, 0, 0, 0, 195, 165, 0, 0, 195, 165, 1, 128, 72, 8, 160, 15, 32, 78, 208, 7, 208, 7, 112, 23, 80, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 52, 8, 0, 0, 0, 0, 208, 7, 112, 23, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141]
我有结构record.Please见附件
记录可能是用 C 编写的,这无济于事。但是,我的问题是 Header。如果,Struct: 只是一个具有多种数据类型的自定义变量。 Header 的结构是否直接对应于我的数据列表中的第一个整数?例如:r_len =
198、r_nbr=2、r_time=0?我是否继续按顺序向下移动列表以获得子记录?如果是这样,时间定义为自 1.1.1970 以来的秒数。那么这怎么可能来自单个整数呢?如果您能提供任何提示,我将不胜感激。感谢您阅读我的长文post。
Structure Record for the data
嗨,罗伯特,感谢你完成了我刚刚愉快完成的任务!
规范明确表示它以字节为单位传递数据,由 C-like 结构描述。我看不出你是如何读取数据的,但我猜你在这里得到了一个字节列表,因为那里的每个值都小于 256。
因此,通过查看结构,我可以尝试将其转换为 human-readable 形式。这是通过 python:
中的 struct 模块完成的
b = bytes(l)
hdr_data = struct.unpack_from('<hBBHLBBHH', b)
print(hdr_data)
说明
此处我将l
视为初始字节列表。根据您提供的记录结构,我构建了 header:
的格式字符串
hBBHLBBHH
表示:short, byte, byte, word, dword, byte, byte, word, word.
开头的<
表示byte-ordering是little-endian
打印出来的结果是
(710, 40, 4, 0, 1587422083, 0, 0, 0, 0)
这里的第一个值是 r_len
,等于 710。你列表的长度 len(l)
是 711,所以很可能我对列表格式和字节顺序的初步猜测是正确的,结果你不小心有一个多余的字节。
下一步
虽然我们已经基本完成了 one-liner,但我们还没有阅读 sr_desc,也没有设置合适的名称匹配。
让我们更改拆包线以同时消耗 struct sr_desc[8]
:
hdr_data = struct.unpack_from('<hBBHLBBHH' + 'hB'*8, b)
现在我们将所有内容都放在一个元组中。
访问字段的一种非常方便的方法是 namedtuple
from collections import namedtuple
D_O_hdr = namedtuple('D_O_hdr',
('r_len', 'r_nbr', 'dri_level', 'plug_id',
'r_time', 'n_subset', 'res', 'dest_plug_id',
'r_maintype',))
header = D_O_hdr(*hdr_data[:9])
print(header)
您现在可以看到您可以轻松访问每个字段,例如 print(header.r_len)
等等。
相同,但有点棘手,因为 sr_data
:
struct_sr_desc = namedtuple('sr_desc', ('sr_offset', 'sr_type',))
sr_data = [struct_sr_desc(off, typ)
for off, typ in zip(hdr_data[9::2], hdr_data[10::2])]
# Just make sure we've got a list of 8 objects
assert len(sr_data) == 8
这里的问题是我们需要将普通列表转换为结构列表。 hdr_data[9::2]
取 sr_desc
的每个第一个字段(即 sr_offset
),hdr_data[10::2]
取每个第二个字段。 zip
使一对列表成为一对列表。
sr_data[3].type
包含 255,这意味着您在一个结构中只有三个子记录,但解包它们已经在您身上了!只是不要忘记 sr_data[i].offset
包含距 header 末尾的偏移量。这很明显,因为 sr_data[0].offset
总是 0
但无论如何。
完整的脚本在这里:https://repl.it/@FooBarrior/CreativePartialOpenlook
祝你好运!
我正在尝试解析通过串行端口从监视器接收到的数据。我已经成功地在 Python 中编写了一个脚本,以字节字符串的形式从监视器中检索数据,并根据 ISO3309 标准进行了必要的数据转换,最后执行了校验和以确保数据完整性。下面是提取的数据。
[198, 2, 40, 4, 0, 0, 131, 35, 158, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 22, 1, 1, 44, 2, 4, 189, 189, 255, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 131, 35, 158, 94, 51, 58, 0, 0, 0, 18, 2, 128, 10, 129, 1, 128, 1, 128, 1, 128, 1, 0, 0, 0, 1, 0, 2, 128, 2, 128, 2, 128, 1, 128, 1, 0, 0, 0, 2, 0, 2, 128, 2, 128, 2, 128, 1, 128, 0, 0, 0, 0, 11, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 3, 0, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 3, 1, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 11, 0, 4, 128, 3, 0, 0, 0, 12, 0, 4, 128, 0, 0, 0, 0, 13, 0, 1, 128, 0, 0, 0, 0, 14, 0, 1, 128, 3, 0, 0, 0, 0, 0, 1, 128, 2, 128, 2, 128, 1, 128, 7, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 203, 29, 3, 0, 0, 0, 0, 0, 41, 8, 41, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 11, 0, 1, 128, 1, 128, 1, 128, 1, 128, 32, 0, 0, 0, 0, 0, 1, 128, 1, 128, 255, 141, 2, 128, 1, 128, 1, 128, 0, 0, 0, 0, 173, 1, 1, 128, 0, 0, 0, 0, 13, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 14, 0, 1, 128, 1, 128, 1, 128, 1, 128, 0, 0, 0, 0, 65, 0, 131, 35, 158, 94, 0, 0, 0, 0, 18, 2, 1, 128, 1, 128, 1, 128, 1, 128, 3, 0, 0, 0, 0, 0, 1, 128, 1, 128, 4, 128, 1, 128, 1, 128, 1, 128, 73, 13, 0, 0, 176, 192, 0, 0, 226, 1, 0, 0, 198, 2, 0, 0, 240, 127, 170, 1, 0, 0, 0, 0, 9, 49, 28, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 3, 0, 0, 0, 0, 0, 0, 0, 0, 195, 165, 0, 0, 195, 165, 1, 128, 72, 8, 160, 15, 32, 78, 208, 7, 208, 7, 112, 23, 80, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 52, 8, 0, 0, 0, 0, 208, 7, 112, 23, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141]
我有结构record.Please见附件
记录可能是用 C 编写的,这无济于事。但是,我的问题是 Header。如果,Struct: 只是一个具有多种数据类型的自定义变量。 Header 的结构是否直接对应于我的数据列表中的第一个整数?例如:r_len =
198、r_nbr=2、r_time=0?我是否继续按顺序向下移动列表以获得子记录?如果是这样,时间定义为自 1.1.1970 以来的秒数。那么这怎么可能来自单个整数呢?如果您能提供任何提示,我将不胜感激。感谢您阅读我的长文post。
Structure Record for the data
嗨,罗伯特,感谢你完成了我刚刚愉快完成的任务!
规范明确表示它以字节为单位传递数据,由 C-like 结构描述。我看不出你是如何读取数据的,但我猜你在这里得到了一个字节列表,因为那里的每个值都小于 256。
因此,通过查看结构,我可以尝试将其转换为 human-readable 形式。这是通过 python:
中的 struct 模块完成的b = bytes(l)
hdr_data = struct.unpack_from('<hBBHLBBHH', b)
print(hdr_data)
说明
此处我将l
视为初始字节列表。根据您提供的记录结构,我构建了 header:
hBBHLBBHH
表示:short, byte, byte, word, dword, byte, byte, word, word.
<
表示byte-ordering是little-endian
打印出来的结果是
(710, 40, 4, 0, 1587422083, 0, 0, 0, 0)
这里的第一个值是 r_len
,等于 710。你列表的长度 len(l)
是 711,所以很可能我对列表格式和字节顺序的初步猜测是正确的,结果你不小心有一个多余的字节。
下一步
虽然我们已经基本完成了 one-liner,但我们还没有阅读 sr_desc,也没有设置合适的名称匹配。
让我们更改拆包线以同时消耗 struct sr_desc[8]
:
hdr_data = struct.unpack_from('<hBBHLBBHH' + 'hB'*8, b)
现在我们将所有内容都放在一个元组中。
访问字段的一种非常方便的方法是 namedtuple
from collections import namedtuple
D_O_hdr = namedtuple('D_O_hdr',
('r_len', 'r_nbr', 'dri_level', 'plug_id',
'r_time', 'n_subset', 'res', 'dest_plug_id',
'r_maintype',))
header = D_O_hdr(*hdr_data[:9])
print(header)
您现在可以看到您可以轻松访问每个字段,例如 print(header.r_len)
等等。
相同,但有点棘手,因为 sr_data
:
struct_sr_desc = namedtuple('sr_desc', ('sr_offset', 'sr_type',))
sr_data = [struct_sr_desc(off, typ)
for off, typ in zip(hdr_data[9::2], hdr_data[10::2])]
# Just make sure we've got a list of 8 objects
assert len(sr_data) == 8
这里的问题是我们需要将普通列表转换为结构列表。 hdr_data[9::2]
取 sr_desc
的每个第一个字段(即 sr_offset
),hdr_data[10::2]
取每个第二个字段。 zip
使一对列表成为一对列表。
sr_data[3].type
包含 255,这意味着您在一个结构中只有三个子记录,但解包它们已经在您身上了!只是不要忘记 sr_data[i].offset
包含距 header 末尾的偏移量。这很明显,因为 sr_data[0].offset
总是 0
但无论如何。
完整的脚本在这里:https://repl.it/@FooBarrior/CreativePartialOpenlook
祝你好运!