
/*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 Event component.
*
*
*END************************************************************************/

#include <string.h>
#include "mqx_inc.h"
#if MQX_USE_EVENTS
#include "name.h"
#include "name_prv.h"
#include "event.h"
#include "event_prv.h"
#include "mqx_str.h"
#include "message.h"
#include "msg_prv.h"
#include "ipc.h"
#include "ipc_prv.h"

/*!
 * \brief Wait for all the specified event bits to be set in the event group for
 * the specified number of milliseconds.
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] timeout         The maximum number of milliseconds to wait for the 
 * events to be set. After the timeout elapses without event signalled, function returns. If the value is 0, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 * 
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                    
 */ 
_mqx_uint _event_wait_all
(
    void     *users_event_ptr,
    _mqx_uint bit_mask,
    uint32_t   timeout
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_all, users_event_ptr, bit_mask, timeout);

    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);

        result = _event_wait_internal(users_event_ptr, bit_mask, &ticks, FALSE, TRUE);
    }
    else
    {
        result = _event_wait_internal(users_event_ptr, bit_mask, NULL, FALSE, TRUE);
    } /* Endif */

    _KLOGX2(KLOG_event_wait_all, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for all the specified event bits to be set in the event group for
 * the specified number of ticks (in tick time).
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] tick_ptr        The maximum number of ticks to wait for the events
 * to be set. If the value is NULL, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 * 
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_wait_all
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                    
 */
_mqx_uint _event_wait_all_for
(
    void               *users_event_ptr,
    _mqx_uint           bit_mask,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_all_for, users_event_ptr, bit_mask, tick_ptr);

    result = _event_wait_internal(users_event_ptr, bit_mask, tick_ptr, FALSE, TRUE);

    _KLOGX2(KLOG_event_wait_all_for, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for all the specified event bits to be set in the event group for
 * the specified number of ticks.
 * 
 * \param[in] users_event_ptr  An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask         Each set bit represents an event bit to wait for.
 * \param[in] timeout_in_ticks The maximum number of ticks to wait for the events
 * to be set. If the value is 0, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 * 
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_until
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                    
 */
_mqx_uint _event_wait_all_ticks
(
    void     *users_event_ptr,
    _mqx_uint bit_mask,
    _mqx_uint timeout_in_ticks
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_all_ticks, users_event_ptr, bit_mask,
                    timeout_in_ticks);

    if (!timeout_in_ticks)
    {
        result = _event_wait_internal(users_event_ptr, bit_mask, NULL, FALSE, TRUE);
    }
    else
    {
        ticks = _mqx_zero_tick_struct;

        PSP_ADD_TICKS_TO_TICK_STRUCT(&ticks, timeout_in_ticks, &ticks);
        result = _event_wait_internal(users_event_ptr, bit_mask, &ticks, FALSE, TRUE);
    } /* Endif */

    _KLOGX2(KLOG_event_wait_all_ticks, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for all the specified event bits to be set in the event group 
 * until the specified time (in tick time).
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] tick_ptr        The time to wait until, in ticks, for the events 
 * to be set. If the value is NULL, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 * 
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                    
 */
_mqx_uint _event_wait_all_until
(
    void   *users_event_ptr,
    _mqx_uint bit_mask,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_all_until, users_event_ptr, bit_mask, tick_ptr);

    result = _event_wait_internal(users_event_ptr, bit_mask, tick_ptr, TRUE, TRUE);

    _KLOGX2(KLOG_event_wait_all_until, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for any of the specified event bits to be set in the event group 
 * for the specified number of milliseconds.
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] timeout         The maximum number of milliseconds to wait for the 
 * events to be set. If the value is 0, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 *  
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR. 
 *  
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until 
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until        
 */  
_mqx_uint _event_wait_any
(
    void     *users_event_ptr,
    _mqx_uint bit_mask,
    uint32_t   timeout
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_any, users_event_ptr, bit_mask, timeout);

    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);
        
        result = _event_wait_internal(users_event_ptr, bit_mask, &ticks, FALSE, FALSE);
    }
    else
    {
        result = _event_wait_internal(users_event_ptr, bit_mask, NULL, FALSE, FALSE);
    } /* Endif */

    _KLOGX2(KLOG_event_wait_any, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for any of the specified event bits to be set in the event group 
 * for the specified number of milliseconds.
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] tick_ptr        The maximum number of ticks to wait for the events
 * to be set. If the value is 0, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 *  
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR. 
 *  
 * \see _event_wait_any
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until 
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until        
 */
_mqx_uint _event_wait_any_for
(
    void   *users_event_ptr,
    _mqx_uint bit_mask,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_any_for, users_event_ptr, bit_mask, tick_ptr);

    result = _event_wait_internal(users_event_ptr, bit_mask, tick_ptr, FALSE, FALSE);

    _KLOGX2(KLOG_event_wait_any_for, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for any of the specified event bits to be set in the event group 
 * for the number of ticks.
 * 
 * \param[in] users_event_ptr  An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask         Each set bit represents an event bit to wait for.
 * \param[in] timeout_in_ticks The maximum number of ticks to wait for the events 
 * to be set. If the value is 0, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 *  
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR. 
 *  
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_until 
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until        
 */
_mqx_uint _event_wait_any_ticks
(
    void   *users_event_ptr,
    _mqx_uint bit_mask,
    _mqx_uint timeout_in_ticks
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_any_ticks, users_event_ptr, bit_mask, timeout_in_ticks);


    if (timeout_in_ticks)
    {
        ticks = _mqx_zero_tick_struct;

        PSP_ADD_TICKS_TO_TICK_STRUCT(&ticks, timeout_in_ticks, &ticks);
        result = _event_wait_internal(users_event_ptr, bit_mask, &ticks, FALSE, FALSE);
    }
    else
    {
        result = _event_wait_internal(users_event_ptr, bit_mask, NULL, FALSE, FALSE);
    } /* Endif */

    _KLOGX2(KLOG_event_wait_any_ticks, result);
    return (result);

} /* Endbody */

/*!
 * \brief Wait for any of the specified event bits to be set in the event group 
 * until the specified time (in tick time).
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to wait for.
 * \param[in] tick_ptr        The time in ticks to wait for the events to be set. 
 * If the value is NULL, then the timeout will be infinite.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)
 *  
 * \warning Blocks until the event combination is set or until the timeout expires.
 * \warning Cannot be called from an ISR. 
 *  
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks 
 * \see _event_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until        
 */
_mqx_uint _event_wait_any_until
(
    void   *users_event_ptr,
    _mqx_uint bit_mask,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE4(KLOG_event_wait_any_until, users_event_ptr, bit_mask, tick_ptr);

    result = _event_wait_internal(users_event_ptr, bit_mask, tick_ptr, TRUE, FALSE);

    _KLOGX2(KLOG_event_wait_any_until, result);
    return (result);

} /* Endbody */

