Common Application Framework overview

Common Application Framework (CAF) is a set of ready-for-use modules and events built on top of Event Manager. Using CAF allows you to have a consistent event-based architecture in your application.

You can check the Common Application Framework preview for a demonstration of how to add ready-for-use and custom CAF modules into an application.

Architecture

In an event-based application, parts of the application functionality are separated into isolated modules that communicate with each other using Event Manager’s events. These events are defined either by CAF or by the application. They are submitted by modules and other modules can subscribe and react to them.

Common Application Framework architecture example

Common Application Framework architecture example

Every CAF module can use additional libraries or drivers. The drivers can be used to communicate with hardware. The module can then broadcast information from the driver using events (for example, the buttons module can submit a button_event on a button press). It can also forward information from application to the driver (for example, the LEDs module can display a given LED effect upon receiving led_event).

In your application, you can use any number of CAF modules together with your own custom modules. Custom modules can use both CAF and custom events. The figure shows an example application that uses one CAF module and one custom module, which has one custom event.

Enabling CAF

To enable CAF, you need to enable the required Kconfig option and enable and initialize Event Manager. You then must submit the first module_state_event, because CAF modules are initialized when they receive a module_state_event that reports MODULE_STATE_READY of the module main.

complete the following steps:

  1. Enable CONFIG_CAF Kconfig option in your project configuration file.

  2. Enable and initialize Event Manager. See Configuration for more details.

  3. Submit the first module_state_event:

    1. Add the following in your main.c file:

      #define MODULE main
      #include <caf/events/module_state_event.h>
      
    2. Call the following function after Event Manager is initialized:

      module_set_state(MODULE_STATE_READY);
      

      This function call submits the required module_state_event.

    For an example implementation, see applications/nrf_desktop/src/main.c.

CAF modules

CAF supports a set of predefined modules. Each of these modules is available for use out of the box and needs to be enabled and configured separately.

There is no limit to the number of modules and events that can be used. However, Event Manager sets the limit of event types in an application to 32, and CAF inherits this limitation.

Configuration of CAF modules

Each module must be configured separately. When configuring CAF modules, you will be asked to use the following configuration methods:

  • Edit Devicetree Specification (DTS) files - These files reflect the hardware configuration. See Devicetree Guide for more information about the DTS data structure.

  • Edit _def files - These files contain configuration arrays for the application modules and are specific to CAF.

  • Select Kconfig options or modify Kconfig files, or both - These reflect the software configuration. See Kconfig - Tips and Best Practices for information about how to configure them.

CAF modules can use all or some of these methods. For example, enabling the CAF: Bluetooth LE advertising module requires enabling Kconfig options and creating a configuration file, while CAF: Bluetooth LE state module can be configured using only Kconfig options.

Adding custom modules

As part of your application, you can add your own custom modules. These modules can communicate using Event Manager’s events. However, if you want to add custom modules that communicate with CAF modules using CAF events, you must make sure that they meet the following requirements:

  • A custom module must register as Event Manager’s listener and subscribe for CAF events that should be handled by that custom module. You can subscribe for a CAF event in the same way as you subscribe for any other Event Manager event. See the Registering a module as listener documentation for instructions about how to configure this.

  • The module must work with module_state_event. It must submit it and react to it.

Note

If you want a module to react to a CAF event, check the event’s documentation for information about the event.

CAF events

Listed below are all available CAF events grouped by module, including details about events and how to handle them.

CAF Bluetooth LE common events

Header file: include/caf/events/ble_common_event.h
Source file: subsys/caf/events/ble_common_event.c
group caf_ble_common_event

CAF Bluetooth LE Common Event.

Enums

enum peer_state

Peer states.

State of the Bluetooth connected peer.

Values:

enumerator PEER_STATE_DISCONNECTED

Bluetooth stack disconnected from the remote peer.

enumerator PEER_STATE_DISCONNECTING

An application module called bt_conn_disconnect() to disconnect the remote peer. This state can be reported by the module that requests peer disconnection to let other application modules prepare for the planned disconnection.

enumerator PEER_STATE_CONNECTED

Bluetooth stack successfully connected to the remote peer.

enumerator PEER_STATE_SECURED

Bluetooth stack set the connection security to at least level 2 (that is, encryption and no authentication).

enumerator PEER_STATE_CONN_FAILED

Bluetooth stack failed to connect the remote peer.

enumerator PEER_STATE_COUNT

Number of peer states.

enum peer_operation

Peer operations.

Values:

