]> granicus.if.org Git - esp-idf/commitdiff
Merge branch 'feature/ipv6_socket_options' into 'master'
authorAngus Gratton <angus@espressif.com>
Mon, 9 Oct 2017 01:03:30 +0000 (09:03 +0800)
committerAngus Gratton <angus@espressif.com>
Mon, 9 Oct 2017 01:03:30 +0000 (09:03 +0800)
IPV6 multicast socket options

See merge request !964

14 files changed:
components/app_trace/gcov/gcov_rtio.c
components/esp32/Kconfig
components/esp32/cpu_start.c
components/esp32/include/esp_task_wdt.h
components/esp32/task_wdt.c
components/freertos/include/freertos/task.h
components/freertos/tasks.c
components/pthread/pthread.c
components/pthread/test/test_pthread_cxx.cpp
docs/api-reference/system/wdts.rst
examples/system/task_watchdog/Makefile [deleted file]
examples/system/task_watchdog/README.md [deleted file]
examples/system/task_watchdog/main/component.mk [deleted file]
examples/system/task_watchdog/main/task_watchdog_example_main.c [deleted file]

index 7556c9f7fac9fb205bfdbe0bf8116936b6031b4a..5e0b7e913e8220cd3212cd532c2c0d555f5d309d 100644 (file)
@@ -14,9 +14,9 @@
 
 // This module implements runtime file I/O API for GCOV.
 
+#include "esp_task_wdt.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-#include "esp_task_wdt.h"
 #include "soc/cpu.h"
 #include "soc/timer_group_struct.h"
 #include "soc/timer_group_reg.h"
index 0870a731bca062923e877b26e41766727adaebc3..8f0c588bcc32acc80fc48ed416f2b9a04bf7022b 100644 (file)
@@ -527,11 +527,10 @@ config INT_WDT_CHECK_CPU1
         Also detect if interrupts on CPU 1 are disabled for too long.
 
 config TASK_WDT
-    bool "Initialize Task Watchdog on startup"
+    bool "Task watchdog"
     default y
     help
         This watchdog timer can be used to make sure individual tasks are still running.
-        The Task Watchdog timer can be initialized at run time as well
 
 config TASK_WDT_PANIC
     bool "Invoke panic handler when Task Watchdog is triggered"
@@ -540,46 +539,33 @@ config TASK_WDT_PANIC
     help
         Normally, the Task Watchdog will only print out a warning if it detects it has not
         been fed. If this is enabled, it will invoke the panic handler instead, which
-        can then halt or reboot the chip. This can also be configured at run time
-        by reinitializing the task watchdog.
+        can then halt or reboot the chip.
 
 config TASK_WDT_TIMEOUT_S
-    int "Task watchdog timeout (ms)"
+    int "Task watchdog timeout (seconds)"
     depends on TASK_WDT
-    range 1 60000
-    default 5000
+    range 1 60
+    default 5
     help
-        Timeout for the task WDT, in ms.
+        Timeout for the task WDT, in seconds.
 
-config TASK_WDT_CHECK_IDLE_TASK_CPU0
-    bool "Add CPU0 idle task to task watchdog on startup"
+config TASK_WDT_CHECK_IDLE_TASK
+    bool "Task watchdog watches CPU0 idle task"
     depends on TASK_WDT
     default y
     help
-        With this turned on, the CPU0 idle task will be added to the task watchdog
-        on startup. Adding the idle task to the task watchdog allows for the detection
-        of CPU starvation. The idle task not being called is usually a symptom of another
+        With this turned on, the task WDT can detect if the idle task is not called within the task
+        watchdog timeout period. The idle task not being called usually is a symptom of another
         task hoarding the CPU. It is also a bad thing because FreeRTOS household tasks depend on the
-        idle task getting some runtime every now and then.
+        idle task getting some runtime every now and then. Take Care: With this disabled, this
+        watchdog will trigger if no tasks register themselves within the timeout value.
 
 config TASK_WDT_CHECK_IDLE_TASK_CPU1
-    bool "Add CPU0 idle task to task watchdog on startup"
-    depends on TASK_WDT && !FREERTOS_UNICORE
+    bool "Task watchdog also watches CPU1 idle task"
+    depends on TASK_WDT_CHECK_IDLE_TASK && !FREERTOS_UNICORE
     default y
     help
-        With this turned on, the CPU1 idle task will also be added to the task watchdog
-        on startup.
-
-config TASK_WDT_LEGACY_BEHAVIOR
-    bool "Use legacy behavior for task watchdog"
-    depends on TASK_WDT
-    default n
-    help
-        Task wdt legacy behavior will add a task to the wdt list on its first
-        call to esp_task_wdt_feed(). Furthermore, tasks can only remove 
-        themselves from the wdt task list when calling esp_task_wdt_delete().
-        Therefore esp_task_wdt_delete() should be called with no parameters
-        when legacy behavior is enabled.
+        Also check the idle task that runs on CPU1.
 
 #The brownout detector code is disabled (by making it depend on a nonexisting symbol) because the current revision of ESP32
 #silicon has a bug in the brown-out detector, rendering it unusable for resetting the CPU.
index 9834938390a305085864a1b257552b99949007b9..f9c921b871b5eb7d9acc8e392dac58c2085548bc 100644 (file)
@@ -323,6 +323,9 @@ void start_cpu0_default(void)
     do_global_ctors();
 #if CONFIG_INT_WDT
     esp_int_wdt_init();
+#endif
+#if CONFIG_TASK_WDT
+    esp_task_wdt_init();
 #endif
     esp_cache_err_int_init();
     esp_crosscore_int_init();
@@ -397,30 +400,6 @@ static void main_task(void* args)
 #endif
     //Enable allocation in region where the startup stacks were located.
     heap_caps_enable_nonos_stack_heaps();
