/******************************************************************************/
/*                       Copyright 2001 Broadcom Corporation                  */
/*                                                                            */
/* This material is the confidential trade secret and proprietary information */
/* of Broadcom Corp.  It may not be reproduced, used, sold or transferred to  */
/* any third party without the prior written consent of Broadcom Corp.        */
/* All rights reserved.                                                       */
/******************************************************************************/
/*   FileName        : bcm_timer.c                                            */
/*   Purpose         : Usefull timer variables used for time out features     */
/*                     This is based on OS timeval & itimer structures        */
/*   Limitations     : None                                                   */
/*   Author          : Emmanuel Hanssens                                      */
/*   Creation Date   : 20-Sep-2001                                            */
/*   History         : Compiled by CVS                                        */
/******************************************************************************/
/*   $Id: bcm_timer.c,v 1.11 2004/09/27 15:33:11 hanssens Exp $  */
/******************************************************************************/

#include <unistd.h>
#include <sys/time.h>
#include "bcm_userdef.h"
#include "bcm_errorHandler.h"
#define TIMER_C
#include "bcm_timer.h"

/* large second number for timer start (will be stopped before interrupt) */
#define TIMER_LARGE_NUMBER_S 10000

/* {{{ startTimer: we count time from this point */
void startTimer(void)
{
  /* itimerval structure having as timeval.tv_sec a large number used to start
   * the timer so that there is plenty of time to stop the timer before it hits
   * 0 (no alarm generation) */
  struct itimerval itimerStart = 
    {
      {0, 0}, 
      {TIMER_LARGE_NUMBER_S, 0}
    };
  
  /* this starts a count-down timer that will generate some interrupts when it
     hits 0, unless we disable it before (see stopTimer) */
  if (setitimer(ITIMER_REAL, &itimerStart, NULL) != 0)
    SOFT_ERROR(1, "Couldn't set timer");
}
/* }}} */

/* {{{ compareTimer: return 1 if elapsed time is larger than specified time */
int compareTimer(MyTime timeOut)
{
  /* itimerval structure used to get the current timer value */
  struct itimerval itimerNow;
  struct timeval  timerRef;

  timerRef.tv_sec  = TIMER_LARGE_NUMBER_S-1-timeOut.sec;
  timerRef.tv_usec = 1000000-timeOut.usec;

#if (PLATFORM == CYGWIN)
  /* cygwin has wrong timeval implementation: structure is (s,ms) iso (s,us) */
  timerRef.tv_usec /= 1000;
#endif
  
  /* get the value of the timer */
  if (getitimer(ITIMER_REAL, &itimerNow) != 0)
    SOFT_ERROR(1, "Couldn't get timer");

  /* compare it with the ref, and return 1 if time out elapsed (count down) */
  return (timercmp(&(itimerNow.it_value), &timerRef, <));
}
/* }}} */

/* {{{ get timer */
void getTimer(MyTime *myTime)
{
  /* itimerval structure used to get the current timer value */
  struct itimerval itimerNow;

  /* get the value of the timer */
  if (getitimer(ITIMER_REAL, &itimerNow) != 0)
    SOFT_ERROR(1, "Couldn't get timer");

#if (PLATFORM == CYGWIN)
  /* cygwin has wrong timeval implementation: structure is (s,ms) iso (s,us) */
  itimerNow.it_value.tv_usec *= 1000;
#endif

  myTime->sec  = TIMER_LARGE_NUMBER_S-1-itimerNow.it_value.tv_sec;
  myTime->usec = 1000000-itimerNow.it_value.tv_usec;

  /* avoid returning (-1, 1000000) when no time has elapsed */
  if (myTime->sec == -1 && myTime->usec == 1000000)
  {
    myTime->sec  = 0;
    myTime->usec = 0;
  }
}
/* }}} */

/* {{{ stopTimer: disable count down timer to avoid interrupt generation */
void stopTimer(void)
{
  struct itimerval itimerNow;

  timerclear(&(itimerNow.it_value));
  setitimer(ITIMER_REAL, &itimerNow, NULL);
}
/* }}} */

/* {{{ just sleep some usec (encaplulation of OS function) */
void goSleep(MyTime timeToSleep)
{
  if (timeToSleep.sec > 0)  sleep(timeToSleep.sec);
  if (timeToSleep.usec > 0) usleep(timeToSleep.usec);
}
/* }}} */