enumerator PEER_OPERATION_SELECT

The peer change is triggered and waiting for confirmation. The operation is not performed by the Bluetooth stack before the selection is confirmed. PEER_OPERATION_SELECTED should be used for confirmed operation.

enumerator PEER_OPERATION_SELECTED

The peer change is confirmed. That results in swapping used local identity. The peers that are connected to previously used Bluetooth local identity should be disconnected. The application can start peer search for peers related to a new local identity.

enumerator PEER_OPERATION_SCAN_REQUEST

Bluetooth scanning is requested.

enumerator PEER_OPERATION_ERASE

The bond erase is triggered and waiting for confirmation. The operation is not performed by the Bluetooth stack before the erase is confirmed. PEER_OPERATION_ERASED should be used for a confirmed operation.

enumerator PEER_OPERATION_ERASE_ADV

Trigger erase advertising for selected local identity.

enumerator PEER_OPERATION_ERASE_ADV_CANCEL

Cancel ongoing erase advertising.

enumerator PEER_OPERATION_ERASED

The bond erase is confirmed. That results in removing all of the Bluetooth bonds of related local identity.

enumerator PEER_OPERATION_CANCEL

Cancel ongoing peer operation. If PEER_OPERATION_ERASE_ADV is cancelled, PEER_OPERATION_ERASE_ADV_CANCEL must be used instead.

enumerator PEER_OPERATION_COUNT

Number of peer operations.

struct ble_peer_event
#include <ble_common_event.h>

Bluetooth LE peer event.

The Bluetooth LE peer event is submitted to inform about state change of a Bluetooth connected peer.

Public Members

struct event_header header

Event header.

enum peer_state state

State of the Bluetooth LE peer.

void *id

ID used to identify Bluetooth connection - pointer to the bt_conn.

struct ble_peer_operation_event
#include <ble_common_event.h>

Bluetooth LE peer operation event.

The Bluetooth LE peer operation event informs about operation that is performed on Bluetooth peers related to a given Bluetooth local identity (and application local identity).

For detailed information related to local identities, peer and bond management, see documentation of the Bluetooth LE bond module in nRF Desktop. The Bluetooth LE bond module is an example of application-specific module that implements Bluetooth peer and bond management.

Public Members

struct event_header header

Event header.

enum peer_operation op

Bluetooth LE peer operation.

uint8_t bt_app_id

Local identity related to the peer operation (used by the application).

uint8_t bt_stack_id

Bluetooth local identity related to the peer operation (used by the Bluetooth stack).

struct ble_peer_conn_params_event
#include <ble_common_event.h>

Bluetooth LE connection parameters event.

The Bluetooth LE connection parameters event is submitted to inform either about received Bluetooth connection parameter update request or fact that connection parameters were already updated.

If the event is related to fact that the connection parameters were already updated, values of interval_min and interval_max are the same. They are equal to the connection interval that is in use.

Public Members

struct event_header header

Event header.

void *id

ID used to identify Bluetooth connection - pointer to the bt_conn.

uint16_t interval_min

Minimum Connection Interval (N * 1.25 ms).

uint16_t interval_max

Maximum Connection Interval (N * 1.25 ms).

uint16_t latency

Connection Latency.

uint16_t timeout

Supervision Timeout (N * 10 ms).

bool updated

Information if the event is related to the fact that connection parameters were already updated or connection parameter update request was received.

struct ble_peer_search_event
#include <ble_common_event.h>

Bluetooth LE peer search event.

The Bluetooth LE peer search event is submitted to inform if applcation is currently looking for a Bluetooth peer. The event can be related either to Bluetooth scanning or advertising.

Public Members

struct event_header header

Event header.

bool active

Information if application is currently looking for a Bluetooth peer.

CAF button events

Header file: include/caf/events/button_event.h
Source file: subsys/caf/events/button_event.c
group caf_button_event

CAF Button Event.

struct button_event
#include <button_event.h>

Button event.

The button event is submitted when a button is pressed or released.

Public Members

struct event_header header

Event header.

uint16_t key_id

ID of the button.

bool pressed

Information if the button was pressed or released.

CAF click events

Header file: include/caf/events/click_event.h
Source file: subsys/caf/events/click_event.c
group caf_click_event

CAF Click Event.

Enums

enum click

Click types.

The click type refers to the way a button can be pressed.

Values:

enumerator CLICK_NONE

Button pressed and held for a period of time that is too long for CLICK_SHORT, but too short for CLICK_LONG.

