Serial console (#117)

* Update readme

* Update README.md (#95)

* v1.6.4 (#113)

* Fix gcode previews with special chars not loading

* Add .gitignore file (#108)

* Bulletproof ci.py (#107)

* Implement file sorting (implement #89)

* Set chip family to ESP32-S3 for specific models (fix #67)

* Add files menu to params panel while printing (implement #80)

* Update ci.py (#110)

Typo fix for ESP32-S3 boards array name

---------

Co-authored-by: Sebastian Göls <6608231+Abrynos@users.noreply.github.com>
Co-authored-by: Miroslav Zuzelka <mzuzelka@gmail.com>

* Added serial console

* backspace, minor tweaks

* - added temporary_config alongside global_config, to hold non-persistent configuration
- added macros LOG, LOG_F, LOG_LN conditional on temporary_config.debug for Serial.print/printf/println
- put all debug to console behind these macros
- added 'debug' serial command to toggle temporary_config.debug, defaults to REPO_DEVELOPMENT
- added 'echo' serial command to toggle remote echo, temporary_config.remote_echo
- added #define DISPLAY_SECRETS to global_config.h, to censor wifi password and api key on serial console
- added entries about serial console to README.md and to _site/index.html

* restored -DREPO_DEVELOPMENT=1 (m)

* Build failed on esp32-3248S035C, reduced console input buffer size (static char cmdline) as it was failing to fit.

* typo

* A lot of what should be LOG_F was LOG_LN instead
Handling undefined REPO_DEVELOPMENT when initializing temporary_config.debug

---------

Co-authored-by: Sims <38142618+suchmememanyskill@users.noreply.github.com>
Co-authored-by: Beebles <102569435+beebls@users.noreply.github.com>
Co-authored-by: Sebastian Göls <6608231+Abrynos@users.noreply.github.com>
Co-authored-by: Miroslav Zuzelka <mzuzelka@gmail.com>
Co-authored-by: Bartosz Wucke <b.wucke@a-ster.pl>
This commit is contained in:
bwucke
2024-08-02 21:16:45 +02:00
committed by GitHub
parent 19cfaefd36
commit 41aa073ae0
21 changed files with 664 additions and 53 deletions

View File

@@ -0,0 +1,153 @@
#include "serial_commands.h"
#include "../../conf/global_config.h"
#include <HardwareSerial.h>
#include <WString.h>
#define MAX_COMDLINE_SIZE 80
#define MAX_WORDS 6
namespace serial_console
{
/*
* read_string_until: Non-blocking replacement for Serial.readStringUntil()..
* With delimeter '\n' acts as 'read line'.
* If input (line) size exceeds provided buffer's size, that entire input (until next delimeter) is silently discarded.
* Serial.available() can return true without \n being ever in the buffer, so we don't trust it here.
*/
bool read_string_until(char delimiter, char *result, int max_len)
{
static int index = 0;
int c; // read character, -1 if none
int cnt = 100; // limit on amount of iterations in one go; we're supposed to be non-blocking!
while ((c = Serial.read()) != -1 && cnt > 0)
{
--cnt;
// backspace
if (c == 8)
{
if (index > 0)
{
if(temporary_config.remote_echo) Serial.print("\x08 \x08"); // overwrite last character with space and move cursor 1 back.
index--;
}
continue;
}
if(temporary_config.remote_echo) Serial.print((char)c); // echo
// Buffer overflow handling:
// start treating current buffer as invalid:
// - stop collecting more data
// - return false on delimeter, flushing everything collected,
// - restart collection from scratch after delimeter,
// - return control as normal.
if (index >= max_len - 1)
{
if (c == delimiter) // got delimeter: flush buffer quietly, restart collection.
{
index = 0;
return false;
}
else
continue; // discard any data past the end of the buffer, keep reading
}
result[index++] = c;
// delimiter was found
if (c == delimiter)
{
result[index] = '\0'; // Null-terminate the string
index = 0;
return true; // Success: Delimiter found
}
}
return false; // still waiting for delimeter
}
// split input into words.
// assumes input ends with '\n', also ends parsing if found MAX_WORDS already.
int tokenize(String results[], char *input)
{
int index = 0;
int word_count = 0;
String word = "";
do
{
if (input[index] == '\t' || input[index] == ' ' || input[index] == '\n' || input[index] == '\r' || input[index] == '\0')
{
if (word.length() > 0)
{
results[word_count] = word;
++word_count;
if (word_count >= MAX_WORDS)
{
return word_count;
}
word = "";
}
if (input[index] == '\n' || input[index] == '\0')
{
return word_count;
}
index++;
}
else
{
word += input[index];
index++;
}
} while (1);
}
void greet()
{
Serial.println("CYD-Klipper " REPO_VERSION);
Serial.println("Type 'help' for serial console command list");
Serial.print("> ");
}
bool verify_arg_count(int got, int expected)
{
if (got != expected)
{
Serial.printf("Command expects %d argument%s, %d given.\n", expected - 1, expected == 2 ? "" : "s", got - 1);
return false;
}
return true;
}
// main "engine": non-blockingly read until newline found, parse, execute.
void run()
{
static char cmdline[MAX_COMDLINE_SIZE + 1] = {0};
if (!read_string_until('\n', cmdline, MAX_COMDLINE_SIZE))
return;
String argv[MAX_WORDS];
int argc = tokenize(argv, cmdline);
if (argc > 0)
{
do
{
int cmd_id = find_command(argv[0]);
if (cmd_id == -1)
break;
if (!verify_arg_count(argc, commandHandlers[cmd_id].argc))
break;
commandHandlers[cmd_id].function(argv);
} while (0);
}
Serial.print("> ");
}
}