Интерактивная оболочка через UART-сериал для Arduino?

Я хотел бы реализовать интерактивную оболочку через последовательный порт UART для Arduino, с чистым кодом стиля C ++ ООП. Но я думаю, что если будет слишком много суждений if-else при оценке пользовательских команд ввода в коде, это будет немного уродливо,

Поэтому я хотел бы спросить, есть ли способ избежать использования оператора if-else? Например,

ДО:

while(Serial.available())
{
serialReceive = Serial.readString();// read the incoming data as string
Serial.println(serialReceive);
}

if(serialReceive.equals("factory-reset"))
{
MyService::ResetSettings();
}
else if(serialReceive.equals("get-freeheap"))
{
MyService::PrintFreeHeap();
}
else if(serialReceive.equals("get-version"))
{
MyService::PrintVersion();
}

ПОСЛЕ:

while(Serial.available())
{
serialReceive = Serial.readString();// read the incoming data as string
Serial.println(serialReceive);
}

MagicClass::AssignCommand("factory-reset", MyService::ResetSettings);
MagicClass::AssignCommand("get-freeheap", MyService::PrintFreeHeap);
MagicClass::AssignCommand("get-version", MyService::PrintVersion);

1

Решение

У вас может быть массив, в котором хранится указатель на функцию вместе со строкой, которая запускает команду (вы можете создать структуру для хранения обоих).

К сожалению, Arduino не поддерживает класс std :: vector, поэтому для моего примера я буду использовать массивы типа c. Однако есть библиотека для Arduino, которая добавляет некоторую поддержку STL для Arduino. https://github.com/maniacbug/StandardCplusplus (также с этой библиотекой вы можете использовать функциональную библиотеку, чтобы упростить передачу функций в качестве аргументов)

//struct that stores function to call and trigger word (can actually have spaces and special characters
struct shellCommand_t
{
//function pointer that accepts functions that look like "void test(){...}"void (*f)(void);
String cmd;
};

//array to store the commands
shellCommand_t* commands;

При этом вы можете либо инициализировать массив команд одним размером при запуске, либо изменять его размер каждый раз, когда добавляете команду, это зависит только от вашего варианта использования.

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

int nCommands = 0;
void addCommand(String cmd, void (*f)(void))
{
shellCommand_t sc;
sc.cmd = cmd;
sc.f = f;

commands[nCommands++] = sc;
}

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

addCommand("test", test);
addCommand("hello world", helloWorld);

Наконец, в вашей функции цикла вы можете использовать цикл for, чтобы просмотреть все команды, проверить входную строку на предмет всех командных строк.

Вы можете вызвать функцию подобранной команды следующим образом

(*(commands[i].f))();
3

Другие решения

Других решений пока нет …