#define OSALM_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/osalm.c,v $
 * Author:       $Author: c-atroshikhin $
 * Revision:     $Revision: 1.20 $
 *
 * Functions:    
 *
 * History:      Use the CVS command rlog to display revision history
 *               information.
 *
 * Description:  Function code to support OSEK OS alarms 
 *
 * Notes:        
 *
 ******************************************************************************/

#if !defined(OSPROPH)
#include "osprop.h"                     /* OS Properties */
#else                                   /* !defined(OSPROPH)    */
#include OSPROPH                        /* OS Properties */
#endif                                  /* !defined(OSPROPH)    */

#include <osapi.h>

#if defined(OSHWCOUNTER) && defined(OSMPC5554) /* MPC5554 has 24-bit EMIOS timers */
#define OSCTRBITS(num) (TickType)(0x00FFFFFF & (num))
#else
#define OSCTRBITS(num) (TickType)(num)
#endif

#if defined(OSALARM)

/*  Global OS variables */

OSALMCB OsAlarms[OSNALMS];

/* local defines */
#define _ctr                            OsCounters[ctrId]
#define _ctrcfg                         OsCountersCfg[ctrId]
#define _almtask                        almId->taskId

/*  Private OS Services */

/***************************************************************************
 * Function:    OSNotifyAlarm
 *
 * Description: Check notification parameters of the alarm,
 *              and perform notification
 *
 * algo: IF      event mask is defined in the notification parameters
 *       THEN    set event for the task to be notified
 *               IF      scheduler ready-queues changed
 *               THEN    RETURN 1
 *               ENDIF
 *       ELSEIF  task is defined in the notification parameters
 *       THEN    activate task to be notified
 *               IF      scheduler ready-queues changed
 *               THEN    RETURN 1
 *               ENDIF
 *       ENDIF
 *       RETURN 0
 *
 * inp:  AlarmId - alarm identifier
 * call: OSChangeEvent, OSChangeTaskState
 *
 * Returns: 0 - no insertions into the scheduler ready queues
 *          <>0 - task was activated and/or (re)inserted into
 *                scheduler ready queues
 *
 * Notes:
 *
 **************************************************************************/
void OSNotifyAlarm( AlarmType almId )
{

#if defined(OSBCC)
  if( OSTASKACTEXHAUSTED(_almtask) )
  {
    OSErrorHook_noPar( E_OS_LIMIT );    /* attempt to multiply activation */
  }
  else
  {
    {
#if defined(OSCC2) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) || defined(OSINRES)
      OSTASKSTATUS(_almtask) |= OSTCBSTART;
#endif                                  /* defined(OSCC2) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) || defined(OSINRES) */
      OSTask2Ready( _almtask );
    }
  }

#elif defined(OSECC)

#if OSNXTSKS > 0
#if defined(OSALMSETEVENT)
  if( almId->event )
  {
    if( (OSTASKSTATUS(_almtask) & OSTCBNOSUSPENDED) == 0 )
    {
      OSErrorHook_noPar( E_OS_STATE ); /* the task is in a suspended state */
    }
    else
    {
      OSSetEvent( &OsTaskTable[_almtask], almId->event );
    }
    return;
  }
  else
#endif                                  /* defined(OSALMSETEVENT) */
  {
    if( OSTASKACTEXHAUSTED(_almtask) )
    {
      OSErrorHook_noPar( E_OS_LIMIT ); /* attempt to multiply activation */
    }
    else
    {                                   /* set flag that task has no valid context  yet */
#if OSNXTSKS > 0
      if( (OSTASKSTATUS(_almtask) & OSTCBEXTENDED) != 0 )
      {
        OsTaskTable[_almtask].set_event = OSNOEVENTS;
      }
#endif                                  /* OSNXTSKS > 0 */
      {
        OSTASKSTATUS(_almtask) |= OSTCBSTART;
        OSTask2Ready( _almtask );
      }
    }
  }
  return;
#else                                   /* OSNXTSKS > 0     */
  if( OSTASKACTEXHAUSTED(_almtask) )
  {
    OSErrorHook_noPar( E_OS_LIMIT );    /* attempt to multiply activation */
  }
  else
  {                                     /* set flag that task has no valid context yet */
    {
      OSTASKSTATUS(_almtask) |= OSTCBSTART;
      OSTask2Ready( _almtask );
    }
  }
#endif                                  /* OSNXTSKS > 0     */
#endif                                  /* defined(OSECC)  */
  return;
}

