From dcfa42c6ff19e5c3d2add4e6021aa0aaa0189b9b Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 24 Sep 2021 02:11:10 +0200 Subject: [PATCH] cgo: add FreeRTOS compatibility headers This is especially useful if we ever want to support the ESP-IDF. Currently implemented: - xTaskGetCurrentTaskHandle - xSemaphoreCreateRecursiveMutex - xSemaphoreDelete - xSemaphoreTakeRecursive - xSemaphoreGiveRecursive --- compileopts/config.go | 3 + loader/goroot.go | 1 + src/compat/freertos/freertos.go | 69 +++++++++++++++++++ .../freertos/include/freertos/FreeRTOS.h | 9 +++ src/compat/freertos/include/freertos/queue.h | 3 + src/compat/freertos/include/freertos/semphr.h | 12 ++++ src/compat/freertos/include/freertos/task.h | 5 ++ 7 files changed, 102 insertions(+) create mode 100644 src/compat/freertos/freertos.go create mode 100644 src/compat/freertos/include/freertos/FreeRTOS.h create mode 100644 src/compat/freertos/include/freertos/queue.h create mode 100644 src/compat/freertos/include/freertos/semphr.h create mode 100644 src/compat/freertos/include/freertos/task.h diff --git a/compileopts/config.go b/compileopts/config.go index f1e34b7f0a..57aa085d8e 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -201,6 +201,9 @@ func (c *Config) RP2040BootPatch() bool { // preprocessing. func (c *Config) CFlags() []string { var cflags []string + // Compatibility CFlags. + cflags = append(cflags, "-I"+filepath.Join(goenv.Get("TINYGOROOT"), "src/compat/freertos/include")) + // CFlags for the target. for _, flag := range c.Target.CFlags { cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT"))) } diff --git a/loader/goroot.go b/loader/goroot.go index 8f0acf1b88..b29d51dcde 100644 --- a/loader/goroot.go +++ b/loader/goroot.go @@ -220,6 +220,7 @@ func needsSyscallPackage(buildTags []string) bool { func pathsToOverride(needsSyscallPackage bool) map[string]bool { paths := map[string]bool{ "/": true, + "compat/": false, "crypto/": true, "crypto/rand/": false, "device/": false, diff --git a/src/compat/freertos/freertos.go b/src/compat/freertos/freertos.go new file mode 100644 index 0000000000..920d8fd1e8 --- /dev/null +++ b/src/compat/freertos/freertos.go @@ -0,0 +1,69 @@ +// Package freertos provides a compatibility layer on top of the TinyGo +// scheduler for C code that wants to call FreeRTOS functions. One example is +// the ESP-IDF, which expects there to be a FreeRTOS-like RTOS. +package freertos + +// #include +// #include +// #include +import "C" +import ( + "sync" + "unsafe" + + "internal/task" +) + +//export xTaskGetCurrentTaskHandle +func xTaskGetCurrentTaskHandle() C.TaskHandle_t { + return C.TaskHandle_t(task.Current()) +} + +type Semaphore struct { + lock sync.Mutex // the lock itself + task *task.Task // the task currently locking this semaphore + count uint32 // how many times this semaphore is locked +} + +//export xSemaphoreCreateRecursiveMutex +func xSemaphoreCreateRecursiveMutex() C.SemaphoreHandle_t { + var mutex Semaphore + return (C.SemaphoreHandle_t)(unsafe.Pointer(&mutex)) +} + +//export vSemaphoreDelete +func vSemaphoreDelete(xSemaphore C.SemaphoreHandle_t) { + mutex := (*Semaphore)(unsafe.Pointer(xSemaphore)) + if mutex.task != nil { + panic("vSemaphoreDelete: still locked") + } +} + +//export xSemaphoreTakeRecursive +func xSemaphoreTakeRecursive(xMutex C.SemaphoreHandle_t, xTicksToWait C.TickType_t) C.BaseType_t { + // TODO: implement xTickToWait, or at least when xTicksToWait equals 0. + mutex := (*Semaphore)(unsafe.Pointer(xMutex)) + if mutex.task == task.Current() { + // Already locked. + mutex.count++ + return 1 // pdTRUE + } + // Not yet locked. + mutex.lock.Lock() + mutex.task = task.Current() + return 1 // pdTRUE +} + +//export xSemaphoreGiveRecursive +func xSemaphoreGiveRecursive(xMutex C.SemaphoreHandle_t) C.BaseType_t { + mutex := (*Semaphore)(unsafe.Pointer(xMutex)) + if mutex.task == task.Current() { + // Already locked. + mutex.count-- + if mutex.count == 0 { + mutex.lock.Unlock() + } + return 1 // pdTRUE + } + panic("xSemaphoreGiveRecursive: not locked by this task") +} diff --git a/src/compat/freertos/include/freertos/FreeRTOS.h b/src/compat/freertos/include/freertos/FreeRTOS.h new file mode 100644 index 0000000000..3e46754e3d --- /dev/null +++ b/src/compat/freertos/include/freertos/FreeRTOS.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +typedef uint32_t TickType_t; +typedef int BaseType_t; +typedef unsigned int UBaseType_t; + +#define portMAX_DELAY (TickType_t)0xffffffffUL diff --git a/src/compat/freertos/include/freertos/queue.h b/src/compat/freertos/include/freertos/queue.h new file mode 100644 index 0000000000..53d7595461 --- /dev/null +++ b/src/compat/freertos/include/freertos/queue.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct QueueDefinition * QueueHandle_t; diff --git a/src/compat/freertos/include/freertos/semphr.h b/src/compat/freertos/include/freertos/semphr.h new file mode 100644 index 0000000000..e394ad771e --- /dev/null +++ b/src/compat/freertos/include/freertos/semphr.h @@ -0,0 +1,12 @@ +#pragma once + +// Note: in FreeRTOS, SemaphoreHandle_t is an alias for QueueHandle_t. +typedef struct SemaphoreDefinition * SemaphoreHandle_t; + +SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void); + +void vSemaphoreDelete(SemaphoreHandle_t xSemaphore); + +// Note: these two functions are macros in FreeRTOS. +BaseType_t xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex, TickType_t xTicksToWait); +BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex); diff --git a/src/compat/freertos/include/freertos/task.h b/src/compat/freertos/include/freertos/task.h new file mode 100644 index 0000000000..76a31228f3 --- /dev/null +++ b/src/compat/freertos/include/freertos/task.h @@ -0,0 +1,5 @@ +#pragma once + +typedef void * TaskHandle_t; + +TaskHandle_t xTaskGetCurrentTaskHandle(void);