.. _watchdog-example-code:

Watchdog Timer Example Code
===========================

On the |DEVICE|, the Watchdog continues to tick using the 32kHz clock in 
Standby. As a workaround, a "soft stop" is implemented by setting
the Watchdog reload value to `0xFFFFFFFF` (~34 hours). Once the |DEVICE| wakes 
from Standby, you can change the Watchdog reload value to the intended value. 
This workaround potentially reduces the power consumption of the |DEVICE|. 
Without the workaround, the |DEVICE| must wake up before the timeout expires, or
a reset will occur.

The code below implements this workaround.

.. code-block:: c 
    :caption: watchdog_addons.h
    :linenos:

    #ifndef WATCHDOG_ADDONS_WATCHDOG_ADDONS_H_
    #define WATCHDOG_ADDONS_WATCHDOG_ADDONS_H_

    #include <stdint.h>
    
    #define WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY 1
    
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
    #include <ti/drivers/Watchdog.h>
    typedef struct
    {
        Watchdog_Handle handle;
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
        uint32_t applicationReloadTicks;
        uint32_t standbyReloadTicks;
    #endif
    } Watchdog_addons_Params;
    #endif
    
    /**
     * assumes Watchdog is already initialized.
     * ok to call if Watchdog is already running.
     * returns 0 if ok
     */
    extern int8_t Watchdog_addons_init(Watchdog_addons_Params *pParams);
    
    
    #endif /* WATCHDOG_ADDONS_WATCHDOG_ADDONS_H_ */


.. code-block:: c 
    :caption: watchdog_addons.c
    :linenos:

    #include "watchdog_addons.h"
    
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
    #include <ti/drivers/Power.h>
    #include <ti/drivers/power/PowerCC23X0.h>
    #endif
    
    static uint8_t gInitDone = 0;
    static Watchdog_addons_Params gCurParams;
    
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
    Power_NotifyObj gPowerNotifyObj;
    int PowerNotify_handler(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg);
    #endif
    
    /**
     * assumes Watchdog is already initialized.
     * ok to call if Watchdog is already running.
     * returns 0 if ok
     */
    int8_t Watchdog_addons_init(Watchdog_addons_Params *pParams)
    {
        if (gInitDone)
            return -1; // error: already initialized
    
        if (!pParams || !pParams->handle)
            return -1; // error: invalid parameters
    
        gCurParams.handle                   =   pParams->handle;
    
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
        gCurParams.applicationReloadTicks   =   pParams->applicationReloadTicks;
        gCurParams.standbyReloadTicks       =   pParams->standbyReloadTicks;
    
        // register for power notifications.
        // if entering standby, set the Watchdog reload value to X (typically will be max, e.g. 0xFFFFFFFF)
        // if exiting standby, set the Watchdog reload value to normal
        int status = Power_registerNotify(&gPowerNotifyObj, PowerLPF3_ENTERING_STANDBY | PowerLPF3_AWAKE_STANDBY, &PowerNotify_handler, 0);
        if (status != Power_SOK) while (1); // error
    #endif
    
        gInitDone = 1;
        return 0;
    }
    
    #if WATCHDOG_ADDON_FEATURE__SOFT_DISABLE_DURING_STANDBY
    int PowerNotify_handler(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg)
    {
        if (eventType == PowerLPF3_ENTERING_STANDBY)
        {
            Watchdog_setReload(gCurParams.handle, gCurParams.standbyReloadTicks);
        }
        else if (eventType == PowerLPF3_AWAKE_STANDBY)
        {
            Watchdog_setReload(gCurParams.handle, gCurParams.applicationReloadTicks);
        }
    
        return Power_NOTIFYDONE;
    }
    #endif


