

#include <sys/types.h>
#include <apci1710.h>

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

/** Convert the chrono value in time.
 *
 * Convert the chronometer measured timing (ul_ChronoValue) in to h, mn, s, ms, us, ns.
 *
 * @param [in] d_TimingInterval  This value is returned by ChronoComputeRealTiming.
 * @param [in] b_TimingUnit      Base timing unity used with ChronoComputeRealTiming.
 * @param [in] ul_ChronoValue    Measured chronometer timing value.

 * @param [out] pul_Hour         Chronometer timing hour
 * @param [out] pb_Minute        Chronometer timing minute
 * @param [out] pb_Second        Chronometer timing second
 * @param [out] pui_MilliSecond  Chronometer timing milli second
 * @param [out] pui_MicroSecond  Chronometer timing micro second
 * @param [out] pui_NanoSecond   Chronometer timing nano second
 */
void v_APCI1710_ConvertChronoValue    (double d_TimingInterval,
            uint8_t b_TimingUnit,
            uint32_t   ul_ChronoValue,
            uint32_t* pul_Hour,
            uint8_t*   pb_Minute,
            uint8_t*   pb_Second,
            uint32_t*  pui_MilliSecond,
            uint32_t*  pui_MicroSecond,
            uint32_t*  pui_NanoSecond)
    {
    double d_Hour;
    double d_Minute;
    double d_Second;
    double d_MilliSecond;
    double d_MicroSecond;
    double d_NanoSecond;

    /**************************/
    /* Test the module number */
    /**************************/


            d_Hour = (double) ul_ChronoValue * d_TimingInterval;

            switch (b_TimingUnit)
               {
               case 0:
                d_Hour = d_Hour / (double) 1000.0;

               case 1:
                d_Hour = d_Hour / (double) 1000.0;

               case 2:
                d_Hour = d_Hour / (double) 1000.0;

               case 3:
                d_Hour = d_Hour / (double) 60.0;

               case 4:
                /**********************/
                /* Calculate the hour */
                /**********************/

                d_Hour    = d_Hour / (double) 60.0;
                *pul_Hour = (uint32_t) d_Hour;

                /************************/
                /* Calculate the minute */
                /************************/

                d_Minute   = d_Hour - *pul_Hour;
                d_Minute   = d_Minute * 60;
                *pb_Minute = (uint8_t) d_Minute;

                /************************/
                /* Calculate the second */
                /************************/

                d_Second   = d_Minute - *pb_Minute;
                d_Second   = d_Second * 60;
                *pb_Second = (uint8_t) d_Second;

                /*****************************/
                /* Calculate the mini second */
                /*****************************/

                d_MilliSecond    = d_Second - *pb_Second;
                d_MilliSecond    = d_MilliSecond * 1000;
                *pui_MilliSecond = (uint32_t) d_MilliSecond;

                /******************************/
                /* Calculate the micro second */
                /******************************/

                d_MicroSecond    = d_MilliSecond - *pui_MilliSecond;
                d_MicroSecond    = d_MicroSecond * 1000;
                *pui_MicroSecond = (uint32_t) d_MicroSecond;

                /******************************/
                /* Calculate the micro second */
                /******************************/

                d_NanoSecond    = d_MicroSecond - *pui_MicroSecond;
                d_NanoSecond    = d_NanoSecond * 1000;
                *pui_NanoSecond = (uint32_t) d_NanoSecond;
                break;
               }

    }

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

/** Prepare the TimerValue for the kernel mode and return the real timer value.
 *
 * @param [in] b_TimingUnit            Base timing unity (0 to 4)<br>
 *                                     0 : ns<br>
 *                                     1 : us<br>
 *                                     2 : ms<br>
 *                                     3 : s<br>
 *                                     4 : mn
 *
 * @param [in] b_ClockSelection        Selection from PCI bus clock<br>
 *                                     - APCI1710_30MHZ :<br>
 *                                     The PC have a PCI bus<br>
 *                                     clock from 30 MHz<br>
 *                                     - APCI1710_33MHZ :<br>
 *                                     The PC have a PCI bus<br>
 *                                     clock from 33 MHz<br>
 *                                     - APCI1710_40MHZ<br>
 *                                     The APCI-1710 have a<br>
 *                                     integrated 40Mhz<br>
 *                                     quartz.
 *
 * @param [in] ul_TimingInterval       Base timing value.
 *
 * @param [out] pul_TimerValue         TimerValue for the kernel mode.
 * @param [out] pul_RealTimingInterval Real timer value (usingned long).
 * @param [out] pd_RealTimingInterval  Real timer value (double).
 */
