//-----------------------------------------------------------------------------
///
/// \brief  Class for RCC
///
/// \date   20150110
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


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


#include <biwak/biwak.h>      // exception
#include <biwak/rcc.h>
#include <HALWrapper/stm32.h>
#include <biwak/exception.h>

#include <HALWrapper/stm32.h>
#include <HALWrapper/stm32_rcc.h>
#include <HALWrapper/stm32_flash.h>

// STM32F0 still on legacy
#ifndef __HAL_RCC_GPIOA_CLK_ENABLE
   #define __HAL_RCC_GPIOA_CLK_ENABLE __GPIOA_CLK_ENABLE
   #define __HAL_RCC_GPIOB_CLK_ENABLE __GPIOB_CLK_ENABLE
   #define __HAL_RCC_GPIOC_CLK_ENABLE __GPIOC_CLK_ENABLE
   #define __HAL_RCC_GPIOD_CLK_ENABLE __GPIOD_CLK_ENABLE
   #define __HAL_RCC_TIM1_CLK_ENABLE __TIM1_CLK_ENABLE
   #define __HAL_RCC_TIM2_CLK_ENABLE __TIM2_CLK_ENABLE
   #define __HAL_RCC_TIM3_CLK_ENABLE __TIM3_CLK_ENABLE
   #define __HAL_RCC_TIM4_CLK_ENABLE __TIM4_CLK_ENABLE
   #define __HAL_RCC_TIM5_CLK_ENABLE __TIM5_CLK_ENABLE
   #define __HAL_RCC_TIM6_CLK_ENABLE __TIM6_CLK_ENABLE
   #define __HAL_RCC_TIM7_CLK_ENABLE __TIM7_CLK_ENABLE

   #define __HAL_RCC_ADC1_CLK_ENABLE __ADC1_CLK_ENABLE
   #define __HAL_RCC_ADC2_CLK_ENABLE __ADC2_CLK_ENABLE

   #ifdef __DAC1_CLK_ENABLE
      #define __HAL_RCC_DAC1_CLK_ENABLE __DAC1_CLK_ENABLE
   #else
      #define __HAL_RCC_DAC_CLK_ENABLE __DAC_CLK_ENABLE
   #endif

   #ifdef __DMA1_CLK_ENABLE
      #define __HAL_RCC_DMA1_CLK_ENABLE __DMA1_CLK_ENABLE
   #else
      #define __HAL_RCC_DMA_CLK_ENABLE __DMA_CLK_ENABLE
   #endif

   // #define __HAL_RCC_DAC_CLK_ENABLE __DAC_CLK_ENABLE
#if 0
   #ifdef __CAN1_CLK_ENABLE
      #define __HAL_RCC_CAN1_CLK_ENABLE __CAN1_CLK_ENABLE
   #else
      #define __HAL_RCC_CAN_CLK_ENABLE __CAN_CLK_ENABLE
   #endif
#endif
   //#define __HAL_RCC_RTC_CLK_ENABLE __RTC_CLK_ENABLE

   #define __HAL_RCC_SPI1_CLK_ENABLE __SPI1_CLK_ENABLE
   #define __HAL_RCC_LEGACY

#endif


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


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


void rccGpioClockEnable(void *GPIOx)
{  
   switch( reinterpret_cast<intptr_t>(GPIOx) )
   {
      case( GPIOA_BASE ):
         __HAL_RCC_GPIOA_CLK_ENABLE();
         break;
      case( GPIOB_BASE ):
         __HAL_RCC_GPIOB_CLK_ENABLE();
         break;
      case( GPIOC_BASE ):
         __HAL_RCC_GPIOC_CLK_ENABLE();
         break;
      #if defined( GPIOD_BASE )
      case( GPIOD_BASE ):
         __HAL_RCC_GPIOD_CLK_ENABLE();
         break;
      #endif
      #ifdef STM32F4
      case( GPIOE_BASE ):
         __HAL_RCC_GPIOE_CLK_ENABLE();
         break;
      #endif
      #if defined( GPIOF_BASE )
      case( GPIOF_BASE ):
         __HAL_RCC_GPIOF_CLK_ENABLE();
         break;
      #endif
      default:
         // "unknown GPIO_TypeDef"
         exception( );
         break;
   }
}


void rccUsartClockEnable(void *UARTx)
{
   switch((int)UARTx)
   {
      #if defined( USART1_BASE )
      case( USART1_BASE ):
         __HAL_RCC_USART1_CLK_ENABLE();
         break;
      #endif
      case( USART2_BASE ):
         __HAL_RCC_USART2_CLK_ENABLE();
         break;
      #if defined( USART3_BASE )
      case( USART3_BASE ):
         __HAL_RCC_USART3_CLK_ENABLE();
         break;
      #endif
      default:
         // "unknown Usart_TypeDef"
         exception( );
         break;
   }
}


