#include #include #include #include #include #include #include "console.h" #include "gen.h" #include "log.h" #include "utils.h" console::console(std::atomic_uint32_t *const stop_event, bus *const b) : stop_event(stop_event), b(b) { memset(screen_buffer, ' ', sizeof screen_buffer); } console::~console() { // done as well in subclasses but also here to // stop lgtm.com complaining about it stop_thread(); } void console::start_thread() { stop_thread_flag = false; #if !defined(ESP32) th = new std::thread(std::ref(*this)); #endif } void console::stop_thread() { if (th) { stop_thread_flag = true; th->join(); delete th; th = nullptr; } } bool console::poll_char() { std::unique_lock lck(input_lock); return input_buffer.empty() == false; } int console::get_char() { std::unique_lock lck(input_lock); if (input_buffer.empty()) return -1; char c = input_buffer.at(0); input_buffer.erase(input_buffer.begin() + 0); return c; } int console::wait_char(const int timeout_ms) { std::unique_lock lck(input_lock); using namespace std::chrono_literals; if (input_buffer.empty() == false || have_data.wait_for(lck, timeout_ms * 1ms) == std::cv_status::no_timeout) { if (input_buffer.empty() == false) { int c = input_buffer.at(0); input_buffer.erase(input_buffer.begin() + 0); return c; } } return -1; } void console::flush_input() { input_buffer.clear(); } void console::emit_backspace() { put_char(8); put_char(' '); put_char(8); } std::string console::read_line(const std::string & prompt) { put_string(prompt); put_string(">"); std::string str; for(;;) { char c = wait_char(500); if (*stop_event == EVENT_TERMINATE) return ""; if (c == -1 || c == 255 /* ESP32 has unsigned char? */) continue; if (c == 13 || c == 10) break; if (c == 8 || c == 127) { // backspace if (!str.empty()) { str = str.substr(0, str.size() - 1); emit_backspace(); } } else if (c == 21) { // ^u for(size_t i=0; i= 32) { str += c; put_char(c); } } put_string_lf(""); return str; } void console::debug(const std::string fmt, ...) { char *buffer = nullptr; va_list ap; va_start(ap, fmt); vasprintf(&buffer, fmt.c_str(), ap); va_end(ap); put_string_lf(buffer); free(buffer); } void console::put_char(const char c) { put_char_ll(c); if (c == 0) { // ignore these } else if (c == 13) tx = 0; else if (c == 10) { if (debug_buffer.empty() == false) { DOLOG(::debug, true, "TTY: %s", debug_buffer.c_str()); debug_buffer.clear(); } ty++; } else if (c == 8) { // backspace if (tx > 0) tx--; } else { screen_buffer[ty][tx++] = c; if (tx == t_width) { tx = 0; ty++; } if (debug_buffer.size() < 4096) debug_buffer += c; } if (ty == t_height) { memmove(&screen_buffer[0], &screen_buffer[1], sizeof(char) * t_width * (t_height - 1)); ty--; memset(screen_buffer[t_height - 1], ' ', t_width); } } void console::put_string(const std::string & what) { for(size_t x=0; x