#ifndef SERIAL_CMD_H #define SERIAL_CMD_H #include #include #ifndef SERIAL_CMD_MAX_LINE #define SERIAL_CMD_MAX_LINE 128 #endif #ifndef SERIAL_CMD_MAX_ARGS #define SERIAL_CMD_MAX_ARGS 16 #endif #ifndef SERIAL_CMD_MAX_COMMANDS #define SERIAL_CMD_MAX_COMMANDS 16 #endif class CmdArgs { public: void parse(char* line); const char* command() const { return _command; } // Positional args (skips flags) const char* arg(int index) const; int intArg(int index, int fallback = 0) const; float floatArg(int index, float fallback = 0.0f) const; int count() const { return _posCount; } // Flag check bool has(const char* flag) const; // Raw token access (includes flags) const char* raw(int index) const; int rawCount() const { return _rawCount; } private: const char* _command = nullptr; const char* _tokens[SERIAL_CMD_MAX_ARGS]; int _rawCount = 0; const char* _positional[SERIAL_CMD_MAX_ARGS]; int _posCount = 0; }; class SerialCmd { public: using Handler = std::function; explicit SerialCmd(Stream& stream); bool on(const char* name, Handler handler); bool on(const char* name, const char* usage, Handler handler); void onDefault(Handler handler); bool poll(); void wait(); bool sync(unsigned long timeout_ms = 5000); void setEcho(bool enabled) { _echo = enabled; } private: void feedChar(char c); void dispatch(); void sendSyncList(); Stream& _stream; bool _echo = false; char _line[SERIAL_CMD_MAX_LINE]; int _linePos = 0; bool _lineReady = false; bool _prevCR = false; struct Command { const char* name; const char* usage; Handler handler; }; Command _commands[SERIAL_CMD_MAX_COMMANDS]; int _commandCount = 0; Handler _defaultHandler; }; #endif