/*! 
 * \brief Clears the specified event bits in an event group.
 * 
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to clear.
 * 
 * \return MQX_OK
 * \return EVENT_INVALID_EVENT_HANDLE (_event_open() or _event_open_fast() did 
 * not get the event group handle or _event_create() did not create the event 
 * group.)
 * \return EVENT_INVALID_EVENT (Event group is not valid.)
 * 
 * \see _event_create
 * \see _event_create_auto_clear
 * \see _event_open
 * \see _event_open_fast
 * \see _event_set
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until 
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until          
 */  
_mqx_uint _event_clear
(
    void   *users_event_ptr,
    _mqx_uint bit_mask
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR           kernel_data);
    register EVENT_CONNECTION_STRUCT_PTR    event_connection_ptr;
    register EVENT_STRUCT_PTR               event_ptr;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE3(KLOG_event_clear, users_event_ptr, bit_mask);
    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;

#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_clear, EVENT_INVALID_EVENT_HANDLE);
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */
#endif

    _INT_DISABLE();
    event_ptr = event_connection_ptr->EVENT_PTR;

#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_event_clear, EVENT_INVALID_EVENT);
        return (EVENT_INVALID_EVENT);
    } /* Endif */
#endif

    event_ptr->EVENT &= ~bit_mask;
    _INT_ENABLE();

    _KLOGX2(KLOG_event_clear, MQX_OK);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Closes connection to the event group.
 * 
 * The function closes the connection to the event group and frees the event 
 * group handle.
 * \n A task that opened an event group on a remote processor can also close the 
 * event group.
 *   
 * \param[in] users_event_ptr An event handle returned from a call to _event_open() 
 * or _event_open_fast().
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Event group connection is not valid.)
 * \return Task error code from _mem_free() (MQX could not free the event group handle.)
 * 
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_destroy
 * \see _event_open
 * \see _event_open_fast         
 */  
_mqx_uint _event_close
(
    void   *users_event_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;

    _GET_KERNEL_DATA(kernel_data);
    _KLOGE2(KLOG_event_close, users_event_ptr);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_close, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;
#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_close, EVENT_INVALID_EVENT_HANDLE);
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */

#endif

    event_connection_ptr->VALID = 0;

    if (_mem_free(event_connection_ptr) != MQX_OK)
    {
        _KLOGX2(KLOG_event_close, kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
        return (kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
    }
    else
    {
        _KLOGX2(KLOG_event_close, MQX_OK);
        return (MQX_OK);
    } /* Endif */

} /* Endbody */

 /*!
  * \brief Creates the event component so that other tasks may create and use 
  * events.
  * 
  * If an application previously called the function and maximum_number is now 
  * greater that what was previously specified, MQX changes the maximum number 
  * of event groups to maximum_number.
  * \n If an application does not explicitly create the event component, MQX does 
  * so with the following default values the first time that a task calls a 
  * function in the _event_create family of functions.
  * \n Parameter default values:
  * \li Initial_number = 8(default)
  * \li Grow_number = 8(default)
  * \li Maximum_number = 0(unlimited)
  * 
  * \param[in] initial_number Initial number of event groups that the application 
  * can create.
  * \param[in] grow_number Number of event groups to add if the application 
  * creates all the event groups
  * \param[in] maximum_number If grow_number is non-zero, maximum number of event 
  * groups (0 means an unlimited number)
  * 
  * \return MQX_OK
  * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
  * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
  * 
  * \see _event_create
  * \see _event_create_auto_clear
  * \see _event_create_fast
  * \see _event_create_fast_auto_clear
  * \see _event_open
  * \see _event_open_fast                                         
  */  
_mqx_uint _event_create_component
(
    _mqx_uint initial_number,
    _mqx_uint grow_number,
    _mqx_uint maximum_number
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR              kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    _mqx_uint                           result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE4(KLOG_event_create_component, initial_number, grow_number, maximum_number);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_create_component, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif

    _lwsem_wait((LWSEM_STRUCT_PTR) (&kernel_data->COMPONENT_CREATE_LWSEM));

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
    if (event_component_ptr != NULL)
    {
        if (maximum_number > event_component_ptr->MAXIMUM_NUMBER)
        {
            event_component_ptr->MAXIMUM_NUMBER = maximum_number;
        } /* Endif */

        _lwsem_post((LWSEM_STRUCT_PTR) (&kernel_data->COMPONENT_CREATE_LWSEM));
        _KLOGX2(KLOG_event_create_component, MQX_OK);
        return (MQX_OK);
    } /* Endif */

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) _mem_alloc_system_zero(
                    (_mem_size) sizeof(EVENT_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (event_component_ptr == NULL)
    {
        _lwsem_post((LWSEM_STRUCT_PTR) (&kernel_data->COMPONENT_CREATE_LWSEM));
        _KLOGX2(KLOG_event_create_component, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(event_component_ptr, MEM_TYPE_EVENT_COMPONENT);

    result = _name_create_handle_internal(&event_component_ptr->NAME_TABLE_HANDLE, initial_number, grow_number,
                    maximum_number, initial_number);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        _lwsem_post((LWSEM_STRUCT_PTR) (&kernel_data->COMPONENT_CREATE_LWSEM));
        _mem_free(event_component_ptr);
        _KLOGX2(KLOG_event_create_component, result);
        return (result);
    } /* Endif */
#endif
    event_component_ptr->VALID = EVENT_VALID;
    event_component_ptr->GROW_NUMBER = grow_number;
    if (maximum_number == 0)
    {
        event_component_ptr->MAXIMUM_NUMBER = MAX_MQX_UINT;
    }
    else if (maximum_number < initial_number)
    {
        event_component_ptr->MAXIMUM_NUMBER = initial_number;
    }
    else
    {
        event_component_ptr->MAXIMUM_NUMBER = maximum_number;
    } /* Endif */

    kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS] = event_component_ptr;

#if MQX_COMPONENT_DESTRUCTION
    kernel_data->COMPONENT_CLEANUP[KERNEL_EVENTS] = _event_cleanup;
#endif

    _lwsem_post((LWSEM_STRUCT_PTR) (&kernel_data->COMPONENT_CREATE_LWSEM));

    _KLOGX2(KLOG_event_create_component, MQX_OK);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Creates the named event group with autoclearing event bits.
 * 
 * After a task creates a named event group, any task that wants to use it must 
 * open a connection to it with _event_open(). When a task no longer needs a 
 * named event group, it can destroy the event group with _event_destroy().
 * \n When a task creates an event group with autoclearing event bits, MQX clears 
 * the event bits as soon as they are set. Tasks that are waiting for the event 
 * bits are made ready, but need not to clear the bits.
 * 
 * \param[in] name_ptr Pointer to the name of the event group.
 * 
 * \return MQX_OK 
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component was not created.)
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.)
 * 
 * \warning Creates the event component with default values if it was not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create
 * \see _event_close
 * \see _event_create_component
 * \see _event_destroy
 * \see _event_open           
 */  
_mqx_uint _event_create_auto_clear
(
    char  *name_ptr
)
{ /* Body */
    EVENT_STRUCT_PTR event_ptr;
    _mqx_uint        result;

    result = _event_create_internal(name_ptr, &event_ptr);

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        return (result);
    } /* Endif */
#endif

    event_ptr->AUTO_CLEAR = TRUE;

    return (result);

} /* Endbody */

/*!
 * \private
 * 
 * \brief Used internally to create an instance of an event.
 * 
 * \param[in]  name_ptr      Pointer to the name of the event group.
 * \param[out] event_ptr_ptr Where the event pointer is.
 * 
 * \return MQX_OK 
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component was not created.)
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.)
 * 
 * \warning Creates the event component with default values if it was not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create
 * \see _event_create_auto_clear          
 */
_mqx_uint _event_create_internal
(
    char              *name_ptr,
    EVENT_STRUCT_PTR  *event_ptr_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR              kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    register EVENT_STRUCT_PTR           event_ptr;
    _mqx_uint                           result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_event_create, name_ptr);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_create, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
    if (event_component_ptr == NULL)
    {
        result = _event_create_component(EVENT_DEFAULT_INITIAL_NUMBER, EVENT_DEFAULT_GROW_NUMBER,
                        EVENT_DEFAULT_MAXIMUM_NUMBER);
        event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (event_component_ptr == NULL)
        {
            _KLOGX2(KLOG_event_create, result);
            return (result);
        } /* Endif */
#endif
    } /* Endif */

#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_create, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    event_ptr = (EVENT_STRUCT_PTR) _mem_alloc_system_zero((_mem_size) sizeof(EVENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (event_ptr == NULL)
    {
        _KLOGX2(KLOG_event_create, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(event_ptr, MEM_TYPE_EVENT);

    _QUEUE_INIT(&event_ptr->WAITING_TASKS, EVENT_MAX_WAITING_TASKS);

    strncpy(event_ptr->NAME, name_ptr, (_mqx_uint) NAME_MAX_NAME_SIZE - 1);
    event_ptr->NAME[NAME_MAX_NAME_SIZE - 1] = '\0';
    result = _name_add_internal(event_component_ptr->NAME_TABLE_HANDLE, event_ptr->NAME, (_mqx_uint) event_ptr);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        _mem_free(event_ptr);
        if (result == NAME_EXISTS)
        {
            _KLOGX2(KLOG_event_create, EVENT_EXISTS);
            return (EVENT_EXISTS);
        }
        else if (result == NAME_TABLE_FULL)
        {
            _KLOGX2(KLOG_event_create, EVENT_TABLE_FULL);
            return (EVENT_TABLE_FULL);
        } /* Endif */
        _KLOGX2(KLOG_event_create, result);
        return (result);
    } /* Endif */
#endif
    event_ptr->VALID = EVENT_VALID;

    *event_ptr_ptr = event_ptr;

    _KLOGX2(KLOG_event_create, result);
    return (result);

} /* Endbody */

/*!
 * \brief Creates the named event group.
 * 
 * After a task creates a named event group, any task that wants to use it must 
 * open a connection to it with _event_open(). When a task no longer needs a 
 * named event group, it can destroy the event group with _event_destroy().
 * 
 * \param[in] name_ptr Pointer to the name of the event group.
 * 
 * \return MQX_OK 
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component was not created.)
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.)
 * 
 * \warning Creates the event component with default values if it was not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create_auto_clear
 * \see _event_close
 * \see _event_create_component
 * \see _event_destroy
 * \see _event_open      
 */ 
_mqx_uint _event_create
(
    char  *name_ptr
)
{ /* Body */
    EVENT_STRUCT_PTR event_ptr;
    _mqx_uint        result;

    result = _event_create_internal(name_ptr, &event_ptr);

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        return (result);
    } /* Endif */
#endif

    event_ptr->AUTO_CLEAR = FALSE;

    return (result);

} /* Endbody */

