1 /*
2  * Copyright (c) 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/devicetree.h>
8 #include <zephyr/drivers/emul.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/gpio/gpio_emul.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/fff.h>
13 #include <zephyr/ztest.h>
14 
15 #include "icm42688_emul.h"
16 #include "icm42688_reg.h"
17 
18 #define NODE DT_NODELABEL(icm42688)
19 
20 DEFINE_FFF_GLOBALS;
21 
22 struct icm42688_fixture {
23 	const struct device *dev;
24 	const struct emul *target;
25 };
26 
icm42688_setup(void)27 static void *icm42688_setup(void)
28 {
29 	static struct icm42688_fixture fixture = {
30 		.dev = DEVICE_DT_GET(DT_NODELABEL(icm42688)),
31 		.target = EMUL_DT_GET(DT_NODELABEL(icm42688)),
32 	};
33 
34 	zassert_not_null(fixture.dev);
35 	zassert_not_null(fixture.target);
36 	return &fixture;
37 }
38 
39 ZTEST_SUITE(icm42688, NULL, icm42688_setup, NULL, NULL, NULL);
40 
ZTEST_F(icm42688,test_fetch_fail_no_ready_data)41 ZTEST_F(icm42688, test_fetch_fail_no_ready_data)
42 {
43 	uint8_t status = 0;
44 
45 	icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, &status, 1);
46 	zassert_equal(-EBUSY, sensor_sample_fetch(fixture->dev));
47 }
48 
test_fetch_temp_mc(const struct icm42688_fixture * fixture,int16_t temperature_mc)49 static void test_fetch_temp_mc(const struct icm42688_fixture *fixture, int16_t temperature_mc)
50 {
51 	struct sensor_value value;
52 	int64_t expected_uc;
53 	int64_t actual_uc;
54 	int16_t temperature_reg;
55 	uint8_t buffer[2];
56 
57 	/* Set the INT_STATUS register to show we have data */
58 	buffer[0] = BIT_INT_STATUS_DATA_RDY;
59 	icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, buffer, 1);
60 
61 	/*
62 	 * Set the temperature data to 22.5C via:
63 	 *   reg_val / 132.48 + 25
64 	 */
65 	temperature_reg = ((temperature_mc - 25000) * 13248) / 100000;
66 	buffer[0] = (temperature_reg >> 8) & GENMASK(7, 0);
67 	buffer[1] = temperature_reg & GENMASK(7, 0);
68 	icm42688_emul_set_reg(fixture->target, REG_TEMP_DATA1, buffer, 2);
69 
70 	/* Fetch the data */
71 	zassert_ok(sensor_sample_fetch(fixture->dev));
72 	zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_DIE_TEMP, &value));
73 
74 	/* Assert data is within 5 milli-C of the tested temperature */
75 	expected_uc = temperature_mc * INT64_C(1000);
76 	actual_uc = sensor_value_to_micro(&value);
77 	zassert_within(expected_uc, actual_uc, INT64_C(5000),
78 		       "Expected %" PRIi64 "uC, got %" PRIi64 "uC", expected_uc, actual_uc);
79 }
80 
ZTEST_F(icm42688,test_fetch_temp)81 ZTEST_F(icm42688, test_fetch_temp)
82 {
83 	/* Test 22.5C */
84 	test_fetch_temp_mc(fixture, 22500);
85 	/* Test -3.175C */
86 	test_fetch_temp_mc(fixture, -3175);
87 }
88 
test_fetch_accel_with_range(const struct icm42688_fixture * fixture,int16_t accel_range_g,const int16_t accel_percent[3])89 static void test_fetch_accel_with_range(const struct icm42688_fixture *fixture,
90 					int16_t accel_range_g, const int16_t accel_percent[3])
91 {
92 	struct sensor_value values[3];
93 	int32_t expect_ug;
94 	int32_t actual_ug;
95 	uint8_t register_buffer[6];
96 
97 	/* Se the INT_STATUS register to show we have data */
98 	register_buffer[0] = BIT_INT_STATUS_DATA_RDY;
99 	icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1);
100 
101 	/* Set accel range */
102 	sensor_g_to_ms2(accel_range_g, &values[0]);
103 	zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_FULL_SCALE,
104 				   &values[0]));
105 
106 	/* Set the accel data accel_percent * accel_range_g */
107 	for (int i = 0; i < 3; ++i) {
108 		register_buffer[i * 2] = (accel_percent[i] >> 8) & GENMASK(7, 0);
109 		register_buffer[i * 2 + 1] = accel_percent[i] & GENMASK(7, 0);
110 	}
111 	icm42688_emul_set_reg(fixture->target, REG_ACCEL_DATA_X1, register_buffer, 6);
112 
113 	/* Fetch the data */
114 	zassert_ok(sensor_sample_fetch(fixture->dev));
115 	zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_ACCEL_XYZ, values));
116 
117 	/* Assert the data is within 0.005g (0.05m/s2) */
118 	actual_ug = sensor_ms2_to_ug(&values[0]);
119 	expect_ug = (int32_t)(accel_percent[0] * INT64_C(1000000) * accel_range_g / INT16_MAX);
120 	zassert_within(expect_ug, actual_ug, INT32_C(5000),
121 		       "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
122 
123 	actual_ug = sensor_ms2_to_ug(&values[1]);
124 	expect_ug = (int32_t)(accel_percent[1] * INT64_C(1000000) * accel_range_g / INT16_MAX);
125 	zassert_within(expect_ug, actual_ug, INT32_C(5000),
126 		       "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
127 
128 	actual_ug = sensor_ms2_to_ug(&values[2]);
129 	expect_ug = (int32_t)(accel_percent[2] * INT64_C(1000000) * accel_range_g / INT16_MAX);
130 	zassert_within(expect_ug, actual_ug, INT32_C(5000),
131 		       "Expected %" PRIi32 " ug, got X=%" PRIi32 " ug", expect_ug, actual_ug);
132 }
133 
ZTEST_F(icm42688,test_fetch_accel)134 ZTEST_F(icm42688, test_fetch_accel)
135 {
136 	/* Use (0.25, -0.33.., 0.91) * range for testing accel values */
137 	const int16_t accel_percent[3] = {
138 		INT16_MAX / INT16_C(4),
139 		INT16_MIN / INT16_C(3),
140 		(int16_t)((INT16_MAX * INT32_C(91)) / INT32_C(100)),
141 	};
142 
143 	test_fetch_accel_with_range(fixture, 2, accel_percent);
144 	test_fetch_accel_with_range(fixture, 4, accel_percent);
145 	test_fetch_accel_with_range(fixture, 8, accel_percent);
146 	test_fetch_accel_with_range(fixture, 16, accel_percent);
147 }
148 
test_fetch_gyro_with_range(const struct icm42688_fixture * fixture,int32_t scale_mdps,const int16_t gyro_percent[3])149 static void test_fetch_gyro_with_range(const struct icm42688_fixture *fixture, int32_t scale_mdps,
150 				       const int16_t gyro_percent[3])
151 {
152 	/* Set the epsilon to 0.075% of the scale */
153 	const int32_t epsilon_10udps = scale_mdps * 75 / 1000;
154 	struct sensor_value values[3];
155 	int32_t expect_10udps;
156 	int32_t actual_10udps;
157 	uint8_t register_buffer[6];
158 
159 	/* Se the INT_STATUS register to show we have data */
160 	register_buffer[0] = BIT_INT_STATUS_DATA_RDY;
161 	icm42688_emul_set_reg(fixture->target, REG_INT_STATUS, register_buffer, 1);
162 
163 	/* Set gyro range */
164 	sensor_degrees_to_rad((scale_mdps / 1000) + (scale_mdps % 1000 == 0 ? 0 : 1), &values[0]);
165 	zassert_ok(sensor_attr_set(fixture->dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_FULL_SCALE,
166 				   &values[0]));
167 
168 	/* Set the gyro data to gyro_percent */
169 	for (int i = 0; i < 3; ++i) {
170 		register_buffer[i * 2] = (gyro_percent[i] >> 8) & GENMASK(7, 0);
171 		register_buffer[i * 2 + 1] = gyro_percent[i] & GENMASK(7, 0);
172 	}
173 	icm42688_emul_set_reg(fixture->target, REG_GYRO_DATA_X1, register_buffer, 6);
174 
175 	/* Fetch the data */
176 	zassert_ok(sensor_sample_fetch(fixture->dev));
177 	zassert_ok(sensor_channel_get(fixture->dev, SENSOR_CHAN_GYRO_XYZ, values));
178 
179 	/* Assert the data is within 0.5 d/s (0.001 rad/s) */
180 	actual_10udps = sensor_rad_to_10udegrees(&values[0]);
181 	expect_10udps = (int32_t)(gyro_percent[0] * INT64_C(100) * scale_mdps / INT16_MAX);
182 	zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
183 		       "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
184 		       " 10ud/s",
185 		       scale_mdps, expect_10udps, actual_10udps);
186 
187 	actual_10udps = sensor_rad_to_10udegrees(&values[1]);
188 	expect_10udps = (int32_t)(gyro_percent[1] * INT64_C(100) * scale_mdps / INT16_MAX);
189 	zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
190 		       "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
191 		       " 10ud/s, ",
192 		       scale_mdps, expect_10udps, actual_10udps);
193 
194 	actual_10udps = sensor_rad_to_10udegrees(&values[2]);
195 	expect_10udps = (int32_t)(gyro_percent[2] * INT64_C(100) * scale_mdps / INT16_MAX);
196 	zassert_within(expect_10udps, actual_10udps, epsilon_10udps,
197 		       "[scale=%" PRIi32 "md/s] Expected %" PRIi32 " 10ud/s, got %" PRIi32
198 		       " 10ud/s",
199 		       scale_mdps, expect_10udps, actual_10udps);
200 }
201 
ZTEST_F(icm42688,test_fetch_gyro)202 ZTEST_F(icm42688, test_fetch_gyro)
203 {
204 	/* Use (0.15, 0.68, -0.22) * range for testing gyro values */
205 	const int16_t gyro_percent[3] = {
206 		(int16_t)((INT16_MAX * INT32_C(15)) / INT32_C(100)),
207 		(int16_t)((INT16_MAX * INT32_C(68)) / INT32_C(100)),
208 		(int16_t)((INT16_MAX * INT32_C(-22)) / INT32_C(100)),
209 	};
210 
211 	test_fetch_gyro_with_range(fixture, 2000000, gyro_percent);
212 	test_fetch_gyro_with_range(fixture, 1000000, gyro_percent);
213 	test_fetch_gyro_with_range(fixture, 500000, gyro_percent);
214 	test_fetch_gyro_with_range(fixture, 250000, gyro_percent);
215 	test_fetch_gyro_with_range(fixture, 125000, gyro_percent);
216 	test_fetch_gyro_with_range(fixture, 62500, gyro_percent);
217 	test_fetch_gyro_with_range(fixture, 31250, gyro_percent);
218 	test_fetch_gyro_with_range(fixture, 15625, gyro_percent);
219 }
220 
221 FAKE_VOID_FUNC(test_interrupt_trigger_handler, const struct device*, const struct sensor_trigger*);
222 
ZTEST_F(icm42688,test_interrupt)223 ZTEST_F(icm42688, test_interrupt)
224 {
225 	const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(NODE, int_gpios);
226 	const struct sensor_trigger trigger = {
227 		.type = SENSOR_TRIG_DATA_READY,
228 		.chan = SENSOR_CHAN_ALL,
229 	};
230 
231 	RESET_FAKE(test_interrupt_trigger_handler);
232 	sensor_trigger_set(fixture->dev, &trigger, test_interrupt_trigger_handler);
233 
234 	/* Toggle the GPIO */
235 	gpio_emul_input_set(spec.port, spec.pin, 0);
236 	k_msleep(5);
237 	gpio_emul_input_set(spec.port, spec.pin, 1);
238 	k_msleep(5);
239 
240 	/* Verify the handler was called */
241 	zassert_equal(test_interrupt_trigger_handler_fake.call_count, 1);
242 }
243