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