#define OSCTR_C
/******************************************************************************
 *
 *       (C) Copyright 2006, Freescale Semiconductor, Inc. All Rights Reserved.
 *
 *       THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
 *       BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
 *       Freescale Semiconductor, Inc.
 *
 * Filename:     $Source: /u/OSEK/src/os2000/src/osesys/src/osctr.c,v $
 * Author:       $Author: c-atroshikhin $
 * Revision:     $Revision: 1.15 $
 *
 * Functions:    
 *
 * History:      Use the CVS command rlog to display revision history
 *               information.
 *
 * Description:  Function code to support OSEK OS counters       
 *
 * Notes:        
 *
 ******************************************************************************/
#if !defined(OSPROPH)
#include "osprop.h"                     /* OS Properties */
#else                                   /* !defined(OSPROPH)    */
#include OSPROPH                        /* OS Properties */
#endif                                  /* !defined(OSPROPH)    */

#include <osapi.h>                      /* Types and constants   */

#if defined(OSCOUNTER)

/*  Global OS variables */

OSCTRCB OsCounters[OSNCTRS];            /* Counters table           */
#if defined(OSHWCOUNTER)
TickType OsTimVal;                      /* used as time base point for compare in HW alarms */
#endif                                  /* defined(OSHWCOUNTER) */

/*  Private OS Services */
#if defined(OSSYSTIMER)
/***************************************************************************
 * Function :   OSSysTimerCancel
 *
 * Description: disable interrupts from output compare channel
 *
 * Returns: 
 *
 * Notes:       for HW counters
 *
 **************************************************************************/
#if defined(OSSECONDTIMER)

void OSSysTimerCancel(CtrType ctrId)
{
#if defined(OSMGT5X00) && defined(OSTIMSLC)
  if( ctrId == OSTIMER1 )
#else                                   /* defined(OSMGT5X00) && defined(OSTIMSLC) */
  if( ctrId == 0 )
#endif                                  /* defined(OSMGT5X00) && defined(OSTIMSLC) */
  {
    OSSysTimDisableInt();               /* disable output compare interrupt     */
    OSSysTimClearFlag();                /* clear output compare interrupt flag  */
  }
  else                                  /* cancel Second Timer                  */
  {
    OSSecondDisableInt();               /* disable output compare interrupt     */
    OSSecondClearFlag();                /* clear output compare interrupt flag  */
  }
  OSISYNC;
}
#else                                   /* defined(OSSECONDTIMER) */

void OSSysTimerCancel(void)
{
  OSSysTimDisableInt();                 /* disable output compare interrupt     */
  OSSysTimClearFlag();                  /* clear output compare interrupt flag  */
  OSISYNC;
}
#endif                                  /* defined(OSSECONDTIMER) */
#endif                                  /* defined(OSSYSTIMER) */

#if defined(OSHWCOUNTER)
/***************************************************************************
 * Function :   OSSysTimerArm
 *
 * Description: set interruption point and enable interrupts
 *
 * Returns: 
 *
 * Notes:
 *
 **************************************************************************/

#if OSNHWCTRS == 1
void OSSysTimerArm( TickType ticks )
#elif OSNHWCTRS == 2
void OSSysTimerArm( CtrType ctrId, TickType ticks )
#endif                                  /* OSNHWCTRS == 1 */
{
#if OSNHWCTRS == 2
  if( ctrId == 0 )
  {
#endif                                  /* OSNHWCTRS */
    OSTIMCHOC = ticks;                  /* set next point to OC register */
    OSSysTimClearFlag();                /* clear output compare interrupt flag  */
    OSSysTimEnableInt();                /* enable interrupts on channel */
#if OSNHWCTRS == 2
  }
  else
  {                                     /* this is for Second Timer */
    OSTIM2CHOC = ticks;                 /* set next point to OC register */
    OSSecondClearFlag();                /* clear output compare interrupt flag  */
    OSSecondEnableInt();                /* enable interrupts on channel */
  }
#endif                                  /* OSNHWCTRS */
}

/***************************************************************************
 * Function :   OSISRSystemTimer
 *
 * Description: ISR for system timer
 *
 * Notes:       called only if timer is armed (HW counter used)
 *
 **************************************************************************/

void OSISRSystemTimer( void )
{
  OSCURRENTISRPRIO_DEF;

  OSOrtiSetISRId( OSORTIISRSYSTIMER );
  OSSysTimClearFlag();
  OSEnterISR2();
#if !defined(OSTIMESCALE)
#if defined(OSALARM)
  OSDI();
  OSCounterNotify( OSTIMER1 );
#endif                                  /* defined(OSALARM) */
#else                                   /* !defined(OSTIMESCALE) */
  OSDI();
  OSProcessTimeScale();                 /* TimeScale is always on the first timer */
#endif                                  /* !defined(OSTIMESCALE) */
  OSLeaveISR2();
}

