1

我有一个通过串行接口连接到 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 并派生其他消息?

4

1 回答 1

1

这真的取决于。两种主要方式将被线程化(就像你提到的那样)和事件。

线程代码很棘手,因为您可以轻松引入竞争条件。你测试了一百万次的代码在工作了几天、几周或几年后偶尔会出错并做错事。很难“证明”事情总是会正确运行。像“i++”这样看似微不足道的东西突然变成了有漏洞的抽象。(看看为什么 i++ 在单核机器上不是线程安全的?

另一种选择是事件编程。基本上,您有一个在所有文件句柄上执行 select() 的主循环。任何准备好的东西都会被查看,并且您尝试在不阻塞的情况下读取/写入尽可能多的字节。(通过 O_NONBLOCK)。有两个棘手的部分:1)在没有办法返回主循环的情况下,您绝不能进行长时间计算,以及 2)您绝不能进行阻塞操作(内核停止您的进程等待读取或写入) .

在实践中,大多数程序的计算时间不长,而且审核少量代码以阻止调用比审核比赛更容易。(尽管在不阻塞的情况下进行 DNS 比应有的要棘手。)

事件代码的好处是不需要锁定(无需担心其他线程)并且它浪费的内存更少(在您创建大量线程的一般情况下。)

最有可能的是,您想使用串行库。termios 处理只是开销和杂散字节做坏事的机会。

于 2013-04-24T03:09:29.620 回答