//----------------------------------------------------------------------------
///
/// \file   platform.cpp
///
/// \brief  The whole SOC
///
/// \date   20121111
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Documentation------------------------------------------------------------


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


//---General--------------------------

#include <stddef.h>
#include <stdlib.h>     /* malloc, free, rand */
#include <errno.h>     /* malloc, free, rand */
#include <math.h>                // Sqrt, getFactors()

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

#include <biwak/config.h>
#include <biwak/rcc.h>
#include <biwak/platform.h>
#include <biwak/led.h>
#include <biwak/handler.h>       // extiHandler
#include <biwak/lltools.h>       // setRcc
#include <biwak/button.h>
#include <biwak/can.h>
#include <biwak/uart.h>
#include <biwak/timer.h>
#include <biwak/temp_tsic.h>
#include <biwak/adc.h>
#include <biwak/irinput.h>
#include <biwak/pwm.h>
#include <biwak/qjtimer.h>
#include <biwak/eadisplay.h>

#include <lepto/log.h>

#include <stm/stm32_rcc.h>
#include <stm/stm32_can.h>


//---Declaration--------------------------------------------------------------


//#define SYSTICK_DIVIDER    0x100000     //0x20 in Tsic
//#define SYSTICK_DIVIDER    0x40000     //0x20 in Tsic
//#define SYSTICK_DIVIDER    0x1000       //0x0
#define SYSTICK_DIVIDER      0x100

#ifdef HAVE_STATIC_PLATFORM
    CPlatform platform;
#else
    CPlatform *pplatform=nullptr;
#endif


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


extern CTimer *m_hrTicker=0;


void platformExtiHandler(int line, void *data)
{
   lHint << "Line: " << line << " Value: " << p.button[0].getValue();
   lHint << (p.button[0].getValue()?"Button pressed ":"Button released");
   if(p.button[0].getValue())
   {
      p.led[1].switchOn();
      p.output[0].switchOn();
   }
   else
   {
      p.led[1].switchOff();
      p.output[0].switchOff();
   }
}


void temperatureExtiHandler(int line, void *data)
{
   lHint << "Temp";
}

//int mhzDivider=32;
// Problem: 0xC00: Zero values
// >0x186 <0x187
// 0x186 perfect value: gives prescaler=1; period=0x7FF8
//int mhzDivider=0xFFF;
//int mhzDivider=0x186;
int mhzDivider=100;


