eric2013 发表于 2024-2-22 09:28:11

FreeRTOS的各种API使用ThreadX实现方法

threadx/utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c at master · eclipse-threadx/threadx (github.com)


切换到ThreadX后,习惯了FreeRTOS的API,这个提供了使用ThreadX实现各种FreeRTOS API的方法

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/

/**************************************************************************/
/**************************************************************************/
/**                                                                     */
/** ThreadX Component                                                   */
/**                                                                     */
/**   FreeRTOS compatibility Kit                                          */
/**                                                                     */
/**************************************************************************/
/**************************************************************************/
/*RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE            NAME                      DESCRIPTION             */
/*                                                                        */
/*09-30-2020   William E. Lamie         Initial Version 6.1         */
/*10-15-2021   William E. Lamie         Modified comment(s), and      */
/*                                          fixed compiler warnings,    */
/*                                          resulting in version 6.1.7*/
/*01-31-2022   William E. Lamie         Modified comment(s), and      */
/*                                          fixed compiler warnings,    */
/*                                          resulting in version 6.1.10 */
/*07-29-2022   Cindy Deng               Added simple static scheduler */
/*                                          start flag, corrected stack */
/*                                          allocation size,            */
/*                                          resulting in version 6.1.12 */
/*12-31-2023   Xiuwen Cai               Modified comment(s), and      */
/*                                          added check for overflow in */
/*                                          queue size calculation,   */
/*                                          resulting in version 6.4.0*/
/*                                                                        */
/**************************************************************************/

#include <stdint.h>
#include <limits.h>

#include <tx_api.h>
#include <tx_thread.h>
#include <tx_semaphore.h>
#include <tx_queue.h>

#include "FreeRTOS.h"

#if (INCLUDE_vTaskDelete == 1)
static TX_THREAD txfr_idle_task;
#ifdef TX_FREERTOS_IDLE_STACK
static UINT txfr_idle_stack;
#else
static UINT txfr_idle_stack;
#endif
static TX_SEMAPHORE txfr_idle_sem;

static txfr_task_t *p_delete_task_head;
#endif // #if (INCLUDE_vTaskDelete == 1)

UBaseType_t g_txfr_task_count;

#ifdef configTOTAL_HEAP_SIZE
static uint8_t txfr_heap_mem;
static TX_BYTE_POOL txfr_heap;
#endif

static UINT txfr_heap_initialized;
#if (TX_FREERTOS_AUTO_INIT == 1)
static UINT txfr_initialized;
static UINT txfr_scheduler_started;
#endif // #if (TX_FREERTOS_AUTO_INIT == 1)

// TODO - do something with malloc.
void *txfr_malloc(size_t len)
{
    void *p;
    UINT ret;

    if(txfr_heap_initialized == 1u) {
      ret = tx_byte_allocate(&txfr_heap, &p, len, 0u);
      if(ret != TX_SUCCESS) {
            return NULL;
      }
    } else {
      return NULL;
    }

    return p;
}

void txfr_free(void *p)
{
    UINT ret;

    if(txfr_heap_initialized == 1u) {
      ret = tx_byte_release(p);
      if(ret != TX_SUCCESS) {
            TX_FREERTOS_ASSERT_FAIL();
      }
    }

    return;
}

#if (INCLUDE_vTaskDelete == 1)
static void txfr_idle_task_entry(ULONG id)
{
    txfr_task_t *p_task;
    UINT ret;
    TX_INTERRUPT_SAVE_AREA;


    for(;;) {
      ret = tx_semaphore_get(&txfr_idle_sem, TX_WAIT_FOREVER);
      if(ret != TX_SUCCESS) {
            TX_FREERTOS_ASSERT_FAIL();
      }

      TX_DISABLE;
      p_task = p_delete_task_head;

      if(p_task != NULL) {
            p_delete_task_head = p_task->p_next;
      }
      g_txfr_task_count--;
      TX_RESTORE;

      if(p_task != NULL) {

            // Make sure the task is terminated, which may return an error if that's already the case so the return value is ignored.
            (void)tx_thread_terminate(&p_task->thread);

            ret = tx_thread_delete(&p_task->thread);
            if(ret != TX_SUCCESS) {
                TX_FREERTOS_ASSERT_FAIL();
            }

            ret = tx_semaphore_delete(&p_task->notification_sem);
            if(ret != TX_SUCCESS) {
                TX_FREERTOS_ASSERT_FAIL();
            }

            if(p_task->allocated == 1u) {
                txfr_free(p_task);
            }
      }

    }
}
#endif // #if (INCLUDE_vTaskDelete == 1)

static uint32_t txfr_prio_fr_to_tx(uint32_t prio)
{
    return TX_MAX_PRIORITIES - 1u - prio;
}


static uint32_t txfr_prio_tx_to_fr(uint32_t prio)
{
    return TX_MAX_PRIORITIES - 1u - prio;
}

#if (TX_FREERTOS_AUTO_INIT == 1)
static void tx_freertos_auto_init(void)
{
    UINT ret;

    tx_kernel_enter();

    ret = tx_freertos_init();
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

    txfr_initialized = 1u;
}
#endif // #if (TX_FREERTOS_AUTO_INIT == 1)

#if (TX_FREERTOS_AUTO_INIT == 1)
VOID tx_application_define(VOID * first_unused_memory)
{
    // Empty tx_application_define() to support auto initialization.
}
#endif // #if (TX_FREERTOS_AUTO_INIT == 1)

UINT tx_freertos_init(void)
{
    UINT ret;

#ifdef configTOTAL_HEAP_SIZE
    if(configTOTAL_HEAP_SIZE > 0u) {
      ret = tx_byte_pool_create(&txfr_heap, "txfr_byte_pool", txfr_heap_mem, configTOTAL_HEAP_SIZE);
      if(ret != TX_SUCCESS) {
            return ret;
      }
      txfr_heap_initialized = 1u;
    }
#endif

#if (INCLUDE_vTaskDelete == 1)
    ret = tx_semaphore_create(&txfr_idle_sem, "txfr_idle_semaphore", 0u);
    if(ret != TX_SUCCESS) {
      return ret;
    }

    ret = tx_thread_create(&txfr_idle_task, "txfr_idle_task", txfr_idle_task_entry, 0u,
            txfr_idle_stack, sizeof(txfr_idle_stack), TX_MAX_PRIORITIES - 1u, TX_MAX_PRIORITIES - 1u, 0u, TX_AUTO_START);
    if(ret != TX_SUCCESS) {
      return ret;
    }
#endif // #if (INCLUDE_vTaskDelete == 1)

    return TX_SUCCESS;
}

void txfr_thread_wrapper(ULONG id)
{
    TX_THREAD *p_thread;
    txfr_task_t *p_txfr_task;

    p_thread = tx_thread_identify();

    p_txfr_task = p_thread->txfr_thread_ptr;

    p_txfr_task->p_task_func(p_txfr_task->p_task_arg);

#if (INCLUDE_vTaskDelete == 1)
    vTaskDelete(NULL);
#else
    // Returning from a task is not allowed when vTaskDelete is disabled.
    TX_FREERTOS_ASSERT_FAIL();
#endif // #if (INCLUDE_vTaskDelete == 1)
}


void *pvPortMalloc(size_t xWantedSize)
{
    return txfr_malloc(xWantedSize);
}

void vPortFree(void *pv)
{
    txfr_free(pv);

    return;
}

void vPortEnterCritical(void)
{
    portDISABLE_INTERRUPTS();
    _tx_thread_preempt_disable++;
}

void vPortExitCritical(void)
{
    if(_tx_thread_preempt_disable == 0u) {
      TX_FREERTOS_ASSERT_FAIL();
    }

    _tx_thread_preempt_disable--;

    if(_tx_thread_preempt_disable == 0u) {
      portENABLE_INTERRUPTS();
    }
}

void vTaskStartScheduler(void)
{
#if (TX_FREERTOS_AUTO_INIT == 1)
    txfr_scheduler_started = 1u;
    _tx_thread_schedule();
#else
    // Nothing to do, THREADX scheduler is already started.
#endif
}


BaseType_t xTaskGetSchedulerState(void)
{
#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_scheduler_started == 0u) {
      return taskSCHEDULER_NOT_STARTED;
    }
#endif
    if(_tx_thread_preempt_disable > 0u) {
      return taskSCHEDULER_SUSPENDED;
    } else {
      return taskSCHEDULER_RUNNING;
    }
}


void vTaskSuspendAll(void)
{
    TX_INTERRUPT_SAVE_AREA;

    TX_DISABLE;
    _tx_thread_preempt_disable++;
    TX_RESTORE;
}

BaseType_t xTaskResumeAll(void)
{
    TX_INTERRUPT_SAVE_AREA;

    TX_DISABLE;
    _tx_thread_preempt_disable--;
    TX_RESTORE;

    return pdFALSE;
}

void vTaskDelay(const TickType_t xTicksToDelay)
{
    tx_thread_sleep(xTicksToDelay);
}

TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode,
                               const char *const pcName,
                               const configSTACK_DEPTH_TYPE ulStackDepth,
                               void *const pvParameters,
                               UBaseType_t uxPriority,
                               StackType_t *const puxStackBuffer,
                               StaticTask_t *const pxTaskBuffer)
{
    UINT prio;
    UINT ret;
    ULONG stack_depth_bytes;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(pxTaskCode != NULL);
    configASSERT(ulStackDepth >= configMINIMAL_STACK_SIZE);
    configASSERT(uxPriority < configMAX_PRIORITIES);
    configASSERT(puxStackBuffer != NULL);
    configASSERT(pxTaskBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    if(ulStackDepth > (ULONG_MAX / sizeof(StackType_t))) {
      /* Integer overflow in stack depth */
      TX_FREERTOS_ASSERT_FAIL();
      return NULL;
    }
    stack_depth_bytes = ulStackDepth * sizeof(StackType_t);

    TX_MEMSET(pxTaskBuffer, 0, sizeof(*pxTaskBuffer));
    pxTaskBuffer->p_task_arg = pvParameters;
    pxTaskBuffer->p_task_func = pxTaskCode;

    ret = tx_semaphore_create(&pxTaskBuffer->notification_sem, "", 0u);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return NULL;
    }

    prio = txfr_prio_fr_to_tx(uxPriority);

    ret = tx_thread_create(&pxTaskBuffer->thread, (CHAR *)pcName, txfr_thread_wrapper, (ULONG)pvParameters,
            puxStackBuffer, stack_depth_bytes, prio, prio, 0u, TX_DONT_START);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return NULL;
    }

    pxTaskBuffer->thread.txfr_thread_ptr = pxTaskBuffer;

    ret = tx_thread_resume(&pxTaskBuffer->thread);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return NULL;
    }

    TX_DISABLE;
    g_txfr_task_count++;
    TX_RESTORE;

    return pxTaskBuffer;
}


BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,
                     const char * const pcName,
                     const configSTACK_DEPTH_TYPE usStackDepth,
                     void *pvParameters,
                     UBaseType_t uxPriority,
                     TaskHandle_t * const pxCreatedTask)
{
    void *p_stack;
    txfr_task_t *p_task;
    UINT ret;
    UINT prio;
    ULONG stack_depth_bytes;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(pvTaskCode != NULL);
    configASSERT(usStackDepth >= configMINIMAL_STACK_SIZE);
    configASSERT(uxPriority < configMAX_PRIORITIES);
    configASSERT(pxCreatedTask != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif
    if((usStackDepth > (SIZE_MAX / sizeof(StackType_t)))
      || (usStackDepth > (ULONG_MAX / sizeof(StackType_t)))) {
      /* Integer overflow in stack depth */
      return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }
    stack_depth_bytes = usStackDepth * sizeof(StackType_t);

    p_stack = txfr_malloc((size_t)stack_depth_bytes);
    if(p_stack == NULL) {
      return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }

    p_task = txfr_malloc(sizeof(txfr_task_t));
    if(p_task == NULL) {
      txfr_free(p_stack);
      return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }

    *pxCreatedTask = p_task;

    TX_MEMSET(p_task, 0, sizeof(*p_task));
    p_task->allocated = 1u;
    p_task->p_task_arg = pvParameters;
    p_task->p_task_func = pvTaskCode;

    ret = tx_semaphore_create(&p_task->notification_sem, "", 0u);
    if(ret != TX_SUCCESS) {
      txfr_free(p_stack);
      txfr_free(p_task);
      TX_FREERTOS_ASSERT_FAIL();
      return (BaseType_t)NULL;
    }

    prio = txfr_prio_fr_to_tx(uxPriority);

    ret = tx_thread_create(&p_task->thread, (CHAR *)pcName, txfr_thread_wrapper, (ULONG)pvParameters,
            p_stack, stack_depth_bytes, prio, prio, 0u, TX_DONT_START);
    if(ret != TX_SUCCESS) {
      (void)tx_semaphore_delete(&p_task->notification_sem);
      txfr_free(p_stack);
      txfr_free(p_task);
      TX_FREERTOS_ASSERT_FAIL();
      return (BaseType_t)NULL;
    }

    p_task->thread.txfr_thread_ptr = p_task;

    ret = tx_thread_resume(&p_task->thread);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
    }

    TX_DISABLE;
    g_txfr_task_count++;
    TX_RESTORE;

    return pdPASS;
}


UBaseType_t uxTaskGetNumberOfTasks(void)
{
    UBaseType_t count;
    TX_INTERRUPT_SAVE_AREA;

    TX_DISABLE;
    count = g_txfr_task_count;
    TX_RESTORE;

    return count;
}

#if (INCLUDE_vTaskDelete == 1)
void vTaskDelete(TaskHandle_t xTask)
{
    UINT ret;
    TX_THREAD *p_thread;
    txfr_task_t *p_txfr_thread;
    TX_INTERRUPT_SAVE_AREA;

    if(xTask == NULL) {
      TX_THREAD_GET_CURRENT(p_thread);
      p_txfr_thread = (txfr_task_t *)p_thread->txfr_thread_ptr;
    } else {
      p_txfr_thread = xTask;
      p_thread = &xTask->thread;
    }

    TX_DISABLE;

    p_txfr_thread->p_next = p_delete_task_head;
    p_delete_task_head = p_txfr_thread;

    _tx_thread_preempt_disable++;

    ret = tx_semaphore_put(&txfr_idle_sem);
    if(ret != TX_SUCCESS) {
      _tx_thread_preempt_disable--;
      TX_RESTORE;
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

    _tx_thread_preempt_disable--;

    TX_RESTORE;

    ret = tx_thread_terminate(p_thread);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

    return;
}
#endif


TaskHandle_t xTaskGetCurrentTaskHandle(void)
{
    TX_THREAD *p_thread;

    p_thread = tx_thread_identify();

    return p_thread->txfr_thread_ptr;
}


void vTaskSuspend(TaskHandle_t xTaskToSuspend)
{
    TX_THREAD *p_thread;
    UINT ret;

    if(xTaskToSuspend == NULL) {
      p_thread = tx_thread_identify();
    } else {
      p_thread = &xTaskToSuspend->thread;
    }

    ret = tx_thread_suspend(p_thread);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }
}


void vTaskResume(TaskHandle_t xTaskToResume)
{
    UINT ret;

    configASSERT(xTaskToResume != NULL);

    ret = tx_thread_resume(&xTaskToResume->thread);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }
}


BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
{
    configASSERT(xTaskToResume != NULL);

    vTaskResume(xTaskToResume);

    return pdFALSE;
}


BaseType_t xTaskAbortDelay(TaskHandle_t xTask)
{
    TX_THREAD *p_thread;
    UINT ret;

    configASSERT(xTask != NULL);

    p_thread = &xTask->thread;

    ret = tx_thread_wait_abort(p_thread);
    if(ret != TX_SUCCESS) {
      return pdFAIL;
    }

    return pdPASS;
}


UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask)
{
    TX_THREAD *p_thread;
    UINT priority;
    UINT ret;

    if(xTask == NULL) {
      p_thread = tx_thread_identify();
    } else {
      p_thread = &xTask->thread;
    }

    ret = tx_thread_info_get(p_thread, NULL, NULL, NULL, &priority, NULL, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    priority = txfr_prio_tx_to_fr(priority);

    return priority;
}


UBaseType_t uxTaskPriorityGetFromISR(const TaskHandle_t xTask)
{
    return uxTaskPriorityGet(xTask);
}


void vTaskPrioritySet(TaskHandle_t xTask,
                      UBaseType_t uxNewPriority)
{
    TX_THREAD *p_thread;
    UINT priority;
    UINT old_priority;
    UINT ret;

    configASSERT(uxNewPriority < configMAX_PRIORITIES);

    if(xTask == NULL) {
      p_thread = tx_thread_identify();
    } else {
      p_thread = &xTask->thread;
    }

    priority = uxNewPriority;
    priority = txfr_prio_fr_to_tx(priority);

    ret = tx_thread_priority_change(p_thread, priority, &old_priority);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

}


char *pcTaskGetName(TaskHandle_t xTaskToQuery)
{
    TX_THREAD *p_thread;
    char *p_task_name;
    UINT ret;

    if(xTaskToQuery == NULL) {
      p_thread = tx_thread_identify();
    } else {
      p_thread = &xTaskToQuery->thread;
    }

    ret = tx_thread_info_get(p_thread, &p_task_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    return p_task_name;
}


eTaskState eTaskGetState(TaskHandle_t xTask)
{
    UINT thread_state;
    eTaskState ret_state;
    TX_THREAD *p_thread;

    TX_INTERRUPT_SAVE_AREA;

    if(xTask == NULL) {
      return eInvalid;
    }

    TX_DISABLE;
    thread_state = xTask->thread.tx_thread_state;
    p_thread = &xTask->thread;
    TX_RESTORE;

    if(p_thread == tx_thread_identify()) {
      return eRunning;
    }

    switch(thread_state) {
      case TX_READY:
            ret_state = eReady;
            break;

      case TX_COMPLETED:
      case TX_TERMINATED:
            ret_state = eDeleted;
            break;

      case TX_SUSPENDED:
      case TX_SLEEP:
            ret_state = eSuspended;
            break;

      case TX_QUEUE_SUSP:
      case TX_SEMAPHORE_SUSP:
      case TX_EVENT_FLAG:
      case TX_BLOCK_MEMORY:
      case TX_BYTE_MEMORY:
      case TX_IO_DRIVER:
      case TX_FILE:
      case TX_TCP_IP:
      case TX_MUTEX_SUSP:
            ret_state = eBlocked;
            break;

      default:
            ret_state = eInvalid;
            break;
    }

    return ret_state;
}


void vTaskDelayUntil(TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement)
{
    TickType_t tick_cur;

    tick_cur = (uint16_t)tx_time_get();

    tx_thread_sleep(xTimeIncrement - (tick_cur - *pxPreviousWakeTime));

    *pxPreviousWakeTime = *pxPreviousWakeTime + xTimeIncrement;
}


BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify)
{
    configASSERT(xTaskToNotify != NULL);

    return xTaskNotify(xTaskToNotify, 0u, eIncrement);
}


void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify,
                            BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTaskToNotify != NULL);

    (void)xTaskNotify(xTaskToNotify, 0u, eIncrement);
}


uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit,
                        TickType_t xTicksToWait)
{
    TX_THREAD *p_thread;
    uint32_t val;
    UINT ret;
    UCHAR pend;
    txfr_task_t *p_task;
    UINT timeout;

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    pend = TX_FALSE;
    p_thread = tx_thread_identify();
    p_task = p_thread->txfr_thread_ptr;

    TX_INTERRUPT_SAVE_AREA;

    TX_DISABLE;

    ret = tx_semaphore_get(&p_task->notification_sem, 0u);
    if(ret == TX_SUCCESS) {
      val = p_task->task_notify_val;
      p_task->p_notify_val_ret = NULL;
      if(xClearCountOnExit != pdFALSE) {
            p_task->task_notify_val = 0u;
      } else {
            p_task->task_notify_val--;
      }
    } else {
      pend = TX_TRUE;
      p_task->p_notify_val_ret = &val;
      p_task->clear_on_pend = xClearCountOnExit;
      p_task->clear_mask = (uint32_t)-1;
    }

    TX_RESTORE;

    if(pend == TX_TRUE) {
      ret = tx_semaphore_get(&p_task->notification_sem, timeout);
      p_task->p_notify_val_ret = NULL;
      if(ret != TX_SUCCESS) {
            return 0u;
      }
    }

    return val;
}

BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry,
                           uint32_t ulBitsToClearOnExit,
                           uint32_t *pulNotificationValue,
                           TickType_t xTicksToWait)
{
    TX_INTERRUPT_SAVE_AREA;
    TX_THREAD *p_thread;
    uint32_t val;
    BaseType_t ret_val;
    UINT ret;
    UCHAR pend;
    txfr_task_t *p_task;
    UINT timeout;

    ret_val = pdPASS;

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    pend = TX_FALSE;
    p_thread = tx_thread_identify();
    p_task = p_thread->txfr_thread_ptr;

    TX_DISABLE;

    ret = tx_semaphore_get(&p_task->notification_sem, 0u);
    if(ret == TX_SUCCESS) {
      val = p_task->task_notify_val;
      p_task->p_notify_val_ret = NULL;
      if(ulBitsToClearOnExit != 0u) {
            p_task->task_notify_val &= ~ulBitsToClearOnExit;
      }
    } else {
      pend = TX_TRUE;
      p_task->p_notify_val_ret = &val;
      p_task->clear_on_pend = 1u;
      p_task->clear_mask = ulBitsToClearOnExit;
    }

    TX_RESTORE;

    if(pend == TX_TRUE) {
      ret = tx_semaphore_get(&p_task->notification_sem, timeout);
      p_task->p_notify_val_ret = NULL;
      if(ret != TX_SUCCESS) {
            return 0u;
      }
    }

    *pulNotificationValue = val;

    return ret_val;
}


BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify,
                     uint32_t ulValue,
                     eNotifyAction eAction)
{

    configASSERT(TXFR_NOTIFYACTION_VALID(eAction));

    return xTaskNotifyAndQuery(xTaskToNotify, ulValue, eAction, NULL);
}

BaseType_t xTaskNotifyFromISR(TaskHandle_t xTaskToNotify,
                              uint32_t ulValue,
                              eNotifyAction eAction,
                              BaseType_t *pxHigherPriorityTaskWoken)
{

    configASSERT(xTaskToNotify != NULL);
    configASSERT(TXFR_NOTIFYACTION_VALID(eAction));

    return xTaskNotify(xTaskToNotify, ulValue, eAction);
}

BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
                               uint32_t ulValue,
                               eNotifyAction eAction,
                               uint32_t *pulPreviousNotifyValue)
{
    UINT ret;
    UCHAR notified;
    TX_INTERRUPT_SAVE_AREA;
    BaseType_t ret_val;
    UCHAR waiting;

    configASSERT(xTaskToNotify != NULL);
    configASSERT(TXFR_NOTIFYACTION_VALID(eAction));

    TX_DISABLE;

    if(pulPreviousNotifyValue != NULL) {
      *pulPreviousNotifyValue = xTaskToNotify->task_notify_val;
    }

    waiting = TX_FALSE;
    notified = TX_FALSE;
    ret_val = pdPASS;

    if(xTaskToNotify->notification_sem.tx_semaphore_suspended_count != 0u) {
      waiting = TX_TRUE;
    }

    if(xTaskToNotify->notification_sem.tx_semaphore_count == 0u) {
      _tx_thread_preempt_disable++;

      ret = tx_semaphore_put(&xTaskToNotify->notification_sem);

      _tx_thread_preempt_disable--;

      if(ret != TX_SUCCESS) {
            TX_RESTORE;
            TX_FREERTOS_ASSERT_FAIL();
            return pdFAIL;
      }
      xTaskToNotify->task_notify_val_pend = xTaskToNotify->task_notify_val;

      notified = TX_TRUE;
    }

    switch (eAction) {
      case eNoAction:
            break;

      case eSetBits:
            xTaskToNotify->task_notify_val |= ulValue;
            break;

      case eIncrement:
            xTaskToNotify->task_notify_val++;
            break;

      case eSetValueWithOverwrite:
            xTaskToNotify->task_notify_val = ulValue;
            break;

      case eSetValueWithoutOverwrite:
            if(notified == TX_TRUE) {
                xTaskToNotify->task_notify_val = ulValue;
            } else {
                ret_val = pdFALSE;
            }
            break;

      default:
            TX_RESTORE;
            return pdFAIL;
            break;
    }

    if(waiting == TX_TRUE) {
      *xTaskToNotify->p_notify_val_ret = xTaskToNotify->task_notify_val;

      if(xTaskToNotify->clear_on_pend == TX_TRUE) {
            xTaskToNotify->task_notify_val &= ~xTaskToNotify->clear_mask;
      } else {
            xTaskToNotify->task_notify_val--;
      }
    }

    TX_RESTORE;

    _tx_thread_system_preempt_check();

    return ret_val;
}


BaseType_t xTaskNotifyAndQueryFromISR(TaskHandle_t xTaskToNotify,
                                    uint32_t ulValue,
                                    eNotifyAction eAction,
                                    uint32_t *pulPreviousNotifyValue,
                                    BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTaskToNotify != NULL);
    configASSERT(TXFR_NOTIFYACTION_VALID(eAction));


    return xTaskNotifyAndQuery(xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue);
}


BaseType_t xTaskNotifyStateClear(TaskHandle_t xTask)
{
    BaseType_t ret_val;
    UINT ret;
    TX_THREAD *p_thread;
    txfr_task_t *p_task;
    TX_INTERRUPT_SAVE_AREA;

    if(xTask == NULL) {
      p_thread = tx_thread_identify();
      p_task = p_thread->txfr_thread_ptr;
    } else {
      p_thread = &xTask->thread;
      p_task = xTask;
    }

    TX_DISABLE;

    if(p_task->notification_sem.tx_semaphore_suspended_count != 0u) {
      ret_val = pdTRUE;
    } else {
      ret_val = pdFALSE;
    }

    ret = tx_semaphore_get(&p_task->notification_sem, 0u);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      TX_FREERTOS_ASSERT_FAIL();
      return pdFALSE;
    }

    TX_RESTORE;

    return ret_val;
}


uint32_t ulTaskNotifyValueClear(TaskHandle_t xTask,
                              uint32_t ulBitsToClear)
{
    BaseType_t ret_val;
    TX_THREAD *p_thread;
    txfr_task_t *p_task;
    TX_INTERRUPT_SAVE_AREA;

    if(xTask == NULL) {
      p_thread = tx_thread_identify();
      p_task = p_thread->txfr_thread_ptr;
    } else {
      p_thread = &xTask->thread;
      p_task = xTask;
    }

    TX_DISABLE;

    ret_val = p_task->task_notify_val;

    p_task->task_notify_val &= ~ulBitsToClear;

    TX_RESTORE;

    return ret_val;
}


SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
                                           UBaseType_t uxInitialCount)
{
    txfr_sem_t *p_sem;
    UINT ret;

    configASSERT(uxMaxCount != 0u);
    configASSERT(uxInitialCount <= uxMaxCount);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    p_sem = txfr_malloc(sizeof(txfr_sem_t));
    if(p_sem == NULL) {
      return NULL;
    }

    TX_MEMSET(p_sem, 0, sizeof(*p_sem));
    p_sem->max_count = uxMaxCount;
    p_sem->allocated = 1u;
    p_sem->is_mutex = 0u;

    ret = tx_semaphore_create(&p_sem->sem, "", uxInitialCount);
    if(ret != TX_SUCCESS) {
      txfr_free(p_sem);
      return NULL;
    }

    return p_sem;
}

SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,
                                                 UBaseType_t uxInitialCount,
                                                 StaticSemaphore_t *pxSemaphoreBuffer)
{
    UINT ret;

    configASSERT(uxMaxCount != 0u);
    configASSERT(uxInitialCount <= uxMaxCount);
    configASSERT(pxSemaphoreBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    TX_MEMSET(pxSemaphoreBuffer, 0, sizeof(*pxSemaphoreBuffer));
    pxSemaphoreBuffer->max_count = uxMaxCount;
    pxSemaphoreBuffer->allocated = 0u;
    pxSemaphoreBuffer->is_mutex = 0u;

    ret = tx_semaphore_create(&pxSemaphoreBuffer->sem, "", uxInitialCount);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxSemaphoreBuffer;
}


SemaphoreHandle_t xSemaphoreCreateBinary(void)
{
    return xSemaphoreCreateCounting(1u, 0u);
}


SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer)
{
    configASSERT(pxSemaphoreBuffer != NULL);

    return xSemaphoreCreateCountingStatic(1u, 0u, pxSemaphoreBuffer);
}


SemaphoreHandle_t xSemaphoreCreateMutex(void)
{
    txfr_sem_t *p_sem;
    UINT ret;

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    p_sem = txfr_malloc(sizeof(txfr_sem_t));
    if(p_sem == NULL) {
      return NULL;
    }

    TX_MEMSET(p_sem, 0, sizeof(*p_sem));
    p_sem->max_count = 1u;
    p_sem->allocated = 1u;
    p_sem->is_mutex = 1u;

    ret = tx_mutex_create(&p_sem->mutex, "", TX_NO_INHERIT);
    if(ret != TX_SUCCESS) {
      txfr_free(p_sem);
      return NULL;
    }

    return p_sem;
}


SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer)
{
    UINT ret;

    configASSERT(pxMutexBuffer != NULL);

    TX_MEMSET(pxMutexBuffer, 0, sizeof(*pxMutexBuffer));
    pxMutexBuffer->max_count = 1u;
    pxMutexBuffer->allocated = 0u;
    pxMutexBuffer->is_mutex = 1u;

    ret = tx_mutex_create(&pxMutexBuffer->mutex, "", TX_NO_INHERIT);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxMutexBuffer;
}


SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void)
{
    txfr_sem_t *p_sem;
    UINT ret;

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    p_sem = txfr_malloc(sizeof(txfr_sem_t));
    if(p_sem == NULL) {
      return NULL;
    }

    TX_MEMSET(p_sem, 0, sizeof(*p_sem));
    p_sem->max_count = 1u;
    p_sem->allocated = 1u;
    p_sem->is_mutex = 1u;

    ret = tx_mutex_create(&p_sem->mutex, "", TX_INHERIT);
    if(ret != TX_SUCCESS) {
      txfr_free(p_sem);
      return NULL;
    }

    return p_sem;
}


SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(StaticSemaphore_t *pxMutexBuffer)
{
    UINT ret;

    configASSERT(pxMutexBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    TX_MEMSET(pxMutexBuffer, 0, sizeof(*pxMutexBuffer));
    pxMutexBuffer->max_count = 1u;
    pxMutexBuffer->allocated = 0u;
    pxMutexBuffer->is_mutex = 1u;

    ret = tx_mutex_create(&pxMutexBuffer->mutex, "", TX_INHERIT);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxMutexBuffer;
}

void vSemaphoreDelete(SemaphoreHandle_t xSemaphore)
{
    UINT ret;

    configASSERT(xSemaphore != NULL);

    if(xSemaphore->is_mutex == 0u) {
      ret = tx_semaphore_delete(&xSemaphore->sem);
    } else {
      ret = tx_mutex_delete(&xSemaphore->mutex);
    }

    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

    if(xSemaphore->allocated == 1u) {
      vPortFree(xSemaphore);
    }
}


BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)
{
    UINT timeout;
    UINT ret;

    configASSERT(xSemaphore != NULL);

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    if(xSemaphore->is_mutex == 1u) {
      if(xSemaphore->mutex.tx_mutex_owner == tx_thread_identify()) {
            return pdFALSE;
      }
      ret = tx_mutex_get(&xSemaphore->mutex, timeout);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }
    } else {
      ret = tx_semaphore_get(&xSemaphore->sem, timeout);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }
    }

    return pdTRUE;
}


BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken)
{
    UINT ret;

    configASSERT(xSemaphore != NULL);

    if(xSemaphore->is_mutex == 1u) {
      return pdFALSE;
    } else {
      ret = tx_semaphore_get(&xSemaphore->sem, 0u);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }
    }

    return pdTRUE;
}


BaseType_t xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex, TickType_t xTicksToWait)
{
    UINT timeout;
    UINT ret;

    configASSERT(xMutex != NULL);

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    if(xMutex->is_mutex == 1u) {
      ret = tx_mutex_get(&xMutex->mutex, timeout);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }
    } else {
      ret = tx_semaphore_get(&xMutex->sem, timeout);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }
    }

    return pdTRUE;
}


BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore)
{
    TX_INTERRUPT_SAVE_AREA
    UINT ret;

    configASSERT(xSemaphore != NULL);

    if(xSemaphore->is_mutex == 1u) {
      ret = tx_mutex_put(&xSemaphore->mutex);
      if(ret != TX_SUCCESS) {
            return pdFALSE;
      }

      return pdTRUE;
    }

    TX_DISABLE;
    _tx_thread_preempt_disable++;

    if(xSemaphore->sem.tx_semaphore_count >= xSemaphore->max_count) {
      /* Maximum semaphore count reached return failure. */
      _tx_thread_preempt_disable--;
         TX_RESTORE
      return pdFALSE;
    }

    ret = tx_semaphore_put(&xSemaphore->sem);
    if(ret != TX_SUCCESS) {
      _tx_thread_preempt_disable--;
      TX_RESTORE;
      return pdFALSE;
    }

    if(xSemaphore->p_set != NULL) {
      // To prevent deadlocks don't wait when posting on a queue set.
      ret = tx_queue_send(&xSemaphore->p_set->queue, &xSemaphore, TX_NO_WAIT);
      if((ret != TX_SUCCESS) && (ret != TX_QUEUE_FULL)) {
            // Fatal error, queue full errors are ignored on purpose to match the original behaviour.
            _tx_thread_preempt_disable--;
            TX_RESTORE;
            TX_FREERTOS_ASSERT_FAIL();
            return pdFALSE;
      }
    }

    _tx_thread_preempt_disable--;
    TX_RESTORE;

    _tx_thread_system_preempt_check();

    return pdTRUE;
}

BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken)
{

    configASSERT(xSemaphore != NULL);

    return xSemaphoreGive(xSemaphore);
}

BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex)
{

    configASSERT(xMutex != NULL);

    return xSemaphoreGive(xMutex);
}