enumerator CLICK_SHORT

Button pressed and released after a short time.

enumerator CLICK_LONG

Button pressed and held for a long period of time.

enumerator CLICK_DOUBLE

Two sequences of the button press and release in a short time interval.

enumerator CLICK_COUNT

Number of click types.

struct click_event
#include <click_event.h>

Click event.

The click event is submitted when a click type is recorded for one of the monitored buttons.

Public Members

struct event_header header

Event header.

uint16_t key_id

ID of the button - matching the key_id used by the button_event.

enum click click

Detected click type.

CAF force power down events

Header file: include/caf/events/force_power_down_event.h
Source file: subsys/caf/events/force_power_down_event.c
group caf_force_power_down_event

CAF Force Power Down Event.

Functions

static inline void force_power_down(void)

Force power down now.

struct force_power_down_event
#include <force_power_down_event.h>

Simple event to force a quick power down.

The event is called when the device has to power down quickly, without waiting. The device would power down if no wakeup event is generated in short period of time. The keep_alive event would be ignored.

Public Members

struct event_header header

Event header.

CAF keep alive events

Header file: include/caf/events/keep_alive_event.h
Source file: subsys/caf/events/keep_alive_event.c
group caf_keep_alive_event

CAF Keep Alive Event.

Functions

static inline void keep_alive(void)

Keep the device alive.

The function generates the power manager event that would reset the power down counter when processed.

struct keep_alive_event
#include <keep_alive_event.h>

Simple event to keep the power manager alive.

The event called would keep power manager from power downing for configured period of time. The event does not take any argument.

Public Members

struct event_header header

Event header.

CAF LED events

Header file: include/caf/events/led_event.h
Source file: subsys/caf/events/led_event.c
group caf_led_event

CAF LED Event.

struct led_event
#include <led_event.h>

LED event.

The LED event is submitted to change effect displayed by the selected LED. The LED effect affects operating mode and color of the LED. The LED effect displayed by the given LED is overridden if LED receives a new LED event. For more information about LED effects see LED Effect.

Public Members

struct event_header header

Event header.

size_t led_id

ID of the LED.

const struct led_effect *led_effect

Pointer to LED effect to be displayed.

struct led_ready_event
#include <led_event.h>

LED ready event.

The LED ready event is submitted to inform that a LED has finished displaying a LED effect. The event is used to notify that the LED is ready to display next effect.

If the displayed LED effect has loop_forever set to true, the effect never ends and the LED ready event should not be submitted.

Public Members

struct event_header header

Event header.

size_t led_id

ID of the LED.

const struct led_effect *led_effect

Pointer to the LED effect that was displayed.

CAF module state events

Header file: include/caf/events/module_state_event.h
Source file: subsys/caf/events/module_state_event.c
group caf_module_state_event

CAF Module State Event.

Defines

MODULE_ID_LIST_SECTION_PREFIX
MODULE_ID_PTR_VAR(mname)
MODULE_ID_LIST_SECTION_NAME
MODULE_ID_PTR_VAR_EXTERN_DEC(mname)
MODULE_IDX(mname)

Get index of module.

For example, the MODULE_IDX(buttons) can be used to get module index of module named buttons.

Parameters
  • mname[in] Name of the module.

Returns

Index of the module.

MODULE_ID(mname)

Get module ID.

For example, the MODULE_ID(buttons) can be used to get module ID of module named buttons.

Parameters
  • mname[in] Name of the module.

Returns

ID of the module.

MODULE_NAME

Enums

enum module_state

Module states.

Values:

enumerator MODULE_STATE_READY

Module is active. This state is reported when the module is initialized or woken up after suspending.

enumerator MODULE_STATE_OFF

Module is suspended in reaction to power_down_event. The module cannot submit wake_up_event.

enumerator MODULE_STATE_STANDBY

Module is suspended in reaction to power_down_event. The module can submit wake_up_event.

enumerator MODULE_STATE_ERROR

Module reported fatal error.

enumerator MODULE_STATE_COUNT

Number of module states.

Functions

static inline size_t module_count(void)

Get number of modules.

Returns

Number of modules.

static inline const void *module_id_get(size_t idx)

Get ID of module with given index.

Parameters
  • idx[in] Index of the module.

Returns

Module ID.

static inline size_t module_idx_get(const void *module_id)

Get IDX of module with given id.

Parameters
  • module_id[in] ID of the module.

Returns

Module IDX.

static inline const char *module_name_get(const void *id)

Get name of the module with given id.

