/*
 * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS 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 THE COPYRIGHT HOLDER OR 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.
 */

#if defined (FSL_RTOS_MQX)

#include <assert.h>
#include "fsl_os_abstraction.h"

////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////

fsl_rtos_status sync_create(sync_object_t *obj, uint8_t initValue)
{
    return MQX_OK == _lwsem_create(obj, initValue) ? kSuccess : kError;
}

fsl_rtos_status sync_wait(sync_object_t *obj, uint32_t timeout)
{
    _mqx_uint retVal;
    
    uint32_t msecs = timeout * 1000 / _time_get_ticks_per_sec();
    retVal = _lwsem_wait_ticks(obj, msecs);
    
    if(MQX_OK == retVal)
    {
        return kSuccess;
    }
    else if (MQX_LWSEM_WAIT_TIMEOUT == retVal)
    {
        return kTimeout;
    }
    else
    {
        return kError;
    }
}

fsl_rtos_status sync_poll(sync_object_t *obj)
{
    return _lwsem_poll(obj) ? kSuccess : kError;
}

fsl_rtos_status sync_signal(sync_object_t *obj)
{
    return MQX_OK == _lwsem_post(obj) ? kSuccess : kError;
}

fsl_rtos_status sync_signal_from_isr(sync_object_t *obj)
{
    return MQX_OK == _lwsem_post(obj) ? kSuccess : kError;
}

fsl_rtos_status sync_destroy(sync_object_t *obj)
{
    return MQX_OK == _lwsem_destroy(obj) ? kSuccess : kError;
}

fsl_rtos_status lock_create(lock_object_t *obj)
{
    _mqx_uint retVal;  
  
    MUTEX_ATTR_STRUCT mutexattr;
    
    retVal = _mutatr_init(&mutexattr);
    if (MQX_OK == retVal) {
        retVal = _mutatr_set_sched_protocol(&mutexattr, MUTEX_PRIO_INHERIT);
        if (MQX_OK == retVal) {
            retVal = _mutex_init(obj, &mutexattr);    
        }
    }
    
    return MQX_OK == retVal ? kSuccess : kError;
}


fsl_rtos_status lock_wait(lock_object_t *obj, uint32_t timeout)
{
    return MQX_OK == _mutex_lock(obj) ? kSuccess : kError;
}

fsl_rtos_status lock_poll(lock_object_t *obj)
{
    return MQX_OK == _mutex_try_lock(obj) ? kSuccess : kError;
}

fsl_rtos_status lock_release(lock_object_t *obj)
{
    return MQX_OK == _mutex_unlock(obj) ? kSuccess : kError;
}

fsl_rtos_status lock_destroy(lock_object_t *obj)
{
    return MQX_OK == _mutex_destroy(obj) ? kSuccess : kError;
}
/*
 * \return MQX_OK
 * \return MQX_EINVAL (lwevent is already initialized.)
 * \return MQX_LWEVENT_INVALID (In case of user mode, MQX tries to access
 * a lwevent with inappropriate access rights.)
*/

fsl_rtos_status event_create(event_object_t *obj, event_clear_type clearType)
{
    _mqx_uint retVal;
    
    retVal = _lwevent_create(obj, kEventAutoClr == clearType ? LWEVENT_AUTO_CLEAR : 0);
    
    return (retVal == MQX_OK) ? kSuccess : kError;
}

fsl_rtos_status event_wait(event_object_t *obj, uint32_t timeout, event_group_t *setFlags)
{
    _mqx_uint retVal;

    if (kSyncWaitForever == timeout)
    {
        retVal = _lwevent_wait_ticks(obj, (uint32_t)-1, FALSE, 0);
    }
    else
    {
        uint32_t msecs = timeout * 1000 / _time_get_ticks_per_sec();
        retVal = _lwevent_wait_ticks(obj, (uint32_t)-1, FALSE, msecs ? msecs : 1);
    }
    
    if (MQX_OK == retVal)
    {
        *setFlags = _lwevent_get_signalled();
        
        return kSuccess;
    }
    else if (LWEVENT_WAIT_TIMEOUT == retVal)
    {
        return kTimeout;
    }
    else
    {
        return kError;
    }
}

fsl_rtos_status event_set(event_object_t *obj, event_group_t flags)
{
    return MQX_OK == _lwevent_set(obj, flags) ? kSuccess : kError;
}