-
-    //Initialize task wdt
-#ifdef CONFIG_TASK_WDT
-#ifdef CONFIG_TASK_WDT_PANIC
-    esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, true);
-#else
-    esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false);
-#endif
-#endif
-    //Add IDLE 0 to task wdt
-#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
-    if(idle_0 != NULL){
-        esp_task_wdt_add(idle_0);
-    }
-#endif
-    //Add IDLE 1 to task wdt
-#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
-    if(idle_1 != NULL){
-        esp_task_wdt_add(idle_1);
-    }
-#endif
-
     app_main();
     vTaskDelete(NULL);
 }
index e2200faefb3849fbd5dd258fc40eaa14415fcea6..eb773770096c5b58083c6de188454c0c4249b9b0 100644 (file)
 #ifndef __ESP_TASK_WDT_H
 #define __ESP_TASK_WDT_H
 
-#include "freertos/task.h"
-#include "esp_err.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/*
-This routine enables a more general-purpose task watchdog which uses the TIMERG0
-WDT: All tasks subscribed to the task wdt must feed the wdt at least once
-before the wdt times out or else the wdt will bark. The Idle tasks can also be
-subscribed to the wdt. This allows for the detection of CPU starvation.
-
-To enable/disable legacy behavior, toggle the CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-option in menuconfig. Under legacy behavior, a task will subscribe to the
-wdt on its first call of esp_task_wdt_feed(). esp_task_wdt_add() SHOULD NOT BE
-CALLED in an application if legacy behavior is enabled. esp_task_wdt_delete()
-will only allow tasks to unsubscribe themselves from the task wdt under legacy
-behavior. Enabling legacy behavior will also force the task wdt to be enabled on
-startup.
-*/
 
-/**
-  * @brief  Initialize the task watchdog timer
-  *
-  * This function will initialize the task watchdog timer. If the wdt
-  * has already been initialized, calling this function again will change the
-  * timeout and panic configuration, then reset the timer count. Once the watchdog
-  * timer has been initialized, tasks can subscribe to the watchdog timer.
-  *
-  * @param[in]  timeout     Timeout(ms) period of watchdog timer
-  * @param[in]  panic       Flag that if set, will cause the wdt to trigger the
-  *                         panic handler when it times out
-  * @return
-  *     - ESP_OK:           Initialization was successful
-  *     - ESP_ERR_NO_MEM:   Initialization was unsuccessful due to lack of
-  *                         memory
-  *
-  * @note   esp_task_wdt_init() must only be called after the scheduler
-  *         started
+/** \defgroup Watchdog_APIs Watchdog APIs
+  * @brief Watchdog APIs
   */
-esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic);
 
+/** @addtogroup Watchdog_APIs
+  * @{
+  */
 
-/**
- * @brief   Deinitialize the task watchdog timer
- *
- * This function will deinitialize the task watchdog timer. This function should
- * be called when all tasks have unsubscribed form the watchdog timer.
- *
- * @return
- *      - ESP_OK:                 Watchdog timer successfully deinitialized
- *      - ESP_ERR_INVALID_STATE:  Error due to wdt not being initialized, or
- *                                if tasks are still subscribed to the wdt
- */
-esp_err_t esp_task_wdt_deinit();
+/*
+This routine enables a more general-purpose task watchdog: tasks can individually
+feed the watchdog and the watchdog will bark if one or more tasks haven't fed the
+watchdog within the specified time. Optionally, the idle tasks can also configured
+to feed the watchdog in a similar fashion, to detect CPU starvation.
+
+This uses the TIMERG0 WDT.
+*/
 
 
 /**
-  * @brief  Subscribes a tasks to the task watchdog timer
-  *
-  * This function subscribes a task to the task watchdog timer. Note that once
-  * subscribed, a task must periodically feed the watchdog timer. If the task
-  * is an IDLE task, this function will enable feeding from the idle hook
-  * automatically.
-  *
-  * @param[in]  handle            Handle of the task to be added. Input NULL
-  *                               to add the current running task
+  * @brief  Initialize the task watchdog. This is called in the init code, if the
+  *         task watchdog is enabled in menuconfig.
   *
-  * @return
-  *     - ESP_OK:                 Successfully subscribed the task to the wdt
-  *     - ESP_ERR_INVALID_ARG:    Failed as task is already subscribed
-  *     - ESP_ERR_INVALID_STATE:  Failed as wdt has not been initialized
-  *     - ESP_ERR_NO_MEM:         Failed due to lack of memory
-  *
-  * @note   This function should not be called from application code if
-  *         CONFIG_TASK_WDT_LEGACY_BEHAVIOR has been enabled. Legacy behavior
-  *         uses esp_task_wdt_feed() to subscribe tasks to the wdt.
   */
-esp_err_t esp_task_wdt_add(TaskHandle_t handle);
+void esp_task_wdt_init();
 
 /**
-  * @brief  Feed the current running task
-  *
-  * This function will feed the current running task if it has subscribed to the
-  * task watchdog timer. All non-idle tasks subscribed to the wdt must call this
-  * function at least once per watchdog timeout period. Idle tasks will feed
-  * the task watchdog automatically from their idle hooks.
+  * @brief  Feed the watchdog. After the first feeding session, the watchdog will expect the calling
+  *         task to keep feeding the watchdog until task_wdt_delete() is called.
   *
-  * @return
-  *     - ESP_OK:                 Successfully fed the current running task
-  *     - ESP_ERR_INVALID_STATE:  Failed to feed current running task as the
-  *                               wdt has not been initialized, or the
-  *                               current running task has not subscribed
-  *
-  * @note   If CONFIG_TASK_WDT_LEGACY_BEHAVIOR is enabled, tasks will subscribe
-  *         to the watchdog on their first call of esp_task_wdt_feed().
   */
