zephyr/drivers/sensor/adi/adxl372/adxl372_decoder.c
Vladislav Pejic 832bbd8030 driver: sensor: adxl372: Bug fix for q31_t conv
This is a bug fix for adxl372_accel_convert_q31 function.
Function is used to convert samples received from
sensor to q31_t format when RTIO stream is used.

Signed-off-by: Vladislav Pejic <vladislav.pejic@orioninc.com>
2024-10-26 03:54:23 +01:00

301 lines
7.3 KiB
C

/*
* 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;
}