UBaseType_t uxSemaphoreGetCount(SemaphoreHandle_t xSemaphore)
{
    UINT ret;
    ULONG count;

    configASSERT(xSemaphore != NULL);

    ret = tx_semaphore_info_get(&xSemaphore->sem, NULL, &count, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    return count;
}

TaskHandle_t xSemaphoreGetMutexHolder(SemaphoreHandle_t xMutex)
{
    configASSERT(xMutex != NULL);

    return xMutex->mutex.tx_mutex_owner->txfr_thread_ptr;
}


TaskHandle_t xSemaphoreGetMutexHolderFromISR(SemaphoreHandle_t xMutex)
{
    return xSemaphoreGetMutexHolder(xMutex);
}


TickType_t xTaskGetTickCount(void)
{
    return tx_time_get();
}

TickType_t xTaskGetTickCountFromISR(void)
{
    return tx_time_get();
}


QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,
                                 UBaseType_t uxItemSize,
                                 uint8_t *pucQueueStorageBuffer,
                                 StaticQueue_t *pxQueueBuffer)
{
    UINT ret;

    configASSERT(uxQueueLength != 0u);
    configASSERT(uxItemSize >= sizeof(UINT));
    configASSERT(pucQueueStorageBuffer != NULL);
    configASSERT(pxQueueBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    TX_MEMSET(pucQueueStorageBuffer, 0, uxQueueLength * uxItemSize);
    TX_MEMSET(pxQueueBuffer, 0, sizeof(*pxQueueBuffer));
    pxQueueBuffer->allocated = 0u;
    pxQueueBuffer->p_mem = pucQueueStorageBuffer;
    pxQueueBuffer->id = TX_QUEUE_ID;

    pxQueueBuffer->p_write = (uint8_t *)pucQueueStorageBuffer;
    pxQueueBuffer->p_read = (uint8_t *)pucQueueStorageBuffer;
    pxQueueBuffer->msg_size = uxItemSize;
    pxQueueBuffer->queue_length = uxQueueLength;

    ret = tx_semaphore_create(&pxQueueBuffer->read_sem, "", 0u);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    ret = tx_semaphore_create(&pxQueueBuffer->write_sem, "", uxQueueLength);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxQueueBuffer;
}


QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize)
{
    txfr_queue_t *p_queue;
    void *p_mem;
    size_t mem_size;
    UINT ret;

    configASSERT(uxQueueLength != 0u);
    configASSERT(uxItemSize >= sizeof(UINT));

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    if ((uxQueueLength > (SIZE_MAX / uxItemSize)) ||
      (uxQueueLength > (ULONG_MAX / uxItemSize))) {

      /* Integer overflow in queue size */
      return NULL;
    }

    p_queue = txfr_malloc(sizeof(txfr_queue_t));
    if(p_queue == NULL) {
      return NULL;
    }

    mem_size = uxQueueLength*(uxItemSize);

    p_mem = txfr_malloc(mem_size);
    if(p_mem == NULL) {
      txfr_free(p_queue);
      return NULL;
    }

    TX_MEMSET(p_mem, 0, mem_size);
    TX_MEMSET(p_queue, 0, sizeof(*p_queue));
    p_queue->allocated = 1u;
    p_queue->p_mem = p_mem;
    p_queue->id = TX_QUEUE_ID;

    p_queue->p_write = (uint8_t *)p_mem;
    p_queue->p_read = (uint8_t *)p_mem;
    p_queue->msg_size = uxItemSize;
    p_queue->queue_length = uxQueueLength;

    ret = tx_semaphore_create(&p_queue->read_sem, "", 0u);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    ret = tx_semaphore_create(&p_queue->write_sem, "", uxQueueLength);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return p_queue;
}

void vQueueDelete(QueueHandle_t xQueue)
{
    UINT ret;

    configASSERT(xQueue != NULL);

    ret = tx_semaphore_delete(&xQueue->read_sem);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
    }

    ret = tx_semaphore_delete(&xQueue->write_sem);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
    }

    if(xQueue->allocated == 1u) {
      vPortFree(xQueue->p_mem);
      vPortFree(xQueue);
    }
}

BaseType_t xQueueSend(QueueHandle_t xQueue,
                      const void *pvItemToQueue,
                      TickType_t xTicksToWait)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT timeout;
    UINT ret;

    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    // Wait for space to be available on the queue.
    ret = tx_semaphore_get(&xQueue->write_sem, timeout);
    if(ret != TX_SUCCESS) {
      return pdFALSE;
    }

    // Enqueue the message.
    TX_DISABLE;
    memcpy(xQueue->p_write, pvItemToQueue, xQueue->msg_size);
    if(xQueue->p_write >= (xQueue->p_mem + (xQueue->msg_size * (xQueue->queue_length - 1u)))) {
      xQueue->p_write = xQueue->p_mem;
    } else {
      xQueue->p_write += xQueue->msg_size;
    }
    TX_RESTORE;

    // Signal that there is an additional message available on the queue.
    ret = tx_semaphore_put(&xQueue->read_sem);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return pdFALSE;
    }

    if(xQueue->p_set != NULL) {
      // To prevent deadlocks don't wait when posting on a queue set.
      ret = tx_queue_send(&xQueue->p_set->queue, &xQueue, TX_NO_WAIT);
      if((ret != TX_SUCCESS) && (ret != TX_QUEUE_FULL)) {
            // Fatal error, queue full errors are ignored on purpose to match the original behaviour.
            TX_FREERTOS_ASSERT_FAIL();
            return pdFALSE;
      }

    }

    return pdPASS;
}

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,
                           const void * pvItemToQueue,
                           BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    return xQueueSend(xQueue, pvItemToQueue, 0u);
}

BaseType_t xQueueSendToBack(QueueHandle_t xQueue,
                            const void * pvItemToQueue,
                            TickType_t xTicksToWait)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
}

BaseType_t xQueueSendToBackFromISR(QueueHandle_t xQueue,
                           const void * pvItemToQueue,
                           BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    return xQueueSend(xQueue, pvItemToQueue, 0u);
}

BaseType_t xQueueSendToFront(QueueHandle_t xQueue,
                           const void *pvItemToQueue,
                           TickType_t xTicksToWait)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT timeout;
    UINT ret;
    // TODO-

    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    if(xQueue->p_set != NULL) {
      TX_DISABLE;
      _tx_thread_preempt_disable++;
    }

    // Wait for space to be available on the queue.
    ret = tx_semaphore_get(&xQueue->write_sem, timeout);
    if(ret != TX_SUCCESS) {
      return pdFALSE;
    }

    // Enqueue the message at the front.
    TX_DISABLE;
    // Push back the read pointer.
    if(xQueue->p_read == xQueue->p_mem) {
      xQueue->p_read = xQueue->p_mem + (xQueue->msg_size * (xQueue->queue_length - 1u));
    } else {
      xQueue->p_read -= xQueue->msg_size;
    }

    memcpy(xQueue->p_read, pvItemToQueue, xQueue->msg_size);
    TX_RESTORE;

    // Signal that there is an additional message available on the queue.
    ret = tx_semaphore_put(&xQueue->read_sem);
    if(ret != TX_SUCCESS) {
      if(xQueue->p_set != NULL) {
            _tx_thread_preempt_disable--;
            TX_RESTORE;
      }
      TX_FREERTOS_ASSERT_FAIL();
      return pdFALSE;
    }

    if(xQueue->p_set != NULL) {
      // To prevent deadlocks don't wait when posting on a queue set.
      ret = tx_queue_send(&xQueue->p_set->queue, &xQueue, TX_NO_WAIT);
      if((ret != TX_SUCCESS) && (ret != TX_QUEUE_FULL)) {
            // Fatal error, queue full errors are ignored on purpose to match the original behaviour.
            _tx_thread_preempt_disable--;
            TX_RESTORE;
            TX_FREERTOS_ASSERT_FAIL();
            return pdFALSE;
      }

      TX_RESTORE;
      _tx_thread_preempt_disable--;

      _tx_thread_system_preempt_check();
    }

    return pdPASS;
}

BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,
                           const void * pvItemToQueue,
                           BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    return xQueueSendToFront(xQueue, pvItemToQueue, 0u);
}

BaseType_t xQueueReceive(QueueHandle_t xQueue,
                         void *pvBuffer,
                         TickType_t xTicksToWait)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT timeout;
    UINT ret;

    configASSERT(xQueue != NULL);
    configASSERT(pvBuffer != NULL);

    if(xTicksToWait == portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    // Wait for a message to be available on the queue.
    ret = tx_semaphore_get(&xQueue->read_sem, timeout);
    if(ret != TX_SUCCESS) {
      return pdFAIL;
    }

    // Retrieve the message.
    TX_DISABLE
    memcpy(pvBuffer, xQueue->p_read, xQueue->msg_size);
    if(xQueue->p_read >= (xQueue->p_mem + (xQueue->msg_size * (xQueue->queue_length - 1u)))) {
      xQueue->p_read = xQueue->p_mem;
    } else {
      xQueue->p_read += xQueue->msg_size;
    }
    TX_RESTORE

    // Signal that there's additional space available on the queue.
    ret = tx_semaphore_put(&xQueue->write_sem);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return pdFALSE;
    }

    return pdPASS;
}

BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue,
                              void *pvBuffer,
                              BaseType_t *pxHigherPriorityTaskWoken)
{
    BaseType_t ret;

    configASSERT(xQueue != NULL);
    configASSERT(pvBuffer != NULL);

    ret = xQueueReceive(xQueue, pvBuffer, 0u);

    return ret;
}

BaseType_t xQueuePeek(QueueHandle_t xQueue,
                      void *pvBuffer,
                      TickType_t xTicksToWait)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT timeout;
    UINT ret;

    configASSERT(xQueue != NULL);
    configASSERT(pvBuffer != NULL);

    if(xTicksToWait ==portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    // Wait for a message to be available on the queue.
    ret = tx_semaphore_get(&xQueue->read_sem, timeout);
    if(ret != TX_SUCCESS) {
      return pdFAIL;
    }

    // Retrieve the message.
    TX_DISABLE;
    _tx_thread_preempt_disable++;

    memcpy(pvBuffer, xQueue->p_read, xQueue->msg_size);

    // Restore the original space on the queue.
    ret = tx_semaphore_put(&xQueue->read_sem);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return pdFALSE;
    }

    _tx_thread_preempt_disable--;
    TX_RESTORE;

    return pdPASS;
}

BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue,
                           void *pvBuffer)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvBuffer != NULL);

    return xQueuePeek(xQueue, pvBuffer, 0u);
}

UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue)
{
    ULONG count;
    UINT ret;

    configASSERT(xQueue != NULL);

    ret = tx_semaphore_info_get(&xQueue->read_sem, NULL, &count, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    return count;
}

UBaseType_t uxQueueMessagesWaitingFromISR(QueueHandle_t xQueue)
{
    configASSERT(xQueue != NULL);

    return uxQueueMessagesWaiting(xQueue);
}

UBaseType_t uxQueueSpacesAvailable(QueueHandle_t xQueue)
{
    ULONG count;
    UINT ret;

    configASSERT(xQueue != NULL);

    ret = tx_semaphore_info_get(&xQueue->write_sem, NULL, &count, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    return count;
}

BaseType_t xQueueIsQueueEmptyFromISR(const QueueHandle_t xQueue)
{
    ULONG count;
    UINT ret;

    configASSERT(xQueue != NULL);

    ret = tx_semaphore_info_get(&xQueue->read_sem, NULL, &count, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    if(count == 0u) {
      return pdTRUE;
    } else {
      return pdFALSE;
    }
}

BaseType_t xQueueIsQueueFullFromISR(const QueueHandle_t xQueue)
{
    ULONG count;
    UINT ret;

    configASSERT(xQueue != NULL);

    ret = tx_semaphore_info_get(&xQueue->write_sem, NULL, &count, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0;
    }

    if(count == 0u) {
      return pdTRUE;
    } else {
      return pdFALSE;
    }
}


BaseType_t xQueueReset(QueueHandle_t xQueue)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT ret;
    UINT write_post;

    configASSERT(xQueue != NULL);

    write_post = 0u;
    TX_DISABLE;
    _tx_thread_preempt_disable++;

    // Reset pointers.
    xQueue->p_write = xQueue->p_mem;
    xQueue->p_read = xQueue->p_mem;

    // Reset read semaphore.
    xQueue->read_sem.tx_semaphore_count = 0u;

    // Reset write semaphore.
    if(xQueue->write_sem.tx_semaphore_count != xQueue->queue_length) {
      write_post = 1u;
      xQueue->write_sem.tx_semaphore_count = xQueue->queue_length - 1u;
    }

    _tx_thread_preempt_disable--;
    TX_RESTORE;

    if(write_post == 1u) {
      // Signal that there's space available on the queue in case a writer was waiting before the reset.
      ret = tx_semaphore_put(&xQueue->write_sem);
      if(ret != TX_SUCCESS) {
            TX_FREERTOS_ASSERT_FAIL();
            return pdFALSE;
      }
    } else {
      _tx_thread_system_preempt_check();
    }

    return pdPASS;
}


BaseType_t xQueueOverwrite(QueueHandle_t xQueue,
                           const void * pvItemToQueue)
{
    TX_INTERRUPT_SAVE_AREA;
    UINT ret;
    UINT read_post;
    uint8_t *p_write_temp;

    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    read_post = 0u;
    TX_DISABLE;

    if(xQueue->read_sem.tx_semaphore_count != 0u) {
      // Go back one message.
      p_write_temp = xQueue->p_write;
      if(p_write_temp == xQueue->p_mem) {
            p_write_temp = (xQueue->p_mem + (xQueue->msg_size * (xQueue->queue_length - 1u)));
      } else {
            p_write_temp -= xQueue->msg_size;
      }

      memcpy(p_write_temp, pvItemToQueue, xQueue->msg_size);
    } else {
      memcpy(xQueue->p_write, pvItemToQueue, xQueue->msg_size);
      if(xQueue->p_write >= (xQueue->p_mem + (xQueue->msg_size * (xQueue->queue_length - 1u)))) {
            xQueue->p_write = xQueue->p_mem;
      } else {
            xQueue->p_write += xQueue->msg_size;
      }
      read_post = 1u;
    }

    TX_RESTORE;

    if(read_post == 1u) {
      // Signal that there is an additional message available on the queue.
      ret = tx_semaphore_put(&xQueue->read_sem);
      if(ret != TX_SUCCESS) {
            TX_FREERTOS_ASSERT_FAIL();
            return pdFALSE;
      }
    }

    return pdPASS;
}


BaseType_t xQueueOverwriteFromISR(QueueHandle_t xQueue,
                                  const void * pvItemToQueue,
                                  BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xQueue != NULL);
    configASSERT(pvItemToQueue != NULL);

    return xQueueOverwrite(xQueue, pvItemToQueue);
}


EventGroupHandle_t xEventGroupCreate(void)
{
    txfr_event_t *p_event;
    UINT ret;

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    p_event = txfr_malloc(sizeof(txfr_event_t));
    if(p_event == NULL) {
      return NULL;
    }

    TX_MEMSET(p_event, 0, sizeof(*p_event));
    p_event->allocated = 1u;

    ret = tx_event_flags_create(&p_event->event, "");
    if(ret != TX_SUCCESS) {
      txfr_free(p_event);
      return NULL;
    }

    return p_event;
}

EventGroupHandle_t xEventGroupCreateStatic(StaticEventGroup_t *pxEventGroupBuffer)
{
    UINT ret;

    configASSERT(pxEventGroupBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    TX_MEMSET(pxEventGroupBuffer, 0, sizeof(*pxEventGroupBuffer));
    pxEventGroupBuffer->allocated = 0u;

    ret = tx_event_flags_create(&pxEventGroupBuffer->event, "");
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxEventGroupBuffer;
}

void vEventGroupDelete(EventGroupHandle_t xEventGroup)
{
    UINT ret;

    configASSERT(xEventGroup != NULL);

    ret = tx_event_flags_delete(&xEventGroup->event);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return;
    }

    if(xEventGroup->allocated == 1u) {
      vPortFree(xEventGroup);
    }
}

EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup,
                              const EventBits_t uxBitsToWaitFor,
                              const BaseType_t xClearOnExit,
                              const BaseType_t xWaitForAllBits,
                              TickType_t xTicksToWait)
{
    ULONG bits;
    UINT timeout;
    UINT ret;
    UINT get_option;

    configASSERT(xEventGroup != NULL);

    if(xTicksToWait == portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    if(xWaitForAllBits == pdFALSE) {
      if(xClearOnExit == pdFALSE) {
            get_option = TX_OR;
      } else {
            get_option = TX_OR_CLEAR;
      }
    } else {
      if(xClearOnExit == pdFALSE) {
            get_option = TX_AND;
      } else {
            get_option = TX_AND_CLEAR;
      }
    }

    ret = tx_event_flags_get(&xEventGroup->event, uxBitsToWaitFor, get_option, &bits, timeout);
    if(ret != TX_SUCCESS) {
      return 0;
    }

    return bits;
}

EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
                               const EventBits_t uxBitsToSet)
{
    UINT ret;
    ULONG bits;

    configASSERT(xEventGroup != NULL);

    ret = tx_event_flags_set(&xEventGroup->event, uxBitsToSet, TX_OR);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    ret = tx_event_flags_info_get(&xEventGroup->event, NULL, &bits, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    return bits;
}

BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup,
                                     const EventBits_t uxBitsToSet,
                                     BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xEventGroup != NULL);

    return xEventGroupSetBits(xEventGroup, uxBitsToSet);
}

EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToClear)
{
    UINT ret;
    ULONG bits;
    ULONG bits_before;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xEventGroup != NULL);

    TX_DISABLE;

    ret = tx_event_flags_info_get(&xEventGroup->event, NULL, &bits_before, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    bits = uxBitsToClear;
    ret = tx_event_flags_set(&xEventGroup->event, ~bits, TX_AND);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    TX_RESTORE;

    return bits_before;
}

BaseType_t xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup,
                                       const EventBits_t uxBitsToClear)
{
    configASSERT(xEventGroup != NULL);

    return xEventGroupClearBits(xEventGroup, uxBitsToClear);
}

EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
{
    UINT ret;
    ULONG bits;

    configASSERT(xEventGroup != NULL);

    ret = tx_event_flags_info_get(&xEventGroup->event, NULL, &bits, NULL, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    return bits;
}


EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup)
{
    configASSERT(xEventGroup != NULL);

    return xEventGroupGetBits(xEventGroup);
}


void txfr_timer_callback_wrapper(ULONG id)
{
    txfr_timer_t *p_timer;

    p_timer = (txfr_timer_t *)id;

    if(p_timer == NULL) {
      TX_FREERTOS_ASSERT_FAIL();
    }

    p_timer->callback(p_timer);
}


