Task watchdog got triggered. The following tasks did not reset the watchdog in time

mowglihaha
Posts: 10
Joined: Tue Feb 28, 2023 8:42 am

Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby mowglihaha » Tue Feb 28, 2023 8:57 am

<r>Hello, i have a question regarding a error where it looks like the watchdog is getting triggered from a usb descriptor or from a http webserver.<br/>
Im working on a project, where a ESP32-S3 is configured to pop up as a RNDIS device when it's plugged in to the computer. THe device is set to a IP-adress of 2.2.2.2 and a mac-adress based on the EFUSE mac adress is set. After that a webserver is configured, that i can access from a browser. From the webserver im sending a array[512], which "works". But after some time the error accurs. I have tried adding the terminal as well as som code snippets.<br/>
<br/>
Heres the terminal<br/>
<IMG src="%5Battachment=0%5DCapture_terminal.PNG%5B/attachment%5D"><s>Image</e></IMG><br/>
<br/>
The websocket written is initialised like the following:
<CODE><s>

Code: Select all

document.addEventListener("DOMContentLoaded", function () {
var ws;
            function connect() {
               //ws = new WebSocket('ws://' + window.location.hostname + '/ws');
               ws = new WebSocket('ws://' + "2.2.2.2:80" + '/ws');
               ws.onopen = function () {
                  // subscribe to some channels
                  ws.send(' ');
               };

               ws.onmessage = function (event) {
                  var emp = JSON.parse(event.data);
                  if (emp.hasOwnProperty('pct')) {
                     $('#display').html('<p>Uptime D:H:M:S : ' + dhm(emp.pct) + '</p>' + emp.time + '</p>Current DMX Adress: ' + Number(emp.cold).toFixed(1) + ' </p>Current DMX Mode:' + Number(emp.warm).toFixed(1) + '</p>');
                     $('#mainFooter').html('<p>Build : ' + emp.builddate + ' ' + emp.buildtime + '</p>');
                  }
                  if (emp.hasOwnProperty('log')) {


                     if (emp.log.charAt(0) === 'I') {
                        $('#log').append('<p class="log">' + emp.log + '</p>');
                     } else if (emp.log.charAt(0) === 'E') {
                        $('#log').append('<p class="logred">' + emp.log + '</p>');
                     } else {
                        $('#log').append('<p class="log">' + emp.log + '</p>');
                     }
                     var objDiv = document.getElementById("log");
                     objDiv.scrollTop = objDiv.scrollHeight;
                  }
                  if (emp.hasOwnProperty('progressFirmware')) {
                     $('#uploadfirmwareProgress').val(emp.progressFirmware);
                  }
                  //alert("I got data: " + evt.data)
               }

               ws.onclose = function (e) {
                  console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
                  setTimeout(function () {
                     connect();
                  }, 1000);
               };

               ws.onerror = function (err) {
                  console.error('Socket encountered error: ', err.message, 'Closing socket');
                  ws.close();
               };
            }
            connect();
            showTab(event, 'display');
            }
<e>
</e></CODE>

<br/>
The webserver handle is the following, the ldeCore, is just like a SQL thing:
<CODE><s>

Code: Select all

</s>static esp_err_t ws_handler(httpd_req_t *req) {
	uint8_t *buf = NULL;
	if (req->method == HTTP_GET) {
		ESP_LOGI(TAG, "Handshake done, the new connection was opened");
		return ESP_OK;
	}
	/* Set max_len = 0 to get the frame len */
	esp_err_t ret;	// = httpd_ws_recv_frame(req, &ws_pkt, 2000);
	httpd_ws_frame_t ws_pkt;
	memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
	ws_pkt.type = HTTPD_WS_TYPE_TEXT;
	ws_pkt.payload = (uint8_t*) readBufWS;
	/* Set max_len = 0 to get the frame len */
	ret = httpd_ws_recv_frame(req, &ws_pkt, 0);
	//ESP_LOGI(TAG, "frame len is %d", ws_pkt.len);
	if(ws_pkt.len){
		buf = calloc(1,ws_pkt.len +1);
		if(buf == NULL){
			ESP_LOGE(TAG, "Failed to calloc memory for buf");
			free(buf);
			return ESP_ERR_NO_MEM;
		}
		ws_pkt.payload = buf;

		ret = httpd_ws_recv_frame(req, &ws_pkt,ws_pkt.len);
		if(ret != ESP_OK){
			free(buf);
			return ret;
		}
		//ESP_LOGI(TAG, "Got packet with message: %s %d", ws_pkt.payload, ws_pkt.len);
	}
	if (ws_pkt.len < readBufSize && ws_pkt.len > 0) {
		//if(ws_pkt.len)
		if (ldeCore_ItemCount(socks) == 0) {
			//esp_log_set_vprintf(vprintf_dvt);
		}
		int count = jsmn_parse(&parser,(char*)ws_pkt.payload,  strlen((char*)ws_pkt.payload), t, 256); // "s" is the char array holding the json content
		int i = 0;
		//ESP_LOGE(TAG, "json: %d",  count);
		if(count < 0){
			//	ESP_LOGE(TAG, "json: %s",  ws_pkt.payload);
		}
		if(count > 0){
			for (i = 1; i < count; i++) {
				if (jsoneq((char*)ws_pkt.payload, &t[i], "dhcp") == 0) {
					//	ESP_LOGE(TAG, "dhcp: %s",  ((char*)ws_pkt.payload) + t[i + 1].start);

				}

			}
		}
		if (!ldeCore_IdxHasItem(socks->idx_Socket, req->handle)) {
			websock_instance *dev;

			dev = ldeCore_ItemAdd(socks);
			dev->descriptor = httpd_req_to_sockfd(req);
			dev->handle = req->handle;
			req->sess_ctx = dev; // Set to nonzero otherwise free_ctx won't get called.
			req->free_ctx = socket_close_cleanup;

			ldeCore_IdxIns(socks->idx_Socket, dev);
			//ESP_LOGE(TAG, "Added socket");
		}
		readBufWS[ws_pkt.len] = 0; // null termination
		if(memcmp(ws_pkt.payload,"settime_",8) == 0){
			uint32_t time = atoi((char*)&ws_pkt.payload[8]);
			ESP_LOGI(TAG, "time: %s %d %d", &ws_pkt.payload[8], ws_pkt.len-8,time);
			/*
			struct rtc_time timeToSet;
			char subbuff[5];
			uint8_t *content;
			content = &ws_pkt.payload[8];
			memcpy( subbuff, &content[0], 4 );
			subbuff[4] = '\0';
			timeToSet.tm_year = atoi(subbuff);

			memcpy( subbuff, &content[5], 2 );
			subbuff[2] = '\0';
			timeToSet.tm_mon = atoi(subbuff);

			memcpy( subbuff, &content[8], 4 );
			subbuff[2] = '\0';
			timeToSet.tm_mday = atoi(subbuff);


			memcpy( subbuff, &content[11], 4 );
			subbuff[2] = '\0';
			timeToSet.tm_hour = atoi(subbuff);

			memcpy( subbuff, &content[14], 4 );
			subbuff[2] = '\0';
			timeToSet.tm_min = atoi(subbuff);
			memcpy( subbuff, &content[17], 4 );
			subbuff[2] = '\0';
			timeToSet.tm_sec = atoi(subbuff);
			//rtc_RV_set(&timeToSet);
			 */
			// rtc_RV_set_unix(time + (60*60));
		}else if(memcmp(ws_pkt.payload,"testData_",9) == 0){
			if(memcmp(&ws_pkt.payload[9],"1",1)){
				Test = 0;
			}else{
				Test = 1;
			}
			char subbuff[8];
			memcpy( subbuff, &ws_pkt.payload[11], 5 );
			subbuff[5] = '\0';


			TestValueWarm  = strtod(subbuff,NULL);
			memcpy( subbuff, &ws_pkt.payload[17], 5 );
			subbuff[5] = '\0';


			TestValueCold  = strtod(subbuff,NULL);
		}else if(memcmp(ws_pkt.payload,"btn_",4) == 0){
			//ESP_LOGI(TAG, "btn pushed:");

			if(memcmp(ws_pkt.payload,"btn_1",5) == 0){
				testBtnUp = 1;
				ESP_LOGI(TAG, "1");
			}
			if(memcmp(ws_pkt.payload,"btn_2",5)== 0){
				testBtnDown = 1;
				//ESP_LOGI(TAG, "2");
			}
			if(memcmp(ws_pkt.payload,"btn_3",5)==0){
				testBtnOnOff = 1;
				//ESP_LOGI(TAG, "3");
			}

		}
		else if(memcmp(ws_pkt.payload,"DMXdata",7)==0){
			uint8_t dmx_data[512];
			int temp_dmx_data = 0;
			for(int i = 0; i <512;i++){

				sscanf((char*)&ws_pkt.payload[9 + (i*3)], ",%x", &temp_dmx_data);
				dmx_data[i] = temp_dmx_data;
			}

			dmx_packet_t dPack;
			dPack.PacketSize = 512;
			dPack.StartCode = 0;
		
			memcpy(dPack.DMX,dmx_data,512);
			dmx_SendDMXPacket(DMX_NUM_1, &dPack);
		}


		//ESP_LOGI(TAG, "Got packet with message: %s %d", ws_pkt.payload, ws_pkt.len);
		
	}
	free(buf);
	return ret;
}<e>
Here is a snippets from the usb_service
<CODE><s>

Code: Select all

</s>void tud_network_init_cb(void) {
	/* if the network is re-initializing and we have a leftover packet, we must do a cleanup */
	ESP_LOGI(TAG, "tud_network_init_cb.");
	tud_rx_len = 0;
	return;
}


}<e>
Last edited by mowglihaha on Fri Mar 24, 2023 9:07 am, edited 1 time in total.

