inputs: serial: implement a CLI
This commit is contained in:
parent
ac94c4be0c
commit
4e56134dd9
@ -1,33 +1,171 @@
|
||||
#include "Serial.h"
|
||||
#include "../Static.h"
|
||||
#include <LittleFS.h>
|
||||
#include "../Config.h"
|
||||
#include "../Sequencer.h"
|
||||
|
||||
InputEvent
|
||||
Serial::read()
|
||||
SerialInput::SerialInput() : InputSource("Serial"),
|
||||
m_state(ParseState::Normal),
|
||||
m_logPrinter(this)
|
||||
{
|
||||
while (Serial.available() > 0) {
|
||||
char nextChar = Serial.read();
|
||||
if (nextChar == '\n') {
|
||||
doCommand();
|
||||
m_buf = "";
|
||||
} else {
|
||||
m_buf += nextChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Serial::doCommand() {
|
||||
if (command == "tasks") {
|
||||
Serial.println("Tasks:");
|
||||
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
|
||||
doHelp(Args& args, Print& out)
|
||||
{
|
||||
out.println("Available commands:");
|
||||
auto sched = MainLoop::instance()->scheduler;
|
||||
for(auto task : sched.tasks) {
|
||||
bool isFigment = task->isFigment();
|
||||
if (isFigment) {
|
||||
Serial.println("F " + task->name);
|
||||
} else {
|
||||
Serial.println("T " + task->name);
|
||||
for(auto &command : task->commands()) {
|
||||
out.print(command.name);
|
||||
out.print(" ");
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
const std::vector<Command> serialCommands = {
|
||||
{"help", doHelp}
|
||||
};
|
||||
|
||||
const std::vector<Command>&
|
||||
SerialInput::commands() const
|
||||
{
|
||||
return serialCommands;
|
||||
}
|
||||
|
||||
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.func(args, m_logPrinter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_logPrinter.println("Unknown command");
|
||||
doHelp(args, m_logPrinter);
|
||||
}
|
||||
|
||||
STATIC_ALLOC(SerialInput);
|
||||
|
@ -3,14 +3,60 @@
|
||||
|
||||
class SerialInput: public InputSource {
|
||||
public:
|
||||
void onStart() override {
|
||||
//Serial.begin();
|
||||
SerialInput();
|
||||
InputEvent read() override;
|
||||
|
||||
class LogPrinter : public Print {
|
||||
private:
|
||||
SerialInput* serial;
|
||||
Ringbuf<char, 512> buf;
|
||||
public:
|
||||
LogPrinter(SerialInput* serial) : serial(serial) {};
|
||||
size_t write(uint8_t byte) {
|
||||
if (byte == '\n') {
|
||||
char c;
|
||||
Serial.print('\r');
|
||||
while (buf.take(c)) {
|
||||
Serial.write(c);
|
||||
}
|
||||
Serial.println();
|
||||
serial->redrawPrompt();
|
||||
} else {
|
||||
buf.insert(byte);
|
||||
}
|
||||
return sizeof(byte);
|
||||
}
|
||||
};
|
||||
|
||||
void redrawPrompt();
|
||||
|
||||
Print* logPrinter() {
|
||||
return &m_logPrinter;
|
||||
}
|
||||
|
||||
InputEvent read();
|
||||
//static SerialInput::Command *s_root;
|
||||
LogPrinter* printer() {
|
||||
return &m_logPrinter;
|
||||
}
|
||||
|
||||
const std::vector<Command> &commands() const override;
|
||||
|
||||
private:
|
||||
enum ParseState {
|
||||
Normal,
|
||||
EscapeSequence,
|
||||
CSI
|
||||
};
|
||||
String m_buf;
|
||||
ParseState m_state;
|
||||
char m_escapeSeq[3];
|
||||
void doCommand();
|
||||
LogPrinter m_logPrinter;
|
||||
bool m_canRedraw = true;
|
||||
Ringbuf<String, 5> m_history;
|
||||
int m_historyOffset = 0;
|
||||
|
||||
}
|
||||
InputEvent parseNormal(char nextChar);
|
||||
InputEvent parseEscape(char nextChar);
|
||||
InputEvent parseCSI(char nextChar);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user