Использование полиморфизма в последовательном коммуникационном стеке 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 ожидаемому для данного идентификатора.