MicroController
Posts: 1702
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby MicroController » Wed Mar 01, 2023 10:48 am

vTaskDelay( 1 / portTICK_PERIOD_MS );

may be part of your problem. Note that by default the tick period is 10ms, so any delay of less than 10ms results in a 0 delay, which can starve lower priority tasks of CPU time which then may fail to reset their watchdogs in time.

Besides, polling on the tud_rx_len variable is probably not the best solution, even if tud_rx_len is volatile. A better and likely much less CPU intensive way would be to use a (binary) semaphore to notify "task(...)" about available data; task would not be consuming any CPU time while blocking on the semaphore, which would then likely solve the problem of one or more other tasks being starved.

mowglihaha
Posts: 10
Joined: Tue Feb 28, 2023 8:42 am

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby mowglihaha » Thu Mar 02, 2023 9:18 am

MicroController wrote:
Wed Mar 01, 2023 10:48 am
vTaskDelay( 1 / portTICK_PERIOD_MS );

may be part of your problem. Note that by default the tick period is 10ms, so any delay of less than 10ms results in a 0 delay, which can starve lower priority tasks of CPU time which then may fail to reset their watchdogs in time.

Besides, polling on the tud_rx_len variable is probably not the best solution, even if tud_rx_len is volatile. A better and likely much less CPU intensive way would be to use a (binary) semaphore to notify "task(...)" about available data; task would not be consuming any CPU time while blocking on the semaphore, which would then likely solve the problem of one or more other tasks being starved.
Where would you notify task from ? - tud_network_recv_cb ? I have the following here:

