1 /*
2 * Copyright (c) 2024 Analog Devices Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "adxl362.h"
8 #include <zephyr/sys/byteorder.h>
9
10 #ifdef CONFIG_ADXL362_STREAM
11
12 /* (2^31 / 2^8(shift) */
13 #define ADXL362_TEMP_QSCALE 8388608
14 #define ADXL362_TEMP_LSB_PER_C 15
15
16 #define ADXL362_COMPLEMENT 0xf000
17
18 static const uint32_t accel_period_ns[] = {
19 [ADXL362_ODR_12_5_HZ] = UINT32_C(10000000000) / 125,
20 [ADXL362_ODR_25_HZ] = UINT32_C(1000000000) / 25,
21 [ADXL362_ODR_50_HZ] = UINT32_C(1000000000) / 50,
22 [ADXL362_ODR_100_HZ] = UINT32_C(1000000000) / 100,
23 [ADXL362_ODR_200_HZ] = UINT32_C(1000000000) / 200,
24 [ADXL362_ODR_400_HZ] = UINT32_C(1000000000) / 400,
25 };
26
27 static const uint32_t range_to_shift[] = {
28 [ADXL362_RANGE_2G] = 5,
29 [ADXL362_RANGE_4G] = 6,
30 [ADXL362_RANGE_8G] = 7,
31 };
32
33 /* (1 / sensitivity) * (pow(2,31) / pow(2,shift)) * (unit_scaler) */
34 static const uint32_t qscale_factor[] = {
35 /* (1.0 / ADXL362_ACCEL_2G_LSB_PER_G) * (2^31 / 2^5) * SENSOR_G / 1000000 */
36 [ADXL362_RANGE_2G] = UINT32_C(658338),
37 /* (1.0 / ADXL362_ACCEL_4G_LSB_PER_G) * (2^31 / 2^6) * SENSOR_G / 1000000 */
38 [ADXL362_RANGE_4G] = UINT32_C(658338),
39 /* (1.0 / ADXL362_ACCEL_8G_LSB_PER_G) * (2^31 / 2^7) ) * SENSOR_G / 1000000 */
40 [ADXL362_RANGE_8G] = UINT32_C(700360),
41 };
42
adxl362_temp_convert_q31(q31_t * out,int16_t data_in)43 static inline void adxl362_temp_convert_q31(q31_t *out, int16_t data_in)
44 {
45 /* See sensitivity and bias specifications in table 1 of datasheet */
46 data_in &= 0xFFF;
47
48 if (data_in & BIT(11)) {
49 data_in |= ADXL362_COMPLEMENT;
50 }
51
52 *out = ((data_in - ADXL362_TEMP_BIAS_LSB) / ADXL362_TEMP_LSB_PER_C
53 + ADXL362_TEMP_BIAS_TEST_CONDITION) * ADXL362_TEMP_QSCALE;
54 }
55
adxl362_accel_convert_q31(q31_t * out,int16_t data_in,int32_t range)56 static inline void adxl362_accel_convert_q31(q31_t *out, int16_t data_in, int32_t range)
57 {
58 data_in &= 0xFFF;
59
60 if (data_in & BIT(11)) {
61 data_in |= ADXL362_COMPLEMENT;
62 }
63
64 *out = data_in * qscale_factor[range];
65 }
66
adxl362_decode_stream(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)67 static int adxl362_decode_stream(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
68 uint32_t *fit, uint16_t max_count, void *data_out)
69 {
70 const struct adxl362_fifo_data *enc_data = (const struct adxl362_fifo_data *)buffer;
71 const uint8_t *buffer_end =
72 buffer + sizeof(struct adxl362_fifo_data) + enc_data->fifo_byte_count;
73 int count = 0;
74 uint8_t sample_num = 0;
75 int16_t data_in;
76
77 if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) {
78 return 0;
79 }
80
81 buffer += sizeof(struct adxl362_fifo_data);
82
83 uint8_t sample_set_size = 6;
84
85 if (enc_data->has_tmp) {
86 sample_set_size = 8;
87 }
88
89 uint64_t period_ns = accel_period_ns[enc_data->accel_odr];
90
91 /* Calculate which sample is decoded. */
92 if ((uint8_t *)*fit >= buffer) {
93 sample_num = ((uint8_t *)*fit - buffer) / sample_set_size;
94 }
95
96 while (count < max_count && buffer < buffer_end) {
97 const uint8_t *sample_end = buffer;
98
99 sample_end += sample_set_size;
100
101 if ((uintptr_t)buffer < *fit) {
102 /* This frame was already decoded, move on to the next frame */
103 buffer = sample_end;
104 continue;
105 }
106
107 if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
108 if (enc_data->has_tmp) {
109 struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;
110
111 memset(data, 0, sizeof(struct sensor_three_axis_data));
112 data->header.base_timestamp_ns = enc_data->timestamp;
113 data->header.reading_count = 1;
114 data->shift = 8;
115
116 data->readings[count].timestamp_delta =
117 period_ns * sample_num;
118
119 data_in = sys_le16_to_cpu(*((int16_t *)(buffer + 6)));
120
121 /* Check if this sample contains temperature value. */
122 if (ADXL362_FIFO_HDR_CHECK_TEMP(data_in)) {
123 adxl362_temp_convert_q31(&data->readings[count].temperature,
124 data_in);
125 }
126 }
127 } else {
128 struct sensor_three_axis_data *data =
129 (struct sensor_three_axis_data *)data_out;
130
131 memset(data, 0, sizeof(struct sensor_three_axis_data));
132 data->header.base_timestamp_ns = enc_data->timestamp;
133 data->header.reading_count = 1;
134 data->shift = range_to_shift[enc_data->selected_range];
135
136 switch (chan_spec.chan_type) {
137 case SENSOR_CHAN_ACCEL_X:
138 data->readings[count].timestamp_delta = sample_num
139 * period_ns;
140
141 /* Convert received data into signeg integer. */
142 data_in = sys_le16_to_cpu(*((int16_t *)buffer));
143
144 /* Check if this sample contains X value. */
145 if (ADXL362_FIFO_HDR_CHECK_ACCEL_X(data_in)) {
146 adxl362_accel_convert_q31(&data->readings[count].x,
147 data_in, enc_data->selected_range);
148 }
149 break;
150 case SENSOR_CHAN_ACCEL_Y:
151 data->readings[count].timestamp_delta = sample_num
152 * period_ns;
153
154 /* Convert received data into signeg integer. */
155 data_in = sys_le16_to_cpu(*((int16_t *)(buffer + 2)));
156
157 /* Check if this sample contains Y value. */
158 if (ADXL362_FIFO_HDR_CHECK_ACCEL_Y(data_in)) {
159 adxl362_accel_convert_q31(&data->readings[count].y,
160 data_in, enc_data->selected_range);
161 }
162 break;
163 case SENSOR_CHAN_ACCEL_Z:
164 data->readings[count].timestamp_delta = sample_num
165 * period_ns;
166 /* Convert received data into signeg integer. */
167 data_in = sys_le16_to_cpu(*((int16_t *)(buffer + 4)));
168
169 /* Check if this sample contains Y value. */
170 if (ADXL362_FIFO_HDR_CHECK_ACCEL_Z(data_in)) {
171 adxl362_accel_convert_q31(&data->readings[count].z,
172 data_in, enc_data->selected_range);
173 }
174 break;
175 case SENSOR_CHAN_ACCEL_XYZ:
176 data->readings[count].timestamp_delta = sample_num * period_ns;
177
178 /* Convert received data into signeg integer. */
179 data_in = sys_le16_to_cpu(*((int16_t *)buffer));
180
181 /* Check if this sample contains X value. */
182 if (ADXL362_FIFO_HDR_CHECK_ACCEL_X(data_in)) {
183 adxl362_accel_convert_q31(&data->readings[count].x,
184 data_in, enc_data->selected_range);
185 }
186
187 /* Convert received data into signeg integer. */
188 data_in = sys_le16_to_cpu(*((int16_t *)(buffer + 2)));
189
190 /* Check if this sample contains Y value. */
191 if (ADXL362_FIFO_HDR_CHECK_ACCEL_Y(data_in)) {
192 adxl362_accel_convert_q31(&data->readings[count].y,
193 data_in, enc_data->selected_range);
194 }
195
196 /* Convert received data into signeg integer. */
197 data_in = sys_le16_to_cpu(*((int16_t *)(buffer + 4)));
198
199 /* Check if this sample contains Z value. */
200 if (ADXL362_FIFO_HDR_CHECK_ACCEL_Z(data_in)) {
201 adxl362_accel_convert_q31(&data->readings[count].z,
202 data_in, enc_data->selected_range);
203 }
204 break;
205 default:
206 return -ENOTSUP;
207 }
208 }
209
210 buffer = sample_end;
211 *fit = (uintptr_t)sample_end;
212 count++;
213 }
214 return count;
215 }
216
217 #endif /* CONFIG_ADXL362_STREAM */
218
adxl362_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)219 static int adxl362_decoder_get_frame_count(const uint8_t *buffer,
220 struct sensor_chan_spec chan_spec,
221 uint16_t *frame_count)
222 {
223 int32_t ret = -ENOTSUP;
224
225 if (chan_spec.chan_idx != 0) {
226 return ret;
227 }
228
229 #ifdef CONFIG_ADXL362_STREAM
230 const struct adxl362_fifo_data *data = (const struct adxl362_fifo_data *)buffer;
231
232 if (!data->is_fifo) {
233 #endif /* CONFIG_ADXL362_STREAM */
234 switch (chan_spec.chan_type) {
235 case SENSOR_CHAN_ACCEL_X:
236 case SENSOR_CHAN_ACCEL_Y:
237 case SENSOR_CHAN_ACCEL_Z:
238 case SENSOR_CHAN_ACCEL_XYZ:
239 *frame_count = 1;
240 ret = 0;
241 break;
242
243 default:
244 break;
245 }
246 #ifdef CONFIG_ADXL362_STREAM
247 } else {
248 if (data->fifo_byte_count == 0) {
249 *frame_count = 0;
250 ret = 0;
251 } else {
252 switch (chan_spec.chan_type) {
253 case SENSOR_CHAN_ACCEL_X:
254 case SENSOR_CHAN_ACCEL_Y:
255 case SENSOR_CHAN_ACCEL_Z:
256 case SENSOR_CHAN_ACCEL_XYZ:
257 if (data->has_tmp) {
258 /*6 bytes for XYZ and 2 bytes for TEMP*/
259 *frame_count = data->fifo_byte_count / 8;
260 ret = 0;
261 } else {
262 *frame_count = data->fifo_byte_count / 6;
263 ret = 0;
264 }
265 break;
266
267 case SENSOR_CHAN_DIE_TEMP:
268 if (data->has_tmp) {
269 /*6 bytes for XYZ and 2 bytes for TEMP*/
270 *frame_count = data->fifo_byte_count / 8;
271 ret = 0;
272 }
273 break;
274
275 default:
276 break;
277 }
278 }
279 }
280 #endif /* CONFIG_ADXL362_STREAM */
281
282 return ret;
283 }
284
adxl362_decode_sample(const struct adxl362_sample_data * data,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)285 static int adxl362_decode_sample(const struct adxl362_sample_data *data,
286 struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out)
287 {
288 struct sensor_value *out = (struct sensor_value *) data_out;
289
290 if (*fit > 0) {
291 return -ENOTSUP;
292 }
293
294 switch (chan_spec.chan_type) {
295 case SENSOR_CHAN_ACCEL_X: /* Acceleration on the X axis, in m/s^2. */
296 adxl362_accel_convert(out, data->acc_x, data->selected_range);
297 break;
298 case SENSOR_CHAN_ACCEL_Y: /* Acceleration on the Y axis, in m/s^2. */
299 adxl362_accel_convert(out, data->acc_y, data->selected_range);
300 break;
301 case SENSOR_CHAN_ACCEL_Z: /* Acceleration on the Z axis, in m/s^2. */
302 adxl362_accel_convert(out, data->acc_z, data->selected_range);
303 break;
304 case SENSOR_CHAN_ACCEL_XYZ: /* Acceleration on the XYZ axis, in m/s^2. */
305 adxl362_accel_convert(out++, data->acc_x, data->selected_range);
306 adxl362_accel_convert(out++, data->acc_y, data->selected_range);
307 adxl362_accel_convert(out, data->acc_z, data->selected_range);
308 break;
309 case SENSOR_CHAN_DIE_TEMP: /* Temperature in degrees Celsius. */
310 adxl362_temp_convert(out, data->temp);
311 break;
312 default:
313 return -ENOTSUP;
314 }
315
316 *fit = 1;
317
318 return 0;
319 }
320
adxl362_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)321 static int adxl362_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
322 uint32_t *fit, uint16_t max_count, void *data_out)
323 {
324 const struct adxl362_sample_data *data = (const struct adxl362_sample_data *)buffer;
325
326 #ifdef CONFIG_ADXL362_STREAM
327 if (data->is_fifo) {
328 return adxl362_decode_stream(buffer, chan_spec, fit, max_count, data_out);
329 }
330 #endif /* CONFIG_ADXL362_STREAM */
331
332 return adxl362_decode_sample(data, chan_spec, fit, max_count, data_out);
333 }
334
adxl362_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)335 static bool adxl362_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
336 {
337 const struct adxl362_fifo_data *data = (const struct adxl362_fifo_data *)buffer;
338
339 if (!data->is_fifo) {
340 return false;
341 }
342
343 switch (trigger) {
344 case SENSOR_TRIG_DATA_READY:
345 return ADXL362_STATUS_CHECK_DATA_READY(data->int_status);
346 case SENSOR_TRIG_FIFO_WATERMARK:
347 return ADXL362_STATUS_CHECK_FIFO_WTR(data->int_status);
348 case SENSOR_TRIG_FIFO_FULL:
349 return ADXL362_STATUS_CHECK_FIFO_OVR(data->int_status);
350 default:
351 return false;
352 }
353 }
354
355 SENSOR_DECODER_API_DT_DEFINE() = {
356 .get_frame_count = adxl362_decoder_get_frame_count,
357 .decode = adxl362_decoder_decode,
358 .has_trigger = adxl362_decoder_has_trigger,
359 };
360
adxl362_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)361 int adxl362_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
362 {
363 ARG_UNUSED(dev);
364 *decoder = &SENSOR_DECODER_NAME();
365
366 return 0;
367 }
368