Skip to content

Commit

Permalink
cgo: add more FreeRTOS compatibility
Browse files Browse the repository at this point in the history
This commit implements:

  * xTaskCreate
  * vTaskDelay
  * xSemaphoreCreateCounting (partially)
  * xSemaphoreTake
  * xSemaphoreGive
  * xQueueCreate
  * vQueueDelete
  * xQueueReceive
  * xQueueSend
  * uxQueueMessagesWaiting
  • Loading branch information
aykevl committed Sep 29, 2021
1 parent dcfa42c commit 853df1f
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 7 deletions.
95 changes: 91 additions & 4 deletions src/compat/freertos/freertos.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
package freertos

// #include <freertos/FreeRTOS.h>
// #include <freertos/queue.h>
// #include <freertos/semphr.h>
// #include <freertos/task.h>
// void freertos_callFunction(void (*function)(void *), void *parameter);
import "C"
import (
"sync"
"time"
"unsafe"

"internal/task"
Expand All @@ -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++
Expand All @@ -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--
Expand All @@ -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)
4 changes: 3 additions & 1 deletion src/compat/freertos/include/freertos/FreeRTOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
9 changes: 8 additions & 1 deletion src/compat/freertos/include/freertos/queue.h
Original file line number Diff line number Diff line change
@@ -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);
7 changes: 6 additions & 1 deletion src/compat/freertos/include/freertos/semphr.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#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);

// 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);
5 changes: 5 additions & 0 deletions src/compat/freertos/include/freertos/task.h
Original file line number Diff line number Diff line change
@@ -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);
14 changes: 14 additions & 0 deletions src/runtime/chan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 853df1f

Please sign in to comment.