代码之家  ›  专栏  ›  技术社区  ›  Praetorian Luchian Grigore

嵌入式结构的描述格式

  •  1
  • Praetorian Luchian Grigore  · 技术社区  · 15 年前

    我有一个C结构,允许用户在嵌入式系统中配置选项。目前,我们用于此配置的GUI是为该配置结构的每个不同版本定制编写的。我想要的是能够以客户机配置应用程序可以读取的某种格式描述结构成员,使其在我们的所有系统中都具有通用性。

    我尝试过用XML描述结构,并让客户机读取文件;这在大多数情况下都有效,除了一些字段具有相互依赖性的情况。因此,我使用的格式需要有一种方法来指定它们;例如,成员A必须始终小于或等于成员B的一半。

    提前感谢您的想法和建议。

    编辑:

    在阅读了第一个回复之后,我意识到我的问题确实有点太模糊了,所以下面是另一个尝试:

    嵌入式系统需要以C结构访问数据,在处理器上运行任何其他语言都不是一个选项。基本上,我所需要的只是一种用这个结构定义元数据的方法,这个元数据将和固件一起下载到flash上。然后,客户机配置实用程序将通过RS-232、CAN等读取元数据文件,并填充一个窗口(树视图),用户可以使用该窗口编辑选项。

    我提到的修补XML文件正是这样做的,它包含结构成员名、数据类型、元素数等。XML文件中成员的位置隐式定义了它在C结构中的位置。此文件驻留在闪存上,由配置程序读取;唯一缺少的是定义结构字段之间依赖关系的方法。

    代码是使用matlab/simulink自动生成的,因此我可以使用脚本语言来帮助创建结构。例如,如果我最终使用XML,那么该结构将仅以XML格式定义,并且在代码生成期间将使用脚本创建C结构。

    希望这更清楚。

    3 回复  |  直到 15 年前
        1
  •  1
  •   jamesv    15 年前

    对于没有关系或与其他单个字段没有关系的简单情况,可以向结构添加两个字段:“其他”字段编号和指向比较这两个字段的函数的指针。然后您需要创建比较两个值的函数,并根据关系是否满足返回true或false。那么,假设您需要创建两个函数来测试关系和关系的倒数(即,如果字段1需要大于字段2,那么字段2需要小于或等于字段1)。如果需要对范围设置多个限制,可以存储指向函数/字段对列表的指针。

    另一种方法是为每个字段创建一个验证函数,并在字段更改时调用它。显然,这个函数可以像您想要的那样复杂,但可能需要更多的手工编码。

    理论上,您可以根据所描述的XML描述为上述任何一种技术生成验证函数。

        2
  •  0
  •   dmckee --- ex-moderator kitten    15 年前

    我希望你现在能得到一些答案,但让我看看我能做些什么。

    你的问题有点含糊,但听起来你想要一个

    • 代码生成
    • 嵌入式扩展语言
    • 一种手工编码的运行时微型语言

    代码生成

    您说,您当前每次更改配置代码时都要手工处理配置代码。我敢打赌,这是一个高度重复的任务,所以没有理由你不能写程序来为你做这件事。生成器应该使用一些特定于域的语言,并发出C代码和头文件,这些文件随后将构建到应用程序中。我在这里说的一个例子是 GNU gengetopt . 使用XML作为输入语言的想法没有任何错误。

    优势:

    • 生成的代码既快又紧凑
    • 不需要在目标平台上运行解释器

    缺点:

    • 你得写发电机
    • 改变事情需要重新编译

    扩展语言

    Tcl、python和其他语言与C代码配合良好,并允许您以动态语言指定配置行为,而不是乱搞C类型和字符串,以及……

    优势:

    • 动态语言可能意味着配置代码更简单
    • 更改配置选项而不重新编译

    缺点:

    • 您需要在目标平台上运行动态语言

    微型语言

    您可以编写自己的嵌入式迷你语言。

    优势:

    • 不需要重新编译
    • 因为你写的它会在你的目标上运行

    缺点:

    • 你得自己写
        3
  •  0
  •   James    15 年前

    结构从版本到版本的变化是多少?当我做这种事情时,我将它硬编码到PC应用程序中,然后计算出固件版本的包的含义——但是唯一的变化通常是每隔几个月在末尾添加一个额外的字段。

    我想如果我想沿着元数据路径走下去的话,我会使用如下的方法。

    typedef struct
    {
        unsigned char field1;
        unsigned short field2;
        unsigned char a_string[4];
    } data;
    
    typedef struct
    {
        unsigned char name[16];
        unsigned char type;
        unsigned char min;
        unsigned char max;
    } field_info;
    
    field_info fields[3];
    
    void init_meta(void)
    {
        strcpy(fields[0].name, "field1");
        fields[0].type = TYPE_UCHAR;
        fields[0].min = 1;
        fields[0].max = 250;
    
        strcpy(fields[1].name, "field2");
        fields[1].type = TYPE_USHORT;
        fields[1].min = 0;
        fields[1].max = 0xffff;
    
        strcpy(fields[2].name, "a_string");
        fields[2].type = TYPE_STRING;
        fields[2].min = 0 // n/a
        fields[2].max = 0 // n/a
    }
    
    void send_meta(void)
    {
        rs232_packet packet;
    
        memcpy(packet.payload, fields, sizeof(fields));
    
        packet.length = sizeof(fields);
    
        send_packet(packet);
    }