1 /*
2  * Copyright (c) 2022 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com
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 ACCEL_ALIAS(i) DT_ALIAS(_CONCAT(accel, i))
17 #define ACCELEROMETER_DEVICE(i, _)                                                           \
18 	IF_ENABLED(DT_NODE_EXISTS(ACCEL_ALIAS(i)), (DEVICE_DT_GET(ACCEL_ALIAS(i)),))
19 #define NUM_SENSORS 1
20 
21 /* support up to 10 accelerometer sensors */
22 static const struct device *const sensors[] = {LISTIFY(10, ACCELEROMETER_DEVICE, ())};
23 
24 #ifdef CONFIG_SENSOR_ASYNC_API
25 
26 #define ACCEL_IODEV_SYM(id) CONCAT(accel_iodev, id)
27 #define ACCEL_IODEV_PTR(id, _) &ACCEL_IODEV_SYM(id)
28 
29 #define ACCEL_TRIGGERS                                   \
30 	{SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_INCLUDE}, \
31 	{SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE}
32 
33 #define ACCEL_DEFINE_IODEV(id, _)         \
34 	SENSOR_DT_STREAM_IODEV(               \
35 		ACCEL_IODEV_SYM(id),              \
36 		ACCEL_ALIAS(id),                  \
37 		ACCEL_TRIGGERS);
38 
39 LISTIFY(NUM_SENSORS, ACCEL_DEFINE_IODEV, (;));
40 
41 struct rtio_iodev *iodevs[NUM_SENSORS] = { LISTIFY(NUM_SENSORS, ACCEL_IODEV_PTR, (,)) };
42 
43 RTIO_DEFINE_WITH_MEMPOOL(accel_ctx, NUM_SENSORS, NUM_SENSORS, NUM_SENSORS*20, 256, sizeof(void *));
44 
print_accels_stream(const struct device * dev,struct rtio_iodev * iodev)45 static int print_accels_stream(const struct device *dev, struct rtio_iodev *iodev)
46 {
47 	int rc = 0;
48 	struct sensor_three_axis_data accel_data = {0};
49 	const struct sensor_decoder_api *decoder;
50 	struct rtio_cqe *cqe;
51 	uint8_t *buf;
52 	uint32_t buf_len;
53 	struct rtio_sqe *handles[NUM_SENSORS];
54 
55 	/* Start the streams */
56 	for (int i = 0; i < NUM_SENSORS; i++) {
57 		printk("sensor_stream\n");
58 		sensor_stream(iodevs[i], &accel_ctx, NULL, &handles[i]);
59 	}
60 
61 	while (1) {
62 		cqe = rtio_cqe_consume_block(&accel_ctx);
63 
64 		if (cqe->result != 0) {
65 			printk("async read failed %d\n", cqe->result);
66 			return cqe->result;
67 		}
68 
69 		rc = rtio_cqe_get_mempool_buffer(&accel_ctx, cqe, &buf, &buf_len);
70 
71 		if (rc != 0) {
72 			printk("get mempool buffer failed %d\n", rc);
73 			return rc;
74 		}
75 
76 		const struct device *sensor = dev;
77 
78 		rtio_cqe_release(&accel_ctx, cqe);
79 
80 		rc = sensor_get_decoder(sensor, &decoder);
81 
82 		if (rc != 0) {
83 			printk("sensor_get_decoder failed %d\n", rc);
84 			return rc;
85 		}
86 
87 		/* Frame iterator values when data comes from a FIFO */
88 		uint32_t accel_fit = 0;
89 
90 		/* Number of accelerometer data frames */
91 		uint16_t frame_count;
92 
93 		rc = decoder->get_frame_count(buf,
94 				(struct sensor_chan_spec) {SENSOR_CHAN_ACCEL_XYZ, 0}, &frame_count);
95 
96 		if (rc != 0) {
97 			printk("sensor_get_decoder failed %d\n", rc);
98 			return rc;
99 		}
100 
101 		/* If a tap has occurred lets print it out */
102 		if (decoder->has_trigger(buf, SENSOR_TRIG_TAP)) {
103 			printk("Tap! Sensor %s\n", dev->name);
104 		}
105 
106 		/* Decode all available accelerometer sample frames */
107 		for (int i = 0; i < frame_count; i++) {
108 			decoder->decode(buf, (struct sensor_chan_spec) {SENSOR_CHAN_ACCEL_XYZ, 0},
109 					&accel_fit, 1, &accel_data);
110 
111 			printk("Accel data for %s (%" PRIq(6) ", %" PRIq(6)
112 					", %" PRIq(6) ") %lluns\n", dev->name,
113 			PRIq_arg(accel_data.readings[0].x, 6, accel_data.shift),
114 			PRIq_arg(accel_data.readings[0].y, 6, accel_data.shift),
115 			PRIq_arg(accel_data.readings[0].z, 6, accel_data.shift),
116 			(accel_data.header.base_timestamp_ns
117 			+ accel_data.readings[0].timestamp_delta));
118 		}
119 
120 		rtio_release_buffer(&accel_ctx, buf, buf_len);
121 	}
122 
123 	return rc;
124 }
125 #else
126 
127 static const enum sensor_channel channels[] = {
128 	SENSOR_CHAN_ACCEL_X,
129 	SENSOR_CHAN_ACCEL_Y,
130 	SENSOR_CHAN_ACCEL_Z,
131 };
132 
print_accels(const struct device * dev)133 static int print_accels(const struct device *dev)
134 {
135 	int ret;
136 	struct sensor_value accel[3];
137 
138 	ret = sensor_sample_fetch(dev);
139 	if (ret < 0) {
140 		printk("%s: sensor_sample_fetch() failed: %d\n", dev->name, ret);
141 		return ret;
142 	}
143 
144 	for (size_t i = 0; i < ARRAY_SIZE(channels); i++) {
145 		ret = sensor_channel_get(dev, channels[i], &accel[i]);
146 		if (ret < 0) {
147 			printk("%s: sensor_channel_get(%c) failed: %d\n", dev->name, 'X' + i, ret);
148 			return ret;
149 		}
150 	}
151 
152 	printk("%16s [m/s^2]:    (%12.6f, %12.6f, %12.6f)\n", dev->name,
153 	       sensor_value_to_double(&accel[0]), sensor_value_to_double(&accel[1]),
154 	       sensor_value_to_double(&accel[2]));
155 
156 	return 0;
157 }
158 #endif /*CONFIG_SENSOR_ASYNC_API*/
159 
set_sampling_freq(const struct device * dev)160 static int set_sampling_freq(const struct device *dev)
161 {
162 	int ret;
163 	struct sensor_value odr;
164 
165 	ret = sensor_attr_get(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);
166 
167 	/* If we don't get a frequency > 0, we set one */
168 	if (ret != 0 || (odr.val1 == 0 && odr.val2 == 0)) {
169 		odr.val1 = 100;
170 		odr.val2 = 0;
171 
172 		ret = sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY,
173 				      &odr);
174 
175 		if (ret != 0) {
176 			printk("%s : failed to set sampling frequency\n", dev->name);
177 		}
178 	}
179 
180 	return 0;
181 }
182 
main(void)183 int main(void)
184 {
185 	int ret;
186 
187 	for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
188 		if (!device_is_ready(sensors[i])) {
189 			printk("sensor: device %s not ready.\n", sensors[i]->name);
190 			return 0;
191 		}
192 		set_sampling_freq(sensors[i]);
193 	}
194 
195 #ifndef CONFIG_COVERAGE
196 	while (1) {
197 #else
198 	for (int i = 0; i < 5; i++) {
199 #endif
200 		for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) {
201 #ifdef CONFIG_SENSOR_ASYNC_API
202 			ret = print_accels_stream(sensors[i], iodevs[i]);
203 #else
204 			ret = print_accels(sensors[i]);
205 #endif /*CONFIG_SENSOR_ASYNC_API*/
206 			if (ret < 0) {
207 				return 0;
208 			}
209 		}
210 		k_msleep(1000);
211 	}
212 	return 0;
213 }
214