|
|
|
|
@@ -26,17 +26,26 @@
|
|
|
|
|
#include "trace.h"
|
|
|
|
|
#include "platform_config.h"
|
|
|
|
|
#include "telnet.h"
|
|
|
|
|
#include "tools.h"
|
|
|
|
|
|
|
|
|
|
#include "messaging.h"
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
pthread_t thread_console;
|
|
|
|
|
static pthread_t thread_console;
|
|
|
|
|
static void * console_thread();
|
|
|
|
|
void console_start();
|
|
|
|
|
static const char * TAG = "console";
|
|
|
|
|
extern bool bypass_network_manager;
|
|
|
|
|
extern void register_squeezelite();
|
|
|
|
|
|
|
|
|
|
static EXT_RAM_ATTR QueueHandle_t uart_queue;
|
|
|
|
|
static EXT_RAM_ATTR struct {
|
|
|
|
|
uint8_t _buf[128];
|
|
|
|
|
StaticRingbuffer_t _ringbuf;
|
|
|
|
|
RingbufHandle_t handle;
|
|
|
|
|
QueueSetHandle_t queue_set;
|
|
|
|
|
} stdin_redir;
|
|
|
|
|
|
|
|
|
|
/* Prompt to be printed before each line.
|
|
|
|
|
* This can be customized, made dynamic, etc.
|
|
|
|
|
*/
|
|
|
|
|
@@ -50,7 +59,7 @@ const char* recovery_prompt = LOG_COLOR_E "recovery-squeezelite-esp32> " LOG_RES
|
|
|
|
|
|
|
|
|
|
#define MOUNT_PATH "/data"
|
|
|
|
|
#define HISTORY_PATH MOUNT_PATH "/history.txt"
|
|
|
|
|
esp_err_t run_command(char * line);
|
|
|
|
|
static esp_err_t run_command(char * line);
|
|
|
|
|
#define ADD_TO_JSON(o,t,n) if (t->n) cJSON_AddStringToObject(o,QUOTE(n),t->n);
|
|
|
|
|
#define ADD_PARMS_TO_CMD(o,t,n) { cJSON * parms = ParmsToJSON(&t.n->hdr); if(parms) cJSON_AddItemToObject(o,QUOTE(n),parms); }
|
|
|
|
|
cJSON * cmdList;
|
|
|
|
|
@@ -230,17 +239,43 @@ void process_autoexec(){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t stdin_read(int fd, void* data, size_t size) {
|
|
|
|
|
size_t bytes = -1;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
QueueSetMemberHandle_t activated = xQueueSelectFromSet(stdin_redir.queue_set, portMAX_DELAY);
|
|
|
|
|
|
|
|
|
|
if (activated == uart_queue) {
|
|
|
|
|
uart_event_t event;
|
|
|
|
|
|
|
|
|
|
xQueueReceive(uart_queue, &event, 0);
|
|
|
|
|
|
|
|
|
|
if (event.type == UART_DATA) {
|
|
|
|
|
bytes = uart_read_bytes(CONFIG_ESP_CONSOLE_UART_NUM, data, size < event.size ? size : event.size, 0);
|
|
|
|
|
// we have to do our own line ending translation here
|
|
|
|
|
for (int i = 0; i < bytes; i++) if (((char*)data)[i] == '\r') ((char*)data)[i] = '\n';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if (xRingbufferCanRead(stdin_redir.handle, activated)) {
|
|
|
|
|
char *p = xRingbufferReceiveUpTo(stdin_redir.handle, &bytes, 0, size);
|
|
|
|
|
// we might receive strings, replace null by \n
|
|
|
|
|
for (int i = 0; i < bytes; i++) if (p[i] == '\0' || p[i] == '\r') p[i] = '\n';
|
|
|
|
|
memcpy(data, p, bytes);
|
|
|
|
|
vRingbufferReturnItem(stdin_redir.handle, p);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stdin_dummy(const char * path, int flags, int mode) { return 0; }
|
|
|
|
|
|
|
|
|
|
void initialize_console() {
|
|
|
|
|
|
|
|
|
|
/* Disable buffering on stdin */
|
|
|
|
|
setvbuf(stdin, NULL, _IONBF, 0);
|
|
|
|
|
|
|
|
|
|
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
|
|
|
|
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
|
|
|
|
|
/* Move the caret to the beginning of the next line on '\n' */
|
|
|
|
|
esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
|
|
|
|
|
|
|
|
|
|
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed (unused if we redirect stdin) */
|
|
|
|
|
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
|
|
|
|
/* Move the caret to the beginning of the next line on '\n' */
|
|
|
|
|
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
|
|
|
|
|
|
|
|
|
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
|
|
|
|
|
* correct while APB frequency is changing in light sleep mode.
|
|
|
|
|
@@ -252,10 +287,28 @@ void initialize_console() {
|
|
|
|
|
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
|
|
|
|
|
|
|
|
|
|
/* Install UART driver for interrupt-driven reads and writes */
|
|
|
|
|
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 3, &uart_queue, 0));
|
|
|
|
|
|
|
|
|
|
/* Tell VFS to use UART driver */
|
|
|
|
|
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
|
|
|
|
|
|
|
|
|
/* re-direct stdin to our own driver so we can gather data from various sources */
|
|
|
|
|
stdin_redir.queue_set = xQueueCreateSet(2);
|
|
|
|
|
stdin_redir.handle = xRingbufferCreateStatic(sizeof(stdin_redir._buf), RINGBUF_TYPE_BYTEBUF, stdin_redir._buf, &stdin_redir._ringbuf);
|
|
|
|
|
xRingbufferAddToQueueSetRead(stdin_redir.handle, stdin_redir.queue_set);
|
|
|
|
|
xQueueAddToSet(uart_queue, stdin_redir.queue_set);
|
|
|
|
|
|
|
|
|
|
const esp_vfs_t vfs = {
|
|
|
|
|
.flags = ESP_VFS_FLAG_DEFAULT,
|
|
|
|
|
.open = stdin_dummy,
|
|
|
|
|
.read = stdin_read,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(esp_vfs_register("/dev/console", &vfs, NULL));
|
|
|
|
|
freopen("/dev/console", "r", stdin);
|
|
|
|
|
|
|
|
|
|
/* Disable buffering on stdin */
|
|
|
|
|
setvbuf(stdin, NULL, _IONBF, 0);
|
|
|
|
|
|
|
|
|
|
/* Initialize the console */
|
|
|
|
|
esp_console_config_t console_config = { .max_cmdline_args = 28,
|
|
|
|
|
@@ -283,20 +336,14 @@ void initialize_console() {
|
|
|
|
|
//linenoiseHistoryLoad(HISTORY_PATH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool console_push(const char *data, size_t size) {
|
|
|
|
|
return xRingbufferSend(stdin_redir.handle, data, size, pdMS_TO_TICKS(100)) == pdPASS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void console_start() {
|
|
|
|
|
if(!is_serial_suppressed()){
|
|
|
|
|
initialize_console();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Initialize the console */
|
|
|
|
|
esp_console_config_t console_config = { .max_cmdline_args = 28,
|
|
|
|
|
.max_cmdline_length = 600,
|
|
|
|
|
#if CONFIG_LOG_COLORS
|
|
|
|
|
.hint_color = atoi(LOG_COLOR_CYAN)
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
ESP_ERROR_CHECK(esp_console_init(&console_config));
|
|
|
|
|
}
|
|
|
|
|
/* we always run console b/c telnet sends commands to stdin */
|
|
|
|
|
initialize_console();
|
|
|
|
|
|
|
|
|
|
/* Register commands */
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Registering help command");
|
|
|
|
|
esp_console_register_help_command();
|
|
|
|
|
@@ -320,67 +367,58 @@ void console_start() {
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Registering i2c commands");
|
|
|
|
|
register_i2ctools();
|
|
|
|
|
|
|
|
|
|
if(!is_serial_suppressed()){
|
|
|
|
|
printf("\n");
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
printf("****************************************************************\n"
|
|
|
|
|
"RECOVERY APPLICATION\n"
|
|
|
|
|
"This mode is used to flash Squeezelite into the OTA partition\n"
|
|
|
|
|
"****\n\n");
|
|
|
|
|
}
|
|
|
|
|
printf("Type 'help' to get the list of commands.\n"
|
|
|
|
|
"Use UP/DOWN arrows to navigate through command history.\n"
|
|
|
|
|
"Press TAB when typing command name to auto-complete.\n"
|
|
|
|
|
"\n");
|
|
|
|
|
if(!is_recovery_running){
|
|
|
|
|
printf("To automatically execute lines at startup:\n"
|
|
|
|
|
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
|
|
|
|
|
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n");
|
|
|
|
|
}
|
|
|
|
|
printf("\n\n");
|
|
|
|
|
|
|
|
|
|
/* Figure out if the terminal supports escape sequences */
|
|
|
|
|
int probe_status = linenoiseProbe();
|
|
|
|
|
if (probe_status) { /* zero indicates success */
|
|
|
|
|
printf("\n****************************\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"
|
|
|
|
|
"****************************\n");
|
|
|
|
|
linenoiseSetDumbMode(1);
|
|
|
|
|
#if CONFIG_LOG_COLORS
|
|
|
|
|
/* Since the terminal doesn't support escape sequences,
|
|
|
|
|
* don't use color codes in the prompt.
|
|
|
|
|
*/
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
recovery_prompt= "recovery-squeezelite-esp32>";
|
|
|
|
|
}
|
|
|
|
|
prompt = "squeezelite-esp32> ";
|
|
|
|
|
|
|
|
|
|
#endif //CONFIG_LOG_COLORS
|
|
|
|
|
}
|
|
|
|
|
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
|
|
|
|
cfg.thread_name= "console";
|
|
|
|
|
cfg.inherit_cfg = true;
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
prompt = recovery_prompt;
|
|
|
|
|
cfg.stack_size = 4096 ;
|
|
|
|
|
}
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Creating console thread with stack size of 4096 bytes");
|
|
|
|
|
esp_pthread_set_cfg(&cfg);
|
|
|
|
|
pthread_attr_t attr;
|
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
|
pthread_create(&thread_console, &attr, console_thread, NULL);
|
|
|
|
|
pthread_attr_destroy(&attr);
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Console thread created");
|
|
|
|
|
}
|
|
|
|
|
else if(!is_recovery_running){
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Running autoexec");
|
|
|
|
|
process_autoexec();
|
|
|
|
|
printf("\n");
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
printf("****************************************************************\n"
|
|
|
|
|
"RECOVERY APPLICATION\n"
|
|
|
|
|
"This mode is used to flash Squeezelite into the OTA partition\n"
|
|
|
|
|
"****\n\n");
|
|
|
|
|
}
|
|
|
|
|
printf("Type 'help' to get the list of commands.\n"
|
|
|
|
|
"Use UP/DOWN arrows to navigate through command history.\n"
|
|
|
|
|
"Press TAB when typing command name to auto-complete.\n"
|
|
|
|
|
"\n");
|
|
|
|
|
if(!is_recovery_running){
|
|
|
|
|
printf("To automatically execute lines at startup:\n"
|
|
|
|
|
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
|
|
|
|
|
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n");
|
|
|
|
|
}
|
|
|
|
|
printf("\n\n");
|
|
|
|
|
|
|
|
|
|
/* Figure out if the terminal supports escape sequences */
|
|
|
|
|
int probe_status = linenoiseProbe();
|
|
|
|
|
if (probe_status) { /* zero indicates success */
|
|
|
|
|
printf("\n****************************\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"
|
|
|
|
|
"****************************\n");
|
|
|
|
|
linenoiseSetDumbMode(1);
|
|
|
|
|
#if CONFIG_LOG_COLORS
|
|
|
|
|
/* Since the terminal doesn't support escape sequences,
|
|
|
|
|
* don't use color codes in the prompt.
|
|
|
|
|
*/
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
recovery_prompt= "recovery-squeezelite-esp32>";
|
|
|
|
|
}
|
|
|
|
|
prompt = "squeezelite-esp32> ";
|
|
|
|
|
#endif //CONFIG_LOG_COLORS
|
|
|
|
|
}
|
|
|
|
|
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
|
|
|
|
cfg.thread_name= "console";
|
|
|
|
|
cfg.inherit_cfg = true;
|
|
|
|
|
if(is_recovery_running){
|
|
|
|
|
prompt = recovery_prompt;
|
|
|
|
|
cfg.stack_size = 4096 ;
|
|
|
|
|
}
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Creating console thread with stack size of 4096 bytes");
|
|
|
|
|
esp_pthread_set_cfg(&cfg);
|
|
|
|
|
pthread_create(&thread_console, NULL, console_thread, NULL);
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Console thread created");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
esp_err_t run_command(char * line){
|
|
|
|
|
|
|
|
|
|
static esp_err_t run_command(char * line){
|
|
|
|
|
/* Try to run the command */
|
|
|
|
|
int ret;
|
|
|
|
|
esp_err_t err = esp_console_run(line, &ret);
|
|
|
|
|
@@ -400,6 +438,7 @@ esp_err_t run_command(char * line){
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void * console_thread() {
|
|
|
|
|
if(!is_recovery_running){
|
|
|
|
|
MEMTRACE_PRINT_DELTA_MESSAGE("Running autoexec");
|
|
|
|
|
|