diff --git a/.gitignore b/.gitignore index 6fae3f75..8f3b64f6 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ libs/ /_* sdkconfig squeezelite-esp32-jsonblob.zip +/flash_cmd.txt +/writeSequeezeEsp.bat +/writeSequeezeEsp.sh diff --git a/build-scripts/ESP32-A1S-sdkconfig.defaults b/build-scripts/ESP32-A1S-sdkconfig.defaults index b143fa21..0592a074 100644 --- a/build-scripts/ESP32-A1S-sdkconfig.defaults +++ b/build-scripts/ESP32-A1S-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 5fee8c1d..0dc46d30 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -594,7 +594,7 @@ CONFIG_FMB_TIMER_INDEX=0 CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y - +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_HZ=100 CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults index f0819243..96583af2 100644 --- a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults @@ -597,6 +597,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults index 8665f49c..72c3a1ed 100644 --- a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults index da977fe5..ea2b0531 100644 --- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults index de796d67..94484e00 100644 --- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults @@ -590,6 +590,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build_flash_cmd.sh b/build_flash_cmd.sh new file mode 100644 index 00000000..7124e1f3 --- /dev/null +++ b/build_flash_cmd.sh @@ -0,0 +1,113 @@ +#!/bin/bash +echo +echo ================================================================= +echo Build flash command +echo ================================================================= +# Location of partitions.csv relative to this script +partitionsCsv="../partitions.csv" + +# File to output readme instructions to +outputReadme="./flash_cmd.txt" + +# File to output bash script to +outputBashScript="./writeSequeezeEsp.sh" + +# File to output bat script to +outputBatScript="./writeSequeezeEsp.bat" + +# The name of partitions to ignore from partitions.csv +paritionsToIgnore=( + "nvs" + "phy_init" + "storage" + "coredump" + "settings" +) + +# Function that maps partition name to actual bin file +# defaults to "[PARTION_NAME_FROM_CSV].bin" +function partitionNameToBinFile { + if [[ "$1" == "otadata" ]]; then + echo "ota_data_initial.bin" + elif [[ "$1" == "ota_0" || "$1" == "factory" ]]; then + echo "squeezelite.bin" + else + echo $1.bin + fi +} + +# write parameters for esptool.py +writeParameters="$writeParameters write_flash" +writeParameters="$writeParameters --flash_mode dio --flash_freq 80m --flash_size detect" + +# bootloader.bin and partitions.bin not in partitions.csv so manually add here +partitionsParameters=" 0x1000 bootloader/bootloader.bin" +partitionsParameters="$partitionsParameters 0x8000 partitions.bin" + +# ============================================================================== + +# Loop over partitions.csv and add partition bins and offsets to partitionsParameters + +for line in $($IDF_PATH/components/partition_table/gen_esp32part.py --quiet build/partitions.bin | grep '^[^#]') +do + partitionName=$(echo $line | awk -F',' '{printf "%s", $1}' ) + partitionOffset=$(echo $line |awk -F',' '{printf "%s", $4}' ) + partitionFile=$(partitionNameToBinFile $partitionName) + + if [[ " ${paritionsToIgnore[@]} " =~ " ${partitionName} " ]]; then + continue + fi + + partitionsParameters="$partitionsParameters $partitionOffset $partitionFile" + echo "$partitionsParameters" + +done + +# Write README Instructions +if [ ! -f "$outputReadme" ]; then + touch $outputReadme +fi + +echo "" >> $outputReadme +echo "====LINUX====" >> $outputReadme +echo "To flash sequeezelite run the following script:" >> $outputReadme +echo "$outputBashScript [PORT_HERE] [BAUD_RATE]" >> $outputReadme +echo "e.g. $outputBashScript /dev/ttyUSB0 115200" >> $outputReadme +echo "" >> $outputReadme +echo "====WINDOWS====" >> $outputReadme +echo "To flash sequeezelite run the following script:" >> $outputReadme +echo "$outputBatScript [PORT_HERE] [BAUD_RATE]" >> $outputReadme +echo "e.g. $outputBatScript COM11 115200" >> $outputReadme +echo "" >> $outputReadme +echo "If you don't know how to run the BAT file with arguments then you can" >> $outputReadme +echo "edit the bat file in Notepad. Open the file up and edit the following:" >> $outputReadme +echo "Change 'set port=%1' to 'set port=[PORT_HERE]'. E.g. 'set port=COM11'" >> $outputReadme +echo "Change 'set baud=%2' to 'set baud=[BAUD_RATE]'. E.g. 'set baud=115200'" >> $outputReadme +echo "" >> $outputReadme +echo "====MANUAL====" >> $outputReadme +echo "Python esptool.py --port [PORT_HERE] --baud [BAUD_RATE] $writeParameters $partitionsParameters" >> $outputReadme + +# Write Linux BASH File +if [ ! -f "$outputBashScript" ]; then + touch $outputBashScript +fi + +echo "#!/bin/bash" >> $outputBashScript +echo >> $outputBashScript +echo "port=\$1" >> $outputBashScript +echo "baud=\$2" >> $outputBashScript +linuxFlashCommand="Python esptool.py --port \$port --baud \$baud" +echo "$linuxFlashCommand $writeParameters $partitionsParameters" >> $outputBashScript + +# Write Windows BAT File +if [ ! -f "$outputBatScript" ]; then + touch $outputBatScript +fi + +echo "echo off" >> $outputBatScript +echo "" >> $outputBatScript +echo "set port=%1" >> $outputBatScript +echo "set baud=%2" >> $outputBatScript +windowsFlashCommand="Python esptool.py --port %port% --baud %baud%" +echo "$windowsFlashCommand $writeParameters $partitionsParameters" >> $outputBatScript + diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index cd9bfadb..b9b94f06 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -50,7 +50,7 @@ const static char tag[] = "telnet"; static int uart_fd=0; RingbufHandle_t buf_handle; -SemaphoreHandle_t xSemaphore = NULL; +//static SemaphoreHandle_t xSemaphore = NULL; static size_t send_chunk=300; static size_t log_buf_size=2000; //32-bit aligned size static bool bIsEnabled=false; @@ -68,7 +68,7 @@ static int stdout_fstat(int fd, struct stat * st); static ssize_t stdout_write(int fd, const void * data, size_t size); static char *eventToString(telnet_event_type_t type); static void handle_telnet_conn(); -static void process_logs( UBaseType_t bytes); +static void process_logs( UBaseType_t bytes, bool is_write_op); static bool bMirrorToUART=false; struct telnetUserData { int sockfd; @@ -76,7 +76,9 @@ struct telnetUserData { char * rxbuf; }; - +bool is_serial_suppressed(){ + return !bIsEnabled || !bMirrorToUART ; +} void init_telnet(){ char *val= get_nvs_value_alloc(NVS_TYPE_STR, "telnet_enable"); if (!val || strlen(val) == 0 || !strcasestr("YXD",val) ) { @@ -100,11 +102,12 @@ void init_telnet(){ log_buf_size=log_buf_size>0?log_buf_size:4000; } // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + //vSemaphoreCreateBinary( xSemaphore ); // Redirect the output to our telnet handler as soon as possible - StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t) ); + // All non-split ring buffer must have their memory alignment set to 32 bits. + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ); buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { ESP_LOGE(tag,"Failed to create ring buffer for telnet!"); @@ -119,7 +122,9 @@ void init_telnet(){ .fstat = &stdout_fstat, .close = &stdout_close, .read = &stdout_read, + }; + if(bMirrorToUART){ uart_fd=open("/dev/uart/0", O_RDWR); } @@ -130,11 +135,11 @@ void init_telnet(){ } void start_telnet(void * pvParameter){ static bool isStarted=false; - StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - StackType_t *xStack = malloc(TELNET_STACK_SIZE); + StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + StackType_t *xStack = heap_caps_malloc(TELNET_STACK_SIZE,(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); if(!isStarted && bIsEnabled) { - xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, xTaskBuffer); + xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_MAIN_PRIO , xStack, xTaskBuffer); isStarted=true; } } @@ -275,23 +280,23 @@ static void handle_telnet_events( } // myhandle_telnet_events -static void process_logs(UBaseType_t count){ +static void process_logs( UBaseType_t bytes, bool is_write_op){ //Receive an item from no-split ring buffer size_t item_size; - UBaseType_t uxItemsWaiting; - UBaseType_t uxBytesToSend=count; + UBaseType_t uxItemsWaiting; + UBaseType_t uxBytesToSend=bytes; - vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); - if(count == 0){ - // this sends the entire buffer to the remote client - uxBytesToSend = uxItemsWaiting; - } - if( partnerSocket ==0 && (uxItemsWaiting*100 / log_buf_size) <75){ - // We still have some room in the ringbuffer and there's no telnet - // connection yet, so bail out for now. - //printf("%s() Log buffer used %u of %u bytes used\n", __FUNCTION__, uxItemsWaiting, log_buf_size); + vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); + bool is_space_available = ((log_buf_size-uxItemsWaiting)>=bytes && log_buf_size>uxItemsWaiting); + if( is_space_available && (is_write_op || partnerSocket == 0) ){ + // there's still some room left in the buffer, and we're either + // processing a write operation or telnet isn't connected yet. return; } + if(is_write_op && !is_space_available && uxBytesToSend==0){ + // flush at least the size of a full chunk + uxBytesToSend = send_chunk; + } while(uxBytesToSend>0){ char *item = (char *)xRingbufferReceiveUpTo(buf_handle, &item_size, pdMS_TO_TICKS(50), uxBytesToSend); @@ -327,12 +332,12 @@ static void handle_telnet_conn() { struct telnetUserData *pTelnetUserData = (struct telnetUserData *)malloc(sizeof(struct telnetUserData)); tnHandle = telnet_init(my_telopts, handle_telnet_events, 0, pTelnetUserData); - pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); pTelnetUserData->tnHandle = tnHandle; pTelnetUserData->sockfd = partnerSocket; // flush all the log buffer on connect - process_logs(0); + process_logs(log_buf_size, false); while(1) { //ESP_LOGD(tag, "waiting for data"); @@ -349,7 +354,7 @@ static void handle_telnet_conn() { partnerSocket = 0; return; } - process_logs(send_chunk); + process_logs(send_chunk, false); taskYIELD(); } @@ -358,37 +363,24 @@ static void handle_telnet_conn() { // ******************* stdout/stderr Redirection to ringbuffer static ssize_t stdout_write(int fd, const void * data, size_t size) { - if (xSemaphoreTake(xSemaphore, (TickType_t) 10) == pdTRUE) { - // #1 Write to ringbuffer - if (buf_handle == NULL) { - printf("%s() ABORT. file handle _log_remote_fp is NULL\n", - __FUNCTION__); - } else { - //Send an item - UBaseType_t res = xRingbufferSend(buf_handle, data, size, - pdMS_TO_TICKS(100)); - if (res != pdTRUE) { - // flush some entries - process_logs(size); - res = xRingbufferSend(buf_handle, data, size, - pdMS_TO_TICKS(100)); - if (res != pdTRUE) { - - printf("%s() ABORT. Unable to store log entry in buffer\n", - __FUNCTION__); - } - } - } - xSemaphoreGive(xSemaphore); + // #1 Write to ringbuffer + if (buf_handle == NULL) { + printf("%s() ABORT. file handle _log_remote_fp is NULL\n", + __FUNCTION__); } else { - // We could not obtain the semaphore and can therefore not access - // the shared resource safely. + // flush the buffer if needed + process_logs(size, true); + //Send an item + UBaseType_t res = xRingbufferSend(buf_handle, data, size, pdMS_TO_TICKS(10)); + assert(res == pdTRUE); + } - return bMirrorToUART?write(uart_fd, data, size):true; + return bMirrorToUART?write(uart_fd, data, size):size; } static ssize_t stdout_read(int fd, void* data, size_t size) { - return read(fd, data, size); + //return read(fd, data, size); + return 0; } static int stdout_open(const char * path, int flags, int mode) { diff --git a/components/telnet/telnet.h b/components/telnet/telnet.h index 255fa3d6..eb563ece 100644 --- a/components/telnet/telnet.h +++ b/components/telnet/telnet.h @@ -1,3 +1,4 @@ void init_telnet(); void start_telnet(void * pvParameter); +extern bool is_serial_suppressed(); diff --git a/main/console.c b/main/console.c index 2b83d68d..62bc5199 100644 --- a/main/console.c +++ b/main/console.c @@ -25,6 +25,7 @@ #include "cmd_decl.h" #include "console.h" #include "wifi_manager.h" +#include "telnet.h" #include "cmd_squeezelite.h" #include "config.h" @@ -156,8 +157,19 @@ void initialize_console() { void console_start() { - initialize_console(); - + if(!is_serial_suppressed()){ + initialize_console(); + } + else { + /* Initialize the console */ + esp_console_config_t console_config = { .max_cmdline_args = 22, + .max_cmdline_length = 600, + #if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) + #endif + }; + ESP_ERROR_CHECK(esp_console_init(&console_config)); + } /* Register commands */ esp_console_register_help_command(); register_system(); @@ -171,54 +183,64 @@ void console_start() { #error "Unknown build configuration" #endif register_i2ctools(); - printf("\n" -#if RECOVERY_APPLICATION - "****************************************************************\n" - "RECOVERY APPLICATION\n" - "This mode is used to flash Squeezelite into the OTA partition\n" - "****\n\n" -#endif - "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 !RECOVERY_APPLICATION - "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" -#endif - "\n" - "\n"); + if(!is_serial_suppressed()){ + printf("\n" + #if RECOVERY_APPLICATION + "****************************************************************\n" + "RECOVERY APPLICATION\n" + "This mode is used to flash Squeezelite into the OTA partition\n" + "****\n\n" + #endif + "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 !RECOVERY_APPLICATION + "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" + #endif + "\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. - */ - prompt = "squeezelite-esp32> "; -#endif //CONFIG_LOG_COLORS + /* 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. + */ + 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 RECOVERY_APPLICATION + cfg.stack_size = 4096 ; + #endif + 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); } - esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); - cfg.thread_name= "console"; - cfg.inherit_cfg = true; -#if RECOVERY_APPLICATION - cfg.stack_size = 4096 ; + else { +#if !RECOVERY_APPLICATION + // process autoexec locally, as we're not going to start the console thread + process_autoexec(); #endif - 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); + } } void run_command(char * line){ /* Try to run the command */ @@ -226,14 +248,14 @@ void run_command(char * line){ esp_err_t err = esp_console_run(line, &ret); if (err == ESP_ERR_NOT_FOUND) { - ESP_LOGE(TAG,"Unrecognized command: %s\n", line); + ESP_LOGE(TAG,"Unrecognized command: %s", line); } else if (err == ESP_ERR_INVALID_ARG) { // command was empty } else if (err == ESP_OK && ret != ESP_OK) { - ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)\n", ret, + ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)", ret, esp_err_to_name(err)); } else if (err != ESP_OK) { - ESP_LOGE(TAG,"Internal error: %s\n", esp_err_to_name(err)); + ESP_LOGE(TAG,"Internal error: %s", esp_err_to_name(err)); } } static void * console_thread() {