//-----------------------------------------------------------------------------
///
/// \brief  Biwak general functions
///
///         blablablub
///
/// \date   20121107
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


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


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

#include <biwak/log_private.h>      // call eventLoop
#include <biwak/heartbeat.hpp>
#include <biwak/iostream.h>
#include <biwak/nvic.h>
#include <biwak/systick.h>
#include <biwak/dataEvent.h>

#if defined ( MCU_PLATFORM_STM32 )
   #include <HALWrapper/stm32_hal.h>
   // #include <HALWrapper/stm32xx_system_sup.h>
#endif


//---Defines-------------------------------------------------------------------


#define STACK_BARRIER_CODE 0xDEADBEEF


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


extern uint32_t __heap_end;
uint32_t &stackBarrier=__heap_end;

#if IS_ENABLED( CONFIG_BIWAK_RESETCOUNTER )
uint32_t &resetCounterVar=*(&__heap_end-1);
#endif

extern "C" {
   void SystemClock_Config( );
}

void biwakInitClock( )
{
#if defined ( MCU_PLATFORM_STM32 )

   #if defined STM32F0
      // NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
      //SCB->VTOR = (int)&CURRENT_FLASH; /* Vector Table Relocation in Internal FLASH. */
      // ARM-M0 has no VTOR register. Changing Vector table can only be done
      // via "SYSMEMREMAP". Not tested yet.
   #else
      // SCB->VTOR = (int)&FLASH_CURRENT; /* Vector Table Relocation in Internal FLASH. */
   #endif

   HAL_Init();
      
   // Not calling these two function may lead to non-working UART on some boards.
   // But wastes a lot of RAM
   SystemClock_Config( );

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

   __HAL_RCC_SYSCFG_CLK_ENABLE();
   __HAL_RCC_PWR_CLK_ENABLE();

   #pragma GCC diagnostic pop

   initSystick();
}


void biwakInitMisc( )
{
   #if defined( STM32L0) || defined ( STM32L1 )
      HAL_PWREx_EnableUltraLowPower();
      HAL_PWREx_EnableFastWakeUp();

      // Allowing debugging in standard mode pulls/pushes some JTAG pins up/down.
      HAL_DBGMCU_DisableDBGStandbyMode();
      //__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

      /*while(__HAL_PWR_GET_FLAG(PWR_FLAG_REGLP) == RESET){
         HAL_Delay(1);
      }
      */
   #elif defined ( STM32L4 )
      HAL_PWREx_EnableLowPowerRunMode();
   #endif
   setvbuf(stdin, NULL, _IONBF, 0);
   setvbuf(stdout, NULL, _IONBF, 0);
   setvbuf(stderr, NULL, _IONBF, 0);

#endif // ? MCU_PLATFORM_STM32
   
   stackBarrier = STACK_BARRIER_CODE;
   
   #if IS_ENABLED( CONFIG_BIWAK_RESETCOUNTER )
   if( ( resetCounterVar & 0xFFFFFF00 ) != 0xDEADBE00 )
   {
      clearResetCounter();
   }
   resetCounterVar++;
   #endif
   
   return;
}

#if IS_ENABLED( CONFIG_BIWAK_RESETCOUNTER )

int resetCounter()
{
   return( resetCounterVar & 0xFF );
}
void clearResetCounter()
{
   resetCounterVar = 0xDEADBE00;
}
#endif

// Would be possible to call this automatically:
//          void biwakInit() __attribute__ ((constructor (101)));
// But the qt version creates an QApplication and an GUI. Is nasty to do this
// before of main.
void biwakInit()
{
   biwakInitClock();
   biwakInitMisc();
}


void biwakInitNoClock()
{
   // Avoiding initializing clocks does not work at all.
   biwakInitClock();
   biwakInitMisc();
}


void biwakDeInit()
{
   SysTick->CTRL = 0;
   setNVInterrupt(SysTick_IRQn , false, NVI_DEFAULT_PRIORITY);

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

   __HAL_RCC_SYSCFG_CLK_DISABLE();

   #pragma GCC diagnostic pop

   return;
}


void biwakEventLoop()
{
   logEventLoop();
      
   #if IS_ENABLED( CONFIG_BIWAK_DATA_EVENT )
      //biwakDataAvailable=0;
   #endif
   
   if( stackBarrier!=STACK_BARRIER_CODE)
   {
      abort();
   }
   return;
}

void systemReset()
{
   NVIC_SystemReset();
}


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