Поддержка токенизации, цветного вывода и автодополнения для 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
- Бинарный протокол для передачи по сети