Skip to content

Commit 3fecf31

Browse files
committed
cgo: add more FreeRTOS compatibility
This commit implements: * xTaskCreate * vTaskDelay * xSemaphoreCreateCounting (partially) * xSemaphoreTake * xSemaphoreGive * xQueueCreate * vQueueDelete * xQueueReceive * xQueueSend * uxQueueMessagesWaiting
1 parent dcfa42c commit 3fecf31

File tree

6 files changed

+127
-7
lines changed

6 files changed

+127
-7
lines changed

src/compat/freertos/freertos.go

+91-4
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
package freertos
55

66
// #include <freertos/FreeRTOS.h>
7+
// #include <freertos/queue.h>
78
// #include <freertos/semphr.h>
89
// #include <freertos/task.h>
10+
// void freertos_callFunction(void (*function)(void *), void *parameter);
911
import "C"
1012
import (
1113
"sync"
14+
"time"
1215
"unsafe"
1316

1417
"internal/task"
@@ -19,30 +22,66 @@ func xTaskGetCurrentTaskHandle() C.TaskHandle_t {
1922
return C.TaskHandle_t(task.Current())
2023
}
2124

25+
//export xTaskCreate
26+
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 {
27+
go func() {
28+
C.freertos_callFunction(pvTaskCode, pvParameters)
29+
}()
30+
if pxCreatedTask != nil {
31+
// Code expectes there to be *something*.
32+
var tcb int
33+
*pxCreatedTask = unsafe.Pointer(&tcb)
34+
}
35+
return 1 // pdPASS
36+
}
37+
38+
//export vTaskDelay
39+
func vTaskDelay(xTicksToDelay C.TickType_t) {
40+
// The default tick rate appears to be 100Hz (10ms per tick).
41+
time.Sleep(time.Duration(xTicksToDelay) * C.portTICK_PERIOD_MS * time.Millisecond)
42+
}
43+
2244
type Semaphore struct {
2345
lock sync.Mutex // the lock itself
2446
task *task.Task // the task currently locking this semaphore
2547
count uint32 // how many times this semaphore is locked
2648
}
2749

50+
//export xSemaphoreCreateCounting
51+
func xSemaphoreCreateCounting(uxMaxCount C.UBaseType_t, uxInitialCount C.UBaseType_t) C.SemaphoreHandle_t {
52+
if uxMaxCount != 1 || uxInitialCount != 0 {
53+
println("TODO: xSemaphoreCreateCounting that's not a mutex")
54+
return nil
55+
}
56+
mutex := Semaphore{}
57+
return C.SemaphoreHandle_t(&mutex)
58+
}
59+
2860
//export xSemaphoreCreateRecursiveMutex
2961
func xSemaphoreCreateRecursiveMutex() C.SemaphoreHandle_t {
3062
var mutex Semaphore
31-
return (C.SemaphoreHandle_t)(unsafe.Pointer(&mutex))
63+
return (C.SemaphoreHandle_t)(&mutex)
3264
}
3365

3466
//export vSemaphoreDelete
3567
func vSemaphoreDelete(xSemaphore C.SemaphoreHandle_t) {
36-
mutex := (*Semaphore)(unsafe.Pointer(xSemaphore))
68+
mutex := (*Semaphore)(xSemaphore)
3769
if mutex.task != nil {
3870
panic("vSemaphoreDelete: still locked")
3971
}
4072
}
4173

74+
//export xSemaphoreTake
75+
func xSemaphoreTake(xSemaphore C.QueueHandle_t, xTicksToWait C.TickType_t) C.BaseType_t {
76+
mutex := (*Semaphore)(xSemaphore)
77+
mutex.lock.Lock()
78+
return 1 // pdTRUE
79+
}
80+
4281
//export xSemaphoreTakeRecursive
4382
func xSemaphoreTakeRecursive(xMutex C.SemaphoreHandle_t, xTicksToWait C.TickType_t) C.BaseType_t {
4483
// TODO: implement xTickToWait, or at least when xTicksToWait equals 0.
45-
mutex := (*Semaphore)(unsafe.Pointer(xMutex))
84+
mutex := (*Semaphore)(xMutex)
4685
if mutex.task == task.Current() {
4786
// Already locked.
4887
mutex.count++
@@ -54,9 +93,16 @@ func xSemaphoreTakeRecursive(xMutex C.SemaphoreHandle_t, xTicksToWait C.TickType
5493
return 1 // pdTRUE
5594
}
5695

96+
//export xSemaphoreGive
97+
func xSemaphoreGive(xSemaphore C.QueueHandle_t) C.BaseType_t {
98+
mutex := (*Semaphore)(xSemaphore)
99+
mutex.lock.Unlock()
100+
return 1 // pdTRUE
101+
}
102+
57103
//export xSemaphoreGiveRecursive
58104
func xSemaphoreGiveRecursive(xMutex C.SemaphoreHandle_t) C.BaseType_t {
59-
mutex := (*Semaphore)(unsafe.Pointer(xMutex))
105+
mutex := (*Semaphore)(xMutex)
60106
if mutex.task == task.Current() {
61107
// Already locked.
62108
mutex.count--
@@ -67,3 +113,44 @@ func xSemaphoreGiveRecursive(xMutex C.SemaphoreHandle_t) C.BaseType_t {
67113
}
68114
panic("xSemaphoreGiveRecursive: not locked by this task")
69115
}
116+
117+
//export xQueueCreate
118+
func xQueueCreate(uxQueueLength C.UBaseType_t, uxItemSize C.UBaseType_t) C.QueueHandle_t {
119+
return chanMakeUnsafePointer(uintptr(uxItemSize), uintptr(uxQueueLength))
120+
}
121+
122+
//export vQueueDelete
123+
func vQueueDelete(xQueue C.QueueHandle_t) {
124+
// Nothing to do. The garbage collector will clean up the queue.
125+
}
126+
127+
//export xQueueReceive
128+
func xQueueReceive(xQueue C.QueueHandle_t, pvBuffer unsafe.Pointer, xTicksToWait C.TickType_t) C.BaseType_t {
129+
// Note: xTicksToWait is ignored.
130+
chanRecvUnsafePointer(xQueue, pvBuffer)
131+
return 1 // pdTRUE
132+
}
133+
134+
//export xQueueSend
135+
func xQueueSend(xQueue C.QueueHandle_t, pvBuffer unsafe.Pointer, xTicksToWait C.TickType_t) C.BaseType_t {
136+
// Note: xTicksToWait is ignored.
137+
chanSendUnsafePointer(xQueue, pvBuffer)
138+
return 1 // pdTRUE
139+
}
140+
141+
//export uxQueueMessagesWaiting
142+
func uxQueueMessagesWaiting(xQueue C.QueueHandle_t) C.UBaseType_t {
143+
return C.UBaseType_t(chanLenUnsafePointer(xQueue))
144+
}
145+
146+
//go:linkname chanMakeUnsafePointer runtime.chanMakeUnsafePointer
147+
func chanMakeUnsafePointer(elementSize uintptr, bufSize uintptr) unsafe.Pointer
148+
149+
//go:linkname chanLenUnsafePointer runtime.chanLenUnsafePointer
150+
func chanLenUnsafePointer(ch unsafe.Pointer) int
151+
152+
//go:linkname chanSendUnsafePointer runtime.chanSendUnsafePointer
153+
func chanSendUnsafePointer(ch, value unsafe.Pointer)
154+
155+
//go:linkname chanRecvUnsafePointer runtime.chanRecvUnsafePointer
156+
func chanRecvUnsafePointer(ch, value unsafe.Pointer)

src/compat/freertos/include/freertos/FreeRTOS.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ typedef uint32_t TickType_t;
66
typedef int BaseType_t;
77
typedef unsigned int UBaseType_t;
88

9-
#define portMAX_DELAY (TickType_t)0xffffffffUL
9+
#define portMAX_DELAY (TickType_t)0xffffffffUL
10+
#define portTICK_PERIOD_MS (10)
11+
#define configMAX_PRIORITIES (25)
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
#pragma once
22

3-
typedef struct QueueDefinition * QueueHandle_t;
3+
typedef void * QueueHandle_t;
4+
5+
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
6+
void vQueueDelete(QueueHandle_t xQueue);
7+
8+
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
9+
BaseType_t xQueueSend(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
10+
UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue);
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
#pragma once
22

33
// Note: in FreeRTOS, SemaphoreHandle_t is an alias for QueueHandle_t.
4-
typedef struct SemaphoreDefinition * SemaphoreHandle_t;
4+
typedef void * SemaphoreHandle_t;
55

6+
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
67
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void);
78

89
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);
910

1011
// Note: these two functions are macros in FreeRTOS.
1112
BaseType_t xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex, TickType_t xTicksToWait);
1213
BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex);
14+
15+
// Note: these functions are macros in FreeRTOS.
16+
BaseType_t xSemaphoreTake(QueueHandle_t xSemaphore, TickType_t xTicksToWait);
17+
BaseType_t xSemaphoreGive(QueueHandle_t xSemaphore);
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#pragma once
22