TimerHandle_t xTimerCreate(const char * const pcTimerName,
                           const TickType_t xTimerPeriod,
                           const UBaseType_t uxAutoReload,
                           void * const pvTimerID,
                           TimerCallbackFunction_t pxCallbackFunction)
{
    txfr_timer_t *p_timer;
    UINT ret;
    ULONG resch_ticks;

    configASSERT(xTimerPeriod != 0u);
    configASSERT(pxCallbackFunction != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    p_timer = txfr_malloc(sizeof(txfr_timer_t));
    if(p_timer == NULL) {
      return NULL;
    }

    TX_MEMSET(p_timer, 0, sizeof(*p_timer));
    p_timer->allocated = 1u;
    p_timer->period = xTimerPeriod;
    p_timer->id = pvTimerID;
    p_timer->callback = pxCallbackFunction;

    if(uxAutoReload != pdFALSE) {
      resch_ticks = xTimerPeriod;
      p_timer->one_shot = 1u;
    } else {
      p_timer->one_shot = 0u;
      resch_ticks = 0u;
    }

    ret = tx_timer_create(&p_timer->timer, (char *)pcTimerName, txfr_timer_callback_wrapper, (ULONG)p_timer, xTimerPeriod, resch_ticks, TX_NO_ACTIVATE);
    if(ret != TX_SUCCESS) {
      txfr_free(p_timer);
      return NULL;
    }

    return p_timer;
}

TimerHandle_t xTimerCreateStatic(const char * const pcTimerName,
                                 const TickType_t xTimerPeriod,
                                 const UBaseType_t uxAutoReload,
                                 void * const pvTimerID,
                                 TimerCallbackFunction_t pxCallbackFunction,
                                 StaticTimer_t *pxTimerBuffer)
{
    UINT ret;
    ULONG resch_ticks;

    configASSERT(xTimerPeriod != 0u);
    configASSERT(pxCallbackFunction != NULL);
    configASSERT(pxTimerBuffer != NULL);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    TX_MEMSET(pxTimerBuffer, 0, sizeof(*pxTimerBuffer));
    pxTimerBuffer->allocated = 0u;
    pxTimerBuffer->period = xTimerPeriod;
    pxTimerBuffer->id = pvTimerID;
    pxTimerBuffer->callback = pxCallbackFunction;

    if(uxAutoReload != pdFALSE) {
      resch_ticks = xTimerPeriod;
    } else {
      resch_ticks = 0u;
    }

    ret = tx_timer_create(&pxTimerBuffer->timer, (char *)pcTimerName, txfr_timer_callback_wrapper, (ULONG)pxTimerBuffer, xTimerPeriod, resch_ticks, TX_NO_ACTIVATE);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return pxTimerBuffer;
}


BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime)
{
    UINT ret;

    configASSERT(xTimer != NULL);

    ret = tx_timer_delete(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return pdFAIL;
    }

    if(xTimer->allocated == 1u) {
      vPortFree(xTimer);
    }

    return pdPASS;
}


BaseType_t xTimerIsTimerActive(TimerHandle_t xTimer)
{
    UINT ret;
    UINT is_active;

    configASSERT(xTimer != NULL);

    ret = tx_timer_info_get(&xTimer->timer, NULL, &is_active, NULL, NULL, NULL);
    if(ret !=TX_SUCCESS) {
      return pdFALSE;
    }

    if(is_active == TX_TRUE) {
      return pdTRUE;
    } else {
      return pdFALSE;
    }
}


BaseType_t xTimerStart(TimerHandle_t xTimer,
                     TickType_t xBlockTime)
{
    UINT ret;

    configASSERT(xTimer != NULL);

    ret = tx_timer_activate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      return pdFAIL;
    }

    return pdPASS;
}


BaseType_t xTimerStop(TimerHandle_t xTimer,
                      TickType_t xBlockTime)
{
    UINT ret;

    configASSERT(xTimer != NULL);

    ret = tx_timer_deactivate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      return pdFAIL;
    }

    return pdPASS;
}


BaseType_t xTimerChangePeriod(TimerHandle_t xTimer,
                              TickType_t xNewPeriod,
                              TickType_t xBlockTime)
{
    UINT ret;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xTimer != NULL);
    configASSERT(xNewPeriod != 0u);

    TX_DISABLE;

    ret = tx_timer_deactivate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    if(xTimer->one_shot != 0u) {
      ret = tx_timer_change(&xTimer->timer, xNewPeriod, xNewPeriod);
    } else {
      ret = tx_timer_change(&xTimer->timer, xNewPeriod, 0u);
    }
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    ret = tx_timer_activate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    TX_RESTORE;

    return pdPASS;
}


BaseType_t xTimerReset(TimerHandle_t xTimer,
                     TickType_t xBlockTime)
{
    UINT ret;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xTimer != NULL);

    TX_DISABLE;

    ret = tx_timer_deactivate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    if(xTimer->one_shot != 0u) {
      ret = tx_timer_change(&xTimer->timer, xTimer->period, xTimer->period);
    } else {
      ret = tx_timer_change(&xTimer->timer, xTimer->period, 0u);
    }
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    ret = tx_timer_activate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return pdFAIL;
    }

    TX_RESTORE;

    return pdPASS;
}


BaseType_t xTimerStartFromISR(TimerHandle_t xTimer,
                              BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTimer != NULL);

    return xTimerStart(xTimer, 0u);
}


BaseType_t xTimerStopFromISR(TimerHandle_t xTimer,
                           BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTimer != NULL);

    return xTimerStop(xTimer, 0u);
}


BaseType_t xTimerChangePeriodFromISR(TimerHandle_t xTimer,
                                     TickType_t xNewPeriod,
                                     BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTimer != NULL);
    configASSERT(xNewPeriod != 0u);

    return xTimerChangePeriod(xTimer, xNewPeriod, 0u);
}


BaseType_t xTimerResetFromISR(TimerHandle_t xTimer,
                              BaseType_t *pxHigherPriorityTaskWoken)
{
    configASSERT(xTimer != NULL);

    return xTimerReset(xTimer, 0u);
}


void *pvTimerGetTimerID(TimerHandle_t xTimer)
{
    TX_INTERRUPT_SAVE_AREA;
    void *p_id;

    configASSERT(xTimer != NULL);

    TX_DISABLE;
    p_id = xTimer->id;
    TX_RESTORE;

    return p_id;
}

void vTimerSetTimerID(TimerHandle_t xTimer, void *pvNewID)
{
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xTimer != NULL);

    TX_DISABLE;
    xTimer->id = pvNewID;
    TX_RESTORE;

    return;
}

void vTimerSetReloadMode(TimerHandle_t xTimer,
                         const UBaseType_t uxAutoReload)
{
    UINT ret;
    TX_INTERRUPT_SAVE_AREA;
    ULONG left;

    configASSERT(xTimer != NULL);

    TX_DISABLE;

    ret = tx_timer_deactivate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return;
    }

    left = xTimer->timer.tx_timer_internal.tx_timer_internal_remaining_ticks;

    if(uxAutoReload != pdFALSE) {
      ret = tx_timer_change(&xTimer->timer, left, xTimer->period);
    } else {
      ret = tx_timer_change(&xTimer->timer, left, 0u);
    }
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return;
    }

    ret = tx_timer_activate(&xTimer->timer);
    if(ret != TX_SUCCESS) {
      TX_RESTORE;
      return;
    }

    TX_RESTORE;

    return;
}


const char * pcTimerGetName(TimerHandle_t xTimer)
{
    configASSERT(xTimer != NULL);

    return (const char *)xTimer->timer.tx_timer_name;
}


TickType_t xTimerGetPeriod(TimerHandle_t xTimer)
{
    TX_INTERRUPT_SAVE_AREA;
    TickType_t period;

    configASSERT(xTimer != NULL);

    TX_DISABLE;

    period = xTimer->period;

    TX_RESTORE;

    return period;
}


TickType_t xTimerGetExpiryTime(TimerHandle_t xTimer)
{
    TX_INTERRUPT_SAVE_AREA;
    ULONG time_tx;
    TickType_t time;
    UINT ret;

    configASSERT(xTimer != NULL);

    TX_DISABLE;

    ret = tx_timer_info_get(&xTimer->timer, NULL, NULL, &time_tx, NULL, NULL);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return 0u;
    }

    time = (TickType_t)(tx_time_get() + time_tx);

    TX_RESTORE;

    return time;
}


UBaseType_t uxTimerGetReloadMode(TimerHandle_t xTimer)
{
    TX_INTERRUPT_SAVE_AREA;
    UBaseType_t type;

    configASSERT(xTimer != NULL);

    TX_DISABLE;

    if(xTimer->one_shot == 0u) {
      type = pdTRUE;
    } else {
      type = pdFALSE;
    }

    TX_RESTORE;

    return type;
}


QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength)
{
    txfr_queueset_t *p_set;
    void *p_mem;
    ULONG queue_size;
    UINT ret;

    configASSERT(uxEventQueueLength != 0u);

#if (TX_FREERTOS_AUTO_INIT == 1)
    if(txfr_initialized != 1u) {
      tx_freertos_auto_init();
    }
#endif

    if ((uxEventQueueLength > (SIZE_MAX / sizeof(void *))) ||
      (uxEventQueueLength > (ULONG_MAX / sizeof(void *)))) {

      /* Integer overflow in queue size */
      return NULL;
    }

    p_set = txfr_malloc(sizeof(txfr_queueset_t));
    if(p_set == NULL) {
      return NULL;
    }

    queue_size = sizeof(void *) * uxEventQueueLength;
    p_mem = txfr_malloc(queue_size);
    if(p_mem == NULL) {
      txfr_free(p_set);
      return NULL;
    }

    ret = tx_queue_create(&p_set->queue, "", sizeof(void *) / sizeof(UINT), p_mem, queue_size);
    if(ret != TX_SUCCESS) {
      TX_FREERTOS_ASSERT_FAIL();
      return NULL;
    }

    return p_set;
}