#if OSNHWCTRS == 2
/***************************************************************************
 * Function :   OSISRSecondTimer
 *
 * Description: ISR for second timer
 *
 * Returns:
 *
 * Notes:       called only if timer is armed (HW counter used)
 *
 **************************************************************************/

void OSISRSecondTimer( void )           /* timer ISR (category 2)   */
{
  OSCURRENTISRPRIO_DEF;

  OSOrtiSetISRId( OSORTIISRSECONDTIMER );
  OSSecondClearFlag();
  OSEnterISR2();
#if defined(OSALARM)
  OSDI();
  OSCounterNotify( OSTIMER2 );
#endif                                  /* defined(OSALARM) */
  OSLeaveISR2();
}
#endif                                  /* OSNHWCTRS == 2 */

#else                                   /* defined(OSHWCOUNTER) */
#if defined(OSSYSTIMER)                 /* 1st system timer is SW */

/***************************************************************************
 * Function :   OSISRSystemTimer
 *
 * Description: ISR for system timer
 *
 * Returns: 
 *
 * Notes:       SW couner used
 *
 **************************************************************************/
#if !defined(OSWITHINTERRUPTLEVEL)
OSINTERRUPT void OSISRSystemTimer( void ) /* timer ISR (category 2)   */
#else                                   /* !defined(OSWITHINTERRUPTLEVEL) */
void OSISRSystemTimer( void )           /* timer ISR (category 2)   */
#endif                                  /* defined(OSISRDISPATCH) */
{
  OSCURRENTISRPRIO_DEF;

  OSOrtiSetISRId( OSORTIISRSYSTIMER );
  OSEnterISR2();
  OSDI();
  OSSysTimClearFlag();
  OSISRCounterTrigger( OSTIMER1 );
  OSLeaveISR2();
}

#if defined(OSWITHINTERRUPTLEVEL)
__declspec(interrupt) void OSisrSystemTimer()
{
#if defined(OSTIMFIT)
  OsSetTSR(OSTSR_FIS);
#else
  OsSetTSR(OSTSR_DIS);
#endif
  OSINTC_SSCIR4_7 = OSSYSSOFTINVOKE;
}
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) */

#endif                                  /* defined(OSSYSTIMER)  */
#endif                                  /* defined(OSHWCOUNTER) */

#if defined(OSSECONDSOFT)
/***************************************************************************
 * Function :   OSISRSecondTimer
 *
 * Description: ISR for 2nd system timer
 *
 * Returns: 
 *
 * Notes:       SW couner used
 *
 **************************************************************************/
#if !defined(OSWITHINTERRUPTLEVEL)
OSINTERRUPT void OSISRSecondTimer( void ) /* timer ISR (category 2)   */
#else
void OSISRSecondTimer( void )           /* timer ISR (category 2)   */
#endif
{
  OSCURRENTISRPRIO_DEF;

  OSOrtiSetISRId( OSORTIISRSECONDTIMER );

  OSEnterISR2();
  OSDI();
  OSSecondClearFlag();
  OSISRCounterTrigger( OSTIMER2 );
  OSLeaveISR2();
}

#if defined(OSWITHINTERRUPTLEVEL)
__declspec(interrupt) void OSisrSecondTimer()
{
#if defined(OSTIM2FIT)
  OsSetTSR(OSTSR_FIS);
#else
  OsSetTSR(OSTSR_DIS);
#endif
  OSINTC_SSCIR4_7 = OSSECSOFTINVOKE;
}

#endif                                  /* defined(OSWITHINTERRUPTLEVEL) */

#endif                                  /* defined(OSSECONDSOFT) */

#if defined(OSSYSTIMER)
/***************************************************************************
 * Function :   OSShutdownSystemTimer
 *
 * Description: disable all timer(s)
 *
 * Returns: 
 *
 * Notes:       only interrupts are disabled, timers are not stopped
 *
 **************************************************************************/

void OSShutdownSystemTimer( void )
{
#if defined(OSSECONDTIMER)
  OSSysTimerCancel( OSTIMER1 );
  OSSysTimStop();
  OSSysTimerCancel( OSTIMER2 );
  OSSecondStop();
#else                                   /* defined(OSSECONDTIMER) */
  OSSysTimerCancel( );
  OSSysTimStop();
#endif                                  /* defined(OSSECONDTIMER) */
}

/***************************************************************************
 * Function :   OSInitializeSystemTimer
 *
 * Description: initialize HW and start timer(s)
 *
 * Notes:       1. MPC55xx HW specific,
 *              2. called with interrupts disabled 
 *
 **************************************************************************/
