Example #1
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available. The data is NOT copied into the user-app. buffer.
 *
 * This is the "zero-copy receive" version of the MCC receive function. No data is copied. 
 * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
 * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
 * make the appropriate API call to free it.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[out] buffer_p Pointer to the MCC buffer of the shared memory where the received data is stored.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of valid bytes in the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_copy
 * \see MCC_ENDPOINT
 */
int mcc_recv_nocopy(MCC_ENDPOINT *endpoint, void **buffer_p, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    int return_value;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
	}

    /* Get the message pointer from the head of the receive buffer list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    *buffer_p = (void*)&list->head->data;
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    mcc_dequeue_buffer(list);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Example #2
0
/*!
 * \brief This function sends a message to an endpoint.
 *
 * The message is copied into the MCC buffer and the destination core is signaled.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to send to.
 * \param[in] msg Pointer to the message to be sent.
 * \param[in] msg_size Size of the message to be sent in bytes.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available)
 * \return MCC_ERR_NOMEM (no free buffer available and timeout_us set to 0)
 * \return MCC_ERR_SQ_FULL (signal queue is full)
 *
 * \see mcc_recv_copy
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_send(MCC_ENDPOINT *endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_us)
{
    int return_value, end_time_set_flag = 0;
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */
    if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) {
        return MCC_ERR_INVAL;
    }

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    buf = mcc_dequeue_buffer(&bookeeping_data->free_list);

    while(buf == null) {
        mcc_release_semaphore();

        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_NOMEM;
        }
        /* Blocking calls: CPU-to-CPU ISR sets the event and thus resumes tasks waiting for a free MCC buffer.
         * As the interrupt request is send to all cores when a buffer is freed it could happen that several
         * tasks from different cores/nodes are waiting for a free buffer and all of them are notified that the buffer
         * has been freed. This function has to check (after the wake up) that a buffer is really available and has not been already
         * grabbed by another "competitor task" that has been faster. If so, it has to wait again for the next notification. */
        /* wait forever */
        else if(timeout_us == 0xFFFFFFFF) {
#if (MCC_OS_USED == MCC_MQX)
            _lwevent_wait_ticks(&lwevent_buffer_freed, 1, TRUE, 0);
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        /* timeout_us > 0 */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(!end_time_set_flag) {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                end_time_set_flag = 1;
            }
            return_value = _lwevent_wait_until(&lwevent_buffer_freed, 1, TRUE, &tick_time);
            if(return_value == LWEVENT_WAIT_TIMEOUT) {
                /* Buffer not dequeued before the timeout */
                return MCC_ERR_TIMEOUT;
            }
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_get_semaphore();
        buf = mcc_dequeue_buffer(&bookeeping_data->free_list);
    }

    /* Semaphore-protected section end */
    mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Copy the message into the MCC receive buffer */
    mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size);
    MCC_DCACHE_FLUSH_MLINES((void*)buf->data, msg_size);
    buf->data_len = msg_size;
    MCC_DCACHE_FLUSH_MLINES((void*)&buf->data_len, sizeof(MCC_MEM_SIZE));

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    if(list == null) {
        /* The endpoint does not exists (has not been registered so far),
         free the buffer and return immediately - error */
        /* Enqueue the buffer back into the free list */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);
      
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    /* Write the signal type into the signal queue of the particular core */
    affiliated_signal.type = BUFFER_QUEUED;
    affiliated_signal.destination = *endpoint;
    return_value = mcc_queue_signal(endpoint->core, affiliated_signal);
    if(return_value != MCC_SUCCESS) {
        /* Signal queue is full, free the buffer and return immediately - error */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);

        mcc_release_semaphore();
        return return_value;
    }

    /* Enqueue the buffer into the endpoint buffer list */
    mcc_queue_buffer(list, buf);

    /* Semaphore-protected section end */
    mcc_release_semaphore();

    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Signal the other core by generating the CPU-to-CPU interrupt */
    return_value = mcc_generate_cpu_to_cpu_interrupt();

    return return_value;
}
Example #3
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available.
 *        The data will be copied from the receive buffer into the user supplied buffer.
 *
 * This is the "receive with copy" version of the MCC receive function. This version is simple
 * to use but it requires copying data from shared memory into the user space buffer.
 * The user has no obligation or burden to manage the shared memory buffers.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[in] buffer Pointer to the user-app. buffer where data will be copied into.
 * \param[in] buffer_size The maximum number of bytes to copy.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_recv_copy(MCC_ENDPOINT *endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
    MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};
    int return_value, i = 0;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
    }

    /* Copy the message from the MCC receive buffer into the user-app. buffer */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    if (list->head->data_len > buffer_size) {
        list->head->data_len = buffer_size;
    }
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    mcc_memcpy((void*)list->head->data, buffer, list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    buf = mcc_dequeue_buffer(list);

    /* Enqueue the buffer into the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    mcc_queue_buffer(&bookeeping_data->free_list, buf);

    /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */
    affiliated_signal.type = BUFFER_FREED;
    affiliated_signal.destination = tmp_destination;
    for (i=0; i<MCC_NUM_CORES; i++) {
        if(i != MCC_CORE_NUMBER) {
            mcc_queue_signal(i, affiliated_signal);
        }
    }
    mcc_generate_cpu_to_cpu_interrupt();

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Example #4
0
/*!
 * \brief 	MQX API handler for usermode - part of wrapper around standard MQX API
 *  which require privilege mode.
 *
 * \param[in] api_no API number - number of wrapped function
 * \param[in] params generic parameter - direct use with called MQX API fn
 *
 * \return uint32_t return of called function
 */
uint32_t _mqx_api_call_handler
    (
        // [IN] API number - number of wrapped function
        MQX_API_NUMBER_ENUM api_no,
        // [IN] generic parameter - direct use with called MQX API fn
        MQX_API_CALL_PARAMS_PTR params
    )
{
    int32_t res = -1;
    uint32_t param0 = params->param0;
    uint32_t param1 = params->param1;
    uint32_t param2 = params->param2;
    uint32_t param3 = params->param3;
    uint32_t param4 = params->param4;

    switch (api_no) {

    // _lwsem
    case MQX_API_LWSEM_POLL:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)))
            res = (uint32_t)_lwsem_poll((LWSEM_STRUCT_PTR)param0);
        break;
    case MQX_API_LWSEM_POST:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)))
            res = _lwsem_post((LWSEM_STRUCT_PTR)param0);
        break;
    case MQX_API_LWSEM_WAIT:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)))
            res = _lwsem_wait((LWSEM_STRUCT_PTR)param0);
        break;
    case MQX_API_LWSEM_CREATE:
        res = _lwsem_create_internal((LWSEM_STRUCT_PTR)param0, (_mqx_int)param1, (bool)param2, TRUE);
        break;