void rccUsbClockEnable(void *USBx)
{
   #if defined (STM32F303x8) // STM32F303 has not USB support
      // STM32F303x8 has no USB support
      exception( );
   #else
      switch((int)USBx)
      {
         #if defined( USB_OTG_FS_PERIPH_BASE )
         case( USB_OTG_FS_PERIPH_BASE ):
            __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
            break;
         #endif
         #if defined ( USB_BASE )
         case( USB_BASE ):
            __HAL_RCC_USB_CLK_ENABLE();
            break;
         #endif
         default:
            // "unknown USB_TypeDef"
            exception( );
            break;
      }
   #endif  // ? ! STM32F303x8
}


void rccTimClockEnable(/*TIM_TypeDef*/ void *TIMx)
{
   switch((int)TIMx)
   {
      #if defined( TIM1_BASE )
      case( TIM1_BASE ):
         __HAL_RCC_TIM1_CLK_ENABLE();
         break;
      #endif
      #if defined( TIM2_BASE )
      case( TIM2_BASE ):
         __HAL_RCC_TIM2_CLK_ENABLE();
         break;
      #endif
      #if defined( TIM3_BASE )
      case( TIM3_BASE ):
         __HAL_RCC_TIM3_CLK_ENABLE();
         break;
      #endif

      //#if defined(STM32F3) || defined(STM32F4) || defined(STM32L1)
      // STM32F0 does not have an TIM4 and TIM5
      #ifdef TIM4
      case( TIM4_BASE ):
         __HAL_RCC_TIM4_CLK_ENABLE();
         break;
      #endif
      #ifdef TIM5
      case( TIM5_BASE ):
         __HAL_RCC_TIM5_CLK_ENABLE();
         break;
      #endif

      //#if defined(STM32F0) || defined(STM32F3) || defined(STM32F4) || defined(STM32L1)
      #ifdef TIM6
      case( TIM6_BASE ):
         __HAL_RCC_TIM6_CLK_ENABLE();
         break;
      #endif
      #ifdef TIM7
      case( TIM7_BASE ):
         __HAL_RCC_TIM7_CLK_ENABLE();
         break;
      #endif
      #ifdef TIM8
      case( TIM8_BASE ):
         __HAL_RCC_TIM8_CLK_ENABLE();
         break;
      #endif
      #ifdef TIM14
      case( TIM14_BASE ):
         __HAL_RCC_TIM14_CLK_ENABLE();
         break;
      #endif
      #ifdef TIM15
      case( TIM15_BASE ):
         __HAL_RCC_TIM15_CLK_ENABLE();
         break;
      #endif

      default:
         // "unknown TIM_TypeDef"
         exception( );
         break;
   }
}


void rccDacClockEnable(/*DAC_TypeDef*/ void *DACx)
{
   switch((int)DACx)
   {
//#if defined(__HAL_RCC_DAC_CLK_ENABLE) || defined(__HAL_RCC_LEGACY)
      #if defined(DAC1_BASE)
      case( DAC1_BASE ):
            #ifdef __HAL_RCC_DAC_CLK_ENABLE
               __HAL_RCC_DAC_CLK_ENABLE();
            #else
               __HAL_RCC_DAC1_CLK_ENABLE();
            #endif
            break;
      #else

      #if defined( DAC_BASE )
      case( (int)DAC_BASE ):
            #ifdef __HAL_RCC_DAC_CLK_ENABLE
               __HAL_RCC_DAC_CLK_ENABLE();
            #else
               __HAL_RCC_DAC1_CLK_ENABLE();
            #endif
            while(1)
            {
               asm("nop;\n");
            };

         break;
      #endif

      #endif
      default:
         // "unknown DAC_TypeDef"
         exception( );
         break;
   }

}


void rccAdcClockEnable(/*DAC_TypeDef*/ void *ADCx)
{
   switch((int)ADCx)
   {
      case( ADC1_BASE ):
         #if defined ( __HAL_RCC_ADC_CLK_ENABLE )
               __HAL_RCC_ADC_CLK_ENABLE();
         #else
            #if defined ( __HAL_RCC_ADC12_CLK_ENABLE )
               __HAL_RCC_ADC12_CLK_ENABLE();
            #else
               __HAL_RCC_ADC1_CLK_ENABLE();
            #endif
         #endif
         break;
      #if defined( ADC2_BASE )
      case( ADC2_BASE ):
         #if defined ( __HAL_RCC_ADC12_CLK_ENABLE )
            __HAL_RCC_ADC12_CLK_ENABLE();
         #else
            __HAL_RCC_ADC2_CLK_ENABLE();
         #endif
         break;
      #endif
      default:
         // "unknown ADC_TypeDef"
         exception( );
         break;
   }

}


