//-----------------------------------------------------------------------------
///
/// \brief  timer
///
/// \date   20151107
/// \author Maximilian Seesslen <development@seesslen.net>
///
//-----------------------------------------------------------------------------


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


#include <biwak/timer.hpp>
#include <unistd.h>             // usleep
#include <sys/time.h>               // gettimeofday
#include <biwak/linux/boardgui.h>
#include <biwak/linux/timer.hpp>
#include <QSpinBox>


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


class CTimerDimpl
{
   friend class CTimer;
   private:
      QSpinBox* m_spinBox=nullptr;
       
   public:
      CTimerDimpl(const char* label)
      {
         CBoardGui *gui=CBoardGui::instance();
         if(gui)
         {
            m_spinBox=gui->createTimer(label);
            m_spinBox->setMaximum(1000000);
         }
      }
};


CTimer::CTimer( const STimerConfig &_configData )
    :m_configData(_configData)
{
   m_pDimpl=new CTimerDimpl( m_configData.label );
}

void CTimer::init()
{

}

void CTimer::setMasterConfig()
{

}

void CTimer::setHRT()
{

}

void delay(hrtimer_t usecDelayValue)
{
   if(usecDelayValue<0)
      return;
   usleep(usecDelayValue);
}


int usleepNoData(useconds_t usecDelayValue)
{
   delay(usecDelayValue);
   return(0);
}


hrtimer_t getHRTUsec() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    return( (tv.tv_sec*(uint64_t)1000000) + tv.tv_usec) ;
}


bool elapsed(hrtimer_t *pUsecStartValue, hrtimer_t usecDelayValue)
{
    hrtimer_t nowValue;

    if( ( (nowValue=getHRTUsec()) - *pUsecStartValue) >= usecDelayValue )
    {
        *pUsecStartValue=nowValue;
        return true;
    }

    return false;
}

int32_t hrtValueToUsec(hrtimer_t hrtValue)
{
   return(hrtValue);
}

hrtimer_t msecToHrtValue(int mseconds)
{
   return( ( mseconds * USECS_PER_MSEC )  );
}

hrtimer_t usecToHrtValue(int useconds)
{
   return( useconds );
}

int32_t lrtValueToSec(lrtimer_t lrtValue)
{
   return( lrtValue / MSECS_PER_SEC );
}

/// \brief  Get high resolution timer on Linux
///
///         To keep it simple we directly use usecs
hrtimer_t getHrTimerValue( )
{
   struct timeval tv;
   gettimeofday(&tv,NULL);
   return( ((uint64_t)tv.tv_sec*(uint64_t)USECS_PER_SEC) + (uint64_t)tv.tv_usec);
}


/// \brief  Get low resolution timer on Linux
///
///         To keep it simple we directly use msecs
lrtimer_t getLrTimerValue()
{
   struct timeval tv;
   gettimeofday(&tv,NULL);
   return( ((uint64_t)tv.tv_sec*(uint64_t)MSECS_PER_SEC) + ( (uint64_t)tv.tv_usec / USECS_PER_MSEC ) );
}

int32_t lrtValueToMsec(lrtimer_t lrtValue)
{
   return ( lrtValue );
}

lrtimer_t msecToLrt( int msec )
{
   return ( (lrtimer_t)msec );
}

lrtimer_t secToLrt(int32_t sec)
{
   return( sec * MSECS_PER_SEC );
}
/*
void rDelay(hrtimer_t *pUsecStartValue, hrtimer_t usecDelayValue)
{
    hrtimer_t nowValue;
    hrtimer_t substract;
    nowValue=getHRTUsec();

    if(!*pUsecStartValue)
       *pUsecStartValue=nowValue;

    substract=nowValue - *pUsecStartValue;

    if( usecDelayValue > substract )
      usleep(usecDelayValue - substract );

    *pUsecStartValue=nowValue;

    return;
}
*/


/// \brief   relative delay to given start value
///
/// \return current high resolution timer value
void delay(hrtimer_t usecDelayValue, hrtimer_t startValue)
{
   hrtimer_t nowValue;
   hrtimer_t realUsecDelay;

   nowValue=getHrTimerValue();

   realUsecDelay= usecDelayValue - hrtValueToUsec( nowValue - startValue );

   delay(realUsecDelay);

   //nowValue=getHrTimerValue();
   // return( nowValue );
   return;
}


void CTimer::startDmaPwm(ETimerChannel, unsigned int const*, int)
{

}


void CTimer::setDmaChannel(CDmaChannel *dmaChannel )
{

}


void CTimer::updateFrequency(frequency_t frequency)
{
   if(m_pDimpl)
   {
        if( m_pDimpl->m_spinBox )
        {
           m_pDimpl->m_spinBox->setValue( frequency );
        }
   }

}

void CTimer::rupdateFrequency(frequency_t frequency)
{
   updateFrequency(frequency);
}

void CTimer::rupdatePulse(int permilli)
{

}

void CTimer::setOutputChannel(ETimerChannel eTimerChannel, int permilli /*=500*/)
{

}

int CTimer::startTimerPwm(ETimerChannel eTimerChannel)
{
   return(0);
}

frequency_t CTimer::calculateFrequencyByValues() const
{
   return( 10 );
}


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