#if MQX_HAS_TICK
    case MQX_API_LWSEM_WAIT_FOR:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)) && (!param1 || _psp_mem_check_access(param1, sizeof(MQX_TICK_STRUCT), MPU_UM_RW)))
            res = _lwsem_wait_for((LWSEM_STRUCT_PTR)param0, (MQX_TICK_STRUCT_PTR)param1);
        break;
    case MQX_API_LWSEM_WAIT_TICKS:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)))
            res = _lwsem_wait_ticks((LWSEM_STRUCT_PTR)param0, (_mqx_uint)param1);
        break;
    case MQX_API_LWSEM_WAIT_UNTIL:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0)) && (!param1 || _psp_mem_check_access(param1, sizeof(MQX_TICK_STRUCT), MPU_UM_RW)))
            res = _lwsem_wait_until((LWSEM_STRUCT_PTR)param0, (MQX_TICK_STRUCT_PTR)param1);
        break;
    case MQX_API_LWSEM_DESTROY:
        if (MQX_OK == (res = _lwsem_usr_check((LWSEM_STRUCT_PTR)param0))) {
            res = _lwsem_destroy_internal((LWSEM_STRUCT_PTR)param0, TRUE);
        }
        break;

#endif // MQX_HAS_TICK

    // _lwevent
