重建 USB CDC 流

Reconstruct USB CDC stream

我在 STM32 上有一个 USB CDC 接口,我向其发送的消息长度可能超过一个 64 字节的块。这意味着我得到 CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) 的多个回调,我必须在其中将传入数据复制到另一个缓冲区(例如 ringbuffer)。

我的问题是,我如何知道数据是属于新消息还是前一个(更大)消息的延续? 我可以说的是,如果到达的字节少于 64 个,我可以假设消息是完整的。但是,如果缓冲区中恰好有 64 个字节,如果没有更多消息传来,我在技术上必须等待。即便如此,我还要等多久才能不把它们和新的混在一起?

USB CDC 和所有源自 RS-232 的串行协议实现基于流的通信,即潜在的无限字节流。

他们没有实现基于消息的通信。因此,他们没有消息的概念,也没有消息开始和消息结束的概念。

USB 的较低层是基于消息的。因此,您可能会观察到看起来像基于消息的通信的模式。您可能还认为 USB CDC 是基于消息的,因为 STM32cube 框架公开了一个 USB API,只要低级 USB 消息到达,它就会传送更多数据。

但是,只有在发送小块数据且中间有停顿并且 USB 总线大部分时间处于空闲状态时,才能观察到此行为。如果速度提高或 USB 总线变得更忙,它就会崩溃。

然后您的 PC 将开始合并数据块。这可以通过尽可能快地发送 100 次 10 字节来轻松测试。前 10 个字节可能在其自己的数据包中发送。但是剩下的数据会被合并并作为64字节的数据包发送(除了最后几个字节)。

所以如果你想在面向流的协议之上有一个面向消息的协议,两种典型的方法是:

  • 在消息之间使用分隔符。例如:如果您有一个人类可读的文本协议,换行符通常用作分隔符。一旦你遇到换行符,你就知道你有一个完整的消息(即行)。

  • 在消息末尾使用长度指示符。这对二进制协议很有用。前两个字节可以包含以字节为单位的消息长度,编码为 16 位数字。所以当消息完成时会很明显。

另请注意,一个接收到的数据包可以包含多个消息,或者一个消息的结尾和下一个消息的开头。