在C中解析Bytestream(嵌入式编程)

时间:2015-12-15 22:59:57

标签: c arrays parsing char bytestream

所以我在两个微控制器之间有一个通信系统,我在它们之间发送数据,即传感器数据从一个μC到另一个,并返回命令。 传感器数据取自一个结构并放入一个框架,看起来像这样(标识符“SENSORFRAME”不是常数;它取决于框架中的内容):

sprintf(message, "\:\\SENSORFRAME\:%.2f;%.2f;%.2f;%d;%d;%u\r\r",
               input.temperature, input.current, input.voltage,
               input.dutycycle,input.lightsensor, input.message);

导致像这样的框架:

:\SENSORFRAME:-12.40;1.42;0.53;500;1200;8\r\r

或者命令帧:

sprintf(message, "\:\\COMMANDFRAME\:%u;%.5f\r\r", input.command, input.data);

导致像这样的框架:

:\COMMANDFRAME:3;1.42\r\r

当字节流到达一个微控制器时,它被写入一个简单的环形缓冲区,直到它被处理完毕。

现在我的两个问题是,首先,在字节流中识别帧的最佳方法是什么,即“:”和“\ r \ r”之间的所有内容,其次是如何有效地将其解析回结构 - strtok(“;”和“:”)以及atoi / atof的某种组合?

1 个答案:

答案 0 :(得分:0)

如果在最后读取双回车符(CR)之前不处理帧类型,然后在双CR之后插入空字节,则可以使用{{{}提取帧类型信息。 1}}或其他解析技术。

sscanf()

现在,您将char frame_type[32]; char colon[2]; int offset; if (sscanf(ring_buffer, ":\\%31[^:]%[:]%n", frame_type, colon, &offset) != 2) …deal with malformatted frame… 中的帧类型作为字符串。稍微奇怪的frame_type只匹配冒号;但重要的是,它被视为成功转换,%[:]转换有效。如果它改为:

%n

你不知道尾随冒号是否匹配,你不知道if (sscanf(":\\%31[^:]:%n", frame_type, &offset) != 1) …deal with malformatted frame… 是否持有有效值(字符串中找到前一个字符冒号的偏移量)。

您至少有两种帧类型;总共有多少人(目前,未来可能有)?在一个层面上,没关系。您可以对可能的帧类型使用一系列字符串比较,或者您可以使用帧类型字符串的哈希值并将其与有效哈希值集进行比较,或者您可以设计另一种机制。

一旦知道了哪种帧类型,就会知道用于读取其余数据的格式字符串。由于您阅读了双CR,您知道结尾包含 - 您无需再次验证它。

例如,对于传感器框架,您可以使用:

offset

或者,对于命令框架,您可以使用:

if (sscanf(ring_buffer + offset, "%.2f;%.2f;%.2f;%d;%d;%u",
           &input.temperature, &input.current, &input.voltage,
           &input.dutycycle, &input.lightsensor, &input.message) != 6)
    …deal with malformatted sensor frame…

唯一复杂的因素是您正在使用环形缓冲区。这可能意味着您的传感器帧被拆分,因此前5个字节位于环形缓冲区的末尾,其余部分位于缓冲区的起始处。坦率地说,如果你能负担得起空间和复制,将环形缓冲区转换为常规(线性?)缓冲区将是最简单的。如果这绝对不是一个选项,那么你可能完全没有使用if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2) …deal with malformatted command frame… 。您将需要编写自己的sscanf()变体,可以告诉环形缓冲区的形状并使用它,或者您必须一次处理角色。

也许您的自定义功能是:

sscanf()

环形缓冲区从int rbscanf(const char *rb_base, int rb_len, int rb_off, const char *format, ...); 开始,总长度为rb_base个字节;数据从rb_len开始。您可能需要指定缓冲区长度和数据长度(&rb_base[rb_off]rb_len)。您可能已经有一个描述环形缓冲区的结构,在这种情况下,您可以将(指针)传递给该函数。

或者,如果您在读取整个帧之前处理数据,则可以在读取字节时进行验证。您仍然需要累积字符串和数字进行转换。您可能会使用rb_nbytesstrtol()而不是strtod()atoi();您需要了解错误,包括追踪未转换的字符,atof()atoi()函数无法告诉您。 atof()函数需要注意,但它们是有效的。