Использование полиморфизма в последовательном коммуникационном стеке C++

Я нахожусь в процессе написания собственного протокола последовательной связи CAN более высокого уровня поверх библиотеки mbed для микроконтроллеров STM32.

Я определил около 2 десятков сообщений, которые будут использоваться в протоколе. Некоторые из сообщений сегментированы (т.е. 3 отдельных сообщения, которые могут поступать последовательно или нет).

На данный момент у меня есть большой оператор switch для обработки входящих сообщений на основе идентификатора сообщения, и он выглядит примерно так:

switch (msgID){
    case END_CHARGE_REPORT_1_MSG:
        return processEndChargeReportMsg(msgID);
    case END_CHARGE_REPORT_2_MSG:
        return processEndChargeReportMsg(msgID);
    case END_CHARGE_REPORT_3_MSG:
        return processEndChargeReportMsg(msgID);
    case END_CHARGE_REQUEST_MSG:
        return processEndChargeRequestMsg(msgID);

    case START_CHARGE_REPORT_1_MSG:
        return processStartChargeReportMsg(msgID);
    case START_CHARGE_REPORT_2_MSG:
        return processStartChargeReportMsg(msgID);
    case START_CHARGE_REPORT_3_MSG:
        return processStartChargeReportMsg(msgID);

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

Я чувствую, что есть лучший / чище / быстрее способ сделать это с полиморфизмом, но я не могу понять, как это сделать.

Я хочу что-то вроде:

class myCANMessages{
    virtual process()
}

//Derived classes for each type of message group
class startChargeMessageGroup : public myCANMessages{
    CANMessage fullMsgGroup[3];
    process(){
          load CANMessage into fullMsgGroup
          if(allMessagesReceived)
                 parse(CANMessage)
                 take_action(decoded data from CANMessage)
    }
}

class endChargeMessageGroup : public myCANMessages{ ///etc...etc...

а затем просто продолжайте обрабатывать входящие сообщения CANMessage (сохраняя индексы в соответствующие сообщения CAN в буфере, анализируя их, когда все они получены, вызывая соответствующие функции, используя полученные данные в качестве параметра) со структурой, подобной этой:

myCANMessages *polymorphPointer

while(1){
 CANMessage = readCANMessage();

--> somehow assign this automagically to correct derivedObject type


polymorphPointer = &derivedObject;
polymorphPointer->process


}

.... не могу понять, хотя... да!

1 ответ

Решение

Вы можете иметь "сообщение CAN" в качестве абстрактного базового класса, а затем наследовать его для каждого уникального идентификатора CAN. Но это звучит немного излишне для меня.

Обычно я решаю эти ситуации с помощью таблицы поиска, отсортированной по идентификаторам. Каждый элемент в таблице содержит поддерживаемый идентификатор и указатель на функцию. (По сути, это то, к чему все-таки приведет полиморфизм.)

Получив сообщение, вы выполняете двоичный поиск в таблице, чтобы узнать, поддерживается ли идентификатор. Если это так, то вызовите функцию.

В основном это псевдокод:

CAN_msg msg = can_read();
const CAN_msg* supported = binary_search(table, msg.id);
if(supported) 
{
  supported->process();
}

Также рекомендуется всегда проверять, соответствуют ли размер (DLC) и бит RTR ожидаемому для данного идентификатора.

Другие вопросы по тегам