#stm32 #cdc
#stm32 #cdc
Вопрос:
У меня есть интерфейс USB CDC на STM32, на который я отправляю сообщения, которые могут быть длиннее одного фрагмента из 64 байт. Это означает, что я получаю несколько обратных CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
вызовов, в которых мне пришлось бы копировать входящие данные в другой буфер (например, ringbuffer).
Моя проблема в том, как мне узнать, принадлежат ли данные новому сообщению или являются продолжением предыдущего (большего) сообщения? Что я могу сказать, так это то, что если поступило менее 64 байт, я могу предположить, что сообщение завершено. Но если в буфере находится ровно 64 байта, мне технически придется подождать, если больше не будет приходить сообщений. И даже тогда, сколько времени мне нужно ждать, чтобы не перепутать их с новыми?
Ответ №1:
USB CDC и все последовательные протоколы, производные от RS-232, реализуют потоковую связь, то есть потенциально бесконечный поток байтов.
Они не реализуют обмен данными на основе сообщений. Поэтому у них нет понятия сообщений, а также понятия начала и конца сообщения.
Нижние уровни USB основаны на сообщениях. Таким образом, вы можете наблюдать шаблоны, которые выглядят как обмен сообщениями на основе сообщений. Вы также можете подумать, что USB CDC основан на сообщениях, потому что платформа STM32Cube предоставляет USB API, который будет доставлять больше данных при поступлении низкоуровневого USB-сообщения.
Но такое поведение может наблюдаться только в том случае, если небольшие фрагменты данных отправляются с промежуточными паузами и если шина USB в основном простаивает. Он разрушается, если скорость увеличивается или шина USB становится более загруженной.
Затем ваш компьютер начнет объединять фрагменты данных. Это можно легко проверить, отправив 100 раз по 10 байт как можно быстрее. Первые 10 байтов, вероятно, отправляются в собственном пакете. Но остальные данные будут объединены и отправлены в виде пакетов по 64 байта (за исключением последних нескольких байтов).
Итак, если вы хотите иметь протокол, ориентированный на сообщения, поверх протокола, ориентированного на поток, два типичных подхода:
- Используйте разделитель между сообщениями. В качестве примера: если у вас есть удобочитаемый текстовый протокол, перевод строки часто используется в качестве разделителя. Как только вы сталкиваетесь с символом перевода строки, вы знаете, что у вас есть полное сообщение (т. Е. Строка).
- Используйте индикатор длины в конце сообщения. Это полезно для двоичных протоколов. Первые два байта могут содержать длину сообщения в байтах, закодированную в виде 16-битного числа. Это будет очевидно, когда сообщение будет завершено.
Также обратите внимание, что принятый пакет может содержать несколько сообщений или конец сообщения и начало следующего сообщения.