From 853df1f434c4222131cb20000627d576ee7e9727 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 29 Sep 2021 01:22:36 +0200 Subject: [PATCH] cgo: add more FreeRTOS compatibility This commit implements: * xTaskCreate * vTaskDelay * xSemaphoreCreateCounting (partially) * xSemaphoreTake * xSemaphoreGive * xQueueCreate * vQueueDelete * xQueueReceive * xQueueSend * uxQueueMessagesWaiting --- src/compat/freertos/freertos.go | 95 ++++++++++++++++++- .../freertos/include/freertos/FreeRTOS.h | 4 +- src/compat/freertos/include/freertos/queue.h | 9 +- src/compat/freertos/include/freertos/semphr.h | 7 +- src/compat/freertos/include/freertos/task.h | 5 + src/runtime/chan.go | 14 +++ 6 files changed, 127 insertions(+), 7 deletions(-) diff --git a/src/compat/freertos/freertos.go b/src/compat/freertos/freertos.go index 920d8fd1e8..392b32259d 100644 --- a/src/compat/freertos/freertos.go +++ b/src/compat/freertos/freertos.go @@ -4,11 +4,14 @@ package freertos // #include +// #include // #include // #include +// void freertos_callFunction(void (*function)(void *), void *parameter); import "C" import ( "sync" + "time" "unsafe" "internal/task" @@ -19,30 +22,66 @@ func xTaskGetCurrentTaskHandle() C.TaskHandle_t { return C.TaskHandle_t(task.Current()) } +//export xTaskCreate +func xTaskCreate(pvTaskCode C.TaskFunction_t, pcName *C.char, usStackDepth uintptr, pvParameters unsafe.Pointer, uxPriority C.UBaseType_t, pxCreatedTask *C.TaskHandle_t) C.BaseType_t { + go func() { + C.freertos_callFunction(pvTaskCode, pvParameters) + }() + if pxCreatedTask != nil { + // Code expectes there to be *something*. + var tcb int + *pxCreatedTask = unsafe.Pointer(&tcb) + } + return 1 // pdPASS +} + +//export vTaskDelay +func vTaskDelay(xTicksToDelay C.TickType_t) { + // The default tick rate appears to be 100Hz (10ms per tick). + time.Sleep(time.Duration(xTicksToDelay) * C.portTICK_PERIOD_MS * time.Millisecond) +} + 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 xSemaphoreCreateCounting +func xSemaphoreCreateCounting(uxMaxCount C.UBaseType_t, uxInitialCount C.UBaseType_t) C.SemaphoreHandle_t { + if uxMaxCount != 1 || uxInitialCount != 0 { + println("TODO: xSemaphoreCreateCounting that's not a mutex") + return nil + } + mutex := Semaphore{} + return C.SemaphoreHandle_t(&mutex) +} + //export xSemaphoreCreateRecursiveMutex func xSemaphoreCreateRecursiveMutex() C.SemaphoreHandle_t { var mutex Semaphore - return (C.SemaphoreHandle_t)(unsafe.Pointer(&mutex)) + return (C.SemaphoreHandle_t)(&mutex) } //export vSemaphoreDelete func vSemaphoreDelete(xSemaphore C.SemaphoreHandle_t) { - mutex := (*Semaphore)(unsafe.Pointer(xSemaphore)) + mutex := (*Semaphore)(xSemaphore) if mutex.task != nil { panic("vSemaphoreDelete: still locked") } } +//export xSemaphoreTake +func xSemaphoreTake(xSemaphore C.QueueHandle_t, xTicksToWait C.TickType_t) C.BaseType_t { + mutex := (*Semaphore)(xSemaphore) + mutex.lock.Lock() + return 1 // pdTRUE +} + //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)) + mutex := (*Semaphore)(xMutex) if mutex.task == task.Current() { // Already locked. mutex.count++ @@ -54,9 +93,16 @@ func xSemaphoreTakeRecursive(xMutex C.SemaphoreHandle_t, xTicksToWait C.TickType return 1 // pdTRUE } +//export xSemaphoreGive +func xSemaphoreGive(xSemaphore C.QueueHandle_t) C.BaseType_t { + mutex := (*Semaphore)(xSemaphore) + mutex.lock.Unlock() + return 1 // pdTRUE +} + //export xSemaphoreGiveRecursive func xSemaphoreGiveRecursive(xMutex C.SemaphoreHandle_t) C.BaseType_t { - mutex := (*Semaphore)(unsafe.Pointer(xMutex)) + mutex := (*Semaphore)(xMutex) if mutex.task == task.Current() { // Already locked. mutex.count-- @@ -67,3 +113,44 @@ func xSemaphoreGiveRecursive(xMutex C.SemaphoreHandle_t) C.BaseType_t { } panic("xSemaphoreGiveRecursive: not locked by this task") } + +//export xQueueCreate +func xQueueCreate(uxQueueLength C.UBaseType_t, uxItemSize C.UBaseType_t) C.QueueHandle_t { + return chanMakeUnsafePointer(uintptr(uxItemSize), uintptr(uxQueueLength)) +} + +//export vQueueDelete +func vQueueDelete(xQueue C.QueueHandle_t) { + // TODO: close the channel +} + +//export xQueueReceive +func xQueueReceive(xQueue C.QueueHandle_t, pvBuffer unsafe.Pointer, xTicksToWait C.TickType_t) C.BaseType_t { + // Note: xTicksToWait is ignored. + chanRecvUnsafePointer(xQueue, pvBuffer) + return 1 // pdTRUE +} + +//export xQueueSend +func xQueueSend(xQueue C.QueueHandle_t, pvBuffer unsafe.Pointer, xTicksToWait C.TickType_t) C.BaseType_t { + // Note: xTicksToWait is ignored. + chanSendUnsafePointer(xQueue, pvBuffer) + return 1 // pdTRUE +} + +//export uxQueueMessagesWaiting +func uxQueueMessagesWaiting(xQueue C.QueueHandle_t) C.UBaseType_t { + return C.UBaseType_t(chanLenUnsafePointer(xQueue)) +} + +//go:linkname chanMakeUnsafePointer runtime.chanMakeUnsafePointer +func chanMakeUnsafePointer(elementSize uintptr, bufSize uintptr) unsafe.Pointer + +//go:linkname chanLenUnsafePointer runtime.chanLenUnsafePointer +func chanLenUnsafePointer(ch unsafe.Pointer) int + +//go:linkname chanSendUnsafePointer runtime.chanSendUnsafePointer +func chanSendUnsafePointer(ch, value unsafe.Pointer) + +//go:linkname chanRecvUnsafePointer runtime.chanRecvUnsafePointer +func chanRecvUnsafePointer(ch, value unsafe.Pointer) diff --git a/src/compat/freertos/include/freertos/FreeRTOS.h b/src/compat/freertos/include/freertos/FreeRTOS.h index 3e46754e3d..4758e2fd97 100644 --- a/src/compat/freertos/include/freertos/FreeRTOS.h +++ b/src/compat/freertos/include/freertos/FreeRTOS.h @@ -6,4 +6,6 @@ typedef uint32_t TickType_t; typedef int BaseType_t; typedef unsigned int UBaseType_t; -#define portMAX_DELAY (TickType_t)0xffffffffUL +#define portMAX_DELAY (TickType_t)0xffffffffUL +#define portTICK_PERIOD_MS (10) +#define configMAX_PRIORITIES (25) diff --git a/src/compat/freertos/include/freertos/queue.h b/src/compat/freertos/include/freertos/queue.h index 53d7595461..d50ddc37c6 100644 --- a/src/compat/freertos/include/freertos/queue.h +++ b/src/compat/freertos/include/freertos/queue.h @@ -1,3 +1,10 @@ #pragma once -typedef struct QueueDefinition * QueueHandle_t; +typedef void * QueueHandle_t; + +QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize); +void vQueueDelete(QueueHandle_t xQueue); + +BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); +BaseType_t xQueueSend(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); +UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue); diff --git a/src/compat/freertos/include/freertos/semphr.h b/src/compat/freertos/include/freertos/semphr.h index e394ad771e..672c51b33f 100644 --- a/src/compat/freertos/include/freertos/semphr.h +++ b/src/compat/freertos/include/freertos/semphr.h @@ -1,8 +1,9 @@ #pragma once // Note: in FreeRTOS, SemaphoreHandle_t is an alias for QueueHandle_t. -typedef struct SemaphoreDefinition * SemaphoreHandle_t; +typedef void * SemaphoreHandle_t; +SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void); void vSemaphoreDelete(SemaphoreHandle_t xSemaphore); @@ -10,3 +11,7 @@ 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); + +// Note: these functions are macros in FreeRTOS. +BaseType_t xSemaphoreTake(QueueHandle_t xSemaphore, TickType_t xTicksToWait); +BaseType_t xSemaphoreGive(QueueHandle_t xSemaphore); diff --git a/src/compat/freertos/include/freertos/task.h b/src/compat/freertos/include/freertos/task.h index 76a31228f3..040ee316e2 100644 --- a/src/compat/freertos/include/freertos/task.h +++ b/src/compat/freertos/include/freertos/task.h @@ -1,5 +1,10 @@ #pragma once typedef void * TaskHandle_t; +typedef void (*TaskFunction_t)(void *); TaskHandle_t xTaskGetCurrentTaskHandle(void); + +BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char * const pcName, uintptr_t usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask); + +void vTaskDelay(const TickType_t xTicksToDelay); diff --git a/src/runtime/chan.go b/src/runtime/chan.go index c2da4f05cf..2209d42c6e 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -127,6 +127,10 @@ type channel struct { buf unsafe.Pointer // pointer to first element of buffer } +func chanMakeUnsafePointer(elementSize, bufSize uintptr) unsafe.Pointer { + return unsafe.Pointer(chanMake(elementSize, bufSize)) +} + // chanMake creates a new channel with the given element size and buffer length in number of elements. // This is a compiler intrinsic. func chanMake(elementSize uintptr, bufSize uintptr) *channel { @@ -495,6 +499,11 @@ func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList sender.Ptr = nil } +func chanSendUnsafePointer(ch, value unsafe.Pointer) { + var blockedlist channelBlockedList + chanSend((*channel)(ch), value, &blockedlist) +} + // chanRecv receives a single value over a channel. // It blocks if there is no available value to recieve. // The recieved value is copied into the value pointer. @@ -532,6 +541,11 @@ func chanRecv(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList return ok } +func chanRecvUnsafePointer(ch, value unsafe.Pointer) { + var blockedlist channelBlockedList + chanRecv((*channel)(ch), value, &blockedlist) +} + // chanClose closes the given channel. If this channel has a receiver or is // empty, it closes the channel. Else, it panics. func chanClose(ch *channel) {