/* * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include #include #include #include #include "osal/osal_api.h" #include typedef struct task_notifiers { sem_t sem; TaskHandle_t id; } task_notifiers_t; typedef struct pthread_params { void *const param; TaskFunction_t task; bool started; TaskHandle_t handle; } pthread_params_t; static uint64_t s_semaphore_data = 0; static task_notifiers_t *s_notifiers; static int s_threads = 0; pthread_mutex_t s_mutex; typedef enum queue_type_tag { MUTEX_REC, MUTEX, SEMA, QUEUE, } queue_type_t; struct generic_queue_handle { queue_type_t type; size_t item_size; void *q; }; static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint32_t len, uint32_t item_size) { struct generic_queue_handle *h = calloc(1, sizeof(struct generic_queue_handle)); h->item_size = len; h->type = type; switch (type) { default: case QUEUE: case SEMA: h->q = osal_queue_create(); break; case MUTEX: case MUTEX_REC: h->q = osal_mutex_create(); break; } return h; } QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize) { return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize); } uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait) { struct generic_queue_handle *h = xQueue; return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL; } uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait) { return xQueueSend(xQueue, pvItemToQueue, xTicksToWait); } uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) { struct generic_queue_handle *h = xQueue; return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL; } BaseType_t xSemaphoreGive(QueueHandle_t xQueue) { struct generic_queue_handle *h = xQueue; if (h->type == MUTEX) { osal_mutex_give(h->q); return pdTRUE; } return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY); } BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue) { struct generic_queue_handle *h = xQueue; if (h->type == MUTEX_REC) { osal_mutex_give(h->q); return pdTRUE; } return pdFALSE; } BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask) { struct generic_queue_handle *h = xQueue; if (h->type == MUTEX) { osal_mutex_take(h->q); return pdTRUE; } return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY); } BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask) { struct generic_queue_handle *h = xQueue; if (h->type == MUTEX_REC) { osal_mutex_take(h->q); return pdTRUE; } return pdFALSE; } void vQueueDelete(QueueHandle_t xQueue) { struct generic_queue_handle *h = xQueue; if (h->q) { if (h->type == MUTEX || h->type == MUTEX_REC) { osal_mutex_delete(h->q); } else { osal_queue_delete(h->q); } } free(xQueue); } QueueHandle_t xSemaphoreCreateBinary(void) { return xQueueCreate(1, 1); } QueueHandle_t xSemaphoreCreateMutex(void) { return (QueueHandle_t)create_generic_queue(MUTEX, 1, 1); } QueueHandle_t xSemaphoreCreateRecursiveMutex(void) { return (QueueHandle_t)create_generic_queue(MUTEX_REC, 1, 1); } void vTaskDelete(TaskHandle_t *task) { for (int i = 0; i < s_threads; ++i) { if (task == s_notifiers[i].id) { sem_destroy(&s_notifiers[i].sem); s_notifiers[i].id = 0; } } if (task == NULL) { pthread_exit(0); } else { pthread_cancel((pthread_t)task); } void *thread_rval = NULL; pthread_join((pthread_t)task, &thread_rval); } void vTaskSuspend(void *task) { vTaskDelete(task); } TickType_t xTaskGetTickCount(void) { struct timespec spec; clock_gettime(CLOCK_REALTIME, &spec); return spec.tv_nsec / 1000000 + spec.tv_sec * 1000; } void vTaskDelay(const TickType_t xTicksToDelay) { usleep(xTicksToDelay * 1000); } void *pthread_task(void *params) { pthread_params_t *pthread_params = params; void *const param = pthread_params->param; TaskFunction_t task = pthread_params->task; pthread_params->handle = xTaskGetCurrentTaskHandle(); if (s_threads == 0) { pthread_mutex_init(&s_mutex, NULL); } pthread_mutex_lock(&s_mutex); s_notifiers = realloc(s_notifiers, sizeof(struct task_notifiers) * (++s_threads)); assert(s_notifiers); s_notifiers[s_threads - 1].id = pthread_params->handle; sem_init(&s_notifiers[s_threads - 1].sem, 0, 0); pthread_mutex_unlock(&s_mutex); pthread_params->started = true; task(param); return NULL; } TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode, const char *const pcName, const uint32_t ulStackDepth, void *const pvParameters, UBaseType_t uxPriority, StackType_t *const puxStackBuffer, StaticTask_t *const pxTaskBuffer, const BaseType_t xCoreID) { static TaskHandle_t pvCreatedTask; xTaskCreate(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &pvCreatedTask); return pvCreatedTask; } BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask, const BaseType_t xCoreID) { xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask); return pdTRUE; } BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask) { pthread_t new_thread = (pthread_t)NULL; pthread_attr_t attr; pthread_params_t pthread_params = { .param = pvParameters, .task = pvTaskCode}; int res = pthread_attr_init(&attr); assert(res == 0); res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); assert(res == 0); res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params); assert(res == 0); // just wait till the task started so we can unwind params from the stack while (pthread_params.started == false) { usleep(1000); } if (pvCreatedTask) { *pvCreatedTask = pthread_params.handle; } return pdTRUE; } void xTaskNotifyGive(TaskHandle_t task) { int i = 0; while (true) { pthread_mutex_lock(&s_mutex); if (task == s_notifiers[i].id) { sem_post(&s_notifiers[i].sem); pthread_mutex_unlock(&s_mutex); return; } pthread_mutex_unlock(&s_mutex); if (++i == s_threads) { i = 0; } usleep(1000); } } BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time) { return true; } TaskHandle_t xTaskGetCurrentTaskHandle(void) { return (TaskHandle_t)pthread_self(); } EventGroupHandle_t xEventGroupCreate(void) { return osal_signal_create(); } void vEventGroupDelete(EventGroupHandle_t xEventGroup) { osal_signal_delete(xEventGroup); } EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear) { return osal_signal_clear(xEventGroup, uxBitsToClear); } EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup) { return osal_signal_get(xEventGroup); } EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet) { return osal_signal_set(xEventGroup, uxBitsToSet); } EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait) { return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait); } void ulTaskNotifyTake(bool clear_on_exit, uint32_t xTicksToWait) { TaskHandle_t task = xTaskGetCurrentTaskHandle(); int i = 0; while (true) { pthread_mutex_lock(&s_mutex); if (task == s_notifiers[i].id) { pthread_mutex_unlock(&s_mutex); sem_wait(&s_notifiers[i].sem); return; } pthread_mutex_unlock(&s_mutex); if (++i == s_threads) { i = 0; } usleep(1000); } }