#ifndef _xmk_sema_h_
#define _xmk_sema_h_
/*----------------------------------------------------------------------------
** SUMMARY: XMK Semaphore API (SEMA)
**
** DESCRIPTION:
**  This file provides interfaces for counting semaphores. Semaphores are  
**  counters for resources shared between threads. The basic operations on 
**  semaphores are: increment the counter atomically, and wait until the 
**  counter is non-null and decrement it atomically.
**
**  TIMEOUTS
**  --------
**  The default/standard interface for semaphores does not have a timeout
**  period associated with the wait/decrement operation.  If the timeout
**  functionality is needed, use the  USE_XMK_SEMAPHORES_WITH_TIMEOUT 
**  configuration option.  If you specify USE_XMK_SEMAPHORES_WITH_TIMEOUT,
**  do not specify USE_XMK_SEMAPHORES.
**  
**  PERFORMACE NOTE
**  ---------------
**  Semaphores-with-a-timeout have a significantly larger ROM and RAM 
**  footprint and higher CPU/Run-time overhead compared to the standard 
**  semaphores. 
** 
** 
** CONFIGURATION OPTION: USE_XMK_SEMAPHORES or
**                       USE_XMK_SEMAPHORES_WITH_TIMEOUT  
**
** DEPENDENCIES:
**  To use this interface the following XMK service(s) MUST always be
**  enabled/configured:
**      USE_XMK_CORE_KERNEL
**      USE_XMK_THREAD_xSLEEP (when using USE_XMK_SEMAPHORES_WITH_TIMEOUT)
**
**  NOTES:
**  1. For efficency/optimization some methods are 'inlined'.  The inlining
**     is done by using the preprocessor/macros.  The application should
**     treat all methods as function calls and not rely on the fact they may
**     be currently defined as a macro.
----------------------------------------------------------------------------*/

#include "xmkcfg.h"     /* For: Project/Application kernel configuraiton */

#ifdef __cplusplus
extern "C" {
#endif


/*-------------- MAGIC CONSTANTS -------------------------------------------*/
/** NULL Semaphore handle */
#define XMK_NULL_SEMAPHORE						_XMK_NULL_SEMAPHORE

/** Maximum legal count for a semaphore */
#define XMK_SEMA_VALUE_MAX                      _XMK_SEMA_VALUE_MAX

/** Infinite timeout period (aka no timeout) */
#define XMK_SEMA_NO_TIMEOUT                     _XMK_SEMA_NO_TIMEOUT 


/*
** ERROR CODES 
*/
/** Attempt to destroy a Semaphore that had one or more threads waiting to it
 */
#define XMK_ERRFATAL_SEMA_STRANDED_WAITERS      _XMK_ERRFATAL_SEMA_STRANDED_WAITERS

/** An attempt was made to increment and/or set the semaphore count greater than
    XMK_SEMA_VALUE_MAX.
 */
#define XMK_ERRFATAL_SEMA_EXCEEDING_MAX_VALUE   _XMK_ERRFATAL_SEMA_EXCEEDING_MAX_VALUE


/*-------------- PUBLIC/PUBLISHED API --------------------------------------*/
/** This method is used to iniitalize a semaphore for use by the application. 
    The count associated with the semaphore is set initially to the function 
    arg: value.
    NOTES:
        o The application is responsible for allocating the memory for
          the semaphore data structure.
        o The range of the semaphore count is the unsigned range of
          the data type, XMK_SEMA_COUNTER (default data type is: 
          unsigned char).
        o This method CAN be called ANY time EVEN before Xmk_initialize().

    Prototype:
        void Xmk_semaInit(XMK_SEMAPHORE* sema, XMK_SEMA_COUNTER value);
 */
#define Xmk_semaInit(s,i)               _Xmk_semaInit(s,i)        

/** This method is used to free kernel resources that are associated
    with the previously initialized. If there are suspended thread(s) waiting 
    on the the semaphore when this method is called, a fatal error is generated.
    NOTES:
        o The application is responsible for freeing the memory of the
          semaphore data structure.
        o Passing an uninitialized semaphore will result in un-defined 
          behavior (and most likely crash your application).

    Prototype:
        void Xmk_semaDestroy( XMK_SEMAPHORE* sema );
 */
#define Xmk_semaDestroy(s)              _Xmk_semaDestroy(s)

/** This method atomically "increases the count" of the semaphore specified by
    sema.  If there is a suspended thread waiting on the semaphore, the thread 
    is made ready for execution.  If no thread is waiting, the semaphore's 
    count is incremented by 1.
    NOTES:
        o This method can ONLY be called from a thread context.
        o Passing an uninitialized semaphore will result in un-defined 
          behavior (and most likely crash your application).

    Prototype:
        void Xmk_semaSignal( XMK_SEMAPHORE* sema );
 */
#define Xmk_semaSignal(s)               _Xmk_semaSignal(s)

/** This method is the same as Xmk_semaSignal() except that can ONLY be called
    from the context of an interrupt service routine.
    Prototype:
        void Xmk_isr_semaSignal( XMK_SEMAPHORE* sema );
 */
#define Xmk_isr_semaSignal(s)           _Xmk_isr_semaSignal(s)

/** This method suspends the calling thread until the semaphore pointed to by 
    sema has non-zero count. It then atomically decreases the semaphore count.
    NOTES:
        o This method can ONLY be called from a thread context.
        o Passing an uninitialized semaphore will result in un-defined 
          behavior (and most likely crash your application).

    Prototype:
        void Xmk_semaWait( XMK_SEMAPHORE* sema );
 */
#define Xmk_semaWait(s)                 _Xmk_semaWait(s)

/** This method is the same as Xmk_semaWait(), except the method will timeout
    and/or return after the specified time interval if the semaphore was
    not signaled.  The method normally returns non-zero (true).  It only 
    returns 0 (false) if the thread 'waited' on the semaphore and the timeout 
    period expired before the semaphore was signaled.
    NOTES:
        o This method is ONLY available if the configuration option
          USE_XMK_SEMAPHORES_WITH_TIMEOUT is used.
        o This method can ONLY be called from a thread context.
        o If XMK_SEMA_NO_TIMEOUT is specified as the timeout  period, the 
          method behaves exactly the same as Xmk_semaWait(), i.e. nevers 
          times-out.
        o The longest timeout period is XMK_SLEEP_MAX_DELAY-1 sleep ticks.
        o If 0 is specified as the timout period, then the call acts
          as a 'polled' operation on the semaphore in that it will never
          block even if the semaphore count is zero when called.
        o CAUTION: Do not assume that since the method returned false due to 
          a time-out, that the semaphore count is now zero.  It is possible 
          that the semaphore is/was signaled after the 'time-out', BUT before 
          the application has an opportunity to check the return code.
        o Passing an uninitialized semaphore will result in un-defined 
          behavior (and most likely crash your application).

    Prototype:
        XMK_BOOL Xmk_semaWaitTimeout( XMK_SEMAPHORE* sema, XMK_SLEEPTICKS maxwait )
 */
#define Xmk_semaWaitTimeout(s,t)        _Xmk_semaWaitTimeout(s,t)

#ifdef __cplusplus
}
#endif
/*--------------------------------------------------------------------------*/
#endif  /* end _xmk_sema_h_ */

