mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-31 12:29:14 +03:00
322 lines
7.4 KiB
C++
322 lines
7.4 KiB
C++
#include "Module/Terminal.h"
|
|
|
|
#include "Utils/TimeUtils.h"
|
|
|
|
#define INPUT_MAX_LENGHT 255
|
|
|
|
Terminal::Terminal(Stream *stream) : _stream{stream},
|
|
_line(INPUT_MAX_LENGHT),
|
|
_cc_pos(0),
|
|
_color(false),
|
|
_controlCodes(false),
|
|
_echo(false),
|
|
_eol(CRLF){};
|
|
|
|
void Terminal::setStream(Stream *stream) {
|
|
_stream = stream;
|
|
}
|
|
|
|
Terminal::~Terminal() {}
|
|
|
|
void Terminal::setOnReadLine(TerminalInputEventHandler h) { inputHandler_ = h; }
|
|
|
|
void Terminal::setOnEvent(TerminalEventHandler h) { eventHandler_ = h; }
|
|
|
|
bool Terminal::available() {
|
|
return _stream != nullptr ? _stream->available() : false;
|
|
}
|
|
|
|
void Terminal::setEOL(EOLType_t eol) {
|
|
_eol = eol;
|
|
}
|
|
|
|
void Terminal::enableEcho(bool enabled) {
|
|
_echo = enabled;
|
|
}
|
|
|
|
void Terminal::enableColors(bool enabled) {
|
|
_color = enabled;
|
|
}
|
|
|
|
void Terminal::enableControlCodes(bool enabled) {
|
|
_controlCodes = enabled;
|
|
}
|
|
|
|
void Terminal::quit() {}
|
|
|
|
void Terminal::loop() {
|
|
if (_stream == nullptr || !_stream->available()) return;
|
|
|
|
sint8_t moveX = 0;
|
|
sint8_t moveY = 0;
|
|
|
|
char c = _stream->read();
|
|
|
|
_lastReceived = millis();
|
|
|
|
if (state == ST_INACTIVE) {
|
|
// wait for CR
|
|
if (c == CHAR_CR) {
|
|
if (eventHandler_) {
|
|
eventHandler_(EVENT_OPEN, _stream);
|
|
state = ST_NORMAL;
|
|
}
|
|
}
|
|
// or ignore all other
|
|
return;
|
|
}
|
|
|
|
if (c == CHAR_LF || c == CHAR_NULL || c == CHAR_BIN)
|
|
return;
|
|
|
|
// Esc
|
|
if (c == CHAR_ESC || c == 195) {
|
|
state = ST_ESC_SEQ;
|
|
_cc_pos = 0;
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
bool timeout = false;
|
|
while (!_stream->available() &&
|
|
!(timeout = millis_since(_lastReceived) > 10)) {
|
|
delay(0);
|
|
}
|
|
if (timeout) {
|
|
state = ST_NORMAL;
|
|
break;
|
|
}
|
|
_lastReceived = millis();
|
|
c = _stream->read();
|
|
_cc_buf[_cc_pos] = c;
|
|
if ((c == '[') || ((c >= 'A' && c <= 'Z') || c == '~')) {
|
|
_cc_pos++;
|
|
_cc_buf[++_cc_pos] = '\x00';
|
|
}
|
|
}
|
|
uint8_t i;
|
|
for (i = 0; i < 10; ++i) {
|
|
if (strcmp(_cc_buf, keyMap[i].cc) == 0) {
|
|
c = keyMap[i].ch;
|
|
state = ST_NORMAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (state == ST_ESC_SEQ) {
|
|
state = ST_NORMAL;
|
|
return;
|
|
}
|
|
|
|
// WHEN NORMAL
|
|
if (state == ST_NORMAL) {
|
|
if (c == CHAR_ESC) {
|
|
if (!_line.available()) {
|
|
// QUIT
|
|
state = ST_INACTIVE;
|
|
if (eventHandler_)
|
|
eventHandler_(EVENT_CLOSE, _stream);
|
|
} else {
|
|
// CLEAR
|
|
_line.clear();
|
|
if (_controlCodes) {
|
|
clear_line();
|
|
} else {
|
|
println();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (c) {
|
|
case CHAR_CR:
|
|
println();
|
|
if (inputHandler_)
|
|
inputHandler_(_line.c_str());
|
|
_line.clear();
|
|
moveY++;
|
|
break;
|
|
case CHAR_TAB:
|
|
if (eventHandler_)
|
|
eventHandler_(EVENT_TAB, _stream);
|
|
return;
|
|
case KEY_LEFT:
|
|
if (_line.prev())
|
|
moveX--;
|
|
break;
|
|
case KEY_RIGHT:
|
|
if (_line.next())
|
|
moveX++;
|
|
break;
|
|
case KEY_HOME:
|
|
moveX = -1 * _line.home();
|
|
break;
|
|
case KEY_END:
|
|
moveX = _line.end();
|
|
break;
|
|
case CHAR_BS:
|
|
case KEY_DEL:
|
|
if (_line.backspace()) {
|
|
backsp();
|
|
moveX--;
|
|
}
|
|
break;
|
|
default:
|
|
// printable ascii 7bit or printable 8bit ISO8859
|
|
if ((c & '\x7F') >= 32 && (c & '\x7F') < 127)
|
|
if (_line.write(c)) {
|
|
if (_echo) write(c);
|
|
moveX++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// if (controlCodesEnabled)
|
|
// move(startY + moveY, startX + moveX);
|
|
}
|
|
}
|
|
|
|
bool Terminal::setLine(const uint8_t *ptr, size_t size) {
|
|
_line.clear();
|
|
if (_line.write(ptr, size))
|
|
print(_line.c_str());
|
|
return true;
|
|
}
|
|
|
|
CharBuffer &Terminal::getLine() { return _line; }
|
|
|
|
void Terminal::start() {
|
|
if (_controlCodes) initscr();
|
|
println();
|
|
}
|
|
|
|
void Terminal::initscr() {
|
|
write_P(SEQ_LOAD_G1);
|
|
attrset(A_NORMAL);
|
|
move(0, 0);
|
|
clear();
|
|
}
|
|
|
|
void Terminal::attrset(const uint16_t attr) {
|
|
uint8_t i;
|
|
|
|
if (attr != this->attr) {
|
|
this->write_P(SEQ_ATTRSET);
|
|
|
|
i = (attr & F_COLOR) >> 8;
|
|
|
|
if (i >= 1 && i <= 8) {
|
|
this->write_P(SEQ_ATTRSET_FCOLOR);
|
|
this->write(i - 1 + '0');
|
|
}
|
|
|
|
i = (attr & B_COLOR) >> 12;
|
|
|
|
if (i >= 1 && i <= 8) {
|
|
this->write_P(SEQ_ATTRSET_BCOLOR);
|
|
this->write(i - 1 + '0');
|
|
}
|
|
|
|
if (attr & A_REVERSE)
|
|
this->write_P(SEQ_ATTRSET_REVERSE);
|
|
if (attr & A_UNDERLINE)
|
|
this->write_P(SEQ_ATTRSET_UNDERLINE);
|
|
if (attr & A_BLINK)
|
|
this->write_P(SEQ_ATTRSET_BLINK);
|
|
if (attr & A_BOLD)
|
|
this->write_P(SEQ_ATTRSET_BOLD);
|
|
if (attr & A_DIM)
|
|
this->write_P(SEQ_ATTRSET_DIM);
|
|
this->write('m');
|
|
this->attr = attr;
|
|
}
|
|
}
|
|
|
|
void Terminal::clear() { write_P(SEQ_CLEAR); }
|
|
|
|
void Terminal::clear_line() {
|
|
write(CHAR_CR);
|
|
write_P(ESC_CLEAR_EOL);
|
|
}
|
|
|
|
void Terminal::move(uint8_t y, uint8_t x) {
|
|
write_P(SEQ_CSI);
|
|
writeByDigit(y + 1);
|
|
write(';');
|
|
writeByDigit(x + 1);
|
|
write('H');
|
|
curY = y;
|
|
curX = x;
|
|
}
|
|
|
|
void Terminal::writeByDigit(uint8_t i) {
|
|
uint8_t ii;
|
|
if (i >= 10) {
|
|
if (i >= 100) {
|
|
ii = i / 100;
|
|
write(ii + '0');
|
|
i -= 100 * ii;
|
|
}
|
|
ii = i / 10;
|
|
write(ii + '0');
|
|
i -= 10 * ii;
|
|
}
|
|
write(i + '0');
|
|
}
|
|
|
|
void Terminal::backsp() {
|
|
write(CHAR_BS);
|
|
write(CHAR_SPACE);
|
|
write(CHAR_BS);
|
|
}
|
|
|
|
size_t Terminal::println(const char *str) {
|
|
size_t n = print(str);
|
|
return n += println();
|
|
}
|
|
|
|
size_t Terminal::println(void) {
|
|
size_t n = 0;
|
|
switch (_eol) {
|
|
case CRLF:
|
|
n += write(CHAR_CR);
|
|
n += write(CHAR_LF);
|
|
break;
|
|
case LF:
|
|
n += write(CHAR_LF);
|
|
break;
|
|
case LFCR:
|
|
n += write(CHAR_LF);
|
|
n += write(CHAR_CR);
|
|
break;
|
|
case CR:
|
|
n += write(CHAR_CR);
|
|
break;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
size_t Terminal::write(uint8_t ch) {
|
|
size_t n = 0;
|
|
if (_stream)
|
|
n = _stream->write(ch);
|
|
return n;
|
|
}
|
|
|
|
size_t Terminal::write_P(PGM_P str) {
|
|
uint8_t ch;
|
|
size_t n = 0;
|
|
while ((ch = pgm_read_byte(str + n)) != '\x0') {
|
|
_stream->write(ch);
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
size_t Terminal::write(const uint8_t *buf, size_t size) {
|
|
size_t n = 0;
|
|
while (size--) {
|
|
if (_stream->write(*buf++))
|
|
n++;
|
|
else
|
|
break;
|
|
}
|
|
return n;
|
|
} |