
/*HEADER**********************************************************************
*
* Copyright 2008 Freescale Semiconductor, Inc.
* Copyright 2004-2008 Embedded Access Inc.
* Copyright 1989-2008 ARC International
*
* This software is owned or controlled by Freescale Semiconductor.
* Use of this software is governed by the Freescale MQX RTOS License
* distributed with this Material.
* See the MQX_RTOS_LICENSE file distributed for more details.
*
* Brief License Summary:
* This software is provided in source form for you to use free of charge,
* but it is not open source software. You are allowed to use this software
* but you cannot redistribute it or derivative works of it in source form.
* The software may be used only in connection with a product containing
* a Freescale microprocessor, microcontroller, or digital signal processor.
* See license agreement file for full license terms including other restrictions.
*****************************************************************************
*
* Comments:
*
*   This file contains functions of the Message component.
*
*
*END************************************************************************/

#include "mqx_inc.h"
#if MQX_USE_MESSAGES
#include "message.h"
#include "msg_prv.h"
#include "ipc.h"
#include "ipcrtprv.h"

#define DEQUEUE_TOP_MSG_ENTRY(mq, im, m, td) \
               --(mq->NO_OF_ENTRIES); \
               im = mq->FIRST_MSG_PTR; \
               mq->FIRST_MSG_PTR = im->NEXT; \
               if ( mq->FIRST_MSG_PTR == NULL ) { \
                  mq->LAST_MSG_PTR = NULL; \
               } else { \
                  (mq->FIRST_MSG_PTR)->PREV = NULL; \
               } \
               if ( mq->TD_PTR ) { \
                  --(mq->TD_PTR->MESSAGES_AVAILABLE); \
               } \
               m = &im->MESSAGE; \
               im->QUEUED = FALSE; \
               im->TD_PTR = td;

/*!
 * \brief Sends the message to multiple message queues.
 * 
 * For conditions on the message, see _msgq_send().
 * \n The function sends a priority 0 message.
 * \n For each copy of the message, the function sets the target queue ID in the 
 * message header with a queue ID from the array of queue IDs.
 * \n The function does not block.
 * \n If the function returns successfully, the message is no longer a resource 
 * of the task.
 * \n It is the responsibility of the application to handle the consequences of 
 * messages being lost.
 * 
 * \param[in] input_msg_ptr Pointer to the message to be sent.
 * \param[in] qid_ptr       An array of _queue_ids, MSGQ_NULL_QUEUE_ID terminated
 * to which the message is to be sent.  A successfull message send will result in 
 * the queue id being overwritten with a MSGQ_NULL_QUEUE_ID.
 * \param[in] pool          One of the following:
 * \li Pool ID to allocate messages from.
 * \li MSGPOOL_NULL_POOL_ID (Messages will be allocated from a system message pool.)
 * 
 * \return Number that represents the size of the array of queue IDs (success).
 * \return Number less than the size of the array of queue IDs (failure).
 * 
 * \warning Calls _mem_copy()
 * \warning Calls _mem_alloc() or _mem_alloc_system() depending on whether pool_id 
 * represents a private or system message pool.
 * \warning Might dispatch one or more tasks.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_INVALID_PARAMETER (Qid_ptr does not point to a valid queue ID.)
 * \li MSGPOOL_OUT_OF_MESSAGES (MQX could not allocate a message from the message 
 * pool.)
 * \li MSGQ_INVALID_MESSAGE (Msg_ptr does not point to a message that was allocated 
 * as described for _msgq_send().)
 * \li Task error codes from _msg_alloc() (If pool_id represents a private 
 * message pool.)
 * \li Task error codes from _msg_alloc_system() (If pool_id represents a system 
 * message pool.) 
 * 
 * \see _msgq_send   
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _msgq_send_priority
 * \see _msgq_send_urgent
 * \see _task_set_error
 * \see _mem_alloc
 * \see _mem_alloc_from
 * \see _mem_alloc_system
 * \see _mem_alloc_system_from
 * \see _mem_alloc_system_zero
 * \see _mem_alloc_system_zero_from
 * \see _mem_alloc_zero
 * \see _mem_alloc_zero_from
 * \see _mem_alloc_align
 * \see _mem_alloc_align_from
 * \see _mem_alloc_at
 * \see _mem_copy
 * \see MESSAGE_HEADER_STRUCT   
 */ 
_mqx_uint _msgq_send_broadcast
(
    void           *input_msg_ptr,
    _queue_id  *qid_ptr,
    _pool_id        pool
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    MESSAGE_HEADER_STRUCT_PTR msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
    input_msg_ptr;
    MESSAGE_HEADER_STRUCT_PTR sending_msg_ptr;
#if MQX_CHECK_ERRORS
    INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
#endif
    _mqx_uint size;
    _mqx_uint count;
    _mqx_uint error;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE4(KLOG_msgq_send_broadcast, msg_ptr, qid_ptr, pool);

    count = 0;

#if MQX_CHECK_ERRORS
    if (msg_ptr == NULL )
    {
        _task_set_error(MSGQ_INVALID_MESSAGE);
        _KLOGX2(KLOG_msgq_send_broadcast, count);
        return(count);
    }/* Endif */
    if (qid_ptr == NULL )
    {
        _task_set_error(MQX_INVALID_PARAMETER);
        _KLOGX2(KLOG_msgq_send_broadcast, count);
        return(count);
    } /* Endif */
#endif

#if MQX_CHECK_ERRORS
    imsg_ptr = GET_INTERNAL_MESSAGE_PTR(msg_ptr);
    if (imsg_ptr->VALID != MSG_VALID)
    {
        /* An invalid message was input by the application. */
        _task_set_error(MSGQ_INVALID_MESSAGE);
        return(count);
    } /* Endif */
#endif

    if (*qid_ptr == MSGQ_NULL_QUEUE_ID )
    {
        /* Nothing to do */
        _KLOGX2(KLOG_msgq_send_broadcast, count);
        return(count);
    } /* Endif */

    size = msg_ptr->SIZE;

    while (*(qid_ptr + 1) != MSGQ_NULL_QUEUE_ID)
    {
        if (pool == MSGPOOL_NULL_POOL_ID)
        {
            sending_msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
            _msg_alloc_system((_msg_size)size);
        }
        else
        {
            sending_msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)_msg_alloc(pool);
        } /* Endif */
        
        if (sending_msg_ptr != NULL)
        {
            _mem_copy(msg_ptr, sending_msg_ptr, (_mem_size)size);
            sending_msg_ptr->TARGET_QID = *qid_ptr;
            error = _task_get_error();
            if (_msgq_send_internal(sending_msg_ptr, FALSE, *qid_ptr++) )
            {
                count++;
            } /* Endif */
            _task_set_error(error);
        } /* Endif */
        else {
            // out of messages, stop sending loop
            // task error is set to MSGPOOL_OUT_OF_MESSAGES in _msg_alloc
            break;
        }
    } /* Endwhile */

    msg_ptr->TARGET_QID = *qid_ptr;
    error = _task_get_error();
    if (_msgq_send_internal(msg_ptr, FALSE, *qid_ptr))
    {
        count++;
    } /* Endif */
    _task_set_error(error);
    _KLOGX2(KLOG_msgq_send_broadcast, count);
    return(count);

} /* Endbody */

/*!
 * \brief Closes the message queue.
 * 
 * Only the task that opens a private message queue (_msgq_open()) can close it. 
 * Any task can close an opened system message queue (_msgq_open_system()).
 * \li If _msgq_close() closes the message queue, it frees any messages that are 
 * in the queue.
 * \li If _msgq_close() closes the message queue, a task can no longer use 
 * queue_id to access the message queue.
 * \li The message queue can subsequently be opened again with _msgq_open() or
 * _msgq_open_system().
 * 
 * \param[in] queue_id Queue ID of the message queue to be closed.
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \warning Calls _msg_free() to free messages that are in the queue.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is not valid for this processor.)
 * \li MSGQ_NOT_QUEUE_OWNER (Task that got queue_id did so by opening a private 
 * message queue (_msgq_open()) and is not the task calling _msgq_close().)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Queue_id does not represent a queue that is open.)
 * \li Task error codes from _msg_free() (If MQX cannot free messages that are 
 * in the queue.)
 * 
 * \see _msgq_open_system
 * \see _msgq_open
 * \see _msg_free
 * \see _msgq_send
 * \see _task_set_error       
 */ 
bool _msgq_close
(
    _queue_id queue_id
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    register TD_STRUCT_PTR               td_ptr;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register MSGQ_STRUCT_PTR             msgq_ptr;
    register MSGQ_STRUCT_PTR             td_msgq_ptr;
    register MSGQ_STRUCT_PTR             qprev_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR tmp_imsg_ptr;
    register uint16_t                     queue;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msgq_close, queue_id);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msgq_close, FALSE, MQX_COMPONENT_DOES_NOT_EXIST);
        return(FALSE);
    } /* Endif */
#endif

#if MQX_CHECK_ERRORS
    if ( PROC_NUMBER_FROM_QID(queue_id) != kernel_data->INIT.PROCESSOR_NUMBER )
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        _KLOGX3(KLOG_msgq_close, FALSE, MSGQ_INVALID_QUEUE_ID);
        return FALSE;
    } /* Endif */
#endif

    queue = QUEUE_FROM_QID(queue_id);

#if MQX_CHECK_ERRORS
    if ( ! VALID_QUEUE(queue) )
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        _KLOGX3(KLOG_msgq_close, FALSE, MSGQ_INVALID_QUEUE_ID);
        return FALSE;
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];

#if MQX_CHECK_ERRORS
    if ( msgq_ptr->QUEUE != (queue) )
    {
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        _KLOGX3(KLOG_msgq_close, FALSE, MSGQ_QUEUE_IS_NOT_OPEN);
        return FALSE;
    } /* Endif */
