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