
/* ------------------------------ Includes ---------------------------------- */
//#include "Global.h"
#include "Std_Types.h"
//#include "Gpt.h"
#include "P417_SWTR_App_ert_rtw/P417_SWTR_App.h"
#include "Timer.h"

/* ------------------------------ Constants --------------------------------- */
#if (TIMER_TIME_UNIT == U_SECONDS)
	
#if ((TIMER_TIME_TICK < 1) || (TIMER_TIME_TICK > 1625))
	#error "Value not supported for TIMER_TIME_TICK"
#else	
	#define TIMER_VALOR ((UI_16)(TIMER_TIME_TICK*FACTOR_CONVERSIO_FCY_US))
#endif

#elif (TIMER_TIME_UNIT == M_SECONDS)

#if ((TIMER_TIME_TICK < 1) || (TIMER_TIME_TICK > 104))
	#error "Value not supported for TIMER_TIME_TICK"
#else
	#define TIMER_VALOR ((UI_16)(((UI_16)TIMER_TIME_TICK)*((UI_16)(FACTOR_CONVERSIO_FCY_MS))))
#endif	

#else 
	#error "Time unit not defined."
#endif /* TIMER_TIME_UNIT */

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

/* --------------------------- Global Variables ----------------------------- */

/* Variable that contain current tick */
static volatile t_timer_tick current_tick = (t_timer_tick)0;

/* Variable to control last cycle tick synchronized */
static volatile t_timer_tick cycle_tick = (t_timer_tick)0;

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

#ifdef TIMER_TICK_CALLBACK
  void TIMER_TICK_CALLBACK (void);
#endif



/******************************************************************************
| Routine: TimerInit
| ----------------------------------------------------------------------------
| Operations contract:
|   This routine initializes the AUTOSAR GPT module 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 FicoTimeWrapper.h
/---------------------------------------------------------------------------*/
void TimerInit(void)
{
   // UI_32 value;
	/* Initialization of tick counters */
    current_tick = (t_timer_tick)0;
    cycle_tick = (t_timer_tick)0;

	/* Value calculation to load counter register */
	#if (TIMER_TIME_UNIT == U_SECONDS)
    value=(TIMER_TIME_TICK * FREQ_SYS_CLOCK) - ((UI_8)1);
	#elif (TIMER_TIME_UNIT == M_SECONDS)
   // value=(TIMER_TIME_TICK * ((UI_32)1000) * FREQ_SYS_CLOCK)- ((UI_8)1);
	#endif
	/* Initialization of the GPT Driver */
	//Gpt_Init(GPT_CONFIG_SET_0);
	/* Enabling the Notification */
    //Gpt_EnableNotification(GPT_CONFIG_CHANNEL_0);
	/* Starting the Timer */
    //Gpt_StartTimer(GPT_CONFIG_CHANNEL_0, value);

} /* TimerInit */

/******************************************************************************
| 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:
/---------------------------------------------------------------------------*/
void TimerReset(void)
{
    //UI_32 value;

	/* Value calculation to load counter register */
	#if (TIMER_TIME_UNIT == U_SECONDS)
    value=(TIMER_TIME_TICK * FREQ_SYS_CLOCK) - ((UI_8)1);
	#elif (TIMER_TIME_UNIT == M_SECONDS)
   // value=(TIMER_TIME_TICK * ((UI_32)1000) * FREQ_SYS_CLOCK)- ((UI_8)1);
	#endif
	
	/* Disabling the Notification */
	//Gpt_DisableNotification(GPT_CONFIG_CHANNEL_0);
	/* Stopping the Timer */
	//Gpt_StopTimer(GPT_CONFIG_CHANNEL_0);

	/* Enabling the Notification */
   // Gpt_EnableNotification(GPT_CONFIG_CHANNEL_0);
	/* Starting the Timer */
    //Gpt_StartTimer(GPT_CONFIG_CHANNEL_0, value);

} /* TimerReset */

