//-----------------------------------------------------------------------------
///
/// \brief  Watchdog
///
///         Watchdog for STM32 microcontroller
///
/// \date   20150915
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


//---Includes------------------------------------------------------------------


//---Own------------------------------

#include <biwak/biwak.h>         // exception
#include <biwak/handler.h>       // WWDG_IRQHandler
#include <biwak/watchdog.h>      // ourself
#include <biwak/rcc.h>           // rccWatchdogClockEnable
#include <lepto/log.h>
#include <string.h>              // memset
#include <HALWrapper/stm32_wdg.h>
#include <HALWrapper/stm32_hal.h>
#include <biwak/exception.h>

#define WDG_WINDOW ( 0x7F ) //must be a number lower than Max_Data = 0x80
#define WDG_COUNTER ( 0x70 )
#define WDG_RELOAD ( 0xFFE )


//---Implementation------------------------------------------------------------

#if 0
struct{
   //IWDG_HandleTypeDef handler;
   IWDG_TypeDef *watchdog;

} static const watchdogData[]=
{
   #if defined(STM32L1)
      [eWatchdog1]={ IWDG},
   #elif defined(STM32F0)
      [eWatchdog1]={ IWDG},
   #elif defined(STM32F1)
      [eWatchdog1]={ IWDG},
   //#elif defined STM32F072xB
   #elif defined(STM32F3)
      [eWatchdog1]={ IWDG},
   #elif defined(STM32F4)
      [eWatchdog1]={ IWDG},
   //#elif defined STM32F072xB
   #endif
};
#endif

//uint8_t watchdogKeeper=0;


CWatchdog::CWatchdog( )
   :eWatchdogState(eWatchdogStateStopped)
{
   m_pHandler=new WATCHDOG_HANDLE_TYPE;
   memset(m_pHandler, 0, sizeof( WATCHDOG_HANDLE_TYPE ) );

   /*
      ### IWDG clock counter = (PCLK1 (48MHz)/4096)/8 = 1464Hz (~683 us)
      IWDG_SetPrescaler(IWDG_Prescaler_8);
      ### Set Window value to 80; IWDG counter should be refreshed only when the counter
      ### is below 80 (and greater than 64) otherwise a reset will be generated
      IWDG_SetWindowValue(80);
      ###Enable IWDG and set counter value to 127, IWDG timeout = ~683 us * 64 = 43.7 ms
      ### In this case the refresh window is: ~683 * (127-80)= 32.1ms < refresh window < ~683 * 64 = 43.7ms
      IWDG_Enable(127);
   */
   m_pHandler->Instance= IWDG;
   // IWDG_PRESCALER_8 around 1 Seconds on STM32F303
   // IWDG_PRESCALER_64 around 8 Seconds on STM32F072
   m_pHandler->Init.Prescaler=IWDG_PRESCALER_64;
   #if ! defined(STM32F1) && ! defined(STM32F4) && ! defined(STM32L1)
      m_pHandler->Init.Window=IWDG_WINDOW_DISABLE;
   #endif
   //pHandler->Init.Window=1;
   //pHandler->Init.Counter=WDG_COUNTER;
   m_pHandler->Init.Reload=WDG_RELOAD;

   rccWatchdogClockEnable(m_pHandler->Instance);

   init();

   #pragma GCC diagnostic push
   #pragma GCC diagnostic ignored "-Wvolatile"

   __HAL_DBGMCU_FREEZE_IWDG();

   #pragma GCC diagnostic pop
}


void CWatchdog::init()
{
   HAL_StatusTypeDef status __attribute__ ( ( unused ) );


   // Dont start the watchdog if there is any debug info
   #if defined NDEBUG
      status=HAL_OK; //
   #else
      status=HAL_OK;
   #endif

   #if defined (STM32F4) || defined (STM32L1) || defined (STM32F3) || defined (STM32F0) || defined (STM32F1)
      //Init starts Watchdog
      eWatchdogState=eWatchdogStateStarted;
   #endif

   bDebugAssert( status == HAL_OK, status );

   return;
}


void CWatchdog::start()
{
   #if defined NDEBUG
   // This init also calls the "__HAL_IWDG_START"
   HAL_IWDG_Init(m_pHandler);
   #endif

    #if defined (STM32F4) || defined (STM32L1) || defined (STM32F3) \
            || defined (STM32F0) || defined (STM32F1) || defined (STM32L0) \
            || defined (STM32L4) || defined (STM32G0) || defined (STM32G4)
	// stm32f4/stm32l1 has no start function? Init starts Watchdog
	// There is an "__HAL_IWDG_START" makro but it gets executed in HAL_IWDG_Init()
    #else
       HAL_IWDG_Start(m_pHandler);
    #endif
   eWatchdogState=eWatchdogStateStarted;

   return;
}


void CWatchdog::stop()
{
   // No Idea how to stop watchdog
   //HAL_IWDG_Init()
   // "Cant stop watchdog"
   exception( );
   eWatchdogState=eWatchdogStateStopped;
   return;
}


void CWatchdog::trigger()
{
   //HAL_StatusTypeDef
   //assert( HAL_IWDG_Refresh(pHandler, WDG_COUNTER) == HAL_OK );
   //if( HAL_IWDG_GetState(pHandler) == HAL_IWDG_STATE_TIMEOUT )

   // if(0)
   //if(( READ_REG(pHandler->Instance->CR) & (uint32_t)IWDG_CR_T ) < WDG_WINDOW)
   // if( HAL_IWDG_GetState(pHandler) == HAL_IWDG_STATE_READY )
   //if( HAL_IWDG_Refresh(pHandler, WDG_COUNTER) != HAL_OK )
   if( eWatchdogState == eWatchdogStateStarted )
      if( HAL_IWDG_Refresh(m_pHandler ) != HAL_OK )
      {
         //HAL_IWDG_DeInit(pHandler);
         // "Could not refresh"
         exception( );
      }

   return;
}


#if defined ( STM32F072xB ) || defined ( STM32F407xx ) || defined ( STM32F3 ) || defined ( STM32F1 )


#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"

IRQ_Funcion_imp( WWDG_IRQHandler )
{
   // Well, lets die together
   exception();
}

#pragma GCC diagnostic pop

#endif // ? STM32F0 ...

//---fin-----------------------------------------------------------------------
