Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 98 additions & 27 deletions CYD-Klipper/src/ui/serial/serial_console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,49 @@

#define MAX_COMDLINE_SIZE 80
#define MAX_WORDS 6
#define BACKSPACE_CHAR 0x08
#define ESCAPE_CHAR '\x1b'
#define CSI_CHAR '['
#define LEFT_ARROW_CHAR 'D'
#define RIGHT_ARROW_CHAR 'C'
#define DELETE_KEY_1_CHAR '3'
#define DELETE_KEY_2_CHAR '~'
#define PRINT_CHAR_START 32
#define PRINT_CHAR_END 126

namespace serial_console
{
bool global_disable_serial_console = false;

/**
* @brief Redraws the characters from the current cursor position to the end of the buffer on the serial console.
*
* This function is used to update the terminal display when characters are inserted or deleted
* in the middle of the input buffer. It:
* - Saves the current cursor position
* - Clears the line from the cursor to the end
* - Prints characters from 'cur' to 'len'
* - Restores the original cursor position
*
* @param cur Current cursor position within the buffer
* @param len Current length of the buffer (number of characters entered)
* @param buf Character buffer containing the input string
*/
static inline void redraw(const int cur, const int len, char *buf) {
if (!temporary_config.remote_echo)
return;

Serial.print("\x1b[s");
Serial.print("\x1b[K");

// Reprint characters from cur to end
for (int i = cur; i < len; i++) {
Serial.print((char)buf[i]);
}

Serial.print(" \x1b[u");
}

/*
* read_string_until: Non-blocking replacement for Serial.readStringUntil()..
* With delimeter '\n' acts as 'read line'.
Expand All @@ -20,6 +58,7 @@ namespace serial_console
bool read_string_until(char delimiter, char *result, int max_len)
{
static int index = 0;
static int cur = 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!

Expand All @@ -28,43 +67,75 @@ namespace serial_console
--cnt;

// backspaceF
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.
if (c == BACKSPACE_CHAR && cur > 0) {
// shift characters left from cursor position
memmove(&result[cur - 1], &result[cur], index - cur);
index--;
}
continue;
}
cur--;
// move cursor left on terminal and redraw updated string
if(temporary_config.remote_echo) Serial.print("\x1b[D");
redraw(cur, index, result);
// handle ANSI escape sequences (arrow keys, delete key)
} else if (c == ESCAPE_CHAR) {

if ((c = Serial.read()) == -1)
break;

if(temporary_config.remote_echo) Serial.print((char)c); // echo
// Expect '[' character
if (c != CSI_CHAR)
continue;

// 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 ((c = Serial.read()) == -1)
break;

if (index >= max_len - 1)
{
if (c == delimiter) // got delimeter: flush buffer quietly, restart collection.
{
// Left arrow key
if (c == LEFT_ARROW_CHAR && cur > 0) {
// move cursor left on terminal
if(temporary_config.remote_echo) Serial.print("\x1b[D");
cur--;
// Right arrow key
} else if(c == RIGHT_ARROW_CHAR && cur < index) {
// move cursor right on terminal
if(temporary_config.remote_echo) Serial.print("\x1b[C");
cur++;
// Delete key
} else if(c == DELETE_KEY_1_CHAR) {
if ((c = Serial.read()) == -1)
break;
if (c == DELETE_KEY_2_CHAR && cur < index) {
memmove(&result[cur], &result[cur + 1], index - cur - 1);
index--;
redraw(cur, index, result);
}
}

// Handle printable characters
} else if (c >= PRINT_CHAR_START && c <= PRINT_CHAR_END) {
// Append character at the end
if (index < max_len - 1 && cur == index) {
if(temporary_config.remote_echo) Serial.print((char)c);
result[index++] = c;
cur++;
// Insert character in the middl
} else if (index < max_len - 1) {
memmove(&result[cur + 1], &result[cur], index - cur);
result[cur] = c;
index++;
if(temporary_config.remote_echo) Serial.print((char)c);
cur++;
redraw(cur, index, result);
} else if (c == delimiter) { // got delimeter: flush buffer quietly, restart collection.
index = 0;
cur = 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)
{
} else if (c == delimiter) {

if(temporary_config.remote_echo) Serial.println();
result[index] = '\0'; // Null-terminate the string
index = 0;
cur = 0;
return true; // Success: Delimiter found
}
}
Expand Down
Loading