python 中解析缓冲区字符串的最佳方法

Best approach to parse buffer string in python

我正在开发一个通过 Uart 发送命令的嵌入式系统。 Uart 工作在 115200 波特

在PC端我想读取这些命令,解析它们并执行相关操作。

我选择python作为构建脚本的语言。

这是从嵌入式系统收到的典型命令:

S;SEND;40;{"ID":"asg01","T":1,"P":{"T":180}};E

每条消息以S开头,以E结尾。 与消息关联的命令是 "SEND",有效载荷长度是 40。

我的想法是读取来自 UART 的字节并:

解析来自异步 uart 的所有字节的最佳方法是什么?

我担心的是由于解析错误(或缓慢)导致的消息丢失。

感谢您的帮助!

BR, 费德里科

此格式 几乎 可解析为 csv,但不完全是,因为第四个字段是 JSON,您可能无法保证 JSON 不包含任何带有嵌入分号的字符串。所以,我想你可能只想使用字符串(或者更确切地说,字节)操作函数:

def parsemsg(buf):
    s, cmd, length, rest = buf.split(b';', 3)
    j, _, e = rest.rpartition(b';')
    if s != b'S' or e != b'E':
        raise ValueError('must start with S and end with E')
    return cmd.decode('utf-8'), int(length), json.loads(j)

然后:

>>> parsemsg(b'S,SEND,40,{"ID":"asg01","T":1,"P":{"T":180}},E')
('SEND', 40, {'ID': 'asg01', 'T': 1, 'P': {'T': 180}})

实际的分号解析部分在我的笔记本电脑上需要 602ns,decodeint 将其提高到 902ns。另一方面,json.loads 需要 10us。所以,如果你担心性能,JSON 部分真的是唯一重要的部分(尝试我碰巧安装的第三方 JSON 库,最快的仍然是 8.1us,这也好不了多少)。你还不如让其他一切都简单而健壮。

此外,考虑到您正在以 115000 波特率读取此文件,您无法以超过 6 毫秒的速度获取这些消息,因此首先花费 11us 来解析它们根本算不上什么问题。

在我的日常工作中,我编写了用于嵌入式系统的软件和通过 USB 电缆相互通信的 PC,使用 UART 协议,波特率为 115,200。

我看到你用 PySerial 标记了你的 post,所以你已经知道 Python 最流行的串行端口通信包。我要补充一点,如果您使用的是 PyQt,那么该包中也包含一个串行模块。

115,200 波特对于现代台式电脑来说并不快。我怀疑您在 PC 端所做的任何解析都无法跟上。我使用 PyQt 实时解析数据流并绘制数据图表。

我在使用 UART 进行嵌入式系统和 PC 之间的通信时注意到,某些数据偶尔会损坏。一个字节可能会出现乱码、重复或丢失。此外,即使没有添加或删除任何字节,您偶尔也可以在缓冲区中只有部分数据包时执行读取,并且读取会提前终止。如果您使用 40 字节的固定读取长度并相信每次读取都将始终与上面显示的数据包完全对齐,那么您经常会出错。

为了解决这类问题,我在Python中写了一个FIFO class,在FIFO头部消耗串口数据,在尾部产生有效数据包,丢弃无效数据包数据。我的 FIFO 容纳的字节数是我的数据包的 3 倍,所以如果我使用特定序列寻找数据包边界,我有很多 signposts。

更多建议:在Python 3 中工作,如果可以选择,它会更干净。使用字节和字节数组对象。不要使用 str,因为你会发现自己在 Unicode 和 ASCII 之间来回转换。