1 /*
2 * Copyright (c) 2023 Google LLC
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <zephyr/drivers/emul.h>
7 #include <zephyr/drivers/sensor.h>
8 #include <zephyr/drivers/sensor_attribute_types.h>
9
10 #include <stdint.h>
11
12 /**
13 * @brief Sensor emulator backend API
14 * @defgroup sensor_emulator_backend Sensor emulator backend API
15 * @ingroup io_interfaces
16 * @{
17 */
18
19 /**
20 * @cond INTERNAL_HIDDEN
21 *
22 * These are for internal use only, so skip these in public documentation.
23 */
24
25 /**
26 * @brief Collection of function pointers implementing a common backend API for sensor emulators
27 */
28 __subsystem struct emul_sensor_driver_api {
29 /** Sets a given fractional value for a given sensor channel. */
30 int (*set_channel)(const struct emul *target, struct sensor_chan_spec ch,
31 const q31_t *value, int8_t shift);
32 /** Retrieve a range of sensor values to use with test. */
33 int (*get_sample_range)(const struct emul *target, struct sensor_chan_spec ch, q31_t *lower,
34 q31_t *upper, q31_t *epsilon, int8_t *shift);
35 /** Set the attribute value(s) of a given channel. */
36 int (*set_attribute)(const struct emul *target, struct sensor_chan_spec ch,
37 enum sensor_attribute attribute, const void *value);
38 /** Get metadata about an attribute. */
39 int (*get_attribute_metadata)(const struct emul *target, struct sensor_chan_spec ch,
40 enum sensor_attribute attribute, q31_t *min, q31_t *max,
41 q31_t *increment, int8_t *shift);
42 };
43 /**
44 * @endcond
45 */
46
47 /**
48 * @brief Check if a given sensor emulator supports the backend API
49 *
50 * @param target Pointer to emulator instance to query
51 *
52 * @return True if supported, false if unsupported or if \p target is NULL.
53 */
emul_sensor_backend_is_supported(const struct emul * target)54 static inline bool emul_sensor_backend_is_supported(const struct emul *target)
55 {
56 return target && target->backend_api;
57 }
58
59 /**
60 * @brief Set an expected value for a given channel on a given sensor emulator
61 *
62 * @param target Pointer to emulator instance to operate on
63 * @param ch Sensor channel to set expected value for
64 * @param value Expected value in fixed-point format using standard SI unit for sensor type
65 * @param shift Shift value (scaling factor) applied to \p value
66 *
67 * @return 0 if successful
68 * @return -ENOTSUP if no backend API or if channel not supported by emul
69 * @return -ERANGE if provided value is not in the sensor's supported range
70 */
emul_sensor_backend_set_channel(const struct emul * target,struct sensor_chan_spec ch,const q31_t * value,int8_t shift)71 static inline int emul_sensor_backend_set_channel(const struct emul *target,
72 struct sensor_chan_spec ch, const q31_t *value,
73 int8_t shift)
74 {
75 if (!target || !target->backend_api) {
76 return -ENOTSUP;
77 }
78
79 struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api;
80
81 if (api->set_channel) {
82 return api->set_channel(target, ch, value, shift);
83 }
84 return -ENOTSUP;
85 }
86
87 /**
88 * @brief Query an emulator for a channel's supported sample value range and tolerance
89 *
90 * @param target Pointer to emulator instance to operate on
91 * @param ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP`
92 * @param[out] lower Minimum supported sample value in SI units, fixed-point format
93 * @param[out] upper Maximum supported sample value in SI units, fixed-point format
94 * @param[out] epsilon Tolerance to use comparing expected and actual values to account for rounding
95 * and sensor precision issues. This can usually be set to the minimum sample value step
96 * size. Uses SI units and fixed-point format.
97 * @param[out] shift The shift value (scaling factor) associated with \p lower, \p upper, and
98 * \p epsilon.
99 *
100 * @return 0 if successful
101 * @return -ENOTSUP if no backend API or if channel not supported by emul
102 *
103 */
emul_sensor_backend_get_sample_range(const struct emul * target,struct sensor_chan_spec ch,q31_t * lower,q31_t * upper,q31_t * epsilon,int8_t * shift)104 static inline int emul_sensor_backend_get_sample_range(const struct emul *target,
105 struct sensor_chan_spec ch, q31_t *lower,
106 q31_t *upper, q31_t *epsilon, int8_t *shift)
107 {
108 if (!target || !target->backend_api) {
109 return -ENOTSUP;
110 }
111
112 struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api;
113
114 if (api->get_sample_range) {
115 return api->get_sample_range(target, ch, lower, upper, epsilon, shift);
116 }
117 return -ENOTSUP;
118 }
119
120 /**
121 * @brief Set the emulator's attribute values
122 *
123 * @param[in] target Pointer to emulator instance to operate on
124 * @param[in] ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP`
125 * @param[in] attribute The attribute to set
126 * @param[in] value the value to use (cast according to the channel/attribute pair)
127 * @return 0 is successful
128 * @return < 0 on error
129 */
emul_sensor_backend_set_attribute(const struct emul * target,struct sensor_chan_spec ch,enum sensor_attribute attribute,const void * value)130 static inline int emul_sensor_backend_set_attribute(const struct emul *target,
131 struct sensor_chan_spec ch,
132 enum sensor_attribute attribute,
133 const void *value)
134 {
135 if (!target || !target->backend_api) {
136 return -ENOTSUP;
137 }
138
139 struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api;
140
141 if (api->set_attribute == NULL) {
142 return -ENOTSUP;
143 }
144 return api->set_attribute(target, ch, attribute, value);
145 }
146
147 /**
148 * @brief Get metadata about an attribute.
149 *
150 * Information provided by this function includes the minimum/maximum values of the attribute as
151 * well as the increment (value per LSB) which can be used as an epsilon when comparing results.
152 *
153 * @param[in] target Pointer to emulator instance to operate on
154 * @param[in] ch The channel to request info for. If \p ch is unsupported, return '-ENOTSUP'
155 * @param[in] attribute The attribute to request info for. If \p attribute is unsupported, return
156 * '-ENOTSUP'
157 * @param[out] min The minimum value the attribute can be set to
158 * @param[out] max The maximum value the attribute can be set to
159 * @param[out] increment The value that the attribute increases by for every LSB
160 * @param[out] shift The shift for \p min, \p max, and \p increment
161 * @return 0 on SUCCESS
162 * @return < 0 on error
163 */
emul_sensor_backend_get_attribute_metadata(const struct emul * target,struct sensor_chan_spec ch,enum sensor_attribute attribute,q31_t * min,q31_t * max,q31_t * increment,int8_t * shift)164 static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target,
165 struct sensor_chan_spec ch,
166 enum sensor_attribute attribute,
167 q31_t *min, q31_t *max,
168 q31_t *increment, int8_t *shift)
169 {
170 if (!target || !target->backend_api) {
171 return -ENOTSUP;
172 }
173
174 struct emul_sensor_driver_api *api = (struct emul_sensor_driver_api *)target->backend_api;
175
176 if (api->get_attribute_metadata == NULL) {
177 return -ENOTSUP;
178 }
179 return api->get_attribute_metadata(target, ch, attribute, min, max, increment, shift);
180 }
181
182 /**
183 * @}
184 */
185