Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

90 lines
2.8 KiB

/*
Part of the TERMINAL MODULE
Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
*/
#pragma once
#include <Arduino.h>
#include "terminal_parsing.h"
#include <forward_list>
#include <functional>
#include <vector>
namespace terminal {
struct Terminal;
// We need to be able to pass arbitrary Args structure into the command function
// Like Embedis implementation, we only pass things that we actually use instead of complete obj instance
struct CommandContext {
std::vector<String> argv;
size_t argc;
Print& output;
};
class Terminal {
public:
enum class Result {
Error, // Genric error condition
Command, // We successfully parsed the line and executed the callback specified via addCommand
CommandNotFound, // ... similar to the above, but command was never added via addCommand
BufferOverflow, // Command line processing failed, no \r\n / \n before buffer was filled
Pending, // We got something in the buffer, but can't yet do anything with it
NoInput // We got nothing in the buffer and stream read() returns -1
};
using CommandFunc = void(*)(const CommandContext&);
using ProcessFunc = bool(*)(Result);
using Names = std::vector<const __FlashStringHelper*>;
using Command = std::pair<const __FlashStringHelper*, CommandFunc>;
using Commands = std::forward_list<Command>;
// stream - see `stream` description below
// buffer_size - set internal limit for the total command line length
Terminal(Stream& stream, size_t buffer_size = 128) :
_stream(stream),
_buffer_size(buffer_size)
{
_buffer.reserve(buffer_size);
}
static void addCommand(const __FlashStringHelper* name, CommandFunc func);
static size_t commands();
static Names names();
// Try to process a single line (until either `\r\n` or just `\n`)
Result processLine();
// Calls processLine() repeatedly.
// Blocks until the stream no longer has any data available.
// `process_f` will return each individual processLine() Result,
// and we can either stop (false) or continue (true) the function.
void process(ProcessFunc = defaultProcessFunc);
private:
static bool defaultProcessFunc(Result);
// general input / output stream:
// - stream.read() should return user input
// - stream.write() can be called from the command callback
// - stream.write() can be called by us to show error messages
Stream& _stream;
// input stream is buffered until it can be parsed
// in case parsing did not happen and we filled the buffer up to it's size,
// the error will be returned and the buffer parsing will start from the beginning
std::vector<char> _buffer;
const size_t _buffer_size;
static Commands _commands;
};
} // namespace terminal