doc/services/sensing/index.rst
.. _sensing:
Sensing Subsystem ########################
.. contents:: :local: :depth: 2
Overview
Sensing Subsystem is a high level sensor framework inside the OS user space service layer. It is a framework focused on sensor fusion, client arbitration, sampling, timing, scheduling and sensor based power management.
Key concepts in Sensing Subsystem include physical sensor and virtual sensor objects, and a scheduling framework over sensor object relationships. Physical sensors do not depend on any other sensor objects for input, and will directly interact with existing zephyr sensor device drivers. Virtual sensors rely on other sensor objects (physical or virtual) as report inputs.
The sensing subsystem relies on Zephyr sensor device APIs (existing version or update in future) to leverage Zephyr's large library of sensor device drivers (100+).
Use of the sensing subsystem is optional. Applications that only need to access simple sensors
devices can use the Zephyr :ref:sensor API directly.
Since the sensing subsystem is separated from device driver layer or kernel space and could support various customizations and sensor algorithms in user space with virtual sensor concepts. The existing sensor device driver can focus on low layer device side works, can keep simple as much as possible, just provide device HW abstraction and operations etc. This is very good for system stability.
The sensing subsystem is decoupled with any sensor expose/transfer
protocols, the target is to support various up-layer frameworks and
Applications with different sensor expose/transfer protocols,
such as CHRE <https://github.com/zephyrproject-rtos/chre>_, HID sensors Applications,
MQTT sensor Applications according different products requirements. Or even support multiple
Applications with different up-layer sensor protocols at the same time
with it's multiple clients support design.
Sensing subsystem can help build a unified Zephyr sensing architecture for cross host OSes support and as well as IoT sensor solutions.
The diagram below illustrates how the Sensing Subsystem integrates with up-layer frameworks.
.. image:: images/sensing_solution.png :align: center :alt: Unified Zephyr sensing architecture.
Configurability
Main Features
Scope Focus on framework for sensor fusion, multiple clients, arbitration, data sampling, timing management and scheduling.
Sensor Abstraction
Data Driven Model
Scheduling Single thread main loop for all sensor objects sampling and process.
Buffer Mode for Batching ..
Configurable Via Devicetree ..
Below diagram shows the API position and scope:
.. image:: images/sensing_api_org.png :align: center :alt: Sensing subsystem API organization.
Sensing Subsystem API is for Applications.
Sensing Sensor API is for development sensors.
Major Flows
.. image:: images/sensor_config_flow.png :align: center :alt: Sensor Configuration Flow (App set report interval to hinge angel sensor example).
.. image:: images/sensor_data_flow.png :align: center :alt: Sensor Data Flow (App receive hinge angel data through data event callback example).
Sensor Types And Instance
The Sensing Subsystem supports multiple instances of the same sensor type,
there're two methods for Applications to identify and open an unique sensor instance:
Enumerate all sensor instances
:c:func:sensing_get_sensors returns all current board configuration supported sensor instances'
information in a :c:struct:sensing_sensor_info pointer array .
Then Applications can use :c:func:sensing_open_sensor to
open specific sensor instance for future accessing, configuration and receive sensor data etc.
This method is suitable for supporting some up-layer frameworks like CHRE, HID which need
to dynamically enumerate the underlying platform's sensor instances.
Open the sensor instance by devicetree node directly
Applications can use :c:func:sensing_open_sensor_by_dt to open a sensor instance directly with
sensor devicetree node identifier.
For example:
.. code-block:: c
sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABEL(base_accel)), cb_list, handle); sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_CHOSEN(zephyr_sensing_base_accel)), cb_list, handle);
This method is useful and easy use for some simple Application which just want to access specific sensor(s).
Sensor type follows the
HID standard sensor types definition <https://usb.org/sites/default/files/hutrr39b_0.pdf>_.
See :zephyr_file:include/zephyr/sensing/sensing_sensor_types.h
Sensor Instance Handler
Clients using a :c:type:sensing_sensor_handle_t type handler to handle a opened sensor
instance, and all subsequent operations on this sensor instance need use this handler,
such as set configurations, read sensor sample data, etc.
For a sensor instance, could have two kinds of clients:
Application clients and Sensor clients.
Application clients can use :c:func:sensing_open_sensor to open a sensor instance
and get it's handler.
For Sensor clients, there is no open API for opening a reporter, because the client-report
relationship is built at the sensor's registration stage with devicetree.
The Sensing Subsystem will auto open and create handlers for client sensor
to it's reporter sensors.
Sensor clients can get it's reporters' handlers via :c:func:sensing_sensor_get_reporters.
.. image:: images/sensor_top.png :align: center :alt: Sensor Reporting Topology.
.. note::
Sensors inside the Sensing Subsystem, the reporting relationship between them are all auto
generated by Sensing Subsystem according devicetree definitions, handlers between client sensor
and reporter sensors are auto created.
Application(s) need to call :c:func:sensing_open_sensor to explicitly open the sensor instance.
Sensor Sample Value
Data Structure
Each sensor sample value defines as a common header + readings[] data structure, like
:c:struct:sensing_sensor_value_3d_q31, :c:struct:sensing_sensor_value_q31, and
:c:struct:sensing_sensor_value_uint32.
The header definition :c:func:sensing_sensor_value_header.
Time Stamp
Time stamp unit in sensing subsystem is micro seconds.
The header defines a base_timestamp, and
each element in the readings[] array defines timestamp_delta.
The timestamp_delta is in relation to the previous readings (or the base_timestamp)
For example:
timestamp of readings[0] is header.base_timestamp + readings[0].timestamp_delta.
timestamp of readings[1] is timestamp of readings[0] + readings[1].timestamp_delta.
Since timestamp unit is micro seconds,
the max timestamp_delta (uint32_t) is 4295 seconds.
If a sensor has batched data where two consecutive readings differ by more than 4295 seconds,
the sensing subsystem runtime will split them across multiple instances of the readings structure,
and send multiple events.
This concept is referred from CHRE Sensor API <https://github.com/zephyrproject-rtos/ chre/blob/zephyr/chre_api/include/chre_api/chre/sensor_types.h>_.
Data Format
Sensing Subsystem uses per sensor type defined data format structure,
and support Q Format defined in :zephyr_file:include/zephyr/dsp/types.h
for zdsp lib support.
For example :c:struct:sensing_sensor_value_3d_q31 can be used by 3D IMU sensors like
:c:macro:SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D,
:c:macro:SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D,
and :c:macro:SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D.
:c:struct:sensing_sensor_value_uint32 can be used by
:c:macro:SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT sensor,
and :c:struct:sensing_sensor_value_q31 can be used by
:c:macro:SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE sensor
See :zephyr_file:include/zephyr/sensing/sensing_datatypes.h
Device Tree Configuration
Sensing subsystem using device tree to configuration all sensor instances and their properties, reporting relationships.
See the example :zephyr_file:samples/subsys/sensing/simple/boards/native_sim.overlay
API Reference
.. doxygengroup:: sensing_api