/*!
 * \brief Used by a task to destroy an instance of an event.
 * 
 * The event group must have been created with _event_create() or 
 * _event_create_auto_clear().
 * \n If tasks are blocked waiting for an event bit in the event group, MQX does 
 * the following:
 * \n - Moves them to their ready queues.
 * \n - Sets their task error code to EVENT_DELETED.
 * \n - Returns EVENT_DELETED for _event_wait_all() and _event_wait_any().
 * 
 * \param[in] name_ptr Pointer to the name of the event group.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component was not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return EVENT_NOT_FOUND (Name is not in the names database.)
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)   
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.) 
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.)
 * 
 * \warning Cannot be called from an ISR
 * 
 * \see _event_create
 * \see _event_create_auto_clear
 * \see _event_create_component
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                  
 */ 
_mqx_uint _event_destroy
(
    char  *name_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR              kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    EVENT_STRUCT_PTR                    event_ptr;
    EVENT_CONNECTION_STRUCT_PTR         event_connection_ptr;
    QUEUE_STRUCT_PTR                    queue_ptr;
    TD_STRUCT_PTR                       td_ptr;
    _mqx_uint                           result;
    _mqx_uint                           i;
    _mqx_max_type                       tmp;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_event_destroy, name_ptr);

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_destroy, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_destroy, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_destroy, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal(event_component_ptr->NAME_TABLE_HANDLE, name_ptr, &tmp);

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX2(KLOG_event_destroy, EVENT_NOT_FOUND);
            return (EVENT_NOT_FOUND);
        } /* Endif */
        _KLOGX2(KLOG_event_destroy, result);
        return (result);
    } /* Endif */
#endif

    event_ptr = (EVENT_STRUCT_PTR) tmp;
    queue_ptr = &event_ptr->WAITING_TASKS;

    _int_disable();
    if (event_ptr->VALID != EVENT_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_event_destroy, EVENT_INVALID_EVENT);
        return (EVENT_INVALID_EVENT);
    } /* Endif */

    /* Effectively stop all access to the event */
    event_ptr->VALID = 0;

    /* Ready all waiting tasks */
    i = _QUEUE_GET_SIZE(queue_ptr) + 1;
    while (--i)
    {
        event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) ((void *) queue_ptr->NEXT);
        td_ptr = event_connection_ptr->TD_PTR;
        if ((td_ptr->STATE & STATE_MASK) == EVENT_BLOCKED)
        {
            _TIME_DEQUEUE(td_ptr, kernel_data);
            _task_set_error_td_internal(td_ptr, EVENT_DELETED);
            _TASK_READY(td_ptr,kernel_data);
        } /* Endif */
    } /* Endwhile */

    _int_enable();

    result = _name_delete_internal(event_component_ptr->NAME_TABLE_HANDLE, name_ptr);