#if defined(OSHWCOUNTER)

/***************************************************************************
 * Function :   OSCounterNotify
 *
 * Description: check for expiried alarms and perform appropriate actions
 *
 * Returns:
 *
 * Notes:       1. called only if at least one alarm expired.
 *              2. this is intended for alarms on "HW" counters only
 *
 **************************************************************************/
void OSCounterNotify( CtrType ctrId )
{

  AlarmType almId;                      /* current alarm        */
  AlarmType *almRef;                    /* temporary pointer    */
  TickType minVal;

 again:

  OsTimVal = OSHWCtrGetOC( ctrId );     /* set osTimVal */
  minVal = OsTimVal - 1;
  almRef = &(_ctr.alarm);

  do{
    if( (*almRef)->delta == OSHWCtrGetOC( ctrId ) )
    {
      almId = *almRef;

#if defined(OSALMCALLBACK)
      if( almId->callBack )
      {
        almId->callBack();
      }
      else
      {
#endif                                  /* defined(OSALMCALLBACK) */
        OSNotifyAlarm( almId );         /* perform alarm action                             */
#if defined(OSALMCALLBACK)
      }
#endif                                  /* defined(OSALMCALLBACK) */

      if( almId->cycle == 0 )
      {                                 /* remove alarm from list if it is not cyclic */
        (almId->prev)->next = almId->next;
        if( almId->next != OSALMCBPTR0 ) /* Is it the last alarm in the list ?   */
        {
          (almId->next)->prev = almId->prev;
        }
        almId->prev = OSALMCBPTR0;      /* It is necessary for check E_OS_STATE */
      }
      else
      {                                 /* reinsert alarm if it is cyclic       */
        almId->delta = OSCTRBITS(almId->delta + almId->cycle);
        if( OSCTRBITS( almId->delta - OsTimVal ) < OSCTRBITS( minVal - OsTimVal
          ) )
        {
          minVal = almId->delta;
        }
        almRef = &(*almRef)->next;
      }
    }
    else
    {
      if( OSCTRBITS( (*almRef)->delta - OsTimVal ) < OSCTRBITS( minVal -
        OsTimVal ) )
      {
        minVal = (*almRef)->delta;
      }
      almRef = &(*almRef)->next;
    }
  }while( *almRef != OSALM0 );

  if( _ctr.alarm != OSALM0 )
  {                                     /* arm counter if there are attached alarms */
    OSHWCtrArm( ctrId, minVal );

    if( OSCTRBITS(OSHWCtrValue( ctrId ) - OsTimVal) >=
     OSCTRBITS(OSHWCtrGetOC( ctrId ) - OsTimVal) ) /* if new alarm already expiried            */
    {
      OSHWCtrCancel( ctrId );           /* disable interrupt and clear channel flag */
      goto again;                       /* repeat notification                      */
    }
  }
  else
  {                                     /* otherwise inform it that no more alarms  */
    OSHWCtrCancel( ctrId );
  }
}
#endif                                  /* defined(OSHWCOUNTER) */

/***************************************************************************
 * Function:    OSCheckAlarms
 *
 * Description: Check linked alarms
 *
 * algo:  If alarm expires either task activation
 *        or event signalling is performed in
 *        accordance with notification parameters
 *
 * Returns:
 *
 * Notes:
 *
 *
 **************************************************************************/
void OSCheckAlarms( CtrType ctrId )
{

  AlarmType almId;                      /* current alarm        */
  OSBYTE dispFlag;                      /* flag saying that dispatch is needed  */

  dispFlag = 0;

  almId = _ctr.alarm;
  while( almId != OSALMCBPTR0 )
  {
    if( almId->delta == _ctr.value )
    {
#if defined(OSALMCALLBACK)
      if( almId->callBack )
      {
        almId->callBack();
      }
      else
      {
#endif                                  /* defined(OSALMCALLBACK) */
        OSNotifyAlarm( almId );         /* perform alarm action                             */
#if defined(OSALMCALLBACK)
      }
#endif                                  /* defined(OSALMCALLBACK) */
      if( almId->cycle == 0 )
      {                                 /* remove alarm from list if it is not cyclic */
        (almId->prev)->next = almId->next;
        if( almId->next != OSALMCBPTR0 ) /* Is it alarme last in the list ? */
        {
          (almId->next)->prev = almId->prev;
        }
        almId->prev = OSALMCBPTR0;      /* It is necessary for check E_OS_STATE */
      }
      else
      {
        almId->delta = _ctr.value + almId->cycle; /* reinsert alarm if it is cyclic   */
        if( almId->delta > OsCountersCfg[almId->ctrId].maxallowedvalue )
        {
          almId->delta -= OsCountersCfg[almId->ctrId].maxallowedvalue + 1;
        }
      }
    }
    almId = almId->next;
  }
}