-esp_err_t esp_task_wdt_feed();
+
+void esp_task_wdt_feed();
+
 
 /**
-  * @brief  Unsubscribes a task from the task watchdog timer
-  *
-  * This function unsubscribes a task from the task watchdog. After unsubscribing,
-  * the task should no longer feed the wdt. If the unsubscribing task is an idle
-  * task, this function will disable feeding from the idle hook automatically.
-  *
-  * @param[in]  handle              Handle of the task to be deleted. Input NULL
-  *                                 if deleting the current running task.
+  * @brief  Delete the watchdog for the current task.
   *
-  * @return
-  *     - ESP_OK:                 Successfully unsubscribed task form the wdt
-  *     - ESP_ERR_INVALID_ARG:    Failed to unsubscribe task as it was not
-  *                               subscribed to begin with
-  *     - ESP_ERR_INVALID_STATE:  Failed to unsubscribe task as wdt has not
-  *                               been initialized yet
-  *
-  * @note   Legacy behavior only allows tasks to unsubscribe from the wdt on their
-  *         own behalf. Therefore, if CONFIG_TASK_WDT_LEGACY_BEHAVIOR is
-  *         enabled, this esp_task_wdt_delete() will accept no parameters and
-  *         unsubscribe the calling task from the wdt.
   */
-#ifdef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-esp_err_t esp_task_wdt_delete();
-#else
-esp_err_t esp_task_wdt_delete(TaskHandle_t handle);
-#endif      //CONFIG_TASK_WDT_LEGACY_BEHAVIOR
+void esp_task_wdt_delete();
+
+/**
+  * @}
+  */
+
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif      //__ESP_TASK_WDT_H
+
+
+#endif
\ No newline at end of file
index bb45b6a4afbc2e18dbd5b45941c2367072a9f3d3..ce3f09b8393a462abb17cbdd1bbde88cde94bc98 100644 (file)
@@ -20,7 +20,6 @@
 #include <string.h>
 #include <stdbool.h>
 #include "sdkconfig.h"
-#include "freertos/FreeRTOSConfig.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "freertos/queue.h"
@@ -29,7 +28,6 @@
 #include "esp_err.h"
 #include "esp_intr.h"
 #include "esp_intr_alloc.h"
-#include "esp_ipc.h"
 #include "esp_attr.h"
 #include "esp_freertos_hooks.h"
 #include "soc/timer_group_struct.h"
 
 #include "esp_task_wdt.h"
 
-//Assertion macro that exits from critical section and returns 'ret'
-#define ASSERT_EXIT_CRIT_RET_ERR(cond, ret)  ({                             \
-            if(!(cond)){                                                    \
-                portEXIT_CRITICAL(&taskwdt_spinlock);                       \
-                return ret;                                                 \
-            }                                                               \
-})
+#if CONFIG_TASK_WDT
+
+static const char* TAG = "task_wdt";
 
 typedef struct wdt_task_t wdt_task_t;
 struct wdt_task_t {
     TaskHandle_t task_handle;
-    bool fed;
+    bool fed_watchdog;
     wdt_task_t *next;
 };
 
-typedef struct task_wdt_config_t task_wdt_config_t;
-struct task_wdt_config_t {
-    wdt_task_t *list;
-    uint32_t timeout;
-    bool panic;
-    bool idle_enable[portNUM_PROCESSORS];
-    TaskHandle_t idle_handles[portNUM_PROCESSORS];
-    intr_handle_t intr_handle;
-};
-
-static task_wdt_config_t *wdt_config = NULL;
+static wdt_task_t *wdt_task_list=NULL;
 static portMUX_TYPE taskwdt_spinlock = portMUX_INITIALIZER_UNLOCKED;
 
-/*
- * Internal function that checks the list for target task. Returns the list item
- * if found and returns null if not found. Also checks if the all the other
- * tasks have checked in. Called within critical.
- */
-static wdt_task_t *check_list(TaskHandle_t handle, bool *checked)
-{
-    wdt_task_t *target = NULL;
-    *checked = true;
-    for(wdt_task_t *task = wdt_config->list; task != NULL; task = task->next){
-        if(task->task_handle == handle){
-            target = task;   //Get pointer to target task list member
-        }else{
-            if(task->fed == false){     //If a task has yet to check in
-                *checked = false;
-            }
-        }
-    }
-    return target;
-}
 