Parameters
  • id[in] Id of the module.

Returns

Module name.

static inline bool module_check_id_valid(size_t module_idx)

Check if given module index is valid.

Parameters
  • module_idx[in] The index to check.

Return values
  • true – Index is valid.

  • false – Index is out of valid range.

static inline bool module_flags_check_zero(const struct module_flags *mf)

Check if there is 0 in all the flags.

Parameters
  • mf[in] Pointer to module flags variable.

Return values
  • true – All the flags have value of 0.

  • false – Any of the flags is not 0.

static inline bool module_flags_test_bit(const struct module_flags *mf, size_t module_idx)

Test single module bit.

Parameters
  • mf[in] Pointer to module flags variable.

  • module_idx[in] The index of the selected module.

Return values
  • true – The module bit in flags is set.

  • false – The module bit in flags is cleared.

static inline void module_flags_clear_bit(struct module_flags *mf, size_t module_idx)

Clear single module bit.

Parameters
  • mf[inout] Pointer to module flags variable.

  • module_idx[in] The index of the selected module.

static inline void module_flags_set_bit(struct module_flags *mf, size_t module_idx)

Set single module bit.

Parameters
  • mf[inout] Pointer to module flags variable.

  • module_idx[in] The index of the selected module.

static inline void module_flags_set_bit_to(struct module_flags *mf, size_t module_idx, bool val)

Set single module bit to specified value.

Parameters
  • mf[inout] Pointer to module flags variable.

  • module_idx[in] The index of the selected module.

  • val[in] The value to be set in a specified module’s bit.

static inline bool check_state(const struct module_state_event *event, const void *module_id, enum module_state state)

Check if the selected module reported the selected state.

The function can be used in event handler to verify if received module state event informs that selected module reported selected state. The MODULE_ID can be used to get module ID of module with selected name.

Parameters
  • event[in] Poitner to handled module state event.

  • module_id[in] ID of the selected module.

  • state[in] Selected module state.

Return values

true – The module state event informs that selected module reported selected state. Otherwise, false is returned.

static inline void module_set_state(enum module_state state)

Submit module state event to inform that state of the module changed.

ID of the module is automatically assigned based on name that is defined as MODULE.

Parameters
  • state[in] New state of the module.

struct module_flags
#include <module_state_event.h>

Structure that provides a flag for every module available in application.

struct module_state_event
#include <module_state_event.h>

Module state event.

The module state event is submitted by a module to inform that state of the module changed. The module_set_state can be used to submit the module state event for a module. The check_state can be used in event_handler to check if the event carries information that selected module reported selected state. See module_state for details about available module states.

Name of the module must be defined as MODULE before including the module_state_event.h header. For example, “#define MODULE buttons” defines name of the module as buttons. The module name is used to identify a module.

Every application module must register for module state event and submit this event when state of the module changes. An application module can initialize itself when all the required application modules are initialized (report MODULE_STATE_READY). This ensures proper initialization order of the application modules.

Public Members

struct event_header header

Event header.

const void *module_id

ID of the module.

enum module_state state

New state of the module.

CAF power events

Header file: include/caf/events/power_event.h
Source file: subsys/caf/events/power_event.c
group caf_power_event

CAF Power Event.

struct power_down_event
#include <power_event.h>

Power down event.

The power down event is submitted to inform the application modules that they should be suspended to reduce the power consumption. The power down event can also be submitted to suspend the modules after an application module reports fatal error submitting module_state_event with state set to MODULE_STATE_ERROR.

An application module that handles the power down event should submit module_state_event with state set to MODULE_STATE_OFF or MODULE_STATE_STANDBY. The MODULE_STATE_STANDBY should be submitted by a module that is capable of submitting wake_up_event to wake up the system on external event. Otherwise MODULE_STATE_OFF should be reported. If the module is unable to suspend at the moment, it should consume the received power down events until it’s ready to suspend itself. The module should also delay submitting the module_state_event until it’s ready to suspend itself.

The module may handle the power down event differently if it’s related to fatal error. In general, an application module should suspend itself, but some of the modules may still need to be active after the fatal error. For example, module that controls hardware LEDs may be used to display LED effect related to the fatal error.

Only the module that controls the power management in the application can submit the power down event. It is also the final subscriber for the power down event. When it receives the power down event, it’s ensured that all other application modules that handle power down event are already suspended. Then it can continue the power down procedure.

Warning

An application module that handles power down event must also handle wake_up_event. Otherwise the module will never be woken up after suspending.