void v_APCI1710_ChronoComputeRealTiming (uint8_t b_TimingUnit,
                uint8_t b_ClockSelection,
                uint32_t ul_TimingInterval,
                uint32_t* pul_TimerValue,
                uint32_t* pul_RealTimingInterval,
                double *pd_RealTimingInterval)
{
                /****************************************/
                /* Calculate the timer 0 division fator */
                /****************************************/

                switch (b_TimingUnit)
                   {
                   /******/
                   /* ns */
                   /******/

                   case 0:

                       /******************/
                       /* Timer 0 factor */
                       /******************/

                       *pul_TimerValue = (unsigned long) (ul_TimingInterval * (0.001 * b_ClockSelection));

                       /*******************/
                       /* Round the value */
                       /*******************/

                       if ((double) ((double) ul_TimingInterval * (0.001 * (double) b_ClockSelection)) >= ((double) ((double) *pul_TimerValue + 0.5)))
                          {
                          *pul_TimerValue = *pul_TimerValue + 1;
                          }

                       /*****************************/
                       /* Calculate the real timing */
                       /*****************************/

                       *pul_RealTimingInterval = (unsigned long) (*pul_TimerValue / (0.001 * (double) b_ClockSelection));
                       *pd_RealTimingInterval = (double) *pul_TimerValue / (0.001 * (double) b_ClockSelection);

                       if ((double) ((double) *pul_TimerValue / (0.001 * (double) b_ClockSelection)) >= (double) ((double) *pul_RealTimingInterval + 0.5))
                          {
                          *pul_RealTimingInterval = *pul_RealTimingInterval + 1;
                          }

                       ul_TimingInterval = ul_TimingInterval - 1;
                       *pul_TimerValue     = *pul_TimerValue - 2;
                       if (b_ClockSelection != APCI1710_40MHZ)
                          {
                          *pul_TimerValue     = (unsigned long) ((double) (*pul_TimerValue) * 0.99392);
                          }
                    break;

                   /******/
                   /* æs */
                   /******/

                   case 1:

                       /******************/
                       /* Timer 0 factor */
                       /******************/

                       *pul_TimerValue = (unsigned long) (ul_TimingInterval * (1.0 * b_ClockSelection));

                       /*******************/
                       /* Round the value */
                       /*******************/

                       if ((double) ((double) ul_TimingInterval * (1.0 * (double) b_ClockSelection)) >= ((double) ((double) *pul_TimerValue + 0.5)))
                          {
                          *pul_TimerValue = *pul_TimerValue + 1;
                          }

                       /*****************************/
                       /* Calculate the real timing */
                       /*****************************/

                       *pul_RealTimingInterval = (unsigned long) (*pul_TimerValue / (1.0 * (double) b_ClockSelection));
                       *pd_RealTimingInterval = (double) *pul_TimerValue / ((double) 1.0 * (double) b_ClockSelection);

                       if ((double) ((double) *pul_TimerValue / (1.0 * (double) b_ClockSelection)) >= (double) ((double) *pul_RealTimingInterval + 0.5))
                          {
                          *pul_RealTimingInterval = *pul_RealTimingInterval + 1;
                          }

                       ul_TimingInterval = ul_TimingInterval - 1;
                       *pul_TimerValue     = *pul_TimerValue - 2;
                       if (b_ClockSelection != APCI1710_40MHZ)
                          {
                          *pul_TimerValue     = (unsigned long) ((double) (*pul_TimerValue) * 0.99392);
                          }


                    break;

                   /******/
                   /* ms */
                   /******/

                   case 2:

                       /******************/
                       /* Timer 0 factor */
                       /******************/

                       *pul_TimerValue = ul_TimingInterval * (1000 * b_ClockSelection);

                       /*******************/
                       /* Round the value */
                       /*******************/

                       if ((double) ((double) ul_TimingInterval * (1000.0 * (double) b_ClockSelection)) >= ((double) ((double) *pul_TimerValue + 0.5)))
                          {
                          *pul_TimerValue = *pul_TimerValue + 1;
                          }

                       /*****************************/
                       /* Calculate the real timing */
                       /*****************************/

                       *pul_RealTimingInterval = (unsigned long) (*pul_TimerValue / (1000.0 * (double) b_ClockSelection));
                       *pd_RealTimingInterval = (double) *pul_TimerValue / (1000.0 * (double) b_ClockSelection);

                       if ((double) ((double) *pul_TimerValue / (1000.0 * (double) b_ClockSelection)) >= (double) ((double) *pul_RealTimingInterval + 0.5))
                          {
                          *pul_RealTimingInterval = *pul_RealTimingInterval + 1;
                          }

                       ul_TimingInterval = ul_TimingInterval - 1;
                       *pul_TimerValue     = *pul_TimerValue - 2;
                       if (b_ClockSelection != APCI1710_40MHZ)
                          {
                          *pul_TimerValue     = (unsigned long) ((double) (*pul_TimerValue) * 0.99392);
                          }

                    break;

                   /*****/
                   /* s */
                   /*****/

                   case 3:

                       /******************/
                       /* Timer 0 factor */
                       /******************/

                       *pul_TimerValue = (unsigned long) (ul_TimingInterval * (1000000.0 * b_ClockSelection));

                       /*******************/
                       /* Round the value */
                       /*******************/

                       if ((double) ((double) ul_TimingInterval * (1000000.0 * (double) b_ClockSelection)) >= ((double) ((double) *pul_TimerValue + 0.5)))
                          {
                          *pul_TimerValue = *pul_TimerValue + 1;
                          }

                       /*****************************/
                       /* Calculate the real timing */
                       /*****************************/

                       *pul_RealTimingInterval = (unsigned long) (*pul_TimerValue / (1000000.0 * (double) b_ClockSelection));
                       *pd_RealTimingInterval = (double) *pul_TimerValue / (1000000.0 * (double) b_ClockSelection);

                       if ((double) ((double) *pul_TimerValue / (1000000.0 * (double) b_ClockSelection)) >= (double) ((double) *pul_RealTimingInterval + 0.5))
                          {
                          *pul_RealTimingInterval = *pul_RealTimingInterval + 1;
                          }

                       ul_TimingInterval = ul_TimingInterval - 1;
                       *pul_TimerValue     = *pul_TimerValue - 2;
                       if (b_ClockSelection != APCI1710_40MHZ)
                          {
                          *pul_TimerValue     = (unsigned long) ((double) (*pul_TimerValue) * 0.99392);
                          }


                    break;

                   /******/
                   /* mn */
                   /******/

                   case 4:

                       /******************/
                       /* Timer 0 factor */
                       /******************/

                       *pul_TimerValue = (unsigned long) ((ul_TimingInterval * 60) * (1000000.0 * b_ClockSelection));

                       /*******************/
                       /* Round the value */
                       /*******************/

                       if ((double) ((double) (ul_TimingInterval * 60.0) * (1000000.0 * (double) b_ClockSelection)) >= ((double) ((double) *pul_TimerValue + 0.5)))
                          {
                          *pul_TimerValue = *pul_TimerValue + 1;
                          }

                       /*****************************/
                       /* Calculate the real timing */
                       /*****************************/

                       *pul_RealTimingInterval = (unsigned long) (*pul_TimerValue / (1000000.0 * (double) b_ClockSelection)) / 60;
                       *pd_RealTimingInterval = ((double) *pul_TimerValue / (0.001 * (double) b_ClockSelection)) / 60.0;

                       if ((double) (((double) *pul_TimerValue / (1000000.0 * (double) b_ClockSelection)) / 60.0) >= (double) ((double) *pul_RealTimingInterval + 0.5))
                          {
                          *pul_RealTimingInterval = *pul_RealTimingInterval + 1;
                          }

                       ul_TimingInterval = ul_TimingInterval - 1;
                       *pul_TimerValue     = *pul_TimerValue - 2;
                       if (b_ClockSelection != APCI1710_40MHZ)
                          {
                          *pul_TimerValue     = (unsigned long) ((double) (*pul_TimerValue) * 0.99392);
                          }


                    break;
                   }
}
