1 /*
2 * Copyright (c) 2024 STMicroelectronics
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/sys/util_macro.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/rtio/rtio.h>
15
16 #define STREAMDEV_ALIAS(i) DT_ALIAS(_CONCAT(stream, i))
17 #define STREAMDEV_DEVICE(i, _) \
18 IF_ENABLED(DT_NODE_EXISTS(STREAMDEV_ALIAS(i)), (DEVICE_DT_GET(STREAMDEV_ALIAS(i)),))
19 #define NUM_SENSORS 1
20
21 /* support up to 10 sensors */
22 static const struct device *const sensors[] = { LISTIFY(10, STREAMDEV_DEVICE, ()) };
23
24 #define STREAM_IODEV_SYM(id) CONCAT(stream_iodev, id)
25 #define STREAM_IODEV_PTR(id, _) &STREAM_IODEV_SYM(id)
26
27 #define STREAM_TRIGGERS \
28 { SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_NOP }, \
29 { SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE }
30
31 #define STREAM_DEFINE_IODEV(id, _) \
32 SENSOR_DT_STREAM_IODEV( \
33 STREAM_IODEV_SYM(id), \
34 STREAMDEV_ALIAS(id), \
35 STREAM_TRIGGERS);
36
37 LISTIFY(NUM_SENSORS, STREAM_DEFINE_IODEV, (;));
38
39 struct rtio_iodev *iodevs[NUM_SENSORS] = { LISTIFY(NUM_SENSORS, STREAM_IODEV_PTR, (,)) };
40
41 RTIO_DEFINE_WITH_MEMPOOL(stream_ctx, NUM_SENSORS, NUM_SENSORS,
42 NUM_SENSORS * 20, 256, sizeof(void *));
43
44 struct sensor_chan_spec accel_chan = { SENSOR_CHAN_ACCEL_XYZ, 0 };
45 struct sensor_chan_spec gyro_chan = { SENSOR_CHAN_GYRO_XYZ, 0 };
46 struct sensor_chan_spec temp_chan = { SENSOR_CHAN_DIE_TEMP, 0 };
47 struct sensor_chan_spec rot_vector_chan = { SENSOR_CHAN_GAME_ROTATION_VECTOR, 0 };
48 struct sensor_chan_spec gravity_chan = { SENSOR_CHAN_GRAVITY_VECTOR, 0 };
49 struct sensor_chan_spec gbias_chan = { SENSOR_CHAN_GBIAS_XYZ, 0 };
50
51 #define TASK_STACK_SIZE 2048ul
52 static K_THREAD_STACK_ARRAY_DEFINE(thread_stack, NUM_SENSORS, TASK_STACK_SIZE);
53 static struct k_thread thread_id[NUM_SENSORS];
54
print_stream(void * p1,void * p2,void * p3)55 static void print_stream(void *p1, void *p2, void *p3)
56 {
57 const struct device *dev = (const struct device *)p1;
58 struct rtio_iodev *iodev = (struct rtio_iodev *)p2;
59 int rc = 0;
60 const struct sensor_decoder_api *decoder;
61 struct rtio_cqe *cqe;
62 uint8_t *buf;
63 uint32_t buf_len;
64 struct rtio_sqe *handle;
65 uint8_t accel_buf[128] = { 0 };
66 uint8_t gyro_buf[128] = { 0 };
67 uint8_t temp_buf[64] = { 0 };
68 uint8_t rot_vect_buf[128] = { 0 };
69 uint8_t gravity_buf[128] = { 0 };
70 uint8_t gbias_buf[128] = { 0 };
71 struct sensor_three_axis_data *accel_data = (struct sensor_three_axis_data *)accel_buf;
72 struct sensor_three_axis_data *gyro_data = (struct sensor_three_axis_data *)gyro_buf;
73 struct sensor_q31_data *temp_data = (struct sensor_q31_data *)temp_buf;
74 struct sensor_game_rotation_vector_data *rot_vect_data =
75 (struct sensor_game_rotation_vector_data *)rot_vect_buf;
76 struct sensor_three_axis_data *gravity_data = (struct sensor_three_axis_data *)gravity_buf;
77 struct sensor_three_axis_data *gbias_data = (struct sensor_three_axis_data *)gbias_buf;
78
79 /* Start the stream */
80 printk("sensor_stream\n");
81 sensor_stream(iodev, &stream_ctx, NULL, &handle);
82
83 while (1) {
84 cqe = rtio_cqe_consume_block(&stream_ctx);
85
86 if (cqe->result != 0) {
87 printk("async read failed %d\n", cqe->result);
88 return;
89 }
90
91 rc = rtio_cqe_get_mempool_buffer(&stream_ctx, cqe, &buf, &buf_len);
92
93 if (rc != 0) {
94 printk("get mempool buffer failed %d\n", rc);
95 return;
96 }
97
98 const struct device *sensor = dev;
99
100 rtio_cqe_release(&stream_ctx, cqe);
101
102 rc = sensor_get_decoder(sensor, &decoder);
103
104 if (rc != 0) {
105 printk("sensor_get_decoder failed %d\n", rc);
106 return;
107 }
108
109 /* Frame iterator values when data comes from a FIFO */
110 uint32_t accel_fit = 0, gyro_fit = 0;
111 uint32_t temp_fit = 0;
112 uint32_t rot_vect_fit = 0, gravity_fit = 0, gbias_fit = 0;
113
114 /* Number of sensor data frames */
115 uint16_t xl_count, gy_count, tp_count;
116 uint16_t rot_vect_count, gravity_count, gbias_count, frame_count;
117
118 rc = decoder->get_frame_count(buf, accel_chan, &xl_count);
119 rc += decoder->get_frame_count(buf, gyro_chan, &gy_count);
120 rc += decoder->get_frame_count(buf, temp_chan, &tp_count);
121 rc += decoder->get_frame_count(buf, rot_vector_chan, &rot_vect_count);
122 rc += decoder->get_frame_count(buf, gravity_chan, &gravity_count);
123 rc += decoder->get_frame_count(buf, gbias_chan, &gbias_count);
124
125 if (rc != 0) {
126 printk("sensor_get_frame failed %d\n", rc);
127 return;
128 }
129
130 frame_count = xl_count + gy_count + tp_count;
131 frame_count += rot_vect_count + gravity_count + gbias_count;
132
133 /* If a tap has occurred lets print it out */
134 if (decoder->has_trigger(buf, SENSOR_TRIG_TAP)) {
135 printk("Tap! Sensor %s\n", dev->name);
136 }
137
138 /* Decode all available sensor FIFO frames */
139 printk("FIFO count - %d\n", frame_count);
140
141 int i = 0;
142
143 while (i < frame_count) {
144 int8_t c = 0;
145
146 /* decode and print Accelerometer FIFO frames */
147 c = decoder->decode(buf, accel_chan, &accel_fit, 8, accel_data);
148
149 for (int k = 0; k < c; k++) {
150 printk("XL data for %s %lluns (%" PRIq(6) ", %" PRIq(6)
151 ", %" PRIq(6) ")\n", dev->name,
152 PRIsensor_three_axis_data_arg(*accel_data, k));
153 }
154 i += c;
155
156 /* decode and print Gyroscope FIFO frames */
157 c = decoder->decode(buf, gyro_chan, &gyro_fit, 8, gyro_data);
158
159 for (int k = 0; k < c; k++) {
160 printk("GY data for %s %lluns (%" PRIq(6) ", %" PRIq(6)
161 ", %" PRIq(6) ")\n", dev->name,
162 PRIsensor_three_axis_data_arg(*gyro_data, k));
163 }
164 i += c;
165
166 /* decode and print Temperature FIFO frames */
167 c = decoder->decode(buf, temp_chan, &temp_fit, 4, temp_data);
168
169 for (int k = 0; k < c; k++) {
170 printk("TP data for %s %lluns %s%d.%d °C\n", dev->name,
171 PRIsensor_q31_data_arg(*temp_data, k));
172 }
173 i += c;
174
175 /* decode and print Game Rotation Vector FIFO frames */
176 c = decoder->decode(buf, rot_vector_chan, &rot_vect_fit, 8, rot_vect_data);
177
178 for (int k = 0; k < c; k++) {
179 printk("ROT data for %s %lluns (%" PRIq(6) ", %" PRIq(6)
180 ", %" PRIq(6) ", %" PRIq(6) ")\n", dev->name,
181 PRIsensor_game_rotation_vector_data_arg(*rot_vect_data, k));
182 }
183 i += c;
184
185 /* decode and print Gravity Vector FIFO frames */
186 c = decoder->decode(buf, gravity_chan, &gravity_fit, 8, gravity_data);
187
188 for (int k = 0; k < c; k++) {
189 printk("GV data for %s %lluns (%" PRIq(6) ", %" PRIq(6)
190 ", %" PRIq(6) ")\n", dev->name,
191 PRIsensor_three_axis_data_arg(*gravity_data, k));
192 }
193 i += c;
194
195 /* decode and print Gyroscope GBIAS FIFO frames */
196 c = decoder->decode(buf, gbias_chan, &gbias_fit, 8, gbias_data);
197
198 for (int k = 0; k < c; k++) {
199 printk("GY GBIAS data for %s %lluns (%" PRIq(6) ", %" PRIq(6)
200 ", %" PRIq(6) ")\n", dev->name,
201 PRIsensor_three_axis_data_arg(*gbias_data, k));
202 }
203 i += c;
204 }
205
206 rtio_release_buffer(&stream_ctx, buf, buf_len);
207 }
208 }
209
check_sensor_is_off(const struct device * dev)210 static void check_sensor_is_off(const struct device *dev)
211 {
212 int ret;
213 struct sensor_value odr;
214
215 ret = sensor_attr_get(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);
216
217 /* Check if accel is off */
218 if (ret != 0 || (odr.val1 == 0 && odr.val2 == 0)) {
219 printk("%s WRN : accelerometer device is off\n", dev->name);
220 }
221
222 ret = sensor_attr_get(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);
223
224 /* Check if gyro is off */
225 if (ret != 0 || (odr.val1 == 0 && odr.val2 == 0)) {
226 printk("%s WRN : gyroscope device is off\n", dev->name);
227 }
228 }
229
main(void)230 int main(void)
231 {
232 struct sensor_value gbias[3];
233
234 for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
235 if (!device_is_ready(sensors[i])) {
236 printk("sensor: device %s not ready.\n", sensors[i]->name);
237 return 0;
238 }
239 check_sensor_is_off(sensors[i]);
240
241 /*
242 * Set GBIAS as 0.5 rad/s, -1 rad/s, 0.2 rad/s
243 *
244 * (here application should initialize gbias x/y/z with latest values
245 * calculated from previous run and probably saved to non volatile memory)
246 */
247 gbias[0].val1 = 0;
248 gbias[0].val2 = 500000;
249 gbias[1].val1 = -1;
250 gbias[1].val2 = 0;
251 gbias[2].val1 = 0;
252 gbias[2].val2 = 200000;
253 sensor_attr_set(sensors[i], SENSOR_CHAN_GBIAS_XYZ, SENSOR_ATTR_OFFSET, gbias);
254
255 k_thread_create(&thread_id[i], thread_stack[i], TASK_STACK_SIZE, print_stream,
256 (void *)sensors[i], (void *)iodevs[i], NULL, K_PRIO_COOP(5),
257 K_INHERIT_PERMS, K_FOREVER);
258 k_thread_start(&thread_id[i]);
259 }
260
261 return 0;
262 }
263