diff --git a/cpu/esp8266/Makefile b/cpu/esp8266/Makefile index 1b16977b69..bb10b55787 100644 --- a/cpu/esp8266/Makefile +++ b/cpu/esp8266/Makefile @@ -3,6 +3,7 @@ MODULE = cpu # Add a list of subdirectories, that should also be built: DIRS += $(RIOTCPU)/esp_common +DIRS += freertos DIRS += periph DIRS += sdk DIRS += vendor diff --git a/cpu/esp8266/Makefile.include b/cpu/esp8266/Makefile.include index f488ed2f61..8a9c37d837 100644 --- a/cpu/esp8266/Makefile.include +++ b/cpu/esp8266/Makefile.include @@ -59,7 +59,7 @@ PSEUDOMODULES += esp_sdk PSEUDOMODULES += esp_sw_timer PSEUDOMODULES += esp_spiffs -USEMODULE += esp +USEMODULE += esp_freertos USEMODULE += mtd USEMODULE += newlib USEMODULE += newlib_nano diff --git a/cpu/esp8266/freertos/Makefile b/cpu/esp8266/freertos/Makefile new file mode 100644 index 0000000000..94a83b3769 --- /dev/null +++ b/cpu/esp8266/freertos/Makefile @@ -0,0 +1,3 @@ +MODULE=esp_freertos + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/freertos/event_groups.c b/cpu/esp8266/freertos/event_groups.c new file mode 100644 index 0000000000..34ba654ad0 --- /dev/null +++ b/cpu/esp8266/freertos/event_groups.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +EventGroupHandle_t xEventGroupCreate (void) +{ + printf("%s is not supported\n", __func__); + return NULL; +} + +void vEventGroupDelete (EventGroupHandle_t xEventGroup) +{ + printf("%s is not supported\n", __func__); +} + +EventBits_t xEventGroupSetBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToSet) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +EventBits_t xEventGroupClearBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToClear ) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +EventBits_t xEventGroupWaitBits (const EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToWaitFor, + const BaseType_t xClearOnExit, + const BaseType_t xWaitForAllBits, + TickType_t xTicksToWait) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/portable.c b/cpu/esp8266/freertos/portable.c new file mode 100644 index 0000000000..0bbfa4326e --- /dev/null +++ b/cpu/esp8266/freertos/portable.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "log.h" +#ifdef MCU_ESP8266 +#include "esp_attr.h" +#include "irq.h" +#include "rom/ets_sys.h" +#endif + +#include "freertos/FreeRTOS.h" + +uint32_t xPortGetTickRateHz(void) { + return MSEC_PER_SEC / portTICK_PERIOD_MS; +} + +BaseType_t xPortInIsrContext(void) +{ + /* is working on single core in that way */ + return irq_is_in(); +} + +#ifdef MCU_ESP8266 + +unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */ + +extern void vTaskEnterCritical( portMUX_TYPE *mux ); +extern void vTaskExitCritical( portMUX_TYPE *mux ); + +void vPortEnterCritical(void) +{ + vTaskEnterCritical(0); +} + +extern void vPortExitCritical(void) +{ + vTaskExitCritical(0); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void IRAM_ATTR vPortETSIntrLock(void) +{ + ETS_INTR_LOCK(); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void IRAM_ATTR vPortETSIntrUnlock(void) +{ + ETS_INTR_UNLOCK(); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void ResetCcountVal(unsigned int cnt_val) +{ + asm volatile("wsr a2, ccount"); +} + +#endif /* MCU_ESP8266 */ + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/queue.c b/cpu/esp8266/freertos/queue.c new file mode 100644 index 0000000000..f90f03ffae --- /dev/null +++ b/cpu/esp8266/freertos/queue.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "irq_arch.h" +#include "log.h" +#include "mutex.h" +#include "rmutex.h" +#include "syscalls.h" +#include "thread.h" + +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/task.h" + +/* + * In FreeRTOS different types of semaphores, mutexes and queues are all + * mapped to a single generic queue type. With all these different types, + * single functions for send, receive, give and take are then used. To be + * able to dsitinguish between these different types in RIOT, we need typed + * objects. + */ +typedef struct { + uint8_t type; /* type of the queue, MUST be the first element */ + list_node_t sending; /* threads that are waiting to send */ + list_node_t receiving; /* threads that are waiting to receive */ + uint8_t* queue; /* the queue of waiting items */ + uint32_t item_size; /* size of each item in the queue */ + uint32_t item_num; /* num of items that can be stored in queue */ + uint32_t item_front; /* first item in queue */ + uint32_t item_tail; /* last item in queue */ + uint32_t item_level; /* num of items stored in queue */ +} _queue_t; + +QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, + const UBaseType_t uxItemSize, + const uint8_t ucQueueType ) +{ + DEBUG("%s pid=%d len=%u size=%u type=%u ", __func__, + thread_getpid(), uxQueueLength, uxItemSize, ucQueueType); + + uint32_t queue_size = uxQueueLength * uxItemSize; + _queue_t* queue = malloc(sizeof(_queue_t) + queue_size); + + queue->type = ucQueueType; + queue->receiving.next = NULL; + queue->sending.next = NULL; + queue->queue = (queue_size) ? (uint8_t*)queue + sizeof(_queue_t) : NULL; + queue->item_num = uxQueueLength; + queue->item_size = uxItemSize; + queue->item_front = 0; + queue->item_tail = 0; + queue->item_level = 0; + + DEBUG("queue=%p\n", queue); + + return queue; +} + +#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 ) + +QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount, + const UBaseType_t uxInitialCount) +{ + _queue_t* queue; + + assert(uxMaxCount != 0); + assert(uxInitialCount <= uxMaxCount); + + queue = xQueueGenericCreate(uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, + queueQUEUE_TYPE_COUNTING_SEMAPHORE); + + DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), queue); + + if (queue != NULL) { + queue->item_level = uxInitialCount; + queue->item_tail = (queue->item_front + queue->item_level) % queue->item_num; + } + + return queue; +} + +void vQueueDelete( QueueHandle_t xQueue ) +{ + DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), xQueue); + + assert(xQueue != NULL); + free(xQueue); +} + +BaseType_t IRAM_ATTR _queue_generic_send(QueueHandle_t xQueue, + const void * const pvItemToQueue, + const BaseType_t xCopyPosition, + TickType_t xTicksToWait, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p pos=%d wait=%u woken=%p isr=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xCopyPosition, xTicksToWait, pxHigherPriorityTaskWoken, + irq_is_in()); + + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + + while (1) { + vTaskEnterCritical(0); + + /* is there still space in the queue */ + if (queue->item_level < queue->item_num || xCopyPosition == queueOVERWRITE) { + uint32_t write_pos; + /* determine the write position in the queue and update positions */ + if (xCopyPosition == queueSEND_TO_BACK) { + write_pos = queue->item_tail; + queue->item_tail = (queue->item_tail + 1) % queue->item_num; + queue->item_level++; + } + else if (xCopyPosition == queueSEND_TO_FRONT) { + queue->item_front = (queue->item_front - 1) % queue->item_num; + queue->item_level++; + write_pos = queue->item_front; + } + else { /* queueOVERWRITE */ + write_pos = queue->item_front; + if (queue->item_level == 0) { + queue->item_level++; + } + } + + /* if the item has no 0 size, copy it to the according place in queue */ + if (queue->item_size && queue->queue && pvItemToQueue) { + memcpy(queue->queue + write_pos * queue->item_size, + pvItemToQueue, queue->item_size); + } + + /* indicates a required context switch */ + bool ctx_switch = false; + + /* unlock waiting receiving thread */ + if (queue->receiving.next != NULL) { + list_node_t *next = list_remove_head(&queue->receiving); + thread_t *proc = container_of((clist_node_t*)next, thread_t, rq_entry); + sched_set_status(proc, STATUS_PENDING); + ctx_switch = proc->priority < sched_threads[thread_getpid()]->priority; + + DEBUG("%s pid=%d queue=%p unlock waiting pid=%d switch=%d\n", + __func__, thread_getpid(), xQueue, proc->pid, ctx_switch); + } + + if (ctx_switch && pxHigherPriorityTaskWoken) { + *pxHigherPriorityTaskWoken = pdTRUE; + vTaskExitCritical(0); + } + else if (ctx_switch) { + vTaskExitCritical(0); + /* sets only the sched_context_switch_request in ISRs */ + thread_yield_higher(); + } + else { + vTaskExitCritical(0); + } + + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + + /* in all cases vTaskExitCritical has been called already */ + return pdPASS; + } + else if (xTicksToWait == 0 || irq_is_in()) { + /* if there was no space and timeout = 0, return with error */ + DEBUG("%s pid=%d queue=%p return errQUEUE_FULL\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return errQUEUE_FULL; + } + else { + /* suspend the calling thread to wait for space in the queue */ + thread_t *me = (thread_t*)sched_active_thread; + sched_set_status(me, STATUS_SEND_BLOCKED); + /* waiting list is sorted by priority */ + thread_add_to_list(&queue->sending, me); + + DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + thread_yield_higher(); + + /* TODO timeout handling with xTicksToWait */ + DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, + thread_getpid(), xQueue); + } + /* in all cases vTaskExitCritical has been called already */ + } + return errQUEUE_FULL; +} + +BaseType_t IRAM_ATTR _queue_generic_recv (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%u woken=%p isr=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xJustPeeking, pxHigherPriorityTaskWoken, + irq_is_in()); + + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + + while (1) { + vTaskEnterCritical(0); + + /* if there is at least one item in the queue */ + if (queue->item_level > 0) { + /* if the item has no 0 size, copy it from queue to buffer */ + if (queue->item_size && queue->item_num && queue->queue && pvBuffer) { + memcpy(pvBuffer, + queue->queue + queue->item_front * queue->item_size, + queue->item_size); + } + + + /* when only peeking leave the element in queue */ + if (xJustPeeking == pdTRUE) { + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return pdPASS; + } + + /* remove element from queue */ + queue->item_front = (queue->item_front + 1) % queue->item_num; + queue->item_level--; + + /* return if there is no waiting sending thread */ + if (queue->sending.next == NULL) { + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return pdPASS; + } + + /* otherwise unlock the waiting sending thread */ + list_node_t *next = list_remove_head(&queue->sending); + thread_t *proc = container_of((clist_node_t*)next, thread_t, rq_entry); + sched_set_status(proc, STATUS_PENDING); + + /* test whether context switch is required */ + bool ctx_switch = proc->priority < sched_threads[thread_getpid()]->priority; + + DEBUG("%s pid=%d queue=%p unlock waiting pid=%d switch=%d\n", + __func__, thread_getpid(), xQueue, proc->pid, ctx_switch); + + if (ctx_switch && pxHigherPriorityTaskWoken) { + *pxHigherPriorityTaskWoken = pdTRUE; + vTaskExitCritical(0); + } + else if (ctx_switch) { + vTaskExitCritical(0); + /* sets only the sched_context_switch_request in ISRs */ + sched_switch(proc->priority); + } + else { + vTaskExitCritical(0); + } + + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + + /* in all cases vTaskExitCritical has been called already */ + return pdPASS; + } + else if (xTicksToWait == 0 || irq_is_in()) { + /* if there was no item in the queue and timeout is 0, return with error */ + DEBUG("%s pid=%d queue=%p return errQUEUE_EMPTY\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return errQUEUE_EMPTY; + } + else { + /* suspend the calling thread to wait for an item in the queue */ + thread_t *me = (thread_t*)sched_active_thread; + sched_set_status(me, STATUS_RECEIVE_BLOCKED); + /* waiting list is sorted by priority */ + thread_add_to_list(&queue->receiving, me); + + DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, + thread_getpid(), xQueue); + + vTaskExitCritical(0); + thread_yield_higher(); + + /* TODO timeout handling with xTicksToWait */ + DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, + thread_getpid(), xQueue); + } + /* in all cases vTaskExitCritical has been called already */ + } +} + +BaseType_t IRAM_ATTR xQueueGenericSend( QueueHandle_t xQueue, + const void * const pvItemToQueue, + TickType_t xTicksToWait, + const BaseType_t xCopyPosition ) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u pos=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xCopyPosition); + + return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition, + xTicksToWait, NULL); +} + +BaseType_t IRAM_ATTR xQueueGenericSendFromISR( QueueHandle_t xQueue, + const void * const pvItemToQueue, + BaseType_t * const pxHigherPriorityTaskWoken, + const BaseType_t xCopyPosition ) +{ + DEBUG("%s pid=%d prio=%d queue=%p pos=%d woken=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xCopyPosition, pxHigherPriorityTaskWoken); + + return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition, + 0, pxHigherPriorityTaskWoken); +} + +BaseType_t IRAM_ATTR xQueueGenericReceive (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xJustPeeking); + + return _queue_generic_recv(xQueue, pvBuffer, xTicksToWait, + xJustPeeking, NULL); +} + +BaseType_t IRAM_ATTR xQueueReceiveFromISR (QueueHandle_t xQueue, + void * const pvBuffer, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p woken=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, pxHigherPriorityTaskWoken); + + return _queue_generic_recv(xQueue, pvBuffer, 0, + 0, pxHigherPriorityTaskWoken); +} + +UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ) +{ + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + return queue->item_level; +} + +BaseType_t xQueueGiveFromISR (QueueHandle_t xQueue, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + /* this function only satisfies the linker and should not be called */ + assert(0); + + DEBUG("%s\n", __func__); + return pdFALSE; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/semphr.c b/cpu/esp8266/freertos/semphr.c new file mode 100644 index 0000000000..8769624b88 --- /dev/null +++ b/cpu/esp8266/freertos/semphr.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "irq_arch.h" +#include "log.h" +#include "mutex.h" +#include "rmutex.h" + +#include "freertos/FreeRTOS.h" + +/* + * In FreeRTOS different types of semaphores, mutexes and queues are all + * mapped to a single generic queue type. With all these different types, + * single functions for send, receive, give and take are then used. To be + * able to dsitinguish between these different types in RIOT, we need typed + * objects. + */ +typedef struct { + uint8_t type; /* type of the mutex, MUST be the first element */ + mutex_t mutex; /* the mutex */ +} _mutex_t; + +typedef struct { + uint8_t type; /* type of the mutex, MUST be the first element */ + rmutex_t rmutex; /* the mutex */ +} _rmutex_t; + +SemaphoreHandle_t xSemaphoreCreateMutex(void) +{ + _mutex_t* _tmp = (_mutex_t*)malloc (sizeof(_mutex_t)); + _tmp->type = queueQUEUE_TYPE_MUTEX; + mutex_init(&_tmp->mutex); + + DEBUG("%s mutex=%p\n", __func__, _tmp); + return _tmp; +} + +void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ) +{ + DEBUG("%s mutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + free(xSemaphore); +} + +BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore) +{ + DEBUG("%s mutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + + uint8_t type = ((_mutex_t*)xSemaphore)->type; + mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + + switch (type) { + case queueQUEUE_TYPE_MUTEX: + mutex_unlock(mutex); + break; + case queueQUEUE_TYPE_RECURSIVE_MUTEX: + return xSemaphoreGiveRecursive (xSemaphore); + default: + return xQueueGenericSend(xSemaphore, NULL, 0, queueSEND_TO_BACK); + } + + return pdTRUE; +} + +BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) +{ + DEBUG("%s mutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + + assert(xSemaphore != NULL); + + uint8_t type = ((_mutex_t*)xSemaphore)->type; + mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + + switch (type) { + case queueQUEUE_TYPE_MUTEX: + { + if (xTicksToWait == 0) { + return (mutex_trylock(mutex) == 1) ? pdPASS : pdFAIL; + } + else { + mutex_lock(mutex); + /* TODO timeout handling */ + return pdTRUE; + } + break; + } + case queueQUEUE_TYPE_RECURSIVE_MUTEX: + return xSemaphoreTakeRecursive (xSemaphore, xTicksToWait); + + default: + return xQueueGenericReceive(xSemaphore, NULL, xTicksToWait, pdFALSE); + } +} + +SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void) +{ + _rmutex_t* _tmp = (_rmutex_t*)malloc (sizeof(_rmutex_t)); + _tmp->type = queueQUEUE_TYPE_RECURSIVE_MUTEX; + rmutex_init(&_tmp->rmutex); + + DEBUG("%s rmutex=%p\n", __func__, _tmp); + + return _tmp; +} + +BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore) +{ + DEBUG("%s rmutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + + rmutex_unlock(&((_rmutex_t*)xSemaphore)->rmutex); + return pdTRUE; +} + +BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) +{ + DEBUG("%s rmutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + + assert(xSemaphore != NULL); + assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + + BaseType_t ret = pdTRUE; + rmutex_t* rmutex = &((_rmutex_t*)xSemaphore)->rmutex; + + if (xTicksToWait == 0) { + ret = (rmutex_trylock(rmutex) == 1) ? pdPASS : pdFAIL; + } + else { + rmutex_lock(&((_rmutex_t*)xSemaphore)->rmutex); + /* TODO timeout handling */ + } + + return ret; +} + +void vPortCPUAcquireMutex(portMUX_TYPE *mux) +{ + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, mux); + critical_enter(); + mutex_lock(mux); /* lock the mutex with interrupts disabled */ + critical_exit(); +} + +void vPortCPUReleaseMutex(portMUX_TYPE *mux) +{ + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, mux); + critical_enter(); + mutex_unlock(mux); /* unlock the mutex with interrupts disabled */ + critical_exit(); +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/task.c b/cpu/esp8266/freertos/task.c new file mode 100644 index 0000000000..36ed86a088 --- /dev/null +++ b/cpu/esp8266/freertos/task.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "log.h" +#include "syscalls.h" +#include "thread.h" +#include "xtimer.h" + +#ifdef MCU_ESP32 +#include "soc/soc.h" +#endif + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define MHZ 1000000 + +#ifdef MCU_ESP8266 +#include "rom/ets_sys.h" + +#define PRO_CPU_NUM (0) +#endif + +/** + * @brief Architecture specific data of thread control blocks + */ +typedef struct { + uint32_t saved_int_state; + uint32_t critical_nesting; +} thread_arch_ext_t; + +volatile thread_arch_ext_t threads_arch_exts[KERNEL_PID_LAST + 1] = {}; + +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) +{ + /* FreeRTOS priority values have to be inverted */ + uxPriority = SCHED_PRIO_LEVELS - uxPriority - 1; + + DEBUG("%s name=%s size=%d prio=%d pvCreatedTask=%p ", + __func__, pcName, usStackDepth, uxPriority, pvCreatedTask); + + char* stack = malloc(usStackDepth + sizeof(thread_t)); + + if (!stack) { + LOG_TAG_ERROR("freertos", "not enough memory to create task %s with " + "stack size of %d bytes\n", pcName, usStackDepth); + abort(); + return pdFALSE; + } + kernel_pid_t pid = thread_create(stack, + usStackDepth + sizeof(thread_t), + uxPriority, + THREAD_CREATE_WOUT_YIELD | + THREAD_CREATE_STACKTEST, + (thread_task_func_t)pvTaskCode, + pvParameters, pcName); + DEBUG("pid=%d\n", pid); + + if (pvCreatedTask) { + *pvCreatedTask = (TaskHandle_t)(0L + pid); + } + + return (pid < 0) ? pdFALSE : 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) +{ + return xTaskCreatePinnedToCore (pvTaskCode, + pcName, + usStackDepth, + pvParameters, + uxPriority, + pvCreatedTask, + PRO_CPU_NUM); +} + +void vTaskDelete (TaskHandle_t xTaskToDelete) +{ + DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToDelete); + + assert(xTaskToDelete != NULL); + + uint32_t pid = (uint32_t)xTaskToDelete; + + /* remove old task from scheduling */ + thread_t* thread = (thread_t*)sched_threads[pid]; + sched_set_status(thread, STATUS_STOPPED); + sched_threads[pid] = NULL; + sched_num_threads--; + sched_active_thread = NULL; + + /* determine the new running task */ + sched_run(); +} + +TaskHandle_t xTaskGetCurrentTaskHandle(void) +{ + DEBUG("%s pid=%d\n", __func__, thread_getpid()); + + uint32_t pid = thread_getpid(); + return (TaskHandle_t)pid; +} + +void vTaskDelay( const TickType_t xTicksToDelay ) +{ + DEBUG("%s xTicksToDelay=%d\n", __func__, xTicksToDelay); +#if defined(MCU_ESP8266) && defined(MODULE_ESP_WIFI_ANY) + uint64_t us = xTicksToDelay * MHZ / xPortGetTickRateHz(); + xtimer_usleep(us); +#endif +} + +TickType_t xTaskGetTickCount (void) +{ + return system_get_time() / USEC_PER_MSEC / portTICK_PERIOD_MS; +} + +void vTaskEnterCritical( portMUX_TYPE *mux ) +{ +#ifdef MCU_ESP8266 + /* we have to return on NMI */ + if (NMIIrqIsOn) { + return; + } +#endif /* MCU_ESP8266 */ + + /* disable interrupts */ + uint32_t state = irq_disable(); + + /* determine calling thread pid (can't fail) */ + kernel_pid_t my_pid = thread_getpid(); + + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + my_pid, sched_threads[my_pid]->priority, mux); + + /* acquire the mutex with interrupts disabled */ + if (mux) { + mutex_lock(mux); /* TODO should be only a spin lock */ + } + + /* increment nesting counter and save old interrupt level */ + threads_arch_exts[my_pid].critical_nesting++; + if (threads_arch_exts[my_pid].critical_nesting == 1) { + threads_arch_exts[my_pid].saved_int_state = state; + } +} + +void vTaskExitCritical( portMUX_TYPE *mux ) +{ +#ifdef MCU_ESP8266 + /* we have to return on NMI */ + if (NMIIrqIsOn) { + return; + } +#endif /* MCU_ESP8266 */ + + /* determine calling thread pid (can't fail) */ + kernel_pid_t my_pid = thread_getpid(); + + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + my_pid, sched_threads[my_pid]->priority, mux); + + /* release the mutex with interrupts disabled */ + if (mux) { + mutex_unlock(mux); /* TODO should be only a spin lock */ + } + + /* decrement nesting counter and restore old interrupt level */ + if (threads_arch_exts[my_pid].critical_nesting) { + threads_arch_exts[my_pid].critical_nesting--; + if (threads_arch_exts[my_pid].critical_nesting == 0) { + irq_restore(threads_arch_exts[my_pid].saved_int_state); + } + } +} + +void vTaskStepTick(const TickType_t xTicksToJump) +{ + DEBUG("%s xTicksToJump=%d\n", __func__, xTicksToJump); + /* + * TODO: + * At the moment, only the calling task is set to sleep state. Usually, the + * complete system should sleep but not only the task. + */ + vTaskDelay(xTicksToJump); +} + +TickType_t prvGetExpectedIdleTime(void) +{ + DEBUG("%s\n", __func__); + /* + * TODO: + * Since we are not able to estimate the time the system will be idle, + * we simply return 0. + */ + return 0; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/timers.c b/cpu/esp8266/freertos/timers.c new file mode 100644 index 0000000000..b134de96c1 --- /dev/null +++ b/cpu/esp8266/freertos/timers.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "log.h" +#include "xtimer.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" + +typedef struct { + xtimer_t xtimer; /* xtimer object */ + const char* name; /* FreeRTOS timer name */ + uint32_t period; /* in us */ + bool autoreload; /* FreeRTOS timer reload indicator */ + const void* timerid; /* FreeRTOS timer id */ + TimerCallbackFunction_t cb; /* FreeRTOS callback function */ +} freertos_xtimer_t; + +static void IRAM_ATTR _xtimer_callback (void *arg) +{ + assert(arg != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)arg; + + if (timer->autoreload) { + xtimer_set(&timer->xtimer, timer->period); + } + + if (timer->cb) { + timer->cb(arg); + } +} + +TimerHandle_t xTimerCreate (const char * const pcTimerName, + const TickType_t xTimerPeriod, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction) +{ + freertos_xtimer_t* timer = malloc(sizeof(freertos_xtimer_t)); + if (timer == NULL) { + return NULL; + } + + /* FreeRTOS timer parameter */ + timer->name = pcTimerName; + timer->period = xTimerPeriod * portTICK_PERIOD_MS * USEC_PER_MSEC; + timer->autoreload = uxAutoReload; + timer->timerid = pvTimerID; + timer->cb = pxCallbackFunction; + + /* xtimer parameter */ + timer->xtimer.callback = _xtimer_callback; + timer->xtimer.arg = timer; + + DEBUG("%s %p %s %d %u\n", __func__, timer, pcTimerName, xTimerPeriod, uxAutoReload); + return timer; +} + +BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_remove(&timer->xtimer); + free(timer); + + return pdTRUE; +} + +BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_set(&timer->xtimer, timer->period); + + return pdTRUE; +} + +BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_remove(&timer->xtimer); + + return pdTRUE; +} + +BaseType_t xTimerReset (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_set(&timer->xtimer, xBlockTime * portTICK_PERIOD_MS * USEC_PER_MSEC); + + return pdTRUE; +} + +void *pvTimerGetTimerID(const TimerHandle_t xTimer) +{ + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + return (void*)timer->timerid; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/include/freertos/FreeRTOS.h b/cpu/esp8266/include/freertos/FreeRTOS.h new file mode 100644 index 0000000000..e333cfd722 --- /dev/null +++ b/cpu/esp8266/include/freertos/FreeRTOS.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_FREERTOS_H +#define FREERTOS_FREERTOS_H + +#ifndef DOXYGEN + +#include "freertos/portmacro.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define configMAX_PRIORITIES SCHED_PRIO_LEVELS + +#ifndef configASSERT +#define configASSERT assert +#endif + +#define portTICK_PERIOD_MS 10 +#define portTickType TickType_t + +#define portTICK_RATE_MS portTICK_PERIOD_MS + +#define BaseType_t portBASE_TYPE +#define UBaseType_t unsigned portBASE_TYPE + +typedef uint32_t TickType_t; + +uint32_t xPortGetTickRateHz(void); +BaseType_t xPortInIsrContext(void); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) + +#ifdef __cplusplus +} +#endif + +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#endif /* DOXYGEN */ +#endif /* FREERTOS_FREERTOS_H */ diff --git a/cpu/esp8266/include/freertos/event_groups.h b/cpu/esp8266/include/freertos/event_groups.h new file mode 100644 index 0000000000..1c70882f6c --- /dev/null +++ b/cpu/esp8266/include/freertos/event_groups.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_EVENT_GROUPS_H +#define FREERTOS_EVENT_GROUPS_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * EventGroupHandle_t; +typedef TickType_t EventBits_t; + +EventGroupHandle_t xEventGroupCreate (void); + +void vEventGroupDelete (EventGroupHandle_t xEventGroup); + +EventBits_t xEventGroupSetBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToSet); + +EventBits_t xEventGroupClearBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToClear ); + +EventBits_t xEventGroupWaitBits (const EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToWaitFor, + const BaseType_t xClearOnExit, + const BaseType_t xWaitForAllBits, + TickType_t xTicksToWait); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_EVENT_GROUPS_H */ diff --git a/cpu/esp8266/include/freertos/portmacro.h b/cpu/esp8266/include/freertos/portmacro.h new file mode 100644 index 0000000000..b0df76c65a --- /dev/null +++ b/cpu/esp8266/include/freertos/portmacro.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_PORTMACRO_H +#define FREERTOS_PORTMACRO_H + +#ifndef DOXYGEN + +#include "stdint.h" + +#include "mutex.h" +#include "irq.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define portBASE_TYPE int +#define portUBASE_TYPE unsigned portBASE_TYPE + +#define portMAX_DELAY 0xFFFFFFFF + +#define portMUX_TYPE mutex_t +#define portMUX_INITIALIZER_UNLOCKED MUTEX_INIT + +#define portYIELD_FROM_ISR thread_yield_higher + +#ifdef MCU_ESP32 + +#define portNUM_PROCESSORS 2 +#define xPortGetCoreID() PRO_CPU_NUM + +#define portENTER_CRITICAL(pm) mutex_lock(pm) +#define portEXIT_CRITICAL(pm) mutex_unlock(pm) +#define portENTER_CRITICAL_NESTED irq_disable +#define portEXIT_CRITICAL_NESTED irq_restore + +#define portENTER_CRITICAL_ISR vTaskEnterCritical +#define portEXIT_CRITICAL_ISR vTaskExitCritical + +#else /* MCU_ESP32 */ + +#define portNUM_PROCESSORS 1 +#define xPortGetCoreID() PRO_CPU_NUM + +#define portENTER_CRITICAL vTaskEnterCritical +#define portEXIT_CRITICAL vTaskExitCritical + +#endif /* MCU_ESP32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_PORTMACRO_H */ diff --git a/cpu/esp8266/include/freertos/queue.h b/cpu/esp8266/include/freertos/queue.h new file mode 100644 index 0000000000..f42b0b86af --- /dev/null +++ b/cpu/esp8266/include/freertos/queue.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_QUEUE_H +#define FREERTOS_QUEUE_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define xQueueHandle QueueHandle_t + +typedef void* QueueHandle_t; + +QueueHandle_t xQueueGenericCreate (const UBaseType_t uxQueueLength, + const UBaseType_t uxItemSize, + const uint8_t ucQueueType); + +QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount, + const UBaseType_t uxInitialCount); + +void vQueueDelete (QueueHandle_t xQueue); + +BaseType_t xQueueGenericReset (QueueHandle_t xQueue, BaseType_t xNewQueue); + +BaseType_t xQueueGenericReceive (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking); + +BaseType_t xQueueGenericSend (QueueHandle_t xQueue, + const void * const pvItemToQueue, + TickType_t xTicksToWait, + const BaseType_t xCopyPosition); + +BaseType_t xQueueReceiveFromISR (QueueHandle_t xQueue, void * const pvBuffer, + BaseType_t * const pxHigherPriorityTaskWoken); + +BaseType_t xQueueGenericSendFromISR (QueueHandle_t xQueue, + const void * const pvItemToQueue, + BaseType_t * const pxHigherPriorityTaskWoken, + const BaseType_t xCopyPosition ); + +BaseType_t xQueueGiveFromISR (QueueHandle_t xQueue, + BaseType_t * const pxHigherPriorityTaskWoken); + +UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) +#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) +#define queueOVERWRITE ( ( BaseType_t ) 2 ) + +#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) + +#define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) +#define errQUEUE_FULL ( ( BaseType_t ) 0 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +#define xQueueCreate( uxQueueLength, uxItemSize ) \ + xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) + +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) \ + xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), \ + pdFALSE ) + +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \ + xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), \ + queueSEND_TO_BACK ) + +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \ + xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), \ + queueSEND_TO_BACK ) + +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) \ + xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), \ + ( pxHigherPriorityTaskWoken ), \ + queueSEND_TO_BACK ) + +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_QUEUE_H */ diff --git a/cpu/esp8266/include/freertos/semphr.h b/cpu/esp8266/include/freertos/semphr.h new file mode 100644 index 0000000000..8b725b27e0 --- /dev/null +++ b/cpu/esp8266/include/freertos/semphr.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_SEMPHR_H +#define FREERTOS_SEMPHR_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#include +#include "mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* SemaphoreHandle_t; + +SemaphoreHandle_t xSemaphoreCreateMutex(void); +SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void); + +void vSemaphoreDelete (SemaphoreHandle_t xSemaphore); + +BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore); +BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait); +BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore); +BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait); + +#define vPortCPUInitializeMutex(m) mutex_init(m) + +void vPortCPUAcquireMutex (portMUX_TYPE *mux); +void vPortCPUReleaseMutex (portMUX_TYPE *mux); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) + +#define xSemaphoreCreateBinary() \ + xQueueGenericCreate( ( UBaseType_t ) 1, \ + semSEMAPHORE_QUEUE_ITEM_LENGTH, \ + queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) \ + xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) + +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ + xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), \ + NULL, ( pxHigherPriorityTaskWoken ) ) + +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ + xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), \ + ( pxHigherPriorityTaskWoken ) ) + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_SEMPHR_H */ diff --git a/cpu/esp8266/include/freertos/task.h b/cpu/esp8266/include/freertos/task.h new file mode 100644 index 0000000000..0f0a958390 --- /dev/null +++ b/cpu/esp8266/include/freertos/task.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_TASK_H +#define FREERTOS_TASK_H + +#ifndef DOXYGEN + +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define xTaskHandle TaskHandle_t +#define tskNO_AFFINITY INT_MAX + +#define taskDISABLE_INTERRUPTS portDISABLE_INTERRUPTS +#define taskENABLE_INTERRUPTS portENABLE_INTERRUPTS + +#define taskENTER_CRITICAL portENTER_CRITICAL +#define taskEXIT_CRITICAL portEXIT_CRITICAL + +typedef void (*TaskFunction_t)(void *); + +typedef void* TaskHandle_t; + +BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const 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); + +void vTaskDelete(TaskHandle_t xTaskToDelete); +void vTaskDelay(const TickType_t xTicksToDelay); + +TaskHandle_t xTaskGetCurrentTaskHandle(void); + +void vTaskEnterCritical(portMUX_TYPE *mux); +void vTaskExitCritical(portMUX_TYPE *mux); + +TickType_t xTaskGetTickCount (void); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_TASK_H */ diff --git a/cpu/esp8266/include/freertos/timers.h b/cpu/esp8266/include/freertos/timers.h new file mode 100644 index 0000000000..dbd37061bc --- /dev/null +++ b/cpu/esp8266/include/freertos/timers.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_TIMERS_H +#define FREERTOS_TIMERS_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" +#include "xtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* TimerHandle_t; + +#define TimerCallbackFunction_t xtimer_callback_t +#define tmrTIMER_CALLBACK TimerCallbackFunction_t + +TimerHandle_t xTimerCreate (const char * const pcTimerName, + const TickType_t xTimerPeriod, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction); +BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerReset (TimerHandle_t xTimer, TickType_t xTicksToWait); + +void *pvTimerGetTimerID(const TimerHandle_t xTimer); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_TIMERS_H */ diff --git a/cpu/esp8266/include/freertos/xtensa_api.h b/cpu/esp8266/include/freertos/xtensa_api.h new file mode 100644 index 0000000000..61f53a7673 --- /dev/null +++ b/cpu/esp8266/include/freertos/xtensa_api.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_XTENSA_API_H +#define FREERTOS_XTENSA_API_H + +#include "xtensa/xtensa_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* FREERTOS_XTENSA_API_H */