void rccDmaClockEnable(/*DMA_TypeDef*/ void *DMAx)
{
   switch((int)DMAx)
   {
      case( DMA1_BASE ):
         __HAL_RCC_DMA1_CLK_ENABLE();
         break;
      default:
         // "unknown DMA_TypeDef"
         exception( );
         break;
   }
}


void rccCanClockEnable(/*CAN_TypeDef*/ void *CANx)
{
   switch((int)CANx)
   {
#if defined(CAN)
      #if defined(STM32L4)
      case( CAN1_BASE ):
      #else
      case( CAN_BASE ):
      #endif
            #if defined (STM32F3)
            __HAL_RCC_CAN1_CLK_ENABLE();
            #else
            __HAL_RCC_CAN1_CLK_ENABLE();
            #endif
         break;
#elif defined(CAN1)
      case( CAN1_BASE ):
         __HAL_RCC_CAN1_CLK_ENABLE();
         break;
#elif defined( FDCAN1_BASE )
      case( FDCAN1_BASE ):
         __HAL_RCC_FDCAN_CLK_ENABLE();
         break;
#endif
      default:
         // "unknown CAN_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccCrcClockEnable(/*CRC_TypeDef*/ void *CRCx)
{
   switch((int)CRCx)
   {
#if defined(CRC)
      case( CRC_BASE ):
         __HAL_RCC_CRC_CLK_ENABLE();
         break;
#endif
      default:
         // "unknown CRC_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccFDCanClockEnable(/*CAN_TypeDef*/ void *FDCANx)
{
   switch((int)FDCANx)
   {
#if defined(FDCAN1)
      case( FDCAN1_BASE ):
         __HAL_RCC_FDCAN_CLK_ENABLE();
         break;
#endif
      default:
         // "unknown FDCan_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccSpiClockEnable(/*SPI_TypeDef*/ void *SPIx)
{
   switch((int)SPIx)
   {
      case( SPI1_BASE ):
         //__SPI1_CLK_ENABLE();
         __HAL_RCC_SPI1_CLK_ENABLE();
         break;
      #if defined ( SPI2_BASE ) && ! defined(STM32F0)
      case( SPI2_BASE ):
         __HAL_RCC_SPI2_CLK_ENABLE();
         break;
      #endif
      #ifdef SPI3_BASE
      case( SPI3_BASE ):
         __SPI3_CLK_ENABLE();
         break;
      #endif
      default:
         // "unknown SPI_TypeDef"
         exception( );
         break;
   }
}


void rccRtcClockEnable(/*RTC_TypeDef*/ void *RTCx)
{
   switch((int)RTCx)
   {
      case( RTC_BASE ):
         __HAL_RCC_RTC_ENABLE();
         #ifdef STM32F1
         __HAL_RCC_BKP_CLK_ENABLE();
         #endif
         break;
      default:
         // "unknown RTC_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccWatchdogClockEnable(/*IWDG_TypeDef*/ void *WDGx)
{
   switch((int)WDGx)
   {
      case( IWDG_BASE ):
         // IWDG must not be enabled?
         //__HAL_RCC_WWDG_CLK_ENABLE();
         break;
      default:
         // "unknown WWDG_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccI2cClockEnable(/*I2C_TypeDef*/ void *I2Cx)
{
   switch((int)I2Cx)
   {
      case( I2C1_BASE ):
         #if defined( __HAL_RCC_I2C1_CONFIG )
            __HAL_RCC_I2C1_CONFIG(RCC_I2C1CLKSOURCE_SYSCLK);
         #endif
         __HAL_RCC_I2C1_CLK_ENABLE();
         break;
      #if defined I2C2_BASE
      case( I2C2_BASE ):
         __HAL_RCC_I2C2_CLK_ENABLE();
         break;
      #endif
      default:
         // "unknown I2C_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccI2cClockDisable(/*I2C_TypeDef*/ void *I2Cx)
{
   switch((int)I2Cx)
   {
      case( I2C1_BASE ):
         __HAL_RCC_I2C1_CLK_DISABLE();
         break;
      default:
         // "unknown I2C_TypeDef"
         exception( );
         break;
   }

   return;
}

void rccTscClockEnable(/*I2C_TypeDef*/ void *TSCx)
{
   switch((int)TSCx)
   {
      #if defined( TSC_BASE )
      case( TSC_BASE ):
         __HAL_RCC_TSC_CLK_ENABLE();
         break;
      #endif
      default:
         // "unknown TSC_TypeDef"
         exception( );
         break;
   }

   return;
}


void rccQSpiClockEnable( void *QSPIx )
{
   switch((long unsigned int)QSPIx)
   {
      #if defined ( QSPI_BASE )
      case( QSPI_BASE ):
         __HAL_RCC_QSPI_CLK_ENABLE();
         break;
      #endif
      default:
         // unknown QSPI_TypeDef
         exception( );
         break;
   }
}


#pragma GCC diagnostic pop


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