Code: Select all

bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
	if (tud_rx_len < 1) {
		for(size_t i=0; i<size;i++){
			tud_rx_buf[i] = src[i];
		}
		//memcpy(tud_rx_buf, src, size);
		tud_rx_len = size; //set tud_rx_len ONLY after finish copying
		return true;
	}else{
		//unable to receive, busy
		ESP_LOGW(TAG, "tud_network_recv_cb busy.");
		return false;
	}
}

MicroController
Posts: 1702
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby MicroController » Thu Mar 02, 2023 2:43 pm

Exactly.

Right after

Code: Select all

tud_rx_len = size; //set tud_rx_len ONLY after finish copying
you can "give" the semaphore, which makes "task" wake up and return from blocking on its semaphore "take" so that it can inspect tud_rx_len and handle the data.

mowglihaha
Posts: 10
Joined: Tue Feb 28, 2023 8:42 am

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby mowglihaha » Sat Mar 04, 2023 3:01 pm

MicroController wrote:
Thu Mar 02, 2023 2:43 pm
Exactly.

Right after

Code: Select all

tud_rx_len = size; //set tud_rx_len ONLY after finish copying
you can "give" the semaphore, which makes "task" wake up and return from blocking on its semaphore "take" so that it can inspect tud_rx_len and handle the data.
Perfect, ill try that. I appriciate your time !

