3

目前,在我的嵌入式系统(用 C 语言编码)上,我有很多调试辅助打印语句,当远程工具连接到可以向 PC 显示消息的系统时,这些语句会被执行。这些有助于了解一般系统状态,但由于消息通过缓慢的 CAN 总线,我相信它们可能会堵塞管道并导致其他问题,试图记录任何有用的数据。

它的基本要点是:

它就像一个 printf,但最终以一种特殊的消息格式通过 CAN 总线从嵌入式系统发送到工具。为此,我可以用特殊的调试消息替换这个通用的打印消息,这些调试消息向它发送一个唯一的 ID,后跟只有可变参数(即 argc/argv)。我想知道这是否是正确的方法,或者是否有我错过的灵丹妙药,或者我没有想到的其他东西。

所以,我发现这个问题一开始就适合我的目的:

使用字符串表“解码器环”的 printf() 调试库

但我没有让它像 printf 一样简单的约束。我可以在远程工具端维护一个字符串表(因为它是 Windows 可执行文件,因此不受代码大小限制)。我是该代码的唯一负责人,并且更愿意在调试时尝试减轻代码大小以及 CAN 总线流量。

我目前的想法是这样的:

printf("[%d] User command: answer call\n", (int)job);

这变成

debug(dbgUSER_COMMAND_ANSWER_CALL, job);

dbgUSER_COMMAND_ANSWER_CALL作为可能的调试消息枚举的一部分

远程端有类似的东西

switch(messagetype)
{
case dbgUSER_COMMAND_ANSWER_CALL:
    /* retrieve an integer from the data portion of the message and put it into a variable */
    printf("[%d] User command: answer call\n", (int)avariable);
}

这相对简单,如果我所有的消息都采用相同的格式,那就太好了。然而,棘手的地方是我的一些语句必须打印非恒定的字符串(例如设备的名称)。

printf("[%d] %02X:%02X:%02X:%02X:%02X:%02X (%s)\n", /* a bunch of parameters here */);

那么,我是否应该使调试消息的内容为 1)消息类型,2)第一个参数的长度,3)参数,4)下一个参数的长度,5)参数,等等和以此类推

还是我忽略了一些更明显或更容易的事情?

谢谢

4

1 回答 1

1

我假设您使用 CAN,因为这是您已经拥有的设备连接。您还没有真正提供有关您的诊断需求的足够信息,但我可以举一个例子说明我们在哪里工作。我们使用自定义构建工具来梳理我们的源代码以构建字符串表。我们的代码使用类似:

        log( LOGH(T0722T),                        //"Position"
             LOG_DOT_HEX_VALUE(i),
             LOG_TEXT(T0178T),                    //"Id"
             LOG_DOT_VALUE(uniqueId % 10000),
             0 );

这将记录一些可以解码为的数据:

<时间戳> H Position.00B Id.0235

我们允许使用 T0000T 让工具为我们查找(或生成)一个唯一编号。该工具使用编译器的 TxxxxT 编号构建一个枚举,以及一​​个包含有序字符串列表的文件。每个构建都会生成一个与枚举编号匹配的字符串表。该系统还与用于生成国际化字符串的数据库系统相关联,但这与您的问题并不真正相关。

每个元素都是一个短的(16 位)。我们允许 12 位用于值,并将高 4 位用于类型和标志信息。编码数据是否为字符串 id;它是一个信号(高/低)还是只是一个事件;它是一个值吗?是十进制,十六进制,base64url;连接(与前一项)或分开。

我们将数据记录在一个大的环形缓冲区中,以便在需要时进行查询。这允许系统在不受干扰的情况下运行,但如果发现问题,可以提取数据。当然可以不断发送数据,如果需要,我建议将任何一条消息限制为单个 CAN 有效负载(假设您仅使用单个 ID,则为 8 个字节)。如果正确编码(假设接收方创建了时间戳),我上面提供的消息将适合一条 CAN 消息。

我们确实有能力包含任意数据(ASCII 或十六进制),但我从不使用它。这通常会浪费日志中的宝贵空间。在嵌入式环境中,日志记录始终是一种平衡。

于 2013-07-25T20:24:43.997 回答