mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 19:24:33 +02:00
console: add support for terminal probing and dumb terminal mode
This commit is contained in:
@@ -112,6 +112,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "linenoise.h"
|
#include "linenoise.h"
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ static linenoiseHintsCallback *hintsCallback = NULL;
|
|||||||
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
|
||||||
|
|
||||||
static int mlmode = 0; /* Multi line mode. Default is single line. */
|
static int mlmode = 0; /* Multi line mode. Default is single line. */
|
||||||
|
static int dumbmode = 0; /* Dumb mode where line editing is disabled. Off by default */
|
||||||
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
|
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
|
||||||
static int history_len = 0;
|
static int history_len = 0;
|
||||||
static char **history = NULL;
|
static char **history = NULL;
|
||||||
@@ -194,6 +196,11 @@ void linenoiseSetMultiLine(int ml) {
|
|||||||
mlmode = ml;
|
mlmode = ml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set if terminal does not recognize escape sequences */
|
||||||
|
void linenoiseSetDumbMode(int set) {
|
||||||
|
dumbmode = set;
|
||||||
|
}
|
||||||
|
|
||||||
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
/* Use the ESC [6n escape sequence to query the horizontal cursor position
|
||||||
* and return it. On error -1 is returned, on success the position of the
|
* and return it. On error -1 is returned, on success the position of the
|
||||||
* cursor. */
|
* cursor. */
|
||||||
@@ -204,6 +211,7 @@ static int getCursorPosition() {
|
|||||||
|
|
||||||
/* Report cursor location */
|
/* Report cursor location */
|
||||||
fprintf(stdout, "\x1b[6n");
|
fprintf(stdout, "\x1b[6n");
|
||||||
|
|
||||||
/* Read the response: ESC [ rows ; cols R */
|
/* Read the response: ESC [ rows ; cols R */
|
||||||
while (i < sizeof(buf)-1) {
|
while (i < sizeof(buf)-1) {
|
||||||
if (fread(buf+i, 1, 1, stdin) != 1) break;
|
if (fread(buf+i, 1, 1, stdin) != 1) break;
|
||||||
@@ -875,6 +883,38 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
|
|||||||
return l.len;
|
return l.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int linenoiseProbe() {
|
||||||
|
/* Switch to non-blocking mode */
|
||||||
|
int flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
int res = fcntl(STDIN_FILENO, F_SETFL, flags);
|
||||||
|
if (res != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Device status request */
|
||||||
|
fprintf(stdout, "\x1b[5n");
|
||||||
|
|
||||||
|
/* Try to read response */
|
||||||
|
int timeout_ms = 200;
|
||||||
|
size_t read_bytes = 0;
|
||||||
|
while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n
|
||||||
|
usleep(1000);
|
||||||
|
char c;
|
||||||
|
int cb = fread(&c, 1, 1, stdin);
|
||||||
|
read_bytes += cb;
|
||||||
|
timeout_ms--;
|
||||||
|
}
|
||||||
|
/* Restore old mode */
|
||||||
|
flags &= ~O_NONBLOCK;
|
||||||
|
res = fcntl(STDIN_FILENO, F_SETFL, flags);
|
||||||
|
if (res != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (read_bytes < 4) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
||||||
int count;
|
int count;
|
||||||
@@ -885,18 +925,65 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count = linenoiseEdit(buf, buflen, prompt);
|
count = linenoiseEdit(buf, buflen, prompt);
|
||||||
printf("\n");
|
fputc('\n', stdout);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int linenoiseDumb(char* buf, size_t buflen, const char* prompt) {
|
||||||
|
/* dumb terminal, fall back to fgets */
|
||||||
|
fputs(prompt, stdout);
|
||||||
|
int count = 0;
|
||||||
|
while (count < buflen) {
|
||||||
|
int c = fgetc(stdin);
|
||||||
|
if (c == '\n') {
|
||||||
|
break;
|
||||||
|
} else if (c >= 0x1c && c <= 0x1f){
|
||||||
|
continue; /* consume arrow keys */
|
||||||
|
} else if (c == BACKSPACE || c == 0x8) {
|
||||||
|
if (count > 0) {
|
||||||
|
buf[count - 1] = 0;
|
||||||
|
count --;
|
||||||
|
}
|
||||||
|
fputs("\x08 ", stdout); /* Windows CMD: erase symbol under cursor */
|
||||||
|
} else {
|
||||||
|
buf[count] = c;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
fputc(c, stdout); /* echo */
|
||||||
|
}
|
||||||
|
fputc('\n', stdout);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sanitize(char* src) {
|
||||||
|
char* dst = src;
|
||||||
|
for (int c = *src; c != 0; src++, c = *src) {
|
||||||
|
if (isprint(c)) {
|
||||||
|
*dst = c;
|
||||||
|
++dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* The high level function that is the main API of the linenoise library. */
|
/* The high level function that is the main API of the linenoise library. */
|
||||||
char *linenoise(const char *prompt) {
|
char *linenoise(const char *prompt) {
|
||||||
char buf[LINENOISE_MAX_LINE];
|
char *buf = calloc(1, LINENOISE_MAX_LINE);
|
||||||
int count;
|
int count = 0;
|
||||||
|
if (!dumbmode) {
|
||||||
count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
|
count = linenoiseRaw(buf, LINENOISE_MAX_LINE, prompt);
|
||||||
if (count == -1) return NULL;
|
} else {
|
||||||
return strdup(buf);
|
count = linenoiseDumb(buf, LINENOISE_MAX_LINE, prompt);
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
sanitize(buf);
|
||||||
|
count = strlen(buf);
|
||||||
|
}
|
||||||
|
if (count <= 0) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is just a wrapper the user may want to call in order to make sure
|
/* This is just a wrapper the user may want to call in order to make sure
|
||||||
|
@@ -56,6 +56,7 @@ void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
|||||||
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||||
|
|
||||||
|
int linenoiseProbe(void);
|
||||||
char *linenoise(const char *prompt);
|
char *linenoise(const char *prompt);
|
||||||
void linenoiseFree(void *ptr);
|
void linenoiseFree(void *ptr);
|
||||||
int linenoiseHistoryAdd(const char *line);
|
int linenoiseHistoryAdd(const char *line);
|
||||||
@@ -65,6 +66,7 @@ int linenoiseHistoryLoad(const char *filename);
|
|||||||
void linenoiseHistoryFree();
|
void linenoiseHistoryFree();
|
||||||
void linenoiseClearScreen(void);
|
void linenoiseClearScreen(void);
|
||||||
void linenoiseSetMultiLine(int ml);
|
void linenoiseSetMultiLine(int ml);
|
||||||
|
void linenoiseSetDumbMode(int set);
|
||||||
void linenoisePrintKeyCodes(void);
|
void linenoisePrintKeyCodes(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -105,41 +105,58 @@ void app_main()
|
|||||||
register_system();
|
register_system();
|
||||||
register_wifi();
|
register_wifi();
|
||||||
|
|
||||||
|
/* Prompt to be printed before each line.
|
||||||
|
* This can be customized, made dynamic, etc.
|
||||||
|
*/
|
||||||
|
const char* prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
|
||||||
|
|
||||||
printf("\n"
|
printf("\n"
|
||||||
"This is an example of ESP-IDF console component.\n"
|
"This is an example of ESP-IDF console component.\n"
|
||||||
"Type 'help' to get the list of commands.\n"
|
"Type 'help' to get the list of commands.\n"
|
||||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||||
"Press TAB when typing command name to auto-complete.\n");
|
"Press TAB when typing command name to auto-complete.\n");
|
||||||
|
|
||||||
/* Prompt to be printed before each line.
|
/* Figure out if the terminal supports escape sequences */
|
||||||
* This can be customized, made dynamic, etc.
|
int probe_status = linenoiseProbe();
|
||||||
*/
|
if (probe_status) { /* zero indicates success */
|
||||||
const char* prompt = LOG_COLOR_I "[esp32]> " LOG_RESET_COLOR;
|
printf("\n"
|
||||||
|
"Your terminal application does not support escape sequences.\n"
|
||||||
|
"Line editing and history features are disabled.\n"
|
||||||
|
"On Windows, try using Putty instead.\n");
|
||||||
|
linenoiseSetDumbMode(1);
|
||||||
|
#if CONFIG_LOG_COLORS
|
||||||
|
/* Since the terminal doesn't support escape sequences,
|
||||||
|
* don't use color codes in the prompt.
|
||||||
|
*/
|
||||||
|
prompt = "esp32> ";
|
||||||
|
#endif //CONFIG_LOG_COLORS
|
||||||
|
}
|
||||||
|
|
||||||
/* Main loop */
|
/* Main loop */
|
||||||
char *line;
|
while(true) {
|
||||||
/* Get a line using linenoise.
|
/* Get a line using linenoise.
|
||||||
* The line is returned when ENTER is pressed.
|
* The line is returned when ENTER is pressed.
|
||||||
*/
|
*/
|
||||||
while((line = linenoise(prompt)) != NULL) {
|
char* line = linenoise(prompt);
|
||||||
if (strlen(line) > 0) { /* Ignore empty lines */
|
if (line == NULL) { /* Ignore empty lines */
|
||||||
/* Add the command to the history */
|
continue;
|
||||||
linenoiseHistoryAdd(line);
|
}
|
||||||
|
/* Add the command to the history */
|
||||||
|
linenoiseHistoryAdd(line);
|
||||||
#if CONFIG_STORE_HISTORY
|
#if CONFIG_STORE_HISTORY
|
||||||
/* Save command history to filesystem */
|
/* Save command history to filesystem */
|
||||||
linenoiseHistorySave(HISTORY_PATH);
|
linenoiseHistorySave(HISTORY_PATH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Try to run the command */
|
/* Try to run the command */
|
||||||
int ret;
|
int ret;
|
||||||
esp_err_t err = esp_console_run(line, &ret);
|
esp_err_t err = esp_console_run(line, &ret);
|
||||||
if (err == ESP_ERR_NOT_FOUND) {
|
if (err == ESP_ERR_NOT_FOUND) {
|
||||||
printf("Unrecognized command\n");
|
printf("Unrecognized command\n");
|
||||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||||
printf("Command returned non-zero error code: 0x%x\n", ret);
|
printf("Command returned non-zero error code: 0x%x\n", ret);
|
||||||
} else if (err != ESP_OK) {
|
} else if (err != ESP_OK) {
|
||||||
printf("Internal error: 0x%x\n", err);
|
printf("Internal error: 0x%x\n", err);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||||
linenoiseFree(line);
|
linenoiseFree(line);
|
||||||
|
Reference in New Issue
Block a user