33
typedef void * TaskHandle_t;
4+
typedef void (*TaskFunction_t)(void *);
45

56
TaskHandle_t xTaskGetCurrentTaskHandle(void);
7+
8+
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char * const pcName, uintptr_t usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask);
9+
10+
void vTaskDelay(const TickType_t xTicksToDelay);

src/runtime/chan.go

+14
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ type channel struct {
127127
buf unsafe.Pointer // pointer to first element of buffer
128128
}
129129

130+
func chanMakeUnsafePointer(elementSize, bufSize uintptr) unsafe.Pointer {
131+
return unsafe.Pointer(chanMake(elementSize, bufSize))
132+
}
133+
130134
// chanMake creates a new channel with the given element size and buffer length in number of elements.
131135
// This is a compiler intrinsic.
132136
func chanMake(elementSize uintptr, bufSize uintptr) *channel {
@@ -495,6 +499,11 @@ func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList
495499
sender.Ptr = nil
496500
}
497501

502+
func chanSendUnsafePointer(ch, value unsafe.Pointer) {
503+
var blockedlist channelBlockedList
504+
chanSend((*channel)(ch), value, &blockedlist)
505+
}
506+
498507
// chanRecv receives a single value over a channel.
499508
// It blocks if there is no available value to recieve.
500509
// The recieved value is copied into the value pointer.
@@ -532,6 +541,11 @@ func chanRecv(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList
532541
return ok
533542
}
534543

544+
func chanRecvUnsafePointer(ch, value unsafe.Pointer) {
545+
var blockedlist channelBlockedList
546+
chanRecv((*channel)(ch), value, &blockedlist)
547+
}
548+
535549
// chanClose closes the given channel. If this channel has a receiver or is
536550
// empty, it closes the channel. Else, it panics.
537551
func chanClose(ch *channel) {

0 commit comments

Comments
 (0)