Я работаю над встроенной системой, которая отправляет команды через Uart. Uart работает на 115200 бод
На стороне ПК я хочу прочитать эти команды, проанализировать их и выполнить соответствующее действие.
Я выбираю Python в качестве языка для создания скрипта.
Это типичная команда, полученная от встроенной системы:
S;SEND;40;{"ID":"asg01","T":1,"P":{"T":180}};E
Каждое сообщение начинается с S и заканчивается на E. С сообщением связана команда «ОТПРАВИТЬ», а длина полезной нагрузки - 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}})
Фактический анализ точки с запятой занимает 602 нс на моем ноутбуке, decode
и int
увеличивают это значение до 902 нс. json.loads
, напротив, требует 10 мкс. Итак, если вы беспокоитесь о производительности, часть JSON - это действительно единственная часть, которая имеет значение (пробуя сторонние библиотеки JSON, которые я установил, самая быстрая из них по-прежнему 8.1us, что не намного лучше). Вы могли бы также сделать все остальное простым и надежным.
Кроме того, учитывая, что вы читаете это со скоростью 115000 бод, вы не можете получать эти сообщения быстрее, чем примерно 6 мс, поэтому потратить 11 мс на их синтаксический анализ - это даже не проблема.
Да, я начал использовать запятую для разделения сообщения, но хочу отправить JSON. ТАК Я изменил "," на ";"
@Federico В примере в вашем вопросе используется ,
, а не ;
. Но в любом случае, можете ли вы гарантировать, что в JSN не будет строк с точкой с запятой? Если нет, вам все равно придется делать это в два этапа вместо одного.
Обновляю пример прямо сейчас. Что касается JSON с столбцами, я добавил json во встроенную систему и могу избежать использования ";" в json. Есть ли у вас какие-либо предложения о том, как создать сообщение на встроенной стороне?
Если вы можете гарантировать отсутствие точек с запятой, возможно, вы можете сделать это немного проще, обернув csv.reader(f, delimiter=';')
вокруг входного потока, а затем просто позволив ему выполнить разделение за вас. Но я думаю, что код, использующий split
и partition
, уже должен быть достаточно простым, поэтому я бы не стал слишком об этом беспокоиться. Но между тем ... есть ли причина, по которой вы не можете просто сделать все, включая команду и длину, текстом JSON?
В своей повседневной работе я написал программное обеспечение для встраиваемой системы и ПК, обменивающихся данными друг с другом через USB-кабель, используя протокол UART на скорости 115 200 бод.
Я вижу, что вы пометили свой пост с помощью PySerial, так что вы уже знаете о самом популярном пакете Python для связи через последовательный порт. Я добавлю, что если вы используете PyQt, в этот пакет также включен последовательный модуль.
115 200 бод - это не так быстро для современного настольного ПК. Я сомневаюсь, что любой синтаксический анализ, который вы делаете на стороне ПК, не успеет. Я анализирую потоки данных и строю графики своих данных в реальном времени с помощью PyQt.
Что я заметил в своей работе со связью между встроенной системой и ПК через UART, так это то, что некоторые данные иногда повреждаются. Байт может быть искажен, повторен или отброшен. Кроме того, даже если байты не добавляются или не отбрасываются, вы можете иногда выполнять чтение, пока в буфере находится только часть пакета, и чтение завершится раньше. Если вы используете фиксированную длину чтения в 40 байтов и уверены, что каждое чтение всегда будет соответствовать пакету данных, как показано выше, вы часто ошибаетесь.
Чтобы решить такие проблемы, я написал класс FIFO на Python, который потребляет данные последовательного порта в начале FIFO, выдает действительные пакеты данных в конце и отбрасывает недопустимые данные. Мой FIFO содержит в 3 раза больше байтов, чем мои пакеты данных, поэтому, если я ищу границы пакета с использованием определенных последовательностей, у меня есть множество указателей.
Еще несколько рекомендаций: работайте с Python 3, если у вас есть выбор, он чище. Используйте байты и объекты байтового массива. Не используйте str, потому что вы обнаружите, что конвертируете туда и обратно между Unicode и ASCII.
Спасибо за предложение. Я буду следовать вашим подсказкам. BR
Какая часть этой «полезной нагрузки»? Бит JSON составляет 34 байта, всего 46, все это за вычетом битов S и E составляет 42… Я не вижу ничего очевидного, длиной в 40 байтов.