如何从MCU UART解析不确定长度的数据包?

时间:2015-12-02 17:48:37

标签: c parsing microcontroller uart osc

我正在尝试通过以太网到串行转换器将新的微控制器连接到现有的OSC(开放式声音控制)网络。

使用以下格式发送OSC消息:

  • OSC地址模式:/ string / optional substring - >总是32位打包/ DWORD与末尾的额外NULL字节对齐
  • 类型标签:int32(i),float32(f),string(s)
  • 数据:对于某些模式,这是一个已知的长度;对于其他人来说,它的长度是不确定的

我对如何最好地划分代码以及如何缓冲这个问题感到困惑。在我的UART接收ISR中,我希望将传入的字节转储到SRAM缓冲区,然后在主循环中对它们进行解码,但我不确定如何使用不确定长度的数据包执行此操作。我从来没有使用过一个可变长度的数据包,它没有在某个地方指示数据包中的数据包大小。似乎没有任何EOP /页脚指示数据包的完成,您将根据类型标记解码x个字节。

一些担忧: 1.如何调整缓冲区的大小?是的,我可以动态地执行此操作,但如果可能的话,我宁愿避免这种开销。这导致我走向循环缓冲区,但是如何在继续解码可变长度数据包的同时从主循环中拉出我需要的东西? 2.在ISR中应该完成多少解码?我是否在主循环中设置某种类型的状态机,它根据传入字节的ISR解码进行,然后在推进FSM时刷新这些字节?

寻找有关如何最好地解决此问题/构建代码的任何建议/指导。提前谢谢。

2 个答案:

答案 0 :(得分:1)

UART接收ISR应该只是从UART读取输入字节并将其复制到循环缓冲区。我不会对ISR中的字节进行任何解码/解析/解释。循环缓冲区应足够大,以包含您希望接收的最大消息(如果消息突发的速度快于主循环可以处理它们,则更大的消息)。

主循环应使用状态机将字节流解析为消息。状态可以命名为READ_ADDRESS,READ_TYPE和READ_DATA。或者,您可能希望为每种消息类型设置唯一的READ_DATA状态。

从高级视图来看,每个状态都应该从循环缓冲区中读取适当的字节数,然后进入下一个状态。听起来数据状态处理函数必须足够智能才能计算出适当的数据字节数。如果您必须解释一些数据以便计算数据长度,那么您可能需要考虑将READ_DATA状态分解为两种状态,一种用于读取足以计算长度而另一种用于读取其余数据。< / p>

在设计状态处理程序函数时,请考虑尚未在循环缓冲区中接收到适当的字节数。从低级别视图,当没有足够的字节可用时,状态处理程序应返回主循环。这允许主循环服务于应用程序的其他部分,同时ISR接收更多字节。然后当你的主循环再次调用状态机时,状态处理程序应该从它停止的地方开始。

答案 1 :(得分:0)

因此,假设您有一个协议,其中数据包具有任意大小,但它们具有一些可识别的模式。对于某些识别技术,请参见下文,首先是阅读过程。

  • 中断:它只是将字节加载到循环缓冲区中,递增写指针(并在缓冲区已满时推出读指针,因此它以稍微干净的方式丢弃字节)。

    < / LI>
  • 主程序:轮询缓冲区。它从当前的读指针开始,并寻找是否可以识别数据包。如果找不到任何内容,它会尝试从读取指针+ 1中寻找,依此类推,直到覆盖缓冲区为止。读指针保持不变(这很重要)。如果可以识别一个数据包,它会处理它,并且(只有这样)将读指针设置在数据包的末尾,从而从循环缓冲区中丢弃它的内容。

为什么在没有数据包被识别的情况下保持读指针不变是很重要的?由于随着进一步的字节流入,更大的数据包可能会在以后完成。

当缓冲区满了垃圾,因此中断正在推出读指针,您可能会遇到危险,这取决于您设计IT和主线程之间的交互的谨慎程度。通常有任何合理的实施,这里不应该有太多的问题。 IT中的推送行为比通过写指针简单地传递读指针(因此间接地丢弃整个缓冲区)更加一致。

通常这种方法适用于任何事情。有一种情况,我的数据包类型包含一个较小的协议正确的数据包。现在这是令人讨厌的修复,以获得外包这些情况! (上面的算法将获取内部数据包,因为它可能会更快到达)

那么识别呢?

  • 如果您有任何可识别的标题,同步字节或其他内容,则更容易获得开头(如果从缓冲区中的给定起始偏移量看起来不像正确的标题,您可以快速保释)。

  • 您可能需要在标识中进行部分处理(当然在主程序中)以确定数据包的长度。最简单的,如果有任何直接长度指示,但如果没有它,如果有一个数据包类型标识(这意味着一个长度,这似乎是你的情况),它就没那么难了。

  • 如果有任何校验和或CRC,检测数据包也是一件好事。使用它作为识别的一部分,即使复杂的标题似乎是正确的:如果它是正确的,那么你肯定有一个有效的数据包。

  • 如果根本没有校验和或CRC,请使用数据包所具有的任何固定位,或协议对数据包中的某些值施加的任何固定范围,以查看它们是否与有效数据包匹配。

使用这些原则我能够解决相当破坏的协议,我的意思是假设几乎没有任何框架的数据包之间的延迟,延迟作为分隔符,在数据通过互联网传播后不再存在和/ /或者由运行操作系统的PC提取(在操作系统环境中,中断和循环缓冲区被操作系统自己的缓冲机制取代,检测数据包的原理是相同的。)