Skip to content

Commit 00851bd

Browse files
author
Amanda Butler
authored
Reorganize content
Make changes from #482 to live site.
1 parent cc57611 commit 00851bd

File tree

1 file changed

+37
-229
lines changed

1 file changed

+37
-229
lines changed

docs/reference/api/platform/platform.md

Lines changed: 37 additions & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
## Platform overview
22

3-
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.
44

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.
913
- [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.
1029
- [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.
1130
- [Error](/docs/v5.8/reference/error.html): A functions that generates a fatal runtime error.
1231
- [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.
1532

1633
<h4 id="callbacks">Callbacks</h4>
1734

@@ -38,182 +55,23 @@ Serial serial(USBTX, USBRX);
3855
3956
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.
4057
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?
5659
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.
5861
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.
6063
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.
6265
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.
6467
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-
void dosomething(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-
class Thing {
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
114-
Thing thing1;
115-
adc.attach(Callback<void(int)>(&thing1, &Thing::catinthehat));
116-
117-
// Or we can create a Callback with the callback function to avoid repeating ourselves
118-
Thing thing2;
119-
adc.attach(callback(&thing2, &Thing::catinthehat));
120-
```
121-
122-
Or you can pass the state to a C-style function.
123-
124-
``` c++
125-
struct thing_t {
126-
int state;
127-
}
128-
129-
void catinthehat(thing_t *thing, float f) {
130-
thing->state = // do something
131-
}
132-
133-
// We can create a Callback with the Callback constructor
134-
thing_t thing1;
135-
adc.attach(Callback<void(int)>(catinthehat, &thing1));
136-
137-
// 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>
143-
144-
``` c++
145-
// Does not work
146-
adc.attach(callback(&thing, &Thing::dosomething, &arg));
147-
```
148-
149-
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-
struct dosomething_arguments {
154-
Thing *thing;
155-
int arg1;
156-
int arg2;
157-
};
158-
159-
// Create a function that calls “dosomething” with the arguments
160-
void dosomething_with_arguments(struct dosomething_arguments *args) {
161-
args->thing->dosomething(args->arg1, args->arg2);
162-
}
68+
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.
16369
164-
165-
// Allocate arguments and pass to callback
166-
struct dosomething_arguments args = { &thing, arg1, arg2 };
167-
adc.attach(callback(dosomething_with_arguments, &args)); // yes
168-
```
169-
170-
#### Call callbacks
171-
172-
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-
void callmemaybe(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++.
20971
21072
<h4 id="the-importance-of-state">The importance of state</h4>
21173
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.
21775
21876
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:
21977
@@ -230,9 +88,9 @@ public:
23088
};
23189
```
23290

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.
23492

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:
23694

23795
``` c++
23896
// Here is a small running-average low-pass filter.
@@ -245,18 +103,15 @@ void low_pass_step(float data) {
245103
ADC adc1;
246104
ADC adc2;
247105

248-
// Here we can register the low-pass filter on both ADC modules
249106
int main() {
250-
// Register one low pass filter
251107
adc1.attach(low_pass_step);
252108

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!
255110
adc2.attach(low_pass_step);
256111
}
257112
```
258113
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.
260115
261116
Here’s the low-pass example using an additional argument for state.
262117
@@ -287,60 +142,15 @@ ADC adc2;
287142
float low_pass_result1;
288143
float low_pass_result2;
289144
290-
// Here we can register the low-pass filter on both ADC modules
291145
int main() {
292-
// Register one low pass filter
293146
adc1.attach(low_pass_step, &low_pass_result1);
294147
295148
// Register a second low pass filter, no more issues!
296149
adc2.attach(low_pass_step, &low_pass_result2);
297150
}
298151
```
299152

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.
344154

345155
Here’s the low-pass filter example rewritten to use the callback class:
346156

@@ -371,9 +181,7 @@ ADC adc2;
371181
LowPass low_pass1;
372182
LowPass low_pass2;
373183

374-
// Here we can register the low-pass filter on both ADC modules
375184
int main() {
376-
// Register one low pass filter
377185
adc1.attach(callback(&low_pass1, &LowPass::step));
378186
adc2.attach(callback(&low_pass2, &LowPass::step));
379187
}

0 commit comments

Comments
 (0)