/***************************************************************************
 * Function: GetAlarmBase
 *
 * Description: Get the alarm base characteristics
 *
 * algo:    If extended status:
 *              Check the alarm signature
 *          Return counter info
 *
 * Returns: E_OK    no errors
 *          E_OS_ID    (ext.status) the identifier is invalid
 *
 * Notes:
 **************************************************************************/

StatusType GetAlarmBase( AlarmType almId, AlarmBaseRefType info )
{

  CtrType ctrId;

#if defined(OSEXTSTATUS)
  OSSIGNEDDWORD i;

  OSOrtiSetServiceWatch( OSServiceId_GetAlarmBase );
  /* set watch to this service */
  for( i = 0; i < OSNALMS; i++ )
  {
    if( almId == &OsAlarms[i] )
    {
      break;
    }
  }
  if( i == OSNALMS )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetAlarmBase, almId );
  }
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_GetAlarmBase );
  /* set watch to this service */
#endif                                  /* defined(OSEXTSTATUS) */

  ctrId = almId->ctrId;

  info->maxallowedvalue = _ctr.info->maxallowedvalue;

  info->ticksperbase = _ctr.info->ticksperbase;

#if defined(OSEXTSTATUS)
  info->mincycle = _ctr.info->mincycle;
#endif                                  /* defined(OSEXTSTATUS) */

  OSOrtiServiceWatchOnExit( OSServiceId_GetAlarmBase );
  return E_OK;
}

/***************************************************************************
 * Function: GetAlarm
 *
 * Description: Get the number of tick before alarm expires
 *
 * algo:    If extended status:
 *              Check the alarm signature
 *          Check the alarm state
 *          Calculate the number of tick before alarm expires
 *
 * Returns: E_OK, E_OS_NOFUNC, E_OS_ID
 *
 * Notes:
 *
 **************************************************************************/

StatusType GetAlarm( AlarmType almId, TickRefType tick )
{

  CtrType ctrId;
  OSIMSAVE                              /* OSINTMASKTYPE save;       */
#if defined(OSEXTSTATUS)
  OSSIGNEDDWORD i;

  OSOrtiSetServiceWatch( OSServiceId_GetAlarm ); /* set watch to this service */

  ctrId = almId->ctrId;
  for( i = 0; i < OSNALMS; i++ )
  {
    if( almId == &OsAlarms[i] )
    {
      break;
    }
  }
  if( i == OSNALMS )
  {                                     /* invalid ID */
    OSRETERROR( E_OS_ID, OSServiceId_GetAlarm, almId );
  }
#else                                   /* defined(OSEXTSTATUS) */
  OSOrtiSetServiceWatch( OSServiceId_GetAlarm ); /* set watch to this service */

  ctrId = almId->ctrId;
#endif                                  /* defined(OSEXTSTATUS) */
  if( almId->prev == OSALMCBPTR0 )      /* Alarm is not linked in the list - not used alarm */
  {                                     /* The alarm is not used */
    OSRETERROR( E_OS_NOFUNC, OSServiceId_GetAlarm, almId );
  }

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

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
  else
#endif                                  /* defined(OSSWCOUNTER) */
  {
    *tick = OSHWCtrValue(ctrId);
  }
#endif                                  /* defined(OSHWCOUNTER) */
  if( almId->delta >= *tick )
  {
    *tick = almId->delta - *tick;
  }
  else
  {
    *tick = almId->delta + _ctr.info->maxallowedvalue + 1 - *tick;
  }

  OSRI( save );

  OSOrtiServiceWatchOnExit( OSServiceId_GetAlarm );
  return( E_OK );
}

/***************************************************************************
 * Function :   OSSetAlarm
 *
 * Description: Insert alarm into list attached to counter,
 *              arm HW counter if it is the first alarm.
 *
 * Returns:
 *
 * Notes:       called with interrupts disabled
 *
 **************************************************************************/

