#define OSEVT_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/osevt.c,v $
 * Author:       $Author: c-atroshikhin $
 * Revision:     $Revision: 1.9 $
 *
 * Functions:    
 *
 * History:      Use the CVS command rlog to display revision history
 *               information.
 *
 * Description:  OSEK OS event control   
 *
 * Notes:        
 *
 ******************************************************************************/

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

#include <osapi.h>

/*  Global OS variables */

/*  Private OS Services */

#if defined(OSECC) && (OSNXTSKS > 0)

/***************************************************************************
 * Function : OSSetEvent
 *
 * Description: set event and moves Task to Ready state
 *
 * Returns: none / Scheduler State ( Dispatch is necessary or not )
 *
 * Notes:   return >0 if task is transformed to ready state &
 *          dispatch is necessary else 0(OSEVTWAIT)
 *
 **************************************************************************/

#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
OSSIGNEDDWORD OSSetEvent(OSTSKCBPTR task, EventMaskType mask)
{
  OSUSETASK2READYCHECK
#else                                   /* OSNOPREEMPT */
  void OSSetEvent(OSTSKCBPTR task, EventMaskType mask)
  {
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */
    task->set_event |= (EventMaskType)(mask);

    if( ( task->status & OSTCBWAIT ) != 0 )
    {
      if( ( task->wait_event & task->set_event) != 0 ) /* Any event is occured */
      {
        task->status &= (OSBYTE)(~OSTCBWAIT); /* Status is not waiting */

#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
        return OSTask2ReadyCheck( task->taskId );
#else                                   /* OSNOPREEMPT */
        OSTask2Ready( task->taskId );
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */
      }
    }
#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
    return OSEVTWAIT;
#else                                   /* OSNOPREEMPT */
    return;
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */
  }

  /*  Public OS Services  */

  /***************************************************************************
   * Function : SetEvent
   *
   * Description: set event and performs dispatching if nessesary
   *
   * inp:         taskID  - task for which event is set
   *              mask    - event mask to set
   *
   * Returns: E_OK                    no errors
   *          E_OS_ID       (ext.status) the identifier is invalid
   *          E_OS_ACCESS   (ext.status) the task is the basic task (not extended)
   *          E_OS_STATE    (ext.status) the task is in suspended state
   *
   * Notes:
   *
   **************************************************************************/

  StatusType SetEvent( TaskType taskId, EventMaskType mask )
  {
    OSIMSAVE                            /* OSINTMASKTYPE save;       */

    OSTSKCB* task_cb = &OsTaskTable[taskId];

    OSOrtiSetServiceWatch( OSServiceId_SetEvent );
    /* set watch to this service */
#if defined(OSEXTSTATUS)
    if( OSTASKIDISINVALID )
    {                                   /* invalid ID */
      OSRETERROR( E_OS_ID, OSServiceId_SetEvent, taskId );
    }
    if( (task_cb->status & OSTSKEXTENDED) == 0 )
    {                                   /* it isn't an extended task */
      OSRETERROR( E_OS_ACCESS, OSServiceId_SetEvent, taskId );
    }
#endif                                  /* defined(OSEXTSTATUS) */
    if( ( task_cb->status & OSTCBNOSUSPENDED ) == 0 )
    {
#if defined(OSEXTSTATUS)                /* the task is in a suspended state */
      OSRETERROR( E_OS_STATE, OSServiceId_SetEvent, taskId );
#else                                   /* defined(OSEXTSTATUS) */
      OSOrtiServiceWatchOnExit( OSServiceId_SetEvent );
      return ( E_OK );
#endif                                  /* defined(OSEXTSTATUS) */
    }

    OSDIS( save );
    OSOrtiSetOldServiceID( OSServiceId_SetEvent );
#if defined(OSISRENTRYEXIT)
    if( OsIsrLevel != OSISRLEVEL0 )
    {
      OSSetEventCast2Void(task_cb, mask);
    }
    else
#endif                                  /* defined(OSISRENTRYEXIT) */
    {
#if defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT)
      if( OSSetEvent(task_cb, mask) > 0 )
      {
        OSDISPATCH();
      }
#else                                   /* OSNOPREEMPT */
      OSSetEvent(task_cb, mask);
      /* no call to dispatcher at all */
#endif                                  /* defined(OSFULLPREEMPT) || defined(OSMIXPREEMPT) */
    }
    OSOrtiResetIdOnExit();
    OSRI( save );
    return( E_OK );
  }

  /***************************************************************************
   * Function : ClearEvent
   *
   * Description:
   *
   * Returns: Status E_OK
   *
   * Notes:
   *
   **************************************************************************/

  StatusType ClearEvent( EventMaskType mask )
  {
    OSIMSAVE                            /* OSINTMASKTYPE save;       */

    OSOrtiSetServiceWatch( OSServiceId_ClearEvent );
    /* set watch to this service */
    OSDIS( save );
#if defined(OSEXTSTATUS)
#if defined(OSISRENTRYEXIT)
    if( OSISRLEVEL != 0 )               /* Check call level */
    {                                   /* Call at interrupt level is invalid */
      OSRI( save );
      OSRETERROR( E_OS_CALLEVEL, OSServiceId_ClearEvent, 0 );
    }
#endif                                  /* defined(OSISRENTRYEXIT) */

    if( (OsRunning->status & OSTSKEXTENDED) == 0 )
    {                                   /* it isn't an extended task */
      OSRI( save );
      OSRETERROR( E_OS_ACCESS, OSServiceId_ClearEvent, 0 );
    }
#endif                                  /* defined(OSEXTSTATUS) */

    OsRunning->set_event &= (EventMaskType)(~mask);

    OSRI( save );

    OSOrtiServiceWatchOnExit( OSServiceId_ClearEvent );
    return( E_OK );
  }

  /***************************************************************************
   * Function : WaitEvent
   *
   * Description: wait event; performs dispatching if nessesary
   *
   * inp:         mask    - event mask to wait on
   *
   * Returns: E_OK                    no errors
   *          E_OS_CALLEVEL (ext.status) call at interrupt level
   *          E_OS_ACCESS   (ext.status) the task is the basic task (not extended)
   *          E_OS_RESOURCE (ext.status) the task occupies the resources
   *
   * Notes:
   *
   **************************************************************************/

  StatusType WaitEvent( EventMaskType mask )
  {
    OSIMSAVE                            /* OSINTMASKTYPE save;       */

    OSOrtiSetServiceWatch( OSServiceId_WaitEvent );
    /* set watch to this service */
#if defined(OSEXTSTATUS)
    if( (OsRunning->status & OSTSKEXTENDED) == 0 )
    {                                   /* it isn't an extended task */
      OSRETERROR( E_OS_ACCESS, OSServiceId_WaitEvent, 0 );
    }
#if defined(OSRESOURCE)
    if( OsRunning->resources != 0 )
    {                                   /* resource is occupied */
      OSRETERROR( E_OS_RESOURCE, OSServiceId_WaitEvent, 0 );
    }
#endif                                  /* defined(OSRESOURCE)  */
#if defined(OSRES_SCHEDULER)
    if( (OsRunning->status & OSTCBSCHEDULER) != 0 )
    {                                   /* resource is occupied */
      OSRETERROR( E_OS_RESOURCE, OSServiceId_WaitEvent, 0 );
    }
#endif                                  /* defined(OSRES_SCHEDULER) */

#if defined(OSISRENTRYEXIT)
    if( OsIsrLevel != 0 )               /* Check call level */
    {                                   /* Call at interrupt level is invalid; also call from hooks checked! */
      OSRETERROR( E_OS_CALLEVEL, OSServiceId_WaitEvent, 0 );
    }
#endif                                  /* defined(OSISRENTRYEXIT) */

#endif                                  /* defined(OSEXTSTATUS) */
#if defined(OSISRENTRYEXIT)
    if( OsIsrLevel != 0 )               /* Check call level */
    {                                   /* also call from hooks checked !!    */
      OSOrtiServiceWatchOnExit( OSServiceId_WaitEvent );
      /* set watch to this service */
      return( E_OK );                   /* Nothing to do in STANDARD status */
    }
#endif                                  /* defined(OSISRENTRYEXIT) */
    OSDI();                             /* It is not necessary to save./restore int.mask  because */
    /* this service shall be called with enabled interrupts only */
    OSOrtiSetOldServiceID( OSServiceId_WaitEvent );

    if( ( (OsRunning->wait_event = mask) & OsRunning->set_event ) == 0 )
    {
#if defined(OSINRES)
      if( OSCLEARRUNPRIOBITISNECESSARY() )
      {                                 /* if there is no ready task of this prio.  */
        OSTask2Suspend( OSTASKRUNPRIO( OsRunning )); /* then clear bit in OsScheduler         */
      }
      OSRESETRUNPRIO();
#endif                                  /* defined(OSINRES) */
      OSRUNNINGSTATUS |= OSTCBWAIT;     /* Task to wait state : Status == OSTCBWAIT & Task to Suspend */
      OSTask2Suspend(OsRunning->taskId);
      OSTaskForceDispatch();            /* force dispatcher */
    }
    OSOrtiResetIdOnExit();
    OSEI();
    return( E_OK );
  }

  /***************************************************************************
   * Function : GetEvent
   *
   * Description:
   *
   * Returns: Status E_OK
   *
   * Notes:   Without critical section, because set_event field will be changed 
   *          either before load, or after load set_event from memory 
   *
   **************************************************************************/

  StatusType GetEvent( TaskType taskId, EventMaskRefType mask )
  {
    OSOrtiSetServiceWatch( OSServiceId_GetEvent );
    /* set watch to this service */
#if defined(OSEXTSTATUS)
    if( OSTASKIDISINVALID )
    {                                   /* invalid ID */
      OSRETERROR( E_OS_ID, OSServiceId_GetEvent, taskId );
    }
    if( (OSTASKSTATUS(taskId) & OSTSKEXTENDED) == 0 )
    {                                   /* it isn't an extended task */
      OSRETERROR( E_OS_ACCESS, OSServiceId_GetEvent, taskId );
    }
    if( (OSTASKSTATUS(taskId) & OSTCBNOSUSPENDED ) == 0 )
    {                                   /* the task is in a suspended state */
      OSRETERROR( E_OS_STATE, OSServiceId_GetEvent, taskId );
    }
#endif                                  /* defined(OSEXTSTATUS) */

    *mask = OsTaskTable[taskId].set_event;

    OSOrtiServiceWatchOnExit( OSServiceId_GetEvent );
    return( E_OK );
  }

#endif                                  /* defined(OSECC)  && (OSNXTSKS > 0)   */

