1 /*
2  * Copyright 2025 CogniPilot Foundation
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <stdio.h>
7 #include <math.h>
8 #include <zephyr/device.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/ztest.h>
11 #include <zephyr/rtio/rtio.h>
12 #include <zephyr/drivers/sensor.h>
13 #include <zephyr/logging/log.h>
14 
15 #define BATCH_DURATION 50
16 
q31_to_double(int32_t q31_value,int8_t shift)17 double q31_to_double(int32_t q31_value, int8_t shift)
18 {
19 	return ((double)q31_value) / (double)(1 << (31 - shift));
20 }
21 
22 static struct rtio_sqe *streaming_handle;
23 
24 static struct sensor_stream_trigger stream_trigger = {
25 	.opt = SENSOR_STREAM_DATA_INCLUDE,
26 	.trigger = SENSOR_TRIG_FIFO_WATERMARK,
27 };
28 
29 static struct sensor_read_config stream_config = {
30 	.sensor = DEVICE_DT_GET(DT_NODELABEL(icm42688_1)),
31 	.is_streaming = true,
32 	.triggers = &stream_trigger,
33 	.count = 0,
34 	.max = 1,
35 };
36 
37 static RTIO_IODEV_DEFINE(iodev_stream, &__sensor_iodev_api, &stream_config);
38 RTIO_DEFINE_WITH_MEMPOOL(rtio, 4, 4, 32, 64, 4);
39 
callback(int result,uint8_t * buf,uint32_t buf_len,void * userdata)40 static void callback(int result, uint8_t *buf, uint32_t buf_len, void *userdata)
41 {
42 	static uint8_t decoded_buffer[127];
43 
44 	zassert_not_null(stream_config.sensor->api);
45 	const struct sensor_decoder_api *decoder;
46 
47 	zassert_ok(sensor_get_decoder(stream_config.sensor, &decoder));
48 	int channels[] = {
49 		SENSOR_CHAN_GYRO_XYZ,
50 		SENSOR_CHAN_ACCEL_XYZ,
51 	};
52 
53 	for (int i = 0; i < ARRAY_SIZE(channels); i++) {
54 		int chan = channels[i];
55 		struct sensor_chan_spec ch = {
56 			.chan_idx = 0,
57 			.chan_type = chan,
58 		};
59 
60 		uint32_t fit = 0;
61 		int count = 0;
62 
63 		while (decoder->decode(buf, ch, &fit, 1, decoded_buffer) > 0) {
64 			zassert(count++ < 127, "fifo overflow");
65 			if (ch.chan_type == SENSOR_CHAN_ACCEL_XYZ) {
66 				struct sensor_three_axis_data *data =
67 					(struct sensor_three_axis_data *)decoded_buffer;
68 				double x = q31_to_double(data->readings[0].values[0], data->shift);
69 				double y = q31_to_double(data->readings[0].values[1], data->shift);
70 				double z = q31_to_double(data->readings[0].values[2], data->shift);
71 
72 				zassert(fabs(x) < 1.0, "fail", "accel x out of range: %10.4f", x);
73 				zassert(fabs(y) < 1.0, "fail", "accel y out of range: %10.4f", y);
74 				zassert(fabs(z - 9.8) < 1.0, "fail",
75 					"accel z out of range: %10.4f", z);
76 			} else if (ch.chan_type == SENSOR_CHAN_GYRO_XYZ) {
77 				struct sensor_three_axis_data *data =
78 					(struct sensor_three_axis_data *)decoded_buffer;
79 				double x = q31_to_double(data->readings[0].values[0], data->shift);
80 				double y = q31_to_double(data->readings[0].values[1], data->shift);
81 				double z = q31_to_double(data->readings[0].values[2], data->shift);
82 
83 				zassert(fabs(x) < 0.1, "fail", "gyro x out of range: %10.4f", x);
84 				zassert(fabs(y) < 0.1, "fail", "gyro y out of range: %10.4f", y);
85 				zassert(fabs(z) < 0.1, "fail", "gyro z out of range: %10.4f", z);
86 			}
87 		}
88 	}
89 }
90 
ZTEST(icm42688_stream,test_icm42688_stream)91 ZTEST(icm42688_stream, test_icm42688_stream)
92 {
93 	stream_config.count = 1;
94 	struct sensor_value val_in = { BATCH_DURATION, 0 };
95 
96 	zassert_ok(sensor_attr_set(
97 		stream_config.sensor,
98 		SENSOR_CHAN_ALL,
99 		SENSOR_ATTR_BATCH_DURATION, &val_in));
100 	struct sensor_value val_out;
101 
102 	zassert_ok(sensor_attr_get(
103 		stream_config.sensor,
104 		SENSOR_CHAN_ALL,
105 		SENSOR_ATTR_BATCH_DURATION, &val_out));
106 	zassert_equal(val_in.val1, val_out.val1);
107 	zassert_ok(sensor_stream(&iodev_stream, &rtio, NULL,
108 		&streaming_handle));
109 	sensor_processing_with_callback(&rtio, callback);
110 	zassert_ok(rtio_sqe_cancel(streaming_handle));
111 }
112 
icm42688_stream_setup(void)113 static void *icm42688_stream_setup(void)
114 {
115 	return NULL;
116 }
117 
118 
119 ZTEST_SUITE(icm42688_stream, NULL, icm42688_stream_setup, NULL, NULL, NULL);
120