Callback
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.
This is the technical reference for callbacks. You should read the Callbacks section of the Platform Overview first for deeper insight into their use.
Calling callbacks
Callbacks overload the function call operator, so you can call a Callback like you would a normal function:
void run_timer_event(Callback<void(float)> on_timer) {
on_timer(1.0f);
}
The only thing to watch out for is that the Callback type has an empty Callback, just like a null function pointer. Default initialized callbacks are empty and assert if you call them. If a callback may be empty, you need to check if it is empty before calling it.
void run_timer_event(Callback<void(float)> on_timer) {
if (on_timer) {
on_timer(1.0f);
}
}
You can reset Callbacks to empty by assigning nullptr
.
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.
Callback class reference
Serial passthrough example with callbacks
#include "mbed.h"
RawSerial pc(USBTX, USBRX);
RawSerial dev(D1, D0);
DigitalOut led1(LED1);
DigitalOut led4(LED4);
void dev_recv()
{
led1 = !led1;
while(dev.readable()) {
pc.putc(dev.getc());
}
}
void pc_recv()
{
led4 = !led4;
while(pc.readable()) {
dev.putc(pc.getc());
}
}
int main()
{
pc.baud(9600);
dev.baud(9600);
pc.attach(&pc_recv, Serial::RxIrq);
dev.attach(&dev_recv, Serial::RxIrq);
while(1) {
sleep();
}
}
Thread example with callbacks
The Callback API provides a convenient way to pass arguments to spawned threads. This example uses a C function pointer in the Callback.
#include "mbed.h"
Thread thread;
DigitalOut led1(LED1);
volatile bool running = true;
// Blink function toggles the led in a long running loop
void blink(DigitalOut *led) {
while (running) {
*led = !*led;
wait(1);
}
}
// Spawns a thread to run blink for 5 seconds
int main() {
thread.start(callback(blink, &led1));
wait(5);
running = false;
thread.join();
}
Sonar example
Here is an example that uses everything discussed in the introduction to callbacks document in the form of a minimal Sonar class. This example uses a C++ class and method in the Callback.
#include "mbed.h"
/**
* Sonar class for the HC-SR04
*/
class Sonar {
DigitalOut trigger;
InterruptIn echo; // calls a callback when a pin changes
Timer timer;
Timeout timeout; // calls a callback once when a timeout expires
Ticker ticker; // calls a callback repeatedly with a timeout
int32_t begin;
int32_t end;
float distance;
public:
/**
* Sonar constructor
* Creates a sonar object on a set of provided pins
* @param trigger_pin Pin used to trigger reads from the sonar device
* @param echo_pin Pin used to receive the sonar's distance measurement
*/
Sonar(PinName trigger_pin, PinName echo_pin) : trigger(trigger_pin), echo(echo_pin) {
trigger = 0;
distance = -1;
echo.rise(callback(this, &Sonar::echo_in)); // Attach handler to the rising interruptIn edge
echo.fall(callback(this, &Sonar::echo_fall)); // Attach handler to the falling interruptIn edge
}
/**
* Start the background task to trigger sonar reads every 100ms
*/
void start(void) {
ticker.attach(callback(this, &Sonar::background_read), 0.01f);
}
/**
* Stop the background task that triggers sonar reads
*/
void stop(void) {
ticker.detach();
}
/**
* Interrupt pin rising edge interrupt handler. Reset and start timer
*/
void echo_in(void) {
timer.reset();
timer.start();
begin = timer.read_us();
}
/**
* Interrupt pin falling edge interrupt handler. Read and disengage timer.
* Calculate raw echo pulse length
*/
void echo_fall(void) {
end = timer.read_us();
timer.stop();
distance = end - begin;
}
/**
* Wrapper function to set the trigger pin low. Callbacks cannot take in both object and argument pointers.
* See use of this function in background_read().
*/
void trigger_toggle(void) {
trigger = 0;
}
/**
* Background callback task attached to the periodic ticker that kicks off sonar reads
*/
void background_read(void) {
trigger = 1;
timeout.attach(callback(this, &Sonar::trigger_toggle), 10.0e-6);
}
/**
* Public read function that returns the scaled distance result in cm
*/
float read(void) {
return distance / 58.0f;
}
};
int main() {
// Create sonar object on pins D5 and D6
Sonar sonar(D5, D6);
// Begin background thread sonar acquires
sonar.start();
while(1) {
wait(0.1f);
// Periodically print results from sonar object
printf("%f\r\n", sonar.read());
}
}