CPlatform::CPlatform()
   //:m_hrTicker(0)
{
   SystemCoreClockUpdate();

   /*
   RCC_HSEConfig(RCC_HSE_ON);
   while(!RCC_WaitForHSEStartUp())
   {
   }
   */
    
   setupRcc();
   setupGpio();

   SysTick_Config(SystemCoreClock/ SYSTICK_DIVIDER );
   // Its an exception, so that may be the reason SysTick_IRQn will not be
   // called when already in an ISR

   //setNVInterrupt(SysTick_IRQn, true, NVI_HIGH_PRIORITY );

   led=new CLed[5] {
         /*[eLedGreen]    =*/ CLed(eGpioPeripheralD, eGpioPin12),  //Green LD4
         /*[eLedOrange]   =*/ CLed(eGpioPeripheralD, eGpioPin13),  //orange
         /*[eLedRed]      =*/ CLed(eGpioPeripheralD, eGpioPin14),  //red LED on Discovery-Board
         /*[eLedBlue]     =*/ CLed(eGpioPeripheralD, eGpioPin15),  //blue
         /*[eLedExtern]   =*/ CLed(eGpioPeripheralD, eGpioPin6),   // PD6
   };

   led[eLedBlue].switchOn();

   output=new COutput[7] {
         COutput(eGpioPeripheralD, eGpioPin11),
         COutput(eGpioPeripheralB, eGpioPin0),
         COutput(eGpioPeripheralB, eGpioPin1),
         COutput(eGpioPeripheralB, eGpioPin2),
         COutput(eGpioPeripheralB, eGpioPin4),
         COutput(eGpioPeripheralB, eGpioPin5),
         COutput(eGpioPeripheralB, eGpioPin7),
   };

   #ifdef STM32_USE_CAN
   can=new CCan[1] {
         CCan( eCan1 ),
         //CCan( 1 ),
   };
   #endif

   //can[1].init( 1 );
   uart=new CUart[3] {
         CUart( eUsart1 ),
         CUart( eUsart2 ),       //USART2 not used yet.
         CUart( eUsart3 ),
         //CUart( NULL ),
   };

   // Direct Inputs
   input=new CInput[2] {
           //CInput(GPIOD, GPIO_Pin_3, 3),
           CInput(eGpioPeripheralD, eGpioPin7),
           CInput(eGpioPeripheralD, eGpioPin4, eGpioTypeInput),
           //CInput(GPIOD, GPIO_Pin_7, 7, eGpioTypeInput),
           //CInput(GPIOD, GPIO_Pin_1, 1, eGpioTypeInput),
    };

   #ifdef STM32_USE_RTC
   irInput=new CIrInput[1] {
          CIrInput(eGpioPeripheralD, eGpioPin7)
   };
   #endif

   #ifdef STM32_USE_RTC
   rtc=new CRtc[1] { CRtc() };
   #endif


   #ifdef STM32_USE_TEMP_SIC
   // Pin PD3 on Discovery-Board
   tempTsic=new CTempTsic[1] { CTempTsic(eGpioPeripheralD, eGpioPin3) };
   #endif


   // Discovery User-Pushbutton: PA0
   button= new CButton[2] {
         CButton(eGpioPeripheralA, eGpioPin0),
         CButton(eGpioPeripheralA, eGpioPin1),
   };

   interrupt=new CInterrupt[1] {
         CInterrupt(eInterruptTest, 0),
   };

   #ifdef STM32_USE_TIMER
   timer= new CTimer[1] {
         //CTimer(eTimer3, 1, 0x10000),
         //CTimer(eTimer3, 0x100, 0x100), // WOrks
         CTimer(eTimer3, (float)(_1MHZ)/(float)mhzDivider),
   };
   m_hrTicker=&timer[0];
   m_hrTicker->setHRT();
   #endif

   //hrtPerUsec=0x1234;

   #ifdef STM32_USE_QJTIMER
   qjtimer= new CQJTimer[1] {
         CQJTimer(eTimer4),
   };
   #endif

   #ifdef STM32_USE_ADC
   adc=new CAdc[1] {
         CAdc( ADC1 ),
   };
   #endif

   pwm=NULL;
   /*new CPwm[1] {
         CPwm(eGpioPeripheralA, eGpioPin15, eTimer2),
   };
   */

   // input pin for blink led
   //extiHandlerData[0]=0;
   //extiHandler[0]=&platformExtiHandler;

   //extiHandlerData[3]=0;
   //extiHandler[3]=&temperatureExtiHandler;
   led[eLedBlue].switchOn();

   
   //CAN_Config();
   /*
   CAN_driver_init(BAUD_125KBIT);
   CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
   lHint << "Can initialized";
    */

#if defined STM32F0
   // No CAN=???
#elif defined STM32F4
   setNVInterrupt(CAN1_RX0_IRQn);
   setNVInterrupt(CAN1_RX1_IRQn);
   setNVInterrupt(CAN1_SCE_IRQn);
   setNVInterrupt(CAN1_TX_IRQn);
#elif defined STM32F4
   setNVInterrupt(CAN1_RX0_IRQn);
   setNVInterrupt(CAN1_RX1_IRQn);
   setNVInterrupt(CAN1_SCE_IRQn);
   setNVInterrupt(CAN1_TX_IRQn);
#endif

   COutput *array3[4] {&output[1], &output[2], &output[3], &output[4]};

   #ifdef STM32_USE_EADISPLAY
   display=new CEaDisplay[1] {
         CEaDisplay(
                  array3,
                  output[5], output[6]
         ),
   };
   #endif


   return;
}


void CPlatform::printInfo()
{
   // RCC_ClocksTypeDef     RCC_Clocks;
   // RCC_GetClocksFreq(&RCC_Clocks);

   //lHint hangs!

   lHint << eLogBaseDec << "SYS Clock : " << (int)HAL_RCC_GetSysClockFreq();
   lHint << eLogBaseDec << " H Clock  : "  << (int)HAL_RCC_GetSysClockFreq();

   lHint << eLogBaseDec << "APB1/PCLK1: " <<  (int)HAL_RCC_GetPCLK1Freq();
   lHint << eLogBaseDec << "APB2/PCLK2: " <<  (int)HAL_RCC_GetPCLK1Freq();
   
   lHint << eLogBaseDec << "HSE       : " << (int)HSE_VALUE;
   //lHint << eLogBaseDec << "HSI       : " << (int)HSI_VALUE;
   lHint << eLogBaseDec << "SysCrClk  : " << (int)SystemCoreClock;
   
}


/*
int CPlatform::getHRTimer()
{
   int hrTickerValue=0;

   if(m_hrTicker)
      hrTickerValue=m_hrTicker->getHRTimer();
   else
      hrTickerValue=getSystemTicker();

   return (hrTickerValue);
}
*/


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