
#ifndef TIMER_H_
#define TIMER_H_

/* Allowed values for TIMER_TIME_UNIT */
#define M_SECONDS (1)
#define U_SECONDS (2)

/* ------------------------------ Includes ---------------------------------- */
//#include "Global.h"
#include "Std_Types.h"
#include "DiagnosticR/_configurations/FicosarCfg.h"

/* ------------------------------ Constants --------------------------------- */

/* Allowed956 values for T_TIMER_TIME_SIZE */
#define T_TIMER_TIME_1_BYTE  (1)
#define T_TIMER_TIME_2_BYTE  (2)
#define T_TIMER_TIME_4_BYTE  (3)

/* Timer time max value definition */
#if(T_TIMER_TIME_SIZE == T_TIMER_TIME_1_BYTE)
#define T_TIMER_TIME_MAX_VALUE   ((UI_8)0xFF)
#elif(T_TIMER_TIME_SIZE == T_TIMER_TIME_2_BYTE)
#define T_TIMER_TIME_MAX_VALUE   ((UI_16)0xFFFF)
#elif(T_TIMER_TIME_SIZE == T_TIMER_TIME_4_BYTE)
#define T_TIMER_TIME_MAX_VALUE   ((UI_32)0xFFFFFFFF)
#else
#error "Size definition for t_timer_time is missing in FicosarCfg.h"
#endif

/* ------------------------------- Macros ---------------------------------- */

/*****************************************************************************
| Macro: TIMER_MS_TO_TIME
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts a time value in milliseconds to time in the units of
|    internal Timer clock according to the configuration selected.
|  * The result value is rounded to the most near natural value.
|  * This macro is used if the requested time has to be approximately accomplished.
|    For example, with request 100ms the time could expire at 100ms+/-(x ms),
|    where x is the error that it could be happen due to tick minimum configuration.
|  * With this macro the time may not be reached exactly according of the timer
|    configuration or cycle time
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  t: time period in milliseconds
|  result: nearest internal timer time units of t miliseconds.
|          The return type is a t_timer_time type
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE
|  Tmax Int En : 0 cpu cycles | O(n): CTE
|  Tmax Total  : 0 cpu cycles | O(n): CTE
/---------------------------------------------------------------------------*/
#if (TIMER_TIME_UNIT == M_SECONDS)
    #if (TIMER_TIME_TICK>1)
        #if ( (t % TIMER_TIME_TICK) >= TIMER_TIME_TICK/2)
            #define TIMER_MS_TO_TIME(t) (t_timer_time)(((UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)1)
        #else                                                                           
            #define TIMER_MS_TO_TIME(t) (t_timer_time)(((UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)0)
        #endif
    #else                                                                                   
        #define TIMER_MS_TO_TIME(t) ( (t_timer_time) (t) )
    #endif
#elif (TIMER_TIME_UNIT == U_SECONDS)
    #if (TIMER_TIME_TICK>1)
        #if ( ((1000*(t)) % (TIMER_TIME_TICK) ) > 0 )          
            #define TIMER_MS_TO_TIME(t) (t_timer_time)((1000*(UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)1)                              
        #else                                                                           
            #define TIMER_MS_TO_TIME(t) (t_timer_time)((1000*(UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)0)
        #endif
    #else                                                                                   
        #define TIMER_MS_TO_TIME(t) ( (t_timer_time) (1000 * (UI_32)(t)) )
    #endif
#endif

/*****************************************************************************
| Macro: TIMER_MS_TO_TIME_RESTRICTIVE
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts a time value in milliseconds to time in the units of
|    internal Timer clock according to the configuration selected.
|  * This macro is used if requested time always has to be accomplished
|    With this macro the time will always be reached and according configuration
|    timer may be exceeded until in 2 timer ticks.
|  * For example, with request 100ms the time could expire at 100ms+(x*2 ms),
|    where x is the error that it could be happen due to tick minimum configuration.
|  * The configured time will always be accomplished
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  t: time period in milliseconds.
|  result: internal timer time units of at least t miliseconds.
|          The return type is a t_timer_time type
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE
|  Tmax Int En : 0 cpu cycles | O(n): CTE
|  Tmax Total  : 0 cpu cycles | O(n): CTE
/---------------------------------------------------------------------------*/
#if (TIMER_TIME_UNIT == M_SECONDS)
    #if (TIMER_TIME_TICK>1)
        #if ( (t % TIMER_TIME_TICK) >= (TIMER_TIME_TICK / 2))
            #define TIMER_MS_TO_TIME_RESTRICTIVE(t) (t_timer_time)(((UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)2)
        #else                                                                           
            #define TIMER_MS_TO_TIME_RESTRICTIVE(t) (t_timer_time)(((UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)1)
        #endif
    #else                                                                                   
        #define TIMER_MS_TO_TIME_RESTRICTIVE(t) ( (t_timer_time) ((t)+(UI_8)1) )
    #endif
