#include "Serial.h" #include "../Static.h" #include #include "../Config.h" #include "../Sequencer.h" SerialInput::SerialInput() : InputSource("Serial"), m_state(ParseState::Normal), m_logPrinter(this) { } void SerialInput::redrawPrompt() { if (m_canRedraw) { Serial.print((char)8); Serial.print((char)27); Serial.print("[2K"); Serial.print((char)8); Serial.print((char)27); Serial.print("[G"); Serial.print('\r'); Serial.print("> "); Serial.print(m_buf); } } InputEvent SerialInput::parseNormal(char nextChar) { if (nextChar == 27) { m_state = ParseState::EscapeSequence; return InputEvent::None; } if (nextChar == 13) { redrawPrompt(); Serial.println(); if (m_buf.length() > 0) { m_canRedraw = false; doCommand(); m_canRedraw = true; m_history.insert(m_buf); m_buf = ""; } m_historyOffset = 0; redrawPrompt(); return InputEvent{}; } if (nextChar == 8) { if (m_buf.length() > 0) { m_buf.remove(m_buf.length() - 1, 1); } Serial.print((char)8); Serial.print((char)27); Serial.print("[K"); redrawPrompt(); return InputEvent::None; } if (nextChar >= 32 && nextChar <= 126) { m_buf += nextChar; Serial.print(nextChar); } return InputEvent::None; } InputEvent SerialInput::parseEscape(char nextChar) { if (nextChar == '[') { m_state = ParseState::CSI; } else { m_state = ParseState::Normal; } return InputEvent::None; } InputEvent SerialInput::parseCSI(char nextChar) { if (nextChar == 'A') { if (m_historyOffset < m_history.size()) { m_historyOffset += 1; m_buf = m_history.peek(m_historyOffset); redrawPrompt(); } else { Serial.print((char)7); } } else if (nextChar == 'B') { if (m_historyOffset > 0) { m_historyOffset -= 1; m_buf = m_history.peek(m_historyOffset); redrawPrompt(); } else { Serial.print((char)7); } } else { Serial.print((char)7); } m_state = ParseState::Normal; return InputEvent::None; } InputEvent SerialInput::read() { while (Serial.available() > 0) { char nextChar = Serial.read(); InputEvent ret = InputEvent::None; switch (m_state) { case ParseState::Normal: ret = parseNormal(nextChar);break; case ParseState::EscapeSequence: ret = parseEscape(nextChar);break; case ParseState::CSI: ret = parseCSI(nextChar);break; } if (ret != InputEvent::None) { return ret; } } return InputEvent::None; } void SerialInput::doHelp(Args& args, Print& out) { out.println("Available commands:"); auto sched = MainLoop::instance()->scheduler; for(auto task : sched.tasks) { for(auto &command : task->commands()) { out.print(command.name); out.print(" "); } } out.println(); } const std::vector& SerialInput::commands() const { static const std::vector _commands = { {"help", &SerialInput::doHelp} }; return _commands; } void SerialInput::doCommand() { auto sched = MainLoop::instance()->scheduler; Args args = Args(&m_buf); const auto cmdName = args[0]; for(auto task : sched.tasks) { for(auto &command : task->commands()) { if (cmdName == command.name) { command.invoke(task, args, m_logPrinter); return; } } } m_logPrinter.println("Unknown command"); doHelp(args, m_logPrinter); } STATIC_ALLOC(SerialInput); STATIC_TASK(SerialInput);