Sensing Subsystem
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 Sensors 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, 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.
Configurability
Reusable and configurable standalone subsystem.
Based on Zephyr existing low-level Sensor API (reuse 100+ existing sensor device drivers)
Provide Zephyr high-level Sensing Subsystem API for Applications.
Separate option CHRE Sensor PAL Implementation module to support CHRE.
Decoupled with any host link protocols, it’s Zephyr Application’s role to handle different protocols (MQTT, HID or Private, all configurable)
Main Features
- Scope
Focus on framework for sensor fusion, multiple clients, arbitration, data sampling, timing management and scheduling.
- Sensor Abstraction
Physical sensor
: interacts with Zephyr sensor device drivers, focus on data collecting.Virtual sensor
: relies on other sensor(s),physical
orvirtual
, focus on data fusion.
- Data Driven Model
Polling mode
: periodical sampling rateInterrupt mode
: data ready, threshold interrupt etc.
- Scheduling
single thread main loop for all sensor objects sampling and process.
Buffer Mode for Batching
Configurable Via Device Tree
Below diagram shows the API position and scope:
Sensing Subsystem API
is for Applications.
Sensing Sensor API
is for development sensors
.
Major Flows
Sensor Configuration Flow
Sensor Data Flow
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
sensing_get_sensors()
returns all current board configuration supported sensor instances’ information in asensing_sensor_info
pointer array .Then Applications can use
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
sensing_open_sensor_by_dt()
to open a sensor instance directly with sensor devicetree node identifier.For example:
sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABLE(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.
Sensor Instance Handler
Clients using a 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 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 sensing_sensor_get_reporters()
.
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 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, likesensing_sensor_value_3d_q31
,sensing_sensor_value_q31
, andsensing_sensor_value_uint32
.The
header
definitionsensing_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]
isheader.base_timestamp
+readings[0].timestamp_delta
.timestamp of
readings[1]
istimestamp of readings[0]
+readings[1].timestamp_delta
.
Since timestamp unit is micro seconds, the max timestamp_delta (
uint32_t
) is4295
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.
Data Format
Sensing Subsystem
uses per sensor type defined data format structure, and supportQ Format
defined in include/zephyr/dsp/types.h forzdsp
lib support.For example
sensing_sensor_value_3d_q31
can be used by 3D IMU sensors likeSENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D
,SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D
, andSENSING_SENSOR_TYPE_MOTION_GYROMETER_3D
.sensing_sensor_value_uint32
can be used bySENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT
sensor,and
sensing_sensor_value_q31
can be used bySENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE
sensor
Device Tree Configuration
Sensing subsystem using device tree to configuration all sensor instances and their properties, reporting relationships.
See the example samples/subsys/sensing/simple/boards/native_sim.overlay
API Reference
- group sensing_sensor_types
Sensor Types Definition.
Sensor types definition followed HID standard. https://usb.org/sites/default/files/hutrr39b_0.pdf
TODO: will add more types
Defines
-
SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT
sensor category light
-
SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D
sensor category motion
-
SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D
-
SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR
-
SENSING_SENSOR_TYPE_OTHER_CUSTOM
sensor category other
-
SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D
-
SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE
-
SENSING_SENSOR_TYPE_ALL
-
SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT
- group sensing_datatypes
Data Types.
-
struct sensing_sensor_value_header
- #include <sensing_datatypes.h>
sensor value header
Each sensor value data structure should have this header
Here use ‘base_timestamp’ (uint64_t) and ‘timestamp_delta’ (uint32_t) to save memory usage in batching mode.
The ‘base_timestamp’ is for readings[0], the ‘timestamp_delta’ is relation to the previous ‘readings’. So, 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 sensor subsystem core will split them across multiple instances of the readings structure, and send multiple events.
This concept is borrowed from CHRE: https://cs.android.com/android/platform/superproject/+/master:\ system/chre/chre_api/include/chre_api/chre/sensor_types.h
-
struct sensing_sensor_value_3d_q31
- #include <sensing_datatypes.h>
Sensor value data structure types based on common data types.
Suitable for common sensors, such as IMU, Light sensors and orientation sensors.
Sensor value data structure for 3-axis sensors. struct sensing_sensor_value_3d_q31 can be used by 3D IMU sensors like: SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D, SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D, q31 version
-
struct sensing_sensor_value_uint32
- #include <sensing_datatypes.h>
Sensor value data structure for single 1-axis value.
struct sensing_sensor_value_uint32 can be used by SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT sensor uint32_t version
-
struct sensing_sensor_value_q31
- #include <sensing_datatypes.h>
Sensor value data structure for single 1-axis value.
struct sensing_sensor_value_q31 can be used by SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE sensor q31 version
-
struct sensing_sensor_value_header
- group sensing_api
Sensing Subsystem API.
Defines
-
SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build)
-
SENSING_SENSOR_FLAG_REPORT_ON_EVENT
Sensor flag indicating if this sensor is on event reporting data.
Reporting sensor data when the sensor event occurs, such as a motion detect sensor reporting a motion or motionless detected event.
-
SENSING_SENSOR_FLAG_REPORT_ON_CHANGE
Sensor flag indicating if this sensor is on change reporting data.
Reporting sensor data when the sensor data changes.
Exclusive with SENSING_SENSOR_FLAG_REPORT_ON_EVENT
Typedefs
-
typedef void *sensing_sensor_handle_t
Define Sensing subsystem sensor handle.
-
typedef void (*sensing_data_event_t)(sensing_sensor_handle_t handle, const void *buf)
Sensor data event receive callback.
- Param handle:
The sensor instance handle.
- Param buf:
The data buffer with sensor data.
Enums
Functions
-
int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info)
Get all supported sensor instances’ information.
This API just returns read only information of sensor instances, pointer info will directly point to internal buffer, no need for caller to allocate buffer, no side effect to sensor instances.
- Parameters:
num_sensors – Get number of sensor instances.
info – For receiving sensor instances’ information array pointer.
- Returns:
0 on success or negative error value on failure.
-
int sensing_open_sensor(const struct sensing_sensor_info *info, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle)
Open sensor instance by sensing sensor info.
Application clients use it to open a sensor instance and get its handle. Support multiple Application clients for open same sensor instance, in this case, the returned handle will different for different clients. meanwhile, also register sensing callback list
- Parameters:
info – The sensor info got from sensing_get_sensors
cb_list – callback list to be registered to sensing.
handle – The opened instance handle, if failed will be set to NULL.
- Returns:
0 on success or negative error value on failure.
-
int sensing_open_sensor_by_dt(const struct device *dev, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle)
Open sensor instance by device.
Application clients use it to open a sensor instance and get its handle. Support multiple Application clients for open same sensor instance, in this case, the returned handle will different for different clients. meanwhile, also register sensing callback list.
- Parameters:
dev – pointer device get from device tree.
cb_list – callback list to be registered to sensing.
handle – The opened instance handle, if failed will be set to NULL.
- Returns:
0 on success or negative error value on failure.
-
int sensing_close_sensor(sensing_sensor_handle_t *handle)
Close sensor instance.
- Parameters:
handle – The sensor instance handle need to close.
- Returns:
0 on success or negative error value on failure.
-
int sensing_set_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *configs, int count)
Set current config items to Sensing subsystem.
- Parameters:
handle – The sensor instance handle.
configs – The configs to be set according to config attribute.
count – count of configs.
- Returns:
0 on success or negative error value on failure, not support etc.
-
int sensing_get_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *configs, int count)
Get current config items from Sensing subsystem.
- Parameters:
handle – The sensor instance handle.
configs – The configs to be get according to config attribute.
count – count of configs.
- Returns:
0 on success or negative error value on failure, not support etc.
-
const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle)
Get sensor information from sensor instance handle.
- Parameters:
handle – The sensor instance handle.
- Returns:
a const pointer to sensing_sensor_info on success or NULL on failure.
-
struct sensing_sensor_version
- #include <sensing.h>
Sensor Version.
-
struct sensing_sensor_info
- #include <sensing.h>
Sensor basic constant information.
Public Members
-
const char *name
Name of the sensor instance.
-
const char *friendly_name
Friendly name of the sensor instance.
-
const char *vendor
Vendor name of the sensor instance.
-
const char *model
Model name of the sensor instance.
-
const int32_t type
Sensor type.
-
const uint32_t minimal_interval
Minimal report interval in micro seconds.
-
const char *name
-
struct sensing_callback_list
- #include <sensing.h>
Sensing subsystem event callback list.
-
struct sensing_sensor_config
- #include <sensing.h>
Sensing subsystem sensor configure, including interval, sensitivity, latency.
-
SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build)
- group sensing_sensor
Sensing Sensor API.
Defines
-
SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, ctx_ptr, api_ptr)
Macro for define a sensor instance from device tree node id.
This macro also defined a struct device for this sensor instance, and registered sensors’ private context data, configuration data structure and API.
sensing_init will enumerate all sensor instances from device tree, and initialize each sensor instance defined by this macro.
Functions
-
static inline void *sensing_sensor_get_ctx_data(const struct device *dev)
Get registered context data pointer for a sensor instance.
Used by a sensor instance to get its registered context data pointer with its struct device.
- Parameters:
dev – The sensor instance device structure.
-
int sensing_sensor_post_data(const struct device *dev, void *buf, int size)
Post sensor data, sensor subsystem runtime will deliver to it’s clients.
Unblocked function, returned immediately.
Used by a virtual sensor to post data to it’s clients.
A reporter sensor can use this API to post data to it’s clients. For example, when a virtual sensor computed a data, then can use this API to deliver the data to it’s clients. Please note, this API just for reporter post data to the sensor subsystem runtime, the runtime will help delivered the data to it’s all clients according clients’ configurations such as reporter interval, data change sensitivity.
- Parameters:
dev – The sensor instance device structure.
buf – The data buffer.
size – The buffer size in bytes.
- Returns:
0 on success or negative error value on failure.
-
int sensing_sensor_get_reporters(const struct device *dev, int type, const int *reporter_handles, int max_handles)
Get reporter handles of a given sensor instance by sensor type.
- Parameters:
dev – The sensor instance device structure.
type – The given type, SENSING_SENSOR_TYPE_ALL to get reporters with all types.
max_handles – The max count of the
reporter_handles
array input. Can get real count number via sensing_sensor_get_reporters_countreporter_handles – Input handles array for receiving found reporter sensor instances
- Returns:
number of reporters found, 0 returned if not found.
-
int sensing_sensor_get_reporters_count(const struct device *dev, int type)
Get reporters count of a given sensor instance by sensor type.
- Parameters:
dev – The sensor instance device structure.
type – The sensor type for checking, SENSING_SENSOR_TYPE_ALL
- Returns:
Count of reporters by
type
, 0 returned if no reporters bytype
.
-
int sensing_sensor_get_state(const struct device *dev, enum sensing_sensor_state *state)
Get this sensor’s state.
- Parameters:
dev – The sensor instance device structure.
state – Returned sensor state value
- Returns:
0 on success or negative error value on failure.
-
struct sensing_sensor_register_info
- #include <sensing_sensor.h>
Sensor registration information.
Public Members
-
uint16_t flags
Sensor flags.
-
uint16_t sample_size
Sample size in bytes for a single sample of the registered sensor.
sensing runtime need this information for internal buffer allocation.
-
uint8_t sensitivity_count
The number of sensor sensitivities.
-
struct sensing_sensor_version version
Sensor version.
Version can be used to identify different versions of sensor implementation.
-
uint16_t flags
-
struct sensing_sensor_ctx
- #include <sensing_sensor.h>
Sensor context data structure.
Public Members
-
void *priv_ptr
For sensing runtime internal private data, sensor should not see and touch.
-
const struct sensing_sensor_register_info *register_info
Pointer to the sensor register information.
-
void *const sensor_ctx_ptr
For sensor private context data, registered by sensor with SENSING_SENSOR_DT_DEFINE.
Sensor could use sensing_sensor_get_ctx_data to fetch out this filed with struct device.
-
void *priv_ptr
-
SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, ctx_ptr, api_ptr)