void OSInitializeSystemTimer( void )
{
#if defined(OSTIMDEC)

  OSSETHID0( OSGETHID0() & ~(OSHID0_TBEN)); /* Time base disable */
  OsSetDECAR(OSTIMMODULO);              /* Write modulo value into the DEC Auto-reload register */
  OSDecTimerSet(OSTIMMODULO);
  OSSysTimClearFlag();                  /* clear interrupt flag  */
  OSSysTimEnableInt();
  OSSETHID0( OSGETHID0() | OSHID0_TBEN); /* Time base Enable */

#elif defined(OSTIMFIT)

  OSSETHID0( OSGETHID0() & ~(OSHID0_TBEN)); /* Time base disable */

  OsSetTCR(OsGetTCR() & ~(OSTCR_FIE | OSTCR_FP | OSTCR_FPEXT) ); /* Clear all FIT bits */

#if defined(OSTIMMODULO)
  OsSetTCR(OsGetTCR() | ((OSFITP << 24) | (OSFITPEXT << 13)) ); /* Set Fixed interval timer period */
#endif                                  /* defined(OSTIMMODULO) */

#if defined(OSWITHINTERRUPTLEVEL)
  OSSET_INT_PSRX(OSSYSSOFTINT, OSTIMPRIO); /* Set priority for Software setable interrupt for FIT */
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) */

  OsSetTCR(OsGetTCR() | (OSTCR_FIE) ); /* Enable FIT interrupts */

  OSSETHID0( OSGETHID0() | OSHID0_TBEN); /* Time base Enable */

#elif defined(OSTIMeMIOS)

  OSTimHWprepare();
  OSSysTimSetHW();
  OSSysTimRun();                        /* start system timer    */

#endif                                  /* System Timer HW */

#if defined(OSTIM2DEC)

  OSSETHID0( OSGETHID0() & ~(OSHID0_TBEN)); /* Time base disable */
  OsSetDECAR(OSTIM2MODULO);             /* Write modulo value into the DEC Auto-reload register */
  OSDecTimerSet(OSTIM2MODULO);
  OSSecondClearFlag();                  /* clear interrupt flag  */
  OSSecondEnableInt();
  OSSETHID0( OSGETHID0() | OSHID0_TBEN); /* Time base Enable */

#elif defined(OSTIM2FIT)

  OSSETHID0( OSGETHID0() & ~(OSHID0_TBEN)); /* Time base disable */

  OsSetTCR(OsGetTCR() & ~(OSTCR_FIE | OSTCR_FP | OSTCR_FPEXT) ); /* Clear all FIT bits */

#if defined(OSTIM2MODULO)
  OsSetTCR(OsGetTCR() | ((OSFITP << 24) | (OSFITPEXT << 13)) ); /* Set Fixed interval timer period */
#endif                                  /* defined(OSTIMMODULO) */

#if defined(OSWITHINTERRUPTLEVEL)
  OSSET_INT_PSRX(OSSECSOFTINT, OSTIM2PRIO); /* Set priority for Software setable interrupt for FIT */
#endif                                  /* defined(OSWITHINTERRUPTLEVEL) */

  OsSetTCR(OsGetTCR() | (OSTCR_FIE) ); /* Enable FIT interrupts */

  OSSETHID0( OSGETHID0() | OSHID0_TBEN); /* Time base Enable */

#elif defined(OSTIM2eMIOS)

  OSTim2HWprepare();
  OSSecondSetHW();
  OSSecondRun();                        /* start second timer    */

#endif                                  /* Second Timer HW */
}

#endif                                  /* defined(OSSYSTIMER) */

/* Public services */

/***************************************************************************
 * Function:    InitCounter
 *
 * Description: Set initial counter value
 *
 * algo: If Extended status
 *           Check call level
 *           Check counter signature and value for admissible limit
 *       Initilalize counter value with Start parameter
 *       Check linked alarms
 *       If there are expires alarms - dispatch task
 *
 * Returns: E_OK, E_ID, E_VALUE, E_CALLEVEL
 *
 * Notes:   1. If alarms are linked to this counter, then its state unchanged.
 *
 **************************************************************************/
StatusType InitCounter( CtrType ctrId, TickType value )
{
  OSOrtiSetServiceWatch( OSServiceId_InitCounter );
  /* set watch to this service */
#if defined(OSEXTSTATUS)
  if( ctrId > OSNCTRS )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_InitCounter, ctrId );
  }
  if( value > OsCounters[ctrId].info->maxallowedvalue )
  {                                     /* value is outside of admissible limit */
    OSRETERROR( E_OS_VALUE, OSServiceId_InitCounter, ctrId );
  }
#endif                                  /* defined(OSEXTSTATUS) */

#if defined(OSSWCOUNTER)
#if defined(OSHWCOUNTER)
  if( ctrId >= OSNHWCTRS )
