C(嵌入式编程)中的Parse ByTestStream

C(嵌入式编程)中的Parse ByTestStream,c,arrays,parsing,char,bytestream,C,Arrays,Parsing,Char,Bytestream,因此,我在两个微控制器之间有一个通信系统,我在它们之间发送数据,即传感器数据从一个µC发送到另一个µC,并返回命令。 传感器数据取自一个结构并放入一个框架中,如下所示(标识符“SENSORFRAME”不是常数;它取决于框架中的内容): 产生如下画面: :\SENSORFRAME:-12.40;1.42;0.53;500;1200;8\r\r :\COMMANDFRAME:3;1.42\r\r 或者对于命令框架: sprintf(message, "\:\\COMMANDFRAME\:%u;%

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

产生如下画面:

:\SENSORFRAME:-12.40;1.42;0.53;500;1200;8\r\r
:\COMMANDFRAME:3;1.42\r\r
或者对于命令框架:

sprintf(message, "\:\\COMMANDFRAME\:%u;%.5f\r\r", input.command, input.data);
产生如下画面:

:\SENSORFRAME:-12.40;1.42;0.53;500;1200;8\r\r
:\COMMANDFRAME:3;1.42\r\r
当ByTestStream到达一个微控制器时,它被写入一个简单的环形缓冲区,直到被处理


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

如果在读取末尾的双回车(CR)后才处理帧类型,然后在双CR后插入空字节,则可以使用
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\u type
中,框架类型是一个字符串。稍微奇怪的
%[:]
只匹配一个冒号;然而,关键是它被视为成功的转换,并且
%n
转换将是有效的。如果更改为:

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

您至少有两种帧类型;总共有多少(目前,将来可能有)?在某种程度上,这并不重要。您可以对可能的帧类型使用一系列字符串比较,或者可以使用帧类型字符串的散列并将其与有效散列值集进行比较,或者可以设计另一种机制

一旦知道了所使用的帧类型,就知道了用于读取其余数据的格式字符串。因为你读到了一个双CR,你知道结尾包含了这个,你不需要再次验证它

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

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…
if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2)
    …deal with malformatted command frame…
或者,对于命令框,您可以使用:

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…
if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2)
    …deal with malformatted command frame…
唯一复杂的因素是您使用的是环形缓冲区。这可能意味着您的传感器帧被拆分,以便前5个字节位于环形缓冲区的末尾,其余字节位于缓冲区的开头。坦率地说,如果您能够提供足够的空间和复制,那么将环形缓冲区转换为常规(线性?)缓冲区将是最容易的。如果这绝对不是一个选项,那么您可能根本就无法使用
sscanf()
;您需要编写自己的
sscanf()
变体,该变体可以告诉您环形缓冲区的形状并使用它,或者您必须一次使用一个字符

您的自定义功能可能是:

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


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

如果在读取末尾的双回车(CR)之前不处理帧类型,然后在双CR后插入空字节,则可以使用
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\u type
中,框架类型是一个字符串。稍微奇怪的
%[:]
只匹配一个冒号;然而,关键是它被视为成功的转换,并且
%n
转换将是有效的。如果更改为:

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

您至少有两种帧类型;总共有多少(目前,将来可能有)?在某种程度上,这并不重要。您可以对可能的帧类型使用一系列字符串比较,或者可以使用帧类型字符串的散列并将其与有效散列值集进行比较,或者可以设计另一种机制

一旦知道了所使用的帧类型,就知道了用于读取其余数据的格式字符串。因为你读到了一个双CR,你知道结尾包含了这个,你不需要再次验证它

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

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…
if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2)
    …deal with malformatted command frame…
或者,对于命令框,您可以使用:

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…
if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2)
    …deal with malformatted command frame…
唯一复杂的因素是您使用的是环形缓冲区。这可能意味着您的传感器帧被拆分,以便前5个字节位于环形缓冲区的末尾,其余字节位于缓冲区的开头。坦率地说,如果您能够提供足够的空间和复制,那么将环形缓冲区转换为常规(线性?)缓冲区将是最容易的。如果这绝对不是一个选项,那么您可能会被非usi所困扰