stm32 - 重建 USB CDC 流
问题描述
我在 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,该 API 将在低级 USB 消息到达时提供更多数据。
但是,只有在发送小块数据且中间有暂停并且 USB 总线大部分处于空闲状态时,才能观察到这种行为。如果速度提高或 USB 总线变得更忙,它就会崩溃。
然后您的 PC 将开始合并数据块。这可以通过尽可能快地发送 100 次 10 字节来轻松测试。前 10 个字节可能在其自己的数据包中发送。但剩余的数据将被合并并作为 64 字节的数据包发送(最后几个字节除外)。
所以如果你想在面向流的协议之上有一个面向消息的协议,两种典型的方法是:
在消息之间使用分隔符。例如:如果您有一个人类可读的文本协议,则通常使用换行符作为分隔符。一旦你遇到换行符,你就知道你有一个完整的消息(即行)。
在消息末尾使用长度指示符。这对于二进制协议很有用。前两个字节可以包含以字节为单位的消息长度,编码为 16 位数字。当消息完成时,这将是显而易见的。
还要注意,一个接收到的数据包可以包含多个消息,或者一个消息的结尾和下一个消息的开始。
推荐阅读
- ruby - 在 Ruby 结构中正确定义常量
- sql - Oracle - 根据最新日期选择记录
- javascript - JavaScript 三元运算符:document.body.className = document.body.className != "cls" ? “cls”:“”;?
- android - 使用 dagger android 时如何在通知上创建 viewmodel 的实例
- kml - 工作多年的 KML/KMZ 文件不再工作
- javascript - 您可以使用phonegap中的缓存来保存图像或访问android中的文件夹吗?
- css - 试图获取 section.class1 而不是 section.class1, scss
- html - 当表格垂直扩展至其最大高度时 - 使元素在下一个表格单元格列中弹出
- sql-server - 无法使用 SQL Server 数据库访问 Cloud SQL 上的导入数据
- php - phpoffice/电子表格如何在图表中为每一列添加一个值