#if MQX_CHECK_ERRORS
    if (result == NAME_NOT_FOUND)
    {
        result = EVENT_NOT_FOUND;
    } /* Endif */
#endif

    _mem_free(event_ptr);

    /* May need to let higher priority task run */
    _CHECK_RUN_SCHEDULER();

    _KLOGX2(KLOG_event_destroy, result);
    return (result);

} /* Endbody */

/*!
 * \brief Creates an instance of a numbered (NOT named) event.
 * 
 * After a task creates a named event group, any task that wants to use it must 
 * open a connection to it with _event_open_fast(). When a task no longer needs a 
 * named event group, it can destroy the event group with _event_destroy_fast().
 * 
 * \param[in] event_index The event group number.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Name component is not created.)
 *  
 * \warning Creates the event component with default values if they were not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create_fast_auto_clear
 * \see _event_close
 * \see _event_create
 * \see _event_create_auto_clear
 * \see _event_create_component
 * \see _event_destroy_fast
 * \see _event_open_fast           
 */  
_mqx_uint _event_create_fast
(
    _mqx_uint event_index
)
{ /* Body */
    EVENT_STRUCT_PTR event_ptr;
    _mqx_uint        result;

    result = _event_create_fast_internal(event_index, &event_ptr);

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        return (result);
    } /* Endif */
#endif

    event_ptr->AUTO_CLEAR = FALSE;

    return (result);

} /* Endbody */

/*!
 * \brief Creates an instance of a numbered (NOT named) event with autoclearing
 * event bits.
 * 
 * After a task creates a named event group, any task that wants to use it must 
 * open a connection to it with _event_open_fast(). When a task no longer needs 
 * a named event group, it can destroy the event group with _event_destroy_fast().
 * \n If a task creates an event group with autoclearing event bits, MQX clears 
 * the event bits as soon as they are set. Task that are waiting for the event 
 * bits are made ready, but need not clear the bits.
 * 
 * \param[in] event_index The event group number.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Name component is not created.)
 * 
 * \warning Creates the event component with default values if they were not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create_fast
 * \see _event_close
 * \see _event_create
 * \see _event_create_auto_clear
 * \see _event_create_component
 * \see _event_destroy_fast
 * \see _event_open_fast           
 */ 
_mqx_uint _event_create_fast_auto_clear
(
    _mqx_uint event_index
)
{ /* Body */
    EVENT_STRUCT_PTR event_ptr;
    _mqx_uint        result;

    result = _event_create_fast_internal(event_index, &event_ptr);

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        return (result);
    } /* Endif */
#endif

    event_ptr->AUTO_CLEAR = TRUE;

    return (result);

} /* Endbody */

/*!
 * \private
 * 
 * \brief Used internally to create an instance of a numbered (NOT named) event.
 * 
 * \param[in]  event_index   The event number to initialize.
 * \param[out] event_ptr_ptr Pointer to event.
 *     
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event group.)
 * \return EVENT_EXISTS (Event group was already created.)
 * \return EVENT_TABLE_FULL (Name table is full and cannot be expanded.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Name component is not created.)
 * 
 * \see _event_create_fast
 * \see _event_create_fast_auto_clear          
 */ 
_mqx_uint _event_create_fast_internal
(
    _mqx_uint event_index,
    EVENT_STRUCT_PTR  *event_ptr_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR              kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    register EVENT_STRUCT_PTR           event_ptr;
    _mqx_uint                           result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_event_create_fast, event_index);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_create_fast, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
    if (event_component_ptr == NULL)
    {
        result = _event_create_component(EVENT_DEFAULT_INITIAL_NUMBER, EVENT_DEFAULT_GROW_NUMBER,
                        EVENT_DEFAULT_MAXIMUM_NUMBER);
        event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (event_component_ptr == NULL)
        {
            _KLOGX2(KLOG_event_create_fast, result);
            return (result);
        } /* Endif */
#endif
    } /* Endif */

#if MQX_CHECK_ERRORS
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_create_fast, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    event_ptr = (EVENT_STRUCT_PTR) _mem_alloc_system_zero((_mem_size) sizeof(EVENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (event_ptr == NULL)
    {
        _KLOGX2(KLOG_event_create_fast, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(event_ptr, MEM_TYPE_EVENT);

    _QUEUE_INIT(&event_ptr->WAITING_TASKS, EVENT_MAX_WAITING_TASKS);

    _str_mqx_uint_to_hex_string(event_index, event_ptr->NAME);

    result = _name_add_internal_by_index(event_component_ptr->NAME_TABLE_HANDLE, event_ptr->NAME,
                    (_mqx_uint) event_ptr, event_index);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        _mem_free(event_ptr);
        if (result == NAME_EXISTS)
        {
            _KLOGX2(KLOG_event_create_fast, EVENT_EXISTS);
            return (EVENT_EXISTS);
        }
        else if (result == NAME_TABLE_FULL)
        {
            _KLOGX2(KLOG_event_create_fast, EVENT_TABLE_FULL);
            return (EVENT_TABLE_FULL);
        } /* Endif */
        _KLOGX2(KLOG_event_create_fast, result);
        return (result);
    } /* Endif */
#endif

    event_ptr->VALID = EVENT_VALID;

    *event_ptr_ptr = event_ptr;

    _KLOGX2(KLOG_event_create_fast, result);
    return (result);

} /* Endbody */

/*!
 * \brief Used by a task to destroy instance of an event using an index.
 * 
 * The event group must have been created with _event_create_fast() or 
 * _event_create_fast_auto_clear().
 * \n If tasks are blocked waiting for an event bit in the event group, MQX does 
 * the following:
 * \n - Moves them to their ready queues.
 * \n - Sets their task error code to EVENT_DELETED.
 * \n - Returns EVENT_DELETED for _event_wait_all() and _event_wait_any().
 * 
 * \param[in] event_index Index of an event to destroy.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component was not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return EVENT_NOT_FOUND (Name is not in the names database.)
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)   
 * 
 * \warning Cannot be called from an ISR.
 * 
 * \see _event_create_component
 * \see _event_create_fast
 * \see _event_create_fast_auto_clear          
 */ 
_mqx_uint _event_destroy_fast
(
    _mqx_uint event_index
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR              kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    EVENT_STRUCT_PTR                    event_ptr;
    EVENT_CONNECTION_STRUCT_PTR         event_connection_ptr;
    QUEUE_STRUCT_PTR                    queue_ptr;
    TD_STRUCT_PTR                       td_ptr;
    _mqx_uint                           result;
    _mqx_uint                           i;
    _mqx_max_type                       tmp;
#if MQX_CHECK_ERRORS
    char name[9];
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_event_destroy_fast, event_index);

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_event_destroy_fast, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_destroy_fast, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_destroy_fast, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal_by_index(event_component_ptr->NAME_TABLE_HANDLE, event_index, &tmp);
    event_ptr = (EVENT_STRUCT_PTR) tmp;
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX2(KLOG_event_destroy_fast, EVENT_NOT_FOUND);
            return (EVENT_NOT_FOUND);
        } /* Endif */
        _KLOGX2(KLOG_event_destroy_fast, result);
        return (result);
    } /* Endif */

    /* event_ptr = (EVENT_STRUCT_PTR)tmp; */
    _str_mqx_uint_to_hex_string(event_index, name);
    if (strncmp(name, event_ptr->NAME, 8))
    {
        /* Name does not match */
        _KLOGX2(KLOG_event_destroy_fast, EVENT_NOT_FOUND);
        return (EVENT_NOT_FOUND);
    } /* Endif */