#endif

    td_ptr = kernel_data->ACTIVE_PTR;
    if ( ((msgq_ptr->TD_PTR == NULL) || (msgq_ptr->TD_PTR == td_ptr)))
    {
        /*
         *  this queue is currently active and is owned by
         *  the requesting task so DELETE the queue.
         */
        _int_disable();
        if ( msgq_ptr->TD_PTR != NULL )
        {
            td_ptr->MESSAGES_AVAILABLE -= msgq_ptr->NO_OF_ENTRIES;
        } /* Endif */
        imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
        while ( imsg_ptr != NULL )
        {
            tmp_imsg_ptr = imsg_ptr->NEXT;
            imsg_ptr->QUEUED = FALSE;
            _msg_free((void *)&imsg_ptr->MESSAGE);
            imsg_ptr = tmp_imsg_ptr;
        } /* Endwhile */
        msgq_ptr->FIRST_MSG_PTR = NULL;

        if ( msgq_ptr->TD_PTR )
        {
            /* Remove the queue from the Task descriptors linked list */
            td_msgq_ptr = (MSGQ_STRUCT_PTR)td_ptr->MSG_QUEUE_HEAD;
            if ( td_msgq_ptr == msgq_ptr )
            {
                td_ptr->MSG_QUEUE_HEAD = (void *)td_msgq_ptr->NEXT_MSGQ_PTR;
                if ( td_ptr->MSG_QUEUE_HEAD == NULL )
                {
                    td_ptr->MSG_QUEUE_TAIL = NULL;
                } /* Endif */
            }
            else
            {
                qprev_ptr = td_msgq_ptr;
                td_msgq_ptr = qprev_ptr->NEXT_MSGQ_PTR;
                while ( td_msgq_ptr != msgq_ptr )
                {
                    qprev_ptr = td_msgq_ptr;
                    td_msgq_ptr = qprev_ptr->NEXT_MSGQ_PTR;
                } /* Endwhile */
                qprev_ptr->NEXT_MSGQ_PTR = td_msgq_ptr->NEXT_MSGQ_PTR;
                if ( td_ptr->MSG_QUEUE_TAIL == (void *)td_msgq_ptr )
                {
                    td_ptr->MSG_QUEUE_TAIL = (void *)qprev_ptr;
                } /* Endif */
            } /* Endif */
        } /* Endif */
        msgq_ptr->QUEUE = 0;
        _int_enable();
        _KLOGX3(KLOG_msgq_close, TRUE, 0);
        return TRUE;
    }
    else
    {
        _task_set_error(MSGQ_NOT_QUEUE_OWNER);
        _KLOGX3(KLOG_msgq_close, FALSE, MSGQ_NOT_QUEUE_OWNER);
        return FALSE;
    } /* Endif */

} /* Endbody */

/*!
 * \brief Gets the number of messages in the message queue.
 * 
 * The message queue must be previously opened on this processor.
 * 
 * \param[in] queue_id One of the following:
 * \li Queue ID of the queue to be checked.
 * \li MSGQ_ANY_QUEUE (Get the number of messages waiting in all message queues 
 * that the task has open.)
 * 
 * \return Number of messages (Success.)
 * \return 0 (Success: queue is empty.)
 * \return 0 (Failure.)
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is not valid for this processor.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Queue_id does not represent a message queue that 
 * is open.)
 * 
 * \see _msgq_open
 * \see _msgq_open_system
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _task_set_error    
 */ 
_mqx_uint _msgq_get_count
(
    _queue_id queue_id
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR      kernel_data;
    MSG_COMPONENT_STRUCT_PTR    msg_component_ptr;
    register MSGQ_STRUCT_PTR    msgq_ptr;
    INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register _mqx_uint          pending;
    register uint16_t            queue;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msgq_get_count, queue_id);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msgq_get_count, MQX_COMPONENT_DOES_NOT_EXIST, 0);
        return(0);
    } /* Endif */
#endif

    if (queue_id == MSGQ_ANY_QUEUE)
    {
        _KLOGX3(KLOG_msgq_get_count, MQX_OK, kernel_data->ACTIVE_PTR->MESSAGES_AVAILABLE);
        return(kernel_data->ACTIVE_PTR->MESSAGES_AVAILABLE );
    } /* Endif */

    pending = 0;
    queue = QUEUE_FROM_QID(queue_id);
    if ( (PROC_NUMBER_FROM_QID(queue_id) == kernel_data->INIT.PROCESSOR_NUMBER) &&
                    VALID_QUEUE(queue) )
    {
        msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
        if ( msgq_ptr->QUEUE == (queue) )
        {
            pending = msgq_ptr->NO_OF_ENTRIES;

            /* Check for short-cutted message ie not on q but could have been */
            if (msgq_ptr->TD_PTR != NULL)
            {
                imsg_ptr = (INTERNAL_MESSAGE_STRUCT_PTR)msgq_ptr->TD_PTR->MESSAGE;
                if ((imsg_ptr != NULL) &&
                                (QUEUE_FROM_QID(imsg_ptr->MESSAGE.TARGET_QID) == queue))
                {
                    ++pending;
                } /* Endif */
            } /* Endif */
        }
        else
        {
            _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        } /* Endif */
    }
    else
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
    } /* Endif */

    _KLOGX2(KLOG_msgq_get_count, pending);
    return(pending);

} /* Endbody */

/*!
 * \brief Converts a message-queue number and processor number to a queue ID.
 * 
 * The queue ID might not represent an open message queue. The queue ID can be 
 * used with functions that access message queues.
 * 
 * \param[in] processor_number One of the following:
 * \li Processor on which the message queue resides.
 * \li 0 (Indicates the local processor.)
 * \param[in] queue_number     Image-wide unique number that identifies the 
 * message queue.
 * 
 * \return Queue ID for the queue (Success.)
 * \return MSGQ_NULL_QUEUE_ID (Failure: _processor_number is not valid.)
 * 
 * \see _msgq_open_system
 * \see _msgq_open 
 */ 
_queue_id _msgq_get_id
(
    _processor_number processor_number,
    _queue_number     queue_number
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;

    _GET_KERNEL_DATA(kernel_data);

#if MQX_CHECK_ERRORS
    if (processor_number > MQX_MAX_PROCESSOR_NUMBER)
    {
        return(MSGQ_NULL_QUEUE_ID);
    }/* Endif */
#endif   
    if ( processor_number == 0 )
    {
        processor_number = (_processor_number)kernel_data->INIT.PROCESSOR_NUMBER;
    } /* Endif */
    return BUILD_QID(processor_number, queue_number);

} /* Endbody */

/*!
 * \brief Sets the notification function for the private or the system message queue.
 * 
 * If the message queue is a system message queue, the function replaces the 
 * notification function and data that were installed with _msgq_open_system().
 * \n The notification function for a system message queue can get messages from 
 * the queue with _msgq_poll().
 * \n The notification function for a private message queue cannot get messages 
 * from the queue.
 *  
 * \param[in] qid                   Private or system message queue for which to 
 * install the notification function. 
 * \param[in] notification_function Function that MQX calls when MQX puts a 
 * message in the queue.
 * \param[in] notification_data     Data that MQX passes when it calls 
 * notification_function.
 * 
 * \return Pointer to the previous notification function (Success.) Notification function installed.
 * \return NULL (Success: Previous notification function was NULL.) Notification function installed.
 * \return NULL (Failure.) Notification function NOT installed.
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_OK (Notification function is installed; the previous function was NULL.)
 * \li MSGQ_INVALID_QUEUE_ID (Qid is not valid.) 
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Queue is not open.)
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * 
 * \see _msgq_open_system
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_get_notification_function
 * \see _task_set_error
 */ 
MSGQ_NOTIFICATION_FPTR _msgq_set_notification_function
(
    _queue_id              qid,
    MSGQ_NOTIFICATION_FPTR notification_function,
    void                  *notification_data
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    MSG_COMPONENT_STRUCT_PTR msg_component_ptr;
    MSGQ_STRUCT_PTR          msgq_ptr;
    MSGQ_NOTIFICATION_FPTR   result;
    _queue_number            queue;
#if MQX_CHECK_ERRORS
    _processor_number        pnum;
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE4(KLOG_msgq_set_notification_function, qid, notification_function, notification_data);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        result = NULL;
        _KLOGX2(KLOG_msgq_set_notification_function, result);
        return(result);
    } /* Endif */
#endif

    queue = QUEUE_FROM_QID(qid);

#if MQX_CHECK_ERRORS
    pnum = PROC_NUMBER_FROM_QID(qid);
    if (( pnum != kernel_data->INIT.PROCESSOR_NUMBER) || ( ! VALID_QUEUE(queue)))
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        result = NULL;
        _KLOGX2(KLOG_msgq_set_notification_function, result);
        return result;
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
    if ( msgq_ptr->QUEUE != (queue) )
    {
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        result = NULL;
    }
    else
    {
        result = msgq_ptr->NOTIFICATION_FUNCTION;
        msgq_ptr->NOTIFICATION_FUNCTION = notification_function;
        msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER = notification_data;
    } /* Endif */

    _KLOGX2(KLOG_msgq_set_notification_function, result);
    return result;

} /* Endbody */
/*!
 * \brief Gets the notification function and its data that are associated with 
 * the private or the system message queue.
 * 
 * \param[in]  qid                   Queue ID of the message queue for which to 
 * get the notification function.
 * \param[out] notification_function Pointer (which might be NULL) to the function 
 * that MQX calls when it puts a message in the message queue.
 * \param[out] notification_data     Pointer (which might be NULL) to data that 
 * MQX passes to the notification function.
 * 
 * \return MQX_OK
 * \return MSGQ_INVALID_QUEUE_ID (Queue_id does not represent a valid message 
 * queue on this processor.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \return MSGQ_QUEUE_IS_NOT_OPEN (Queue_id does not represent an open message 
 * queue.)
 * 
 * \warning On error, does not initialize notification_function or notification_data.
 * 
 * \see _msgq_open_system      
 * \see _msgq_open
 * \see _msgq_set_notification_function   
 */ 