#endif                                  /* defined(OSHWCOUNTER) */
  {
    OSSWCtrInit( ctrId, value);
  }
#endif                                  /* defined(OSSWCOUNTER) */

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
  else
#endif                                  /* defined(OSSWCOUNTER) */
  {
    OSHWCtrInit( ctrId, value);
  }
#endif                                  /* defined(OSHWCOUNTER) */

  OSOrtiServiceWatchOnExit( OSServiceId_InitCounter );
  return E_OK;
}

/***************************************************************************
 * Function:    GetCounterValue
 *
 * Description: Return counter value
 *
 * algo: If Extended status
 *           Check call level
 *           Check counter signature
 *       Return counter value
 *
 * Returns: E_OK, E_ID, E_CALLEVEL
 *
 * Notes:
 *
 **************************************************************************/
StatusType GetCounterValue( CtrType ctrId, TickRefType ticks )
{
  OSOrtiSetServiceWatch( OSServiceId_GetCounterValue );
  /* set watch to this service */
#if defined(OSEXTSTATUS)
  if( ctrId > OSNCTRS )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetCounterValue, ctrId );
  }
#endif                                  /* defined(OSEXTSTATUS) */

#if defined(OSSWCOUNTER)
#if defined(OSHWCOUNTER)
  if( ctrId >= OSNHWCTRS )
#endif                                  /* defined(OSHWCOUNTER) */
  {
    *ticks = OSSWCtrValue(ctrId);
  }
#endif                                  /* defined(OSSWCOUNTER) */

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
  else
#endif                                  /* defined(OSSWCOUNTER) */
  {
    *ticks = OSHWCtrValue(ctrId);
  }
#endif                                  /* defined(OSHWCOUNTER) */
  OSOrtiServiceWatchOnExit( OSServiceId_GetCounterValue );
  return E_OK;
}

/***************************************************************************
 * Function:    CounterTrigger
 *
 * Description: Increment counter value
 *
 * algo: If Extended status
 *           Check call level
 *           Check counter signature
 *       Calculate new counter value
 *       Check linked alarms
 *       If call at the task level and there are expired alarms  - dispath tasks
 *
 * Returns: E_OK, E_ID
 *
 * Notes:
 *
 **************************************************************************/
StatusType CounterTrigger( CtrType ctrId )
{

  OSUSETASK2READYCHECK
  OSIMSAVE                              /* OSINTMASKTYPE save;       */

  OSOrtiSetServiceWatch( OSServiceId_CounterTrigger );
  /* set watch to this service */
#if defined(OSEXTSTATUS)
  if( (ctrId > OSNCTRS )
#if defined(OSHWCOUNTER)
   || (ctrId < OSNHWCTRS)
#endif                                  /* defined(OSHWCOUNTER) */
   )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_CounterTrigger, ctrId );
  }
#endif                                  /* defined(OSEXTSTATUS) */

  OSDIS( save );
  OSOrtiSetOldServiceID( OSServiceId_CounterTrigger );

  if(OsCounters[ctrId].value == OsCounters[ctrId].info->maxallowedvalue )
  {
    OsCounters[ctrId].value = 0;
  }
  else
  {
    OsCounters[ctrId].value++;          /* increment counter value  */
  }

#if defined(OSALARM)
  OSPUTPARAM( OSServiceId_CounterTrigger, ctrId );
  OSCheckAlarms( ctrId );
  OSCLEARPARAM();
#endif                                  /* defined(OSALARM) */

  if((OSTask2ReadyCheck( OSTASKID(OsRunning) ) < 0)
#if defined(OSISRNORMAL)
   && (OsIsrLevel == 0 )
#endif                                  /* defined(OSISRNORMAL) */
   )
  {
    OSDISPATCH();
  }
  OSOrtiResetIdOnExit();
  OSRI( save );
  return E_OK;
}

/***************************************************************************
 * Function:    GetCounterInfo
 *
 * Description: Fill counter info structure
 *
 * algo: If Extended status
 *           Check call level
 *           Check counter signature
 *       Return counter info
 *
 * Returns: E_OK, E_ID, E_CALLEVEL
 *
 * Notes:
 *
 **************************************************************************/
StatusType GetCounterInfo( CtrType ctrId, CtrInfoRefType info )
{
  OSOrtiSetServiceWatch( OSServiceId_GetCounterInfo );
  /* set watch to this service */
#if defined(OSEXTSTATUS)
  if( ctrId > OSNCTRS )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetCounterInfo, ctrId );
  }
#endif                                  /* defined(OSEXTSTATUS) */

  /* Fill counter info structure */

  *info = OsCountersCfg[ctrId];
  OSOrtiServiceWatchOnExit( OSServiceId_GetCounterInfo );
  return E_OK;
}

#endif                                  /* defined(OSCOUNTER) */