-/*
- * Resets the wdt and fed flags of each task on the list. Called within critical
- */
-static void feed_wdt()
-{
-    //All tasks have checked in; time to feed the hw watchdog.
-    TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
-    TIMERG0.wdt_feed=1;
-    TIMERG0.wdt_wprotect=0;
-    //Reset fed flags on all tasks in list
-    for (wdt_task_t *task = wdt_config->list; task != NULL; task = task->next){
-        task->fed=false;
-    }
-}
-
-/*
- * ISR for when wdt expires. Checks for which tasks have not fed. Trigger panic
- * if configured to do so in initialization
- */
-static void task_wdt_isr(void *arg)
-{
-    portENTER_CRITICAL(&taskwdt_spinlock);
+static void task_wdt_isr(void *arg) {
     wdt_task_t *wdttask;
     const char *cpu;
-    //Feed the watchdog so we don't reset
+    //Feed the watchdog so we do not reset
     TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
     TIMERG0.wdt_feed=1;
     TIMERG0.wdt_wprotect=0;
@@ -122,14 +65,16 @@ static void task_wdt_isr(void *arg)
     //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.
-    if (!wdt_config->list) {       //No tasks on list
+    portENTER_CRITICAL(&taskwdt_spinlock);
+    if (!wdt_task_list) {
+        //No task on list. Maybe none registered yet.
         portEXIT_CRITICAL(&taskwdt_spinlock);
         return;
     }
     //Watchdog got triggered because at least one task did not report in.
     ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n");
-    for (wdttask=wdt_config->list; wdttask!=NULL; wdttask=wdttask->next) {
-        if (!wdttask->fed) {
+    for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
+        if (!wdttask->fed_watchdog) {
             cpu=xTaskGetAffinity(wdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1");
             if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1");
             ets_printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu);
@@ -140,243 +85,125 @@ static void task_wdt_isr(void *arg)
         ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
     }
 
-    if (wdt_config->panic){
-        ets_printf("Aborting.\n");
-        portEXIT_CRITICAL(&taskwdt_spinlock);
-        abort();
-    }
-
+#if CONFIG_TASK_WDT_PANIC
+    ets_printf("Aborting.\n");
+    abort();
+#endif
     portEXIT_CRITICAL(&taskwdt_spinlock);
 }
 
-/*
- * Idle hook for Idle Task to feed the wdt. Will only call feed if the idle task
- * of that core has been added to wdt task list.
- */
-static bool idle_hook(void)
-{
-    uint32_t core_id = xPortGetCoreID();
-    if (wdt_config->idle_enable[core_id]){
-        esp_task_wdt_feed();
-    }
-    return true;
-}
 
-/*
- * Initializes the task watchdog timer 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)
-{
+void esp_task_wdt_feed() {
+    wdt_task_t *wdttask=wdt_task_list;
+    bool found_task=false, do_feed_wdt=true;
+    TaskHandle_t handle=xTaskGetCurrentTaskHandle();
     portENTER_CRITICAL(&taskwdt_spinlock);
-    if(wdt_config == NULL){        //wdt not initialized yet
-       //Allocate memory for wdt_config
-        wdt_config = calloc(1, sizeof(task_wdt_config_t));
-        ASSERT_EXIT_CRIT_RET_ERR((wdt_config != NULL), ESP_ERR_NO_MEM);
-
-        wdt_config->list = NULL;
-        wdt_config->timeout = timeout;
-        wdt_config->panic = panic;
 
-        //Get idle task handles
-        for(int i = 0; i <  portNUM_PROCESSORS; i++){
-            wdt_config->idle_handles[i] = xTaskGetIdleTaskHandleForCPU( i );
-            wdt_config->idle_enable[i] = false;
+    //Walk the linked list of wdt tasks to find this one, as well as see if we need to feed
+    //the real watchdog timer.
+    for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
+        //See if we are at the current task.
+        if (wdttask->task_handle == handle) {
+            wdttask->fed_watchdog=true;
+            found_task=true;
         }
-
-        //Register Idle Hook and Interrupts
-        esp_register_freertos_idle_hook(idle_hook);
-        ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &wdt_config->intr_handle))
-
-        //Configure hardware timer
-        TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;               //Disable write protection
-        TIMERG0.wdt_config0.sys_reset_length=7;                 //3.2uS
-        TIMERG0.wdt_config0.cpu_reset_length=7;                 //3.2uS
-        TIMERG0.wdt_config0.level_int_en=1;
-        TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT;          //1st stage timeout: interrupt
-        TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
-        TIMERG0.wdt_config1.clk_prescale=80*500;                //Prescaler: wdt counts in ticks of 0.5mS
-        TIMERG0.wdt_config2=wdt_config->timeout*2;      //Set timeout before interrupt
-        TIMERG0.wdt_config3=wdt_config->timeout*4;      //Set timeout before reset
-        TIMERG0.wdt_config0.en=1;
+        //If even one task in the list doesn't have the do_feed_wdt var set, we do not feed the watchdog.
+        if (!wdttask->fed_watchdog) do_feed_wdt=false;
+    }
+    
+    if (!found_task) {
+        //This is the first time the task calls the task_wdt_feed function. Create a new entry for it in
+        //the linked list.
+        wdt_task_t *newtask=malloc(sizeof(wdt_task_t));
+        memset(newtask, 0, sizeof(wdt_task_t));
+        newtask->task_handle=handle;
+        newtask->fed_watchdog=true;
+        if (wdt_task_list == NULL) {
+            wdt_task_list=newtask;
+        } else {
+            for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) ;
+            wdttask->next=newtask;
+        }
+    }
+    if (do_feed_wdt) {
+        //All tasks have checked in; time to feed the hw watchdog.
+        TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
         TIMERG0.wdt_feed=1;
-        TIMERG0.wdt_wprotect=0;                         //Enable write protection
-
-    }else{      //wdt_config previously initialized
-        //Reconfigure task wdt
-        wdt_config->panic = panic;
-        wdt_config->timeout = timeout;
-
-        //Reconfigure hardware timer
-        TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;   //Disable write protection
-        TIMERG0.wdt_config0.en=0;                   //Disable timer
-        TIMERG0.wdt_config2=wdt_config->timeout*2;           //Set timeout before interrupt
-        TIMERG0.wdt_config3=wdt_config->timeout*4;           //Set timeout before reset
-        TIMERG0.wdt_config0.en=1;                   //Renable timer
-        TIMERG0.wdt_feed=1;                         //Reset timer
-        TIMERG0.wdt_wprotect=0;                     //Enable write protection
+        TIMERG0.wdt_wprotect=0;
+        //Reset fed_watchdog status
+        for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false;
     }
     portEXIT_CRITICAL(&taskwdt_spinlock);
-    return ESP_OK;
 }
 
-esp_err_t esp_task_wdt_deinit()
-{
+void esp_task_wdt_delete() {
+    TaskHandle_t handle=xTaskGetCurrentTaskHandle();
+    wdt_task_t *wdttask=wdt_task_list;
     portENTER_CRITICAL(&taskwdt_spinlock);
-    //wdt must already be initialized
-    ASSERT_EXIT_CRIT_RET_ERR((wdt_config != NULL), ESP_ERR_INVALID_STATE);
-    //Task list must be empty
-    ASSERT_EXIT_CRIT_RET_ERR((wdt_config->list == NULL), ESP_ERR_INVALID_STATE);
 
-    //Disable hardware timer
-    TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;   //Disable write protection
-    TIMERG0.wdt_config0.en=0;                   //Disable timer
-    TIMERG0.wdt_wprotect=0;                     //Enable write protection
-
-    esp_deregister_freertos_idle_hook(idle_hook);   //deregister idle hook
-    ESP_ERROR_CHECK(esp_intr_free(wdt_config->intr_handle))  //Unregister interrupt
-    free(wdt_config);                      //Free wdt_config
-    wdt_config = NULL;
-    portEXIT_CRITICAL(&taskwdt_spinlock);
-    return ESP_OK;
-}
-
-esp_err_t esp_task_wdt_add(TaskHandle_t handle)
-{
-    portENTER_CRITICAL(&taskwdt_spinlock);      //Nested critical in Legacy (called from feed)
-#ifdef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-    wdt_task_t *target_task;
-#else
-    //Return error if wdt has not been initialized
-    ASSERT_EXIT_CRIT_RET_ERR((wdt_config != NULL), ESP_ERR_INVALID_STATE);
-
-    wdt_task_t *target_task;
-    bool all_fed;
-    if (handle == NULL){    //Get handle of current task if none is provided
-        handle = xTaskGetCurrentTaskHandle();
+    //Wdt task list can't be empty
+    if (!wdt_task_list) {
+        ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?");
+        portEXIT_CRITICAL(&taskwdt_spinlock);
+        return;
     }
-
-    //Check if tasks exists in task list, and if all other tasks have checked in
-    target_task = check_list(handle, &all_fed);
-    //Return error if task has already been added
-    ASSERT_EXIT_CRIT_RET_ERR((target_task == NULL), ESP_ERR_INVALID_ARG);
-#endif      //CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-    //Add task to wdt list
-    target_task = calloc(1,sizeof(wdt_task_t));
-    //Return error if calloc failed
-    ASSERT_EXIT_CRIT_RET_ERR((target_task != NULL), ESP_ERR_NO_MEM);
-
-    target_task->task_handle = handle;
-    target_task->fed = true;
-    target_task->next = NULL;
-    if (wdt_config->list == NULL) {    //Adding to empty list
-        wdt_config->list = target_task;
-    } else {    //Adding to tail of list
-        wdt_task_t *task;
-        for (task = wdt_config->list; task->next != NULL; task = task->next){
-            ;   //point task to current tail of wdt task list
+    if (handle==wdt_task_list) {
+        //Current task is first on list.
+        wdt_task_list=wdt_task_list->next;
+        free(wdttask);
+    } else {
+        //Find current task in list
+        if (wdt_task_list->task_handle==handle) {
+            //Task is the very first one.
+            wdt_task_t *freeme=wdt_task_list;
+            wdt_task_list=wdt_task_list->next;
+            free(freeme);
+            portEXIT_CRITICAL(&taskwdt_spinlock);
+            return;
         }
-        task->next = target_task;
-    }
-
-    //If idle task, set idle_enable flag
-    for(int i = 0; i < portNUM_PROCESSORS; i++){
-        if(handle == wdt_config->idle_handles[i]){
-            wdt_config->idle_enable[i] = true;
-            break;
+        while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next;
+        if (!wdttask->next) {
+            ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!");
+            portEXIT_CRITICAL(&taskwdt_spinlock);
+            return;
         }
+        wdt_task_t *freeme=wdttask->next;
+        wdttask->next=wdttask->next->next;
+        free(freeme);
     }
-
-#ifndef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-    if(all_fed){     //Reset if all other tasks in list have checked in
-        feed_wdt();
-    }
-#endif
-    portEXIT_CRITICAL(&taskwdt_spinlock);              //Nested critical if Legacy
-    return ESP_OK;
-}
-
-esp_err_t esp_task_wdt_feed()
-{
-    portENTER_CRITICAL(&taskwdt_spinlock);
-    //Return error if wdt has not been initialized
-    ASSERT_EXIT_CRIT_RET_ERR((wdt_config != NULL), ESP_ERR_INVALID_STATE);
-
-    TaskHandle_t handle = xTaskGetCurrentTaskHandle();
-    wdt_task_t *target_task;
-    bool all_fed;
-
-    //Check if tasks exists in task list, and if all other tasks have checked in
-    target_task = check_list(handle, &all_fed);
-
-    if(target_task == NULL){
-#ifdef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-        //Add task to wdt task list if it doesn't exist, return error if failed to add
-        ASSERT_EXIT_CRIT_RET_ERR((esp_task_wdt_add(handle) == ESP_OK), ESP_ERR_NO_MEM);
-#else
-        portEXIT_CRITICAL(&taskwdt_spinlock);
-        return ESP_ERR_INVALID_STATE;                  //Return error if task does not exist
-#endif      //CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-    }else{
-        target_task->fed = true;   //Feed the task
-    }
-
-    if(all_fed){     //Reset if all other tasks in list have checked in
-        feed_wdt();
-    }
-
     portEXIT_CRITICAL(&taskwdt_spinlock);
-    return ESP_OK;
 }
 
-#ifdef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-esp_err_t esp_task_wdt_delete()
-{
-    TaskHandle_t handle = xTaskGetCurrentTaskHandle();
-#else
-esp_err_t esp_task_wdt_delete(TaskHandle_t handle)
-{
-    if(handle == NULL){
-        handle = xTaskGetCurrentTaskHandle();
-    }
-#endif      //CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-    portENTER_CRITICAL(&taskwdt_spinlock);
-    //Return error if wdt has not been initialized
-    ASSERT_EXIT_CRIT_RET_ERR((wdt_config != NULL), ESP_ERR_INVALID_STATE);
-    wdt_task_t *target_task;
-    bool all_fed;
-
-    target_task = check_list(handle, &all_fed);
 
-    //Task doesn't exist on list. Return error
-    ASSERT_EXIT_CRIT_RET_ERR((target_task != NULL), ESP_ERR_INVALID_ARG);
-
-    if(target_task == wdt_config->list){     //target_task is head of list. Delete
-        wdt_config->list = target_task->next;
-        free(target_task);
-    }else{                                      //target_task not head of list. Delete
-        wdt_task_t *prev;
-        for (prev = wdt_config->list; prev->next != target_task; prev = prev->next){
-            ;   //point prev to task preceding target_task
-        }
-        prev->next = target_task->next;
-        free(target_task);
-    }
-
-    //If idle task, disable idle_enable flag
-    for(int i = 0; i < portNUM_PROCESSORS; i++){
-        if(handle == wdt_config->idle_handles[i]){
-            wdt_config->idle_enable[i] = false;
-        }
-    }
+#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
+static bool idle_hook(void) {
+#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
+    if (xPortGetCoreID()!=0) return true;
+#endif
+    esp_task_wdt_feed();
+    return true;
+}
+#endif
 
-    if(all_fed){     //Reset timer if all remaining tasks have checked in
-        feed_wdt();
-    }
 
-    portEXIT_CRITICAL(&taskwdt_spinlock);
-    return ESP_OK;
+void esp_task_wdt_init() {
+    TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
+    TIMERG0.wdt_config0.sys_reset_length=7;                 //3.2uS
+    TIMERG0.wdt_config0.cpu_reset_length=7;                 //3.2uS
+    TIMERG0.wdt_config0.level_int_en=1;
+    TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT;          //1st stage timeout: interrupt
+    TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
+    TIMERG0.wdt_config1.clk_prescale=80*500;                //Prescaler: wdt counts in ticks of 0.5mS
+    TIMERG0.wdt_config2=CONFIG_TASK_WDT_TIMEOUT_S*2000;     //Set timeout before interrupt
+    TIMERG0.wdt_config3=CONFIG_TASK_WDT_TIMEOUT_S*4000;     //Set timeout before reset
+    TIMERG0.wdt_config0.en=1;
+    TIMERG0.wdt_feed=1;
+    TIMERG0.wdt_wprotect=0;
+#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
+    esp_register_freertos_idle_hook(idle_hook);
+#endif
+    ESP_ERROR_CHECK( esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, NULL) );
 }
 
+
+#endif
index 073267445f6915e18ecc9a6b43a185d4e6a06323..2438d960001ba7be8d22e8b90f6ec8be51c68f99 100644 (file)
@@ -1382,15 +1382,6 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
  */
 TaskHandle_t xTaskGetIdleTaskHandle( void );
 
-/**
- * xTaskGetIdleTaskHandleForCPU() is only available if
- * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h.
- *
- * Simply returns the idle task handle of a given cpu. It is not valid to call
- * xTaskGetIdleTaskHandleForCPU() before the scheduler has been started.
- */
-TaskHandle_t xTaskGetIdleTaskHandleForCPU( UBaseType_t cpuid );
-
 /**
  * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for
  * uxTaskGetSystemState() to be available.
index 9fe36dbd9abd6df1cffcfaa97204cc39978ef67c..15d2e135d3eed0b4ced0e1f4a7ded3f3e6446fdf 100644 (file)
@@ -2371,18 +2371,6 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
                return xIdleTaskHandle[ xPortGetCoreID() ];
        }
 
-       TaskHandle_t xTaskGetIdleTaskHandleForCPU( UBaseType_t cpuid )
-       {
-           TaskHandle_t xReturn = NULL;
-           /* If xTaskGetIdleTaskHandleForCPU() is called before the scheduler has been
-        started, then xIdleTaskHandle will be NULL. */
-           if (cpuid < portNUM_PROCESSORS) {
-               configASSERT( ( xIdleTaskHandle[ cpuid ] != NULL ) );
-               xReturn = xIdleTaskHandle[ cpuid ];
-           }
-           return xReturn;
-       }
-
 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
 /*----------------------------------------------------------*/
 
index 73f23a00d7f7cf1a21047f049d2a0ab618f24b85..7817355fbb2f5128c3f8f4dcfc14c6fa3076f203 100644 (file)
@@ -72,7 +72,7 @@ static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickT
 esp_err_t esp_pthread_init(void)
 {
     vListInitialise((List_t *)&s_threads_list);
-    s_once_mux = xSemaphoreCreateMutex();
+    s_once_mux = xSemaphoreCreateRecursiveMutex();
     if (s_once_mux == NULL) {
         return ESP_ERR_NO_MEM;
     }
@@ -232,6 +232,7 @@ int pthread_join(pthread_t thread, void **retval)
 {
     esp_pthread_t *pthread = (esp_pthread_t *)thread;
     int ret = 0;
+    bool wait = false;
 
     ESP_LOGV(TAG, "%s %p", __FUNCTION__, pthread);
 
@@ -257,6 +258,7 @@ int pthread_join(pthread_t thread, void **retval)
         } else {
             if (pthread->state == PTHREAD_TASK_STATE_RUN) {
                 pthread->join_task = xTaskGetCurrentTaskHandle();
+                wait = true;
             } else {
                 pthread_delete(pthread);
             }
@@ -264,7 +266,7 @@ int pthread_join(pthread_t thread, void **retval)
     }
     xSemaphoreGive(s_threads_mux);
 
-    if (ret == 0 && pthread->join_task) {
+    if (ret == 0 && wait) {
         xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
         if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) {
             assert(false && "Failed to lock threads list!");
@@ -375,7 +377,9 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
     TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
     // do not take mutex if OS is not running yet
     if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ||
-            !cur_task || xSemaphoreTake(s_once_mux, portMAX_DELAY) == pdTRUE)
+            // init_routine can call pthread_once for another objects, so use recursive mutex
+            // FIXME: behaviour is undefined if init_routine calls pthread_once for the same object in the current context
+            !cur_task || xSemaphoreTakeRecursive(s_once_mux, portMAX_DELAY) == pdTRUE)
     {
         if (!once_control->init_executed) {
             ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
@@ -383,7 +387,7 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
             once_control->init_executed = 1;
         }
         if (cur_task) {
-            xSemaphoreGive(s_once_mux);
+            xSemaphoreGiveRecursive(s_once_mux);
         }
     }
     else
index 287a1da1b1dd20a1ac3b4362576060b622d61efe..ced961d09fa10e4b7eba087365c84f4fbc59be34 100644 (file)
@@ -1,10 +1,17 @@
 #include <iostream>
+#include <sstream>
 #include <thread>
 #include <mutex>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
 #include "unity.h"
 
 #if __GTHREADS && __GTHREADS_CXX0X
 
+#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
+#include "esp_log.h"
+const static char *TAG = "pthread_test";
+
 static std::shared_ptr<int> global_sp;
 static std::mutex           mtx;
 static std::recursive_mutex recur_mtx;
@@ -56,7 +63,7 @@ static void thread_main()
     }
 }
 
-TEST_CASE("pthread CXX", "[pthread]")
+TEST_CASE("pthread C++", "[pthread]")
 {
     global_sp.reset(new int(1));
 
@@ -80,4 +87,36 @@ TEST_CASE("pthread CXX", "[pthread]")
     }
 }
 
+static void task_test_sandbox(void *arg)
+{
+    bool *running = (bool *)arg;
+
+    ESP_LOGI(TAG, "About to create a string stream");
+    std::stringstream ss;
+    ESP_LOGI(TAG, "About to write to string stream");
+    ss << "Hello World!";
+    ESP_LOGI(TAG, "About to extract from stringstream");
+    ESP_LOGI(TAG, "Text: %s", ss.str().c_str());
+
+    if (running) {
+        *running = false;
+        vTaskDelete(NULL);
+    }
+}
+
+TEST_CASE("pthread mix C/C++", "[pthread]")
+{
+    bool running = true;
+
+    std::thread t1(task_test_sandbox, (void *)NULL);
+    xTaskCreatePinnedToCore((TaskFunction_t)&task_test_sandbox, "task_test_sandbox", 2048, &running, 5, NULL, 0);
+    while (running) {
+        vTaskDelay(1);
+    }
+    if (t1.joinable()) {
+        std::cout << "Join thread " << std::hex << t1.get_id() << std::endl;
+        t1.join();
+    }
+}
+
 #endif
index 98506cf1445fcf176ed4ef41488679bf10c9c8e2..e15ff53dd7132db38ecd28d63ec8500259c89af0 100644 (file)
@@ -28,40 +28,23 @@ Task watchdog
 ^^^^^^^^^^^^^
 
 Any tasks can elect to be watched by the task watchdog. If such a task does not feed the watchdog within the time
-specified by the task watchdog timeout, the watchdog will print out a warning with information about which processes 
-are running on the ESP32 CPUs and which processes failed to feed the watchdog.
+specified by the task watchdog timeout (which is configurable using ``make menuconfig``), the watchdog will
+print out a warning with information about which processes are running on the ESP32 CPUs and which processes
+failed to feed the watchdog.
 
-Ideally, the task watchdog should watch the idle tasks. The usual cause of the idle tasks not feeding the watchdog 
+By default, the task watchdog watches the idle tasks. The usual cause of idle tasks not feeding the watchdog 
 is a higher-priority process looping without yielding to the lower-priority processes, and can be an indicator
 of badly-written code that spinloops on a peripheral or a task that is stuck in an infinite loop.
 
-Other task can elect to be watched by the task watchdog. If the watchdog watches multiple tasks, all the tasks
-must feed before the watchdog times out. If one or more tasks fails to feed, the watchdog timeout will trigger.
-The watchdog timer can be initialized using :cpp:func:`esp_task_wdt_init` which will configure the hardware timer and
-establish the hardware timer interrupts. In order for a task to be watched by the task watchdog, a task must subscribe to
-the task watchdog using :cpp:func:`esp_task_wdt_add`. Once added, each subscribed task must call :cpp:func:`esp_task_wdt_feed` 
-periodically to prevent the watchdog from timing out. If all tasks being watched have fed, the watchdog timer counter immediately resets
-and starts recounting to the timeout value from zero. To unsubscribe a task from the task watchdog, call :cpp:func:`esp_task_wdt_delete()`.
-Once all tasks have been unsubscribed form the task watchdog, :cpp:func:`esp_task_wdt_deinit()` can be called to deinitialize
-the task watchdog. Deinitialization will stop the hardware timer, deregister the hardware timer interrupts, and remove the idle hooks
-if idle tasks were being watched.
-
-By setting the task watchdog options in ``make menuconfig``, the task watchdog can be automatically initialized
-during startup by enabling the :ref:`CONFIG_TASK_WDT`. Moreover the two Idle tasks can also be subscibed to the 
-task watchdog on startup as well by enabling :ref:`CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0` and 
-:ref:`CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1`.
-
-The task watchdog is built around the hardware watchdog in timer group 0. If the watchdog for some reason
+Other task can elect to be watched by the task watchdog by calling ``esp_task_wdt_feed()``. Calling this routine
+for the first time will register the task to the task watchdog; calling it subsequent times will feed
+the watchdog. If a task does not want to be watched anymore (e.g. because it is finished and will call 
+``vTaskDelete()`` on itself), it needs to call ``esp_task_wdt_delete()``.
+
+The task watchdog is built around the hardware watchdog in timer group 0. If this watchdog for some reason
 cannot execute the interrupt handler that prints the task data (e.g. because IRAM is overwritten by garbage
 or interrupts are disabled entirely) it will hard-reset the SOC.
 
-Note: ``make menuconfig`` provides a :ref:`CONFIG_TASK_WDT_LEGACY_BEHAVIOR` option which will change the behavior of the 
-task watchdog to make it compatible with the legacy code. Note that the legacy behavior causes tasks to subscribe to the
-task watchdog on their first call to :cpp:func:`esp_task_wdt_feed`. Moreover, legacy behavior only allows
-tasks to unsubscribe on their own behalf when calling :cpp:func:`esp_task_wdt_delete()`. It is strongly recommended that 
-non-legacy behavior is used as additions/deletions/feeds are explicit.
-
-
 JTAG and watchdogs
 ^^^^^^^^^^^^^^^^^^
 
@@ -70,27 +53,20 @@ CPU. This makes it very hard to debug code; that is why the OpenOCD config will
 This does mean that you will not get any warnings or panics from either the task or interrupt watchdog when the ESP32
 is connected to OpenOCD via JTAG.
 
-Interrupt Watchdog API Reference
---------------------------------
+API Reference
+-------------
 
-Header File
-^^^^^^^^^^^
+Header Files
+^^^^^^^^^^^^
 
   * :component_file:`esp32/include/esp_int_wdt.h`
+  * :component_file:`esp32/include/esp_task_wdt.h`
 
 
 Functions
 ---------
-.. doxygenfunction:: esp_int_wdt_init
-
-Task Watchdog API Reference
-----------------------------
 
-NOTE: Ensure that the :ref:`CONFIG_TASK_WDT_LEGACY_BEHAVIOR` configuraiton is disabled using ``make menuconfig``
-to prevent legacy behavior of the task watchdog.
-
-A full example using the Task Watchdog is available in esp-idf: :example:`system/task_watchdog`
-
-
-.. include:: /_build/inc/esp_task_wdt.inc
+.. doxygenfunction:: esp_int_wdt_init
+.. doxygenfunction:: esp_task_wdt_init
+.. doxygenfunction:: esp_task_wdt_feed
+.. doxygenfunction:: esp_task_wdt_delete
diff --git a/examples/system/task_watchdog/Makefile b/examples/system/task_watchdog/Makefile
deleted file mode 100644 (file)
index fb4f26b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# This is a project Makefile. It is assumed the directory this Makefile resides in is a
-# project subdirectory.
-#
-
-PROJECT_NAME := task_watchdog
-
-include $(IDF_PATH)/make/project.mk
-
diff --git a/examples/system/task_watchdog/README.md b/examples/system/task_watchdog/README.md
deleted file mode 100644 (file)
index 92a3132..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Example: task_watchdog
-
-This test code shows how to initialize the task watchdog, add tasks to the
-watchdog task list, feeding the tasks, deleting tasks from the watchdog task
-list, and deinitializing the task watchdog.
-
-
-### Test:
-
-Program should run without error. Comment out "esp_task_wdt_feed()" to observe
-a watchdog timeout.
-
diff --git a/examples/system/task_watchdog/main/component.mk b/examples/system/task_watchdog/main/component.mk
deleted file mode 100644 (file)
index 44bd2b5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#
-# Main Makefile. This is basically the same as a component makefile.
-#
diff --git a/examples/system/task_watchdog/main/task_watchdog_example_main.c b/examples/system/task_watchdog/main/task_watchdog_example_main.c
deleted file mode 100644 (file)
index 072ac73..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Task_Watchdog Example
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "freertos/queue.h"
-#include "esp_task_wdt.h"
-
-#ifndef CONFIG_TASK_WDT_LEGACY_BEHAVIOR
-
-#define TIMEOUT 4000
-#define TASK_PERIOD 2000
-
-#define ASSERT_PRINT_ERROR(cond, str)    ({                                 \
-            if(!(cond)){                                                    \
-                printf("%s\n",str);                                         \
-            }                                                               \
-})
-
-void feeding_task(void *arg){
-    int core = xPortGetCoreID();
-    //Simple task that periodically feeds watchdog
-    while(1){
-        if(esp_task_wdt_feed() == ESP_OK){
-            printf("Feed Task %d\n", core);
-        }
-        vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
-    }
-}
-
-void app_main(void)
-{
-    //Initialize task watchdog
-    if(esp_task_wdt_init(TIMEOUT, false) != ESP_OK){
-        printf("Error\n");
-    }
-
-    //Create tasks
-    TaskHandle_t handle_0;
-    TaskHandle_t handle_1;
-    xTaskCreatePinnedToCore(feeding_task, "Feed Task 0", 2000, NULL, 15, &handle_0, 0);
-    xTaskCreatePinnedToCore(feeding_task, "Feed Task 1", 2000, NULL, 15, &handle_1, 1);
-
-    //Add tasks to wdt
-    ASSERT_PRINT_ERROR(esp_task_wdt_add(handle_0) == ESP_OK, "Add failed");
-    ASSERT_PRINT_ERROR(esp_task_wdt_add(handle_1) == ESP_OK, "Add failed");
-
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    //Adding Idles. Idle hook will call feed automatically
-    TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
-    ASSERT_PRINT_ERROR(idle_0 != NULL, "Get Idle handle failed");
-    ASSERT_PRINT_ERROR(esp_task_wdt_add(idle_0) == ESP_OK, "Add failed");
-#endif
-
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
-    ASSERT_PRINT_ERROR(idle_1 != NULL, "Get Idle handle failed");
-    ASSERT_PRINT_ERROR(esp_task_wdt_add(idle_1) == ESP_OK, "Add failed");
-#endif
-
-    //Wait 10 seconds
-    vTaskDelay(pdMS_TO_TICKS(10000));
-
-    //Remove tasks form wdt
-    ASSERT_PRINT_ERROR(esp_task_wdt_delete(handle_0) == ESP_OK, "Failed to delete");
-    ASSERT_PRINT_ERROR(esp_task_wdt_delete(handle_1) == ESP_OK, "Failed to delete");
-    //Delete tasks
-    vTaskDelete(handle_0);
-    vTaskDelete(handle_1);
-
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
-    ASSERT_PRINT_ERROR(esp_task_wdt_delete(idle_0) == ESP_OK, "Failed to delete");
-#endif
-
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    ASSERT_PRINT_ERROR(esp_task_wdt_delete(idle_1) == ESP_OK, "Failed to delete");
-#endif
-
-
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
-#ifndef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    //Deinit task watchdog. Can only do so once all tasks (including idle) are deleted from wdt
-    ASSERT_PRINT_ERROR(esp_task_wdt_deinit() == ESP_OK, "deinit failed");
-#endif
-#endif
-
-    printf("Complete\n");
-
-}
-
-#endif