_mqx_uint _msgq_get_notification_function
(
    _queue_id                    qid,
    MSGQ_NOTIFICATION_FPTR  *notification_function,
    void                   **notification_data
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    MSG_COMPONENT_STRUCT_PTR msg_component_ptr;
    MSGQ_STRUCT_PTR          msgq_ptr;
    _mqx_uint                result = MQX_OK;
    _queue_number            queue;
#if MQX_CHECK_ERRORS
    _processor_number        pnum;
#endif

    _GET_KERNEL_DATA(kernel_data);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        return(MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif

    queue = QUEUE_FROM_QID(qid);

#if MQX_CHECK_ERRORS
    pnum = PROC_NUMBER_FROM_QID(qid);
    if (( pnum != kernel_data->INIT.PROCESSOR_NUMBER) || ( ! VALID_QUEUE(queue)))
    {
        result = MSGQ_INVALID_QUEUE_ID;
    } /* Endif */
#endif

    if (result == MQX_OK)
    {
        msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
        if ( msgq_ptr->QUEUE != (queue) )
        {
            result = MSGQ_QUEUE_IS_NOT_OPEN;
        }
        else
        {
            *notification_function = msgq_ptr->NOTIFICATION_FUNCTION;
            *notification_data = msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER;
        } /* Endif */
    } /* Endif */

    return result;

} /* Endbody */

/*!
 * \brief Opens the private message queue.
 * 
 * The open message queue has a NULL notification function.
 * \n Only the task that opens a private message queue can receive messages from 
 * the queue.
 * \n A task can subsequently attach a notification function and notification data 
 * to the message queue with _msgq_set_notification_function().
 * 
 * \param[in] queue One of the following:
 * \li Queue number of the message queue to be opened on this processor (min. 8, 
 * max. as defined in the MQX initialization structure).
 * \li MSGQ_FREE_QUEUE (MQX opens an unopened message queue.)
 * \param[in] max_queue_size One of the following:
 * \li Maximum queue size.
 * \li 0 (Unlimited size.)
 * 
 * \return Queue ID (Success.)
 * \return MSGQ_NULL_QUEUE_ID (Failure.)
 * 
 * \warning Creates the message component if it was not previously created.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MSGQ_INVALID_QUEUE_NUMBER
 * \li MSGQ_QUEUE_IN_USE One of the following: message queue is already open or 
 * MQX cannot get a queue number for an unopened queue.
 * 
 * \see _msgq_close  
 * \see _msgq_open_system
 * \see _msg_create_component
 * \see _msgq_set_notification_function
 * \see _task_set_error 
 */ 
_queue_id _msgq_open
(
    _queue_number queue,
    uint16_t       max_queue_size
)
{ /* Body */
    _queue_id result;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE3(KLOG_msgq_open, queue, max_queue_size);

    result = _msgq_open_internal(
        queue, max_queue_size, MSG_QUEUE, (MSGQ_NOTIFICATION_FPTR)NULL, NULL
    );

    _KLOGX2(KLOG_msgq_open, result);

    return result;

} /* Endbody */

/*!
 * \private
 *  
 * \brief This is an internal function used to open a message queue.
 * 
 * \param[in] queue                 The queue being opened.
 * \param[in] max_queue_size        The maximum number of entries allowed in this 
 * queue.
 * \param[in] queue_type            The type of queue, NORMAL or SYSTEM.
 * \param[in] notification_function The function to be called when an entry is 
 * put on the queue.
 * \param[in] notification_data     Information to pass to the notification 
 * function.
 * 
 * \return Queue ID (Success.)
 * \return MSGQ_NULL_QUEUE_ID (Failure.)
 * 
 * \see _msgq_open   
 */ 
_queue_id _msgq_open_internal
(
    _queue_number          queue,
    uint16_t                max_queue_size,
    _mqx_uint              queue_type,
    MSGQ_NOTIFICATION_FPTR notification_function,
    void                  *notification_data
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    TD_STRUCT_PTR            td_ptr;
    MSG_COMPONENT_STRUCT_PTR msg_component_ptr;
    register MSGQ_STRUCT_PTR temp_msgq_ptr;
    register MSGQ_STRUCT_PTR msgq_ptr;
    register _queue_id       qid;
    register _mqx_uint       i;
    _mqx_uint                result;

    _GET_KERNEL_DATA(kernel_data);
    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
    qid = (_queue_id)0;

    if (msg_component_ptr == NULL)
    {
        result = _msg_create_component();
        msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (msg_component_ptr == NULL)
        {
            _task_set_error(result);
            return(qid);
        } /* Endif */
#endif      
    } /* Endif */

    _int_disable();
    if (queue == MSGQ_FREE_QUEUE)
    {
        /* Lets find a free queue entry */
        msgq_ptr = &msg_component_ptr->MSGQS_PTR[MSGQ_FIRST_USER_QUEUE];
        for (i = MSGQ_FIRST_USER_QUEUE; i <= msg_component_ptr->MAX_MSGQS; ++i)
        {
            if (msgq_ptr->QUEUE != (_queue_number)i)
            {
                queue = (_queue_number)i;
                break;
                /* Found one! */
            } /* Endif */
            ++msgq_ptr;
        } /* Endfor */
        if (queue == MSGQ_FREE_QUEUE)
        {
            /* Did not get one */
            _int_enable();
            _task_set_error(MSGQ_QUEUE_IN_USE);
            return(qid);
        }/* Endif */
    }
    else
    {
        if (queue >= msg_component_ptr->MAX_MSGQS)
        {
            _int_enable();
            _task_set_error(MSGQ_INVALID_QUEUE_NUMBER);
            return(qid);
        }
    }

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];

#if MQX_CHECK_ERRORS
    if (msgq_ptr->QUEUE == queue)
    {
        _int_enable();
        _task_set_error(MSGQ_QUEUE_IN_USE);
        return(qid);
    } /* Endif */
#endif

    msgq_ptr->QUEUE = queue;
    msgq_ptr->FIRST_MSG_PTR = NULL;
    msgq_ptr->LAST_MSG_PTR = NULL;
    msgq_ptr->NEXT_MSGQ_PTR = NULL;
    msgq_ptr->NO_OF_ENTRIES = 0;
    msgq_ptr->TYPE = (uint16_t)queue_type;
    msgq_ptr->MAX_ENTRIES = max_queue_size;
    msgq_ptr->NOTIFICATION_FUNCTION = notification_function;
    msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER = notification_data;

    if ( queue_type == MSG_QUEUE )
    {
        td_ptr = kernel_data->ACTIVE_PTR;
        msgq_ptr->TD_PTR = td_ptr;
        if ( td_ptr->MSG_QUEUE_HEAD == NULL )
        {
            td_ptr->MSG_QUEUE_HEAD = (void *)msgq_ptr;
            td_ptr->MSG_QUEUE_TAIL = (void *)msgq_ptr;
            td_ptr->MESSAGES_AVAILABLE = 0;
        }
        else
        {
            temp_msgq_ptr = (MSGQ_STRUCT_PTR)(td_ptr->MSG_QUEUE_TAIL);
            temp_msgq_ptr->NEXT_MSGQ_PTR = msgq_ptr;
            td_ptr->MSG_QUEUE_TAIL = (void *)msgq_ptr;
        } /* Endif */
    }
    else
    {
        msgq_ptr->TD_PTR = NULL;
    } /* Endif */

    _INT_ENABLE();
    qid = BUILD_QID(kernel_data->INIT.PROCESSOR_NUMBER, queue);
    return (qid);

} /* Endbody */

/*!
 * \brief Gets the task ID of the task that owns the message queue.
 * 
 * \param[in] queue_id Queue ID of the message queue.
 * 
 * \return Task ID (Success.)
 * \return MQX_NULL_TASK_ID (Failure.)
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MQX_INVALID_PROCESSOR_NUMBER (Processor number that queue_id specifies is 
 * not valid.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Message queue with queue ID queue_id is not open.)
 * 
 * \see _msgq_open
 * \see _msgq_open_system
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_send family
 * \see _task_set_error 
 */ 
_task_id _msgq_get_owner
(
    _queue_id queue_id
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    MSG_COMPONENT_STRUCT_PTR msg_component_ptr;
    register MSGQ_STRUCT_PTR msgq_ptr;
    _queue_number            queue;
    _task_id                 task_id;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msgq_get_owner, queue_id);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msgq_get_owner, MQX_NULL_TASK_ID, MQX_COMPONENT_DOES_NOT_EXIST);
        return(MQX_NULL_TASK_ID);
    } /* Endif */
#endif

    queue = QUEUE_FROM_QID(queue_id);

#if MQX_CHECK_ERRORS
    if ((PROC_NUMBER_FROM_QID(queue_id) != kernel_data->INIT.PROCESSOR_NUMBER) ||
                    (! VALID_QUEUE(queue)) )
    {
        _task_set_error(MQX_INVALID_PROCESSOR_NUMBER);
        _KLOGX3(KLOG_msgq_get_owner, MQX_NULL_TASK_ID, MQX_INVALID_PROCESSOR_NUMBER);
        return (MQX_NULL_TASK_ID);
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
    if (msgq_ptr->QUEUE != (queue))
    {
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        _KLOGX3(KLOG_msgq_get_owner, MQX_NULL_TASK_ID, MSGQ_QUEUE_IS_NOT_OPEN);
        return (MQX_NULL_TASK_ID);
    } /* Endif */

    task_id = msgq_ptr->TD_PTR->TASK_ID;
    _KLOGX3(KLOG_msgq_get_owner, task_id, MQX_OK);
    return (task_id);

} /* Endbody */

/*!
 * \brief Gets a pointer to the message that is at the start of the message 
 * queue, but do not remove the message.
 * 
 * Call _msgq_get_count() first to determine whether there are messages in the 
 * queue. If there are no messages, _msgq_peek() calls _task_set_error() with 
 * MSGQ_MESSAGE_NOT_AVAILABLE.
 * 
 * \param[in] queue_id The queue to look at.
 * 
 * \return Pointer to the message that is at the start of the message queue 
 * (Success.)
 * \return NULL (Failure.) 
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is not valid.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (There are no messages in the message queue.)
 * \li MSGQ_NOT_QUEUE_OWNER (Task is not the owner of the private message queue.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Queue is not open.)
 * 
 * \see _msgq_get_count
 * \see _msgq_open_system
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_send
 * \see _task_set_error
 * \see _msg_create_component
 * \see MESSAGE_HEADER_STRUCT  
 */ 
void *_msgq_peek
(
    _queue_id queue_id
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register MESSAGE_HEADER_STRUCT_PTR   message_ptr;
    register MSGQ_STRUCT_PTR             msgq_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    _queue_number                        queue;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msgq_peek, queue_id);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msgq_peek, NULL, MQX_COMPONENT_DOES_NOT_EXIST);
        return(NULL);
    } /* Endif */
#endif

    message_ptr = NULL;
    queue = QUEUE_FROM_QID(queue_id);

#if MQX_CHECK_ERRORS
    if ((PROC_NUMBER_FROM_QID(queue_id) != kernel_data->INIT.PROCESSOR_NUMBER) ||
                    (! VALID_QUEUE(queue)) )
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        _KLOGX3(KLOG_msgq_peek, NULL, MSGQ_INVALID_QUEUE_ID);
        return (void *)message_ptr;
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
    if (msgq_ptr->QUEUE != (queue))
    {
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_QUEUE_IS_NOT_OPEN);
        return((void *)message_ptr);
    } /* Endif */

#if MQX_CHECK_ERRORS
    if (msgq_ptr->TD_PTR != NULL)
    {
        if (msgq_ptr->TD_PTR != kernel_data->ACTIVE_PTR)
        {
            _task_set_error(MSGQ_NOT_QUEUE_OWNER);
            _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_NOT_QUEUE_OWNER);
            return((void *)message_ptr);
        } /* Endif */
    } /* Endif */