BaseType_t xQueueAddToSet(QueueSetMemberHandle_t xQueueOrSemaphore,
                        QueueSetHandle_t xQueueSet)
{
    txfr_sem_t *p_sem;
    txfr_queue_t *p_queue;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xQueueOrSemaphore != NULL);
    configASSERT(xQueueSet != NULL);

    TX_DISABLE;
    if(*((ULONG *)(xQueueOrSemaphore)) == TX_SEMAPHORE_ID) {
      p_sem = (txfr_sem_t *)xQueueOrSemaphore;
      if(p_sem->p_set != NULL) {
            TX_RESTORE;
            return pdFAIL;
      }

      p_sem->p_set = xQueueSet;

    } else if(*((ULONG *)(xQueueOrSemaphore)) == TX_QUEUE_ID) {
      p_queue = (txfr_queue_t *)xQueueOrSemaphore;
      if(p_queue->p_set != NULL) {
            TX_RESTORE;
            return pdFAIL;
      }

      p_queue->p_set = xQueueSet;

    } else {
      TX_RESTORE;
      configASSERT(0u);
      return pdFAIL;
    }

    TX_RESTORE;

    return pdPASS;
}


BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore,
                               QueueSetHandle_t xQueueSet)
{
    txfr_sem_t *p_sem;
    txfr_queue_t *p_queue;
    TX_INTERRUPT_SAVE_AREA;

    configASSERT(xQueueOrSemaphore != NULL);
    configASSERT(xQueueSet != NULL);

    TX_DISABLE;

    if(*((ULONG *)(xQueueOrSemaphore)) == TX_SEMAPHORE_ID) {
      p_sem = (txfr_sem_t *)xQueueOrSemaphore;

      if(p_sem->p_set != xQueueSet) {
            TX_RESTORE;
            return pdFAIL;
      } else{
            p_sem->p_set = NULL;
      }

    } else if(*((ULONG *)(xQueueOrSemaphore)) == TX_QUEUE_ID) {
      p_queue = (txfr_queue_t *)xQueueOrSemaphore;

      if(p_queue->p_set != xQueueSet) {
            TX_RESTORE;
            return pdFAIL;
      } else{
            p_queue->p_set = NULL;
      }

    } else {
      TX_RESTORE;
      configASSERT(0u);
      return pdFAIL;
    }

    TX_RESTORE;

    return pdPASS;
}


QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_t xQueueSet,
                                           const TickType_t xTicksToWait)
{
    void *p_ptr;
    UINT ret;
    UINT timeout;

    configASSERT(xQueueSet != NULL);

    if(xTicksToWait == portMAX_DELAY) {
      timeout = TX_WAIT_FOREVER;
    } else {
      timeout = (UINT)xTicksToWait;
    }

    ret = tx_queue_receive(&xQueueSet->queue, &p_ptr, timeout);
    if(ret != TX_SUCCESS) {
      return NULL;
    }

    return p_ptr;
}


QueueSetMemberHandle_t xQueueSelectFromSetFromISR(QueueSetHandle_t xQueueSet)
{
    return xQueueSelectFromSet(xQueueSet, 0u);
}

lhaoyue 发表于 2024-2-22 14:36:29

用cmsis_os2封装层是不是就没这个需求了?https://cdn.jsdelivr.net/gh/master-of-forums/master-of-forums/public/images/patch.gif

eric2013 发表于 2024-2-22 15:45:44

lhaoyue 发表于 2024-2-22 14:36
用cmsis_os2封装层是不是就没这个需求了?

是的,都用V2封装层就没有这个问题了。

hpdell 发表于 2024-3-1 11:08:22

这个封装层 有没有哪位测试过没,能否正常使用啊 ??

eric2013 发表于 2024-3-1 11:40:25

hpdell 发表于 2024-3-1 11:08
这个封装层 有没有哪位测试过没,能否正常使用啊 ??

能正常使用,你那边测试不正常?

hpdell 发表于 2024-3-1 19:52:40

本帖最后由 hpdell 于 2024-3-1 21:02 编辑

eric2013 发表于 2024-3-1 11:40
能正常使用,你那边测试不正常?
我目前还没有测试, 等后续有空也捣鼓一下看看

有参考例程 不 ??

eric2013 发表于 2024-3-2 09:28:40

hpdell 发表于 2024-3-1 19:52
我目前还没有测试, 等后续有空也捣鼓一下看看

有参考例程 不 ??

直接添加到工程即可。

hpdell 发表于 2024-3-2 15:11:10

本帖最后由 hpdell 于 2024-3-2 15:12 编辑

eric2013 发表于 2024-3-2 09:28
直接添加到工程即可。


刚刚捣鼓了一下,提示错误,




其中 FreeRTOSConfig.h 我是从 以前的 FreeRTOS 系统里面复制出来的


目前使用的 tx os 版本 6.2.1


eric2013 发表于 2024-3-2 15:13:13

hpdell 发表于 2024-3-2 15:11
刚刚捣鼓了一下,提示错误,




后面我整理个分析下。

hpdell 发表于 2024-3-2 17:30:11

eric2013 发表于 2024-3-2 15:13
后面我整理个分析下。

好的, 期待中 喔 ...:handshake

morning_enr6U 发表于 2024-3-4 10:11:09

{:34:}

soga238 发表于 2024-3-5 09:29:13

RTOS用不同的方法实现一个功能,内部运行机制不一样,并且RTOS本身有各种特色功能。统一API不知道是否真的省心省力

eric2013 发表于 2024-3-5 11:51:13

soga238 发表于 2024-3-5 09:29
RTOS用不同的方法实现一个功能,内部运行机制不一样,并且RTOS本身有各种特色功能。统一API不知道是否真的 ...

对,这种的封装层就有个兼容性的问题。

hpdell 发表于 2024-3-12 11:15:18

eric2013 发表于 2024-3-5 11:51
对,这种的封装层就有个兼容性的问题。

问一下,移植 os2 封装层教程大概还需要多久可以搞好啊??

eric2013 发表于 2024-3-13 08:48:53

hpdell 发表于 2024-3-12 11:15
问一下,移植 os2 封装层教程大概还需要多久可以搞好啊??

给那个系统移植。

跟着硬汉学 发表于 2024-3-13 09:04:03

cmsis—V1那个封装的FreeRTOS用到的很多API现在都弃用了,换成最新的API,需要改很多东西!

hpdell 发表于 2024-3-13 14:07:24

本帖最后由 hpdell 于 2024-3-13 14:08 编辑

eric2013 发表于 2024-3-13 08:48
给那个系统移植。
h7 的

eric2013 发表于 2024-3-14 00:28:04

hpdell 发表于 2024-3-13 14:07
h7 的

这个例子挺多的,RTX5和FreeRTOS都做了V2封装层的案例。

hpdell 发表于 2024-3-14 10:55:30

eric2013 发表于 2024-3-14 00:28
这个例子挺多的,RTX5和FreeRTOS都做了V2封装层的案例。

我需要 threadx os2 的封装层啊,按照上面的移植提示错误啊 ?! 貌似提示什么东东没有定义 ??

eric2013 发表于 2024-3-15 10:04:43

hpdell 发表于 2024-3-14 10:55
我需要 threadx os2 的封装层啊,按照上面的移植提示错误啊 ?! 貌似提示什么东东没有定义 ??

那你搞错了,这个才是。

https://github.com/STMicroelectronics/x-cube-azrtos-h7/tree/main/Projects/STM32H747I-DISCO/Applications/ThreadX/Tx_CMSIS_Wrapper

hpdell 发表于 2024-3-15 10:49:47

eric2013 发表于 2024-3-15 10:04
那你搞错了,这个才是。

https://github.com/STMicroelectronics/x-cube-azrtos-h7/tree/main/Project ...



这路径搞的够深的呀,感谢感谢啊,

hpdell 发表于 2024-3-16 20:13:26

eric2013 发表于 2024-3-15 10:04
那你搞错了,这个才是。

https://github.com/STMicroelectronics/x-cube-azrtos-h7/tree/main/Project ...

貌似移植后,编译没有错误, 但是 os 貌似没有运行是怎么个情况呀 ?

eric2013 发表于 2024-3-18 08:15:29

hpdell 发表于 2024-3-16 20:13
貌似移植后,编译没有错误, 但是 os 貌似没有运行是怎么个情况呀 ?

这个只能你再调试下了,这个例子是没问题的。

hpdell 发表于 2024-3-18 10:22:32

eric2013 发表于 2024-3-18 08:15
这个只能你再调试下了,这个例子是没问题的。

好的,我再研究研究看看
页: [1]
查看完整版本: FreeRTOS的各种API使用ThreadX实现方法