2021-09-29 10:45:38 -04:00
|
|
|
/*
|
2022-01-17 21:32:56 -05:00
|
|
|
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
2021-09-29 10:45:38 -04:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
2016-10-21 05:59:57 -04:00
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
#include "freertos/task.h"
|
2016-11-16 04:53:50 -05:00
|
|
|
#include "freertos/queue.h"
|
|
|
|
#include "freertos/semphr.h"
|
2022-04-14 06:08:08 -04:00
|
|
|
#include <sys/queue.h>
|
2016-10-21 05:59:57 -04:00
|
|
|
#include <esp_types.h>
|
|
|
|
#include "esp_err.h"
|
2022-04-14 06:08:08 -04:00
|
|
|
#include "esp_check.h"
|
2019-03-26 04:30:43 -04:00
|
|
|
#include "esp_intr_alloc.h"
|
2016-10-25 05:05:13 -04:00
|
|
|
#include "esp_attr.h"
|
2020-03-27 05:58:12 -04:00
|
|
|
#include "esp_debug_helpers.h"
|
2016-11-11 06:20:54 -05:00
|
|
|
#include "esp_freertos_hooks.h"
|
2019-05-13 06:02:45 -04:00
|
|
|
#include "soc/timer_periph.h"
|
2016-10-21 05:59:57 -04:00
|
|
|
#include "esp_log.h"
|
2021-10-25 05:13:46 -04:00
|
|
|
#include "esp_private/periph_ctrl.h"
|
2016-10-21 05:59:57 -04:00
|
|
|
#include "esp_task_wdt.h"
|
2019-03-21 00:21:01 -04:00
|
|
|
#include "esp_private/system_internal.h"
|
2020-03-27 05:58:12 -04:00
|
|
|
#include "esp_private/crosscore_int.h"
|
2019-12-26 03:30:03 -05:00
|
|
|
#include "hal/timer_types.h"
|
|
|
|
#include "hal/wdt_hal.h"
|
2019-07-24 11:18:19 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// --------------------------------------------------- Definitions -----------------------------------------------------
|
2016-10-21 05:59:57 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// ----------------------- Macros --------------------------
|
2016-10-21 05:59:57 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// HAL related variables and constants
|
2019-12-26 03:30:03 -05:00
|
|
|
#define TWDT_INSTANCE WDT_MWDT0
|
|
|
|
#define TWDT_TICKS_PER_US MWDT0_TICKS_PER_US
|
2022-04-14 06:08:08 -04:00
|
|
|
#define TWDT_PRESCALER MWDT0_TICK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
|
2019-12-26 03:30:03 -05:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// ---------------------- Typedefs -------------------------
|
|
|
|
|
|
|
|
// Structure used for each subscribed task
|
|
|
|
typedef struct twdt_entry twdt_entry_t;
|
|
|
|
struct twdt_entry {
|
|
|
|
SLIST_ENTRY(twdt_entry) slist_entry;
|
2016-10-25 06:18:11 -04:00
|
|
|
TaskHandle_t task_handle;
|
2017-10-09 06:07:30 -04:00
|
|
|
bool has_reset;
|
|
|
|
};
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// Structure used to hold run time configuration of the TWDT
|
|
|
|
typedef struct twdt_obj twdt_obj_t;
|
|
|
|
struct twdt_obj {
|
|
|
|
wdt_hal_context_t hal;
|
|
|
|
SLIST_HEAD(entry_list_head, twdt_entry) entries_slist;
|
|
|
|
bool panic; // Flag to trigger panic when TWDT times out
|
2017-10-09 06:07:30 -04:00
|
|
|
intr_handle_t intr_handle;
|
2016-10-21 05:59:57 -04:00
|
|
|
};
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// ----------------------- Objects -------------------------
|
2016-10-21 05:59:57 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
static const char *TAG = "task_wdt";
|
|
|
|
static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
static twdt_obj_t *p_twdt_obj = NULL;
|
2016-11-17 05:05:47 -05:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// ----------------------------------------------------- Private -------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Find an entry from its task handle, and checks if all other entries have been reset
|
|
|
|
*
|
|
|
|
* @param[in] handle Task handle
|
|
|
|
* @param[out] all_reset Whether all entries have been reset
|
|
|
|
* @return Entry, or NULL if not found
|
2017-10-09 06:07:30 -04:00
|
|
|
*/
|
2022-04-14 06:08:08 -04:00
|
|
|
static twdt_entry_t *find_entry_from_handle_and_check_all_reset(TaskHandle_t handle, bool *all_reset)
|
2017-10-09 06:07:30 -04:00
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
twdt_entry_t *target = NULL;
|
|
|
|
bool found_non_reset = false;
|
|
|
|
|
|
|
|
twdt_entry_t *entry;
|
|
|
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
|
|
|
if (entry->task_handle == handle) {
|
|
|
|
target = entry;
|
|
|
|
} else if (entry->has_reset == false) {
|
|
|
|
found_non_reset = true;
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
|
|
|
|
*all_reset = !found_non_reset;
|
2017-10-09 06:07:30 -04:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
/**
|
|
|
|
* @brief Reset hardware timer and entry flags
|
2017-10-09 06:07:30 -04:00
|
|
|
*/
|
2019-07-16 05:33:30 -04:00
|
|
|
static void reset_hw_timer(void)
|
2017-10-09 06:07:30 -04:00
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
// All tasks have reset; time to reset the hardware timer.
|
|
|
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_feed(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
|
|
|
//C lear the has_reset flag in each entry
|
|
|
|
twdt_entry_t *entry;
|
|
|
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
|
|
|
entry->has_reset = false;
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
/**
|
|
|
|
* @brief Idle hook callback
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @return Always returns true
|
|
|
|
*/
|
|
|
|
static bool idle_hook_cb(void)
|
|
|
|
{
|
|
|
|
esp_task_wdt_reset();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief User ISR callback placeholder
|
|
|
|
*
|
|
|
|
* 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.
|
2018-09-03 01:33:12 -04:00
|
|
|
*/
|
|
|
|
void __attribute__((weak)) esp_task_wdt_isr_user_handler(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
/**
|
|
|
|
* @brief TWDT timeout ISR function
|
|
|
|
*
|
|
|
|
* Tee ISR checks which entries have not been reset, prints some debugging information, and triggers a panic if
|
|
|
|
* configured to do so.
|
|
|
|
*
|
|
|
|
* @param arg ISR argument
|
2017-10-09 06:07:30 -04:00
|
|
|
*/
|
|
|
|
static void task_wdt_isr(void *arg)
|
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
portENTER_CRITICAL_ISR(&spinlock);
|
|
|
|
// Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
|
|
|
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_handle_intr(&p_twdt_obj->hal); // Feeds WDT and clears acknowledges interrupt
|
|
|
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
|
|
|
// If there are no entries, there's nothing to do.
|
|
|
|
if (SLIST_EMPTY(&p_twdt_obj->entries_slist)) {
|
|
|
|
portEXIT_CRITICAL_ISR(&spinlock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Find what entries triggered the TWDT timeout (i.e., which entries have not been reset)
|
|
|
|
/*
|
|
|
|
Note: We are currently in a critical section, thus under normal circumstances, logging should not be allowed.
|
|
|
|
However, TWDT timeouts count as fatal errors, thus reporting the fatal error is considered more important than
|
|
|
|
minimizing interrupt latency. Thus we allow logging in critical sections in this narrow case.
|
|
|
|
*/
|
2018-08-21 07:47:21 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, "Task watchdog got triggered. The following tasks did not reset the watchdog in time:");
|
2022-04-14 06:08:08 -04:00
|
|
|
twdt_entry_t *entry;
|
|
|
|
SLIST_FOREACH(entry, &p_twdt_obj->entries_slist, slist_entry) {
|
|
|
|
if (!entry->has_reset) {
|
|
|
|
BaseType_t task_affinity = xTaskGetAffinity(entry->task_handle);
|
|
|
|
const char *cpu;
|
|
|
|
if (task_affinity == 0) {
|
|
|
|
cpu = DRAM_STR("CPU 0");
|
|
|
|
} else if (task_affinity == 1) {
|
|
|
|
cpu = DRAM_STR("CPU 1");
|
|
|
|
} else {
|
|
|
|
cpu = DRAM_STR("CPU 0/1");
|
2021-01-25 22:20:09 -05:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetName(entry->task_handle), cpu);
|
2016-10-25 06:18:11 -04:00
|
|
|
}
|
|
|
|
}
|
2018-08-21 07:47:21 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:"));
|
2022-04-14 06:08:08 -04:00
|
|
|
for (int x = 0; x < portNUM_PROCESSORS; x++) {
|
2022-02-08 04:39:38 -05:00
|
|
|
ESP_EARLY_LOGE(TAG, "CPU %d: %s", x, pcTaskGetName(xTaskGetCurrentTaskHandleForCPU(x)));
|
2016-10-25 06:18:11 -04:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
portEXIT_CRITICAL_ISR(&spinlock);
|
2016-10-25 06:08:55 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// Run user ISR handler
|
2018-09-03 01:33:12 -04:00
|
|
|
esp_task_wdt_isr_user_handler();
|
2022-04-14 06:08:08 -04:00
|
|
|
// Trigger configured timeout behavior (e.g., panic or print backtrace)
|
|
|
|
if (p_twdt_obj->panic) {
|
2018-08-21 07:47:21 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, "Aborting.");
|
2018-07-29 05:57:59 -04:00
|
|
|
esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
|
2017-10-09 06:07:30 -04:00
|
|
|
abort();
|
2022-04-14 06:08:08 -04:00
|
|
|
} else { // Print
|
2022-01-17 21:32:56 -05:00
|
|
|
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2 // TODO: ESP32-C3 IDF-2986
|
2020-03-27 05:58:12 -04:00
|
|
|
int current_core = xPortGetCoreID();
|
2022-04-14 06:08:08 -04:00
|
|
|
// Print backtrace of current core
|
2020-03-27 05:58:12 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, "Print CPU %d (current core) backtrace", current_core);
|
|
|
|
esp_backtrace_print(100);
|
2020-12-29 00:20:24 -05:00
|
|
|
#if !CONFIG_FREERTOS_UNICORE
|
2022-04-14 06:08:08 -04:00
|
|
|
// Print backtrace of other core
|
2020-03-27 05:58:12 -04:00
|
|
|
ESP_EARLY_LOGE(TAG, "Print CPU %d backtrace", !current_core);
|
|
|
|
esp_crosscore_int_send_print_backtrace(!current_core);
|
2020-12-29 00:20:24 -05:00
|
|
|
#endif
|
|
|
|
#endif
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
2020-11-10 02:40:01 -05:00
|
|
|
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// ----------------------------------------------------- Public --------------------------------------------------------
|
|
|
|
|
2017-10-09 06:07:30 -04:00
|
|
|
esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic)
|
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
|
|
|
|
|
|
|
twdt_obj_t *obj = NULL;
|
|
|
|
if (p_twdt_obj == NULL) {
|
|
|
|
// Allocate and initialize TWDT driver object
|
|
|
|
obj = calloc(1, sizeof(twdt_obj_t));
|
|
|
|
ESP_GOTO_ON_FALSE((obj != NULL), ESP_ERR_NO_MEM, err, TAG, "insufficient memory");
|
|
|
|
SLIST_INIT(&obj->entries_slist);
|
|
|
|
obj->panic = panic;
|
|
|
|
ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &obj->intr_handle));
|
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Configure hardware timer
|
2017-11-30 23:11:37 -05:00
|
|
|
periph_module_enable(PERIPH_TIMG0_MODULE);
|
2022-04-14 06:08:08 -04:00
|
|
|
wdt_hal_init(&obj->hal, TWDT_INSTANCE, TWDT_PRESCALER, true);
|
|
|
|
// Assign the driver object
|
|
|
|
p_twdt_obj = obj;
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
|
|
|
// Configure 1st stage timeout and behavior
|
|
|
|
wdt_hal_config_stage(&p_twdt_obj->hal, WDT_STAGE0, timeout * (1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_INT);
|
|
|
|
// Configure 2nd stage timeout and behavior
|
|
|
|
wdt_hal_config_stage(&p_twdt_obj->hal, WDT_STAGE1, timeout * (2 * 1000000 / TWDT_TICKS_PER_US), WDT_STAGE_ACTION_RESET_SYSTEM);
|
|
|
|
// Enable the WDT
|
|
|
|
wdt_hal_enable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
ret = ESP_OK;
|
|
|
|
err:
|
|
|
|
return ret;
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
|
|
|
|
2019-07-16 05:33:30 -04:00
|
|
|
esp_err_t esp_task_wdt_deinit(void)
|
2017-10-09 06:07:30 -04:00
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
|
|
|
|
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Check TWDT state
|
|
|
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
|
|
|
ESP_GOTO_ON_FALSE(SLIST_EMPTY(&p_twdt_obj->entries_slist), ESP_ERR_INVALID_STATE, err, TAG, "all tasks must be deleted");
|
|
|
|
// Disable hardware timer and the interrupt
|
|
|
|
wdt_hal_write_protect_disable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_disable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_write_protect_enable(&p_twdt_obj->hal);
|
|
|
|
wdt_hal_deinit(&p_twdt_obj->hal);
|
|
|
|
esp_intr_disable(p_twdt_obj->intr_handle);
|
|
|
|
// Unassign driver object
|
|
|
|
twdt_obj_t *obj = p_twdt_obj;
|
|
|
|
p_twdt_obj = NULL;
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
|
|
|
|
// Free driver resources
|
|
|
|
ESP_ERROR_CHECK(esp_intr_free(obj->intr_handle)); //Deregister interrupt
|
|
|
|
free(obj); //Free p_twdt_obj
|
2017-10-09 06:07:30 -04:00
|
|
|
return ESP_OK;
|
2022-04-14 06:08:08 -04:00
|
|
|
|
|
|
|
err:
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
return ret;
|
2016-10-21 05:59:57 -04:00
|
|
|
}
|
|
|
|
|
2017-10-09 06:07:30 -04:00
|
|
|
esp_err_t esp_task_wdt_add(TaskHandle_t handle)
|
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
|
|
|
if (handle == NULL) { //Get handle of current task if none is provided
|
2017-10-09 06:07:30 -04:00
|
|
|
handle = xTaskGetCurrentTaskHandle();
|
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
|
|
|
|
// Allocate entry for task
|
|
|
|
twdt_entry_t *entry = calloc(1, sizeof(twdt_entry_t));
|
|
|
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NO_MEM, alloc_err, TAG, "insufficient memory");
|
|
|
|
entry->task_handle = handle;
|
|
|
|
entry->has_reset = false;
|
|
|
|
|
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Check TWDT state
|
|
|
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, state_err, TAG, "task watchdog was never initialized");
|
|
|
|
// Check if the task is an entry, and if all entries have been reset
|
|
|
|
bool all_reset;
|
|
|
|
twdt_entry_t *found_entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
|
|
|
ESP_GOTO_ON_FALSE((found_entry == NULL), ESP_ERR_INVALID_ARG, state_err, TAG, "task is already subscribed");
|
|
|
|
// Add task to entry list
|
|
|
|
SLIST_INSERT_HEAD(&p_twdt_obj->entries_slist, entry, slist_entry);
|
|
|
|
if (all_reset) { //Reset hardware timer if all other tasks in list have reset in
|
|
|
|
reset_hw_timer();
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
portEXIT_CRITICAL(&spinlock); //Nested critical if Legacy
|
2017-10-09 06:07:30 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// If the task was the 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 02:49:39 -04:00
|
|
|
ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_hook_cb, i));
|
2017-10-09 06:07:30 -04:00
|
|
|
break;
|
2017-09-30 06:07:19 -04:00
|
|
|
}
|
|
|
|
}
|
2017-10-09 06:07:30 -04:00
|
|
|
return ESP_OK;
|
2022-04-14 06:08:08 -04:00
|
|
|
|
|
|
|
state_err:
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
free(entry);
|
|
|
|
alloc_err:
|
|
|
|
return ret;
|
2016-10-21 05:59:57 -04:00
|
|
|
}
|
|
|
|
|
2019-07-16 05:33:30 -04:00
|
|
|
esp_err_t esp_task_wdt_reset(void)
|
2017-10-09 06:07:30 -04:00
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
2017-10-09 06:07:30 -04:00
|
|
|
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Check TWDT state
|
|
|
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
|
|
|
// Find entry for task
|
|
|
|
bool all_reset;
|
|
|
|
twdt_entry_t *entry;
|
|
|
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
|
|
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NOT_FOUND, err, TAG, "task not found");
|
|
|
|
// Mark entry as reset and issue timer reset if all entries have been reset
|
|
|
|
entry->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
|
2017-10-09 06:07:30 -04:00
|
|
|
reset_hw_timer();
|
2016-10-25 06:18:11 -04:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
ret = ESP_OK;
|
|
|
|
err:
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
2017-10-09 06:07:30 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
return ret;
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t esp_task_wdt_delete(TaskHandle_t handle)
|
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
|
|
|
if (handle == NULL) {
|
2017-10-09 06:07:30 -04:00
|
|
|
handle = xTaskGetCurrentTaskHandle();
|
|
|
|
}
|
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Check TWDT state
|
|
|
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
|
|
|
// Find entry for task
|
2017-10-09 06:07:30 -04:00
|
|
|
bool all_reset;
|
2022-04-14 06:08:08 -04:00
|
|
|
twdt_entry_t *entry;
|
|
|
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
|
|
|
ESP_GOTO_ON_FALSE((entry != NULL), ESP_ERR_NOT_FOUND, err, TAG, "task not found");
|
|
|
|
// Remove entry
|
|
|
|
SLIST_REMOVE(&p_twdt_obj->entries_slist, entry, twdt_entry, slist_entry);
|
|
|
|
// Reset hardware timer if all remaining tasks have reset
|
|
|
|
if (all_reset) {
|
|
|
|
reset_hw_timer();
|
2017-10-09 06:07:30 -04:00
|
|
|
}
|
2022-04-14 06:08:08 -04:00
|
|
|
portEXIT_CRITICAL(&spinlock);
|
2017-10-09 06:07:30 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
// Free the entry
|
|
|
|
free(entry);
|
|
|
|
// If idle task, deregister idle hook callback form appropriate core
|
|
|
|
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
|
|
|
if (handle == xTaskGetIdleTaskHandleForCPU(i)) {
|
2017-10-09 06:07:30 -04:00
|
|
|
esp_deregister_freertos_idle_hook_for_cpu(idle_hook_cb, i);
|
|
|
|
break;
|
2017-08-30 09:11:10 -04:00
|
|
|
}
|
|
|
|
}
|
2017-10-09 06:07:30 -04:00
|
|
|
return ESP_OK;
|
2022-04-14 06:08:08 -04:00
|
|
|
|
|
|
|
err:
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
return ret;
|
2016-10-21 05:59:57 -04:00
|
|
|
}
|
|
|
|
|
2017-10-09 06:07:30 -04:00
|
|
|
esp_err_t esp_task_wdt_status(TaskHandle_t handle)
|
|
|
|
{
|
2022-04-14 06:08:08 -04:00
|
|
|
esp_err_t ret;
|
|
|
|
if (handle == NULL) {
|
2017-10-09 06:07:30 -04:00
|
|
|
handle = xTaskGetCurrentTaskHandle();
|
|
|
|
}
|
2017-08-30 09:11:10 -04:00
|
|
|
|
2022-04-14 06:08:08 -04:00
|
|
|
portENTER_CRITICAL(&spinlock);
|
|
|
|
// Check TWDT state
|
|
|
|
ESP_GOTO_ON_FALSE((p_twdt_obj != NULL), ESP_ERR_INVALID_STATE, err, TAG, "task watchdog was never initialized");
|
|
|
|
// Find entry for task
|
|
|
|
bool all_reset;
|
|
|
|
twdt_entry_t *entry;
|
|
|
|
entry = find_entry_from_handle_and_check_all_reset(handle, &all_reset);
|
|
|
|
(void) all_reset; // Unused
|
|
|
|
ret = (entry != NULL) ? ESP_OK : ESP_ERR_NOT_FOUND;
|
|
|
|
err:
|
|
|
|
portEXIT_CRITICAL(&spinlock);
|
|
|
|
|
|
|
|
return ret;
|
2017-09-30 06:07:19 -04:00
|
|
|
}
|