首页 > 解决方案 > 重建 USB CDC 流

问题描述

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

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

标签: stm32cdc

解决方案


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

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

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

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

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

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

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

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

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


推荐阅读