Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / abstraction-rtos / source / COMPONENT_RTX / cyabs_rtos_rtxv5.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 32 KB Fix file modes.
/***********************************************************************************************//**
 * \file cyabs_rtos_rtxv5.c
 *
 * \brief
 * Implementation for CMSIS RTOS v2 abstraction
 *
 ***************************************************************************************************
 * \copyright
 * Copyright 2018-2021 Cypress Semiconductor Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **************************************************************************************************/

#include <stdlib.h>
#include <cy_utils.h>
#include <cyabs_rtos.h>

#if defined(__cplusplus)
extern "C" {
#endif

#define CY_RTOS_THREAD_FLAG 0x01

/******************************************************
*                 Error Converter
******************************************************/

// Last received error status
static cy_rtos_error_t dbgErr;


//--------------------------------------------------------------------------------------------------
// cy_rtos_last_error
//--------------------------------------------------------------------------------------------------
cy_rtos_error_t cy_rtos_last_error()
{
    return dbgErr;
}


//--------------------------------------------------------------------------------------------------
// error_converter
//
// Converts internal error type to external error type
//--------------------------------------------------------------------------------------------------
static cy_rslt_t error_converter(cy_rtos_error_t internalError)
{
    cy_rslt_t value;

    switch (internalError)
    {
        case osOK:
            value = CY_RSLT_SUCCESS;
            break;

        case osErrorTimeout:
            value = CY_RTOS_TIMEOUT;
            break;

        case osErrorParameter:
            value = CY_RTOS_BAD_PARAM;
            break;

        case osErrorNoMemory:
            value = CY_RTOS_NO_MEMORY;
            break;

        case osError:
        case osErrorResource:
        case osErrorISR:
        default:
            value = CY_RTOS_GENERAL_ERROR;
            break;
    }

    // Update the last known error status
    dbgErr = internalError;
    return value;
}


//--------------------------------------------------------------------------------------------------
// convert_ms_to_ticks
//--------------------------------------------------------------------------------------------------
static uint32_t convert_ms_to_ticks(cy_time_t timeout_ms)
{
    if (timeout_ms == CY_RTOS_NEVER_TIMEOUT)
    {
        return osWaitForever;
    }
    else if (timeout_ms == 0)
    {
        return 0;
    }
    else
    {
        // Get number of ticks per second
        uint32_t tick_freq = osKernelGetTickFreq();
        uint32_t ticks = (uint32_t)(((uint64_t)timeout_ms * tick_freq) / 1000);

        if (ticks == 0)
        {
            ticks = 1;
        }
        else if (ticks >= UINT32_MAX)
        {
            // if ticks if more than 32 bits, change ticks to max possible value that isn't
            // osWaitForever.
            ticks = UINT32_MAX - 1;
        }
        return ticks;
    }
}


/******************************************************
*                 Threads
******************************************************/

cy_rslt_t cy_rtos_create_thread(cy_thread_t* thread, cy_thread_entry_fn_t entry_function,
                                const char* name, void* stack, uint32_t stack_size,
                                cy_thread_priority_t priority, cy_thread_arg_t arg)
{
    cy_rslt_t      status = CY_RSLT_SUCCESS;
    osThreadAttr_t attr;

    if ((thread == NULL) || (stack_size < CY_RTOS_MIN_STACK_SIZE))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else if ((stack != NULL) && (0 != (((uint32_t)stack) & CY_RTOS_ALIGNMENT_MASK)))
    {
        status = CY_RTOS_ALIGNMENT_ERROR;
    }
    else
    {
        attr.name       = name;
        attr.attr_bits  = osThreadJoinable;
        attr.cb_size    = osRtxThreadCbSize;
        attr.stack_size = stack_size;
        attr.priority   = (osPriority_t)priority;
        attr.tz_module  = 0;
        attr.reserved   = 0;

        // Allocate stack if NULL was passed
        if ((uint32_t*)stack == NULL)
        {
            // Note: 1 malloc so that it can be freed with 1 call when terminating
            uint32_t cb_mem_pad = (~osRtxThreadCbSize + 1) & CY_RTOS_ALIGNMENT_MASK;
            attr.cb_mem = malloc(osRtxThreadCbSize + cb_mem_pad + stack_size);
            if (attr.cb_mem != NULL)
            {
                attr.stack_mem =
                    (uint32_t*)((uint32_t)attr.cb_mem + osRtxThreadCbSize + cb_mem_pad);
            }
        }
        else
        {
            attr.cb_mem    = malloc(osRtxThreadCbSize);
            attr.stack_mem = stack;
        }

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            CY_ASSERT(((uint32_t)attr.stack_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *thread = osThreadNew((osThreadFunc_t)entry_function, arg, &attr);
            CY_ASSERT((*thread == attr.cb_mem) || (*thread == NULL));
            status = (*thread == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_exit_thread
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_exit_thread()
{
    // This does not have a return statement because the osThreadExit() function * does not return
    // so the return statement would be unreachable and causes a * warning for IAR compiler.
    osThreadExit();
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_terminate_thread
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_terminate_thread(cy_thread_t* thread)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (thread == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osThreadTerminate(*thread);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_is_thread_running
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_is_thread_running(cy_thread_t* thread, bool* running)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((thread == NULL) || (running == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *running = (osThreadGetState(*thread) == osThreadRunning) ? true : false;
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_thread_state
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_thread_state(cy_thread_t* thread, cy_thread_state_t* state)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((thread == NULL) || (state == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        switch (osThreadGetState(*thread))
        {
            case osThreadInactive:
                *state = CY_THREAD_STATE_INACTIVE;
                break;

            case osThreadReady:
                *state = CY_THREAD_STATE_READY;
                break;

            case osThreadRunning:
                *state = CY_THREAD_STATE_RUNNING;
                break;

            case osThreadBlocked:
                *state = CY_THREAD_STATE_BLOCKED;
                break;

            case osThreadTerminated:
                *state = CY_THREAD_STATE_TERMINATED;
                break;

            case osThreadError:
            case osThreadReserved:
            default:
                *state = CY_THREAD_STATE_UNKNOWN;
                break;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_join_thread
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_join_thread(cy_thread_t* thread)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (thread == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osThreadJoin(*thread);
        status         = error_converter(statusInternal);

        if (status == CY_RSLT_SUCCESS)
        {
            free(*thread);
            *thread = NULL;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_thread_handle
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_thread_handle(cy_thread_t* thread)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if (thread == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *thread = osThreadGetId();
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_wait_thread_notification
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_wait_thread_notification(cy_time_t num_ms)
{
    uint32_t ret;
    cy_rslt_t status = CY_RSLT_SUCCESS;
    ret = osThreadFlagsWait(CY_RTOS_THREAD_FLAG, osFlagsWaitAll, convert_ms_to_ticks(num_ms));
    if (ret & osFlagsError)
    {
        status = (ret == osFlagsErrorTimeout) ? CY_RTOS_TIMEOUT : CY_RTOS_GENERAL_ERROR;
        // Update the last known error status
        dbgErr = (cy_rtos_error_t)ret;
    }
    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_set_thread_notification
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_set_thread_notification(cy_thread_t* thread, bool in_isr)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;
    uint32_t ret;

    (void)in_isr;
    if (thread == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        /* According to the description of CMSIS-RTOS v2
         * osThreadFlagsSet() can be called inside ISR
         */
        ret = osThreadFlagsSet(*thread, CY_RTOS_THREAD_FLAG);
        if (ret & osFlagsError)
        {
            status = CY_RTOS_GENERAL_ERROR;
            // Update the last known error status
            dbgErr = (cy_rtos_error_t)ret;
        }
    }
    return status;
}


/******************************************************
*                 Mutexes
******************************************************/

cy_rslt_t cy_rtos_init_mutex2(cy_mutex_t* mutex, bool recursive)
{
    cy_rslt_t     status;
    osMutexAttr_t attr;

    if (mutex == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        attr.name      = NULL;
        attr.attr_bits = osMutexPrioInherit;
        if (recursive)
        {
            attr.attr_bits |= osMutexRecursive;
        }
        attr.cb_mem  = malloc(osRtxMutexCbSize);
        attr.cb_size = osRtxMutexCbSize;

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *mutex = osMutexNew(&attr);
            CY_ASSERT((*mutex == attr.cb_mem) || (*mutex == NULL));
            status = (*mutex == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_mutex
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_mutex(cy_mutex_t* mutex, cy_time_t timeout_ms)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (mutex == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osMutexAcquire(*mutex, timeout_ms);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_set_mutex
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_set_mutex(cy_mutex_t* mutex)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (mutex == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osMutexRelease(*mutex);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_deinit_mutex
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_deinit_mutex(cy_mutex_t* mutex)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (mutex == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osMutexDelete(*mutex);
        status         = error_converter(statusInternal);

        if (status == CY_RSLT_SUCCESS)
        {
            free(*mutex);
            *mutex = NULL;
        }
    }

    return status;
}


/******************************************************
*                 Semaphores
******************************************************/

cy_rslt_t cy_rtos_init_semaphore(cy_semaphore_t* semaphore, uint32_t maxcount, uint32_t initcount)
{
    cy_rslt_t         status;
    osSemaphoreAttr_t attr;

    if (semaphore == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        attr.name      = NULL;
        attr.attr_bits = 0U;
        attr.cb_mem    = malloc(osRtxSemaphoreCbSize);
        attr.cb_size   = osRtxSemaphoreCbSize;

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *semaphore = osSemaphoreNew(maxcount, initcount, &attr);
            CY_ASSERT((*semaphore == attr.cb_mem) || (*semaphore == NULL));
            status = (*semaphore == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_semaphore
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_semaphore(cy_semaphore_t* semaphore, cy_time_t timeout_ms, bool in_isr)
{
    cy_rslt_t       status = CY_RSLT_SUCCESS;
    cy_rtos_error_t statusInternal;

    if (semaphore == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        // Not allowed to be called in ISR if timeout != 0
        if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
        {
            statusInternal = osSemaphoreAcquire(*semaphore, timeout_ms);
        }
        else
        {
            statusInternal = osErrorISR;
        }

        status = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_set_semaphore
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_set_semaphore(cy_semaphore_t* semaphore, bool in_isr)
{
    cy_rslt_t       status = CY_RSLT_SUCCESS;
    cy_rtos_error_t statusInternal;
    (void)in_isr; // Unused parameter in this implementation

    if (semaphore == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osSemaphoreRelease(*semaphore);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_count_semaphore
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_count_semaphore(cy_semaphore_t* semaphore, size_t* count)
{
    cy_rslt_t status;
    if ((semaphore == NULL) || (count == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *count = osSemaphoreGetCount(*semaphore);
        status = CY_RSLT_SUCCESS;
    }
    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_deinit_semaphore
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_deinit_semaphore(cy_semaphore_t* semaphore)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (semaphore == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osSemaphoreDelete(*semaphore);
        status         = error_converter(statusInternal);
        if (status == CY_RSLT_SUCCESS)
        {
            free(*semaphore);
            *semaphore = NULL;
        }
    }

    return status;
}


/******************************************************
*                 Events
******************************************************/

#define CY_RTOS_EVENT_ERRORFLAG     0x80000000UL
#define CY_RTOS_EVENT_FLAGS         0x7FFFFFFFUL

//--------------------------------------------------------------------------------------------------
// cy_rtos_init_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_init_event(cy_event_t* event)
{
    cy_rslt_t          status;
    osEventFlagsAttr_t attr;

    if (event == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        attr.name      = NULL;
        attr.attr_bits = 0U;
        attr.cb_mem    = malloc(osRtxEventFlagsCbSize);
        attr.cb_size   = osRtxEventFlagsCbSize;

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *event = osEventFlagsNew(&attr);
            CY_ASSERT((*event == attr.cb_mem) || (*event == NULL));
            status = (*event == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_setbits_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_setbits_event(cy_event_t* event, uint32_t bits, bool in_isr)
{
    cy_rslt_t       status = CY_RSLT_SUCCESS;
    cy_rtos_error_t statusInternal;
    (void)in_isr; // Unused parameter in this implementation

    if (event == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = (osStatus_t)osEventFlagsSet(*event, bits);
        if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) != 0UL)
        {
            status = error_converter(statusInternal);
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_clearbits_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_clearbits_event(cy_event_t* event, uint32_t bits, bool in_isr)
{
    cy_rslt_t       status = CY_RSLT_SUCCESS;
    cy_rtos_error_t statusInternal;
    (void)in_isr; // Unused parameter in this implementation

    if (event == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = (osStatus_t)osEventFlagsClear(*event, bits);
        if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) != 0UL)
        {
            status = error_converter(statusInternal);
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_getbits_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_getbits_event(cy_event_t* event, uint32_t* bits)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((event == NULL) || (bits == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *bits = osEventFlagsGet(*event);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_waitbits_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_waitbits_event(cy_event_t* event, uint32_t* bits, bool clear, bool all,
                                 cy_time_t timeout)
{
    cy_rslt_t       status = CY_RSLT_SUCCESS;
    cy_rtos_error_t statusInternal;
    uint32_t        flagOption;

    if ((event == NULL) || (bits == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        flagOption = (all) ? osFlagsWaitAll : osFlagsWaitAny;
        if (!clear)
        {
            flagOption |= osFlagsNoClear;
        }

        statusInternal = (osStatus_t)osEventFlagsWait(*event, *bits, flagOption, timeout);
        if ((statusInternal & CY_RTOS_EVENT_ERRORFLAG) == 0UL)
        {
            *bits = statusInternal;
        }
        else
        {
            status = error_converter(statusInternal);
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_deinit_event
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_deinit_event(cy_event_t* event)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (event == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osEventFlagsDelete(*event);
        status         = error_converter(statusInternal);
        if (status == CY_RSLT_SUCCESS)
        {
            free(*event);
            *event = NULL;
        }
    }

    return status;
}


/******************************************************
*                 Queues
******************************************************/

cy_rslt_t cy_rtos_init_queue(cy_queue_t* queue, size_t length, size_t itemsize)
{
    cy_rslt_t            status;
    osMessageQueueAttr_t attr;

    if (queue == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        attr.name      = NULL;
        attr.attr_bits = 0U;
        attr.cb_size   = osRtxMessageQueueCbSize;
        uint32_t blockSize = ((itemsize + 3U) & ~3UL) + sizeof(osRtxMessage_t);
        attr.mq_size = blockSize * length;

        // Note: 1 malloc for both so that they can be freed with 1 call
        uint32_t cb_mem_pad = (8 - (osRtxMessageQueueCbSize & 0x07)) & 0x07;
        attr.cb_mem = malloc(osRtxMessageQueueCbSize + cb_mem_pad + attr.mq_size);
        if (attr.cb_mem != NULL)
        {
            attr.mq_mem = (uint32_t*)((uint32_t)attr.cb_mem + osRtxMessageQueueCbSize + cb_mem_pad);
        }

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            CY_ASSERT(((uint32_t)attr.mq_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *queue = osMessageQueueNew(length, itemsize, &attr);
            CY_ASSERT((*queue == attr.cb_mem) || (*queue == NULL));
            status = (*queue == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_put_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_put_queue(cy_queue_t* queue, const void* item_ptr, cy_time_t timeout_ms,
                            bool in_isr)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if ((queue == NULL) || (item_ptr == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        // Not allowed to be called in ISR if timeout != 0
        if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
        {
            statusInternal = osMessageQueuePut(*queue, (uint8_t*)item_ptr, 0u, timeout_ms);
        }
        else
        {
            statusInternal = osErrorISR;
        }

        status = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_get_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_get_queue(cy_queue_t* queue, void* item_ptr, cy_time_t timeout_ms, bool in_isr)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if ((queue == NULL) || (item_ptr == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        // Not allowed to be called in ISR if timeout != 0
        if ((!in_isr) || (in_isr && (timeout_ms == 0U)))
        {
            statusInternal = osMessageQueueGet(*queue, (uint8_t*)item_ptr, 0u, timeout_ms);
        }
        else
        {
            statusInternal = osErrorISR;
        }

        status = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_count_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_count_queue(cy_queue_t* queue, size_t* num_waiting)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((queue == NULL) || (num_waiting == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *num_waiting = osMessageQueueGetCount(*queue);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_space_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_space_queue(cy_queue_t* queue, size_t* num_spaces)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((queue == NULL) || (num_spaces == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *num_spaces = osMessageQueueGetSpace(*queue);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_reset_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_reset_queue(cy_queue_t* queue)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (queue == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osMessageQueueReset(*queue);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_deinit_queue
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_deinit_queue(cy_queue_t* queue)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (queue == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osMessageQueueDelete(*queue);
        status         = error_converter(statusInternal);

        if (status == CY_RSLT_SUCCESS)
        {
            free(*queue);
            *queue = NULL;
        }
    }

    return status;
}


/******************************************************
*                 Timers
******************************************************/

cy_rslt_t cy_rtos_init_timer(cy_timer_t* timer, cy_timer_trigger_type_t type,
                             cy_timer_callback_t fun, cy_timer_callback_arg_t arg)
{
    cy_rslt_t     status;
    osTimerAttr_t attr;

    if (timer == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        attr.name      = NULL;
        attr.attr_bits = 0U;
        attr.cb_mem    = malloc(osRtxTimerCbSize);
        attr.cb_size   = osRtxTimerCbSize;

        if (attr.cb_mem == NULL)
        {
            status = CY_RTOS_NO_MEMORY;
        }
        else
        {
            osTimerType_t osTriggerType = (CY_TIMER_TYPE_PERIODIC == type)
                ? osTimerPeriodic
                : osTimerOnce;

            CY_ASSERT(((uint32_t)attr.cb_mem & CY_RTOS_ALIGNMENT_MASK) == 0UL);
            *timer = osTimerNew((osTimerFunc_t)fun, osTriggerType, (void*)arg, &attr);
            CY_ASSERT((*timer == attr.cb_mem) || (*timer == NULL));
            status = (*timer == NULL) ? CY_RTOS_GENERAL_ERROR : CY_RSLT_SUCCESS;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_start_timer
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_start_timer(cy_timer_t* timer, cy_time_t num_ms)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (timer == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osTimerStart(*timer, convert_ms_to_ticks(num_ms));
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_stop_timer
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_stop_timer(cy_timer_t* timer)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (timer == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osTimerStop(*timer);
        status         = error_converter(statusInternal);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_is_running_timer
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_is_running_timer(cy_timer_t* timer, bool* state)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;

    if ((timer == NULL) || (state == NULL))
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        *state = osTimerIsRunning(*timer);
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_deinit_timer
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_deinit_timer(cy_timer_t* timer)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    if (timer == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        statusInternal = osTimerDelete(*timer);
        status         = error_converter(statusInternal);

        if (status == CY_RSLT_SUCCESS)
        {
            free(*timer);
            *timer = NULL;
        }
    }

    return status;
}


/******************************************************
*                 Time
******************************************************/

cy_rslt_t cy_rtos_get_time(cy_time_t* tval)
{
    cy_rslt_t status = CY_RSLT_SUCCESS;
    uint32_t  tick_freq;

    if (tval == NULL)
    {
        status = CY_RTOS_BAD_PARAM;
    }
    else
    {
        // Get Number of ticks per second
        tick_freq = osKernelGetTickFreq();

        // Convert ticks count to time in milliseconds
        if (tick_freq != 0)
        {
            *tval = (cy_time_t)((osKernelGetTickCount() * 1000LL) / tick_freq);
        }
        else
        {
            status = CY_RTOS_GENERAL_ERROR;
        }
    }

    return status;
}


//--------------------------------------------------------------------------------------------------
// cy_rtos_delay_milliseconds
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_rtos_delay_milliseconds(cy_time_t num_ms)
{
    cy_rslt_t       status;
    cy_rtos_error_t statusInternal;

    statusInternal = osDelay(num_ms);
    status         = error_converter(statusInternal);

    return status;
}


#if defined(__cplusplus)
}
#endif