/******************************************************************************
| 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]
|			 num_ticks = TIMER_TICKS_CICLE is reserved to TimerSyncCycle
|  result: ERROR_OK if the timer didn't reach the synchronization point
|          num_tick before the call
|          ERROR_GENERIC if the timer reached the synchronization point
|          num_tick before the call                                             
/---------------------------------------------------------------------------*/
t_error TimerSyncTick(t_timer_tick num_tick)
{
    t_error resultat = ERROR_OK;
	BOOL synchronized;
	t_timer_tick enter_loop_tick = 0;

    /* Case in which next cycle tick overflows the ticks variable */
    if(cycle_tick > (T_TIMER_TICK_MAX_VALUE - num_tick)) {
		/* Mutex to avoid that RSI could modify the value during the calculation */
	  //  DISABLE_INTERRUPTS();
	    synchronized = (current_tick < cycle_tick) && (current_tick >= ((t_timer_tick) (cycle_tick + num_tick)));
		//ENABLE_INTERRUPTS();
        /* Check if next tick to synchronize is already reached*/
        if (synchronized == TRUE) {
            /* Notify that cycle was already expired, the current main loop */
            /* path was larger than expected by design */
			resultat = ERROR_GENERIC;
        }
        else {
            /*  Active waiting to synchronize to given tick */
            while (synchronized == FALSE) {
                /* Mutex to avoid that RSI could modify the value during the calculation */
              //  DISABLE_INTERRUPTS();
                synchronized = (current_tick < cycle_tick) && (current_tick >= ((t_timer_tick) (cycle_tick + num_tick)));
               // ENABLE_INTERRUPTS();
            }
        }
    }
    /* Case in which next cycle tick does not overflow the ticks variable */
    else {
		/* Mutex to avoid that RSI could modify the value during the calculation */
	   // DISABLE_INTERRUPTS();
		synchronized = (current_tick >= ((t_timer_tick) (cycle_tick + num_tick)));
		//ENABLE_INTERRUPTS();
        /* Check if next tick to synchronize is already reached */
        if (synchronized == TRUE) {
            /* Notify that cycle was already expired, the current main loop */
            /* path was larger than expected by design */
			resultat = ERROR_GENERIC;
        }
        else {
			//DISABLE_INTERRUPTS();
			enter_loop_tick = current_tick;
			//ENABLE_INTERRUPTS();
            /*  Active waiting to synchronize to given tick */
            while (synchronized == FALSE) {
                /* Mutex to avoid that RSI could modify the value during the calculation */
               // DISABLE_INTERRUPTS();
				if(current_tick >= enter_loop_tick) {
					synchronized = (current_tick >= ((t_timer_tick) (cycle_tick + num_tick)));
				}else{
					synchronized = TRUE;
				}
                //ENABLE_INTERRUPTS();
            }
        }
    }
    
    return resultat;
}

/******************************************************************************
| 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                                            
/---------------------------------------------------------------------------*/
t_error TimerSyncCicle(void)
{
    t_error resultat;

    /* Synchronize with configured ticks cycle */
    resultat = TimerSyncTick(TIMER_TICKS_CICLE);

    /* Case which synchronization cycle was correctly performed */
    if(resultat == ERROR_OK) {
        /* Set next cycle initial tick as current cycle initial tick plus
		the number ticks of a cycle */
        cycle_tick += TIMER_TICKS_CICLE;
    }
    /* Case which synchronization point was already reached so the main loop */
    /* path was larger than what was expected by design */
    else {
        /* Set next cycle initial tick as next current tick to assure next cycle
		   will have a complete TIMER_TICKS_CICLE ticks */
    	/* Mutex to avoid that RSI could modify the value during the calculation */
    	//DISABLE_INTERRUPTS();
        cycle_tick = current_tick + (UI_8)1;
    	//ENABLE_INTERRUPTS();
    }
	
    return resultat;
}

/*****************************************************************************
| 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
/---------------------------------------------------------------------------*/
t_timer_tick TimerGetCurrentTick(void)
{
	t_timer_tick aux_tick;

	/* Mutex to avoid that RSI could modify the value during the calculation */
	//DISABLE_INTERRUPTS();
	aux_tick = current_tick;
	//ENABLE_INTERRUPTS();

    return aux_tick;
}

/*****************************************************************************
| 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:
|  old_tick: Input/output parameter.
|			 As input, certain time tick obtained on the previous or current program
|            cycle with the routine TimerGetCurrentTick or with the last
|            call of TimerDeltaTime.
|			 As output return the current tick.
|  result: spend time between the old_tick and the current tick.
|          The units are in ticks. 
|          The equivalence between one tick and time is defined in HalCfg.
/---------------------------------------------------------------------------*/
t_timer_time TimerDeltaTime(t_timer_tick *old_tick)
{
    t_timer_time time_diff;
	t_timer_tick aux_tick;
	
	/* Mutex to avoid that RSI could modify the value during the calculation */
	//DISABLE_INTERRUPTS();
	aux_tick = current_tick;
	//ENABLE_INTERRUPTS();
	
    /* Case in which current tick overflows the maximum tick*/
	if(aux_tick < (*old_tick)){
        time_diff = (T_TIMER_TIME_MAX_VALUE - (*old_tick)) + aux_tick + (UI_8)1;
    }
	/* Case in which current tick does not overflow the maximum tick*/
    else{
        /* Get  the difference between given tick with current tick*/
        time_diff = (t_timer_time)(aux_tick - (*old_tick));
    }

    /* Return the new tick */
    *old_tick = aux_tick;

    /* Return the difference of current tick compared to initial tick */
    return time_diff;
}

/*****************************************************************************
| 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)
/---------------------------------------------------------------------------*/
void TimerIncrTime(t_timer_time incr_time)
{
	/* Mutex to avoid that RSI could modify the value during the calculation */
	//DISABLE_INTERRUPTS();
	current_tick += incr_time;
	cycle_tick += incr_time;
	//ENABLE_INTERRUPTS();
}

void SystemTimerGPT_callback(void)
{
	/* Increase tick counter */
	current_tick++;

#ifdef TIMER_TICK_CALLBACK
	TIMER_TICK_CALLBACK();
#endif
}
