Поддержка токенизации, цветного вывода и автодополнения для embedded-систем и не только.
Мощный и легковесный процессор команд для встроенных систем (Embedded C++) с поддержкой токенизации, цветного вывода и автодополнения.
Этот проект представляет собой шаблонный класс на C++ для обработки текстовых команд в интерфейсах командной строки (CLI). Он разработан с учетом работы на микроконтроллерах (AVR) и на ПК, поддерживает динамическую токенизацию, цветной вывод, обработку escape-последовательностей и поиск команд.
Внимание: В примерах показан лишь интерфейс использования и концепция работы библиотеки. Реализация некоторых методов и внутренняя логика намеренно скрыты, так как являются:
- 🧠 Интеллектуальной собственностью автора.
- 🔧 Оптимизированными алгоритмами для embedded-систем.
- 🛡️ Ноу-хау в области обработки текстовых команд на микроконтроллерах.
- ⚡ Уникальными решениями по эффективности использования памяти.
- Кросс-платформенность: Работает как на AVR (Arduino), так и на PC (Linux/Windows/MacOS).
- Шаблонный дизайн: Размеры буферов и индексов задаются на этапе компиляции для контроля потребления памяти.
- Динамическая токенизация: Гибкое разбиение входной строки на аргументы с различными режимами.
- Цветной вывод: Поддержка ANSI-цветов для удобства отладки и пользовательского интерфейса.
- Система команд: Простая регистрация и поиск команд с указанием количества ожидаемых аргументов.
- Автодополнение: Функция для показа похожих команд по подстроке.
- Экранирование символов: Встроенная обработка escape-последовательностей (\n, \t, \r и др.).
#include "CommandProcessor.h"
#include "io.h"
#include "utils.h"
using utils::i; // char* to int
using utils::d; // char* to double
// Создаем экземпляр процессора (буфер 64 байта, индекс на 16 токенов)
CommandProcessor<64, 16> cli;
// Создаём простую функцию
void sayHello() {
// cli[1] содержит первый аргумент
io::println(io::YELLOW, "!!! ", cli[1], " !!!", io::NO);
}
// Создаём вспомогательную функцию по выислению квадратного корня методом Ньютона-Рафсона
double NewtonRaphsonSqrt(double x, double initial_guess, double iterations, bool verbose = false) {
// Метод Ньютона-Рафсона
double result = initial_guess;
for (int i = 0; i < iterations; ++i) {
result = 0.5 * (result + x / result);
if (verbose)
io::cout << i << ": " << result << io::endl;
}
return result;
}
// Оборачиваем метод для подачи в массив комманд
void sqrt() {
int result = NewtonRaphsonSqrt( d(cli[1]), d(cli[2]), i(cli[3]), i(cli[4]) );
io::println(io::ORANGE, result, io::NO);
}
// Объявляем массив команд: {Имя, Функция-обработчик, Кол-во аргументов}
Command cmd[] = {
{"say", sayHello, 1}, // Ожидает 1 аргумент
{"sqrt", sqrt, -1}, // Ожидает бесконечного много аргументов, но необходимо всего 3
};
void setup() {
io::init(115200); // Инициализируем Serial
cli.setPrompt(">> ")
.showWelcome()
.setDebugMode(false); // Включаем по необходимости
cli.setCommands(cmd);
}
void loop() {
cli.readInput(); // Неблокирующее чтение из Serial
}
#include "CommandProcessor.h"
#include "io.h"
#include "utils.h"
using utils::d; // char* to double
CommandProcessor<64, 16> cli;
void half_sum() {
double a = d( cli[1] );
double b = d( cli[2] );
double result = (a + b) / 2;
io::println("The half-sum of ", a, " and ", b, " is ", io::BLUE, result, io::NO);
}
Command cmd[] = {
{"hsum", half_sum, -1},
};
int main() {
cli.run(cmd, false, ">>> "); // режим дебага выключен, приглашение осуществляется символами ">>> "
return 0;
}
В строке
{"cmd", cmd, -1},
"cmd"
— это имя (или псевдоним) к функции-обработчику, по которому к этой функции можно обращаться интерактивно;cmd
— сама функция-обработчик;-1
— ожидаемое количество аргументов.
В зависимости от ожидаемого количества аргументов на выходе получается разная интерпретация:
"cmd arg1 arg2 arg3 arg4" → ["cmd", "arg1 arg2 arg3 arg4"] при 1;
"cmd arg1 arg2 arg3 arg4" → ["cmd", "arg1", "arg2 arg3 arg4"] при 2;
"cmd arg1 arg2 arg3 arg4" → ["cmd", "arg1", "arg2", "arg3 arg4"] при 3;
И т.д.
"cmd arg1 arg2 arg3 arg4" → ["cmd arg1 arg2 arg3 arg4"] при 0;
"cmd arg1 arg2 arg3 arg4" → ["cmd", "arg1", "arg2", "arg3", "arg4"] при -1;
Для аргументов, которые подаются в комлексе, может быть использован специальный парсер, разработанный пользователем.
.
├── CommandProcessor.h # Основной класс процессора команд
├── index.h # Класс для работы с индексами (статический/динамический буфер)
├── io.h # Абстракция ввода/вывода с поддержкой цветов (ANSI)
├── internal.h # Внутренние платформо-зависимые функции (AVR/PC)
├── utils.h # Вспомогательные утилиты (строки, математика)
└── examples/ # Папка с примерами использования (рекомендуется создать)
Библиотека может быть адаптирована для работы поверх любых сетевых интерфейсов, что делает её идеальным решением для IoT-устройств и систем удаленного управления.
Интерфейс | Готовность | Сценарии использования |
---|---|---|
UART/Serial | ✅ Полная поддержка | Локальное управление устройством |
WiFi (TCP/IP) | 🔄 Готова к адаптации | Удаленное управление по сети |
Ethernet | 🔄 Готова к адаптации | Промышленные системы, стационарные устройства |
Bluetooth SPP | 🔄 Готова к адаптации | Мобильное управление с smartphones |
Библиотека оптимизирована для работы с ограниченными ресурсами микроконтроллеров:
Параметр | Значение | Примечания |
---|---|---|
Память кода | 2-5 KB | Зависит от компилятора и оптимизаций |
Память данных | Настраивается | Зависит от BUFFER_SIZE и INDEX_SIZE |
Время обработки | < 1 ms | На AVR @ 16MHz |
Стек вызовов | < 512 B | Безопасно для RTOS |
// Примеры конфигураций для разных устройств
CommandProcessor<64, 8> cli; // ATtiny85, очень мало памяти
CommandProcessor<128, 16> cli; // ATmega328P (Arduino Uno)
CommandProcessor<256, 32> cli; // ESP8266/32, больше ресурсов
CommandProcessor<1024, 64> cli; // STM32, сетевые приложения
Архитектура библиотеки позволяет легко добавить:
- Историю команд (вверх/вниз для повтора)
- Выполнение скриптов из последовательности команд
- Поддержку JSON для структурированного вывода
- Авто-документацию команд через help
- Бинарный протокол для передачи по сети