/**************************************************************
$Workfile:   ipostimer.c  $
***************************************************************
**
** FIRMWARE, Copyright (C) 2000-2002
** Ikanos Communication, Fremont, CA 
** All rights reserved.
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of
** Ikanos Communication
**  
$Revision: 1.1 $
$Date: 2006/10/16 04:34:50 $
**************************************************************/


/*************************************************************
** 
** This file contains generic timer module
**       This module contains the following functionality
**             -> Timer Task creation, initialization
**             -> Creating a timer
**             -> Setting and resetting a timer
**             -> Freeing a timer
**
**************************************************************/


#include <stdio.h>
#include <time.h>

#include "ipos.h"
#include "ipostimer.h"
#include "apposmacro.h"  // for OS_SUCCESS, OS_ERROR and for taskFunc define.
#include "oamptask.h"

#define IPOS_TIMER_TASK_PRIORITY 100
#define IPOS_TIMER_TASK_STACK_SIZE 8192

static void processTimers(void) ;
static void create_inactive_list(void) ;
static void iposTimerTask(int arg,...) ;

ipos_tmr_info *pHeadActiveList ;
ipos_tmr_info *pHeadInactiveList ;

ipos_tmr_info ipos_tmr[IPOS_MAX_TMRS] ;


/*
 *
 * TIMER TASK INITIALIZATION 
 *
 * This function is used to initialize timer module. 
 * This function
 *         -> Initializes Active list head and inactive list head to NULL
 *         -> Allocate memory for ipos_tmr_info array, ipos_tmr. The array 
 *            size is IPOS_MAX_TIMERS
 *         -> Prepares inactive linked list 
 *         -> Spawns timer task - starts iposTimerTask().
 *
 *
 * Arguments :
 *     None.
 *
 * Return values :
 *   IPOS_SUCCESS
 *   IPOS_ERROR, if the task is not spawned.
 *
 */


/* Only call iposTmrInit from the start method or some
   other bootup routine where it can be guaranteed no
   competing threads or tasks will be calling iposTmrInit
   tmrState lets iposTmrInit be called more than once
   but only in sequence.				*/

static U8		tmrState = 0;

int iposTmrInit( void )
{
  int taskId ;

  if (tmrState == 0)			/* prevent multiple initializations */
  {
    pHeadActiveList   = NULL ;
    pHeadInactiveList = NULL ;

  /* Prepare inactive list */
    create_inactive_list() ;

    taskId = iposTaskSpawn(
             "TimerTask",
             IPOS_TIMER_TASK_PRIORITY,
             IPOS_TIMER_TASK_STACK_SIZE,
             iposTimerTask,
             0,
             0,
             0
           ) ;

    if (taskId != OS_SUCCESS) {
      printf("iposTmrInit(): Error spawning a task\n") ;
      return IPOS_ERROR ;
    } /* if */
    tmrState = 1;	/* will NOT work if multiple tasks call iposTmrInit !!! */
  }

  return IPOS_SUCCESS ;
} /* iposTmrInit() */


/*
 *
 * TIMER TASK Function 
 *
 * This function is timer module main(top level) function. 
 * This function
 *         -> Processes the active timer list periodically with a delay of IPOS_TMR_RESOLUTION 
 *            milliseconds.
 *         -> contains an infinite loop.
 *         -> is a static function
 *
 * Arguments :
 *     arg  - This argument can be used by user for any purpose.
 *
 * Return values :
 *     None.   
 *
 */

static void iposTimerTask(int arg,...)
{

//  printf("Timer task initialization\n") ;

  while (1) {
    processTimers() ;

/* changed to iposTaskDelay from VxWorks taskDelay per TT ID 1159 */

    iposTaskDelay((CLOCKS_PER_SEC * IPOS_TMR_RESOLUTION)/1000) ;   // IPOS_TMR_RESOLUTION ms
  } /* while */

} /* iposTimerTask() */


/*
 *
 * PROCESS TIMER Function 
 *
 * This function
 *         -> increments the elapsed time of each active timer for every IPOS_TMR_RESOLUTION ms. 
 *         -> checks if the elapsed time >= expiry time.
 *         -> calls expiry callback function, if yes.   
 *         -> is a static function.
 * 
 * Arguments :
 *     None.    
 * 
 * Return values :
 *     None.   
 *
 */

static void processTimers( void ) 
{
   ipos_tmr_info *list_active_tmr ;
   int           intlock ;

   
   list_active_tmr = pHeadActiveList ;

   while (list_active_tmr!= NULL) 
	{
		if (list_active_tmr->status == IPOS_TMR_ACTIVE) 
		{
		 
			if (list_active_tmr->elapsedtime < list_active_tmr->timecount) 
			{
			
				intlock = iposIntLock() ;
				list_active_tmr->elapsedtime++ ;
				iposIntUnlock(intlock) ;
                
			} else if (list_active_tmr->elapsedtime == list_active_tmr->timecount) 
			{
			
			 intlock = iposIntLock() ;
			 list_active_tmr->elapsedtime++ ;
			 iposIntUnlock(intlock) ;
			 /* call expiry Cb Func */
			 if(list_active_tmr->ptrCbFunc!=NULL)
			 {
				list_active_tmr->ptrCbFunc(list_active_tmr->user_arg1, list_active_tmr->user_arg2) ;
			 }
			} /* if */
		} /* if */
     list_active_tmr = list_active_tmr->next ;
   } /* while */
  
} /* processTimers() */


