xref: /aosp_15_r20/external/pigweed/pw_sensor/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_sensor:
2
3=========
4pw_sensor
5=========
6This is the main documentation file for pw_sensor. It is under construction.
7
8.. toctree::
9   :maxdepth: 1
10
11   py/docs
12
13Defining types
14==============
15Pigweed provides a data-definition layer for sensors. This allows the properties
16of a sensor to be declared once and shared across multiple languages or runtimes.
17More information is available in :ref:`module-pw_sensor-py`.
18
19Once we define our units, measurements, attributes, and triggers we can import
20them and use them in our language-specific sensor code.
21
22Here's an example sensor definition YAML file for a custom sensor made by a
23company called "MyOrg" with a part ID "MyPaRt12345". This sensor supports
24reading acceleration and its internal die temperature. We can also configure
25the sample rate for the acceleration readings.
26
27.. code-block:: yaml
28
29   deps:
30      - "third_party/pigweed/pw_sensor/attributes.yaml"
31      - "third_party/pigweed/pw_sensor/channels.yaml"
32      - "third_party/pigweed/pw_sensor/units.yaml"
33   compatible:
34      org: "MyOrg"
35      part: "MyPaRt12345"
36   channels:
37      acceleration: []
38      die_temperature: []
39   attributes:
40      -  attribute: "sample_rate"
41         channel: "acceleration"
42         units: "frequency"
43         representation: "unsigned"
44
45Now that we have our sensor spec in a YAML file we can use it in our C++ code:
46
47.. tab-set::
48
49   .. tab-item:: Bazel
50
51      Compiling one or more sensor YAML files into a header is done by a call to
52      the ``pw_sensor_library`` rule. It looks like:
53
54      .. code-block::
55
56         load("@pigweed//pw_sensor:sensor.bzl", "pw_sensor_library")
57
58         pw_sensor_library(
59            name = "my_sensor_lib",
60            out_header = "my_app/generated/sensor_constants.h",
61            srcs = [
62               "my_sensor0.yaml",
63               "my_sensor1.yaml",
64            ],
65            inputs = [
66               "@pigweed//pw_sensor:attributes.yaml",
67               "@pigweed//pw_sensor:channels.yaml",
68               "@pigweed//pw_sensor:triggers.yaml",
69               "@pigweed//pw_sensor:units.yaml",
70            ],
71            generator_includes = ["@pigweed//"],
72            deps = [
73               "@pigweed//pw_sensor:pw_sensor_types",
74               "@pigweed//pw_containers:flag_map",
75               "@pigweed//pw_tokenizer:pw_tokenizer",
76            ],
77         )
78
79   .. tab-item:: GN
80
81      Compiling one or more sensor YAML files into a header is done by a call to
82      the ``pw_sensor_library`` template. It looks like:
83
84      .. code-block::
85
86         import("$dir_pw_sensor/sensor.gni")
87
88         pw_sensor_library("my_sensor_lib") {
89           out_header = "my_app/generated/sensor_constants.h"
90           sources = [
91            "my_sensor0.yaml",
92            "my_sensor1.yaml",
93           ]
94           inputs = [
95            "$dir_pw_sensor/attributes.yaml",
96            "$dir_pw_sensor/channels.yaml",
97            "$dir_pw_sensor/triggers.yaml",
98            "$dir_pw_sensor/units.yaml",
99           ]
100           generator_includes = [ getenv["PW_ROOT"] ]
101           public_deps = [
102            "$dir_pw_sensor:pw_sensor_types",
103            "$dir_pw_containers:flag_map",
104            "$dir_pw_tokenizer:pw_tokenizer",
105           ]
106         }
107
108   .. tab-item:: CMake
109
110      Compiling one or more sensor YAML files into a header is done by a call to
111      the ``pw_sensor_library`` function. It looks like:
112
113      .. code-block::
114
115         include($ENV{PW_ROOT}/pw_sensor/sensor.cmake)
116
117         # Generate an interface library called my_sensor_lib which exposes a
118         # header file that can be included as
119         # "my_app/generated/sensor_constants.h".
120         pw_sensor_library(my_sensor_lib
121            OUT_HEADER
122               my_app/generated/sensor_constants.h
123            INPUTS
124               $ENV{PW_ROOT}/attributes.yaml
125               $ENV{PW_ROOT}/channels.yaml
126               $ENV{PW_ROOT}/triggers.yaml
127               $ENV{PW_ROOT}/units.yaml
128            GENERATOR_INCLUDES
129               $ENV{PW_ROOT}
130            SOURCES
131               my_sensor0.yaml
132               my_sensor1.yaml
133            PUBLIC_DEPS
134               pw_sensor.types
135               pw_containers
136               pw_tokenizer
137         )
138
139The final product is an interface library that can be linked and used in your
140application. As an example:
141
142.. code-block::
143
144   #include "my_app/generated/sensor_constants.h"
145
146   int main() {
147     PW_LOG_INFO(
148       PW_LOG_TOKEN_FMT() " is measured in " PW_LOG_TOKEN_FMT(),
149       pw::sensor::channels::kAcceleration::kMeasurementName,
150       pw::sensor::GetMeasurementUnitNameFromType(
151         pw::sensor::channels::kAcceleration::kUnitType
152       )
153     );
154   }
155
156--------------
157Under the hood
158--------------
159
160In order to communicate with Pigweed's sensor stack, there are a few type
161definitions that are used:
162
163* Unit types - created with ``PW_SENSOR_UNIT_TYPE``. These can be thought of as
164  defining things like "meters", "meters per second square",
165  "radians per second", etc.
166* Measurement types - created with ``PW_SENSOR_MEASUREMENT_TYPE``. These are
167  different things you can measure with a given unit. Examples: "height",
168  "width", and "length" would all use "meters" as a unit but are different
169  measurement types.
170* Attribute types - created with ``PW_SENSOR_ATTRIBUTE_TYPE``. These are
171  configurable aspects of the sensor. They are things like sample rates, tigger
172  thresholds, etc. Attributes are unitless until they are paired with the
173  measurement type that they modify. As an example "range" attribute for
174  acceleration measurements would be in "m/s^2", while a "range" attribute for
175  rotational velocity would be in "rad/s".
176* Attribute instances - created with ``PW_SENSOR_ATTRIBUTE_INSTANCE``. These
177  lump together an attribute with the measurement it applies to along with a
178  unit to use. Example: Attribute("sample rate") + Measurement("acceleration") +
179  Unit("frequency").
180* Trigger types - created with ``PW_SENSOR_TRIGGER_TYPE``. These are events that
181  affect the streaming API. These can be events like "fifo full", "tap",
182  "double tap"
183
184Developers don't need to actually touch these, as they're automatically called
185from the generated sensor library above. The important thing from the input YAML
186file is that our final generated header will include the following types:
187``attributes::kSampleRate``, ``channels::kAcceleration``,
188``channels::kDieTemperature``, and ``units::kFrequency``. All of these are used
189by our sensor.
190
191A later change will also introduce the ``PW_SENSOR_ATTRIBUTE_INSTANCE``.
192