【发布时间】:2013-04-24 00:35:01
【问题描述】:
我有一个通过串行接口连接到 BeagleBone 计算机的设备。我以简单的二进制格式进行通信,例如
|MessagID (1 Byte) | Data (n Bytes) | checksum (2 bytes) |
每个命令的消息长度是固定的,这意味着在收到命令的第一个字节后知道要读取多少字节。经过一些初始设置通信后,它每 20 毫秒发送一次数据包。
我的方法是使用 termios 或类似串行库的东西,然后开始一个循环这样做(a:
while(keepRunning)
{
char* buffer[256];
serial.read(buffer, 1)
switch(buffer[0])
{
case COMMAND1:
serial.read(&buffer[1], sizeof(MessageHello)+2); //Read data + checksum
if (calculateChecksum(buffer, sizeof(MessageHello)+3) )
{
extractDatafromCommand(buffer);
}
else
{
doSomeErrorHandling(buffer[0]);
}
break;
case COMMAND2:
serial.read(&buffer[1], sizeof(MessageFoo)+2);
[...]
}
}
extractDatafromCommand 然后会创建一些结构,例如:
struct MessageHello
{
char name[20];
int version;
}
将所有内容放在自己的读取线程中,并使用信号量(或简单标志)向程序的其他部分发出新数据包的可用性信号。
这是一个可行的解决方案还是有更好的改进(我假设是这样)?
也许创建一个抽象类 Message 并派生其他消息?
【问题讨论】:
-
您可以添加一个退出while循环的命令,这在某些情况下可能很有用
-
我认为拥有该阅读线程是个好主意。最好不要阻塞命令。一些错误恢复机制也会很有用。
-
您可以为每条消息定义一个结构,然后使用 sizeof() 代替硬编码的常量。
-
您的程序似乎假定接收到的第一个字节是消息帧的第一个字节。这种帧同步将在它读取消息时持续存在。如果串行字符丢失,所有这一切都会中断。查找并维护消息帧对于稳健的串行通信协议至关重要。消息 ID 和 2 个校验和字节可能是查找可变长度消息帧的挑战。您可能需要添加一个固定值同步字节来简化寻找消息帧开始的过程。
-
“固定字节” 具有误导性。您有 可变 长度的消息。长度是从 messageID 派生/推导出来的,而不是显式存储在消息中只是一个小细节。与固定长度的消息相比,对于可变长度的消息,搜索消息帧的开头更加困难。如果您的 USART 具有 “接收器超时” 功能,那么您可以使用该计时器来帮助检测单个消息帧(即消息之间的 20 毫秒)。但是检测消息之间的时间间隔必须由硬件完成,而不是软件。
标签: c++ linux serial-port protocols