我目前正在我的固件中为UART通信编写代码。我收到的每个字节都有一个中断(这意味着我一次不能得到一块数据,1字节,但在下面的示例中,我将它们存储在一块数据中,仅用于模拟数据解析)。
我有一个动态消息长度格式,如下面的代码所示。我可以知道解析这个消息的最有效和最优雅的方法是什么吗?我相信我现在的代码还可以进一步改进。
#include <stdint.h>
typedef struct {
uint8_t header_DLE;
uint16_t id;
uint8_t msg_command;
uint16_t msg_length;
uint8_t data[400];
uint8_t footer_DLE;
uint8_t footer_BCC;
} Serial_Rx_Data;
Serial_Rx_Data _rx_data;
static int _rx_index;
static uint8_t _rawData[512];
int main()
{
uint8_t data[18];
//Message format
data[0] = 0x10; //DLE
data[1] = 0x03; //ID
data[2] = 0; //ID
data[3] = 0x03; //Command
data[4] = 0x03; //Length - determines the data length
data[5] = 0; //Length
data[6] = 0x41; //Data
data[7] = 0x42; //Data
data[8] = 0x43; //Data
data[9] = 0x03; //DLE
data[10] = 0xfa; //BCC
//Simulate getting data every byte
for (int i = 0; i <= 10; i++) {
_rawData[_rx_index] = data[i];
if (_rx_index == 5) {
_rx_data.header_DLE = _rawData[0];
_rx_data.id = _rawData[2] << 8 | _rawData[1];
_rx_data.msg_command = _rawData[3];
_rx_data.msg_length = _rawData[5] << 8 | _rawData[4];
}
//Get the length of data
if ((_rx_index == 6) && (_rx_data.msg_length > 0)) {
for (int j = 0; j < _rx_data.msg_length; j++) {
_rx_data.data[j] = _rawData[6 + j];
}
}
//Get the last 2 byte
if (_rx_index == (_rx_data.msg_length + 6 + 1)) {
_rx_data.footer_DLE = _rawData[6 + _rx_data.msg_length];
_rx_data.footer_BCC = _rawData[6 + _rx_data.msg_length + 1];
//Complete parsing
//Callback to other function
}
_rx_index++;
}
return 0;
}发布于 2015-06-02 09:09:35
以下是一些可以帮助您提高代码质量的东西。
中的消息解析
您没有显式地这样说,但是从上下文来看,您似乎试图在中断处理程序中解析串行接收的消息。这通常不是个好主意。中断处理程序应该是快速的,并且能够完成尽可能少的工作量。对于串行消息协议,这通常意味着读取每个字符,将其放入内存缓冲区(通常作为循环缓冲区实现)并更新指针。然后,不在中断中的主例程读取缓冲区的内容,并执行任何消息解析/处理。
在这种情况下,消息长度似乎是8个字节(6个标头+2个预告片),加上封闭式数据的大小。消息的开头似乎也有某种特殊的标记。因此,快速检查消息解析器如下所示:
如果这两个问题的答案都是“否”,则不可能是真正的消息,因此数据可能会留在缓冲区中,直到收到更多的消息。如果这两个问题的答案都是“是”,那么这可能是一个信息。接下来的步骤可能是:
如果这两个问题的答案都是“是”,那么您实际上可以对消息采取行动(通常将其传递给更高层的协议处理程序)。
像这样解析消息的典型方法是使用状态机。在这种情况下,各州可能是:
也经常有错误和超时的状态。
这段代码中到处都是“魔术数字”,即未命名的常量,如400、512、10、5等。一般来说,最好避免这种情况,并给这些常量取有意义的名称。这样,如果需要更改任何内容,您就不必在代码中搜索"5“的所有实例,然后尝试确定这个特定的5是否意味着消息结构中的偏移量或具有相同值的其他常量。
的防范
为数据分配一个固定的400个字节可能是可以的,但是如果是这样的话,那么您绝对需要在复制消息之前确保消息在这个空间中是合适的。如果不这样做,就有可能出现缓冲区溢出。
https://codereview.stackexchange.com/questions/92427
复制相似问题