#if MQX_USE_LWEVENTS
    case MQX_API_LWEVENT_CLEAR:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0)))
            res = _lwevent_clear((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1);
        break;
    case MQX_API_LWEVENT_SET:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0)))
            res = _lwevent_set((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1);
        break;
    case MQX_API_LWEVENT_SET_AUTO_CLEAR:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0)))
            res = _lwevent_set_auto_clear((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1);
        break;
    case MQX_API_LWEVENT_WAIT_FOR:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0)) && \
            (!param3 || _psp_mem_check_access(param3, sizeof(MQX_TICK_STRUCT), MPU_UM_RW))) {
            res = _lwevent_wait_for((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1, (bool)param2, (MQX_TICK_STRUCT_PTR)param3);
        }
        break;
    case MQX_API_LWEVENT_WAIT_FOR_TICKS:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0))) {
            res = _lwevent_wait_ticks((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1, (bool)param2, (_mqx_uint)param3);
        }
        break;
    case MQX_API_LWEVENT_WAIT_UNTIL:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0)) && \
            (!param3 || _psp_mem_check_access(param3, sizeof(MQX_TICK_STRUCT), MPU_UM_RW))) {
            res = _lwevent_wait_until((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1, (bool)param2, (MQX_TICK_STRUCT_PTR)param3);
        }
        break;
    case MQX_API_LWEVENT_GET_SIGNALLED:
        res = _lwevent_get_signalled();
        break;

    case MQX_API_LWEVENT_CREATE:
        res = _lwevent_create_internal((LWEVENT_STRUCT_PTR)param0, (_mqx_uint)param1, TRUE);
        break;

    case MQX_API_LWEVENT_DESTROY:
        if (MQX_OK == (res = _lwevent_usr_check((LWEVENT_STRUCT_PTR)param0))) {
            res = _lwevent_destroy_internal((LWEVENT_STRUCT_PTR)param0, TRUE);
        }
        break;
#endif

#if MQX_USE_LWMSGQ
    case MQX_API_LWMSGQ_INIT:
        res = _lwmsgq_init_internal((void *)param0, (_mqx_uint)param1, (_mqx_uint)param2, TRUE);
        break;
    case MQX_API_LWMSGQ_RECEIVE:
        if (MQX_OK == (res = _lwmsgq_usr_check((LWMSGQ_STRUCT_PTR)param0)) && \
            _psp_mem_check_access(param1, ((LWMSGQ_STRUCT_PTR)param0)->MSG_SIZE, MPU_UM_RW) && \
            (!param4 || _psp_mem_check_access(param4, sizeof(MQX_TICK_STRUCT), MPU_UM_RW)))
            res = _lwmsgq_receive((void *)param0, (_mqx_max_type_ptr)param1, (_mqx_uint)param2, (_mqx_uint)param3, (MQX_TICK_STRUCT_PTR)param4);

        break;
    case MQX_API_LWMSGQ_SEND:
        if (MQX_OK == (res = _lwmsgq_usr_check((LWMSGQ_STRUCT_PTR)param0)) && \
            _psp_mem_check_access(param1, ((LWMSGQ_STRUCT_PTR)param0)->MSG_SIZE, MPU_UM_RW))
            res = _lwmsgq_send((void *)param0, (_mqx_max_type_ptr)param1, (_mqx_uint)param2);
        break;
#endif // MQX_USE_LWMSGQ

    case MQX_API_TASK_CREATE:
        res = _task_create_internal((_processor_number)param0, (_mqx_uint)param1, (uint32_t)param2, TRUE);
        break;
    case MQX_API_TASK_DESTROY:
        res = _task_destroy_internal((_task_id)param0, TRUE);
        break;
    case MQX_API_TASK_ABORT:
        res = _task_abort_internal((_task_id)param0, TRUE);
        break;
    case MQX_API_TASK_READY:
        _task_ready((void *)param0);
        res = MQX_OK;       // irelevant, function is without return value
        break;
    case MQX_API_TASK_SET_ERROR:
        res = _task_set_error((_mqx_uint)param0);
        break;
    case MQX_API_TASK_GET_TD:
        res = (uint32_t)_task_get_td((_task_id)param0);
        break;

#if MQX_USE_LWMEM
    case MQX_API_LWMEM_ALLOC:
        res = (uint32_t)_usr_lwmem_alloc_internal((_mem_size)param0);
        break;

    case MQX_API_LWMEM_ALLOC_FROM:
        if (_psp_mem_check_access(param0, sizeof(LWMEM_POOL_STRUCT), MPU_UM_RW) && \
            _psp_mem_check_access((uint32_t)(((LWMEM_POOL_STRUCT_PTR)param0)->POOL_ALLOC_START_PTR), (char*)(((LWMEM_POOL_STRUCT_PTR)param0)->POOL_ALLOC_END_PTR) - (char*)(((LWMEM_POOL_STRUCT_PTR)param0)->POOL_ALLOC_START_PTR), MPU_UM_RW))
            res = (uint32_t)_lwmem_alloc_from((_lwmem_pool_id)param0, (_mem_size)param1);
        else
            res = 0; // NULL, allocation failed
        break;

    case MQX_API_LWMEM_FREE:
        if (_psp_mem_check_access(param0, 4, MPU_UM_RW))
            res = _lwmem_free((void *)param0);
        break;

    case MQX_API_LWMEM_CREATE_POOL:\
        if (_psp_mem_check_access(param0, sizeof(LWMEM_POOL_STRUCT), MPU_UM_RW) && \
            _psp_mem_check_access(param1, param2, MPU_UM_RW))
            res = (uint32_t)_lwmem_create_pool((LWMEM_POOL_STRUCT_PTR)param0, (void *)param1, (_mem_size)param2);
        break;

    case MQX_API_LWMEM_REALLOC:
        if (_psp_mem_check_access(param0, 4, MPU_UM_RW))
          res = (uint32_t)_lwmem_realloc((void *)param0,(_mem_size)param1);
        break;
#endif // MQX_USE_LWMEM

    // _time
    case MQX_API_TIME_DELAY:
        _time_delay(param0);
        res = MQX_OK;       // irelevant, function is without return value
        break;

#if MQX_HAS_TICK
    case MQX_API_TIME_DELAY_TICKS:
        _time_delay_ticks(param0);
        res = MQX_OK;       // irelevant, function is without return value
        break;
    case MQX_API_TIME_GET_ELAPSED_TICKS:
        if (_psp_mem_check_access(param0, sizeof(MQX_TICK_STRUCT), MPU_UM_RW)) {
            _time_get_elapsed_ticks((MQX_TICK_STRUCT_PTR)param0);
            res = MQX_OK;       // irelevant, function is without return value
        }
        else {
            _task_set_error(MQX_ACCESS_ERROR);
        }

        break;
#endif // MQX_HAS_TICK
    default:
        while (1);
    }

    return res;
}