renderbug/src/inputs/Serial.cpp

172 lines
3.5 KiB
C++

#include "Serial.h"
#include "../Static.h"
#include <LittleFS.h>
#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<Command>&
SerialInput::commands() const
{
static const std::vector<Command> _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);