/* * Copyright (c) 2024 Analog Devices Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include "adxl372.h" #ifdef CONFIG_ADXL372_STREAM /* (1.0 / 10 (sensor sensitivity)) * (2^31 / 2^11 (sensor shift) ) * SENSOR_G */ #define SENSOR_QSCALE_FACTOR UINT32_C(1027604) #define ADXL372_COMPLEMENT 0xf000 static const uint32_t accel_period_ns[] = { [ADXL372_ODR_400HZ] = UINT32_C(1000000000) / 400, [ADXL372_ODR_800HZ] = UINT32_C(1000000000) / 800, [ADXL372_ODR_1600HZ] = UINT32_C(1000000000) / 1600, [ADXL372_ODR_3200HZ] = UINT32_C(1000000000) / 3200, [ADXL372_ODR_6400HZ] = UINT32_C(1000000000) / 6400, }; static inline void adxl372_accel_convert_q31(q31_t *out, const uint8_t *buff) { int16_t data_in = ((int16_t)*buff << 4) | (((int16_t)*(buff + 1) & 0xF0) >> 4); if (data_in & BIT(11)) { data_in |= ADXL372_COMPLEMENT; } *out = data_in * SENSOR_QSCALE_FACTOR; } static int adxl372_decode_stream(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out) { const struct adxl372_fifo_data *enc_data = (const struct adxl372_fifo_data *)buffer; const uint8_t *buffer_end = buffer + sizeof(struct adxl372_fifo_data) + enc_data->fifo_byte_count; int count = 0; uint8_t sample_num = 0; if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) { return 0; } struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)data_out; memset(data, 0, sizeof(struct sensor_three_axis_data)); data->header.base_timestamp_ns = enc_data->timestamp; data->header.reading_count = 1; data->header.shift = 11; /* Sensor shift */ buffer += sizeof(struct adxl372_fifo_data); uint8_t sample_set_size = enc_data->sample_set_size; uint64_t period_ns = accel_period_ns[enc_data->accel_odr]; /* Calculate which sample is decoded. */ if ((uint8_t *)*fit >= buffer) { sample_num = ((uint8_t *)*fit - buffer) / sample_set_size; } while (count < max_count && buffer < buffer_end) { const uint8_t *sample_end = buffer; sample_end += sample_set_size; if ((uintptr_t)buffer < *fit) { /* This frame was already decoded, move on to the next frame */ buffer = sample_end; continue; } switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: if (enc_data->has_x) { data->readings[count].timestamp_delta = sample_num * period_ns; adxl372_accel_convert_q31(&data->readings[count].x, buffer); } break; case SENSOR_CHAN_ACCEL_Y: if (enc_data->has_y) { uint8_t buff_offset = 0; /* If packet has X channel, then Y channel has offset. */ if (enc_data->has_x) { buff_offset = 2; } data->readings[count].timestamp_delta = sample_num * period_ns; adxl372_accel_convert_q31(&data->readings[count].y, (buffer + buff_offset)); } break; case SENSOR_CHAN_ACCEL_Z: if (enc_data->has_z) { uint8_t buff_offset = 0; /* If packet has X channel and/or Y channel, * then Z channel has offset. */ if (enc_data->has_x) { buff_offset = 2; } if (enc_data->has_y) { buff_offset += 2; } data->readings[count].timestamp_delta = sample_num * period_ns; adxl372_accel_convert_q31(&data->readings[count].z, (buffer + buff_offset)); } break; case SENSOR_CHAN_ACCEL_XYZ: data->readings[count].timestamp_delta = sample_num * period_ns; uint8_t buff_offset = 0; if (enc_data->has_x) { adxl372_accel_convert_q31(&data->readings[count].x, buffer); buff_offset = 2; } if (enc_data->has_y) { adxl372_accel_convert_q31(&data->readings[count].y, (buffer + buff_offset)); buff_offset += 2; } if (enc_data->has_z) { adxl372_accel_convert_q31(&data->readings[count].z, (buffer + buff_offset)); } break; default: return -ENOTSUP; } buffer = sample_end; *fit = (uintptr_t)sample_end; count++; } return count; } #endif /* CONFIG_ADXL372_STREAM */ static int adxl372_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint16_t *frame_count) { int32_t ret = -ENOTSUP; if (chan_spec.chan_idx != 0) { return ret; } #ifdef CONFIG_ADXL372_STREAM const struct adxl372_fifo_data *data = (const struct adxl372_fifo_data *)buffer; if (!data->is_fifo) { #endif /* CONFIG_ADXL372_STREAM */ switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: case SENSOR_CHAN_ACCEL_Y: case SENSOR_CHAN_ACCEL_Z: case SENSOR_CHAN_ACCEL_XYZ: *frame_count = 1; ret = 0; break; default: break; } #ifdef CONFIG_ADXL372_STREAM } else { if (data->fifo_byte_count == 0) { *frame_count = 0; ret = 0; } else { switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: if (data->has_x) { *frame_count = data->fifo_byte_count / data->sample_set_size; ret = 0; } break; case SENSOR_CHAN_ACCEL_Y: if (data->has_y) { *frame_count = data->fifo_byte_count / data->sample_set_size; ret = 0; } break; case SENSOR_CHAN_ACCEL_Z: if (data->has_z) { *frame_count = data->fifo_byte_count / data->sample_set_size; ret = 0; } break; case SENSOR_CHAN_ACCEL_XYZ: if (data->has_x || data->has_y || data->has_z) { *frame_count = data->fifo_byte_count / data->sample_set_size; ret = 0; } break; default: break; } } } #endif /* CONFIG_ADXL372_STREAM */ return ret; } static int adxl372_decode_sample(const struct adxl372_xyz_accel_data *data, struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out) { struct sensor_value *out = (struct sensor_value *)data_out; if (*fit > 0) { return -ENOTSUP; } switch (chan_spec.chan_type) { case SENSOR_CHAN_ACCEL_X: adxl372_accel_convert(out, data->x); break; case SENSOR_CHAN_ACCEL_Y: adxl372_accel_convert(out, data->y); break; case SENSOR_CHAN_ACCEL_Z: adxl372_accel_convert(out, data->z); break; case SENSOR_CHAN_ACCEL_XYZ: adxl372_accel_convert(out++, data->x); adxl372_accel_convert(out++, data->y); adxl372_accel_convert(out, data->z); break; default: return -ENOTSUP; } *fit = 1; return 0; } static int adxl372_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out) { const struct adxl372_xyz_accel_data *data = (const struct adxl372_xyz_accel_data *)buffer; #ifdef CONFIG_ADXL372_STREAM if (data->is_fifo) { return adxl372_decode_stream(buffer, chan_spec, fit, max_count, data_out); } #endif /* CONFIG_ADXL372_STREAM */ return adxl372_decode_sample(data, chan_spec, fit, max_count, data_out); } static bool adxl372_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) { const struct adxl372_fifo_data *data = (const struct adxl372_fifo_data *)buffer; if (!data->is_fifo) { return false; } switch (trigger) { case SENSOR_TRIG_DATA_READY: return FIELD_GET(ADXL372_INT1_MAP_DATA_RDY_MSK, data->int_status); case SENSOR_TRIG_FIFO_WATERMARK: case SENSOR_TRIG_FIFO_FULL: return FIELD_GET(ADXL372_INT1_MAP_FIFO_FULL_MSK, data->int_status); default: return false; } } SENSOR_DECODER_API_DT_DEFINE() = { .get_frame_count = adxl372_decoder_get_frame_count, .decode = adxl372_decoder_decode, .has_trigger = adxl372_decoder_has_trigger, }; int adxl372_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) { ARG_UNUSED(dev); *decoder = &SENSOR_DECODER_NAME(); return 0; }