FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
future Namespace Reference

Contains the API around Future implementation. More...

Classes

class  AbstractFakeFuture
 Base class for all FakeFutures. More...
 
class  AbstractFuture
 Base class for all Futures. More...
 
class  AbstractFuturesGroup
 Abstract class to allow aggregation of several futures. More...
 
class  FakeFuture
 Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future. More...
 
class  Future
 Represent a value to be obtained, in some asynchronous way, in the future. More...
 

Enumerations

enum class  FutureStatus : uint8_t {
  NOT_READY = 0 ,
  READY ,
  ERROR ,
  INVALID
}
 Status of a Future. More...
 
enum class  FutureNotification : uint8_t {
  NONE = 0 ,
  STATUS = 1 ,
  OUTPUT = 2 ,
  BOTH = 3
}
 Notification(s) dispatched by a Future. More...
 

Detailed Description

Contains the API around Future implementation.

A Future allows you to pass and get values across different units of executions (threads, or more likely on AVR MCU, the main program and an ISR).

Concepts applied in this API:

  • A Future holds a buffer for a future "output" value (any type, even void, i.e. no value)
  • A Future may also hold a storage "input" value (constant, any type) with same lifetime as the Future
  • A Future is either:
    • Not ready: its value has not been obtained yet (initial status)
    • Ready: its value has been fully set and not yet read by anyone
    • Error: an error occurred in the provider, hence no value will ever be held by this Future, the actual error has not yet been read by anyone
  • Output value providers must hold a reference (or pointer) to the Future they need to fill
  • Storage input value consumers must hold a reference (or pointer) to the Future in order to get its storage value
  • It is possible to subclass a Future to add last minute transformation on Future.get() method

There are two hierarchies of futures:

The main difference is that fake futures must be filled in immediately (not piece after piece, e.g. through an ISR).

In general you won't need fake futures in your program, but these exist to fit some FastArduino API (I2C) that can work in either asynchronous or synchronous mode. In synchronous mode, the cost of "real futures" (code size and execution speed) is not needed, but in order to fulfill internal requirements to work with a future API, we have implemented fake futures too, with the same API as real ones.

Futures can be listened to through a special, virtual-free, mechanism. Futures can send notfications to dedicated listeners. There are 2 kinds of notifications that a future may dispatch:

Listeners to future notification are instances of classes that must:

  1. Call interrupt::register_handler() at construction time and interrupt::unregister_handler() at destruction time
  2. Must be registered statically with REGISTER_FUTURE_STATUS_LISTENERS(), REGISTER_FUTURE_OUTPUT_LISTENERS() or both (if they want to be notified of both kinds of notifications)
  3. Have a on_status_change(const F&, FutureStatus) or on_output_change(const F&) methods (F is either AbstractFuture or AbstractFakeFuture, based on which future ind you want to use)
  4. These methods must either be public in the class or, if not, the class must use DECL_FUTURE_LISTENERS_FRIEND in its definition, so that FastArduino notification dispatch mechanism can call those methods
Warning
Only one instance can exist for each listener class at a given time; behavior is undefined if several instances exist at the same time.
All listeners receive all notifications coming from all futures having notification enabled. Hence any listener callback method shall start by checking the passed future reference is of interest or not, then act accordingly.
All listener classes must be registered statically at the same time, with a single call to REGISTER_FUTURE_STATUS_LISTENERS() (resp. REGISTER_FUTURE_OUTPUT_LISTENERS). Doing otherwise will result in link errors.
If you use futures in your program but do not need notifications (of one or both kinds), you still need to use REGISTER_FUTURE_STATUS_NO_LISTENERS(), REGISTER_FUTURE_OUTPUT_NO_LISTENERS() or REGISTER_FUTURE_NO_LISTENERS(). Doing otherwise will result in a link failure.
Note
FastArduino I2C API is based on futures, thus the previous warnings apply when you use I2C in your program.

Here is a simple usage example of this API, using PCINT0 interrupt to take a "snapshot" of 6 input buttons connected to all PORTB pins, after one of them has changed level:

// PCINT0 ISR
class ButtonsSnapshot {
public:
ButtonsSnapshot() : port_{0x3F, 0x3F} {
signal_.set_enable_pins(0x3F);
signal_.enable();
}
bool get_snapshot(uint8_t& snapshot) {
// Wait for future result
bool result = future_.get(snapshot);
// Reset future
future_.reset_();
return result;
}
private:
void take_snapshot() {
future_.set_future_value_(port_.get_PIN());
}
Future<uint8_t> future_;
DECL_PCINT_ISR_FRIENDS
};
REGISTER_PCI_ISR_METHOD(PCINT, ButtonsSnapshot, &ButtonsSnapshot::take_snapshot, board::InterruptPin::D8_PB0_PCI0)
int main() {
// Enable interrupts at startup time
sei();
// Initialize PORT and PCI through ButtonsSnapshot
ButtonsSnapshot snapshot_taker;
while (true) {
// Wait for the future to be filled in by the PCINT0 ISR
uint8_t snapshot = 0;
if (snapshot_taker.get_snapshot(snapshot)) {
// Do something with the obtained snapshot
}
}
}
API that manipulates a whole digital IO port.
Definition: gpio.h:204
Handler of a Pin Change Interrupt vector.
Definition: pci.h:177
static void init()
Performs special initialization for the target MCU.
Definition: empty.h:43
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:185
#define REGISTER_PCI_ISR_METHOD(PCI_NUM, HANDLER, CALLBACK, PIN,...)
Register the necessary ISR (Interrupt Service Routine) for a Pin Change Interrupt vector.
Definition: pci.h:44

Enumeration Type Documentation

◆ FutureStatus

enum class future::FutureStatus : uint8_t
strong

Status of a Future.

A Future follows a strict lifecycle by passing through the various statuses defined here.

See also
Future
Enumerator
NOT_READY 

The status of a Future immediately after it has been constructed.

The Future will keep this status until:

  • either its output value provider has fully filled its value (then its status will become READY)
  • or its output value provider has reported an error to it (then its status will become ERROR)
See also
Future.set_future_value_()
Future.set_future_finish()
Future.set_future_error()
READY 

The status of a Future once its output value has been fully set by a provider.

See also
Future.set_future_value()
Future.set_future_finish()
Future.get()
ERROR 

The status of a Future once a value provider has reported an error to it.

See also
Future.set_future_error()
Future.error()
INVALID 

The status of a Future that has been moved, if it was NOT_READY before moving.

Definition at line 320 of file future.h.

◆ FutureNotification

enum class future::FutureNotification : uint8_t
strong

Notification(s) dispatched by a Future.

This is passed to Future constructor and detrmines whether the instantiated Future will dispatch of its own notification changes.

Enumerator
NONE 

No notification is dispatched by the Future.

STATUS 

Notification is dispatched whenever the Future status changes.

OUTPUT 

Notification is dispatched whenever the Future output buffer gets filled, even partly.

BOTH 

Notification is dispatched whenever the Future status changes or the Future output buffer gets filled, even partly.

Definition at line 404 of file future.h.