-
Notifications
You must be signed in to change notification settings - Fork 1
/
static_rtos.h
226 lines (188 loc) · 6.3 KB
/
static_rtos.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
* Wrappers for creating static freeRTOS objects and some
* other convenience functions.
* Note that these don't have destructors because the intended
* use case is to keep these alive for the lifetime of the program.
*/
#pragma once
#include "FreeRTOS.h"
#include "catch_errors.h"
#include "cmsis_os.h"
#include "event_groups.h"
#include "interfaces.h"
#include "message_buffer.h"
#include "queue.h"
#include "semphr.h"
#include "stream_buffer.h"
#include "task.h"
// ------- Chapter 2: Task -----------
/*
* Constructor has near-identical API as xTaskCreate()
* Differences are:
* A non-void argument type for "func" may be specified (via TArg) to improve type safety
* Stack depth is passed via template parameter
* - Note that this represents the number of WORDS used for stack storage.
* Task function parameters and priority are optional (uses defaults if omitted)
* Handle is stored within the object, so no need to create this ahead of time to pass in.
* Handle is retrieved via .handle
*/
template<typename TArg = void, uint32_t TDepth = configMINIMAL_STACK_SIZE * 2>
class StaticTask
{
public:
StaticTask(const char* const name, // task name
void (*func)(TArg*), // function to run
TArg* const params = nullptr, // function arguments
UBaseType_t priority = osPriorityNormal // task priority
)
: handle{ xTaskCreateStatic((TaskFunction_t)func, name, TDepth, params, priority, stack, &taskData) }
{} // No body in constructor
const TaskHandle_t handle; // the task handle
private:
StackType_t stack[TDepth]; // Static storage for task stack
StaticTask_t taskData; // Static storage for task bookkeeping data
};
// Convenience wrappers for xTaskNotifyFromISR
// Setting bits
inline void isrTaskNotifyBits(TaskHandle_t task, uint32_t bits)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(task, bits, eSetBits, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// Increment
inline void isrTaskNotifyIncrement(TaskHandle_t task)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// second argument is unused
xTaskNotifyFromISR(task, 42, eIncrement, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// ------- Chapter 3: Queue -----------
// Provide the element type and the number of elements to store in the queue
template<typename T, size_t TLen = 16>
class StaticQueue
{
public:
StaticQueue()
: handle{ xQueueCreateStatic(TLen, sizeof(T), queueBuf, &staticQ) }
{
// Todo - Assign human-readable name as a debugging aid
vQueueAddToRegistry(handle, "todoQueueName");
}
const QueueHandle_t handle; // the message buffer handle
private:
uint8_t queueBuf[TLen * sizeof(T)]; // storage for queue
StaticQueue_t staticQ; // static storage for bookkeeping data
};
// ------- Chapter 4: Semaphore -----------
class StaticMutex
{
public:
StaticMutex()
: handle{ xSemaphoreCreateMutexStatic(&staticSemaphore) }
{
// Todo - Assign human-readable name as a debugging aid
vQueueAddToRegistry(handle, "todoMutexName");
}
const SemaphoreHandle_t handle; // the mutex / semaphore handle
private:
StaticSemaphore_t staticSemaphore; // static storage for mutex / semaphore
};
// Enables scoped locking (i.e. never forgetting to unlock a mutex).
// May provide non-maximum timeout and then call gotLock() to check if
// lock was successfully acquired.
// Note - create recursive and from-isr versions as needed
class ScopedLock
{
public:
// Blocks forever while waiting for mutex
ScopedLock(StaticMutex& mutex, TickType_t ticks = portMAX_DELAY)
: mutex{ mutex }
{
locked = xSemaphoreTake(mutex.handle, ticks);
}
~ScopedLock()
{
if (locked) {
xSemaphoreGive(mutex.handle);
}
}
bool gotLock() { return locked; }
private:
StaticMutex& mutex;
bool locked;
};
// ------- Chapter 5: Timer -----------
// ------- Chapter 6: Event Groups -----------
class StaticEventGroup
{
public:
StaticEventGroup()
: handle{ xEventGroupCreateStatic(&staticEventGroup) }
{}
const EventGroupHandle_t handle;
private:
StaticEventGroup_t staticEventGroup;
};
// ------- Chapter 7: Kernel config - skip -----------
// ------- Chapter 8: Stream Buffer -----------
template<size_t TSize = 1024>
class StaticStreamBuffer
: public Readable
, public Writable
{
public:
StaticStreamBuffer()
: handle{ xStreamBufferCreateStatic(TSize,
1, // trigger level. Unblock as soon as any bytes are available
mbStorage,
&staticMb) }
{} // No body in constructor
size_t write(const void* buf, size_t len, TickType_t ticks) //
{
return xStreamBufferSend(handle, buf, len, ticks);
}
size_t read(void* buf, size_t len, TickType_t ticks) //
{
return xStreamBufferReceive(handle, buf, len, ticks);
}
const StreamBufferHandle_t handle; // the message buffer handle
private:
uint8_t mbStorage[TSize + 1]; // storage for message buffer, must contain an additional byte
StaticStreamBuffer_t staticMb; // static storage for bookkeeping data
};
// ------- Chapter 9: Message Buffer -----------
template<size_t TSize = 1024>
class StaticMessageBuffer
: public Readable
, public Writable
{
public:
StaticMessageBuffer()
: handle{ xMessageBufferCreateStatic(TSize, mbStorage, &staticMb) }
{} // No body in constructor
size_t write(const void* buf, size_t len, TickType_t ticks) //
{
return xMessageBufferSend(handle, buf, len, ticks);
}
size_t read(void* buf, size_t len, TickType_t ticks)
{
// Attempt to get next message
size_t retLen = xMessageBufferReceive(handle, buf, len, ticks);
// Check if zero returned because next message is too big to fit in buffer
size_t nextLen = nextLengthBytes();
if (retLen == 0 && len < nextLen) {
critical();
}
return retLen;
}
size_t nextLengthBytes() //
{
return xMessageBufferNextLengthBytes(handle);
}
const MessageBufferHandle_t handle; // the message buffer handle
private:
uint8_t mbStorage[TSize + 1]; // storage for message buffer, must contain an additional byte
StaticMessageBuffer_t staticMb; // static storage for bookkeeping data
};