/*
 *
 * CREATE TIMER Function 
 *
 * This function
 *         -> takes(removes) a timer from inactive timer list
 *         -> appends the timer to active timer list
 *         -> is called by application that needs a timer.
 * 
 * Arguments :
 *     tmrHandle :  OUTPUT
 *                  TYPE : pointer to pointer to ipos_tmr_info
 *                  A free timer (pointer) that is removed from 
 *                  inactive list is assigned to tmrHandle.
 * 
 * Return values : int
 *     IPOS_ERROR, if there are no free timers available
 *     IPOS_SUCCESS, otherwise.
 *
 */

int iposCreateTmr(ipos_tmr_info **tmrHandle)
{
  ipos_tmr_info *freetmr;
  int           intlock ;

  intlock = iposIntLock() ;

  /* Get Free tmr from inactive list */
  if (pHeadInactiveList == NULL) {
    printf("No free timers available\n") ;
    
	iposIntUnlock(intlock) ;
    return IPOS_ERROR ;
  }  
   
  freetmr = pHeadInactiveList ;					/* get the free timer from the free list	*/
  pHeadInactiveList = pHeadInactiveList->next ;	/* inactive list point to the next free chain */

  
  /* Append timer at the head of Active list */
  freetmr->next = pHeadActiveList ;
  pHeadActiveList = freetmr ;
  *tmrHandle = freetmr ;

  iposIntUnlock(intlock) ;

  return IPOS_SUCCESS ;
} /* iposCreateTmr() */


/*
 *
 * FREE TIMER Function 
 *
 * This function
 *         -> removes the active timer from active timer list
 *         -> appends the timer to inactive timer list
 *         -> is called by application that uses the timer.
 * 
 * Arguments :
 *     tmrHandle :  INPUT
 *                  TYPE : pointer to ipos_tmr_info
 *                  This is pointer to a timer that needs to be 
 *                  removed from active timer list. This is appended
 *                  to inactive list.
 * 
 * Return values : int
 *     IPOS_ERROR, if the timer is not available, 
 *                 if user tries to remove the timer from empty list.
 *     IPOS_SUCCESS, otherwise.
 *
 */


int iposFreeTmr(ipos_tmr_info *tmrHandle)
{
  ipos_tmr_info *temp ;
  int           intlock ;

  intlock = iposIntLock() ;
  /* Removing the timer from the Active list */
  if (pHeadActiveList == NULL) {
    printf("Attempting to remove from an empty list\n") ;
    iposIntUnlock(intlock) ;
    return IPOS_ERROR ;
  } /* if */

  /* Timer at the head */
  if (tmrHandle == pHeadActiveList) {
    pHeadActiveList = tmrHandle->next ;
  } else {
    temp = pHeadActiveList ;

    while ((temp->next != tmrHandle) && (temp->next != NULL)) {
      temp=temp->next ;      
    } /* while */

    if (temp->next == NULL) {
      printf("Error: Timer not available in the list\n") ;
      iposIntUnlock(intlock) ;
      return IPOS_ERROR ;
    } /* if */

    temp->next = tmrHandle->next ;
      
  } /* if */

  /* Append the timer to Inactive list at head */
  tmrHandle->next = pHeadInactiveList ;
  pHeadInactiveList = tmrHandle ;

  iposIntUnlock(intlock) ;
  
  return IPOS_SUCCESS ;
} /* iposFreeTmr() */


/*
 *
 * SET TIMER Function 
 *
 * This function
 *         -> sets the following in the structure
 *                o timecount
 *                o timer expiry callback function
 *                o other user arguments.
 *         -> is called by application that uses the timer.
 *         -> HAS TO BE CALLED AFTER createTmr() 
 * 
 * Arguments :
 *     tmr       :  INPUT
 *                  TYPE : pointer to ipos_tmr_info
 *                  This is pointer to a timer that is given by 
 *                  createTmr(). The timer on which any action 
 *                  has to be taken by timer expiry function shall 
 *                  be specified by the last argument.
 *
 *     timecount :  INPUT
 *                  TYPE : U16
 *                  The amount of time that the timer has to be active. 
 *                  This count shall be the number of times the 
 *                  IPOS_TMR_RESOLUTION. 
 *                  for e.g., for one Sec, timecount value shall be
 *                  5, assuming IPOS_TMR_RESOLUTION as 200 ms.   
 *
 *     pFunc     :  INPUT
 *                  TYPE : pointer to timer expiry function.
 *                  This is the pointer to a function that shall be 
 *                  called on expiry of the timer. 
 *
 *     arg1      :  INPUT or OUTPUT
 *                  TYPE : int
 *                  This parameter can be used by the user for any purpose
 * 
 *     arg2      :  INPUT or OUTPUT
 *                  This is used to specify the timerhandle to timer callback 
 *                  function on which some action needs to be taken
 *
 * 
 * Return values : int
 *     IPOS_ERROR, if the timer is not available, 
 *     IPOS_SUCCESS, otherwise.
 *
 */