#elif (TIMER_TIME_UNIT == U_SECONDS)
    #if (TIMER_TIME_TICK>1)
        #if ( ((1000*(t)) % (TIMER_TIME_TICK) ) >= (TIMER_TIME_TICK / 2) )          
            #define TIMER_MS_TO_TIME_RESTRICTIVE(t) (t_timer_time)((1000*(UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)2)                              
        #else                                                                           
            #define TIMER_MS_TO_TIME_RESTRICTIVE(t) (t_timer_time)((1000*(UI_32)(t))/((UI_8)TIMER_TIME_TICK) + (UI_8)1)
        #endif
    #else                                                                                   
        #define TIMER_MS_TO_TIME_RESTRICTIVE(t) ( (t_timer_time) (1000 * (UI_32)((t)+(UI_8)1)) )
    #endif
#endif

/*****************************************************************************
| Macro: TIMER_US_TO_TIME
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts a time value in microseconds to time in the units of
|    internal Timer clock according to the configuration selected.
|  * The result value is rounded to the most near natural value.
|  * This macro is used if the requested time has to be approximately accomplished.
|    For example, with request 100us the time could expire at 100us+/-(x us),
|    where x is the error that it could be happen due to tick minimum configuration.
|  * With this macro the time may not be reached exactly according of the timer
|    configuration or cycle time
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  t: time period in microseconds.
|  result: nearest internal timer time units of t microseconds.
|          The return type is a t_timer_time type
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE
|  Tmax Int En : 0 cpu cycles | O(n): CTE
|  Tmax Total  : 0 cpu cycles | O(n): CTE
/---------------------------------------------------------------------------*/
#if (TIMER_TIME_UNIT == M_SECONDS)
    #define TIMER_US_TO_TIME(t)                                                 \
        ((t_timer_time)((((UI_32)(t))/((UI_8)TIMER_TIME_TICK * (UI_16)1000)) +                               \
         (((((UI_32)(t))%((UI_8)TIMER_TIME_TICK * (UI_16)1000)) >= ((UI_8)TIMER_TIME_TICK * (UI_16)500)) ? \
         (UI_8)1 : (UI_8)0)))
#elif (TIMER_TIME_UNIT == U_SECONDS)
#define TIMER_US_TO_TIME(t)                                                  \
        (((UI_8)TIMER_TIME_TICK > (UI_8)1) ?                                                  \
            ((t_timer_time)((((UI_32)(t))/((UI_8)TIMER_TIME_TICK)) +                                     \
             (((((UI_32)(t))%((UI_8)TIMER_TIME_TICK)) >= (((UI_8)TIMER_TIME_TICK/(UI_8)2))) ? (UI_8)1 : (UI_8)0))) : \
            ((t_timer_time)(t)))
#endif

/*****************************************************************************
| Macro: TIMER_US_TO_TIME_RESTRICTIVE
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts a time value in microseconds to time in the units of
|    internal Timer clock according to the configuration selected.
|  * This macro is used if requested time always has to be accomplished
|    With this macro the time will always be reached and according configuration
|    timer may be exceeded until in 2 timer ticks.
|  * For example, with request 100us the time could expire at 100us+(x*2 us),
|    where x is the error that it could be happen due to tick minimum configuration.
|  * The configured time will always be accomplished
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  t: time period in microseconds.
|  result: internal timer time units of at least t microseconds.
|          The return type is a t_timer_time type
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE
|  Tmax Int En : 0 cpu cycles | O(n): CTE
|  Tmax Total  : 0 cpu cycles | O(n): CTE
/---------------------------------------------------------------------------*/
#if (TIMER_TIME_UNIT == M_SECONDS)
    #define TIMER_US_TO_TIME_RESTRICTIVE(t)                                                 \
        ((t_timer_time)((((UI_32)(t))/((UI_8)TIMER_TIME_TICK * (UI_16)1000)) + (UI_8)1 +                               \
         (((((UI_32)(t))%((UI_8)TIMER_TIME_TICK * (UI_16)1000)) >= ((UI_8)TIMER_TIME_TICK * (UI_16)500)) ? \
         (UI_8)1 : (UI_8)0)))