mowglihaha
Posts: 10
Joined: Tue Feb 28, 2023 8:42 am

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby mowglihaha » Mon Mar 06, 2023 11:07 am

MicroController wrote:
Thu Mar 02, 2023 2:43 pm
Exactly.

Right after

Code: Select all

tud_rx_len = size; //set tud_rx_len ONLY after finish copying
you can "give" the semaphore, which makes "task" wake up and return from blocking on its semaphore "take" so that it can inspect tud_rx_len and handle the data.
Okay i have tried looking at this, but i cant seem to understand how i should use the binary semphaphore .

MicroController
Posts: 1702
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Task watchdog got triggered. The following tasks did not reset the watchdog in time

Postby MicroController » Mon Mar 06, 2023 4:10 pm

Try it like this:

Code: Select all

// Stores the handle to the semaphore
SemaphoreHandle_t tud_data_recd_sem;

Initialize the semaphore first, e.g. in app_main(): tud_data_recd_sem = xSemaphoreCreateBinary();

bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
	if (tud_rx_len < 1) {
		for(size_t i=0; i<size;i++){
			tud_rx_buf[i] = src[i];
		}
		//memcpy(tud_rx_buf, src, size);
		tud_rx_len = size; //set tud_rx_len ONLY after finish copying
		
		// "Give" the semaphore, signalling that data was received:
		xSemaphoreGive(tud_data_recd_sem);
		
		// Or, if this runs from an ISR context, use:
		// xSemaphoreGiveFromISR(tud_data_recd_sem, NULL);
		
		return true;
	}else{
		//unable to receive, busy
		ESP_LOGW(TAG, "tud_network_recv_cb busy.");
		return false;
	}
}

static void task(void *arg){
	esp_netif_t *netif = (esp_netif_t *) arg;
	size_t hs;

	while(1){
	        /* Try and "take" the semaphore. This task will "sleep" until either the
	           semaphore is "given" by another task/ISR or the timeout (e.g. 10000ms) elapses. */
		if ( xSemaphoreTake(tud_data_recd_sem, 10000 / portTICK_PERIOD_MS) == pdTRUE ) {
			// Data was received!
	                if (tud_rx_len > 0){
			    esp_netif_receive(netif, tud_rx_buf, tud_rx_len, NULL);
			    tud_network_recv_renew();
			    tud_rx_len = 0; //indicate buf is now read
			    hs = xPortGetFreeHeapSize();
			    //ESP_LOGI(TAG, "rx heap check (%u).", hs);
			}
		} else {
		    // Semaphore take timed out after 10000ms, i.e. no data received within 10000ms. Do we care?
		    ESP_LOGI(TAG, "no data received in the last 10s, will continue to wait.");
		}
	}
}
Alternatively, you can also look into FreeRTOS's stream buffers which are specifically made to pass variable length data from one task to the other.

Who is online

Users browsing this forum: ESP_Roland, martins, rudi ;-) and 77 guests