#ifndef _TIMER_H_
#define _TIMER_H_
//----------------------------------------------------------------------------
///
/// \brief  Timer unit
///
///         See implementation files for further information.
//
/// \date   20121117
/// \author Maximilian Seesslen <development@seesslen.net>
///
//----------------------------------------------------------------------------


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


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

#include <biwak/biwak.h>
#include <biwak/timer_calc.h>
#include <biwak/systick.h>          // Makros
#include <sys/types.h>                  // useconds_t


//---Forward declarations-----------------------------------------------------


#if defined (MCU_PLATFORM_STM32)
   #define TIM_HANDLE_TYPE    TIM_HandleTypeDef
   #include <HALWrapper/stm32_dma.h>       // tim needs that
   #include <HALWrapper/stm32_tim.h>
   #include <biwak/gpio.hpp>          // EAltFunc
#else
   #define TIM_HANDLE_TYPE    void
   enum EAltFunc
   {

   };
   #define     TIM_CHANNEL_1     1
   #define     TIM_CHANNEL_2     2
   #define     TIM_CHANNEL_3     3
   #define     TIM_CHANNEL_4     4
#endif


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


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


enum ETimerMode
{
   //eTimerModeRepetitive,
   //eTimerModeSingle
   eTimerModeStandard,
   eTimerModePWM,
   eTimerModeDAC,
   eTimerModeOC
};

enum ETimerChannel
{
   //eTimerModeRepetitive,
   //eTimerModeSingle
//   [eTimerChannelNone]=TIM_CHANNEL_1,
//   [eTimerChannel1]=TIM_CHANNEL_1,
//   [eTimerChannel2]=TIM_CHANNEL_2,
//   [eTimerChannel3]=TIM_CHANNEL_3,
//   [eTimerChannel4]=TIM_CHANNEL_4,

   eTimerChannelNone=TIM_CHANNEL_1,
   eTimerChannel1=TIM_CHANNEL_1,
   eTimerChannel2=TIM_CHANNEL_2,
   eTimerChannel3=TIM_CHANNEL_3,
   eTimerChannel4=TIM_CHANNEL_4,
};

class CDmaChannel;
//enum EAltFunc;

struct STimerConfig;
class CTimerDimpl;


class CTimer
{

   private:
      #if ! defined( STM32 )
         CTimerDimpl *m_pDimpl;
      #endif
         
      const STimerConfig &m_configData;
      TIM_HANDLE_TYPE *m_pHandler;
      ETimerMode eTimerMode;

   public:
      //unsigned int         m_prescaler;
      //unsigned int         m_period;
      //frequency_t          m_frequency;

      CTimer( const STimerConfig &_configData );
      CTimer( const STimerConfig &_configData
              , int prescaler, int period, ETimerMode _eTimerMode);
      CTimer( const STimerConfig &_configData
              , frequency_t frequency, ETimerMode _eTimerMode);
      CTimer( const CTimer& that ) = delete;
      void init();
      // void reinit( int prescaler, int period );

      ~CTimer()
      { };
      TIM_HANDLE_TYPE *getHandler()
      {
         return(m_pHandler);
      }

      void setMasterConfig();
      //uint32_t getRemain();
      //volatile uint32_t getCounter();
      void setOutputChannel( ETimerChannel eTimerChannel, int permili=500 );
      // int initDelay();
      uint32_t getRemaining();
      uint32_t getRemainingUsec();
      #if defined STM32
      unsigned int getPeriod() const
      {
         return( m_pHandler->Init.Period + 1 );
      }
      unsigned int getPrescaler() const
      {
         return( m_pHandler->Init.Prescaler + 1 );
      }
      #else
      unsigned int getPeriod()
      {
         return( 1 );
      }
      #endif
      void setEnable(bool value);
      void setMode(ETimerMode _eTimerMode)
      {
         eTimerMode=_eTimerMode;
         init();
      };

      void calculateValuesByFrequency(frequency_t frequency);
      //void calculateValuesByUSec(int usec);
      frequency_t calculateFrequencyByValues() const;
#if 1
      frequency_t getFrequency() const
      {
         return( calculateFrequencyByValues() );
         //return m_frequency;
      }
#endif

#if 0
      void calculateTicksPerUsecByFrequency()
      {
         m_hrtPerUsec=m_period      / ( (frequency_t)_1MHZ / getFrequency() );
         m_lrtPerMsec=MSECS_PER_SEC / ( (frequency_t)_1MHZ / getFrequency() );
         m_usecPerHrt=( (frequency_t)_1MHZ / getFrequency() ) / m_period;
         //m_secPerLrt=( (frequency_t)_1MHZ / getFrequency() );
      }

      hrtimer_t getHrtPerUsec()
      {
         return m_hrtPerUsec;
      }
      hrtimer_t getLrtPerMsec()
      {
         return m_lrtPerMsec;
      }

      hrtimer_t hrtToUsec(hrtimer_t hrt)
      {
         return(hrt/m_hrtPerUsec);
      }

      hrtimer_t getUsecPerHrt()
      {
         return m_usecPerHrt;
      }
#endif
      void updateFrequency(frequency_t frequency);
      void updateFrequency(int prescaler, int period);
      void rupdateFrequency(frequency_t frequency);
      void rupdatePulse(int permilli);
      void setHRT();
      void stop();
      void start();
      void startNoInt();
      int startTimerPwm(ETimerChannel eTimerChannel);
      void startDmaPwm(ETimerChannel channel, const uint32_t *buffer, int size);
      void stopPwm(ETimerChannel channel);
      void setDmaChannel(CDmaChannel *dmaChannel );
      void interrupt();
};


extern "C"
{
   int usleep(useconds_t usecDelayValue);
   void sleepMode();
   void standyMode();
   void stopMode();
}

hrtimer_t hrNow();
lrtimer_t lrNow();
lrtimer_t lrStart();
void stDelay(uint32_t stDelayValue);

bool elapsed(hrtimer_t *pStartValue, int32_t usecDelayValue);

int hrElapsedMSeconds(hrtimer_t pStartValue);
int elapsedUSeconds(hrtimer_t startValue);
int elapsedUSeconds(hrtimer_t startValue, hrtimer_t endValue);

hrtimer_t msecToHrtValue( int mseconds );
hrtimer_t usecToHrtValue( int useconds );

int lrElapsed(lrtimer_t startValue);
bool lrElapsedMSeconds(lrtimer_t *pStartValue, int32_t msecDelayValue);
//int elapsedSeconds(hrtimer_t startValue);
int lrElapsedSeconds(lrtimer_t startValue);
int lrElapsedMSeconds(lrtimer_t startValue);
lrtimer_t msecondsToHrt(int mseconds);
bool lrElapsedSeconds(lrtimer_t *pStartValue, int32_t secDelayValue);
int lrTill(lrtimer_t *pStartValue, int32_t msecDelayValue);

void mseconds2time(int in_msec, int &hour, int &min, int &sec, int &msec);


//---fin----------------------------------------------------------------------
#endif // ? ! _TIMER_H_
