Генерация типа сообщения с препроцессором - PullRequest
0 голосов
/ 02 октября 2019

Я хочу создать протокол связи между двумя микроконтроллерами, я использую логику классов, которая включает типы сообщений между системами. Я хочу разработать более простой процесс создания новых сообщений, выполнив что-то очень простое, например:

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, чтобы сделать возможным (таким образом, эффективность все еще в порядке)

1 Ответ

0 голосов
/ 06 октября 2019

Я отвечу сам. Есть на самом деле «простой» способ решения вышеуказанной задачи в препроцессоре. Библиотека boost предлагает инструменты для работы примерно на препроцессоре, как на обычных языках. У них есть пакет под названием препроцессор, входящий в состав пакета поддержки . Прочитайте документы , вы можете скачать его здесь , это часть основного пакета.

Основная функция, котораяПомочь в решении вышеуказанной задачи была идея переслать кортеж массивов в конструкции, известные нам из функционального программирования. На самом деле это BOOST_PP_SEQ_FOR_EACH(macro, data, seq). Еще одна особенность, которая помогла решить задачу, была эта реализация парней для создания двойных скобок вокруг каждого элемента.

Как идея, она будет работать следующим образом. У меня есть приведенный выше список кортежей:

#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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...