#elif (TIMER_TIME_UNIT == U_SECONDS)
#define TIMER_US_TO_TIME_RESTRICTIVE(t)                                                  \
        (((UI_8)TIMER_TIME_TICK > (UI_8)1) ?                                                  \
            ((t_timer_time)((((UI_32)(t))/((UI_8)TIMER_TIME_TICK)) + (UI_8)1 +                                    \
             (((((UI_32)(t))%((UI_8)TIMER_TIME_TICK)) >= (((UI_8)TIMER_TIME_TICK/(UI_8)2))) ? (UI_8)1 : (UI_8)0))) : \
            ((t_timer_time)((t) + (UI_8)1)))
#endif

/*****************************************************************************
| Macro: TIMER_1SEG_TO_TIME
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts 1 second to time in the units of internal Timer 
|    clock according to the configuration selected.
|  * The result value is rounded to the most near natural value.
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  result: internal timer time of 1 second. The return type is a t_timer_time
|          type
|---------------------------------------------------------------------------                                 
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE 
|  Tmax Int En : 0 cpu cycles | O(n): CTE 
|  Tmax Total  : 0 cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
#define TIMER_1SEG_TO_TIME() (TIMER_MS_TO_TIME((UI_16)1000))

/*****************************************************************************
| Macro: TIMER_1MIN_TO_TIME
|----------------------------------------------------------------------------
| Operations contract:
|  * This macro converts 1 minute to time in the units of internal Timer 
|    clock according to the configuration selected.
|  * The result value is rounded to the most near natural value.
|  * This macro is thought to be solved during compiling time
|---------------------------------------------------------------------------
| Parameters explanation:
|  result: internal timer time of 1 second. The return type is a t_timer_time
|          type
|---------------------------------------------------------------------------                                 
| Execution time:
|  Tmax Int Dis: 0 cpu cycles | O(n): CTE 
|  Tmax Int En : 0 cpu cycles | O(n): CTE 
|  Tmax Total  : 0 cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
#define TIMER_1MIN_TO_TIME() (TIMER_MS_TO_TIME((UI_16)60000))

/* ------------------------------ Data Types -------------------------------- */

/* Timer tick and time types definition */
#if(T_TIMER_TIME_SIZE == T_TIMER_TIME_1_BYTE)
typedef UI_8 t_timer_time;
typedef UI_8 t_timer_tick;
#elif(T_TIMER_TIME_SIZE == T_TIMER_TIME_2_BYTE)
typedef UI_16 t_timer_time;
typedef UI_16 t_timer_tick;
#elif(T_TIMER_TIME_SIZE == T_TIMER_TIME_4_BYTE)
typedef UI_32 t_timer_time;
typedef UI_32 t_timer_tick;
#else
#error "Size definition for t_timer_time is missing in HalCFG"
#endif

/* ------------------------------ Functions --------------------------------- */

