/*** BeginHeader */
#ifndef __MCOS_MUTEX_C
#define __MCOS_MUTEX_C

// uC/OS-2 version: 1.05

/*** EndHeader */


/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                  MUTUAL EXCLUSION SEMAPHORE MANAGEMENT
*
*                          (c) Copyright 1992-2001, Jean J. Labrosse, Weston, FL
*                                           All Rights Reserved
*
* File : OS_MUTEX.C
* By   : Jean J. Labrosse
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                            LOCAL CONSTANTS
*********************************************************************************************************
*/

/*** BeginHeader OSMutexAccept, OSMutexCreate, OSMutexDel, OSMutexPend, OSMutexPost, OSMutexQuery */

#define  OS_MUTEX_KEEP_LOWER_8   0x00FF
#define  OS_MUTEX_KEEP_UPPER_8   0xFF00
#define  OS_MUTEX_AVAILABLE      0x00FF

#if OS_MUTEX_EN > 0

OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *err);
void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err);
INT8U  OSMutexPost (OS_EVENT *pevent);

#if OS_MUTEX_ACCEPT_EN > 0
INT8U  OSMutexAccept (OS_EVENT *pevent, INT8U *err);
#endif

#if OS_MUTEX_DEL_EN
OS_EVENT  *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err);
#endif

#if OS_MUTEX_QUERY_EN > 0
INT8U  OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata);
#endif

#endif
/*** EndHeader */


#if OS_MUTEX_EN > 0
/*
*********************************************************************************************************
*                                   ACCEPT MUTUAL EXCLUSION SEMAPHORE
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexAccept                                               <UCOS.LIB>

SYNTAX:       	INT8U  OSMutexAccept (OS_EVENT *pevent, INT8U *err);

DESCRIPTION:	This  function checks the mutual exclusion semaphore to see
               if a resource is available.  Unlike OSMutexPend(),
               OSMutexAccept() does not suspend the calling task if the
               resource is not available or the event did not occur.  This
               function CANNOT be called from an ISR because mutual
               exclusion semaphores are intended to be used by tasks only.

PARAMETER1:    Pointer to the event control block.

PARAMETER2:    Pointer to an error code which will be returned to your
               application:
               OS_NO_ERR          if the call was successful.
               OS_ERR_EVENT_TYPE  if 'pevent' is not a pointer to a mutex
               OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
               OS_ERR_PEND_ISR    if you called this function from an ISR

RETURN VALUE:  == 1       if the resource is available, the mutual
                          exclusion semaphore is acquired
               == 0       a) if the resource is not available
                          b) you didn't pass a pointer to a mutual
                             exclusion semaphore
                          c) you called this function from an ISR

END DESCRIPTION **********************************************************/

#if OS_MUTEX_ACCEPT_EN > 0
nodebug
INT8U  OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
    auto OS_CPU_SR  cpu_sr;