#endif

    queue_ptr = &event_ptr->WAITING_TASKS;

    _int_disable();
    if (event_ptr->VALID != EVENT_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_event_destroy_fast, EVENT_INVALID_EVENT);
        return (EVENT_INVALID_EVENT);
    } /* Endif */

    /* Effectively stop all access to the event */
    event_ptr->VALID = 0;

    /* Ready all waiting tasks */
    i = _QUEUE_GET_SIZE(queue_ptr) + 1;
    while (--i)
    {
        event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) ((void *) queue_ptr->NEXT);
        td_ptr = event_connection_ptr->TD_PTR;
        if ((td_ptr->STATE & STATE_MASK) == EVENT_BLOCKED)
        {
            _TIME_DEQUEUE(td_ptr, kernel_data);
            _task_set_error_td_internal(td_ptr, EVENT_DELETED);
            _TASK_READY(td_ptr,kernel_data);
        } /* Endif */
    } /* Endwhile */

    _int_enable();

    result = _name_delete_internal_by_index(event_component_ptr->NAME_TABLE_HANDLE, event_index);
#if MQX_CHECK_ERRORS
    if (result == NAME_NOT_FOUND)
    {
        result = EVENT_NOT_FOUND;
    } /* Endif */
#endif

    _mem_free(event_ptr);

    /* May need to let higher priority task run */
    _CHECK_RUN_SCHEDULER();

    _KLOGX2(KLOG_event_destroy_fast, result);
    return (result);

} /* Endbody */

/*!
 * \brief Opens a connection to the indexed event group.
 * 
 * The indexed event group must have been created with _event_create_fast() or 
 * _event_create_fast_auto_clear(). Each task that needs access to the indexed 
 * event group must first open a connection to it.
 * 
 * \param[in]  event_index        Index of the event group to gain access to.
 * \param[out] returned_event_ptr Where to write the event group handle (NULL is 
 * written if an error occurred).
 * 
 * \return MQX_OK
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event 
 * connection data.)
 * \return EVENT_INVALID_EVENT (Event group data is no longer valid.)
 * \return EVENT_NOT_FOUND (Named event group is not in the name table.)
 * 
 * \see _event_close
 * \see _event_create_fast
 * \see _event_create_fast_auto_clear
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until                    
 */ 
_mqx_uint _event_open_fast
(
    _mqx_uint event_index,
    void    **returned_event_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR  event_component_ptr;
    EVENT_STRUCT_PTR                     event_ptr;
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    _mqx_uint                            result;
    _mqx_max_type                        tmp;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_event_open_fast, event_index, returned_event_ptr);

    *returned_event_ptr = NULL;

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
#if MQX_CHECK_ERRORS
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_open_fast, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_open_fast, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal_by_index(event_component_ptr->NAME_TABLE_HANDLE, event_index, &tmp);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX2(KLOG_event_open_fast, EVENT_NOT_FOUND);
            return (EVENT_NOT_FOUND);
        } /* Endif */
        _KLOGX2(KLOG_event_open_fast, result);
        return (result);
    } /* Endif */
#endif

    event_ptr = (EVENT_STRUCT_PTR) tmp;

#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        /* Event not valid */
        _KLOGX2(KLOG_event_open_fast, EVENT_INVALID_EVENT);
        return (EVENT_INVALID_EVENT);
    } /* Endif */