.. code-block:: c 
    :caption: watchdog.c
    :linenos:
    :emphasize-lines: 40, 129, 165

    #include <stdint.h>
    #include <stddef.h>
    #include <unistd.h>
   
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/Power.h>
    #include <ti/drivers/Watchdog.h>
   
    /* Driver configuration */
    #include "ti_drivers_config.h"
   
    #include "watchdog_addons.h"
   
    #define TIMEOUT_MS 1000
    #define SLEEP_US   500000
   
    Watchdog_Handle watchdogHandle;
    uint32_t reloadValue;
   
    static void testWatchdogAddon(uint8_t useWatchdogAddon);
   
    /*
    *  ======== gpioButtonIsr ========
    */
    void gpioButtonIsr(uint_least8_t index)
    {
       GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
   
       /*
       * Simulate the application being stuck in an ISR. This ISR can be
       * preempted by the watchdog Non-Maskable Interrupt (NMI).
       */
       while (1) {}
    }
   
    /*
    *  ======== mainThread ========
    */
    void *mainThread(void *arg0)
    {
       Watchdog_Params params;
   
       /* Call driver init functions */
       GPIO_init();
       Watchdog_init();
   
       /* Configure the LED and button pins */
       GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
       GPIO_setConfig(CONFIG_GPIO_LED_1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
   
       /* Open a Watchdog driver instance */
       Watchdog_Params_init(&params);
       params.debugStallMode = Watchdog_DEBUG_STALL_ON;
       params.resetMode      = Watchdog_RESET_ON;
   
       watchdogHandle = Watchdog_open(CONFIG_WATCHDOG_0, &params);
       if (watchdogHandle == NULL)
       {
          /* Error opening Watchdog */
          while (1) {}
       }
   
       /*
       * The watchdog reload value is initialized during the
       * Watchdog_open() call. The reload value can also be
       * set dynamically during runtime.
       *
       * Converts TIMEOUT_MS to watchdog clock ticks.
       * This API is not applicable for all devices.
       * See the device specific watchdog driver documentation
       * for your device.
       */
       reloadValue = Watchdog_convertMsToTicks(watchdogHandle, TIMEOUT_MS);
   
       /*
       * A value of zero (0) indicates the converted value exceeds 32 bits
       * OR that the API is not applicable for this specific device.
       */
       if (reloadValue != 0)
       {
          Watchdog_setReload(watchdogHandle, reloadValue);
       }
   
       const uint8_t useAddon = 1;
       testWatchdogAddon(useAddon);
   
       while (1)
       {
   
          /*
          * Disabling power policy will prevent the device from entering
          * low power state. The device will stay awake when the CPU is
          * idle.
          */
          Power_disablePolicy();
   
          /* Sleep for SLEEP_US before clearing the watchdog */
          usleep(SLEEP_US);
          Watchdog_clear(watchdogHandle);
          GPIO_toggle(CONFIG_GPIO_LED_0);
   
          /*
          * Enabling power policy will allow the device to enter a low
          * power state when the CPU is idle. How the watchdog peripheral
          * behaves in a low power state is device specific.
          */
          Power_enablePolicy();
   
          /* Sleep for SLEEP_US before clearing the watchdog */
          usleep(SLEEP_US);
          Watchdog_clear(watchdogHandle);
          GPIO_toggle(CONFIG_GPIO_LED_0);
       }
    }
   
    /*
    * This function tests when Standby is entered.
    * Then Watchdog will have a "soft" stop during Standby.
    * So, Watchdog will never trigger reset, as long as time(standby) < time(standby Watchdog reload).
    * While device is active:
    *  - Watchdog will trigger if time(application interval Watchdog_clear) > time(application Watchdog ticks)
    *  - Watchdog will not trigger if time(application interval Watchdog_clear) < time(application Watchdog ticks)
    */
    #include DeviceFamily_constructPath(inc/hw_types.h)
    #include DeviceFamily_constructPath(inc/hw_memmap.h)
    #include DeviceFamily_constructPath(inc/hw_ckmd.h)
    #include DeviceFamily_constructPath(driverlib/hapi.h)
    static void testWatchdogAddon(uint8_t useWatchdogAddon)
    {
       if (useWatchdogAddon)
       {
          Watchdog_addons_Params params;
          params.handle = watchdogHandle;
          params.applicationReloadTicks = reloadValue;
          params.standbyReloadTicks = 0xFFFFFFFF;
          int8_t status = Watchdog_addons_init(&params);
          if (status) while (1); // error
       }
   
       // Stay in Standby for longer than time(Watchdog application reload value).
       // If Watchdog addon for "soft stop in standby" is used, then Watchdog should not trigger a reset.
       // Else if not used, then Watchdog should trigger a reset.
       //
       // test result:
       // - OK: if useWatchdogAddon==0, then a reset is generated
       // - OK: if useWatchdogAddon==1, then reset is not generated
   
       // Stay in Active for longer than time(Watchdog application reload value).
       // Independent of whether "soft stop in standby" is used, Watchdog should trigger a reset.
       // Test results:
       // - OK: if useWatchdogAddon==0, then a reset is generated
       // - OK: if useWatchdogAddon==1, then reset is not generated
   
       // Two Test Cases:
       // - clearWatchdog == 1 --> proves that the workaround works in the normal
       //    case (application wakes up periodically from Standby to clear the 
       //    Watchdog).
       // - clearWatchdog == 0 --> proves that the Watchdog will reset the device
       //    if the device a) is in Active Mode and b) does not clear the 
       //    Watchdog.
       // Assume addon always enabled (useWatchdogAddon == 1).
       const uint32_t sleep_sec = (TIMEOUT_MS * 2) / 1000;
       const uint8_t clearWatchdog = 1;
       while (1)
       {
          sleep(sleep_sec);
   
          if (clearWatchdog)
          {
             Watchdog_clear(watchdogHandle);
          }
          else
          {
             while (1);
          }
       }
    }
   