#endif


    if (bios_intnesting > 0) {                         /* Make sure it's not called from an ISR        */
        *err = OS_ERR_PEND_ISR;
        return (0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                     /* Validate 'pevent'                            */
        *err = OS_ERR_PEVENT_NULL;
        return (0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {  /* Validate event block type                    */
        *err = OS_ERR_EVENT_TYPE;
        return (0);
    }
#endif
    OS_ENTER_CRITICAL();							   /* Get value (0 or 1) of Mutex                  */
    if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;   /*      Mask off LSByte (Acquire Mutex)         */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;     /*      Save current task priority in LSByte    */
        pevent->OSEventPtr  = (void *)OSTCBCur;        /*      Link TCB of task owning Mutex           */
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return (1);
    }
    OS_EXIT_CRITICAL();
    *err = OS_NO_ERR;
    return (0);
}
#endif		// if OS_MUTEX_ACCEPT_EN > 0

/*
*********************************************************************************************************
*                                  CREATE A MUTUAL EXCLUSION SEMAPHORE
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexCreate                                               <UCOS.LIB>

SYNTAX:       	OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *err);

DESCRIPTION:	This function creates a mutual exclusion semaphore.  Note
               that:
               1) The LEAST significant 8 bits of '.OSEventCnt' are used to
                  hold the priority number of the task owning the mutex or
                  0xFF if no task owns the mutex.
               2) The MOST significant 8 bits of '.OSEventCnt' are used to
                  hold the priority number to use to reduce priority
                  inversion.

PARAMETER1:    The priority to use when accessing the mutual exclusion
               semaphore.  In other words, when the semaphore is acquired
               and a higher priority task attempts to obtain the semaphore
               then the priority of the task owning the semaphore is raised
               to this priority.  It is assumed that you will specify a
               priority that is LOWER in value than ANY of the tasks
               competing for the mutex.

PARAMETER2:    is a pointer to an error code which will be returned to your
               application:
               OS_NO_ERR           if the call was successful.
               OS_ERR_CREATE_ISR   if you attempted to create a MUTEX from
                                   an ISR
               OS_PRIO_EXIST       if a task at the priority inheritance
                                   priority already exist.
               OS_ERR_PEVENT_NULL  No more event control blocks available.
               OS_PRIO_INVALID     if the priority you specify is higher
                                   that the maximum allowed
                                   (i.e. > OS_LOWEST_PRIO)

RETURN VALUE:  != (void *)0  is a pointer to the event control clock
                  (OS_EVENT) associated with the created mutex.
               == (void *)0  if an error is detected.

END DESCRIPTION **********************************************************/

nodebug
OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr;
#endif
    OS_EVENT  *pevent;


    if (bios_intnesting > 0) {                             /* See if called from ISR ...               */
        *err = OS_ERR_CREATE_ISR;                          /* ... can't CREATE mutex from an ISR       */
        return ((OS_EVENT *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (prio >= OS_LOWEST_PRIO) {                          /* Validate PIP                             */
        *err = OS_PRIO_INVALID;
        return ((OS_EVENT *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {               /* Mutex priority must not already exist    */
        OS_EXIT_CRITICAL();                                /* Task already exist at priority ...       */
        *err = OS_PRIO_EXIST;                              /* ... inheritance priority                 */
        return ((OS_EVENT *)0);
    }
    OSTCBPrioTbl[prio] = (OS_TCB *)1;                      /* Reserve the table entry                  */
    pevent             = OSEventFreeList;                  /* Get next free event control block        */
    if (pevent == (OS_EVENT *)0) {                         /* See if an ECB was available              */
        OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* No, Release the table entry              */
        OS_EXIT_CRITICAL();
        *err               = OS_ERR_PEVENT_NULL;           /* No more event control blocks             */
        return (pevent);
    }
    OSEventFreeList     = (OS_EVENT *)OSEventFreeList->OSEventPtr;   /* Adjust the free list           */
    OS_EXIT_CRITICAL();
    pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
    pevent->OSEventCnt  = (prio << 8) | OS_MUTEX_AVAILABLE;/* Resource is available                    */
    pevent->OSEventPtr  = (void *)0;                       /* No task owning the mutex                 */
    OS_EventWaitListInit(pevent);
    *err                = OS_NO_ERR;
    return (pevent);
}

/*
*********************************************************************************************************
*                                          DELETE A MUTEX
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexDel                                                   <UCOS.LIB>

SYNTAX:       	OS_EVENT  *OSMutexDel (OS_EVENT *pevent,
                                      INT8U opt, INT8U *err);

DESCRIPTION:   This function deletes a mutual exclusion semaphore and
               readies all tasks pending on the it.  Note that:
               1) This function must be used with care.  Tasks that would
                  normally expect the presence of the mutex MUST check the
                  return code of OSMutexPend().
               2) This call can potentially disable interrupts for a long
                  time. The interrupt disable time is directly proportional
                  to the number of tasks waiting on the mutex.
               3) Because ALL tasks pending on the mutex will be readied,
                  you MUST be careful because the resource(s) will no
                  longer be guarded by the mutex.

PARAMETER1:    Pointer to the event control block associated with the
               desired mutex.

PARAMETER2:    determines delete options as follows:
               opt == OS_DEL_NO_PEND   Delete mutex ONLY if no task pending
               opt == OS_DEL_ALWAYS    Deletes the mutex even if tasks are
                                       waiting. In this case, all the tasks
                                       pending will be readied.

PARAMETER3:    Pointer to an error code that can contain one of the
               following values:
               OS_NO_ERR               The call was successful and the
                                       mutex was deleted
               OS_ERR_DEL_ISR          If you attempted to delete the MUTEX
                                       from an ISR
               OS_ERR_INVALID_OPT      An invalid option was specified
               OS_ERR_TASK_WAITING     One or more tasks were waiting on
                                       the mutex
               OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a
                                       mutex
               OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.

RETURN VALUE:  pevent                  upon error
              (OS_EVENT *)0            if the mutex was successfully
                                       deleted.

END DESCRIPTION **********************************************************/

#if OS_MUTEX_DEL_EN
nodebug
OS_EVENT  *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif
    auto BOOLEAN    tasks_waiting;
    auto INT8U      pip;


    if (bios_intnesting > 0) {                             /* See if called from ISR ...               */
        *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
        return (pevent);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        *err = OS_ERR_PEVENT_NULL;
        return ((OS_EVENT *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
        *err = OS_ERR_EVENT_TYPE;
        return (pevent);
    }
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                      /* See if any tasks waiting on mutex        */
        tasks_waiting = TRUE;                              /* Yes                                      */
    } else {
        tasks_waiting = FALSE;                             /* No                                       */
    }
    switch (opt) {
        case OS_DEL_NO_PEND:                               /* Delete mutex only if no task waiting     */
             if (tasks_waiting == FALSE) {
                 pip                 = (INT8U)(pevent->OSEventCnt >> 8);
                 OSTCBPrioTbl[pip]   = (OS_TCB *)0;        /* Free up the PIP                          */
                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
                 OSEventFreeList     = pevent;
                 OS_EXIT_CRITICAL();
                 *err = OS_NO_ERR;
                 return ((OS_EVENT *)0);                   /* Mutex has been deleted                   */
             } else {
                 OS_EXIT_CRITICAL();
                 *err = OS_ERR_TASK_WAITING;
                 return (pevent);
             }

        case OS_DEL_ALWAYS:                                /* Always delete the mutex                  */
             while (pevent->OSEventGrp != 0x00) {          /* Ready ALL tasks waiting for mutex        */
                 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
             }
             pip                 = (INT8U)(pevent->OSEventCnt >> 8);
             OSTCBPrioTbl[pip]   = (OS_TCB *)0;            /* Free up the PIP                          */
             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr  = OSEventFreeList;        /* Return Event Control Block to free list  */
             OSEventFreeList     = pevent;                 /* Get next free event control block        */
             OS_EXIT_CRITICAL();
             if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
                 OS_Sched();                               /* Find highest priority task ready to run  */
             }
             *err = OS_NO_ERR;
             return ((OS_EVENT *)0);                       /* Mutex has been deleted                   */

        default:
             OS_EXIT_CRITICAL();
             *err = OS_ERR_INVALID_OPT;
             return (pevent);
    }
}
#endif

/*
*********************************************************************************************************
*                                  PEND ON MUTUAL EXCLUSION SEMAPHORE
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexPend                                                  <UCOS.LIB>

SYNTAX:       	void  OSMutexPend (OS_EVENT *pevent,
                                  INT16U timeout, INT8U *err);

DESCRIPTION:   This function waits for a mutual exclusion semaphore.
               Note that:
               1) The task that owns the Mutex MUST NOT pend on any other
                  event while it owns the mutex.
               2) You MUST NOT change the priority of the task that owns
                  the mutex

PARAMETER1:    Pointer to the event control block associated with the
               desired mutex.

PARAMETER2:    Optional timeout period (in clock ticks).  If non-zero, your
               task will wait for the resource up to the amount of time
               specified by this argument.  If you specify 0, however, your
               task will wait forever at the specified mutex or, until the
               resource becomes available.

PARAMETER3:    Pointer to where an error message will be deposited.
               Possible error messages are:
               OS_NO_ERR          The call was successful and your task
                                  owns the mutex
               OS_TIMEOUT         The mutex was not available within the
                                  specified time.
               OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a mutex
               OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
               OS_ERR_PEND_ISR    If you called this function from an ISR
                                  and the result would lead to a
                                  suspension.

RETURN VALUE:  None

END DESCRIPTION **********************************************************/

nodebug
void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    auto OS_CPU_SR  cpu_sr;
#endif
    auto INT8U      pip;                                   /* Priority Inheritance Priority (PIP)      */
    auto INT8U      mprio;                                 /* Mutex owner priority                     */
    auto BOOLEAN    rdy;                                   /* Flag indicating task was ready           */
    auto OS_TCB    *ptcb;


    if (bios_intnesting > 0) {                             /* See if called from ISR ...               */
        *err = OS_ERR_PEND_ISR;                            /* ... can't PEND from an ISR               */
        return;
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        *err = OS_ERR_PEVENT_NULL;
        return;
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
        *err = OS_ERR_EVENT_TYPE;
        return;
    }
#endif
    OS_ENTER_CRITICAL();								   /* Is Mutex available?                      */
    if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* Yes, Acquire the resource                */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /*      Save priority of owning task        */
        pevent->OSEventPtr  = (void *)OSTCBCur;            /*      Point to owning task's OS_TCB       */
        OS_EXIT_CRITICAL();
        *err  = OS_NO_ERR;
        return;
    }
    pip   = (INT8U)(pevent->OSEventCnt >> 8);                     /* No, Get PIP from mutex            */
    mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /*     Get priority of mutex owner   */
    ptcb  = (OS_TCB *)(pevent->OSEventPtr);                       /*     Point to TCB of mutex owner   */
    if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) {  /*     Need to promote prio of owner?*/
        if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { /*     See if mutex owner is ready   */
                                                                  /*     Yes, Remove owner from Rdy ...*/
                                                                  /*          ... list at current prio */
            if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
                OSRdyGrp &= ~ptcb->OSTCBBitY;
            }
            rdy = TRUE;
        } else {
            rdy = FALSE;                                          /* No                                */
        }
        ptcb->OSTCBPrio         = pip;                     /* Change owner task prio to PIP            */
        ptcb->OSTCBY            = ptcb->OSTCBPrio >> 3;
        ptcb->OSTCBBitY         = OSMapTbl[ptcb->OSTCBY];
        ptcb->OSTCBX            = ptcb->OSTCBPrio & 0x07;
        ptcb->OSTCBBitX         = OSMapTbl[ptcb->OSTCBX];
        if (rdy == TRUE) {                                 /* If task was ready at owner's priority ...*/
            OSRdyGrp               |= ptcb->OSTCBBitY;     /* ... make it ready at new priority.       */
            OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        }
        OSTCBPrioTbl[pip]       = (OS_TCB *)ptcb;
    }
    OSTCBCur->OSTCBStat |= OS_STAT_MUTEX;             /* Mutex not available, pend current task        */
    OSTCBCur->OSTCBDly   = timeout;                   /* Store timeout in current task's TCB           */
    OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
    OS_EXIT_CRITICAL();
    OS_Sched();                                       /* Find next highest priority task ready         */
    OS_ENTER_CRITICAL();
    if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) {        /* Must have timed out if still waiting for event*/
        OS_EventTO(pevent);
        OS_EXIT_CRITICAL();
        *err = OS_TIMEOUT;                            /* Indicate that we didn't get mutex within TO   */
        return;
    }
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
    OS_EXIT_CRITICAL();
    *err = OS_NO_ERR;
}

