| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | //     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdint.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							|  |  |  | #include "sdkconfig.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | #include "freertos/FreeRTOSConfig.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "freertos/task.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-16 17:53:50 +08:00
										 |  |  | #include "freertos/queue.h"
 | 
					
						
							|  |  |  | #include "freertos/semphr.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | #include <esp_types.h>
 | 
					
						
							|  |  |  | #include "esp_err.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-26 16:30:43 +08:00
										 |  |  | #include "esp_intr_alloc.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-25 17:05:13 +08:00
										 |  |  | #include "esp_attr.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-11 19:20:54 +08:00
										 |  |  | #include "esp_freertos_hooks.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-13 18:02:45 +08:00
										 |  |  | #include "soc/timer_periph.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | #include "esp_log.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-23 02:15:27 +08:00
										 |  |  | #include "driver/timer.h"
 | 
					
						
							| 
									
										
										
										
											2017-12-01 12:11:37 +08:00
										 |  |  | #include "driver/periph_ctrl.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | #include "esp_task_wdt.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-21 12:21:01 +08:00
										 |  |  | #include "esp_private/system_internal.h"
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  | #include "hal/timer_ll.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  | static const char *TAG = "task_wdt"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | //Assertion macro where, if 'cond' is false, will exit the critical section and return 'ret'
 | 
					
						
							|  |  |  | #define ASSERT_EXIT_CRIT_RETURN(cond, ret)  ({                              \
 | 
					
						
							|  |  |  |             if(!(cond)){                                                    \ | 
					
						
							|  |  |  |                 portEXIT_CRITICAL(&twdt_spinlock);                          \ | 
					
						
							|  |  |  |                 return ret;                                                 \ | 
					
						
							|  |  |  |             }                                                               \ | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2017-09-30 18:07:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | //Empty define used in ASSERT_EXIT_CRIT_RETURN macro when returning in void
 | 
					
						
							|  |  |  | #define VOID_RETURN
 | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | //Structure used for each subscribed task
 | 
					
						
							|  |  |  | typedef struct twdt_task_t twdt_task_t; | 
					
						
							|  |  |  | struct twdt_task_t { | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     TaskHandle_t task_handle; | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     bool has_reset; | 
					
						
							|  |  |  |     twdt_task_t *next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //Structure used to hold run time configuration of the TWDT
 | 
					
						
							|  |  |  | typedef struct twdt_config_t twdt_config_t; | 
					
						
							|  |  |  | struct twdt_config_t { | 
					
						
							|  |  |  |     twdt_task_t *list;      //Linked list of subscribed tasks
 | 
					
						
							|  |  |  |     uint32_t timeout;       //Timeout period of TWDT
 | 
					
						
							|  |  |  |     bool panic;             //Flag to trigger panic when TWDT times out
 | 
					
						
							|  |  |  |     intr_handle_t intr_handle; | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | static twdt_config_t *twdt_config = NULL; | 
					
						
							|  |  |  | static portMUX_TYPE twdt_spinlock = portMUX_INITIALIZER_UNLOCKED; | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Idle hook callback for Idle Tasks to reset the TWDT. This callback will only | 
					
						
							|  |  |  |  * be registered to the Idle Hook of a particular core when the corresponding | 
					
						
							|  |  |  |  * Idle Task subscribes to the TWDT. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static bool idle_hook_cb(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_task_wdt_reset(); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-17 18:05:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Internal function that looks for the target task in the TWDT task list. | 
					
						
							|  |  |  |  * Returns the list item if found and returns null if not found. Also checks if | 
					
						
							|  |  |  |  * all the other tasks have reset. Should be called within critical. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     twdt_task_t *target = NULL; | 
					
						
							|  |  |  |     *all_reset = true; | 
					
						
							|  |  |  |     for(twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ | 
					
						
							|  |  |  |         if(task->task_handle == handle){ | 
					
						
							|  |  |  |             target = task;   //Get pointer to target task list member
 | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             if(task->has_reset == false){     //If a task has yet to reset
 | 
					
						
							|  |  |  |                 *all_reset = false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return target; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Resets the hardware timer and has_reset flags of each task on the list. | 
					
						
							|  |  |  |  * Called within critical | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | static void reset_hw_timer(void) | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     //All tasks have reset; time to reset the hardware timer.
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  |     timer_ll_wdt_set_protect(&TIMERG0, false); | 
					
						
							|  |  |  |     timer_ll_wdt_feed(&TIMERG0); | 
					
						
							|  |  |  |     timer_ll_wdt_set_protect(&TIMERG0, true); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     //Clear all has_reset flags in list
 | 
					
						
							|  |  |  |     for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ | 
					
						
							|  |  |  |         task->has_reset=false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-03 13:33:12 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This function is called by task_wdt_isr function (ISR for when TWDT times out). | 
					
						
							|  |  |  |  * It can be redefined in user code to handle twdt events. | 
					
						
							|  |  |  |  * Note: It has the same limitations as the interrupt function. | 
					
						
							|  |  |  |  *       Do not use ESP_LOGI functions inside. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void __attribute__((weak)) esp_task_wdt_isr_user_handler(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ISR for when TWDT times out. Checks for which tasks have not reset. Also | 
					
						
							|  |  |  |  * triggers panic if configured to do so | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void task_wdt_isr(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-08-29 11:39:04 +05:30
										 |  |  |     portENTER_CRITICAL_ISR(&twdt_spinlock); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     twdt_task_t *twdttask; | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     const char *cpu; | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     //Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  |     timer_ll_wdt_set_protect(&TIMERG0, false); | 
					
						
							|  |  |  |     timer_ll_wdt_feed(&TIMERG0); | 
					
						
							|  |  |  |     timer_ll_wdt_set_protect(&TIMERG0, true); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     //Acknowledge interrupt
 | 
					
						
							| 
									
										
										
										
											2019-07-15 14:21:36 +08:00
										 |  |  |     timer_ll_wdt_clear_intr_status(&TIMERG0); | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |     //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty
 | 
					
						
							| 
									
										
										
										
											2016-11-16 17:53:50 +08:00
										 |  |  |     //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
 | 
					
						
							|  |  |  |     //something bad already happened and reporting this is considered more important
 | 
					
						
							|  |  |  |     //than the badness caused by a spinlock here.
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     //Return immediately if no tasks have been added to task list
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config->list != NULL), VOID_RETURN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //Watchdog got triggered because at least one task did not reset in time.
 | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |     ESP_EARLY_LOGE(TAG, "Task watchdog got triggered. The following tasks did not reset the watchdog in time:"); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     for (twdttask=twdt_config->list; twdttask!=NULL; twdttask=twdttask->next) { | 
					
						
							|  |  |  |         if (!twdttask->has_reset) { | 
					
						
							|  |  |  |             cpu=xTaskGetAffinity(twdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1"); | 
					
						
							|  |  |  |             if (xTaskGetAffinity(twdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1"); | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |             ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetTaskName(twdttask->task_handle), cpu); | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |     ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:")); | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     for (int x=0; x<portNUM_PROCESSORS; x++) { | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |         ESP_EARLY_LOGE(TAG, "CPU %d: %s", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x))); | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-10-25 18:08:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-03 13:33:12 +08:00
										 |  |  |     esp_task_wdt_isr_user_handler(); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     if (twdt_config->panic){     //Trigger Panic if configured to do so
 | 
					
						
							| 
									
										
										
										
											2018-08-21 19:47:21 +08:00
										 |  |  |         ESP_EARLY_LOGE(TAG, "Aborting."); | 
					
						
							| 
									
										
										
										
											2018-08-29 11:39:04 +05:30
										 |  |  |         portEXIT_CRITICAL_ISR(&twdt_spinlock); | 
					
						
							| 
									
										
										
										
											2018-07-29 12:57:59 +03:00
										 |  |  |         esp_reset_reason_set_hint(ESP_RST_TASK_WDT); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |         abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 11:39:04 +05:30
										 |  |  |     portEXIT_CRITICAL_ISR(&twdt_spinlock); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Initializes the TWDT by allocating memory for the config data | 
					
						
							|  |  |  |  * structure, obtaining the idle task handles/registering idle hooks, and | 
					
						
							|  |  |  |  * setting the hardware timer registers. If reconfiguring, it will just modify | 
					
						
							|  |  |  |  * wdt_config and reset the hardware timer. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     if(twdt_config == NULL){        //TWDT not initialized yet
 | 
					
						
							|  |  |  |         //Allocate memory for wdt_config
 | 
					
						
							|  |  |  |         twdt_config = calloc(1, sizeof(twdt_config_t)); | 
					
						
							|  |  |  |         ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NO_MEM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         twdt_config->list = NULL; | 
					
						
							|  |  |  |         twdt_config->timeout = timeout; | 
					
						
							|  |  |  |         twdt_config->panic = panic; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //Register Interrupt and ISR
 | 
					
						
							| 
									
										
										
										
											2018-09-24 08:49:39 +02:00
										 |  |  |         ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &twdt_config->intr_handle)); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         //Configure hardware timer
 | 
					
						
							| 
									
										
										
										
											2017-12-01 12:11:37 +08:00
										 |  |  |         periph_module_enable(PERIPH_TIMG0_MODULE); | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  |         timer_ll_wdt_set_protect(&TIMERG0, false);               //Disable write protection
 | 
					
						
							|  |  |  |         timer_ll_wdt_init(&TIMERG0); | 
					
						
							|  |  |  |         timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
 | 
					
						
							|  |  |  |         //1st stage timeout: interrupt
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT); | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); | 
					
						
							|  |  |  |         //2nd stage timeout: reset system
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM); | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); | 
					
						
							|  |  |  |         timer_ll_wdt_set_enable(&TIMERG0, true); | 
					
						
							|  |  |  |         timer_ll_wdt_feed(&TIMERG0); | 
					
						
							|  |  |  |         timer_ll_wdt_set_protect(&TIMERG0, true);                         //Enable write protection
 | 
					
						
							|  |  |  |     } else {      //twdt_config previously initialized
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |         //Reconfigure task wdt
 | 
					
						
							|  |  |  |         twdt_config->panic = panic; | 
					
						
							|  |  |  |         twdt_config->timeout = timeout; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //Reconfigure hardware timer
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  |         timer_ll_wdt_set_protect(&TIMERG0, false);   //Disable write protection
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_enable(&TIMERG0, false);                   //Disable timer
 | 
					
						
							|  |  |  |         //Set timeout before interrupt
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); | 
					
						
							|  |  |  |         //Set timeout before reset
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); | 
					
						
							|  |  |  |         timer_ll_wdt_set_enable(&TIMERG0, true);                   //Renable timer
 | 
					
						
							|  |  |  |         timer_ll_wdt_feed(&TIMERG0);                         //Reset timer
 | 
					
						
							|  |  |  |         timer_ll_wdt_set_protect(&TIMERG0, true);                     //Enable write protection
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | esp_err_t esp_task_wdt_deinit(void) | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     //TWDT must already be initialized
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND); | 
					
						
							|  |  |  |     //Task list must be empty
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //Disable hardware timer
 | 
					
						
							| 
									
										
										
										
											2019-07-24 23:18:19 +08:00
										 |  |  |     timer_ll_wdt_set_protect(&TIMERG0, false);   //Disable write protection
 | 
					
						
							|  |  |  |     timer_ll_wdt_set_enable(&TIMERG0, false);                   //Disable timer
 | 
					
						
							|  |  |  |     timer_ll_wdt_set_protect(&TIMERG0, true);                     //Enable write protection
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-24 08:49:39 +02:00
										 |  |  |     ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle));  //Unregister interrupt
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     free(twdt_config);                      //Free twdt_config
 | 
					
						
							|  |  |  |     twdt_config = NULL; | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | esp_err_t esp_task_wdt_add(TaskHandle_t handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     //TWDT must already be initialized
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     twdt_task_t *target_task; | 
					
						
							|  |  |  |     bool all_reset; | 
					
						
							|  |  |  |     if (handle == NULL){    //Get handle of current task if none is provided
 | 
					
						
							|  |  |  |         handle = xTaskGetCurrentTaskHandle(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     //Check if tasks exists in task list, and if all other tasks have reset
 | 
					
						
							|  |  |  |     target_task = find_task_in_twdt_list(handle, &all_reset); | 
					
						
							|  |  |  |     //task cannot be already subscribed
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((target_task == NULL), ESP_ERR_INVALID_ARG); | 
					
						
							| 
									
										
										
										
											2017-08-30 21:11:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     //Add target task to TWDT task list
 | 
					
						
							|  |  |  |     target_task = calloc(1,sizeof(twdt_task_t)); | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NO_MEM); | 
					
						
							|  |  |  |     target_task->task_handle = handle; | 
					
						
							|  |  |  |     target_task->has_reset = true; | 
					
						
							|  |  |  |     target_task->next = NULL; | 
					
						
							|  |  |  |     if (twdt_config->list == NULL) {    //Adding to empty list
 | 
					
						
							|  |  |  |         twdt_config->list = target_task; | 
					
						
							|  |  |  |     } else {    //Adding to tail of list
 | 
					
						
							|  |  |  |         twdt_task_t *task; | 
					
						
							|  |  |  |         for (task = twdt_config->list; task->next != NULL; task = task->next){ | 
					
						
							|  |  |  |             ;   //point task to current tail of TWDT task list
 | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |         task->next = target_task; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //If idle task, register the idle hook callback to appropriate core
 | 
					
						
							|  |  |  |     for(int i = 0; i < portNUM_PROCESSORS; i++){ | 
					
						
							|  |  |  |         if(handle == xTaskGetIdleTaskHandleForCPU(i)){ | 
					
						
							| 
									
										
										
										
											2018-09-24 08:49:39 +02:00
										 |  |  |             ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_hook_cb, i)); | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2017-09-30 18:07:19 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(all_reset){     //Reset hardware timer if all other tasks in list have reset in
 | 
					
						
							|  |  |  |         reset_hw_timer(); | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock);       //Nested critical if Legacy
 | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | esp_err_t esp_task_wdt_reset(void) | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     //TWDT must already be initialized
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); | 
					
						
							| 
									
										
										
										
											2016-11-16 17:53:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     TaskHandle_t handle = xTaskGetCurrentTaskHandle(); | 
					
						
							|  |  |  |     twdt_task_t *target_task; | 
					
						
							|  |  |  |     bool all_reset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //Check if task exists in task list, and if all other tasks have reset
 | 
					
						
							|  |  |  |     target_task = find_task_in_twdt_list(handle, &all_reset); | 
					
						
							|  |  |  |     //Return error if trying to reset task that is not on the task list
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NOT_FOUND); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     target_task->has_reset = true;    //Reset the task if it's on the task list
 | 
					
						
							|  |  |  |     if(all_reset){     //Reset if all other tasks in list have reset in
 | 
					
						
							|  |  |  |         reset_hw_timer(); | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t esp_task_wdt_delete(TaskHandle_t handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if(handle == NULL){ | 
					
						
							|  |  |  |         handle = xTaskGetCurrentTaskHandle(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     //Return error if twdt has not been initialized
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     twdt_task_t *target_task; | 
					
						
							|  |  |  |     bool all_reset; | 
					
						
							|  |  |  |     target_task = find_task_in_twdt_list(handle, &all_reset); | 
					
						
							|  |  |  |     //Task doesn't exist on list. Return error
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_INVALID_ARG); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(target_task == twdt_config->list){     //target_task is head of list. Delete
 | 
					
						
							|  |  |  |         twdt_config->list = target_task->next; | 
					
						
							|  |  |  |         free(target_task); | 
					
						
							|  |  |  |     }else{                                      //target_task not head of list. Delete
 | 
					
						
							|  |  |  |         twdt_task_t *prev; | 
					
						
							|  |  |  |         for (prev = twdt_config->list; prev->next != target_task; prev = prev->next){ | 
					
						
							|  |  |  |             ;   //point prev to task preceding target_task
 | 
					
						
							| 
									
										
										
										
											2016-10-25 18:18:11 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |         prev->next = target_task->next; | 
					
						
							|  |  |  |         free(target_task); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //If idle task, deregister idle hook callback form appropriate core
 | 
					
						
							|  |  |  |     for(int i = 0; i < portNUM_PROCESSORS; i++){ | 
					
						
							|  |  |  |         if(handle == xTaskGetIdleTaskHandleForCPU(i)){ | 
					
						
							|  |  |  |             esp_deregister_freertos_idle_hook_for_cpu(idle_hook_cb, i); | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2017-08-30 21:11:10 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(all_reset){     //Reset hardware timer if all remaining tasks have reset
 | 
					
						
							|  |  |  |         reset_hw_timer(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							| 
									
										
										
										
											2016-10-21 17:59:57 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  | esp_err_t esp_task_wdt_status(TaskHandle_t handle) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if(handle == NULL){ | 
					
						
							|  |  |  |         handle = xTaskGetCurrentTaskHandle(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-30 21:11:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 18:07:30 +08:00
										 |  |  |     portENTER_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     //Return if TWDT is not initialized
 | 
					
						
							|  |  |  |     ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     twdt_task_t *task; | 
					
						
							|  |  |  |     for(task = twdt_config->list; task!=NULL; task=task->next){ | 
					
						
							|  |  |  |         //Return ESP_OK if task is found
 | 
					
						
							|  |  |  |         ASSERT_EXIT_CRIT_RETURN((task->task_handle != handle), ESP_OK); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //Task could not be found
 | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&twdt_spinlock); | 
					
						
							|  |  |  |     return ESP_ERR_NOT_FOUND; | 
					
						
							| 
									
										
										
										
											2017-09-30 18:07:19 +08:00
										 |  |  | } |