/******************************************************************************
| Routine: TimerInit
| ----------------------------------------------------------------------------
| Operations contract:         
|   This routine initializes the TIM peripheral to control the time according
|   to the parameters given and permit to synchronize the main program cycle
|   at each required point.                                   
|-----------------------------------------------------------------------------
| Parameters explanation:
|   All the configuration parameters are defined in HalCFG.h
|-----------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
void TimerInit(void);

/******************************************************************************
| Routine: TimerReset
| ----------------------------------------------------------------------------
| Operations contract: 
|  * This routine reinitialize the actual tick counter.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:                                               
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
void TimerReset(void);

/******************************************************************************
| Routine: TimerSyncTick
| ----------------------------------------------------------------------------
| Operations contract: 
|  * This routine is optional and only have to be called from the main program
|    cycle
|  * This routine is used to make an active wait to synchronize the main 
|    program cycle with a tick chosen between one of the number of ticks in 
|    which the main cycle has been divided
|  * The user must be sure that if he makes different synchronizations inside 
|    the main program cycle, he increments the num_tick parameter given in
|    each of the call.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:  
|  num_tick: number of tick in which the user want to synchronize the main
|            program cycle. This parameter must be inside the range
|            [1..TIMER_TICKS_CICLE-1]
|  result: ERROR_OK if the time didn't expired the synchronization point
|          given as a parameter
|          ERROR_GENERIC if the time expired the synchronization point
|          given as a parameter                                             
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
t_error TimerSyncTick(t_timer_tick num_tick);

/******************************************************************************
| Routine: TimerSyncCicle
| ----------------------------------------------------------------------------
| Operations contract: 
|  * This routine is mandatory in critical real time clock systems, and must 
|    be called one time at the end of the main program cycle.
|  * This routine is used to make an active wait to synchronize the main 
|    program cycle with the cycle number of ticks configured
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:
|  result: ERROR_OK if the time didn't expired the synchronization point
|          of the last tick
|          ERROR_GENERIC if the time expired the synchronization point
|          of the last tick                                            
|---------------------------------------------------------------------------
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
t_error TimerSyncCicle(void); 

/*****************************************************************************
| Routine: TimerGetCurrentTick
|----------------------------------------------------------------------------
| Operations contract:
|  * Routine to request the current tick at one point inside the main program
|    cycle.
|  * This routine shall be called when any FSM or function wants to start
|    using a timer. At the timer initialization, the tick should be taken
|    using this routine. Then with the TimerDeltaTime function the timer
|    will be increased at each FSM or function execution and the tick will be
|    directly updated by the TimerDeltaTime routine.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:
|  result: current tick
|---------------------------------------------------------------------------                                 
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
t_timer_tick TimerGetCurrentTick(void);

/*****************************************************************************
| Routine: TimerDeltaTime
|----------------------------------------------------------------------------
| Operations contract:
|  * Routine to compute the spent time between a tick given from the last task
|    execution and the current tick at the moment of the call.
|  * The precision is one clock tick.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:
|  ini_tick: certain time tick obtained on the previous or current program
|            cycle with the routine TimerGetCurrentTick or with the last
|            call of TimerDeltaTime
|  result: spend time between the ini_tick tick and the current tick. The
|          units are the ones configured in the TimerInit call.
|---------------------------------------------------------------------------                                 
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
t_timer_time TimerDeltaTime(t_timer_tick *old_tick);

/*****************************************************************************
| Routine: TimerIncrTime
|----------------------------------------------------------------------------
| Operations contract:
|  * Routine to increase the timer current tick time with a specific amount
|    of time. This routine shall be called due to an operation which normally
|    freezes the CPU and makes that the normal timer interrupt is not raised
|    during some amount of time. Examples:
|       - Execution of erasing or programming operations where CPU freezes
|		- Usage of sleep functions or CPU low power operation modes where 
|		  timer interrupt is not working
|  * The precision is one clock tick.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:
|  incr_time: time in which the timer shall increase its internal tick due to
|             an external operation that avoids the normal counting of timer.
|			  This parameter shall be given using one of the macros:
|				TIMER_MS_TO_TIME(x) or TIMER_US_TO_TIME(x)
|---------------------------------------------------------------------------                                 
| Execution time:
|  Tmax Int Dis: ??? cpu cycles | O(n): CTE 
|  Tmax Int En : ??? cpu cycles | O(n): CTE 
|  Tmax Total  : ??? cpu cycles | O(n): CTE 
/---------------------------------------------------------------------------*/
void TimerIncrTime(t_timer_time incr_time);

/******************************************************************************
| Routine: SystemTimerGPT_callback
| ----------------------------------------------------------------------------
| Operations contract:
|  * This routine is the callback routine of AUTOSAR GPT (Timer) and it is called
|    every tick of the clock.
|  * This routine reinitialize the actual tick counter.
|  * Before calling this routine, the driver must have been initialized with
|    the TimerInit routine.
|---------------------------------------------------------------------------
| Parameters explanation:
|---------------------------------------------------------------------------
| Execution time:
|
/---------------------------------------------------------------------------*/
void SystemTimerGPT_callback(void);

//ACF deprecated
typedef t_timer_time t_clock;
#define TIMER_US_TO_TICKS(t) 		(TIMER_US_TO_TIME((t)))
#define TIMER_MS_TO_TICKS(t) 		(TIMER_MS_TO_TIME((t)))
#define TIMER_1SEG_TO_TICKS() 		(TIMER_1SEG_TO_TIME())
#define TIMER_1MIN_TO_TICKS() 		(TIMER_1MIN_TO_TIME())
#define TimerDeltaCicleConsulta() 	((UI_16)(TIMER_TICKS_CICLE))
#define T_CLOCK_MAX_VALUE 			(T_TIMER_TIME_MAX_VALUE)

#endif /* FICOSARTIMER_H_ */
