LINUX.ORG.RU

Виртуальный COM-порт, Qt и бинарные данные

 , ,


0

1

Имеется железка, которая реализует класс USB CDC. Она посылает с некоторой периодичностью пакеты данных длиной 32 байта. Максимальный размер пакета конечной точки BULK как раз 32 байта. Таким образом каждый пакет данных приходит целиком и они не могут перемешаться на этапе передачи по USB. Чисто гипотетически если работать через libusb, то проблем быть не должно.

Но я пытаюсь работать через QtSerialPort и данные приходят не очень хорошо. Я делаю port->read(buffer, 32) в обработчике сигнала readyRead. В итоге сразу после открытия порта до первого пакета GUI висит (вероятно, Linux закешировал несколько последних байт и сигнал readyRead сработал сразу после открытия порта, но 32 байта не набралось, поэтому повис блокирующий вызов). И данные выдаются неверные (скорее всего съехало разбиение на 32-байтовые пакеты).

В общем, надо как-то отключить буферизацию и сбросить все буферы после открытия, а потом читать по 32 байта.

★★★★★

В общем, надо как-то отключить буферизацию и сбросить все буферы после открытия, а потом читать по 32 байта.

че спросить-то хотел? ;)

зы. эти вопросы решаются уровнем прикладного протокола, заголовки там, суммы и пр. опираться на 32 байта - грех.

dib2 ★★★★★
()
Ответ на: комментарий от dib2

Хотел спросить как это понадёжнее сделать.

Насчёт протокола: что можете посоветовать? Там микроконтроллер, а данных может быть много, поэтому не стоит использовать что-то ресурсоёмкое. В данных могут встречаться любые байты, включая нули и переносы строк.

KivApple ★★★★★
() автор топика

Не знаю, поможет ли. Тоже использовал этот QSerialPort и немного помучился. В итоге вынес его в отдельный поток и уже там по readyRead проверял значение bytesAvailable. Вот когда оно равнялось нужному мне значению, вычитывал буфер. Работает, вроде, нормально.

baldman88
()
Ответ на: комментарий от KivApple

Самая простая схема пакета: <маркер начала пакета> <длина пакета> <данные> <контрольная сумма>. При старте отбрасываешь все до тех пор, пока не встретишь маркер начала пакета (придумай его сам, оцени, какой байт или пара байтов должны встречаться реже всего). После того, как нашел маркер, получаешь длину пакета и читаешь данные в буфер до контрольной суммы. Потом считаешь контрольную сумму полученных данных и сверяешь ее с той, что пришла. Если они совпадут, значит это нормальный пакет, его можно передавать на обработку, иначе просто неповезло попасть вместо маркера начала пакета на кусок данных, поэтому тупо ждешь следующий маркер. Описанная схема реализуется тривиальным конечным автоматом за 15 минут.

m0rph ★★★★★
()

(вероятно, Linux закешировал несколько последних байт и сигнал readyRead сработал сразу после открытия порта, но 32 байта не набралось, поэтому повис блокирующий вызов). И данные выдаются неверные (скорее всего съехало разбиение на 32-байтовые пакеты).

Бред №1.

1. По USB приходят *всегда* сразу все данные целиком и ничего не может висеть. 2. QSerialPort работает в неблокирующем режиме, и также нчего и нигде не может висеть.

В общем, надо как-то отключить буферизацию и сбросить все буферы после открытия

QSerialPort::clear() - если так уж необходимо.

а потом читать по 32 байта.

Бред №2.

Никто не гарантирует что сделав read(32) прочитается 32 байта. т.к. может прочитаться меньше (сколько доступно). Нужно проверять с помощью bytesAvailable() в каждом readyRead().

kuzulis ★★
()
Ответ на: комментарий от baldman88

Тоже использовал этот QSerialPort и немного помучился

В чем мучения то? Для этого есть соответствующие форумы или баг-трекер.

В итоге вынес его в отдельный поток и уже там по readyRead проверял значение bytesAvailable.

Это имеет смысл если не хватает производительности CPU и пр. (можно смотреть в top на загрузку CPU и пр. при работе приложения).

И да.. в Linux QSerialPort жрет ресурсы (нет времени чтобы в этом разобраться). Но это в случае если идет непрерывный стрим.

Поэтому проще всегда перемещать QSerialPort в отдельный поток дабы сохранить нервы и время.

kuzulis ★★
()
Ответ на: комментарий от kuzulis

Это имеет смысл если не хватает производительности CPU и пр.

Машина на которой это работает древняя до ужаса (Celeron начала 2000-х, 256 МБ).

Но это в случае если идет непрерывный стрим.

Машина посылает в устройство стартовый байт и ждёт ответа от него, после получения необходимого количества ответных байт всё повторяется, так что можно сказать, что непрерывно.

baldman88
()
Ответ на: комментарий от kuzulis

В чем мучения то? Для этого есть соответствующие форумы или баг-трекер.

Думаю, где я Ваш ник видел, теперь вспомнил. Вы, случайно, не автор QSerialPort?

baldman88
()

Делать ставку на число байт на входе в QSerialPort - фу таким быть :)

Просто должен быть протокол что даже если данные прилетят по 1 байту - всё равно должно работать. Иного не дано. Даже в TCP/UDP я такого подхода придерживаюсь и не подвело.

I-Love-Microsoft ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.