Browse Source

fix system freezing on telnet activation

Sebastien 5 years ago
parent
commit
0acb0dc3e7

+ 3 - 0
.gitignore

@@ -67,3 +67,6 @@ libs/
 /_*
 sdkconfig
 squeezelite-esp32-jsonblob.zip
+/flash_cmd.txt
+/writeSequeezeEsp.bat
+/writeSequeezeEsp.sh

+ 1 - 0
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
 
 

+ 1 - 1
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
 

+ 1 - 0
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
 
 

+ 1 - 0
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
 
 

+ 1 - 0
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
 
 

+ 1 - 0
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
 
 

+ 113 - 0
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
+

+ 43 - 51
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;
-
-	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);
+	UBaseType_t uxItemsWaiting;
+	UBaseType_t uxBytesToSend=bytes;
+
+    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) {

+ 1 - 0
components/telnet/telnet.h

@@ -1,3 +1,4 @@
 
 void init_telnet();
 void start_telnet(void * pvParameter);
+extern bool is_serial_suppressed();

+ 72 - 50
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");
-
-	/* 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
+	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
 
+		}
+
+
+		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() {