You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The role of the platform modules is to provide a consistent user experience on top of different standard libraries and toolchains. This section consists of the `Callback`, `Wait` and `Time` APIs. This page contains reference material about these subjects. You can also jump straight to the APIs:
3
+
The role of the platform modules is to provide general purpose MCU management infrastructure, a few common data structures and a consistent user experience on top of different standard libraries and toolchains. This page contains reference material about these subjects.
4
4
5
-
-[Wait](/docs/v5.8/reference/wait.html): An API that provides simple wait capabilities.
6
-
-[Callback](/docs/v5.8/reference/callback.html): An API that executes the user’s code in its own context.
7
-
-[DeepSleepLock](/docs/v5.8/reference/deepsleeplock.html): The sleep function for Mbed OS.
8
-
-[Power management](/docs/v5.8/reference/power-management.html): The function that provides an API to control sleep modes.
5
+
### General MCU Management Infrastructure
6
+
7
+
Mbed OS eases MCU management through the use of several scoped locks and several global APIs.
8
+
9
+
The locks, `DeepSleepLock` and `CriticalSectionLock`, use RAII to create a scope within which the appropriate lock is held; These locks acquire operation is their constructor and their release operation is their destructor. This uses core C++ language features, object lifetime and deconstruction on scope exit, to eliminate most resource leaks and reduce program complexity. The `DeepSleepLock` prevents the MCU from deep sleeping while it's alive and the `CriticalSectionLock` prevents preemption while it's alive. As these acquisition of a critical section or a deep sleep lock cannot fail, both of these classes do not raise exceptions.
10
+
11
+
Mbed OS also provides global APIs for the sleep and preemption global resources. The `PowerManagement` module includes a function to go to sleep now and the `Wait` module include a function to preempt now.
12
+
-[Wait](/docs/v5.8/reference/wait.html): An API that provides simple wait capabilities. These wait capabilities are integrated with the RTOS to schedule another thread if the current thread is blocked. If all threads are blocked, the idle thread will save power by putting the MCU to sleep.
9
13
-[CriticalSectionLock](/docs/v5.8/reference/criticalsectionlock.html): An object that establishes the beginning of a critical section and uses RAII to disable and restore interrupt state when the current scope exits.
14
+
-[Power management](/docs/v5.8/reference/power-management.html): An API to control sleep modes. A user of this API configures the sleep states that the MCU enters on idle, when everything is blocked.
15
+
-[DeepSleepLock](/docs/v5.8/reference/deepsleeplock.html): A class that prevents sleep within a scope. For instance, Use this class to prevent the configured sleep mode from interfering with a fast or low latency communication channel.
16
+
17
+
### Common data structures
18
+
19
+
Mbed OS provides the CircularBuffer and ATCmdParser as these are commonly used utilities in embedded systems.
20
+
21
+
-[CircularBuffer](/docs/v5.8/reference/circularbuffer.html): The class that provides APIs to push and pop data from a buffer in an interrupt safe fashion.
22
+
-[ATCmdParser](/docs/v5.8/reference/atcmdparser.html): An Mbed OS compatible AT command parser and serializer.
23
+
24
+
### C++ ergonomics extensions
25
+
26
+
Mbed OS includes a few convenience classes that are tailored for embedded systems development. These are the `Callback`, `Error` and `NonCopyable` classes.
27
+
28
+
-[Callback](/docs/v5.8/reference/callback.html): An API that executes the user’s code in its own context. Many other Mbed OS APIs build on the Callback API by taking a callback to execute.
10
29
-[Time](/docs/v5.8/reference/time.html): A group of functions in the standard library of the C programming language implementing date and time manipulation operations.
11
30
-[Error](/docs/v5.8/reference/error.html): A functions that generates a fatal runtime error.
12
31
-[NonCopyable](/docs/v5.8/reference/noncopyable.html): An API that tags a class as not supporting copy operations. It creates a compile-time error if you copy the object.
13
-
-[CircularBuffer](/docs/v5.8/reference/circularbuffer.html): The class that provides APIs to push and pop data from a buffer
14
-
-[ATCmdParser](/docs/v5.8/reference/atcmdparser.html): An Mbed OS compatible AT command parser.
15
32
16
33
<h4id="callbacks">Callbacks</h4>
17
34
@@ -38,182 +55,23 @@ Serial serial(USBTX, USBRX);
38
55
39
56
The Callback class manages C/C++ function pointers so you don't have to. If you are asking yourself why you should use the Callback class, you should read the [Importance of State](/docs/v5.8/reference/platform.html#the-importance-of-state) section.
40
57
41
-
#### Why should you use Callbacks?
42
-
43
-
Unfortunately, supporting all of the standard C++ function types is difficult.
44
-
45
-
- State is important, so need to support either C-style function pointers with state, or C++ member function pointers.
46
-
47
-
- Stateless callbacks are just as common, but passing a stateless callback as a member function function requires writing a lot of boilerplate code and instantiating an empty class. So we need to also support a standard function pointer.
48
-
49
-
- Another design pattern you may see is the function object, a class that overrides the function call operator. We can expect the user to pass function objects as C++ member function pointers if needed.
50
-
51
-
- A useful C++ feature is the enforcement of const-correctness, but this becomes unfortunately complicated with the state associated with callbacks. A C++ API needs to support both the const and non-const versions of member function pointers.
52
-
53
-
- Another C++ feature is volatile-correctness in case the underlying state must be volatile, but if necessary we can probably expect the user to hide volatile members inside of a non-volatile class.
54
-
55
-
C++ requires a large set of overloads to support all of the standard function types. It is unreasonable to expect a new library author to add all of these overloads to every function that could take in a callback.
58
+
#### Why should you use callbacks?
56
59
57
-
C++ provides the tools to delegate this problem to a single class. This class is the Callback class. The Callback class should be familiar to users of the std::function class that C++11 introduced but is available for older versions of C++.
60
+
Supporting all of the standard C++ function types is difficult for an API developer. An API developer must consider state, C++ Function objects, const correctness and volatile correctness.
58
61
59
-
**An overly-simplified description of the Callback class is that is contains all of this madness so you don’t have to.**
62
+
State is important, so an API developer must support either C-style function pointers with state, or C++ member function pointers. Stateless callbacks are just as common, but passing a stateless callback as a member function function requires writing a lot of boilerplate code and instantiating an empty class. Further, an API developer also must support a standard function pointer.
60
63
61
-
#### Create callbacks
64
+
Another common design pattern is the function object, a class that overrides the function call operator. A user may pass function objects as C++ member function pointers and C++ requires a large set of overloads to support all of the standard function types. It is unreasonable to expect a new library author to add all of these overloads to every function that could take in a callback.
62
65
63
-
First, you need to understand the syntax of the Callback type. The Callback type is a templated type parameterized by a C++ function declaration:
66
+
A useful C++ feature is compile time const-correctness checks, which increases API complexity when combined by callbacks with state. To allow a user to take full advantage of the const-correctness checks, a C++ API must support both the const and non-const versions of member function pointers.
64
67
65
-
``` c++
66
-
// Callback</*return type*/(/*parameters*/)> cb;
67
-
Callback<int(float)> cb; // A callback that takes in a float and returns an int
68
-
Callback<void(float)> cb; // A callback that takes in a float and returns nothing
69
-
Callback<int()> cb; // A callback that takes in nothing and returns an int
70
-
Callback<void(float, float)> cb; // A callback that takes in two floats and returns nothing
71
-
```
72
-
73
-
You can create a Callback directly from a C function or function pointer with the same type:
74
-
75
-
```c++
76
-
voiddosomething(int) {
77
-
// do something
78
-
}
79
-
80
-
Callback<void(int)> cb(dosomething);
81
-
```
82
-
83
-
If an API provides a function that takes in a callback, you can pass in a C function or function pointer with the same type:
84
-
85
-
``` c++
86
-
class ADC {
87
-
// ADC can pass an analog value to the callback
88
-
void attach(Callback<void(float)> cb);
89
-
};
90
-
91
-
void dosomething(float f) {
92
-
// do something
93
-
}
94
-
95
-
ADC adc;
96
-
adc.attach(dosomething);
97
-
```
98
-
99
-
But what about state? The Callback type also supports passing a state pointer for a function. This state can be either a pointer to an object that is passed to a member function, or a pointer passed to a C-style function.
100
-
101
-
Because this form of creating Callbacks requires two arguments, you need to create the Callback explicitly using the Callback constructor. The Callback also comes with the lowercase callback function, which creates callbacks based on the arguments type and avoids the need to repeat the template type.
102
-
103
-
You can create a callback with a member function.
104
-
105
-
```c++
106
-
classThing {
107
-
int state;
108
-
void catinthehat(int i) {
109
-
state = // do something
110
-
}
111
-
}
112
-
113
-
// We can create a Callback with the Callback constructor
// Or we can create a Callback with the callback function to avoid repeating ourselves
138
-
thing_t thing2;
139
-
adc.attach(callback(catinthehat, &thing2));
140
-
```
141
-
142
-
<span class="notes">**Note:** This state is restricted to a single pointer. This means you can’t bind both an object and argument to a callback.</span>
If you need to pass multiple arguments to a callback and you can’t store the arguments in the class, you can create a struct that contains all of the arguments and pass a pointer to that. However, you need to handle the memory allocation yourself.
150
-
151
-
```c++
152
-
// Create a struct that contains all of the state needed for “dosomething”
153
-
structdosomething_arguments {
154
-
Thing *thing;
155
-
int arg1;
156
-
int arg2;
157
-
};
158
-
159
-
// Create a function that calls “dosomething” with the arguments
Another useful C++ feature is volatile-correctness. When volatile-correctness is necessary, we expect that the user hides volatile members inside of a non-volatile class.
Callbacks overload the function call operator, so you can call a Callback like you would a normal function:
173
-
174
-
```c++
175
-
void callme(Callback<void(float)> cb) {
176
-
cb(1.0f);
177
-
}
178
-
```
179
-
180
-
The only thing to watch out for is that the Callback type has a null Callback, just like a null function pointer. Uninitialized callbacks are null and assert if you call them. If you want a call to always succeed, you need to check if it is null first.
181
-
182
-
```c++
183
-
voidcallmemaybe(Callback<void(float)> cb) {
184
-
if (cb) {
185
-
cb(1.0f);
186
-
}
187
-
}
188
-
```
189
-
190
-
The Callback class is what’s known in C++ as a “Concrete Type”. That is, the Callback class is lightweight enough to be passed around like an int, pointer or other primitive type.
191
-
192
-
```c++
193
-
class Thing {
194
-
private:
195
-
Callback<void(int)> _cb;
196
-
197
-
public:
198
-
void attach(Callback<void(int)> cb) {
199
-
_cb = cb
200
-
}
201
-
202
-
void dothething(int arg) {
203
-
If (_cb) {
204
-
_cb(arg);
205
-
}
206
-
}
207
-
}
208
-
```
70
+
C++ provides the tools to delegate this complexity to a single class. This class is the Callback class. The Callback class should be familiar to users of the std::function class that C++11 introduced and is available for older versions of C++.
209
71
210
72
<h4 id="the-importance-of-state">The importance of state</h4>
211
73
212
-
A callback is a user provided function that a user may pass to an API. The callback allows the API to execute the user’s code in its own context. You can find more information on how to use callbacks in the [technical callback documentation](/docs/v5.8/reference/callback.html).
213
-
214
-
##### Why not function pointers?
215
-
216
-
Callbacks have two important pieces of information, the code to execute and the state associated with the callback.
74
+
Callbacks may have two important pieces of information, the code to execute and the state associated with the callback.
217
75
218
76
A common API design mistake is to use a callback type that doesn’t allow a user to attach state to a callback. The most common example of this is a simple C function pointer:
219
77
@@ -230,9 +88,9 @@ public:
230
88
};
231
89
```
232
90
233
-
This API is sufficient for simple applications but falls apart when there are multiple ADC modules available. This problem becomes especially noticeable when a user tries to reuse the same procedure for multiple callbacks.
91
+
This API is sufficient for simple applications, but falls apart when there are multiple ADC modules available. This problem becomes especially noticeable when a user tries to reuse the same procedure for multiple callbacks.
234
92
235
-
For example, consider applying a low-pass filter to two different ADC modules
93
+
For example, consider applying a low-pass filter to two different ADC modules:
236
94
237
95
```c++
238
96
// Here is a small running-average low-pass filter.
// Here we can register the low-pass filter on both ADC modules
249
106
int main() {
250
-
// Register one low pass filter
251
107
adc1.attach(low_pass_step);
252
108
253
-
// Register a second low pass filter
254
-
// Problem! Now both low pass filters are sharing the same state!
109
+
// Problem! Now both low pass filters share the same state!
255
110
adc2.attach(low_pass_step);
256
111
}
257
112
```
258
113
259
-
Without state, callbacks offer very limited composability. In C, you can fix this by adding an additional “state” argument to the function pointer, which allows you to pass in the opaque “state” when you register the callback.
114
+
Without state, callbacks compose poorly. In C, you fix this by adding a "state" argument to the function pointer, and by passing opaque "state" when you register the callback.
260
115
261
116
Here’s the low-pass example using an additional argument for state.
262
117
@@ -287,60 +142,15 @@ ADC adc2;
287
142
float low_pass_result1;
288
143
float low_pass_result2;
289
144
290
-
// Here we can register the low-pass filter on both ADC modules
291
145
int main() {
292
-
// Register one low pass filter
293
146
adc1.attach(low_pass_step, &low_pass_result1);
294
147
295
148
// Register a second low pass filter, no more issues!
296
149
adc2.attach(low_pass_step, &low_pass_result2);
297
150
}
298
151
```
299
152
300
-
One of the core features of C++ is the encapsulation of this “state” in classes, with operations that modify the state being represented as member functions in the class. Unfortunately, member function pointers are not compatible with standard function pointers, but you can rewrite the low-pass example to use member function pointers, allowing you to pass in state as a C++ object.
301
-
302
-
Here’s the low-pass example rewritten to use member function pointers.
303
-
304
-
```c++
305
-
class ADC {
306
-
public:
307
-
// Here, the adc_callback_t type is a function that takes in data
308
-
template <typename T>
309
-
typedef void (T::*adc_callback_t)(float data);
310
-
311
-
312
-
// In this example, the ADC read function calls the user-provided callback
313
-
// when data is available.
314
-
template <typename T>
315
-
void attach(T *obj, adc_callback_t<T> cb);
316
-
};
317
-
318
-
class LowPass {
319
-
float result;
320
-
321
-
public:
322
-
// Move the low pass filter implementation to the ADC module
323
-
void step(float data) {
324
-
result = result*0.99 + data*0.01;
325
-
}
326
-
};
327
-
328
-
329
-
// Our two adc modules
330
-
ADC adc1;
331
-
ADC adc2;
332
-
333
-
// Our two low-pass filters
334
-
LowPass low_pass1;
335
-
LowPass low_pass2;
336
-
337
-
// Here we can register the low-pass filter on both ADC modules
338
-
int main() {
339
-
// Register one low pass filter
340
-
adc1.attach(&low_pass1, &LowPass::step);
341
-
adc2.attach(&low_pass2, &LowPass::step);
342
-
}
343
-
```
153
+
One of the core features of C++ is the encapsulation of this "state" in classes, with operations that modify the state being represented as member functions in the class. Member function pointers are not compatible with standard function pointers. The Callback class allows API authors to implement a single interface that accepts a callback, and the user may provide a C function and state or C++ member function and object without special consideration by the API author.
344
154
345
155
Here’s the low-pass filter example rewritten to use the callback class:
346
156
@@ -371,9 +181,7 @@ ADC adc2;
371
181
LowPass low_pass1;
372
182
LowPass low_pass2;
373
183
374
-
// Here we can register the low-pass filter on both ADC modules
0 commit comments