int iposSetTmr(ipos_tmr_info *tmr, U16 timecount, tmrExp pFunc, U32 arg1, U32 arg2)
{ 
  int           intlock ;
 
  intlock = iposIntLock() ;
  
  if (tmr != NULL) {
    tmr->ptrCbFunc   = pFunc ;
    tmr->timecount   = timecount ;
    tmr->elapsedtime = 0 ;
    tmr->status      = IPOS_TMR_ACTIVE ;
    tmr->user_arg1   = arg1 ;
    tmr->user_arg2   = arg2 ;
  } else {
    printf("Invalid timer\n") ;
    
	iposIntUnlock(intlock) ;
	return IPOS_ERROR ;
  } /* if */

  iposIntUnlock(intlock) ;

  return IPOS_SUCCESS ;
} /* iposSetTimer() */


/*
 *
 * RESET TIMER Function 
 *
 * This function
 *         -> searches for specified timer
 *         -> changes the status of the timer from IPOS_TMR_ACTIVE
 *            to IPOS_TMR_PASSIVE.
 *         -> is called by application that uses the timer.
 *         -> enables the user to set the timer again voiding 
 *            creation of it again.
 * 
 * Arguments :
 *     tmrHandle :  INPUT
 *                  TYPE : pointer to ipos_tmr_info
 *                  This is pointer to a timer whose status needs to be 
 *                  changed to IPOS_TMR_PASSIVE. 
 * 
 * Return values : int
 *     IPOS_ERROR, if the timer is not available, 
 *                 if user tries to remove the timer from empty list.
 *     IPOS_SUCCESS, otherwise.
 *
 */


int iposResetTmr(ipos_tmr_info *tmr)
{ 

  int           intlock ;
  
  intlock = iposIntLock() ;

  if (tmr != NULL) {
    tmr->status = IPOS_TMR_PASSIVE ;
  } else {
	
	iposIntUnlock(intlock) ;
	printf("Invalid Timer\n") ;
    return IPOS_ERROR ;
  } /* if */

  iposIntUnlock(intlock) ;

  return IPOS_SUCCESS ;
} /* iposResetTimer() */


/*
 *
 * CREATE INACTIVE LIST Function 
 *
 * This function
 *         -> prepares linked list of inactive timers.
 *         -> Allocates memory for the nodes from the array initialized
 *            in iposTmrInit().
 *         -> is a static function.
 *         -> is called in iposTmrInit().
 * 
 * Arguments :
 *     None. 
 * 
 * Return values : void
 *     None.
 *
 */


static void create_inactive_list( void ) 
{
  int i ;
  ipos_tmr_info *newtmr;

  pHeadInactiveList=&ipos_tmr[0];

  for (i=0; i<IPOS_MAX_TMRS-1; i++) {
    newtmr = &ipos_tmr[i] ;
    newtmr->status = IPOS_TMR_PASSIVE ;
    newtmr->elapsedtime = 0 ;
    newtmr->timecount = 0 ;
    newtmr->next =&ipos_tmr[i+1]  ;
  }

  /* last one	*/
  ipos_tmr[IPOS_MAX_TMRS-1].next=NULL;


} /* create_inactive_list() */







#if 0

/*
 *
 * PRINT LISTS Function 
 *
 * This function
 *         -> displays the list of active and inactive timers separately.
 * 
 * Arguments :
 *     None. 
 * 
 * Return values : void
 *     None.
 *
 */

void print_lists( void )
{
  ipos_tmr_info 	*temp ;
  int             num = 1 ;
  int           intlock ;

  intlock = iposIntLock() ;

  printf("Active List :\n\t") ;
  temp = pHeadActiveList ;
  if (temp == NULL) {
    printf("None.") ;
  } /* if */
  while (temp != NULL) {
    printf("%d %p\n",num,temp) ;
    num++ ;
    temp = temp->next ;
  } /* while */

  num = 1 ;
  printf("\n\nInActive List :\n\t") ;
  temp = pHeadInactiveList ;
  if (temp == NULL) {
    printf("None.") ;
  } /* if */
  while (temp != NULL) {
    printf("%d %p\n",num, temp) ;
    num++ ;
    temp = temp->next ;
  } /* while */ 

  iposIntUnlock(intlock) ;
  
} /* print_lists() */

#endif
