【问题标题】:Generating message type with preprocessor使用预处理器生成消息类型
【发布时间】:2019-10-02 16:51:37
【问题描述】:

我想在两个微控制器之间创建一个通信协议,我使用在系统之间合并消息类型的类逻辑。我想通过做一些非常简单的事情来开发一个更简单的过程来创建新消息

BEGIN_MSG(LinearDriveMsg)
  ADD_2BIT(DriveSpeed, speed)
  ADD_16BIT(GMath::Position, position.x)
END_MSG

理想情况下,它会扩展为:

BEGIN_MSG(LinearDriveMsg)
  BEGIN_SERIALIZER
    ADD_SERIALIZER_2BIT(DriveSpeed, speed)
    ADD_SERIALIZER_16BIT(GMath::Position, position.x)
  END_SERIALIZER

  BEGIN_DESERIALIZER
    ADD_DESERIALIZER_2BIT(DriveSpeed, speed)
    ADD_DESERIALIZER_16BIT(GMath::Position, position.x)
  END_DESERIALIZER
END_MSG

然后展开为cpp代码

...

bool LinearDriveMsg::deserialize(const uint8_t *incoming_buffer, const uint8_t *incoming_size) override{
        if (*incoming_size != getMessageSize())
            return false;

        _speed = (DriveSpeed)((incoming_buffer[0] & SPEED_MASK) >> SPEED_OFFSET);
        weldTwoBytesToInt(&incoming_buffer[1], _position.x);
        return true;
}

int LinearDriveMsg::serialize(uint8_t *outgoing_buffer, uint8_t *outgoing_size) const override{
    if (*outgoing_size < getMessageSize())
        return -1;

    outgoing_buffer[0] |= ((uint8_t)_speed << SPEED_OFFSET) & SPEED_MASK;
    cutIntToTwoBytes(_position.x, outgoing_buffer + 1, 2);

    return getMessageSize();
}

...

我知道做一些高级预处理器的东西很棘手,但也许有一些方法可以完成这项任务?也可以调整实际cpp代码使其成为可能(这样效率还是可以的)

【问题讨论】:

  • 我最好在 python 或 lua 之类的东西上编写代码生成器,而不是处理预处理器。不过,您的任务应该可以使用模板来完成。

标签: c++ serialization deserialization message preprocessor


【解决方案1】:

我会自己回答。实际上有“简单”的方法来解决预处理器中的上述任务。 boost 库提供了在预处理器中工作的工具,就像在普通语言中一样。他们有一个名为 preprocessor 的包作为 boost 套件的一部分 read the docs,你可以下载它here 它是主包的一部分。

帮助解决上述任务的主要功能是将数组元组转发到我们从函数式编程中知道的构造的想法。实际上是BOOST_PP_SEQ_FOR_EACH(macro, data, seq)。另一个有助于解决该任务的功能是 this guy 实现,用于在每个元素周围创建双括号。

按照想法,它将像以下那样工作。我有上面的元组列表:

#define frame_composition (begin_byte(0), begin_bit(0), int8_t, speed)\
    (begin_byte(1), begin_bit(4), int16_t, direction)\

我有某种动作序列,因为我想要串行第一和反串行:

#define COMPOSE_FRAME(seq) \
    ADD_SERIAL(seq) \
    ADD_DESERIAL(seq)

现在每个添加类别的内容:

#define ADD_SERIAL(seq) \
    BOOST_PP_SEQ_FOR_EACH(ADD_SERIAL_ELEM, ~, GLK_PP_SEQ_DOUBLE_PARENS(seq))
#define ADD_DESERIAL(seq) \
    BOOST_PP_SEQ_FOR_EACH(ADD_DESERIAL_ELEM, ~, GLK_PP_SEQ_DOUBLE_PARENS(seq)) \

很酷的是,我们将相同的元组列表转发给不同的结构,以执行一些不同的算法。现在 X_ELEM 的内容定义:

#define ADD_SERIAL_ELEM(seq) \
    outgoing_buffer[BOOST_PP_TUPLE_ELEM( 0, elem)] = (uint8_t) BOOST_PP_TUPLE_ELEM( 3, elem); 
#define ADD_DESERIAL_ELEM(seq) \
    BOOST_PP_TUPLE_ELEM(3,elem) = (BOOST_PP_TUPLE_ELEM(2,elem)) incoming_buffer[BOOST_PP_TUPLE_ELEM(0,elem)];

如果您需要,您可以区分元素“功能”中的不同用例

BOOST_PP_IF(cond, t, f)

对对象和简单变量做不同的事情

这现在不是完整的解决方案,但要了解这个想法,并且可以使用 cpp 创建高度可移植的简单消息生成器框架。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2023-03-08
    相关资源
    最近更新 更多