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