fsl_rtos_status event_clear(event_object_t *obj, event_group_t flags)
{
    return MQX_OK == _lwevent_clear(obj, flags) ? kSuccess : kError;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : event_check_flags
 * Description   : Check the event bit is set or not.
 * Return kFlagSet if any bit is set, otherwise return kFlagNotSet.
 *
 *END**************************************************************************/
event_status event_check_flags(event_object_t *obj,
                               event_group_t   flag)
{
    if ((obj->VALUE & flag) != 0) {
        return kFlagSet;
    }
    else {
        return kFlagNotSet;
    }
}

fsl_rtos_status event_set_from_isr(event_object_t *obj, event_group_t flags)
{
    return MQX_OK == _lwevent_set(obj, flags) ? kSuccess : kError;
}

fsl_rtos_status event_destroy(event_object_t *obj)
{
    return MQX_OK == _lwevent_destroy(obj) ? kSuccess : kError;
}


fsl_rtos_status __task_create(task_t task, uint8_t *name, uint16_t stackSize, task_stack_t *stackMem,
                              uint16_t priority, void *param, bool usesFloat, task_handler_t *handler)
{
   
    TASK_TEMPLATE_STRUCT taskTemplate = 
        {
            .TASK_TEMPLATE_INDEX = 0,   /* Don't care */
            .TASK_ADDRESS = task,
            .TASK_STACKSIZE = stackSize,
            .TASK_PRIORITY = priority,
            .TASK_NAME = (char *)name,
            .TASK_ATTRIBUTES = 0,
            .CREATION_PARAMETER = (uint32_t)param,
            .DEFAULT_TIME_SLICE = 0,   /* Don't care */
        };
    
    if (usesFloat)
    {
        taskTemplate.TASK_ATTRIBUTES |= MQX_FLOATING_POINT_TASK;
    }
    
    /* Create task on local processor and passing a task template */
    *handler = _task_create(0, 0, (uint32_t)&taskTemplate);
    
    if (MQX_NULL_TASK_ID != *handler)
    {
        return kSuccess;
    }
    else
    {
        return kError;
    }
}

fsl_rtos_status task_destroy(task_handler_t handler)
{
    return MQX_OK == _task_abort(handler) ? kSuccess : kError;
}

msg_queue_handler_t msg_queue_create(msg_queue_t *queue, uint16_t number, uint16_t size)
{
    _mqx_uint retVal;
    MQX_OSA_QUEUE *moq = (MQX_OSA_QUEUE *)queue;
    
    /* Create the message queue where each element is a pointer to the message item. */
#if __FSL_RTOS_MSGQ_COPY_MSG__
    retVal = _lwmsgq_init(moq->msgq, number, SIZE_IN_MMT_UNITS(size * 4));
#else //__FSL_RTOS_MSGQ_COPY_MSG__
    retVal = _lwmsgq_init(moq->msgq, number, SIZE_IN_MMT_UNITS(sizeof(msg_queue_t)));
#endif //__FSL_RTOS_MSGQ_COPY_MSG__
    
    if (MQX_OK == retVal)
    {
        return (msg_queue_handler_t)queue;
    }
    else
    {
        return (msg_queue_handler_t)NULL;
    }
}

fsl_rtos_status msg_queue_put(msg_queue_handler_t handler, msg_queue_item_t item)
{
    MQX_OSA_QUEUE *moq = (MQX_OSA_QUEUE *)handler;
    #if __FSL_RTOS_MSGQ_COPY_MSG__
        return MQX_OK == _lwmsgq_send(moq->msgq, (_mqx_max_type_ptr)item, 0) ? kSuccess : kError;     /* Does not block if full */
    #else
        return MQX_OK == _lwmsgq_send(moq->msgq, (_mqx_max_type_ptr)(&item), 0) ? kSuccess : kError;     /* Does not block if full */
    #endif
}

fsl_rtos_status msg_queue_get(msg_queue_handler_t handler, msg_queue_item_t *item, uint32_t timeout)
{
    _mqx_uint retVal;
    MQX_OSA_QUEUE *moq = (MQX_OSA_QUEUE *)handler;

    /* Pending timeout translation */
    if (kSyncWaitForever == timeout)
    {
        #if __FSL_RTOS_MSGQ_COPY_MSG__
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)(*item), LWMSGQ_RECEIVE_BLOCK_ON_EMPTY, 0, NULL);
        #else
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)item, LWMSGQ_RECEIVE_BLOCK_ON_EMPTY, 0, NULL);
        #endif
    }
    else if (timeout)
    {
        uint32_t msecs = timeout * 1000 / _time_get_ticks_per_sec();
        #if __FSL_RTOS_MSGQ_COPY_MSG__
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)(*item), LWMSGQ_RECEIVE_BLOCK_ON_EMPTY, msecs, NULL);
        #else
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)item, LWMSGQ_RECEIVE_BLOCK_ON_EMPTY, msecs, NULL);
        #endif
    }
    else
    {
        #if __FSL_RTOS_MSGQ_COPY_MSG__
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)(*item), 0, 0, NULL);
        #else
            retVal = _lwmsgq_receive(moq->msgq, (_mqx_max_type_ptr)item, 0, 0, NULL);
        #endif
    }

    if (MQX_OK == retVal)
    {
        return kSuccess;
    }
    else if (LWMSGQ_TIMEOUT == retVal)
    {
        return kTimeout;
    }
    else
    {
        return kError;
    }
}

fsl_rtos_status msg_queue_flush(msg_queue_handler_t handler)
{
    _mqx_uint retVal;
    MQX_OSA_QUEUE *moq = (MQX_OSA_QUEUE *)handler;
    
    do
    {
        retVal = _lwmsgq_receive(moq->msgq, moq->one_msg, 0, 0, NULL);     /* Does not block if empty */
    } while (MQX_OK == retVal);

    /* If last status indicates the queue is empty, then the operation succeeded. Return erro otherwise. */
    if (LWMSGQ_EMPTY == retVal)
    {
        return kSuccess;
    }
    else
    {
        return kError;
    }
}

fsl_rtos_status msg_queue_destroy(msg_queue_handler_t handler)
{
    MQX_OSA_QUEUE *moq = (MQX_OSA_QUEUE *)handler;
    return MQX_OK == _lwmsgq_deinit(moq->msgq) ? kSuccess : kError;
}

void * mem_allocate(size_t size)
{
    /* We allocate memory as a system, not as a calling task. That will prevent
     * us from failures during freeing the same memory from another task.
     */
    return _mem_alloc_system(size);
}

void * mem_allocate_zero(size_t size)
{
    return _mem_alloc_system_zero(size);
}

fsl_rtos_status mem_free(void *ptr)
{
    return MQX_OK == _mem_free(ptr) ? kSuccess : kError;
}

void rtos_enter_critical(void)
{
    _int_disable();
}

void rtos_exit_critical(void)
{
    _int_enable();
}

void time_delay(uint32_t delay)
{
    _time_delay(delay);
}

#endif
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