#endif

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) _mem_alloc_zero((_mem_size) sizeof(EVENT_CONNECTION_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (event_connection_ptr == NULL)
    {
        _KLOGX2(KLOG_event_open_fast, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(event_connection_ptr, MEM_TYPE_EVENT_CONNECTION);

    event_connection_ptr->EVENT_PTR = event_ptr;
    event_connection_ptr->VALID = EVENT_VALID;
    event_connection_ptr->TD_PTR = kernel_data->ACTIVE_PTR;

    *returned_event_ptr = (void *) event_connection_ptr;

    _KLOGX3(KLOG_event_open_fast, MQX_OK, event_connection_ptr);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Opens a connection to the named event group.
 * 
 * The named event group must have been created with _event_create() or 
 * _event_create_auto_clear(). Each task that needs access to the named event 
 * group must first open a connection to it.
 * \n To open an event group on a remote processor, prepend the event-group name 
 * with the remote processor number as follows.
 * <table>
 *   <tr>
 *     <td><b>This string:</b></td>
 *     <td><b>Opens an event group with this name:</b></td>
 *     <td><b>On this processor:</b></td>   
 *   </tr>
 *   <tr>
 *     <td>"2:Fred"</td>
 *     <td>"Fred"</td>
 *     <td>2</td>   
 *   </tr>
 *   <tr>
 *     <td>"0:Sue"</td>
 *     <td>"Sue"</td>
 *     <td>Local processor</td>   
 *   </tr>   
 * </table> 
 * \n The other allowed event operations on remote processors are:
 * \n - _event_set()
 * \n - _event_close()
 * \n The task closes the connection with _event_close(). 
 * 
 * \param[in]  name_ptr           String name of the event.
 * \param[out] returned_event_ptr Where to write the event group handle (NULL 
 * is written if an error occurred).
 * 
 * \return MQX_OK
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX could not allocate memory for the event 
 * connection data.)  
 * \return EVENT_INVALID_EVENT (Event group data is no longer valid.)
 * \return EVENT_NOT_FOUND (Named event group is not in the name table.)
 * \return NAME_TOO_SHORT (Name is 0 length string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.) 
 * 
 * \see _event_close
 * \see _event_create
 * \see _event_create_auto_clear
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all 
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until          
 */ 
_mqx_uint _event_open
(
    char     *name_ptr,
    void    **returned_event_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    register EVENT_COMPONENT_STRUCT_PTR  event_component_ptr;
    EVENT_STRUCT_PTR                     event_ptr;
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    _mqx_uint                            result;
    char                                *parse_ptr;
    uint32_t                              processor;
    _mqx_max_type                        tmp;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_event_open, name_ptr, returned_event_ptr);

    *returned_event_ptr = NULL;

    event_component_ptr = kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
#if MQX_CHECK_ERRORS
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_open, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_open, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    /* If lead by a number, this is a processor number */
    processor = 0;
    parse_ptr = name_ptr;
    while (*parse_ptr && (*parse_ptr >= '0') && (*parse_ptr <= '9'))
    {
        processor = (processor * 10) + *parse_ptr - (char) '0';
        parse_ptr++;
    } /* Endwhile */
    if (processor)
    {
        /* Processor number must be followed by ':' */
        if (*parse_ptr == ':')
        {
            parse_ptr++;
        }
        else
        {
            processor = 0;
        } /* Endif */
    } /* Endif */

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) _mem_alloc_zero((_mem_size) sizeof(EVENT_CONNECTION_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (event_connection_ptr == NULL)
    {
        _KLOGX2(KLOG_event_open, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(event_connection_ptr, MEM_TYPE_EVENT_CONNECTION);

    if (processor != 0)
    {

#if MQX_IS_MULTI_PROCESSOR
        if (kernel_data->IPC)
        {
            /* This open is for a remote processor */
            result = (*kernel_data->IPC)(TRUE, processor, KERNEL_EVENTS,
                            IPC_EVENT_OPEN | IPC_STRING_PARAMETER, 1, parse_ptr);
            if (result != MQX_OK)
            {
                _mem_free(event_connection_ptr);
                _KLOGX2(KLOG_event_open, result);
                return(result);
            } /* Endif */
            event_connection_ptr->EVENT_PTR = (void *)
            kernel_data->ACTIVE_PTR->INFO;
            event_connection_ptr->REMOTE_CPU = processor;
        }
        else
        {
#endif
        _mem_free(event_connection_ptr);
        _KLOGX2(KLOG_event_open, EVENT_NOT_FOUND);
        return (EVENT_NOT_FOUND);
#if MQX_IS_MULTI_PROCESSOR
    }/* Endif */
#endif

    }
    else
    {

        result = _name_find_internal(event_component_ptr->NAME_TABLE_HANDLE, name_ptr, &tmp);

#if MQX_CHECK_ERRORS
        if (result != MQX_OK)
        {
            _mem_free(event_connection_ptr);
            if (result == NAME_NOT_FOUND)
            {
                _KLOGX2(KLOG_event_open, EVENT_NOT_FOUND);
                return (EVENT_NOT_FOUND);
            } /* Endif */
            _KLOGX2(KLOG_event_open, result);
            return (result);
        } /* Endif */
#endif

        event_ptr = (EVENT_STRUCT_PTR) tmp;

#if MQX_CHECK_VALIDITY
        if (event_ptr->VALID != EVENT_VALID)
        {
            /* Event not valid */
            _mem_free(event_connection_ptr);
            _KLOGX2(KLOG_event_open, EVENT_INVALID_EVENT);
            return (EVENT_INVALID_EVENT);
        } /* Endif */
#endif

        event_connection_ptr->EVENT_PTR = event_ptr;

    }/* Endif */

    event_connection_ptr->VALID = EVENT_VALID;
    event_connection_ptr->TD_PTR = kernel_data->ACTIVE_PTR;
    *returned_event_ptr = (void *) event_connection_ptr;

    _KLOGX3(KLOG_event_open, MQX_OK, event_connection_ptr);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Sets the specified event bits in the event group.
 * 
 * Before a task can set an event bit in an event group, the event group must be 
 * created and the task must open an connection to the event group.
 * \n A task can set or clear one event bit or any combination of event bits in 
 * the event group.
 * \n A task that opened an event group on a remote processor can set bits in 
 * the event group.
 * 
 * \param[in] users_event_ptr Event group handle returned by _event_open() or 
 * _event_open_fast().
 * \param[in] bit_mask        Each set bit represents an event bit to be set.
 * 
 * \return MQX_OK
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Event component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is no longer valid.)
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_INVALID_EVENT_HANDLE (Event group handle is not a valid event
 * connection.) 
 * \return EVENT_NOT_FOUND
 * \return Task error code for ?   
 * 
 * \warning Tasks waiting for the event bits might be dispatched.
 * 
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all 
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until             
 */ 
_mqx_uint _event_set
(
    void     *users_event_ptr,
    _mqx_uint bit_mask
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR      kernel_data;
    EVENT_STRUCT_PTR            event_ptr;
    EVENT_COMPONENT_STRUCT_PTR  event_component_ptr;
    EVENT_CONNECTION_STRUCT_PTR conn_ptr;
    EVENT_CONNECTION_STRUCT_PTR next_conn_ptr;
    EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    TD_STRUCT_PTR               new_td_ptr;
    _mqx_uint                   set_bits;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_event_set, users_event_ptr, bit_mask);

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;

#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_set, EVENT_INVALID_EVENT_HANDLE);
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */
#endif

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];

#if MQX_CHECK_ERRORS
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_set, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_set, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

#if MQX_IS_MULTI_PROCESSOR
    if (event_connection_ptr->REMOTE_CPU)
    {
        if (kernel_data->IPC)
        {
            /* This open is for a remote processor */
            (*kernel_data->IPC)(TRUE, event_connection_ptr->REMOTE_CPU,
                            KERNEL_EVENTS, IPC_EVENT_SET, 2, event_connection_ptr->EVENT_PTR,
                            bit_mask);
            _KLOGX2(KLOG_event_set, kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
            return(kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
        }
        else
        {
            _KLOGX2(KLOG_event_set, EVENT_NOT_FOUND);
            return(EVENT_NOT_FOUND);
        }/* Endif */
    }/* Endif */
#endif

    _INT_DISABLE();
    event_ptr = event_connection_ptr->EVENT_PTR;

#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        _INT_ENABLE();
        _KLOGX2(KLOG_event_set, EVENT_INVALID_EVENT);
        return (EVENT_INVALID_EVENT);
    } /* Endif */
#endif

    set_bits = event_ptr->EVENT | bit_mask;

    if (_QUEUE_GET_SIZE(&event_ptr->WAITING_TASKS))
    {
        /* Schedule waiting task(s) to run if bits ok */

        conn_ptr = (EVENT_CONNECTION_STRUCT_PTR) ((void *) event_ptr->WAITING_TASKS.NEXT);
        while (conn_ptr != (EVENT_CONNECTION_STRUCT_PTR) ((void *) &event_ptr->WAITING_TASKS))
        {
            next_conn_ptr = (EVENT_CONNECTION_STRUCT_PTR) conn_ptr->NEXT;
            if (((conn_ptr->FLAGS & EVENT_WANTS_ALL) && ((conn_ptr->MASK & set_bits) == conn_ptr->MASK))
                            || ((!(conn_ptr->FLAGS & EVENT_WANTS_ALL)) && (conn_ptr->MASK & set_bits)))
            {
                new_td_ptr = conn_ptr->TD_PTR;
                if ((new_td_ptr->STATE & STATE_MASK) == EVENT_BLOCKED)
                {
                    /* He may have timed out */
                    conn_ptr->FLAGS |= EVENT_OCCURRED;
                    _TIME_DEQUEUE(new_td_ptr, kernel_data);
                    _TASK_READY(new_td_ptr, kernel_data);
                    /* Only ready one task if event is an auto clear event */
                    if (event_ptr->AUTO_CLEAR)
                    {
                        set_bits &= ~conn_ptr->MASK;
                        break;
                    } /* Endif */
                } /* Endif */
            } /* Endif */
            conn_ptr = next_conn_ptr;
        } /* Endwhile */
    } /* Endif */

    event_ptr->EVENT = set_bits;

    _INT_ENABLE();

    /* May need to let higher priority task run */
    _CHECK_RUN_SCHEDULER();

    _KLOGX2(KLOG_event_set, MQX_OK);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Used during task destruction to free up any events resources owned by 
 * this task.
 * 
 * The function checks the resource list of the task and look for an event 
 * connection struct. It can detect one by looking for EVENT_VALID in the 
 * correct location.
 * 
 * \param[in] td_ptr Pointer to the task descriptor of a task to destroy.   
 */ 
void _event_cleanup
(
    TD_STRUCT_PTR td_ptr
)
{ /* Body */
    EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    EVENT_CONNECTION_STRUCT_PTR connection_ptr;
    EVENT_STRUCT_PTR            event_ptr;

    connection_ptr = _mem_get_next_block_internal(td_ptr, NULL);
    while (connection_ptr)
    {
        if ((connection_ptr->VALID == EVENT_VALID) && (connection_ptr->TD_PTR == td_ptr))
        {
            event_ptr = connection_ptr->EVENT_PTR;
            if (event_ptr->VALID == EVENT_VALID)
            {
                /* Check if the connection is on the queue */
                _int_disable();
                event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) ((void *) event_ptr->WAITING_TASKS.NEXT);
                while (event_connection_ptr != (void *) &event_ptr->WAITING_TASKS.NEXT)
                {
                    if (event_connection_ptr == connection_ptr)
                    {
                        /* Connection is queued, so dequeue it */
                        _QUEUE_REMOVE(&event_ptr->WAITING_TASKS, connection_ptr);
                        break;
                    }/* Endif */
                    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) event_connection_ptr->NEXT;
                } /* Endwhile */
                _int_enable();
            }/* Endif */
        } /* Endif */
        connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) _mem_get_next_block_internal(td_ptr, connection_ptr);
    } /* Endwhile */

} /* Endbody */

/*!
 * \brief Tests the event component for validity and consistency.
 * 
 * \param[out] event_error_ptr Handle for the event group that has an error if 
 * MQX found an error in the event component (NULL if no error is found).
 * 
 * \return MQX_OK
 * \return EVENT_INVALID_EVENT (Data for an event group is not valid.)
 * \return MQX_INVALID_COMPONENT_BASE (Event component data is not valid.)
 * \return Return code from _queue_test() (Waiting queue for an event group has 
 * an error.)
 * 
 * \see _event_close
 * \see _event_open
 * \see _event_set
 * \see _event_get_wait_count
 * \see _event_get_value
 * \see _event_wait_all 
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until            
 */ 
_mqx_uint _event_test
(
    void    **event_error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR     kernel_data;
    EVENT_COMPONENT_STRUCT_PTR event_component_ptr;
    EVENT_STRUCT_PTR           event_ptr;
    void                      *table_ptr;
    _mqx_uint                  result;
    _mqx_uint                  i;
    _mqx_max_type              data;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_event_test, event_error_ptr);

    *event_error_ptr = NULL;

    event_component_ptr = (EVENT_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_EVENTS];
    if (event_component_ptr == NULL)
    {
        _KLOGX2(KLOG_event_test, MQX_OK);
        return (MQX_OK);
    } /* Endif */

    if (event_component_ptr->VALID != EVENT_VALID)
    {
        _KLOGX2(KLOG_event_test, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */

    _int_disable();
    /* Test the event name table */
    result = _name_test_internal((NAME_COMPONENT_STRUCT_PTR) event_component_ptr->NAME_TABLE_HANDLE,
                    (void **) &table_ptr, (void **) event_error_ptr);
    _int_enable();
    if (result != MQX_OK)
    {
        _KLOGX3(KLOG_event_test, MQX_INVALID_COMPONENT_BASE, *event_error_ptr);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */

    i = 0;
    while (TRUE)
    {
        _int_disable();
        result = _name_find_internal_by_index(event_component_ptr->NAME_TABLE_HANDLE, i++, &data);
        if (result != MQX_OK)
        {
            result = MQX_OK;
            break;
        } /* Endif */

        event_ptr = (EVENT_STRUCT_PTR) data;
        if (event_ptr->VALID != EVENT_VALID)
        {
            result = EVENT_INVALID_EVENT;
            break;
        } /* Endif */
        result = _queue_test(&event_ptr->WAITING_TASKS, event_error_ptr);
        if (result != MQX_OK)
        {
            break;
        } /* Endif */
        _int_enable();

    } /* Endwhile */

    _int_enable();

    _KLOGX3(KLOG_event_test, result, *event_error_ptr);
    return (result);

} /* Endbody */

/*!
 * \brief Gets the current event bits that have been set.
 * 
 * \param[in] users_event_ptr Event group handle returned by _event_open() or 
 * _event_open_fast().
 * \param[out] event_value_ptr Where to write the value of the event bits (on error, 
 * 0 is written). 
 * 
 * \return MQX_OK
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_INVALID_EVENT_HANDLE (Event group handle is not valid.)
 * 
 * \see _event_clear
 * \see _event_set
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until       
 */ 
_mqx_uint _event_get_value
(
    void   *users_event_ptr,
    _mqx_uint_ptr event_value_ptr
)
{ /* Body */
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    register EVENT_STRUCT_PTR            event_ptr;

    *event_value_ptr = 0;
    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;
#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */
#endif

    event_ptr = event_connection_ptr->EVENT_PTR;
#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        return (EVENT_INVALID_EVENT);
    } /* Endif */
#endif

    *event_value_ptr = event_ptr->EVENT;

    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Gets the number of tasks that are waiting for event bits in the event 
 * group.
 * 
 * Tasks can be waiting for different combinations of event bits.
 * 
 * \param[in] users_event_ptr Event group handle returned by _event_open() or 
 * _event_open_fast().
 * 
 * \return Number of waiting tasks. (Success.)
 * \return MAX_MQX_UINT (Failure.)
 * \return MAX_UINT_32 (Failure.)
 * 
 * \warning On failure, calls _task_set_error() to set the task error code to 
 * EVENT_INVALID_EVENT_HANDLE.
 * 
 * \see _event_open
 * \see _event_open_fast
 * \see _event_wait_all_for
 * \see _event_wait_all_ticks
 * \see _event_wait_all_until
 * \see _event_wait_any
 * \see _event_wait_any_for
 * \see _event_wait_any_ticks
 * \see _event_wait_any_until 
 * \see _task_set_error        
 */ 
_mqx_uint _event_get_wait_count
(
    void   *users_event_ptr
)
{ /* Body */
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;
    register EVENT_STRUCT_PTR            event_ptr;

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;
#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        _task_set_error(EVENT_INVALID_EVENT_HANDLE);
        return ((_mqx_uint) MAX_UINT_32);
    } /* Endif */
#endif

    event_ptr = event_connection_ptr->EVENT_PTR;
#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        _task_set_error(EVENT_INVALID_EVENT_HANDLE);
        return (MAX_MQX_UINT);
    } /* Endif */
#endif

    return (_QUEUE_GET_SIZE(&(event_ptr->WAITING_TASKS)));

} /* Endbody */

/*!
 * \private
 * 
 * \brief Used internally by a task to wait for all or any specified events
 * according to bit mask
 * 
 * \param[in] users_event_ptr    Event group handle returned by _event_open() or 
 * _event_open_fast().
 * \param[in] bit_mask           Each set bit represents an event bit to wait for.
 * \param[in] tick_ptr           The maximum number of ticks to wait for the 
 * events to be set. If the value is NULL, then the timeout will be infinite.
 * \param[in] ticks_are_absolute TRUE (ticks represents absolute time), FALSE 
 * (ticks represents relative time).
 * \param[in] all                Specifies whether wait for all bits.
 *  
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return EVENT_INVALID_EVENT_HANDLE (Handle is not a valid event group handle.)
 * \return EVENT_CANNOT_WAIT_ON_REMOTE_EVENT 
 * \return EVENT_INVALID_EVENT (Event group is no longer valid.)
 * \return EVENT_DELETED (Event group was destroyed while the task waited.)
 * \return EVENT_WAIT_TIMEOUT (Timeout expired before the event bits were set.)   
 */ 
_mqx_uint _event_wait_internal
(
    void               *users_event_ptr,
    _mqx_uint           bit_mask,
    MQX_TICK_STRUCT_PTR tick_ptr,
    bool             ticks_are_absolute,
    bool             all
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    TD_STRUCT_PTR                        td_ptr;
    register EVENT_STRUCT_PTR            event_ptr;
    register EVENT_CONNECTION_STRUCT_PTR event_connection_ptr;

    _GET_KERNEL_DATA(kernel_data);

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

    event_connection_ptr = (EVENT_CONNECTION_STRUCT_PTR) users_event_ptr;

#if MQX_CHECK_VALIDITY
    if (event_connection_ptr->VALID != EVENT_VALID)
    {
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */
#endif

    if (event_connection_ptr->REMOTE_CPU)
    {
        _KLOGX2(KLOG_event_wait_all, EVENT_CANNOT_WAIT_ON_REMOTE_EVENT);
        return (EVENT_CANNOT_WAIT_ON_REMOTE_EVENT);
    }/* Endif */

    td_ptr = kernel_data->ACTIVE_PTR;

#if MQX_CHECK_ERRORS
    if (event_connection_ptr->TD_PTR != td_ptr)
    {
        return (EVENT_INVALID_EVENT_HANDLE);
    } /* Endif */
#endif

    _INT_DISABLE();
    event_ptr = event_connection_ptr->EVENT_PTR;

#if MQX_CHECK_VALIDITY
    if (event_ptr->VALID != EVENT_VALID)
    {
        _int_enable();
        return (EVENT_INVALID_EVENT);
    } /* Endif */
#endif

    if ((all && ((event_ptr->EVENT & bit_mask) != bit_mask)) || (!all && ((event_ptr->EVENT & bit_mask) == 0)))
    {
        /* Must wait for a event to become available */
        if (all)
        {
            event_connection_ptr->FLAGS = EVENT_WANTS_ALL;
        }
        else
        {
            event_connection_ptr->FLAGS = 0;
        } /* Endif */

        event_connection_ptr->MASK = bit_mask;

        /* Enqueue at end */
        _QUEUE_ENQUEUE(&event_ptr->WAITING_TASKS, event_connection_ptr);

        /* Now put the task to sleep */
        td_ptr->STATE = EVENT_BLOCKED;

        if (tick_ptr)
        {
            if (ticks_are_absolute)
            {
                _time_delay_until(tick_ptr);
            }
            else
            {
                _time_delay_for(tick_ptr);
            } /* Endif */
        }
        else
        {
            _task_block();
        } /* Endif */

#if MQX_COMPONENT_DESTRUCTION
        if (event_ptr->VALID == 0)
        { /* We've been deleted */
            _int_enable();
            return (EVENT_DELETED);
        } /* Endif */
#endif

        _QUEUE_REMOVE(&event_ptr->WAITING_TASKS, event_connection_ptr);

        if (tick_ptr && !(event_connection_ptr->FLAGS & EVENT_OCCURRED))
        {
            /* MUST have timed out */
            _INT_ENABLE();
            return (EVENT_WAIT_TIMEOUT);
        } /* Endif */
    } /* Endif */

    if (event_ptr->AUTO_CLEAR)
    {
        event_ptr->EVENT = event_ptr->EVENT & ~bit_mask;
    } /* Endif */

    /* GOT IT */
    _INT_ENABLE();

    return (MQX_OK);

} /* Endbody */

#endif /* MQX_USE_EVENTS */

/* EOF */