#endif

    /* check the specified queue for an entry */
    _INT_DISABLE();
    if ( msgq_ptr->NO_OF_ENTRIES == 0 )
    {
        _INT_ENABLE();
#if MQXCFG_ENABLE_MSG_TIMEOUT_ERROR
        _task_set_error(MSGQ_MESSAGE_NOT_AVAILABLE);
#endif
        _KLOGX3(KLOG_msgq_peek, NULL, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else
    {
        /* Return the top entry, but keep it on the queue */
        imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
        message_ptr = (MESSAGE_HEADER_STRUCT_PTR)&imsg_ptr->MESSAGE;

        _INT_ENABLE();
        _KLOGX5(KLOG_msgq_peek, message_ptr, message_ptr->TARGET_QID, message_ptr->SOURCE_QID, *(_mqx_uint_ptr)((unsigned char *)message_ptr+sizeof(MESSAGE_HEADER_STRUCT)));
    } /* Endif */
    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Polls the message queue for a message, but do not wait if a message is 
 * not in the queue. The function is a non-blocking alternative to _msgq_receive(); 
 * therefore, ISRs can use it.
 * 
 * The function is the only way for tasks to receive messages from a system 
 * message queue.
 * \li If a system message queue has a notification function, the function can get 
 * messages from the queue with _msgq_poll().
 * \li If a message is returned, the message becomes a resource of the task.
 * 
 * \param[in] queue_id Private or system message queue from which to receive a 
 * message.
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)  
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is not valid or is not on this processor.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (There are no messages in the message queue.)
 * \li MSGQ_NOT_QUEUE_OWNER (Queue is a private message queue that the task does 
 * not own.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Queue is not open.)
 * 
 * \see _msgq_get_count
 * \see _msgq_open_system
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_send
 * \see _task_set_error
 * \see _msg_create_component
 * \see MESSAGE_HEADER_STRUCT  
 */ 
void *_msgq_poll
(
    _queue_id queue_id
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register MESSAGE_HEADER_STRUCT_PTR   message_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MSGQ_STRUCT_PTR             msgq_ptr;
    _queue_number                        queue;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msgq_poll, queue_id);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msgq_poll, NULL, MQX_COMPONENT_DOES_NOT_EXIST);
        return(NULL);
    } /* Endif */
#endif

    message_ptr = NULL;
    queue = QUEUE_FROM_QID(queue_id);

#if MQX_CHECK_ERRORS
    if ((PROC_NUMBER_FROM_QID(queue_id) != kernel_data->INIT.PROCESSOR_NUMBER) ||
                    (! VALID_QUEUE(queue)) )
    {
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_INVALID_QUEUE_ID);
        return (void *)message_ptr;
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
    if (msgq_ptr->QUEUE != (queue))
    {
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_QUEUE_IS_NOT_OPEN);
        return((void *)message_ptr);
    } /* Endif */

#if MQX_CHECK_ERRORS
    if (msgq_ptr->TD_PTR != NULL)
    {
        if (msgq_ptr->TD_PTR != kernel_data->ACTIVE_PTR)
        {
            _task_set_error(MSGQ_NOT_QUEUE_OWNER);
            _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_NOT_QUEUE_OWNER);
            return((void *)message_ptr);
        } /* Endif */
    } /* Endif */
