1 /*
2 * Copyright (c) 2023 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "icm42688_decoder.h"
8 #include "icm42688_reg.h"
9 #include "icm42688.h"
10 #include <errno.h>
11
12 #include <zephyr/logging/log.h>
13 #include <zephyr/drivers/sensor_clock.h>
14
15 LOG_MODULE_REGISTER(ICM42688_DECODER, CONFIG_SENSOR_LOG_LEVEL);
16
17 #define DT_DRV_COMPAT invensense_icm42688
18
icm42688_get_shift(enum sensor_channel channel,int accel_fs,int gyro_fs,int8_t * shift)19 static int icm42688_get_shift(enum sensor_channel channel, int accel_fs, int gyro_fs, int8_t *shift)
20 {
21 switch (channel) {
22 case SENSOR_CHAN_ACCEL_XYZ:
23 case SENSOR_CHAN_ACCEL_X:
24 case SENSOR_CHAN_ACCEL_Y:
25 case SENSOR_CHAN_ACCEL_Z:
26 switch (accel_fs) {
27 case ICM42688_DT_ACCEL_FS_2:
28 *shift = 5;
29 return 0;
30 case ICM42688_DT_ACCEL_FS_4:
31 *shift = 6;
32 return 0;
33 case ICM42688_DT_ACCEL_FS_8:
34 *shift = 7;
35 return 0;
36 case ICM42688_DT_ACCEL_FS_16:
37 *shift = 8;
38 return 0;
39 default:
40 return -EINVAL;
41 }
42 case SENSOR_CHAN_GYRO_XYZ:
43 case SENSOR_CHAN_GYRO_X:
44 case SENSOR_CHAN_GYRO_Y:
45 case SENSOR_CHAN_GYRO_Z:
46 switch (gyro_fs) {
47 case ICM42688_DT_GYRO_FS_15_625:
48 *shift = -1;
49 return 0;
50 case ICM42688_DT_GYRO_FS_31_25:
51 *shift = 0;
52 return 0;
53 case ICM42688_DT_GYRO_FS_62_5:
54 *shift = 1;
55 return 0;
56 case ICM42688_DT_GYRO_FS_125:
57 *shift = 2;
58 return 0;
59 case ICM42688_DT_GYRO_FS_250:
60 *shift = 3;
61 return 0;
62 case ICM42688_DT_GYRO_FS_500:
63 *shift = 4;
64 return 0;
65 case ICM42688_DT_GYRO_FS_1000:
66 *shift = 5;
67 return 0;
68 case ICM42688_DT_GYRO_FS_2000:
69 *shift = 6;
70 return 0;
71 default:
72 return -EINVAL;
73 }
74 case SENSOR_CHAN_DIE_TEMP:
75 *shift = 9;
76 return 0;
77 default:
78 return -EINVAL;
79 }
80 }
81
icm42688_convert_raw_to_q31(struct icm42688_cfg * cfg,enum sensor_channel chan,int32_t reading,q31_t * out)82 int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel chan, int32_t reading,
83 q31_t *out)
84 {
85 int32_t whole;
86 int32_t fraction;
87 int64_t intermediate;
88 int8_t shift;
89 int rc;
90
91 rc = icm42688_get_shift(chan, cfg->accel_fs, cfg->gyro_fs, &shift);
92 if (rc != 0) {
93 return rc;
94 }
95
96 switch (chan) {
97 case SENSOR_CHAN_ACCEL_XYZ:
98 case SENSOR_CHAN_ACCEL_X:
99 case SENSOR_CHAN_ACCEL_Y:
100 case SENSOR_CHAN_ACCEL_Z:
101 icm42688_accel_ms(cfg, reading, &whole, &fraction);
102 break;
103 case SENSOR_CHAN_GYRO_XYZ:
104 case SENSOR_CHAN_GYRO_X:
105 case SENSOR_CHAN_GYRO_Y:
106 case SENSOR_CHAN_GYRO_Z:
107 icm42688_gyro_rads(cfg, reading, &whole, &fraction);
108 break;
109 case SENSOR_CHAN_DIE_TEMP:
110 icm42688_temp_c(reading, &whole, &fraction);
111 break;
112 default:
113 return -ENOTSUP;
114 }
115 intermediate = ((int64_t)whole * INT64_C(1000000) + fraction);
116 if (shift < 0) {
117 intermediate =
118 intermediate * ((int64_t)INT32_MAX + 1) * (1 << -shift) / INT64_C(1000000);
119 } else if (shift > 0) {
120 intermediate =
121 intermediate * ((int64_t)INT32_MAX + 1) / ((1 << shift) * INT64_C(1000000));
122 }
123 *out = CLAMP(intermediate, INT32_MIN, INT32_MAX);
124
125 return 0;
126 }
127
icm42688_get_channel_position(enum sensor_channel chan)128 static int icm42688_get_channel_position(enum sensor_channel chan)
129 {
130 switch (chan) {
131 case SENSOR_CHAN_DIE_TEMP:
132 return 0;
133 case SENSOR_CHAN_ACCEL_XYZ:
134 case SENSOR_CHAN_ACCEL_X:
135 return 1;
136 case SENSOR_CHAN_ACCEL_Y:
137 return 2;
138 case SENSOR_CHAN_ACCEL_Z:
139 return 3;
140 case SENSOR_CHAN_GYRO_XYZ:
141 case SENSOR_CHAN_GYRO_X:
142 return 4;
143 case SENSOR_CHAN_GYRO_Y:
144 return 5;
145 case SENSOR_CHAN_GYRO_Z:
146 return 6;
147 default:
148 return 0;
149 }
150 }
151
icm42688_encode_channel(enum sensor_channel chan)152 static uint8_t icm42688_encode_channel(enum sensor_channel chan)
153 {
154 uint8_t encode_bmask = 0;
155
156 switch (chan) {
157 case SENSOR_CHAN_DIE_TEMP:
158 case SENSOR_CHAN_ACCEL_X:
159 case SENSOR_CHAN_ACCEL_Y:
160 case SENSOR_CHAN_ACCEL_Z:
161 case SENSOR_CHAN_GYRO_X:
162 case SENSOR_CHAN_GYRO_Y:
163 case SENSOR_CHAN_GYRO_Z:
164 encode_bmask = BIT(icm42688_get_channel_position(chan));
165 break;
166 case SENSOR_CHAN_ACCEL_XYZ:
167 encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_X)) |
168 BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Y)) |
169 BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Z));
170 break;
171 case SENSOR_CHAN_GYRO_XYZ:
172 encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_X)) |
173 BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Y)) |
174 BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Z));
175 break;
176 default:
177 break;
178 }
179
180 return encode_bmask;
181 }
182
icm42688_encode(const struct device * dev,const struct sensor_chan_spec * const channels,const size_t num_channels,uint8_t * buf)183 int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *const channels,
184 const size_t num_channels, uint8_t *buf)
185 {
186 struct icm42688_dev_data *data = dev->data;
187 struct icm42688_encoded_data *edata = (struct icm42688_encoded_data *)buf;
188 uint64_t cycles;
189 int rc;
190
191 edata->channels = 0;
192
193 for (int i = 0; i < num_channels; i++) {
194 edata->channels |= icm42688_encode_channel(channels[i].chan_type);
195 }
196
197 rc = sensor_clock_get_cycles(&cycles);
198 if (rc != 0) {
199 return rc;
200 }
201
202 edata->header.is_fifo = false;
203 edata->header.accel_fs = data->cfg.accel_fs;
204 edata->header.gyro_fs = data->cfg.gyro_fs;
205 edata->header.timestamp = sensor_clock_cycles_to_ns(cycles);
206
207 return 0;
208 }
209
210 #define IS_ACCEL(chan) ((chan) >= SENSOR_CHAN_ACCEL_X && (chan) <= SENSOR_CHAN_ACCEL_XYZ)
211 #define IS_GYRO(chan) ((chan) >= SENSOR_CHAN_GYRO_X && (chan) <= SENSOR_CHAN_GYRO_XYZ)
212
icm42688_read_temperature_from_packet(const uint8_t * pkt)213 static inline q31_t icm42688_read_temperature_from_packet(const uint8_t *pkt)
214 {
215 int32_t temperature;
216 int32_t whole;
217 int32_t fraction;
218
219 /* Temperature always assumes a shift of 9 for a range of (-273,273) C */
220 if (FIELD_GET(FIFO_HEADER_20, pkt[0]) == 1) {
221 temperature = (pkt[0xd] << 8) | pkt[0xe];
222
223 icm42688_temp_c(temperature, &whole, &fraction);
224 } else {
225 if (FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1 &&
226 FIELD_GET(FIFO_HEADER_GYRO, pkt[0]) == 1) {
227 temperature = pkt[0xd];
228 } else {
229 temperature = pkt[0x7];
230 }
231
232 int64_t sensitivity = 207;
233 int64_t temperature100 = (temperature * 100) + (25 * sensitivity);
234
235 whole = temperature100 / sensitivity;
236 fraction =
237 ((temperature100 - whole * sensitivity) * INT64_C(1000000)) / sensitivity;
238 }
239 __ASSERT_NO_MSG(whole >= -512 && whole <= 511);
240 return FIELD_PREP(GENMASK(31, 22), whole) | (fraction * GENMASK64(21, 0) / 1000000);
241 }
242
icm42688_read_imu_from_packet(const uint8_t * pkt,bool is_accel,int fs,uint8_t axis_offset,q31_t * out)243 static int icm42688_read_imu_from_packet(const uint8_t *pkt, bool is_accel, int fs,
244 uint8_t axis_offset, q31_t *out)
245 {
246 uint32_t unsigned_value;
247 int32_t signed_value;
248 bool is_hires = FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1;
249 int offset = 1 + (axis_offset * 2);
250
251 const uint32_t scale[2][2] = {
252 /* low-res, hi-res */
253 {35744, 8936}, /* gyro */
254 {40168, 2511}, /* accel */
255 };
256
257 if (!is_accel && FIELD_GET(FIFO_HEADER_ACCEL, pkt[0]) == 1) {
258 offset += 6;
259 }
260
261 unsigned_value = (pkt[offset] << 8) | pkt[offset + 1];
262
263 if (is_hires) {
264 uint32_t mask = is_accel ? GENMASK(7, 4) : GENMASK(3, 0);
265 offset = 17 + axis_offset;
266 unsigned_value = (unsigned_value << 4) | FIELD_GET(mask, pkt[offset]);
267 signed_value = unsigned_value | (0 - (unsigned_value & BIT(19)));
268 } else {
269 signed_value = unsigned_value | (0 - (unsigned_value & BIT(16)));
270 }
271
272 *out = (q31_t)(signed_value * scale[is_accel][is_hires]);
273 return 0;
274 }
275
276 static uint32_t accel_period_ns[] = {
277 [ICM42688_DT_ACCEL_ODR_1_5625] = UINT32_C(10000000000000) / 15625,
278 [ICM42688_DT_ACCEL_ODR_3_125] = UINT32_C(10000000000000) / 31250,
279 [ICM42688_DT_ACCEL_ODR_6_25] = UINT32_C(10000000000000) / 62500,
280 [ICM42688_DT_ACCEL_ODR_12_5] = UINT32_C(10000000000000) / 12500,
281 [ICM42688_DT_ACCEL_ODR_25] = UINT32_C(1000000000) / 25,
282 [ICM42688_DT_ACCEL_ODR_50] = UINT32_C(1000000000) / 50,
283 [ICM42688_DT_ACCEL_ODR_100] = UINT32_C(1000000000) / 100,
284 [ICM42688_DT_ACCEL_ODR_200] = UINT32_C(1000000000) / 200,
285 [ICM42688_DT_ACCEL_ODR_500] = UINT32_C(1000000000) / 500,
286 [ICM42688_DT_ACCEL_ODR_1000] = UINT32_C(1000000),
287 [ICM42688_DT_ACCEL_ODR_2000] = UINT32_C(1000000) / 2,
288 [ICM42688_DT_ACCEL_ODR_4000] = UINT32_C(1000000) / 4,
289 [ICM42688_DT_ACCEL_ODR_8000] = UINT32_C(1000000) / 8,
290 [ICM42688_DT_ACCEL_ODR_16000] = UINT32_C(1000000) / 16,
291 [ICM42688_DT_ACCEL_ODR_32000] = UINT32_C(1000000) / 32,
292 };
293
294 static uint32_t gyro_period_ns[] = {
295 [ICM42688_DT_GYRO_ODR_12_5] = UINT32_C(10000000000000) / 12500,
296 [ICM42688_DT_GYRO_ODR_25] = UINT32_C(1000000000) / 25,
297 [ICM42688_DT_GYRO_ODR_50] = UINT32_C(1000000000) / 50,
298 [ICM42688_DT_GYRO_ODR_100] = UINT32_C(1000000000) / 100,
299 [ICM42688_DT_GYRO_ODR_200] = UINT32_C(1000000000) / 200,
300 [ICM42688_DT_GYRO_ODR_500] = UINT32_C(1000000000) / 500,
301 [ICM42688_DT_GYRO_ODR_1000] = UINT32_C(1000000),
302 [ICM42688_DT_GYRO_ODR_2000] = UINT32_C(1000000) / 2,
303 [ICM42688_DT_GYRO_ODR_4000] = UINT32_C(1000000) / 4,
304 [ICM42688_DT_GYRO_ODR_8000] = UINT32_C(1000000) / 8,
305 [ICM42688_DT_GYRO_ODR_16000] = UINT32_C(1000000) / 16,
306 [ICM42688_DT_GYRO_ODR_32000] = UINT32_C(1000000) / 32,
307 };
308
icm42688_fifo_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)309 static int icm42688_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
310 uint32_t *fit, uint16_t max_count, void *data_out)
311 {
312 const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer;
313 const uint8_t *buffer_end = buffer + sizeof(struct icm42688_fifo_data) + edata->fifo_count;
314 int accel_frame_count = 0;
315 int gyro_frame_count = 0;
316 int count = 0;
317 int rc;
318
319 if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) {
320 return 0;
321 }
322
323 ((struct sensor_data_header *)data_out)->base_timestamp_ns = edata->header.timestamp;
324
325 buffer += sizeof(struct icm42688_fifo_data);
326 while (count < max_count && buffer < buffer_end) {
327 const bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]) == 1;
328 const bool has_accel = FIELD_GET(FIFO_HEADER_ACCEL, buffer[0]) == 1;
329 const bool has_gyro = FIELD_GET(FIFO_HEADER_GYRO, buffer[0]) == 1;
330 const uint8_t *frame_end = buffer;
331
332 if (is_20b) {
333 frame_end += 20;
334 } else if (has_accel && has_gyro) {
335 frame_end += 16;
336 } else {
337 frame_end += 8;
338 }
339 if (has_accel) {
340 accel_frame_count++;
341 }
342 if (has_gyro) {
343 gyro_frame_count++;
344 }
345
346 if ((uintptr_t)buffer < *fit) {
347 /* This frame was already decoded, move on to the next frame */
348 buffer = frame_end;
349 continue;
350 }
351 if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
352 struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;
353
354 data->shift = 9;
355 if (has_accel) {
356 data->readings[count].timestamp_delta =
357 accel_period_ns[edata->accel_odr] * (accel_frame_count - 1);
358 } else {
359 data->readings[count].timestamp_delta =
360 gyro_period_ns[edata->gyro_odr] * (gyro_frame_count - 1);
361 }
362 data->readings[count].temperature =
363 icm42688_read_temperature_from_packet(buffer);
364 } else if (IS_ACCEL(chan_spec.chan_type) && has_accel) {
365 /* Decode accel */
366 struct sensor_three_axis_data *data =
367 (struct sensor_three_axis_data *)data_out;
368 uint64_t period_ns = accel_period_ns[edata->accel_odr];
369
370 icm42688_get_shift(SENSOR_CHAN_ACCEL_XYZ, edata->header.accel_fs,
371 edata->header.gyro_fs, &data->shift);
372
373 data->readings[count].timestamp_delta = (accel_frame_count - 1) * period_ns;
374 rc = icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 0,
375 &data->readings[count].x);
376 rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 1,
377 &data->readings[count].y);
378 rc |= icm42688_read_imu_from_packet(buffer, true, edata->header.accel_fs, 2,
379 &data->readings[count].z);
380 if (rc != 0) {
381 accel_frame_count--;
382 buffer = frame_end;
383 continue;
384 }
385 } else if (IS_GYRO(chan_spec.chan_type) && has_gyro) {
386 /* Decode gyro */
387 struct sensor_three_axis_data *data =
388 (struct sensor_three_axis_data *)data_out;
389 uint64_t period_ns = gyro_period_ns[edata->gyro_odr];
390
391 icm42688_get_shift(SENSOR_CHAN_GYRO_XYZ, edata->header.accel_fs,
392 edata->header.gyro_fs, &data->shift);
393
394 data->readings[count].timestamp_delta = (gyro_frame_count - 1) * period_ns;
395 rc = icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 0,
396 &data->readings[count].x);
397 rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 1,
398 &data->readings[count].y);
399 rc |= icm42688_read_imu_from_packet(buffer, false, edata->header.gyro_fs, 2,
400 &data->readings[count].z);
401 if (rc != 0) {
402 gyro_frame_count--;
403 buffer = frame_end;
404 continue;
405 }
406 }
407 buffer = frame_end;
408 *fit = (uintptr_t)frame_end;
409 count++;
410 }
411 return count;
412 }
413
icm42688_one_shot_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)414 static int icm42688_one_shot_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
415 uint32_t *fit, uint16_t max_count, void *data_out)
416 {
417 const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer;
418 const struct icm42688_decoder_header *header = &edata->header;
419 struct icm42688_cfg cfg = {
420 .accel_fs = edata->header.accel_fs,
421 .gyro_fs = edata->header.gyro_fs,
422 };
423 uint8_t channel_request;
424 int rc;
425
426 if (*fit != 0) {
427 return 0;
428 }
429 if (max_count == 0 || chan_spec.chan_idx != 0) {
430 return -EINVAL;
431 }
432
433 switch (chan_spec.chan_type) {
434 case SENSOR_CHAN_ACCEL_X:
435 case SENSOR_CHAN_ACCEL_Y:
436 case SENSOR_CHAN_ACCEL_Z:
437 case SENSOR_CHAN_GYRO_X:
438 case SENSOR_CHAN_GYRO_Y:
439 case SENSOR_CHAN_GYRO_Z:
440 case SENSOR_CHAN_DIE_TEMP: {
441 channel_request = icm42688_encode_channel(chan_spec.chan_type);
442 if ((channel_request & edata->channels) != channel_request) {
443 return -ENODATA;
444 }
445
446 struct sensor_q31_data *out = data_out;
447
448 out->header.base_timestamp_ns = edata->header.timestamp;
449 out->header.reading_count = 1;
450
451 rc = icm42688_get_shift(chan_spec.chan_type, header->accel_fs, header->gyro_fs,
452 &out->shift);
453 if (rc != 0) {
454 return -EINVAL;
455 }
456
457 icm42688_convert_raw_to_q31(
458 &cfg, chan_spec.chan_type,
459 edata->readings[icm42688_get_channel_position(chan_spec.chan_type)],
460 &out->readings[0].value);
461 *fit = 1;
462 return 1;
463 }
464 case SENSOR_CHAN_ACCEL_XYZ:
465 case SENSOR_CHAN_GYRO_XYZ: {
466 channel_request = icm42688_encode_channel(chan_spec.chan_type);
467 if ((channel_request & edata->channels) != channel_request) {
468 return -ENODATA;
469 }
470
471 struct sensor_three_axis_data *out = data_out;
472
473 out->header.base_timestamp_ns = edata->header.timestamp;
474 out->header.reading_count = 1;
475 rc = icm42688_get_shift(chan_spec.chan_type, header->accel_fs, header->gyro_fs,
476 &out->shift);
477 if (rc != 0) {
478 return -EINVAL;
479 }
480
481 icm42688_convert_raw_to_q31(
482 &cfg, chan_spec.chan_type - 3,
483 edata->readings[icm42688_get_channel_position(chan_spec.chan_type - 3)],
484 &out->readings[0].x);
485 icm42688_convert_raw_to_q31(
486 &cfg, chan_spec.chan_type - 2,
487 edata->readings[icm42688_get_channel_position(chan_spec.chan_type - 2)],
488 &out->readings[0].y);
489 icm42688_convert_raw_to_q31(
490 &cfg, chan_spec.chan_type - 1,
491 edata->readings[icm42688_get_channel_position(chan_spec.chan_type - 1)],
492 &out->readings[0].z);
493 *fit = 1;
494 return 1;
495 }
496 default:
497 return -EINVAL;
498 }
499 }
500
icm42688_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)501 static int icm42688_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
502 uint32_t *fit, uint16_t max_count, void *data_out)
503 {
504 const struct icm42688_decoder_header *header =
505 (const struct icm42688_decoder_header *)buffer;
506
507 if (header->is_fifo) {
508 return icm42688_fifo_decode(buffer, chan_spec, fit, max_count, data_out);
509 }
510 return icm42688_one_shot_decode(buffer, chan_spec, fit, max_count, data_out);
511 }
512
icm42688_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)513 static int icm42688_decoder_get_frame_count(const uint8_t *buffer,
514 struct sensor_chan_spec chan_spec,
515 uint16_t *frame_count)
516 {
517 const struct icm42688_fifo_data *data = (const struct icm42688_fifo_data *)buffer;
518 const struct icm42688_encoded_data *enc_data = (const struct icm42688_encoded_data *)buffer;
519 const struct icm42688_decoder_header *header = &data->header;
520
521 if (chan_spec.chan_idx != 0) {
522 return -ENOTSUP;
523 }
524
525 uint8_t channel_request = icm42688_encode_channel(chan_spec.chan_type);
526
527
528 if ((!enc_data->header.is_fifo) &&
529 (enc_data->channels & channel_request) != channel_request) {
530 return -ENODATA;
531 }
532
533 if (!header->is_fifo) {
534 switch (chan_spec.chan_type) {
535 case SENSOR_CHAN_ACCEL_X:
536 case SENSOR_CHAN_ACCEL_Y:
537 case SENSOR_CHAN_ACCEL_Z:
538 case SENSOR_CHAN_ACCEL_XYZ:
539 case SENSOR_CHAN_GYRO_X:
540 case SENSOR_CHAN_GYRO_Y:
541 case SENSOR_CHAN_GYRO_Z:
542 case SENSOR_CHAN_GYRO_XYZ:
543 case SENSOR_CHAN_DIE_TEMP:
544 *frame_count = 1;
545 return 0;
546 default:
547 return -ENOTSUP;
548 }
549 return 0;
550 }
551
552 /* Skip the header */
553 buffer += sizeof(struct icm42688_fifo_data);
554
555 uint16_t count = 0;
556 const uint8_t *end = buffer + data->fifo_count;
557
558 while (buffer < end) {
559 bool is_20b = FIELD_GET(FIFO_HEADER_20, buffer[0]);
560 int size = is_20b ? 3 : 2;
561
562 if (FIELD_GET(FIFO_HEADER_ACCEL, buffer[0])) {
563 size += 6;
564 }
565 if (FIELD_GET(FIFO_HEADER_GYRO, buffer[0])) {
566 size += 6;
567 }
568 if (FIELD_GET(FIFO_HEADER_TIMESTAMP_FSYNC, buffer[0])) {
569 size += 2;
570 }
571 if (is_20b) {
572 size += 3;
573 }
574
575 buffer += size;
576 ++count;
577 }
578
579 *frame_count = count;
580 return 0;
581 }
582
icm42688_decoder_get_size_info(struct sensor_chan_spec chan_spec,size_t * base_size,size_t * frame_size)583 static int icm42688_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size,
584 size_t *frame_size)
585 {
586 switch (chan_spec.chan_type) {
587 case SENSOR_CHAN_ACCEL_XYZ:
588 case SENSOR_CHAN_GYRO_XYZ:
589 *base_size = sizeof(struct sensor_three_axis_data);
590 *frame_size = sizeof(struct sensor_three_axis_sample_data);
591 return 0;
592 case SENSOR_CHAN_ACCEL_X:
593 case SENSOR_CHAN_ACCEL_Y:
594 case SENSOR_CHAN_ACCEL_Z:
595 case SENSOR_CHAN_GYRO_X:
596 case SENSOR_CHAN_GYRO_Y:
597 case SENSOR_CHAN_GYRO_Z:
598 case SENSOR_CHAN_DIE_TEMP:
599 *base_size = sizeof(struct sensor_q31_data);
600 *frame_size = sizeof(struct sensor_q31_sample_data);
601 return 0;
602 default:
603 return -ENOTSUP;
604 }
605 }
606
icm24688_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)607 static bool icm24688_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
608 {
609 const struct icm42688_fifo_data *edata = (const struct icm42688_fifo_data *)buffer;
610
611 if (!edata->header.is_fifo) {
612 return false;
613 }
614
615 switch (trigger) {
616 case SENSOR_TRIG_DATA_READY:
617 return FIELD_GET(BIT_INT_STATUS_DATA_RDY, edata->int_status);
618 case SENSOR_TRIG_FIFO_WATERMARK:
619 return FIELD_GET(BIT_INT_STATUS_FIFO_THS, edata->int_status);
620 case SENSOR_TRIG_FIFO_FULL:
621 return FIELD_GET(BIT_INT_STATUS_FIFO_FULL, edata->int_status);
622 default:
623 return false;
624 }
625 }
626
627 SENSOR_DECODER_API_DT_DEFINE() = {
628 .get_frame_count = icm42688_decoder_get_frame_count,
629 .get_size_info = icm42688_decoder_get_size_info,
630 .decode = icm42688_decoder_decode,
631 .has_trigger = icm24688_decoder_has_trigger,
632 };
633
icm42688_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)634 int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
635 {
636 ARG_UNUSED(dev);
637 *decoder = &SENSOR_DECODER_NAME();
638
639 return 0;
640 }
641