void OSSetAlarm( AlarmType almId, TickType start, TickType cycle )
{

  CtrType ctrId;

  OSUSETASK2READYCHECK

  ctrId = almId->ctrId;

  /*********** insert alarm into list **************/
  almId->delta = start;
  almId->cycle = cycle;

  almId->next = _ctr.alarm;             /* Alarm is linked into head of the list */
  _ctr.alarm = almId;
  almId->prev = (AlarmType)(&(_ctr.alarm)); /* The counter node is previous for first in list */
  if( almId->next != OSALMCBPTR0 )      /* There are already alarms in the list */
  {
    ( almId->next )->prev = almId;
  }

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
  if( ctrId < OSNHWCTRS )
#endif                                  /* defined(OSSWCOUNTER) */
  {
    if( (almId->next == OSALMCBPTR0) ||
     (OSCTRBITS( OSHWCtrGetOC( ctrId ) - OsTimVal) > OSCTRBITS(start - OsTimVal)
      ) )
    {                                   /* if new HW alarm is the first to expire */
      OSHWCtrArm( ctrId, start );       /* then arm it */
    }
    /* check if alarm(s) just expiried */
    if( OSCTRBITS( OSHWCtrValue( ctrId ) - OsTimVal ) >= OSCTRBITS(
      OSHWCtrGetOC( ctrId ) - OsTimVal ) )
    {
      OSCounterNotify( ctrId );
    }
  }
#if defined(OSSWCOUNTER)
  else
#endif                                  /* defined(OSSWCOUNTER) */
#endif                                  /* defined(OSHWCOUNTER) */

#if defined(OSSWCOUNTER)
  {
    if( start == OSSWCtrValue( ctrId ) )
    {
      OSCheckAlarms( ctrId );
    }
  }
#endif                                  /* defined(OSSWCOUNTER) */

  OSCLEARPARAM();
#if defined(OSECC) || defined(OSRESOURCE) || defined(OSBCC2) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE)
  if((OSTask2ReadyCheck( OsRunning->taskId ) < 0)
#else
   if((OSTask2ReadyCheck( OsRunning ) < 0)
#endif
#if defined(OSISRNORMAL)
    && (OsIsrLevel == 0 )
#endif                                  /* defined(OSISRNORMAL) */
    )
   {
     OSDISPATCH();
   }
   return;
 }

#if defined(OSNAUTOALMS)
 /***************************************************************************
  * Function :   OSInitAutoAlarms
  *
  * Description: Initialize autostarted alarms
  *
  * Notes:       used only by OSStartUp
  *
  **************************************************************************/
#if (OSNAPPMODES > 1)
 void OSInitAutoAlarms(AppModeType mode)
#else                                   /* (OSNAPPMODES > 1) */
 void OSInitAutoAlarms()
#endif                                  /* (OSNAPPMODES > 1) */
 {
   OSCARDINAL i;
   CtrType ctrId;
   AlarmType almId;
   TickType start;
   TickType cycle;

   for( i = 0; i < OSNAUTOALMS; i++ )
   {
#if (OSNAPPMODES > 1)
     if( (OsAutoAlarms[i].autostart & (1 << mode)) != 0 )
     {
#endif                                  /* (OSNAPPMODES > 1) */
       almId = OsAutoAlarms[i].almId;
       ctrId = almId->ctrId;
       start = OsAutoAlarms[i].time;
       cycle = OsAutoAlarms[i].cycle;

#if defined(OSSWCOUNTER)
#if defined(OSHWCOUNTER)
       if( ctrId >= OSNHWCTRS )
#endif                                  /* defined(OSHWCOUNTER) */
       {
         if( (OsCountersCfg[ctrId].maxallowedvalue - OSSWCtrValue(ctrId)) <
          start )
         {
           start -= (OsCountersCfg[ctrId].maxallowedvalue - OSSWCtrValue(ctrId)
            + 1);
         }
         else
         {
           start += OSSWCtrValue(ctrId);
         }
       }
#endif                                  /* defined(OSSWCOUNTER) */

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
       else
#endif                                  /* defined(OSSWCOUNTER) */
       {
         OsTimVal = OSHWCtrValue( ctrId );
         /* set OsTimValue to the current counter value  */

         if( (OsCounters[ctrId].alarm != OSALM0) && OSInterruptRaised( ctrId ) )
         {                              /* if there was an alarm                        */
           /* and HW counter has crossed old OC value      */
           OsTimVal = OSHWCtrGetOC( ctrId );
           /* set OsTimValue to the current value of the OC register */
           /* to achive valid comparision in OsSetAlarm */
           start += OSHWCtrValue( ctrId );
         }
         else
         {
           start += OsTimVal;
         }
       }
#endif                                  /* defined(OSHWCOUNTER) */
       /*********** insert alarm into list **************/
       almId->delta = start;
       almId->cycle = cycle;

       almId->next = OsCounters[ctrId].alarm; /* Alarm is linked into head of the list */
       OsCounters[ctrId].alarm = almId;
       almId->prev = (AlarmType)(&(OsCounters[ctrId].alarm)); /* The counter node is previous for first in list */
       if( almId->next != OSALMCBPTR0 ) /* There are already alarms in the list */
       {
         ( almId->next )->prev = almId;
       }

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
       if( ctrId < OSNHWCTRS )
#endif                                  /* defined(OSSWCOUNTER) */
       {
         if( (almId->next == OSALMCBPTR0) ||
          (OSCTRBITS( OSHWCtrGetOC( ctrId ) - OsTimVal) > OSCTRBITS( start -
            OsTimVal) ) )
         {                              /* if new HW alarm is the first to expire */
           OSHWCtrArm( ctrId, start ); /* then arm it */
         }
         /* check if alarm(s) just expiried */
         if( OSCTRBITS( OSHWCtrValue( ctrId ) - OsTimVal ) >= OSCTRBITS(
           OSHWCtrGetOC( ctrId ) - OsTimVal ) )
         {
           OSCounterNotify( ctrId );
         }
       }
#if defined(OSSWCOUNTER)
       else
#endif                                  /* defined(OSSWCOUNTER) */
#endif                                  /* defined(OSHWCOUNTER) */

#if defined(OSSWCOUNTER)
       {
         if( start == OSSWCtrValue( ctrId ) )
         {
           OSCheckAlarms( ctrId );
         }
       }
#endif                                  /* defined(OSSWCOUNTER) */

#if (OSNAPPMODES > 1)
     }
#endif                                  /* (OSNAPPMODES > 1) */
   }
 }
#endif                                  /* defined(OSNAUTOALMS) */

 /***************************************************************************
  * Function: SetRelAlarm
  *
  * Description: Start the relative alarm
  *
  * algo:    If extended status:
  *              Check the alarm signature
  *          Check the alarm state
  *          If extended status:
  *              Check the alarm start and cycle value
  *          store initial and cycle value in the alarm node
  *          next alarm into counter list
  *
  * Returns: E_OK, E_OS_STATE, E_OS_ID, E_OS_VALUE
  *
  * Notes:
  *
  **************************************************************************/
 StatusType SetRelAlarm( AlarmType almId, TickType increment, TickType cycle )
 {

   CtrType ctrId;
   OSIMSAVE                             /* OSINTMASKTYPE save;       */
#if defined(OSEXTSTATUS)
   OSSIGNEDDWORD i;

   OSOrtiSetServiceWatch( OSServiceId_SetRelAlarm );
   /* set watch to this service */
   for( i = 0; i < OSNALMS; i++ )
   {
     if( almId == &OsAlarms[i] )
     {
       break;
     }
   }
   if( i == OSNALMS )
   {                                    /* invalid ID */
     OSRETERROR( E_OS_ID, OSServiceId_SetRelAlarm, almId );
   }
#else                                   /* defined(OSEXTSTATUS) */
   OSOrtiSetServiceWatch( OSServiceId_SetRelAlarm );
   /* set watch to this service */
#endif                                  /* defined(OSEXTSTATUS) */
   ctrId = almId->ctrId;

#if defined(OSEXTSTATUS)
   /* Check initial value and cycle value */
   if( increment > _ctrcfg.maxallowedvalue )
   {                                    /* increment value is outside of admissible limit */
     OSRETERROR( E_OS_VALUE, OSServiceId_SetRelAlarm, almId );
   }
   if( (cycle != 0) && ( (cycle > _ctrcfg.maxallowedvalue || (cycle <
       _ctrcfg.mincycle) ) ) )
   {                                    /* cycle value is outside of admissible limit */
     OSRETERROR( E_OS_VALUE, OSServiceId_SetRelAlarm, almId );
   }
#endif                                  /* defined(OSEXTSTATUS) */
   /* Check state of the alarm */
   if( almId->prev != OSALMCBPTR0 )     /* Alarm is linked in the list - running alarm */
   {                                    /* The alarm is already in use */
     OSRETERROR( E_OS_STATE, OSServiceId_SetRelAlarm, almId );
   }

   OSDIS( save );
   OSOrtiSetOldServiceID( OSServiceId_SetRelAlarm );

#if defined(OSSWCOUNTER)
#if defined(OSHWCOUNTER)
   if( ctrId >= OSNHWCTRS )
#endif                                  /* defined(OSHWCOUNTER) */
   {
     if( (_ctrcfg.maxallowedvalue - OSSWCtrValue(ctrId)) < increment )
     {
       increment -= (_ctrcfg.maxallowedvalue - OSSWCtrValue(ctrId) + 1);
     }
     else
     {
       increment += OSSWCtrValue(ctrId);
     }
   }
#endif                                  /* defined(OSSWCOUNTER) */

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
   else
#endif                                  /* defined(OSSWCOUNTER) */
   {
     OsTimVal = OSHWCtrValue( ctrId );
     /* set OsTimValue to the current counter value  */

     if( (_ctr.alarm != OSALM0) && OSInterruptRaised( ctrId ) )
     {                                  /* if there was an alarm                        */
       /* and HW counter has crossed old OC value      */
       OsTimVal = OSHWCtrGetOC( ctrId );
       /* set OsTimValue to the current value of the OC register */
       /* to achive valid comparision in OsSetAlarm */
       increment += OSHWCtrValue( ctrId );
     }
     else
     {
       increment += OsTimVal;
     }
   }
#endif                                  /* defined(OSHWCOUNTER) */

   OSPUTPARAM( OSServiceId_SetRelAlarm, almId );
   OSSetAlarm( almId, OSCTRBITS(increment), cycle );

   OSOrtiResetIdOnExit();
   OSRI( save );
   return( E_OK );
 }

 /***************************************************************************
  * Function: SetAbsAlarm
  *
  * Description: Start the alarm
  *
  * algo:    If extended status:
  *              Check the alarm signature
  *          Check the alarm state
  *          If extended status:
  *              Check the alarm start and cycle value
  *          calculate initial tick for absolute alarm
  *          store initial and cycle value in the alarm node
  *          link alarm into counter list
  *
  * Returns: E_OK, E_OS_STATE, E_OS_ID, E_OS_VALUE
  *
  * Notes:
  *
  **************************************************************************/
 StatusType SetAbsAlarm( AlarmType almId, TickType start, TickType cycle )
 {

   CtrType ctrId;
   OSIMSAVE                             /* OSINTMASKTYPE save;       */
#if defined(OSEXTSTATUS)
   OSSIGNEDDWORD i;

   OSOrtiSetServiceWatch( OSServiceId_SetAbsAlarm );
   /* set watch to this service */
   for( i = 0; i < OSNALMS; i++ )
   {
     if( almId == &OsAlarms[i] )
     {
       break;
     }
   }
   if( i == OSNALMS )
   {                                    /* invalid ID */
     OSRETERROR( E_OS_ID, OSServiceId_SetAbsAlarm, almId );
   }
#else                                   /* defined(OSEXTSTATUS) */
   OSOrtiSetServiceWatch( OSServiceId_SetAbsAlarm );
   /* set watch to this service */
#endif                                  /* defined(OSEXTSTATUS) */
   ctrId = almId->ctrId;
#if defined(OSEXTSTATUS)

   /* Check initial value and cycle value */
   if( start > _ctrcfg.maxallowedvalue )
   {                                    /* start value is outside of admissible limit */
     OSRETERROR( E_OS_VALUE, OSServiceId_SetAbsAlarm, almId );
   }
   if( ( cycle != 0 ) && ( (cycle > _ctrcfg.maxallowedvalue || (cycle <
       _ctrcfg.mincycle) ) ) )
   {                                    /* cycle value is outside of admissible limit */
     OSRETERROR( E_OS_VALUE, OSServiceId_SetAbsAlarm, almId );
   }
#endif                                  /* defined(OSEXTSTATUS) */
   /* Check state of the alarm */
   if( almId->prev != OSALMCBPTR0 )     /* Alarm is linked in the list - running alarm */
   {                                    /* The alarm is already in use */
     OSRETERROR( E_OS_STATE, OSServiceId_SetAbsAlarm, almId );
   }

   OSDIS( save );
   OSOrtiSetOldServiceID( OSServiceId_SetAbsAlarm );

#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
   if( ctrId < OSNHWCTRS )
#endif                                  /*  defined(OSSWCOUNTER) */
   {
     OsTimVal = OSHWCtrValue( ctrId );
     /* set OsTimValue to the current counter value  */
     if( OsCounters[ctrId].alarm != OSALM0 )
     {                                  /* if there was an alarm                        */
       if( OSInterruptRaised( ctrId ) )
       /* and HW counter has crossed old OC value      */
       {
         OsTimVal = OSHWCtrGetOC( ctrId );
         /* set OsTimValue to the current value of the OC register */
       }                                /* to achive valid comparision in OsSetAlarm */
     }
   }

#endif                                  /* defined(OSHWCOUNTER) */

   OSPUTPARAM( OSServiceId_SetAbsAlarm, almId );
   OSSetAlarm( almId, start, cycle );

   OSOrtiResetIdOnExit();
   OSRI( save );

   return( E_OK );
 }

 /***************************************************************************
  * Function: CancelAlarm
  *
  * Description: Stop the alarm
  *
  * algo:    If extended status:
  *              Check the alarm signature
  *          Check the alarm state
  *          unnext alarm from counter list
  *
  * Returns: E_OK, E_OS_NOFUNC, E_OS_ID
  *
  * Notes:
  *
  **************************************************************************/
 StatusType CancelAlarm( AlarmType almId )
 {

   CtrType ctrId;
   AlarmType almRef;
   AlarmType min = OSALMCBPTR0;
   OSUSETASK2READYCHECK
   OSIMSAVE                             /* OSINTMASKTYPE save;       */

#if defined(OSEXTSTATUS)
   OSSIGNEDDWORD i;

   OSOrtiSetServiceWatch( OSServiceId_CancelAlarm );
   /* set watch to this service */
   for( i = 0; i < OSNALMS; i++ )
   {
     if( almId == &OsAlarms[i] )
     {
       break;
     }
   }
   if( i == OSNALMS )
   {                                    /* invalid ID */
     OSRETERROR( E_OS_ID, OSServiceId_CancelAlarm, almId );
   }
#else                                   /* defined(OSEXTSTATUS) */
   OSOrtiSetServiceWatch( OSServiceId_CancelAlarm );
   /* set watch to this service */
#endif                                  /* defined(OSEXTSTATUS) */

   ctrId = almId->ctrId;

   OSDIS( save );
   OSOrtiSetOldServiceID( OSServiceId_CancelAlarm );

   if( almId->prev == OSALMCBPTR0 )     /* Alarm is not used                */
   {                                    /* The alarm is not used            */
     OSRI( save );                      /* attempt to multiply deactivation */
     OSRETERROR( E_OS_NOFUNC, OSServiceId_CancelAlarm, almId );
   }

   (almId->prev)->next = almId->next;
   if( almId->next != OSALMCBPTR0 )     /* Is this alarm last in the list ? */
   {
     (almId->next)->prev = almId->prev;
   }
#if defined(OSHWCOUNTER)
#if defined(OSSWCOUNTER)
   if( ctrId < OSNHWCTRS )
#endif                                  /* defined(OSSWCOUNTER) */
   {
     almId->prev = OSALMCBPTR0;         /* It is necessary for check E_OS_STATE */
     OsTimVal = OSHWCtrGetOC( ctrId ); /* set osTimVal */
     if( _ctr.alarm == OSALM0 )
     {                                  /* if there are no more alarms on HW counter */
       OSHWCtrCancel( ctrId );          /* then cancel it */
     }
     else
     {                                  /* reArm counter and check for expiried alarms */
       almRef = _ctr.alarm;
       do{
         if( ( min == OSALMCBPTR0 ) ||
          ( OSCTRBITS( min->delta - OsTimVal ) > OSCTRBITS( almRef->delta -
            OsTimVal ) ) )
         {
           min = almRef;
         }
         almRef = almRef->next;
       }while( almRef != OSALM0 );

       if( min->delta != OSHWCtrGetOC( ctrId ) )
       {
         OsTimVal = OSHWCtrValue( ctrId ); /* set OsTimVal the current counter value */
         if( OSInterruptRaised( ctrId ) ) /* Interrupt raised since last OSDI() */
         {
           OsTimVal = OSHWCtrGetOC( ctrId ); /* set OsTimVal the current value of the OC register */
         }
         OSHWCtrArm( ctrId, min->delta );
         /* if new alarm already expiried  */
         if( OSCTRBITS( OSHWCtrValue( ctrId ) - OsTimVal ) >= OSCTRBITS(
           OSHWCtrGetOC( ctrId ) - OsTimVal ) )
         {
           OSPUTPARAM( OSServiceId_CancelAlarm, almId );
           OSCounterNotify( ctrId );
           OSCLEARPARAM();

#if defined(OSECC) || defined(OSRESOURCE) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE)
           if( (OSTask2ReadyCheck( OsRunning->taskId ) < 0 )
#else
            if( (OSTask2ReadyCheck( OsRunning ) < 0 )
#endif
#if defined(OSISRNORMAL)
             && (OsIsrLevel == 0 )
#endif                                  /* defined(OSISRNORMAL) */
             )
            {
              OSDISPATCH();
            }
          }
        }
      }
    }
#if defined(OSSWCOUNTER)
    else
#endif                                  /* defined(OSSWCOUNTER) */
#endif                                  /* defined(OSHWCOUNTER) */
    {
      almId->prev = OSALMCBPTR0;        /* It is necessary for check E_OS_STATE */
    }
    OSOrtiResetIdOnExit();
    OSRI( save );

    return( E_OK );
  }

#endif                                  /* defined(OSALARM) */

#if defined(OSTIMESCALE)

  const OSTIMESTEP *OsTimeStep;

  /***************************************************************************
   * Function: OSProcessTimeScale
   *
   * Description: Activate next task in Time Scale
   *
   * Returns: 
   *
   * Notes:
   *
   **************************************************************************/
  void OSProcessTimeScale( void )
  {

   again:

    if( OSTASKACTEXHAUSTED(OsTimeStep->taskId) )
    {
      OSErrorHook_noPar( E_OS_LIMIT ); /* attempt to multiply activation */
    }
    else
    {                                   /* set flag that task has no valid context yet */
#if OSNXTSKS > 0
      if( (OSTASKSTATUS(OsTimeStep->taskId) & OSTCBEXTENDED) != 0 )
      {
        OsTaskTable[OsTimeStep->taskId].set_event = OSNOEVENTS;
      }
#endif                                  /* OSNXTSKS > 0 */
      {
#if defined(OSCC2) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) || defined(OSINRES)
        OSTASKSTATUS(OsTimeStep->taskId) |= OSTCBSTART;
#endif                                  /* defined(OSCC2) || defined(OSEXTSTATUS) || defined(OSNOFASTTERMINATE) || defined(OSINRES) */
        OSTask2Ready( OsTimeStep->taskId );
      }
    }
    /* arm timer */
    OsTimVal = OSHWCtrGetOC( OSTIMER1 );
    OSHWCtrArm( OSTIMER1, OsTimVal + OsTimeStep->delta );

    OsTimeStep = OsTimeStep->next;
    /* if new alarm already expiried  */
    if( OSCTRBITS( OSHWCtrValue( OSTIMER1 ) - OsTimVal ) >= OSCTRBITS(
      OSHWCtrGetOC( OSTIMER1 ) - OsTimVal ) )
    {
      OSHWCtrCancel( OSTIMER1 );        /* disable interrupt and clear channel flag */
      goto again;                       /* repeat notification                      */
    }
  }

  /***************************************************************************
   * Function: StartTimeScale
   *
   * Description: Start Time Scale processing
   *
   * Returns: 
   *
   * Notes:
   *
   **************************************************************************/
  void StartTimeScale( void )
  {
    OSIMSAVE                            /* OSINTMASKTYPE save;      */
    OSOrtiSetServiceWatch( OSServiceId_StartTimeScale );
    /* set watch to this service */
    OSDIS( save );

    OSOrtiSetOldServiceID( OSServiceId_StartTimeScale );
    OSPUTPARAM( OSServiceId_StartTimeScale, 0 );

    OsTimeStep = &OsSteps[0];           /* set first point to proceed   */
    OSHWCtrArm( OSTIMER1, OSHWCtrValue( OSTIMER1 ) ); /* set OC register              */

    OSSysTimClearFlag();                /* clear output compare interrupt flag  */
    OSProcessTimeScale();               /* process TimeScale as in ISR          */

    OSCLEARPARAM();

    if( ( OSGETMAXPRIOTASK != OsRunning ) /* if task of higher prio was moved to READY   */
#if defined(OSISRENTRYEXIT)
     && ( OsIsrLevel == 0 )             /* and it is the task-level call: call dispatcher */
#endif                                  /* defined(OSISRENTRYEXIT) */
     )
    {
      OSDISPATCH();
    }

    OSRI(save);
    OSOrtiResetIdOnExit();
  }

#endif                                  /* defined(OSTIMESCALE) */