/*
*********************************************************************************************************
*                                  POST TO A MUTUAL EXCLUSION SEMAPHORE
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexPost                                                   <UCOS.LIB>

SYNTAX:       	INT8U  OSMutexPost (OS_EVENT *pevent);

DESCRIPTION:   This function signals a mutual exclusion semaphore

PARAMETER1:    Pointer to the event control block associated with the
               desired mutex.

RETURN VALUE:  OS_NO_ERR               The call was successful and the
                                       mutex was signaled.
               OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a
                                       mutex
               OS_ERR_PEVENT_NULL      'pevent' is a NULL pointer
               OS_ERR_POST_ISR         Attempted to post from an ISR (not
                                       valid for MUTEXes)
               OS_ERR_NOT_MUTEX_OWNER  The task that did the post is NOT
                                       the owner of the MUTEX.

END DESCRIPTION **********************************************************/

nodebug
INT8U  OSMutexPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
    auto OS_CPU_SR  cpu_sr;
#endif
    auto INT8U      pip;                              /* Priority inheritance priority                 */
    auto INT8U      prio;


    if (bios_intnesting > 0) {                        /* See if called from ISR ...                    */
        return (OS_ERR_POST_ISR);                     /* ... can't POST mutex from an ISR              */
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }
#endif
    OS_ENTER_CRITICAL();
    pip  = (INT8U)(pevent->OSEventCnt >> 8);          /* Get priority inheritance priority of mutex    */
    prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /* Get owner's original priority      */
    if (OSTCBCur->OSTCBPrio != pip &&
        OSTCBCur->OSTCBPrio != prio) {                /* See if posting task owns the MUTEX            */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NOT_MUTEX_OWNER);
    }
    if (OSTCBCur->OSTCBPrio == pip) {                 /* Did we have to raise current task's priority? */
                                                      /* Yes, Return to original priority              */
                                                      /*      Remove owner from ready list at 'pip'    */
        if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBPrio         = prio;
        OSTCBCur->OSTCBY            = prio >> 3;
        OSTCBCur->OSTCBBitY         = OSMapTbl[OSTCBCur->OSTCBY];
        OSTCBCur->OSTCBX            = prio & 0x07;
        OSTCBCur->OSTCBBitX         = OSMapTbl[OSTCBCur->OSTCBX];
        OSRdyGrp                   |= OSTCBCur->OSTCBBitY;
        OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
        OSTCBPrioTbl[prio]          = (OS_TCB *)OSTCBCur;
    }
    OSTCBPrioTbl[pip] = (OS_TCB *)1;                  /* Reserve table entry                           */
    if (pevent->OSEventGrp != 0x00) {                 /* Any task waiting for the mutex?               */
                                                      /* Yes, Make HPT waiting for mutex ready         */
        prio                = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;  /*      Save priority of mutex's new owner       */
        pevent->OSEventCnt |= prio;
        pevent->OSEventPtr  = OSTCBPrioTbl[prio];     /*      Link to mutex owner's OS_TCB             */
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /*      Find highest priority task ready to run  */
        return (OS_NO_ERR);
    }
    pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;         /* No,  Mutex is now available                   */
    pevent->OSEventPtr  = (void *)0;
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}

