0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-06-15 19:22:09 +00:00
Files
2022-01-04 12:22:53 +02:00

1367 lines
42 KiB
C

/*HEADER*********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: ipc.c$
* $Version : 3.8.1.0$
* $Date : Apr-13-2012$
*
* Comments:
*
* This file contains functions of the IPC
* (Inter Processor Communication) component.
*
*END************************************************************************/
#include <stdarg.h>
#include <string.h>
#include "mqx_inc.h"
#if MQX_USE_IPC
#include "message.h"
#include "msg_prv.h"
#include "fio.h"
#include "io.h"
#include "io_pcb.h"
#include "name.h"
#include "name_prv.h"
#include "event.h"
#include "event_prv.h"
#include "ipc.h"
#include "ipc_prv.h"
#include "ipc_pcb.h"
#include "ipc_pcbv.h"
#include "ipcrtprv.h"
/* A list of current IPC PCB drivers that have been installed */
QUEUE_STRUCT _ipc_pcb_drivers =
{ NULL, NULL, 0, 0};
/* Dummy router table for the IPC. */
const IPC_ROUTING_STRUCT _ipc_routing_table[] =
{
{ 0, 0, 0}
};
/*
* Definition of the field sizes in the IPC message data.
* So that the ENDIAN-ness can be swapped by _msg_swap_endian_data
*/
static const uchar _ipc_msg_type_def[] =
{
sizeof(_mqx_uint),
0};
static const uchar _ipc_msg_def[] =
{
sizeof(_mqx_uint), sizeof(_task_id),
/* Parameters... number of these must equal IPC_MAX_PARAMETERS */
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint),
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint),
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint),
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint),
0};
static const uchar _ipc_mqx_msg_def[] =
{
sizeof(_mqx_uint), sizeof(_task_id), sizeof(_task_id), sizeof(_mqx_uint),
sizeof(_mqx_uint), sizeof(void (_CODE_PTR_)(_mqx_uint)),
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(char _PTR_),
sizeof(_mqx_uint), sizeof(_mqx_uint), sizeof(_mqx_uint),
0};
const IPC_PROTOCOL_INIT_STRUCT _ipc_init_table[] =
{
{ NULL, NULL, NULL, 0}
};
static const IPC_INIT_STRUCT _default_ipc_init =
{
_ipc_routing_table,
_ipc_init_table
};
/*!
* \brief Adds an IPC handler for the MQX component.
*
* The IPC task calls the function when an IPC message for the specified MQX
* component is received. The IPC task calls the function once for each component.
* \n The parameter component can be one of:
* \li KERNEL_EDS_SERIAL
* \li KERNEL_EVENTS
* \li KERNEL_IPC
* \li KERNEL_IPC_MSG_ROUTING
* \li KERNEL_LOG
* \li KERNEL_LWLOG
* \li KERNEL_MESSAGES
* \li KERNEL_MUTEXES
* \li KERNEL_NAME_MANAGEMENT
* \li KERNEL_PARTITIONS
* \li KERNEL_SEMAPHORES
* \li KERNEL_TIMER
* \li KERNEL_WATCHDOG
*
* \param[in] handler Pointer to the function that MQX calls when it receives
* an IPC request for the component.
* \param[in] component MQX component that the handler is for (see Description).
*
* \return MQX_OK
* \return MQX_COMPONENT_DOES_NOT_EXIST (IPC component was not created.)
* \return MQX_IPC_SERVICE_NOT_AVAILABLE (IPC server has not been started.)
*
* \see _ipc_add_io_ipc_handler
*/
_mqx_uint _ipc_add_ipc_handler
(
IPC_HANDLER_FPTR handler,
_mqx_uint component
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_COMPONENT_STRUCT_PTR ipc_component_ptr;
_GET_KERNEL_DATA(kernel_data);
ipc_component_ptr = kernel_data->IPC_COMPONENT_PTR;
#if MQX_CHECK_ERRORS
if (!ipc_component_ptr)
{
return MQX_IPC_SERVICE_NOT_AVAILABLE;
} /* Endif */
if (component > MAX_KERNEL_COMPONENTS)
{
return MQX_COMPONENT_DOES_NOT_EXIST;
} /* Endif */
#endif
ipc_component_ptr->IPC_COMPONENT_HANDLER[component] = handler;
return MQX_OK;
} /* Endif */
/*!
* \brief Add an IPC handler for the I/O component.
*
* The IPC task calls the function when an IPC message for the specified I/O
* component is received. The IPC task calls the function once for each component.
* \n The parameter component can be one of:
* \li IO_CAN_COMPONENT
* \li IO_EDS_COMPONENT
* \li IO_HDLC_COMPONENT
* \li IO_LAPB_COMPONENT
* \li IO_LAPD_COMPONENT
* \li IO_MFS_COMPONENT
* \li IO_PPP_COMPONENT
* \li IO_RTCS_COMPONENT
* \li IO_SDLC_COMPONENT
* \li IO_SNMP_COMPONENT
* \li IO_SUBSYSTEM_COMPONENT
*
* \param[in] handler Pointer to the function that MQX calls when it receives
* an IPC request for the component.
* \param[in] component I/O component that the handler is for (see Description).
*
* \return MQX_OK
* \return MQX_IPC_SERVICE_NOT_AVAILABLE (IPC server has not been started.)
*
* \see _ipc_add_ipc_handler
*/
_mqx_uint _ipc_add_io_ipc_handler
(
IPC_HANDLER_FPTR handler,
_mqx_uint component
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_COMPONENT_STRUCT_PTR ipc_component_ptr;
_GET_KERNEL_DATA(kernel_data);
ipc_component_ptr = kernel_data->IPC_COMPONENT_PTR;
#if MQX_CHECK_ERRORS
if (!ipc_component_ptr)
{
return MQX_IPC_SERVICE_NOT_AVAILABLE;
} /* Endif */
#endif
ipc_component_ptr->IPC_IO_COMPONENT_HANDLER[component] = handler;
return MQX_OK;
} /* Endbody */
/*!
* \brief Handles multi-processor event requests.
*
* \param[in] imsg_ptr The incoming message.
*
* \return MQX_OK
*/
_mqx_uint _event_ipc_handler
(
pointer imsg_ptr
)
{ /* Body */
IPC_MESSAGE_STRUCT_PTR ipc_msg_ptr = imsg_ptr;
pointer event_ptr;
_mqx_uint error_code;
_mqx_uint result = 0;
switch (IPC_GET_TYPE(ipc_msg_ptr->MESSAGE_TYPE))
{
case IPC_EVENT_OPEN:
error_code = _event_open((char _PTR_)&ipc_msg_ptr->PARAMETERS[0],
&event_ptr);
result = (_mqx_uint)event_ptr;
break;
case IPC_EVENT_SET:
event_ptr = (pointer)ipc_msg_ptr->PARAMETERS[0];
error_code = _event_set(event_ptr, ipc_msg_ptr->PARAMETERS[1]);
break;
default:
error_code = MQX_IPC_INVALID_MESSAGE;
break;
} /* Endswitch */
_ipc_send_internal(FALSE,
PROC_NUMBER_FROM_QID(ipc_msg_ptr->HEADER.SOURCE_QID),
KERNEL_MESSAGES, IPC_ACTIVATE,
3, result, ipc_msg_ptr->REQUESTOR_ID,
error_code);
_msg_free(ipc_msg_ptr);
return MQX_OK;
} /* Endbody */
/*!
* \brief Installs the handler for IPC events.
*/
void _event_install_ipc_handler(void)
{ /* Body */
_ipc_add_ipc_handler( _event_ipc_handler, KERNEL_EVENTS);
} /* Endbody */
/*!
* \brief Initializes an IPC for a PCB driver.
*
* The function is used in structure of type IPC_PROTOCOL_STRUCT to initialize the
* Inter-Processor Communications over a serial port using the standard
* ASYNC_SERIAL driver.
* \n The IPC_PROTOCOL_INIT_DATA field in IPC_PROTOCOL_INIT_STRUCT must point to
* a structure of type IPC_PCB_INIT_STRUCT.
*
* \param[in] init_ptr Pointer to an IPC protocol initialization structure
* (IPC_PROTOCOL_INIT_STRUCT).
* \param[in] data_ptr Pointer to an IPC protocol information structure
* (IPC_PROTOCOL_INFO_STRUCT).
*
* \return MQX_OK
* \return IPC_PCB_OUTPUT_PCB_POOL_CREATE_FAILED
* \return IPC_PCB_INVALID_QUEUE
* \return IPC_PCB_PACKET_POOL_CREATE_FAILED
* \return IPC_PCB_DEVICE_OPEN_FAILED
* \return IPC_PCB_INPUT_PCB_POOL_CREATE_FAILED
* \return
*/
_mqx_uint _ipc_pcb_init(
const IPC_PROTOCOL_INIT_STRUCT * init_ptr,
pointer data_ptr)
{
IPC_PROTOCOL_INFO_STRUCT_PTR info_ptr;
IPC_PCB_INFO_STRUCT_PTR pcb_info_ptr;
IPC_PCB_INIT_STRUCT_PTR pcb_init_ptr;
_io_pcb_pool_id pcb_pool;
_queue_id qid;
_pool_id msg_pool;
_mqx_uint result = MQX_OK;
_psp_code_addr _ipc_pcb_function_location = (_psp_code_addr) _ipc_pcb_input_notification;
info_ptr = (IPC_PROTOCOL_INFO_STRUCT_PTR) data_ptr;
pcb_info_ptr = (IPC_PCB_INFO_STRUCT_PTR) _mem_alloc_system_zero((_mem_size) sizeof(IPC_PCB_INFO_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (pcb_info_ptr == NULL)
{
return (_task_get_error());
}
#endif
info_ptr->IPC_PROTOCOL_INFO_PTR = pcb_info_ptr;
pcb_init_ptr = (IPC_PCB_INIT_STRUCT_PTR) init_ptr->IPC_PROTOCOL_INIT_DATA;
info_ptr->IPC_TYPE = IPC_PCB_PROTOCOL;
info_ptr->IPC_INIT_PTR = init_ptr;
/* CREATE OUTPUT PCB POOL */
pcb_pool = _io_pcb_create_pool(1, 0, pcb_init_ptr->OUT_PCBS_INITIAL, pcb_init_ptr->OUT_PCBS_TO_GROW,
pcb_init_ptr->OUT_PCBS_MAX, 0, NULL, 0, NULL);
#if MQX_CHECK_ERRORS
if (pcb_pool == IO_PCB_NULL_POOL_ID)
{
result = IPC_PCB_OUTPUT_PCB_POOL_CREATE_FAILED;
}
else
{
#endif
pcb_info_ptr->PCB_OUTPUT_POOL = pcb_pool;
#if MQX_CHECK_ERRORS
}
#endif
/* Create output message queue */
if (result == MQX_OK)
{
qid = _msgq_open_system((_queue_number) info_ptr->IPC_INIT_PTR->IPC_OUT_QUEUE, 0, _ipc_pcb_output_notification,
info_ptr);
#if MQX_CHECK_ERRORS
if (qid == MSGQ_NULL_QUEUE_ID)
{
result = IPC_PCB_INVALID_QUEUE;
}
else
{
#endif
pcb_info_ptr->OUT_MSG_QID = qid;
#if MQX_CHECK_ERRORS
}
#endif
}
if (result == MQX_OK)
{
/* Create input message pool */
msg_pool = _msgpool_create(pcb_init_ptr->IN_MESSAGES_MAX_SIZE, pcb_init_ptr->IN_MESSAGES_TO_ALLOCATE,
pcb_init_ptr->IN_MESSAGES_TO_GROW, pcb_init_ptr->IN_MESSAGES_MAX_ALLOCATE);
#if MQX_CHECK_ERRORS
if (msg_pool == MSGPOOL_NULL_POOL_ID)
{
result = (IPC_PCB_PACKET_POOL_CREATE_FAILED);
}
else
{
#endif
pcb_info_ptr->MSG_INPUT_POOL = msg_pool;
#if MQX_CHECK_ERRORS
}
#endif
}
if (result == MQX_OK)
{
if (pcb_init_ptr->DEVICE_INSTALL != NULL)
{
result = (*pcb_init_ptr->DEVICE_INSTALL)(pcb_init_ptr->IO_PCB_DEVICE_NAME,
pcb_init_ptr->DEVICE_INSTALL_PARAMETER);
}
}
if (result == MQX_OK)
{
/* Open the IO PCB device */
pcb_info_ptr->FD = fopen(pcb_init_ptr->IO_PCB_DEVICE_NAME, (char_ptr) 0);
#if MQX_CHECK_ERRORS
if (pcb_info_ptr->FD == NULL)
{
result = IPC_PCB_DEVICE_OPEN_FAILED;
}
#endif
}
if (result == MQX_OK)
{
pcb_pool = _io_pcb_create_pool(1, 0, pcb_init_ptr->IN_MESSAGES_TO_ALLOCATE, pcb_init_ptr->IN_MESSAGES_TO_GROW,
pcb_init_ptr->IN_MESSAGES_MAX_ALLOCATE, _ipc_pcb_alloc, info_ptr, 0, NULL);
#if MQX_CHECK_ERRORS
if (pcb_pool == IO_PCB_NULL_POOL_ID)
{
result = IPC_PCB_INPUT_PCB_POOL_CREATE_FAILED;
}
else
{
#endif
pcb_info_ptr->PCB_INPUT_POOL = pcb_pool;
#if MQX_CHECK_ERRORS
}
#endif
}
if (result == MQX_OK)
{
result = ioctl(pcb_info_ptr->FD, IO_PCB_IOCTL_READ_CALLBACK_SET, &_ipc_pcb_function_location);
}
if (result == MQX_OK)
{
result = ioctl(pcb_info_ptr->FD, IO_PCB_IOCTL_SET_INPUT_POOL, (pointer) &pcb_info_ptr->PCB_INPUT_POOL);
}
if (result == MQX_OK)
{
result = ioctl(pcb_info_ptr->FD, IO_PCB_IOCTL_START, NULL);
}
#if MQX_CHECK_ERRORS
if (result != MQX_OK)
{
if (pcb_info_ptr->FD)
{
fclose(pcb_info_ptr->FD);
}
if (pcb_info_ptr->PCB_INPUT_POOL)
{
_io_pcb_destroy_pool(pcb_info_ptr->PCB_INPUT_POOL);
}
if (pcb_info_ptr->MSG_INPUT_POOL)
{
_msgpool_destroy(pcb_info_ptr->MSG_INPUT_POOL);
}
if (pcb_info_ptr->OUT_MSG_QID)
{
_msgq_close(pcb_info_ptr->OUT_MSG_QID);
}
if (pcb_info_ptr->PCB_OUTPUT_POOL)
{
_io_pcb_destroy_pool(pcb_info_ptr->PCB_OUTPUT_POOL);
}
_mem_free(pcb_info_ptr);
}
else
{
#endif
if (_ipc_pcb_drivers.NEXT == NULL)
{
_queue_init(&_ipc_pcb_drivers, 0);
}
_queue_enqueue(&_ipc_pcb_drivers, &pcb_info_ptr->QUEUE);
#if MQX_CHECK_ERRORS
}
#endif
return (result);
}
/*!
* \brief This function is called whenever a message is to be sent offboard.
*
* It packs the message into a PCB and sends it off to an IO PCB device driver.
* The function is called by _msg_send (it is an activation function).
* Note that the PCB free function is set to _ipc_pcb_free.
*
* \param[in] data_ptr Pointer to an IPC protocol information structure
* (IPC_PROTOCOL_INFO_STRUCT).
*/
void _ipc_pcb_output_notification
(
pointer data_ptr
)
{ /* Body */
IPC_PROTOCOL_INFO_STRUCT_PTR info_ptr;
IPC_PCB_INFO_STRUCT_PTR pcb_info_ptr;
IO_PCB_STRUCT_PTR pcb_ptr;
IPC_MESSAGE_STRUCT_PTR msg_ptr;
#if PSP_MEMORY_ADDRESSING_CAPABILITY > 8
boolean must_unpack;
boolean success;
uint_32 frag_size;
uint_32 result;
#endif
info_ptr = (IPC_PROTOCOL_INFO_STRUCT_PTR) data_ptr;
pcb_info_ptr = (IPC_PCB_INFO_STRUCT_PTR) info_ptr->IPC_PROTOCOL_INFO_PTR;
#if PSP_MEMORY_ADDRESSING_CAPABILITY > 8
/* Determine if we must unpack the messages */
result = ioctl(pcb_info_ptr->FD, IO_PCB_IOCTL_UNPACKED_ONLY, &must_unpack);
if (result != MQX_OK)
{
must_unpack = FALSE;
}
#endif
while (_msgq_get_count(info_ptr->IPC_OUT_QID))
{
pcb_ptr = _io_pcb_alloc(pcb_info_ptr->PCB_OUTPUT_POOL, FALSE);
if (pcb_ptr == NULL)
{
return;
}
msg_ptr = (IPC_MESSAGE_STRUCT_PTR) _msgq_poll(info_ptr->IPC_OUT_QID);
#if PSP_MEMORY_ADDRESSING_CAPABILITY > 8
if (must_unpack)
{
success = _ipc_pcb_unpack_message(msg_ptr, pcb_ptr);
_msg_free(msg_ptr);
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (!success)
{
/* Toss the packet */
_io_pcb_free_internal(pcb_ptr);
return;
}
#endif
}
else
{
pcb_ptr->FRAGMENTS[0].LENGTH = (uint_32)msg_ptr->HEADER.SIZE;
pcb_ptr->FRAGMENTS[0].FRAGMENT = (uchar_ptr)msg_ptr;
pcb_ptr->OWNER_PRIVATE_FLAGS = IPC_PCB_FRAG_IS_MSG;
}
#else
pcb_ptr->FRAGMENTS[0].LENGTH = (uint_32) msg_ptr->HEADER.SIZE;
pcb_ptr->FRAGMENTS[0].FRAGMENT = (uchar_ptr) msg_ptr;
#endif
pcb_ptr->FREE_PCB_FUNCTION_PTR = _ipc_pcb_free;
_io_pcb_write(pcb_info_ptr->FD, pcb_ptr);
pcb_info_ptr->OUTPUT_MESSAGE_COUNT++;
}
}
/*!
* \brief Frees a pcb sent via the ipc_pcb output task.
*
* The message that is in the PCB must be freed.
*
* \param[in] pcb_ptr The pcb that has finished.
*/
_mqx_uint _ipc_pcb_free
(
IO_PCB_STRUCT_PTR pcb_ptr
)
{
_msg_free(pcb_ptr->FRAGMENTS[0].FRAGMENT);
return (_io_pcb_free_internal(pcb_ptr));
}
/*!
* \brief Obtains PCB from input PCB pool.
*
* This function is called whenever a PCB is being allocated from the input PCB
* pool, by the input task. For example, when the input task is preparing to set
* up receive data, it would obtain a PCB from the input pool. At that point,
* this function will be called by the pcb alloc function. This function obtains
* a message and sets up the PCB to point to it.
*
* \param[out] pcb_ptr Pointer to the new PCB.
* \param[in] data_ptr Pointer to an IPC protocol information structure.
* (IPC_PROTOCOL_INFO_STRUCT).
*
* \return Pointer to the PCB (or new PCB).
* \return NULL (failure)
*/
IO_PCB_STRUCT_PTR _ipc_pcb_alloc
(
IO_PCB_STRUCT_PTR pcb_ptr,
pointer data_ptr
)
{
IPC_PROTOCOL_INFO_STRUCT_PTR info_ptr;
IPC_PCB_INFO_STRUCT_PTR pcb_info_ptr;
MESSAGE_HEADER_STRUCT_PTR msg_ptr;
info_ptr = (IPC_PROTOCOL_INFO_STRUCT_PTR) data_ptr;
pcb_info_ptr = (IPC_PCB_INFO_STRUCT_PTR) info_ptr->IPC_PROTOCOL_INFO_PTR;
msg_ptr = _msg_alloc(pcb_info_ptr->MSG_INPUT_POOL);
#if MQX_CHECK_ERRORS
if (msg_ptr == NULL)
{
return (NULL);
}
#endif
pcb_ptr->FRAGMENTS[0].LENGTH = 0;
pcb_ptr->FRAGMENTS[0].FRAGMENT = (uchar_ptr) msg_ptr;
pcb_ptr->INSTANTIATOR_PRIVATE = info_ptr;
return (pcb_ptr);
}
/*!
* \brief This function is called by the underlying IO PCB device driver whenever
* an input message has been received.
*
* \param[in] fd_ptr The file descriptor used to set the notification function.
* \param[in] pcb_ptr The pcb that has arrived.
*/
void _ipc_pcb_input_notification
(
MQX_FILE_PTR fd_ptr,
IO_PCB_STRUCT_PTR pcb_ptr
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_PROTOCOL_INFO_STRUCT_PTR info_ptr;
IPC_PCB_INFO_STRUCT_PTR pcb_info_ptr;
MESSAGE_HEADER_STRUCT_PTR msg_ptr;
_GET_KERNEL_DATA(kernel_data);
info_ptr = (IPC_PROTOCOL_INFO_STRUCT_PTR) pcb_ptr->INSTANTIATOR_PRIVATE;
pcb_info_ptr = (IPC_PCB_INFO_STRUCT_PTR) info_ptr->IPC_PROTOCOL_INFO_PTR;
msg_ptr = (MESSAGE_HEADER_STRUCT_PTR) pcb_ptr->FRAGMENTS[0].FRAGMENT;
if (MSG_MUST_CONVERT_HDR_ENDIAN(msg_ptr->CONTROL))
{
_msg_swap_endian_header(msg_ptr);
}
if (PROC_NUMBER_FROM_QID(msg_ptr->TARGET_QID) == 0)
{
/* This is a special message for this CPU */
msg_ptr->TARGET_QID = BUILD_QID(kernel_data->INIT.PROCESSOR_NUMBER, QUEUE_FROM_QID(msg_ptr->TARGET_QID));
}
_msgq_send(msg_ptr);
_io_pcb_free(pcb_ptr);
pcb_info_ptr->INPUT_MESSAGE_COUNT++;
}
/*!
* \brief Adds a route to the message routing table.
*
* The IPC component must first be created.
*
* \param[in] min_proc_number Minimum processor number in the range.
* \param[in] max_proc_number Maximum processor number in the range.
* \param[in] queue Queue number of the IPC to use for processor numbers
* in the range.
*
* \return MQX_OK
* \return MQX_COMPONENT_DOES_NOT_EXIST (IPC component was not created.)
* \return MQX_INVALID_PROCESSOR_NUMBER
* \return MSGQ_INVALID_QUEUE_ID
* \return IPC_ROUTE_EXISTS
* \return MQX_OUT_OF_MEMORY
*
* \see _ipc_msg_route_remove
* \see _ipc_msg_processor_route_exists
* \see IPC_ROUTING_STRUCT
*/
_mqx_uint _ipc_msg_route_add
(
_processor_number min_proc_number,
_processor_number max_proc_number,
_queue_number queue
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR component_ptr;
IPC_MSG_ROUTING_STRUCT_PTR routing_ptr;
#if MQX_CHECK_ERRORS
_processor_number i;
#endif
_GET_KERNEL_DATA(kernel_data);
component_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING];
#if MQX_CHECK_ERRORS
if (component_ptr == NULL)
{
return (MQX_COMPONENT_DOES_NOT_EXIST);
}
if ((min_proc_number < 1) || (max_proc_number > MQX_MAX_PROCESSOR_NUMBER) || (min_proc_number > max_proc_number))
{
return (MQX_INVALID_PROCESSOR_NUMBER);
}
if ((queue == 0) || (queue >= MAX_QNUMBERS))
{
return (MSGQ_INVALID_QUEUE_ID);
}
for (i = min_proc_number; i <= max_proc_number; ++i)
{
if (_ipc_msg_processor_route_exists(i))
{
return (IPC_ROUTE_EXISTS);
}
}
#endif
routing_ptr = (IPC_MSG_ROUTING_STRUCT_PTR) _mem_alloc_system(sizeof(IPC_MSG_ROUTING_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (routing_ptr == NULL)
{
return (MQX_OUT_OF_MEMORY);
}
#endif
routing_ptr->MIN_PROC_NUMBER = min_proc_number;
routing_ptr->MAX_PROC_NUMBER = max_proc_number;
routing_ptr->QUEUE = queue;
_QUEUE_ENQUEUE(&component_ptr->ROUTING_LIST, &routing_ptr->LINK);
return (MQX_OK);
}
/*!
* \brief Removes a route from the message routing table.
*
* The IPC component must first be installed.
*
* \param[in] min_proc_number Minimum processor number in the range.
* \param[in] max_proc_number Maximum processor number in the range.
* \param[in] queue Queue number of the IPC to remove.
*
* \return MQX_OK
* \return MQX_COMPONENT_DOES_NOT_EXIST (IPC component was not created.)
* \return MQX_INVALID_PROCESSOR_NUMBER
*
* \see _ipc_msg_route_add
* \see _ipc_msg_processor_route_exists
*/
_mqx_uint _ipc_msg_route_remove
(
_processor_number min_proc_number,
_processor_number max_proc_number,
_queue_number queue
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR component_ptr;
IPC_MSG_ROUTING_STRUCT_PTR routing_ptr;
IPC_MSG_ROUTING_STRUCT_PTR next_ptr;
uint_16 i;
_GET_KERNEL_DATA(kernel_data);
component_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR)(
(pointer) kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING]);
#if MQX_CHECK_ERRORS
if (component_ptr == NULL)
{
return (MQX_COMPONENT_DOES_NOT_EXIST);
}
if ((min_proc_number < 1) || (max_proc_number > MQX_MAX_PROCESSOR_NUMBER) || (min_proc_number > max_proc_number))
{
return (MQX_INVALID_PROCESSOR_NUMBER);
}
#endif
routing_ptr = (IPC_MSG_ROUTING_STRUCT_PTR)((pointer) component_ptr->ROUTING_LIST.NEXT);
/* Scan list for specified processors */
for (i = 0; i < component_ptr->ROUTING_LIST.SIZE; i++)
{
next_ptr = (IPC_MSG_ROUTING_STRUCT_PTR)((pointer) routing_ptr->LINK.NEXT);
if ((routing_ptr->MIN_PROC_NUMBER == min_proc_number) && (routing_ptr->MAX_PROC_NUMBER == max_proc_number))
{
#if MQX_CHECK_ERRORS
if (routing_ptr->QUEUE == queue)
{
#endif
_QUEUE_REMOVE(&component_ptr->ROUTING_LIST, &routing_ptr->LINK);
_mem_free(routing_ptr);
#if MQX_CHECK_ERRORS
}
#endif
}
routing_ptr = next_ptr;
}
return (MQX_OK);
}
/*!
* \brief Checks whether a route to the specified processor exists.
*
* \param[in] proc_number Processor number to check for a route.
*
* \return Pointer to the route (a route exists).
* \return NULL (Route does not exist.)
*
* \see _ipc_msg_route_add
* \see _ipc_msg_route_remove
*/
pointer _ipc_msg_processor_route_exists
(
_processor_number proc_number
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR component_ptr;
IPC_MSG_ROUTING_STRUCT_PTR routing_ptr;
uint_16 i;
_GET_KERNEL_DATA(kernel_data);
component_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING];
#if MQX_CHECK_ERRORS
if (component_ptr == NULL)
{
return (NULL);
}
#endif
routing_ptr = (IPC_MSG_ROUTING_STRUCT_PTR)((pointer) component_ptr->ROUTING_LIST.NEXT);
for (i = 0; i < component_ptr->ROUTING_LIST.SIZE; i++)
{
if ((proc_number >= routing_ptr->MIN_PROC_NUMBER) && (proc_number <= routing_ptr->MAX_PROC_NUMBER))
{
return ((pointer) routing_ptr);
}
routing_ptr = (IPC_MSG_ROUTING_STRUCT_PTR)((pointer) routing_ptr->LINK.NEXT);
}
/* Route not found */
return (NULL);
}
/*!
* \private
*
* \brief This function is called from the _ipc_init to initialize the message
* router.
*
* \param[in] route_ptr Pointer to IPC routing structure (IPC_MSG_ROUTING_STRUCT_PTR).
*
* \return MQX_OK
* \return MQX_COMPONENT_DOES_NOT_EXIST (IPC component was not created.)
* \return MQX_INVALID_PROCESSOR_NUMBER
* \return MSGQ_INVALID_QUEUE_ID
* \return IPC_ROUTE_EXISTS
* \return MQX_OUT_OF_MEMORY
*/
_mqx_uint _ipc_msg_route_init_internal
(
const IPC_ROUTING_STRUCT * route_ptr
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR component_ptr;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
component_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR) _mem_alloc_system_zero(
(_mem_size) sizeof(IPC_MSG_ROUTING_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (component_ptr == NULL)
{
return (MQX_OUT_OF_MEMORY);
}
#endif
_QUEUE_INIT(&component_ptr->ROUTING_LIST, 0);
/* Install the message routing handlers */
kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING] = (pointer) component_ptr;
while (route_ptr->QUEUE != 0)
{
result = _ipc_msg_route_add(route_ptr->MIN_PROC_NUMBER, route_ptr->MAX_PROC_NUMBER, route_ptr->QUEUE);
#if MQX_CHECK_ERRORS
if (result != MQX_OK)
{
return (result);
}
#endif
route_ptr++;
}
component_ptr->MSG_ROUTER = _ipc_msg_route_internal;
return (MQX_OK);
}
/*!
* \private
*
* \brief This function is called from _msg_send to route an inter-processor message.
*
* \param[in] pnum The processor to send the message to.
* \param[in] message The message to be sent.
* \param[in] blocking Is this a blocking message.
*
* \return TRUE or FALSE
*
* \warning On failure, calls _task_set_error() to set the following task error code:
* \li MSGQ_INVALID_QUEUE_ID
*/
_mqx_uint _ipc_msg_route_internal
(
_processor_number pnum,
pointer message,
boolean blocking
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR component_ptr;
IPC_MSG_ROUTING_STRUCT_PTR route_ptr;
boolean result;
_queue_number queue;
_GET_KERNEL_DATA(kernel_data);
component_ptr = (IPC_MSG_ROUTING_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_IPC_MSG_ROUTING];
route_ptr = (IPC_MSG_ROUTING_STRUCT_PTR) _ipc_msg_processor_route_exists(pnum);
if (!route_ptr)
{
_task_set_error(MSGQ_INVALID_QUEUE_ID);
return (FALSE);
}
queue = route_ptr->QUEUE;
result = _msgq_send_queue(message, BUILD_QID(kernel_data->INIT.PROCESSOR_NUMBER, queue));
if (result && blocking && (!kernel_data->IN_ISR))
{
_int_disable();
kernel_data->ACTIVE_PTR->STATE = SEND_BLOCKED;
_task_block();
_int_enable();
}
return (result);
}
/*!
* \brief Task that initializes IPCs and processes remote service requests.
*
* For applications to use the IPC component, the task must be either specified
* in the task template list as an autostart task or explicitly created.
* \n The task installs the IPCs that are listed in the IPC initialization
* structure. Pointer to this initialization structure (IPC_INIT_STRUCT_PTR) is
* provided as the creation parameter, otherwise default IPC_INIT_STRUCT is used
* (_default_ipc_init). When the initialization is finished it waits for service
* requests from remote processors.
*
* \param[in] parameter Pointer to the IPC_INIT_STRUCT (task creation parameter).
*
* \see IPC_INIT_STRUCT
*/
void _ipc_task
(
uint_32 parameter
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_COMPONENT_STRUCT_PTR ipc_component_ptr;
const IPC_INIT_STRUCT * ipc_init_ptr = (IPC_INIT_STRUCT_PTR) parameter;
IPC_MESSAGE_STRUCT_PTR msg_ptr;
IPC_MQX_MESSAGE_STRUCT_PTR ipc_msg_ptr;
const IPC_PROTOCOL_INIT_STRUCT * protocol_init_ptr;
IPC_PROTOCOL_INFO_STRUCT_PTR info_ptr;
TD_STRUCT_PTR td_ptr;
IPC_HANDLER_FPTR handler;
_queue_id queue;
_mqx_uint result;
_mqx_uint component;
_GET_KERNEL_DATA(kernel_data);
if (ipc_init_ptr == NULL)
{
ipc_init_ptr = &_default_ipc_init;
}
/* Install the message routing handlers */
result = _ipc_msg_route_init_internal(ipc_init_ptr->ROUTING_LIST_PTR);
#if MQX_CHECK_ERRORS
if (result != MQX_OK)
{
_task_set_error(result);
_task_block();
}
#endif
kernel_data->MY_IPC_TD_PTR = kernel_data->ACTIVE_PTR;
kernel_data->MY_IPC_ID = kernel_data->ACTIVE_PTR->TASK_ID;
/* Create the IPC component structure */
ipc_component_ptr = (IPC_COMPONENT_STRUCT_PTR) _mem_alloc_zero((_mem_size) sizeof(IPC_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (ipc_component_ptr == NULL)
{
_task_block();
}
#endif
kernel_data->IPC_COMPONENT_PTR = ipc_component_ptr;
/* Create a pool of messages for use by the ipc task. */
kernel_data->IPC_NAMED_POOL = _msgpool_create(sizeof(IPC_MESSAGE_STRUCT), IPC_NUM_MESSAGES, IPC_GROW_MESSAGES,
IPC_LIMIT_MESSAGES);
#if MQX_CHECK_ERRORS || MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (kernel_data->IPC_NAMED_POOL == MSGPOOL_NULL_POOL_ID)
{
_task_block();
}
#endif
/* Open the ipc message queue */
queue = _msgq_open(IPC_MESSAGE_QUEUE_NUMBER, 0);
#if MQX_CHECK_ERRORS
if (queue == MSGQ_NULL_QUEUE_ID)
{
_task_block();
}
#endif
kernel_data->IPC = _ipc_send_internal;
/* Initialize inter-processor communications protocols */
protocol_init_ptr = ipc_init_ptr->PROTOCOL_LIST_PTR;
while (protocol_init_ptr->IPC_PROTOCOL_INIT != NULL)
{
#if MQX_CHECK_ERRORS
if (((_queue_number) protocol_init_ptr->IPC_OUT_QUEUE) == 0
|| ((_queue_number) protocol_init_ptr->IPC_OUT_QUEUE > MQX_MAX_PROCESSOR_NUMBER))
{
_task_block();
}
#endif
info_ptr = (IPC_PROTOCOL_INFO_STRUCT_PTR) _mem_alloc_zero((_mem_size) sizeof(IPC_PROTOCOL_INFO_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
if (info_ptr == NULL)
{
_task_block();
}
#endif
info_ptr->IPC_OUT_QUEUE = protocol_init_ptr->IPC_OUT_QUEUE;
info_ptr->IPC_NAME = protocol_init_ptr->IPC_NAME;
info_ptr->IPC_OUT_QID = _msgq_get_id(0, (_queue_number) protocol_init_ptr->IPC_OUT_QUEUE);
info_ptr->IPC_INIT_PTR = protocol_init_ptr;
(*protocol_init_ptr->IPC_PROTOCOL_INIT)(protocol_init_ptr, info_ptr);
protocol_init_ptr++;
}
/*
* The IPC Initialization is complete. Wait for messages to come in
* and service them.
*/
while (TRUE)
{
_task_set_error(MQX_OK);
msg_ptr = (IPC_MESSAGE_STRUCT_PTR) _msgq_receive(MSGQ_ANY_QUEUE, 0L);
if (MSG_MUST_CONVERT_DATA_ENDIAN(msg_ptr->HEADER.CONTROL))
{
_msg_swap_endian_data((uchar _PTR_) ((pointer) _ipc_msg_type_def), (MESSAGE_HEADER_STRUCT_PTR)(
(pointer) msg_ptr));
if (msg_ptr->MESSAGE_TYPE & IPC_MQX_TYPE_MASK)
{
_mem_swap_endian((uchar _PTR_) _ipc_mqx_msg_def, &msg_ptr->NUMBER_OF_PARAMETERS);
}
else
{
_mem_swap_endian_len((uchar _PTR_) _ipc_msg_def, &msg_ptr->NUMBER_OF_PARAMETERS,
msg_ptr->NUMBER_OF_PARAMETERS + 2);
}
}
if (msg_ptr->MESSAGE_TYPE & IPC_MQX_TYPE_MASK)
{
ipc_msg_ptr = (IPC_MQX_MESSAGE_STRUCT_PTR)((pointer) msg_ptr);
switch (ipc_msg_ptr->MESSAGE_TYPE & IPC_MQX_TYPE_MASK)
{
case IPC_MQX_CREATE:
_KLOGE4(KLOG_task_create, 0, ipc_msg_ptr->TEMPLATE_INDEX,ipc_msg_ptr->CREATE_PARAMETER)
;
if (ipc_msg_ptr->TEMPLATE_INDEX == 0)
{
td_ptr = _task_build_internal(0, (uint_32) &ipc_msg_ptr->TEMPLATE, NULL, 0, FALSE);
}
else
{
td_ptr = _task_build_internal(ipc_msg_ptr->TEMPLATE_INDEX,
(uint_32) ipc_msg_ptr->CREATE_PARAMETER, NULL, 0, FALSE);
}
_KLOGX3(KLOG_task_create, MQX_NULL_TASK_ID, MQX_INVALID_PROCESSOR_NUMBER)
;
if (td_ptr != NULL)
{
td_ptr->PARENT = ipc_msg_ptr->REQUESTOR_ID;
_task_ready(td_ptr);
_KLOGX3(KLOG_task_create, td_ptr->TASK_ID, MQX_OK);
}
else
{
_KLOGX3(KLOG_task_create, MQX_NULL_TASK_ID, _task_get_error());
}
result = (_mqx_uint) td_ptr->TASK_ID;
_ipc_send_internal(FALSE, PROC_NUMBER_FROM_TASKID(msg_ptr->REQUESTOR_ID), KERNEL_MESSAGES,
IPC_ACTIVATE, (_mqx_uint) 3, result, msg_ptr->REQUESTOR_ID,
kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
break;
case IPC_MQX_ABORT:
result = (_mqx_uint) _task_abort(ipc_msg_ptr->VICTIM_ID);
break;
case IPC_MQX_RESTART:
result = (_mqx_uint) _task_restart(ipc_msg_ptr->VICTIM_ID, NULL, TRUE);
break;
case IPC_MQX_DESTROY:
result = (_mqx_uint) _task_destroy(ipc_msg_ptr->VICTIM_ID);
break;
case IPC_MQX_ACTIVATE:
/* Start the specified task, setting the INFO
* to the returned result.
*/
td_ptr = (TD_STRUCT_PTR) _task_get_td(ipc_msg_ptr->REQUESTOR_ID);
if (td_ptr != NULL)
{
if (td_ptr->STATE == SEND_BLOCKED)
{
td_ptr->INFO = ipc_msg_ptr->VICTIM_ID;
_task_set_error_td_internal(td_ptr, ipc_msg_ptr->CREATE_PARAMETER);
_task_ready(td_ptr);
}
}
result = MQX_OK;
break;
}
_msg_free((pointer) msg_ptr);
}
else
{
component = IPC_GET_COMPONENT(msg_ptr->MESSAGE_TYPE);
if (component < MAX_KERNEL_COMPONENTS)
{
handler = ipc_component_ptr->IPC_COMPONENT_HANDLER[component];
#if MQX_CHECK_ERRORS
if (handler)
{
#endif
_task_set_error(MQX_OK);
result = (*handler)((pointer) msg_ptr);
#if MQX_CHECK_ERRORS
}
else
{
result = MQX_IPC_SERVICE_NOT_AVAILABLE;
}
#endif
}
else if (component < (MAX_KERNEL_COMPONENTS + MAX_IO_COMPONENTS))
{
handler = ipc_component_ptr->IPC_IO_COMPONENT_HANDLER[component - MAX_KERNEL_COMPONENTS];
#if MQX_CHECK_ERRORS
if (handler)
{
#endif
_task_set_error(MQX_OK);
result = (*handler)((pointer) msg_ptr);
#if MQX_CHECK_ERRORS
}
else
{
result = MQX_IPC_SERVICE_NOT_AVAILABLE;
_msg_free((pointer) msg_ptr);
}
#endif
}
else
{
result = MQX_IPC_INVALID_MESSAGE;
_msg_free((pointer) msg_ptr);
}
}
}
}
/*!
* \private
*
* \brief Creates an IPC message and sends it.
*
* \param[in] blocking Specifies whether or not to block current task.
* \param[in] processor_number The processor to send to.
* \param[in] component The component to receive the message.
* \param[in] type The type of component message.
* \param[in] num_parameters The number of parameters in the message.
*
* \return MQX_OK
* \return Task error code from ....
*/
_mqx_uint _ipc_send_internal
(
boolean blocking,
_processor_number processor_number,
_mqx_uint component,
_mqx_uint type,
_mqx_uint num_parameters,
...)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
IPC_MESSAGE_STRUCT_PTR msg_ptr;
IPC_MQX_MESSAGE_STRUCT_PTR ipc_msg_ptr;
va_list ap;
_mqx_uint i;
_GET_KERNEL_DATA(kernel_data);
kernel_data->ACTIVE_PTR->TASK_ERROR_CODE = MQX_OK;
msg_ptr = (IPC_MESSAGE_STRUCT_PTR) _msg_alloc((_pool_id) kernel_data->IPC_NAMED_POOL);
while (msg_ptr == NULL)
{
_time_delay(kernel_data->KERNEL_ALARM_RESOLUTION * 2);
msg_ptr = (IPC_MESSAGE_STRUCT_PTR) _msg_alloc((_pool_id) kernel_data->IPC_NAMED_POOL);
}
msg_ptr->HEADER.TARGET_QID = BUILD_QID(processor_number, IPC_MESSAGE_QUEUE_NUMBER);
msg_ptr->HEADER.SOURCE_QID = BUILD_QID((_processor_number) kernel_data->INIT.PROCESSOR_NUMBER,
IPC_MESSAGE_QUEUE_NUMBER);
va_start(ap, num_parameters);
if (component == KERNEL_MESSAGES)
{
ipc_msg_ptr = (IPC_MQX_MESSAGE_STRUCT_PTR)((pointer) msg_ptr);
ipc_msg_ptr->REQUESTOR_ID = kernel_data->ACTIVE_PTR->TASK_ID;
switch (type)
{
case IPC_TASK_CREATE:
case IPC_TASK_CREATE_WITH_TEMPLATE:
ipc_msg_ptr->MESSAGE_TYPE = IPC_MQX_CREATE;
if (type == IPC_TASK_CREATE_WITH_TEMPLATE)
{
ipc_msg_ptr->TEMPLATE_INDEX = 0;
ipc_msg_ptr->TEMPLATE.TASK_TEMPLATE_INDEX = va_arg(ap, uint_32);
ipc_msg_ptr->TEMPLATE.TASK_ADDRESS = (TASK_FPTR)va_arg(ap, _psp_code_addr);
ipc_msg_ptr->TEMPLATE.TASK_STACKSIZE = va_arg(ap, _mem_size);
ipc_msg_ptr->TEMPLATE.TASK_PRIORITY = va_arg(ap, _mqx_uint);
ipc_msg_ptr->TEMPLATE.TASK_NAME = va_arg(ap, char_ptr);
ipc_msg_ptr->TEMPLATE.TASK_ATTRIBUTES = va_arg(ap, _mqx_uint);
ipc_msg_ptr->TEMPLATE.CREATION_PARAMETER = va_arg(ap, uint_32);
ipc_msg_ptr->CREATE_PARAMETER = ipc_msg_ptr->TEMPLATE.CREATION_PARAMETER;
ipc_msg_ptr->TEMPLATE.DEFAULT_TIME_SLICE = va_arg(ap, uint_32);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT);
}
else
{
i = va_arg(ap, _mqx_uint); /* Toss processor number */
ipc_msg_ptr->TEMPLATE_INDEX = va_arg(ap, _mqx_uint);
ipc_msg_ptr->CREATE_PARAMETER = (uint_32) va_arg(ap, uint_32);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT) - sizeof(TASK_TEMPLATE_STRUCT);
}
break;
case IPC_TASK_DESTROY:
ipc_msg_ptr->MESSAGE_TYPE = IPC_MQX_DESTROY;
ipc_msg_ptr->VICTIM_ID = va_arg(ap, _mqx_uint);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT) - sizeof(TASK_TEMPLATE_STRUCT);
break;
case IPC_TASK_ABORT:
ipc_msg_ptr->MESSAGE_TYPE = IPC_MQX_ABORT;
ipc_msg_ptr->VICTIM_ID = va_arg(ap, _mqx_uint);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT) - sizeof(TASK_TEMPLATE_STRUCT);
break;
case IPC_TASK_RESTART:
ipc_msg_ptr->MESSAGE_TYPE = IPC_MQX_RESTART;
ipc_msg_ptr->VICTIM_ID = va_arg(ap, _mqx_uint);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT) - sizeof(TASK_TEMPLATE_STRUCT);
break;
case IPC_ACTIVATE:
ipc_msg_ptr->MESSAGE_TYPE = IPC_MQX_ACTIVATE;
ipc_msg_ptr->VICTIM_ID = va_arg(ap, _mqx_uint);
ipc_msg_ptr->REQUESTOR_ID = va_arg(ap, _mqx_uint);
ipc_msg_ptr->CREATE_PARAMETER = (uint_32) va_arg(ap, uint_32);
ipc_msg_ptr->HEADER.SIZE = sizeof(IPC_MQX_MESSAGE_STRUCT) - sizeof(TASK_TEMPLATE_STRUCT);
break;
}
}
else
{
msg_ptr->MESSAGE_TYPE = IPC_SET_COMPONENT(0, component);
msg_ptr->MESSAGE_TYPE = IPC_SET_TYPE(msg_ptr->MESSAGE_TYPE, type);
if (!blocking)
{
msg_ptr->MESSAGE_TYPE = IPC_SET_NON_BLOCKING(msg_ptr->MESSAGE_TYPE, 1);
}
msg_ptr->REQUESTOR_ID = kernel_data->ACTIVE_PTR->TASK_ID;
if (num_parameters > IPC_MAX_PARAMETERS)
{
num_parameters = IPC_MAX_PARAMETERS;
}
if (type & IPC_STRING_PARAMETER)
{
--num_parameters;
msg_ptr->HEADER.SIZE = (_msg_size) sizeof(IPC_MESSAGE_STRUCT);
}
else
{
msg_ptr->HEADER.SIZE = (_msg_size)(sizeof(IPC_MESSAGE_STRUCT) - (IPC_MAX_PARAMETERS * sizeof(uint_32))
+ (num_parameters * sizeof(uint_32)));
}
msg_ptr->NUMBER_OF_PARAMETERS = (uint_32) num_parameters;
for (i = 0; (i < num_parameters) && (i < IPC_MAX_PARAMETERS); ++i)
{
msg_ptr->PARAMETERS[i] = (uint_32) (va_arg(ap, uint_32));
}
if (type & IPC_STRING_PARAMETER)
{
char_ptr to_ptr = (char_ptr) &msg_ptr->PARAMETERS[i];
char_ptr from_ptr = (char_ptr) va_arg(ap, pointer);
uint_32 size = (IPC_MAX_PARAMETERS - i) * sizeof(uint_32);
strncpy((pointer) to_ptr, (pointer) from_ptr, size);
to_ptr[size - 1] = '\0';
}
}
va_end(ap);
if (blocking)
{
if (_msgq_send_blocked_internal(msg_ptr))
{
return MQX_OK;
}
}
else
{
if (_msgq_send(msg_ptr))
{
return MQX_OK;
}
}
return kernel_data->ACTIVE_PTR->TASK_ERROR_CODE;
}
#endif /* MQX_USE_IPC */
/* EOF */