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>
301 lines
7.3 KiB
C
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;
|
|
}
|