#endif

    /* check the specified queue for an entry */
    _INT_DISABLE();
    if ( msgq_ptr->NO_OF_ENTRIES == 0 )
    {
        _INT_ENABLE();
#if MQXCFG_ENABLE_MSG_TIMEOUT_ERROR
        _task_set_error(MSGQ_MESSAGE_NOT_AVAILABLE);
#endif
        _KLOGX3(KLOG_msgq_poll, NULL, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else
    {

        --(msgq_ptr->NO_OF_ENTRIES);
        imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
        msgq_ptr->FIRST_MSG_PTR = imsg_ptr->NEXT;
        if ( msgq_ptr->FIRST_MSG_PTR == NULL )
        {
            msgq_ptr->LAST_MSG_PTR = NULL;
        }
        else
        {
            (msgq_ptr->FIRST_MSG_PTR)->PREV = NULL;
        } /* Endif */

        if ( msgq_ptr->TD_PTR )
        {
            --(msgq_ptr->TD_PTR->MESSAGES_AVAILABLE);
        } /* Endif */
        message_ptr = &imsg_ptr->MESSAGE;
        imsg_ptr->QUEUED = FALSE;
        imsg_ptr->TD_PTR = NULL;

        _INT_ENABLE();
        _KLOGX2(KLOG_msgq_poll, message_ptr);
    } /* Endif */
    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Wait for a message from the private message queue for the specified 
 * number of milliseconds.
 * 
 * The function removes the first message from the queue and returns a pointer to 
 * the message. The message becomes a resource of the task.
 * \n The function cannot be used to receive messages from system message queues; 
 * this must be done with _msgq_poll().
 * 
 * \param[in] queue_id One of the following:
 * \li Private message queue from which to receive a message.
 * \li MSGQ_ANY_QUEUE (Any queue that the task owns.)
 * \param[in] timeout  One of the following:
 * \li Maximum number of milliseconds to wait. After the timeout elapses without message, function returns.
 * \li 0 (Unlimited wait.)
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)
 * 
 * \warning If no message is available, blocks the task until the message queue 
 * gets a message or the timeout expires.
 * \warning Cannot be called from an ISR.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is for a specific queue, but the ID is 
 * not valid.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (No messages were in the message queue before 
 * the timeout expired.)
 * \li MSGQ_NOT_QUEUE_OWNER (Message is not a resource of the task.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN One of the following: specific queue is not open 
 * or queue_id is MSGQ_ANY_QUEUE, but the task has no queues open.
 * 
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_get_count
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_send
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */ 
void *_msgq_receive
(
    _queue_id queue_id,
    uint32_t   timeout
)
{ /* Body */
    MQX_TICK_STRUCT           ticks;
#if MQX_KERNEL_LOGGING
    KERNEL_DATA_STRUCT_PTR    kernel_data;
#endif
    MESSAGE_HEADER_STRUCT_PTR message_ptr;
    _mqx_uint                 error;

#if MQX_KERNEL_LOGGING
    _GET_KERNEL_DATA(kernel_data);
    _KLOGE3(KLOG_msgq_receive, queue_id, timeout);
#endif

    if (timeout)
    {
        /* Compute the number of tick events required to accomplish the least amount of time[ms]. */
        /* tick_events = (required_time[ms] + (time_per_tick[ms] - 1)) / time_per_tick[ms]) + 1  --> 
         * tick_events = ((required_time[ms] - 1) / time_per_tick[ms]) + 2
         */
        timeout--;
        /* Convert milliseconds to ticks, truncated */
        PSP_MILLISECONDS_TO_TICKS_QUICK(timeout, &ticks);
        /* Resolve truncation by adding one tick. Add another tick to accomplish the requested amount of time. */
        PSP_ADD_TICKS_TO_TICK_STRUCT(&ticks, 2, &ticks);

        message_ptr = _msgq_receive_internal(queue_id, &ticks,
                        MSG_TIMEOUT_RELATIVE, &error);
    }
    else
    {
        message_ptr = _msgq_receive_internal(queue_id, &ticks,
                        MSG_TIMEOUT_NONE, &error);
    } /* Endif */

#if MQX_KERNEL_LOGGING
    if ( (error == MQX_OK) && (message_ptr == NULL) )
    {
        _KLOGX3(KLOG_msgq_receive, message_ptr, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else if (error == MQX_OK)
    {
        _KLOGX5(KLOG_msgq_receive, message_ptr, message_ptr->TARGET_QID,
                        message_ptr->SOURCE_QID, *(_mqx_uint_ptr)((unsigned char *)message_ptr+
                                        sizeof(MESSAGE_HEADER_STRUCT)));
    }
    else
    {
        _KLOGX3(KLOG_msgq_receive, message_ptr, error);
    } /* Endif */
#endif

    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Wait for a message from the private message queue for the specified 
 * number of ticks (in tick time).
 * 
 * The function removes the first message from the queue and returns a pointer to 
 * the message. The message becomes a resource of the task.
 * \n The function cannot be used to receive messages from system message queues; 
 * this must be done with _msgq_poll().
 * 
 * \param[in] queue_id One of the following:
 * \li Private message queue from which to receive a message.
 * \li MSGQ_ANY_QUEUE (Any queue that the task owns.)
 * \param[in] tick_ptr  One of the following:
 * \li Pointer to the maximum number of ticks to wait.
 * \li NULL (Unlimited wait.)
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)
 * 
 * \warning If no message is available, blocks the task until the message queue 
 * gets a message or the timeout expires.
 * \warning Cannot be called from an ISR.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is for a specific queue, but the ID is 
 * not valid.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (No messages were in the message queue before 
 * the timeout expired.)
 * \li MSGQ_NOT_QUEUE_OWNER (Message is not a resource of the task.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN One of the following: specific queue is not open 
 * or queue_id is MSGQ_ANY_QUEUE, but the task has no queues open.
 * 
 * \see _msgq_receive
 * \see _msgq_receive_ticks
 * \see _msgq_receive_until
 * \see _msgq_get_count
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_send
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */
void *_msgq_receive_for
(
    _queue_id           queue_id,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
#if MQX_KERNEL_LOGGING
    KERNEL_DATA_STRUCT_PTR    kernel_data;
#endif
    MESSAGE_HEADER_STRUCT_PTR message_ptr;
    _mqx_uint                 error;

#if MQX_KERNEL_LOGGING
    _GET_KERNEL_DATA(kernel_data);
    _KLOGE3(KLOG_msgq_receive_for, queue_id, tick_ptr);
#endif

    message_ptr = _msgq_receive_internal(queue_id, tick_ptr,
                    MSG_TIMEOUT_RELATIVE, &error);

#if MQX_KERNEL_LOGGING
    if ( (error == MQX_OK) && (message_ptr == NULL) )
    {
        _KLOGX3(KLOG_msgq_receive_for, message_ptr, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else if (error == MQX_OK)
    {
        _KLOGX5(KLOG_msgq_receive_for, message_ptr, message_ptr->TARGET_QID,
                        message_ptr->SOURCE_QID, *(_mqx_uint_ptr)((unsigned char *)message_ptr+
                                        sizeof(MESSAGE_HEADER_STRUCT)));
    }
    else
    {
        _KLOGX3(KLOG_msgq_receive_for, message_ptr, error);
    } /* Endif */
#endif

    return (void *)message_ptr;

} /* Endbody */

/*!
 * \private
 * 
 * \brief Dequeue the first item from the specified queue.
 * 
 * \param[in]  queue_id         ID of the queue from which a message is to be 
 * received.
 * \param[in]  timeout_tick_ptr Indication of the number of ticks which can expire 
 * before this request times out.
 * \param[in]  mode             Relative or absolute time specified in tick_ptr.
 * \param[out] error_ptr        Where the error code is to be stored.   
 *  
 * \return Pointer to the message (Success).
 * \return NULL (Failure.)   
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_CANNOT_CALL_FUNCTION_FROM_ISR
 * \li MQX_COMPONENT_DOES_NOT_EXIST
 * \li MSGQ_QUEUE_IS_NOT_OPEN
 * \li MSGQ_INVALID_QUEUE_ID
 * \li MSGQ_NOT_QUEUE_OWNER
 * \li MSGQ_MESSAGE_NOT_AVAILABLE
 * \li MSGQ_INVALID_MESSAGE  
 */ 
MESSAGE_HEADER_STRUCT_PTR _msgq_receive_internal
(
    _queue_id           queue_id,
    MQX_TICK_STRUCT_PTR timeout_tick_ptr,
    _mqx_uint           mode,
    _mqx_uint_ptr       error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register TD_STRUCT_PTR               td_ptr;
    MESSAGE_HEADER_STRUCT_PTR            message_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MSGQ_STRUCT_PTR             msgq_ptr;
    _queue_number                        queue;

    *error_ptr = MQX_OK;

    _GET_KERNEL_DATA(kernel_data);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _task_set_error(MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        *error_ptr = MQX_CANNOT_CALL_FUNCTION_FROM_ISR;
        return(NULL);
    }/* Endif */
#endif

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        *error_ptr = MQX_COMPONENT_DOES_NOT_EXIST;
        return(NULL);
    } /* Endif */
#endif

    message_ptr = NULL;
    td_ptr = kernel_data->ACTIVE_PTR;

    if (queue_id == MSGQ_ANY_QUEUE)
    {
        /* if queue_id is 0 than a receive from any queue is performed */

        /* Does the task own a queue */
        if (td_ptr->MSG_QUEUE_HEAD == NULL)
        {
            /* Does NOT */
            _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
            *error_ptr = MSGQ_QUEUE_IS_NOT_OPEN;
            return NULL;
        } /* Endif */

        _INT_DISABLE();
        if (td_ptr->MESSAGES_AVAILABLE == 0)
        {
            td_ptr->STATE = RCV_ANY_BLOCKED;
            td_ptr->INFO = queue_id;
            td_ptr->MESSAGE = NULL;

            if (mode == MSG_TIMEOUT_NONE)
            {
                _task_block();
            }
            else if (mode == MSG_TIMEOUT_RELATIVE)
            {
                _time_delay_for(timeout_tick_ptr);
            }
            else
            {
                _time_delay_until(timeout_tick_ptr);
            } /* Endif */

            /* 
             * SHORTCUT...
             * The message send routine does not queue up a message in this case.
             * the message is deposited directly into the task descriptor
             */
            message_ptr = (MESSAGE_HEADER_STRUCT_PTR)td_ptr->MESSAGE;
            if (message_ptr == NULL)
            {
                /* A timeout has occurred */
#if MQXCFG_ENABLE_MSG_TIMEOUT_ERROR
                _task_set_error(MSGQ_MESSAGE_NOT_AVAILABLE);
#endif
            } /* Endif */
            td_ptr->MESSAGE = NULL;

        }
        else
        {

            /*  Check all queues for an available entry .. There must be at least
             *  one entry available
             */
            msgq_ptr = (MSGQ_STRUCT_PTR)td_ptr->MSG_QUEUE_HEAD;
            while (msgq_ptr != NULL)
            {

                if (msgq_ptr->NO_OF_ENTRIES)
                {
                    /* dequeue the top entry */
                    DEQUEUE_TOP_MSG_ENTRY(msgq_ptr, imsg_ptr, message_ptr, td_ptr);
                    break;
                } /* Endif */
                msgq_ptr = msgq_ptr->NEXT_MSGQ_PTR;

            } /* Endwhile */
        } /* Endif */

    }
    else
    {

        /* RECEIVE from a specific qid */
        queue = QUEUE_FROM_QID(queue_id);
#if MQX_CHECK_ERRORS
        if ( (PROC_NUMBER_FROM_QID(queue_id) != kernel_data->INIT.PROCESSOR_NUMBER) ||
                        (! VALID_QUEUE(queue)) )
        {
            _task_set_error(MSGQ_INVALID_QUEUE_ID);
            *error_ptr = MSGQ_INVALID_QUEUE_ID;
            return (void *)message_ptr;
        } /* Endif */
#endif

        msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
#if MQX_CHECK_ERRORS
        if ( msgq_ptr->QUEUE != queue )
        {
            _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
            *error_ptr = MSGQ_QUEUE_IS_NOT_OPEN;
            return message_ptr;
        } /* Endif */
        if ( (msgq_ptr->TD_PTR != NULL) && (msgq_ptr->TD_PTR != td_ptr) )
        {
            _task_set_error(MSGQ_NOT_QUEUE_OWNER);
            *error_ptr = MSGQ_NOT_QUEUE_OWNER;
            return message_ptr;
        } /* Endif */
#endif

        /*
         * check the specified queue for an entry
         * if not entry, then block until an entry is received or
         * timeout occurs
         */
        _INT_DISABLE();
        if (msgq_ptr->NO_OF_ENTRIES == 0)
        {
            if (msgq_ptr->TD_PTR == NULL)
            {
                /* A system message queue, indicate none available */
                message_ptr = NULL;
            }
            else
            {
                td_ptr->STATE = RCV_SPECIFIC_BLOCKED;
                td_ptr->INFO = queue;
                td_ptr->MESSAGE = NULL;

                if (mode == MSG_TIMEOUT_NONE)
                {
                    _task_block();
                }
                else if (mode == MSG_TIMEOUT_RELATIVE)
                {
                    _time_delay_for(timeout_tick_ptr);
                }
                else
                {
                    _time_delay_until(timeout_tick_ptr);
                } /* Endif */

                message_ptr = (MESSAGE_HEADER_STRUCT_PTR)td_ptr->MESSAGE;
                if ( message_ptr == NULL )
                {
#if MQXCFG_ENABLE_MSG_TIMEOUT_ERROR
                    _task_set_error(MSGQ_MESSAGE_NOT_AVAILABLE);
#endif
                }
                else if ((message_ptr->TARGET_QID != queue_id) &&
                                (msgq_ptr->NO_OF_ENTRIES > 0))
                {
                    /* The original msg was swapped out in msgq_sendi() for 
                     * a higher priority msg with a different target_qid.
                     * Enqueue this msg, and then dequeue the msg we need.
                     */
                    register MSGQ_STRUCT_PTR tmp_msgq_ptr;
                    register _queue_number tmp_queue;

                    /* Get the msg's queue */
                    tmp_queue = QUEUE_FROM_QID(message_ptr->TARGET_QID);
                    tmp_msgq_ptr = &msg_component_ptr->MSGQS_PTR[tmp_queue];

                    if ((tmp_msgq_ptr->MAX_ENTRIES == 0) ||
                                    (tmp_msgq_ptr->NO_OF_ENTRIES < tmp_msgq_ptr->MAX_ENTRIES))
                    {
                        /* the msg's queue has room */
                        imsg_ptr = GET_INTERNAL_MESSAGE_PTR(message_ptr);

#if MQX_CHECK_ERRORS
                        if (imsg_ptr->VALID != MSG_VALID)
                        {
                            /* An invalid message was input by the application. */
                            _task_set_error(MSGQ_INVALID_MESSAGE);
                            message_ptr = NULL;
                        }
                        else
#endif
                        {
                            /* enqueue the msg */
                            _msgq_insert_message_internal(tmp_msgq_ptr, imsg_ptr, TRUE);

                            if (tmp_msgq_ptr->TD_PTR)
                            {
                                ++(tmp_msgq_ptr->TD_PTR->MESSAGES_AVAILABLE);
                            } /* Endif */

                            /* now dequeue our queue's top entry */
                            DEQUEUE_TOP_MSG_ENTRY(msgq_ptr, imsg_ptr, message_ptr, td_ptr);
                        }
                    }
                    else
                    {
                        /* Queue full, error - this should not happen 
                         * since msgq_sendi() checks for room on the queue 
                         * for all msgs, including short-cut msgs. 
                         */
                        _task_set_error(MSGQ_QUEUE_FULL);
                        message_ptr = NULL;
                    }
                } /* Endif */
                td_ptr->MESSAGE = NULL;
            } /* Endif */
        }
        else
        {
            /* dequeue the top entry */
            DEQUEUE_TOP_MSG_ENTRY(msgq_ptr, imsg_ptr, message_ptr, td_ptr);
        } /* Endif */
    } /* Endif */

    _INT_ENABLE();

    return message_ptr;

} /* Endbody */

/*!
 * \brief Wait for a message from the private message queue for the specified 
 * number of ticks.
 * 
 * The function removes the first message from the queue and returns a pointer to 
 * the message. The message becomes a resource of the task.
 * \n The function cannot be used to receive messages from system message queues; 
 * this must be done with _msgq_poll().
 * 
 * \param[in] queue_id One of the following:
 * \li Private message queue from which to receive a message.
 * \li MSGQ_ANY_QUEUE (Any queue that the task owns.)
 * \param[in] time_in_ticks  One of the following:
 * \li Maximum number of ticks to wait.
 * \li 0 (Unlimited wait.)
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)
 * 
 * \warning If no message is available, blocks the task until the message queue 
 * gets a message or the timeout expires.
 * \warning Cannot be called from an ISR.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is for a specific queue, but the ID is 
 * not valid.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (No messages were in the message queue before 
 * the timeout expired.)
 * \li MSGQ_NOT_QUEUE_OWNER (Message is not a resource of the task.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN One of the following: specific queue is not open 
 * or queue_id is MSGQ_ANY_QUEUE, but the task has no queues open.
 * 
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_until
 * \see _msgq_get_count
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_send
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */ 
void *_msgq_receive_ticks
(
    _queue_id queue_id,
    _mqx_uint time_in_ticks
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    MESSAGE_HEADER_STRUCT_PTR message_ptr;
    _mqx_uint error;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE3(KLOG_msgq_receive_ticks, queue_id, time_in_ticks);

    if (time_in_ticks)
    {
        _time_init_ticks(&ticks, time_in_ticks);

        message_ptr = _msgq_receive_internal(queue_id, &ticks, MSG_TIMEOUT_RELATIVE, &error);
    }
    else
    {
        message_ptr = _msgq_receive_internal(queue_id, &ticks, MSG_TIMEOUT_NONE, &error);
    } /* Endif */

#if MQX_KERNEL_LOGGING
    if ( (error == MQX_OK) && (message_ptr == NULL) )
    {
        _KLOGX3(KLOG_msgq_receive_ticks, message_ptr, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else if (error == MQX_OK)
    {
        _KLOGX5(KLOG_msgq_receive_ticks, message_ptr, message_ptr->TARGET_QID,
                        message_ptr->SOURCE_QID, *(_mqx_uint_ptr)((unsigned char *)message_ptr+
                                        sizeof(MESSAGE_HEADER_STRUCT)));
    }
    else
    {
        _KLOGX3(KLOG_msgq_receive_ticks, message_ptr, error);
    } /* Endif */
#endif

    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Wait for a message from the private message queue until the specified 
 * time (in tick time).
 * 
 * The function removes the first message from the queue and returns a pointer to 
 * the message. The message becomes a resource of the task.
 * \n The function cannot be used to receive messages from system message queues; 
 * this must be done with _msgq_poll().
 * 
 * \param[in] queue_id One of the following:
 * \li Private message queue from which to receive a message.
 * \li MSGQ_ANY_QUEUE (Any queue that the task owns.)
 * \param[in] tick_ptr One of the following:
 * \li Pointer to the time (in tick time) until which to wait.
 * \li NULL (Unlimited wait)
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)
 * 
 * \warning If no message is available, blocks the task until the message queue 
 * gets a message or the timeout expires.
 * \warning Cannot be called from an ISR.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_QUEUE_ID (Queue_id is for a specific queue, but the ID is 
 * not valid.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (No messages were in the message queue before 
 * the timeout expired.)
 * \li MSGQ_NOT_QUEUE_OWNER (Message is not a resource of the task.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN One of the following: specific queue is not open 
 * or queue_id is MSGQ_ANY_QUEUE, but the task has no queues open.
 * 
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks
 * \see _msgq_get_count
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_send
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */
void *_msgq_receive_until
(
    _queue_id           queue_id,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
#if MQX_KERNEL_LOGGING
    KERNEL_DATA_STRUCT_PTR    kernel_data;
#endif
    MESSAGE_HEADER_STRUCT_PTR message_ptr;
    _mqx_uint                 error;

#if MQX_KERNEL_LOGGING
    _GET_KERNEL_DATA(kernel_data);
    _KLOGE3(KLOG_msgq_receive_for, queue_id, tick_ptr);
#endif

    message_ptr = _msgq_receive_internal(queue_id, tick_ptr,
                    MSG_TIMEOUT_ABSOLUTE, &error);

#if MQX_KERNEL_LOGGING
    if ( (error == MQX_OK) && (message_ptr == NULL) )
    {
        _KLOGX3(KLOG_msgq_receive_until, message_ptr, MSGQ_MESSAGE_NOT_AVAILABLE);
    }
    else if (error == MQX_OK)
    {
        _KLOGX5(KLOG_msgq_receive_until, message_ptr, message_ptr->TARGET_QID,
                        message_ptr->SOURCE_QID, *(_mqx_uint_ptr)((unsigned char *)message_ptr+
                                        sizeof(MESSAGE_HEADER_STRUCT)));
    }
    else
    {
        _KLOGX3(KLOG_msgq_receive_until, message_ptr, error);
    } /* Endif */
#endif

    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Sends the message to the message queue.
 * 
 * The function sends a message (priority 0) to a private message queue or a system 
 * message queue. The function does not block. The message must be from one of:
 * \li _msg_alloc()
 * \li _msg_alloc_system()
 * \li _msgq_poll()
 * \li _msgq_receive()
 * The message must be overlaid with MESSAGE_HEADER_STRUCT, with the data portion 
 * following the header. In the header, the sending task sets:
 * \li TARGET_ID to a valid queue ID for the local processor or for a remote 
 * processor (if TARGET_ID is for a remote processor, the function cannot verify 
 * the ID or determine whether the maximum size of the queue is reached).
 * \li SIZE to the number of single-addressable units in the message, including 
 * the header. If the message is for a meesage queue on a local processor, then MQX send the 
 * message to the message queue. Otherwise, it is sent to the remote processor. 
 * If the function returns successfully, the message is no longer a resource 
 * of the task.
 *  
 * \param[in] input_msg_ptr Pointer to the message to be sent.
 * 
 * \return TRUE (Success: see Description.) or FALSE (Failure.)
 * 
 * \warning Might dispatch a task.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * 
 * <table>
 *   <tr>
 *     <td><b>Task error code</b></td>
 *     <td><b>Meaning</b></td>
 *     <td><b>Message accepted</b></td>
 *     <td><b>Message freed</b></td>    
 *   </tr>
 *   <tr>
 *     <td>MQX_COMPONENT_DOES_NOT_EXIST</td>
 *     <td>Message component is not created.</td>
 *     <td>No</td>
 *     <td>No</td>    
 *   </tr>
 *   <tr>
 *     <td>MSGQ_INVALID_MESSAGE</td>
 *     <td>msg_ptr is NULL or points to a message that is one of:
 *     \li not valid
 *     \li on a message queue
 *     \li free</td>
 *     <td>No</td>
 *     <td>No</td>    
 *   </tr>
 *   <tr>
 *     <td>MSGQ_INVALID_QUEUE_ID</td>
 *     <td>Target ID is not a valid queue ID.</td>
 *     <td>No</td>
 *     <td>Yes</td>    
 *   </tr>
 *   <tr>
 *     <td>MSGQ_QUEUE_FULL</td>
 *     <td>Target message queue has reached its maximum size.</td>
 *     <td>No</td>
 *     <td>Yes</td>    
 *   </tr>
 *   <tr>
 *     <td>MSGQ_QUEUE_IS_NOT_OPEN</td>
 *     <td>Target ID does not represent an open message queue.</td>
 *     <td>No</td>
 *     <td>Yes</td>    
 *   </tr>
 *   <tr>
 *     <td>Task error codes from _msg_free()</td>
 *     <td>(If message needs to be freed.)</td>
 *     <td>Yes</td>
 *     <td>No</td>    
 *   </tr>        
 * </table>   
 * 
 * \see _msg_alloc_system
 * \see _msg_alloc
 * \see _msgq_open
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks 
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _msgq_send_priority
 * \see _msgq_send_urgent
 * \see _msg_free
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT  
 */ 
bool _msgq_send
(
    void   *input_msg_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    MESSAGE_HEADER_STRUCT_PTR msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
    input_msg_ptr;
    bool result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_msgq_send, msg_ptr, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->TARGET_QID, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->SOURCE_QID);

    result = _msgq_send_internal(msg_ptr, FALSE, msg_ptr->TARGET_QID);

    _KLOGX2(KLOG_msgq_send, result);

    return(result);

} /* Endbody */
/*!
 * \private
 *  
 * \brief Verify the input queue_id and try to send the message directly.
 *
 * This can only be used by tasks.
 * \n The calling task is blocked after the send.
 * 
 * \param[in] input_msg_ptr Pointer to the message being sent by application.
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \see _msgq_send_internal  
 */ 
bool _msgq_send_blocked_internal
(
    void   *input_msg_ptr
)
{ /* Body */
    bool result;
    MESSAGE_HEADER_STRUCT_PTR msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
    input_msg_ptr;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE4(KLOG_msgq_send_blocked, msg_ptr, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->TARGET_QID, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->SOURCE_QID);

    result = _msgq_send_internal(msg_ptr, TRUE, msg_ptr->TARGET_QID);

    _KLOGX2(KLOG_msgq_send_blocked, result);
    return(result);

} /* Endbody */

/*!
 * \private
 * 
 * \brief Verify the input queue_id and try to send the message directly.
 * 
 * \param[in] msg_ptr    Pointer to the message being sent by application.
 * \param[in] blocking   Is the calling task to be blocked after the call.
 * \param[in] target_qid The queue to put the message onto.
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_INVALID_MESSAGE (Msg_ptr is NULL or points to a message that is: not 
 * valid, on a message queue or free}.
 * \li MSGQ_INVALID_QUEUE_ID (Target ID is not a valid queue ID.)
 * \li MSGQ_QUEUE_FULL (Target message queue has reached its maximum size.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN (Target ID does not represent an open message queue.)
 * \li Task error codes from _msg_free() (If message needs to be freed.) 
 */ 
bool _msgq_send_internal
(
    MESSAGE_HEADER_STRUCT_PTR msg_ptr,
    bool                   blocking,
    _queue_id                 target_qid
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MSGQ_STRUCT_PTR             msgq_ptr;
    register TD_STRUCT_PTR               td_ptr;
    MESSAGE_HEADER_STRUCT_PTR            tmp_msg_ptr;
    register _mqx_uint                   state;
    register _queue_number               queue;
    register _processor_number           pnum;
    bool                              swapped_msg;

    _GET_KERNEL_DATA(kernel_data);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        return(FALSE);
    } /* Endif */
    if (msg_ptr == NULL)
    {
        _task_set_error(MSGQ_INVALID_MESSAGE);
        return(FALSE);
    } /* Endif */
#endif

    imsg_ptr = GET_INTERNAL_MESSAGE_PTR(msg_ptr);

#if MQX_CHECK_ERRORS
    if (imsg_ptr->VALID != MSG_VALID)
    {
        /* An invalid message was input by the application. */
        _task_set_error(MSGQ_INVALID_MESSAGE);
        return FALSE;
    } /* Endif */
#endif

#if MQX_CHECK_ERRORS
    if (imsg_ptr->FREE || imsg_ptr->QUEUED)
    {
        /* Trying to send a free message, or one on a message queue. */
        _task_set_error(MSGQ_INVALID_MESSAGE);
        return FALSE;
    } /* Endif */
#endif

    pnum = PROC_NUMBER_FROM_QID(target_qid);

    /* If processor number is zero then the message is for this processor */
    if (pnum == 0)
    {
        /* Fix up the target QID in the message header */
        msg_ptr->TARGET_QID = BUILD_QID(kernel_data->INIT.PROCESSOR_NUMBER,
                        msg_ptr->TARGET_QID);
    }
    else if (pnum != kernel_data->INIT.PROCESSOR_NUMBER)
    {
#if MQX_IS_MULTI_PROCESSOR
        IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR ipc_msg_comp_ptr;
        ipc_msg_comp_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR)
        kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING];
        if (ipc_msg_comp_ptr && ipc_msg_comp_ptr->MSG_ROUTER)
        {
            return( (*ipc_msg_comp_ptr->MSG_ROUTER)(pnum, msg_ptr, blocking));
        }
        else
        {
#endif
            _msg_free(msg_ptr);
            _task_set_error(MSGQ_INVALID_QUEUE_ID);
            return FALSE;
#if MQX_IS_MULTI_PROCESSOR
        }/* Endif */
#endif
    } /* Endif */

    queue = QUEUE_FROM_QID(target_qid);

#if MQX_CHECK_ERRORS
    if ( ! VALID_QUEUE(queue))
    {
        _msg_free(msg_ptr);
        _task_set_error(MSGQ_INVALID_QUEUE_ID);
        return FALSE;
    } /* Endif */
#endif

    msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];
    if (msgq_ptr->QUEUE != queue)
    {
        msgq_ptr = NULL;
    } /* Endif */

#if MQX_CHECK_ERRORS
    if (msgq_ptr == NULL)
    {
        _msg_free(msg_ptr);
        _task_set_error(MSGQ_QUEUE_IS_NOT_OPEN);
        return FALSE;
    } /* Endif */
#endif

    _INT_DISABLE();

    if ((msgq_ptr->MAX_ENTRIES == 0) ||
                    (msgq_ptr->NO_OF_ENTRIES < msgq_ptr->MAX_ENTRIES))
    {

        /* There is room on the queue, so add the msg.  We 
         * need to check for room here even if the msg ends up
         * being short-cutted to the receiver (via td_ptr->MESSAGE)
         * in case msg_receive needs to enqueue the msg.
         */

        if (msgq_ptr->TYPE == MSG_QUEUE)
        {
            /* THIS MESSAGE QUEUE IS ATTACHED TO A TASK */

            /* check for pending receive
             * if a receive is pending then satisfy the request
             * and add the receiving task onto the ready-to-run queue
             */

            td_ptr = msgq_ptr->TD_PTR;
            state = td_ptr->STATE & STATE_MASK;
            if ( (state == RCV_ANY_BLOCKED) ||
                            ((state == RCV_SPECIFIC_BLOCKED) && (td_ptr->INFO == queue)))
            {
                /* The task is blocked, waiting for a message */
                td_ptr->MESSAGE = &imsg_ptr->MESSAGE;
                imsg_ptr->TD_PTR = td_ptr;
                _TIME_DEQUEUE(td_ptr,kernel_data);
                _TASK_READY(td_ptr,kernel_data);

                /* Now run the notification function */
                if (msgq_ptr->NOTIFICATION_FUNCTION != NULL)
                {
                    (*msgq_ptr->NOTIFICATION_FUNCTION)(msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER);
                } /* Endif */

                if (blocking)
                {
                    if ( ! kernel_data->IN_ISR)
                    {
                        td_ptr = kernel_data->ACTIVE_PTR;
                        td_ptr->STATE = SEND_BLOCKED;
                        _task_block();
                    } /* Endif */
                }
                else
                {
                    /*
                     *  if the highest priority ready task is not the
                     *  same priority as the sending task, then a higher
                     *  priority task was made ready and it has to be allowed
                     *  to run.
                     */
                    _CHECK_RUN_SCHEDULER(); /* Let a higher priority task run */
                } /* Endif */

            }
            else
            {
                /* The task is ready to run and pre-empted OR blocked and
                 * on a different queue.
                 */

                swapped_msg = FALSE;
                if ((msg_ptr->CONTROL & MSG_PRIORITY_MASK) &&
                                (td_ptr->MESSAGE != NULL))
                {
                    /* Check the message in the TD */
                    tmp_msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)td_ptr->MESSAGE;
                    if ( (msg_ptr->CONTROL & MSG_HDR_URGENT) ||
                                    /* Urgent messages first */
                                    ( (! (tmp_msg_ptr->CONTROL & MSG_HDR_URGENT)) &&
                                                    ( (_mqx_uint)(tmp_msg_ptr->CONTROL & MSG_HDR_PRIORITY_MASK) <
                                                                    (_mqx_uint)(msg_ptr->CONTROL & MSG_HDR_PRIORITY_MASK))
                                    )
                    )
                    /* Higher priority messages first */
                    {
                        /* Put new message into TD */
                        td_ptr->MESSAGE = msg_ptr;

                        /* Set the new message's ownership to the receiving queue's TD */
                        imsg_ptr = GET_INTERNAL_MESSAGE_PTR(msg_ptr);
                        imsg_ptr->TD_PTR = td_ptr;

                        /* Old message which we pulled from TD, need to add to queue, below */
                        msg_ptr = tmp_msg_ptr;
                        imsg_ptr = GET_INTERNAL_MESSAGE_PTR(msg_ptr);

                        /* Don't know the sender's TD for the swapped out msg,
                         * so set it to NULL; 
                         */
                        imsg_ptr->TD_PTR = NULL;
                        /* Indicate that a swap occurred */
                        swapped_msg = TRUE;
                        /* Set the queue to the swapped msg's queue. */
                        if (target_qid != msg_ptr->TARGET_QID)
                        {
                            queue = QUEUE_FROM_QID(msg_ptr->TARGET_QID);
                            msgq_ptr = &msg_component_ptr->MSGQS_PTR[queue];

                            /* This msg's queue was not full when it was short-cut,
                             * so we should not get here.  Check anyway. 
                             */
                            if ((msgq_ptr->MAX_ENTRIES != 0) &&
                                            (msgq_ptr->NO_OF_ENTRIES >= msgq_ptr->MAX_ENTRIES))
                            {
                                /* Queue full, error */
                                _INT_ENABLE();
                                _msg_free(msg_ptr);
                                _task_set_error(MSGQ_QUEUE_FULL);
                                return FALSE;
                            } /* Endif */
                        } /* Endif */
                    } /* Endif */
                } /* Endif */

                /* add the message */
                _msgq_insert_message_internal(msgq_ptr, imsg_ptr, swapped_msg);

                if (msgq_ptr->TD_PTR)
                {
                    ++(msgq_ptr->TD_PTR->MESSAGES_AVAILABLE);
                } /* Endif */

                /* Now run the notification function */
                if (msgq_ptr->NOTIFICATION_FUNCTION != NULL)
                {
                    (*msgq_ptr->NOTIFICATION_FUNCTION)(msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER);
                } /* Endif */

                if (blocking && ! kernel_data->IN_ISR )
                {
                    td_ptr = kernel_data->ACTIVE_PTR;
                    td_ptr->STATE = SEND_BLOCKED;
                    _task_block();
                } /* Endif */

            } /* Endif */

        }
        else
        {
            /* THIS IS A SYSTEM QUEUE NOT ATTACHED TO A TASK */

            /* add the message to the queue */
            _msgq_insert_message_internal(msgq_ptr, imsg_ptr, FALSE);

            /* Run the notification function. */
            if ( msgq_ptr->NOTIFICATION_FUNCTION != NULL )
            {
                (*msgq_ptr->NOTIFICATION_FUNCTION)(msgq_ptr->NOTIFICATION_FUNCTION_PARAMETER);
            } /* Endif */

        } /* Endif */

    }
    else
    {
        /* Queue full, error */
        _INT_ENABLE();
        _task_set_error(MSGQ_QUEUE_FULL);
        _msg_free(&imsg_ptr->MESSAGE);
        return FALSE;
    } /* Endif */

    _INT_ENABLE();
    return TRUE; /* Message sent MQX_OK */

} /* Endbody */

/*!
 * \private
 * 
 * \brief Inserts the message into the message queue according to its priority 
 * and urgency.
 * 
 * \param[in] msgq_ptr    The message queue to put the message onto.
 * \param[in] imsg_ptr    The message which is to be inserted.
 * \param[in] swapped_msg Was this message swapped out from the TD?
 */ 
void _msgq_insert_message_internal
(
    register MSGQ_STRUCT_PTR             msgq_ptr,
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr,
    register bool                     swapped_msg
)
{ /* Body */
    register INTERNAL_MESSAGE_STRUCT_PTR prev_imsg_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR next_imsg_ptr;
    _mqx_uint                            control;
    _mqx_uint                            priority;

    if (msgq_ptr->FIRST_MSG_PTR == NULL)
    {
        imsg_ptr->PREV = NULL;
        imsg_ptr->NEXT = NULL;
        msgq_ptr->FIRST_MSG_PTR = imsg_ptr;
        msgq_ptr->LAST_MSG_PTR = imsg_ptr;
    }
    else
    {
        if (imsg_ptr->MESSAGE.CONTROL & MSG_HDR_URGENT || swapped_msg)
        {
            /* Insert at front if urgent 
             * OR if we are dealing with message previously in TD that was pulled 
             * out by a higher priority message. 
             */
            imsg_ptr->NEXT = msgq_ptr->FIRST_MSG_PTR;
            imsg_ptr->PREV = NULL;
            (msgq_ptr->FIRST_MSG_PTR)->PREV = imsg_ptr;
            msgq_ptr->FIRST_MSG_PTR = imsg_ptr;
        }
        else if (imsg_ptr->MESSAGE.CONTROL & MSG_HDR_PRIORITY_MASK)
        {
            /* We must insert the message into the queue */
            priority = imsg_ptr->MESSAGE.CONTROL & MSG_HDR_PRIORITY_MASK;
            prev_imsg_ptr = NULL;
            next_imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
            while (next_imsg_ptr)
            {
                control = next_imsg_ptr->MESSAGE.CONTROL & MSG_HDR_PRIORITY_MASK;
                if (priority > control)
                {
                    break;
                } /* Endif */
                prev_imsg_ptr = next_imsg_ptr;
                next_imsg_ptr = next_imsg_ptr->NEXT;
            } /* Endwhile */

            if (prev_imsg_ptr == NULL)
            {
                /* Insert at front */
                imsg_ptr->NEXT = msgq_ptr->FIRST_MSG_PTR;
                imsg_ptr->PREV = NULL;
                (msgq_ptr->FIRST_MSG_PTR)->PREV = imsg_ptr;
                msgq_ptr->FIRST_MSG_PTR = imsg_ptr;
            }
            else if (next_imsg_ptr == NULL)
            {
                /* Insert at end */
                imsg_ptr->PREV = msgq_ptr->LAST_MSG_PTR;
                imsg_ptr->NEXT = NULL;
                (msgq_ptr->LAST_MSG_PTR)->NEXT = imsg_ptr;
                msgq_ptr->LAST_MSG_PTR = imsg_ptr;
            }
            else
            {
                /* Insert in middle */
                imsg_ptr->PREV = prev_imsg_ptr;
                imsg_ptr->NEXT = next_imsg_ptr;
                prev_imsg_ptr->NEXT = imsg_ptr;
                next_imsg_ptr->PREV = imsg_ptr;
            } /* Endif */
        }
        else
        {
            /* Tack on to end */
            imsg_ptr->PREV = msgq_ptr->LAST_MSG_PTR;
            imsg_ptr->NEXT = NULL;
            (msgq_ptr->LAST_MSG_PTR)->NEXT = imsg_ptr;
            msgq_ptr->LAST_MSG_PTR = imsg_ptr;
        } /* Endif */
    } /* Endif */

    ++(msgq_ptr->NO_OF_ENTRIES);
    imsg_ptr->QUEUED = TRUE;

} /* Endbody */

/*!
 * \brief Sends the priority message to the message queue.
 * 
 * The function inserts the message in a message queue based on the priority of 
 * the message; it inserts higher-priority messages ahead of lower-priority ones. 
 * Messages with the same priority are inserted in FIFO order.
 * \n If the function returns successfully, the message is no longer a resource 
 * of the task.
 * \n Messages sent with _msgq_send() and _msgq_send_broadcast() are priority 0 
 * messages.
 * 
 * \param[in] input_msg_ptr Pointer to the message to be sent.
 * \param[in] priority      Priority of the message, between:
 * \li 0 (Lowest.)
 * \li MSG_MAX_PRIORITY (highest; 15.)
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \warning Might dispatch a task.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li See _msgq_send() for error codes.
 * \li MSGQ_INVALID_MESSAGE_PRIORITY (Priority is greater than MSG_MAX_PRIORITY 
 * (message is not accepted and is not freed).)
 * 
 * \see _msgq_send   
 * \see _msg_alloc_system
 * \see _msg_alloc
 * \see _msgq_send_broadcast
 * \see _msgq_send_urgent
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks 
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT     
 */ 
bool _msgq_send_priority
(
    void     *input_msg_ptr,
    _mqx_uint priority

)
{ /* Body */
    bool result;
    MESSAGE_HEADER_STRUCT_PTR msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
    input_msg_ptr;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE6(KLOG_msgq_send_priority, msg_ptr, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->TARGET_QID, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->SOURCE_QID, priority, urgent);

    if (priority > MSG_MAX_PRIORITY)
    {
        _task_set_error(MSGQ_INVALID_MESSAGE_PRIORITY);
        _KLOGX2(KLOG_msgq_send_priority, FALSE);
        return FALSE;
    } /* Endif */

    msg_ptr->CONTROL &= 0xF0;
    msg_ptr->CONTROL |= (priority & 0xF);

    result = _msgq_send_internal(msg_ptr, FALSE, msg_ptr->TARGET_QID);

    _KLOGX2(KLOG_msgq_send_priority, result);
    return(result);

} /* Endbody */

/*!
 * \brief Sends the message directly to the private or system message queue.
 * 
 * The function uses qid instead of the target queue ID that the message header 
 * specifies and sends the message as described for _msgq_send().
 * \n If the function returns successfully, the message is no longer a resource 
 * of the task.
 * 
 * \param[in] msg_ptr Pointer to the message to be sent.
 * \param[in] qid     Message queue into which to put the message.
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \warning Might dispatch a task
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li See _msgq_send() for error codes.
 * 
 * \see _msgq_send   
 * \see _msgq_send_broadcast
 * \see _msgq_send_urgent
 * \see _msgq_send_priority
 * \see _msg_alloc_system
 * \see _msg_alloc
 * \see _msgq_open
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks 
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT
 */ 
bool _msgq_send_queue
(
    void     *msg_ptr,
    _queue_id qid
)
{ /* Body */
    bool result;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_msgq_send_queue, msg_ptr, qid, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->SOURCE_QID);

    result = _msgq_send_internal((MESSAGE_HEADER_STRUCT_PTR)msg_ptr, FALSE, qid);

    _KLOGX2(KLOG_msgq_send_queue, result);
    return(result);

} /* Endbody */

/*!
 * \brief Sends the urgent message to the message queue.
 * 
 * The function sends the message as described for _msgq_send().
 * \n The function puts the message at the start of the message queue, ahead of 
 * any other urgent messages.
 * \n If the function returns successfully, the message is no longer a resource 
 * of the task.
 * 
 * \param[in] input_msg_ptr Pointer to the message to be sent.
 * 
 * \return TRUE (Success.) or FALSE (Failure.)
 * 
 * \warning Might dispatch a task
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li See _msgq_send() for error codes.
 * 
 * \see _msgq_send   
 * \see _msgq_send_priority
 * \see _msgq_send_queue
 * \see _msg_alloc_system
 * \see _msg_alloc
 * \see _msgq_receive
 * \see _msgq_receive_for
 * \see _msgq_receive_ticks 
 * \see _msgq_receive_until
 * \see _msgq_poll
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */ 
bool _msgq_send_urgent
(
    void   *input_msg_ptr
)
{ /* Body */
    bool result;
    MESSAGE_HEADER_STRUCT_PTR msg_ptr = (MESSAGE_HEADER_STRUCT_PTR)
    input_msg_ptr;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE4(KLOG_msgq_send_urgent, msg_ptr, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->TARGET_QID, ((MESSAGE_HEADER_STRUCT_PTR)msg_ptr)->SOURCE_QID);

    msg_ptr->CONTROL |= MSG_HDR_URGENT;

    result = _msgq_send_internal(msg_ptr, FALSE, msg_ptr->TARGET_QID);

    _KLOGX2(KLOG_msgq_send_urgent, result);
    return(result);

} /* Endbody */

/*!
 * \brief Opens the system message queue.
 * 
 * Once a system message queue is opened, any task can use the queue ID to receive 
 * messages with _msgq_poll().
 * \li Tasks cannot receive messages from system message queues with _msgq_receive().
 * \li The notification function can get messages from the message queue with 
 * _msgq_poll().
 * \li A task can change the notification function and its data with 
 * _msgq_set_notification_function().
 * 
 * \param[in] queue                 One of the following:
 * \li System message queue to be opened (min. 8, max. as defined in the MQX 
 * initialization structure).
 * \li MSGQ_FREE_QUEUE (MQX chooses an unopened system queue number.)
 * \param[in] max_queue_size        One of the following:
 * \li Maximum queue size.
 * \li 0 (Unlimited size.)
 * \param[in] notification_function One of the following:              
 * \li Pointer to the function that MQX calls when it puts a message in the queue.
 * \li NULL (MQX does not call a function when it puts a message in the queue.)
 * \param[in] notification_data     Data that MQX passes when it calls 
 * notification_function.
 * 
 * \return Queue ID (Success.)
 * \return 0 (Failure.)
 * 
 * \warning Creates the message component if it was not previously created.
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li See _msgq_open() for error codes
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGQ_MESSAGE_NOT_AVAILABLE (There are no messages in the message queue.)
 * \li MSGQ_NOT_QUEUE_OWNER (Task is not the owner of the private message queue.)
 * \li MSGQ_QUEUE_IS_NOT_OPEN Queue is not open.  
 * 
 * \see _msgq_close
 * \see _msgq_open
 * \see _msgq_poll
 * \see _msgq_set_notification_function
 * \see _task_set_error  
 */ 
_queue_id _msgq_open_system
(
    _queue_number          queue,
    uint16_t                max_queue_size,
    MSGQ_NOTIFICATION_FPTR notification_function,
    void                  *notification_data
)
{ /* Body */
    _queue_id result;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE5(KLOG_msgq_open_system, queue, max_queue_size, notification_function, notification_data);

    result = _msgq_open_internal(queue, max_queue_size, SYSTEM_MSG_QUEUE,
                    notification_function, notification_data);

    _KLOGX2(KLOG_msgq_open_system, result);

    return(result);

} /* Endbody */

/*!
 * \brief Tests all messages in all open message queues for validity and consistency.
 * 
 * The function checks the consistency and validity of all messages in all 
 * private and system message queues that are open.
 * 
 * \param[out] queue_error_ptr Pointer to the message queue that has a message 
 * with an error (initialized only if an error is found).
 * \param[out] msg_error_ptr   Pointer to the message that has an error 
 * (initialized only if an error is found).
 * 
 * \return MQX_OK (Success: no errors are found.)
 * \return MSGQ_INVALID_MESSAGE (Success: an error is found.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Failure: Message component is not created.)
 * 
 * \warning Disables and enables interrupts.
 * 
 * \see _msgq_open
 * \see _msgq_open_system 
 */ 
_mqx_uint _msgq_test
(
    void    **queue_error_ptr,
    void    **msg_error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR      kernel_data;
    MSG_COMPONENT_STRUCT_PTR    msg_component_ptr;
    MSGQ_STRUCT_PTR             msgq_ptr;
    INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    _mqx_uint                   i,j;

    _GET_KERNEL_DATA(kernel_data);
    _KLOGE3(KLOG_msgq_test, queue_error_ptr, msg_error_ptr);
    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _KLOGX2(KLOG_msgq_test, MQX_COMPONENT_DOES_NOT_EXIST);
        return(MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif

    /* test the message queues */
    msgq_ptr = &msg_component_ptr->MSGQS_PTR[MSGQ_FIRST_USER_QUEUE];
    for (i = MSGQ_FIRST_USER_QUEUE; i <= msg_component_ptr->MAX_MSGQS; i++)
    {
        _int_disable();
        if (msgq_ptr->QUEUE == i)
        {
            /* Queue is open */
            imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
            for (j = 0; j < msgq_ptr->NO_OF_ENTRIES; ++j)
            {
                if ((imsg_ptr->VALID != MSG_VALID) && (imsg_ptr->QUEUED))
                {
                    _int_enable();
                    *queue_error_ptr = msgq_ptr;
                    *msg_error_ptr = imsg_ptr;
                    _KLOGX4(KLOG_msgq_test, MSGQ_INVALID_MESSAGE, msgq_ptr,
                                    imsg_ptr);
                    return(MSGQ_INVALID_MESSAGE);
                } /* Endif */
                imsg_ptr = imsg_ptr->NEXT;
            } /* Endfor */
        } /* Endif */
        _int_enable();
        ++msgq_ptr;
    } /* Endfor */

    _KLOGX2(KLOG_msgq_test, MQX_OK);
    return(MQX_OK);

} /* Endbody */

#endif /* MQX_USE_MESSAGES */

/* EOF */