/*
*********************************************************************************************************
*                                     QUERY A MUTUAL EXCLUSION SEMAPHORE
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSMutexQuery                                                  <UCOS.LIB>

SYNTAX:       	INT8U  OSMutexQuery (OS_EVENT *pevent,
                                    OS_MUTEX_DATA *pdata);

DESCRIPTION:   This function obtains information about a mutex.

PARAMETER1:    Pointer to the event control block associated with the
               desired mutex

PARAMETER2:    Pointer to a structure that will contain information about
               the mutex

RETURN VALUE:  OS_NO_ERR            The call was successful and the message
                                    was sent
               OS_ERR_QUERY_ISR     If you called this function from an ISR
               OS_ERR_PEVENT_NULL   'pevent' is a NULL pointer
               OS_ERR_EVENT_TYPE    If you are attempting to obtain data
                                    from a non mutex.

END DESCRIPTION **********************************************************/

#if OS_MUTEX_QUERY_EN > 0
nodebug
INT8U  OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif
    auto INT8U     *psrc;
    auto INT8U     *pdest;


    if (bios_intnesting > 0) {                             /* See if called from ISR ...               */
        return (OS_ERR_QUERY_ISR);                         /* ... can't QUERY mutex from an ISR        */
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        return (OS_ERR_PEVENT_NULL);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
        return (OS_ERR_EVENT_TYPE);
    }
#endif
    OS_ENTER_CRITICAL();
    pdata->OSMutexPIP  = (INT8U)(pevent->OSEventCnt >> 8);
    pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
    if (pdata->OSOwnerPrio == 0xFF) {
        pdata->OSValue = 1;
    } else {
        pdata->OSValue = 0;
    }
    pdata->OSEventGrp  = pevent->OSEventGrp;               /* Copy wait list                           */
    psrc               = &pevent->OSEventTbl[0];
    pdest              = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 1
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 2
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 3
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 4
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 5
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 6
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 7
    *pdest             = *psrc;
#endif
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}

#endif      // if OS_MUTEX_QUERY_EN > 0

#endif		// if OS_MUTEX_EN > 0

/*** BeginHeader */
#endif
/*** EndHeader */