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 
9 #include <stdint.h>
10 
11 /**
12  * @brief Sensor emulator backend API
13  * @defgroup sensor_emulator_backend Sensor emulator backend API
14  * @ingroup io_interfaces
15  * @{
16  */
17 
18 /**
19  * @cond INTERNAL_HIDDEN
20  *
21  * These are for internal use only, so skip these in public documentation.
22  */
23 
24 /**
25  * @brief Collection of function pointers implementing a common backend API for sensor emulators
26  */
27 __subsystem struct emul_sensor_backend_api {
28 	/** Sets a given fractional value for a given sensor channel. */
29 	int (*set_channel)(const struct emul *target, enum sensor_channel ch, q31_t value,
30 			   int8_t shift);
31 	/** Retrieve a range of sensor values to use with test. */
32 	int (*get_sample_range)(const struct emul *target, enum sensor_channel ch, q31_t *lower,
33 				q31_t *upper, q31_t *epsilon, int8_t *shift);
34 };
35 /**
36  * @endcond
37  */
38 
39 /**
40  * @brief Check if a given sensor emulator supports the backend API
41  *
42  * @param target Pointer to emulator instance to query
43  *
44  * @return True if supported, false if unsupported or if \p target is NULL.
45  */
emul_sensor_backend_is_supported(const struct emul * target)46 static inline bool emul_sensor_backend_is_supported(const struct emul *target)
47 {
48 	return target && target->backend_api;
49 }
50 
51 /**
52  * @brief Set an expected value for a given channel on a given sensor emulator
53  *
54  * @param target Pointer to emulator instance to operate on
55  * @param ch Sensor channel to set expected value for
56  * @param value Expected value in fixed-point format using standard SI unit for sensor type
57  * @param shift Shift value (scaling factor) applied to \p value
58  *
59  * @return 0 if successful
60  * @return -ENOTSUP if no backend API or if channel not supported by emul
61  * @return -ERANGE if provided value is not in the sensor's supported range
62  */
emul_sensor_backend_set_channel(const struct emul * target,enum sensor_channel ch,q31_t value,int8_t shift)63 static inline int emul_sensor_backend_set_channel(const struct emul *target, enum sensor_channel ch,
64 						  q31_t value, int8_t shift)
65 {
66 	if (!target || !target->backend_api) {
67 		return -ENOTSUP;
68 	}
69 
70 	struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api;
71 
72 	if (api->set_channel) {
73 		return api->set_channel(target, ch, value, shift);
74 	}
75 	return -ENOTSUP;
76 }
77 
78 /**
79  * @brief Query an emulator for a channel's supported sample value range and tolerance
80  *
81  * @param target Pointer to emulator instance to operate on
82  * @param ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP`
83  * @param[out] lower Minimum supported sample value in SI units, fixed-point format
84  * @param[out] upper Maximum supported sample value in SI units, fixed-point format
85  * @param[out] epsilon Tolerance to use comparing expected and actual values to account for rounding
86  *             and sensor precision issues. This can usually be set to the minimum sample value step
87  *             size. Uses SI units and fixed-point format.
88  * @param[out] shift The shift value (scaling factor) associated with \p lower, \p upper, and
89  *             \p epsilon.
90  *
91  * @return 0 if successful
92  * @return -ENOTSUP if no backend API or if channel not supported by emul
93  *
94  */
emul_sensor_backend_get_sample_range(const struct emul * target,enum sensor_channel ch,q31_t * lower,q31_t * upper,q31_t * epsilon,int8_t * shift)95 static inline int emul_sensor_backend_get_sample_range(const struct emul *target,
96 						       enum sensor_channel ch, q31_t *lower,
97 						       q31_t *upper, q31_t *epsilon, int8_t *shift)
98 {
99 	if (!target || !target->backend_api) {
100 		return -ENOTSUP;
101 	}
102 
103 	struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api;
104 
105 	if (api->get_sample_range) {
106 		return api->get_sample_range(target, ch, lower, upper, epsilon, shift);
107 	}
108 	return -ENOTSUP;
109 }
110 
111 /**
112  * @}
113  */
114