Public Members

struct event_header header

Event header.

bool error

Information if the power down was triggered by a fatal error.

struct wake_up_event
#include <power_event.h>

Wake up event.

The wake up event is submitted to trigger exiting the suspended state.

The wake up event can be submitted by any application module after the application is suspended. The event can be submitted for example on button press or sensor trigger.

Every application module that handles wake up event should exit suspended state, turn on functionalities disabled on power_down_event and submit module_state_event with state set to MODULE_STATE_READY. If the module is already woken up, it should ignore the event. The module must not consume the wake up event to ensure that other listeners will be informed.

The module that controls power management of the application should be an only early subscriber for the wake up event. This module can consume the wake up events to prevent waking up the application modules after fatal error.

Note

For more information about suspending modules see power_down_event.

Public Members

struct event_header header

Event header.

CAF power manager events

Header file: include/caf/events/power_manager_event.h
Source file: subsys/caf/events/power_manager_event.c
group caf_power_manager_event

CAF Power Manager Event.

Enums

enum power_manager_level

Available power levels.

The power levels provided by the power manager.

Values:

enumerator POWER_MANAGER_LEVEL_ALIVE

Stay alive.

enumerator POWER_MANAGER_LEVEL_SUSPENDED

Suspend but do not go to power off.

enumerator POWER_MANAGER_LEVEL_OFF

Go to full power off.

enumerator POWER_MANAGER_LEVEL_MAX

Number of supported levels.

Functions

static inline void power_manager_restrict(size_t module_idx, enum power_manager_level lvl)

Set the deepest power sleep mode allowed.

Parameters
  • module_idx – The index of the module

  • lvl – Maximal allowed mode

struct power_manager_restrict_event
#include <power_manager_event.h>

An event to specify which power state is allowed by module.

Any module can set maximum allowed power state that can be configured by power manager.

Public Members

struct event_header header

Event header.

size_t module_idx

The module index.

The index of the module that wish to block possibility to set power mode below specified level.

enum power_manager_level level

The deepest sleep mode allowed.

CAF sensor events

Header file: include/caf/events/sensor_event.h
Source file: subsys/caf/events/sensor_event.c
group caf_sensor_event

CAF Sensor Event.

Enums

enum sensor_state

Sensor states.

Values:

enumerator SENSOR_STATE_DISABLED

Initial state of the sensor. The state is used only before sensor is initialized and it should not be broadcasted using sensor_state_event.

enumerator SENSOR_STATE_SLEEP

Sensor is sleeping and no sampling is performed.

enumerator SENSOR_STATE_ACTIVE

Sensor is sampled periodically.

enumerator SENSOR_STATE_ERROR

Sensor error occurred. The sensor is no longer sampled.

enumerator SENSOR_STATE_COUNT

Number of sensor states.

Functions

static inline size_t sensor_event_get_data_cnt(const struct sensor_event *event)

Get size of sensor data.

Parameters
Returns

Size of the sensor data, expressed as a number of floating-point values.

static inline float *sensor_event_get_data_ptr(const struct sensor_event *event)

Get pointer to the sensor data.

Parameters
Returns

Pointer to the sensor data.

struct sensor_state_event
#include <sensor_event.h>

Sensor state event.

The sensor state event is submitted when state of a sensor changes.

The description field is a pointer to a string that is used to identify the sensor by the application. The Common Application Framework does not impose any standard way of describing sensors. Format and content of the sensor description is defined by the application.

Warning

The sensor state event related to the given sensor must use the same description as sensor_event related to the sensor.

Public Members

struct event_header header

Event header.

const char *descr

Description of the sensor.

enum sensor_state state

New state of the sensor.

struct sensor_event
#include <sensor_event.h>

Sensor event.

The sensor event is submitted when a sensor is sampled.

The description field is a pointer to a string that is used to identify the sensor by the application. The Common Application Framework does not impose any standard way of describing sensors. Format and content of the sensor description is defined by the application.

The dyndata contains sensor readouts represented as array of floating-point values. Content of the array depends only on selected sensor. For example an accelerometer may report acceleration in X, Y and Z axis as three floating-point values. sensor_event_get_data_cnt and sensor_event_get_data_ptr can be used to access the sensor data provided by a given sensor event.

Warning

The sensor event related to the given sensor must use the same description as sensor_state_event related to the sensor.

Public Members

struct event_header header

Event header.

const char *descr

Description of the sensor.

struct event_dyndata dyndata

Sensor data. Provided as floating-point values.