sensor: testing: Update sensor emul backend
Update the backend for sensor emulators to include a function for setting the offset as well as a function to query an attribute's metadata such as bounds and increment size. Additionally, add backend support for setting the _xyz channel values. Make the appropriate test changes to accomodate. Signed-off-by: Yuval Peress <peress@google.com>
This commit is contained in:
parent
6033161216
commit
be563239c8
|
@ -134,7 +134,7 @@ static int akm09918c_emul_init(const struct emul *target, const struct device *p
|
|||
}
|
||||
|
||||
static int akm09918c_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch,
|
||||
q31_t value, int8_t shift)
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
if (!target || !target->data) {
|
||||
return -EINVAL;
|
||||
|
@ -162,8 +162,9 @@ static int akm09918c_emul_backend_set_channel(const struct emul *target, enum se
|
|||
data->reg[AKM09918C_REG_ST1] |= AKM09918C_ST1_DRDY;
|
||||
|
||||
/* Convert fixed-point Gauss values into microgauss and then into its bit representation */
|
||||
int32_t microgauss = (shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift)) *
|
||||
1000000 / ((int64_t)INT32_MAX + 1);
|
||||
int32_t microgauss =
|
||||
(shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift)) * 1000000 /
|
||||
((int64_t)INT32_MAX + 1);
|
||||
|
||||
int16_t reg_val =
|
||||
CLAMP(microgauss, AKM09918C_MAGN_MIN_MICRO_GAUSS, AKM09918C_MAGN_MAX_MICRO_GAUSS) /
|
||||
|
|
|
@ -100,7 +100,7 @@ static int sb_tsi_emul_init(const struct emul *target, const struct device *pare
|
|||
}
|
||||
|
||||
static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan,
|
||||
q31_t value, int8_t shift)
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
struct sb_tsi_emul_data *data = target->data;
|
||||
int64_t scaled_value;
|
||||
|
@ -111,7 +111,7 @@ static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channe
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
scaled_value = (int64_t)value << shift;
|
||||
scaled_value = (int64_t)*value << shift;
|
||||
millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1);
|
||||
reg_value = CLAMP(millicelsius / 125, 0, 0x7ff);
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@ LOG_MODULE_REGISTER(bosch_bmi160);
|
|||
#include <bmi160.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/emul.h>
|
||||
#include <zephyr/drivers/emul_sensor.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/i2c_emul.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/drivers/spi_emul.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
/** Run-time data used by the emulator */
|
||||
struct bmi160_emul_data {
|
||||
|
@ -42,25 +44,18 @@ struct bmi160_emul_cfg {
|
|||
};
|
||||
|
||||
/* Names for the PMU components */
|
||||
static const char *const pmu_name[] = { "acc", "gyr", "mag", "INV" };
|
||||
static const char *const pmu_name[] = {"acc", "gyr", "mag", "INV"};
|
||||
|
||||
static void sample_read(union bmi160_sample *buf)
|
||||
int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out, size_t count)
|
||||
{
|
||||
/*
|
||||
* Use hard-coded scales to get values just above 0, 1, 2 and
|
||||
* 3, 4, 5. Values are stored in little endianness.
|
||||
* gyr[x] = 0x0b01 // 3 * 1000000 / BMI160_GYR_SCALE(2000) + 1
|
||||
* gyr[y] = 0x0eac // 4 * 1000000 / BMI160_GYR_SCALE(2000) + 1
|
||||
* gyr[z] = 0x1257 // 5 * 1000000 / BMI160_GYR_SCALE(2000) + 1
|
||||
* acc[x] = 0x0001 // 0 * 1000000 / BMI160_ACC_SCALE(2) + 1
|
||||
* acc[y] = 0x0689 // 1 * 1000000 / BMI160_ACC_SCALE(2) + 1
|
||||
* acc[z] = 0x0d11 // 2 * 1000000 / BMI160_ACC_SCALE(2) + 1
|
||||
*/
|
||||
static uint8_t raw_data[] = { 0x01, 0x0b, 0xac, 0x0e, 0x57, 0x12,
|
||||
0x01, 0x00, 0x89, 0x06, 0x11, 0x0d };
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
|
||||
LOG_INF("Sample read");
|
||||
memcpy(buf->raw, raw_data, ARRAY_SIZE(raw_data));
|
||||
if (reg_number < 0 || reg_number + count > BMI160_REG_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(out, cfg->reg + reg_number, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reg_write(const struct emul *target, int regn, int val)
|
||||
|
@ -68,25 +63,25 @@ static void reg_write(const struct emul *target, int regn, int val)
|
|||
struct bmi160_emul_data *data = target->data;
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
|
||||
LOG_INF("write %x = %x", regn, val);
|
||||
LOG_DBG("write %x = %x", regn, val);
|
||||
cfg->reg[regn] = val;
|
||||
switch (regn) {
|
||||
case BMI160_REG_ACC_CONF:
|
||||
LOG_INF(" * acc conf");
|
||||
LOG_DBG(" * acc conf");
|
||||
break;
|
||||
case BMI160_REG_ACC_RANGE:
|
||||
LOG_INF(" * acc range");
|
||||
LOG_DBG(" * acc range");
|
||||
break;
|
||||
case BMI160_REG_GYR_CONF:
|
||||
LOG_INF(" * gyr conf");
|
||||
LOG_DBG(" * gyr conf");
|
||||
break;
|
||||
case BMI160_REG_GYR_RANGE:
|
||||
LOG_INF(" * gyr range");
|
||||
LOG_DBG(" * gyr range");
|
||||
break;
|
||||
case BMI160_REG_CMD:
|
||||
switch (val) {
|
||||
case BMI160_CMD_SOFT_RESET:
|
||||
LOG_INF(" * soft reset");
|
||||
LOG_DBG(" * soft reset");
|
||||
break;
|
||||
default:
|
||||
if ((val & BMI160_CMD_PMU_BIT) == BMI160_CMD_PMU_BIT) {
|
||||
|
@ -108,16 +103,16 @@ static void reg_write(const struct emul *target, int regn, int val)
|
|||
}
|
||||
data->pmu_status &= 3 << shift;
|
||||
data->pmu_status |= pmu_val << shift;
|
||||
LOG_INF(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val,
|
||||
LOG_DBG(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val,
|
||||
data->pmu_status);
|
||||
} else {
|
||||
LOG_INF("Unknown command %x", val);
|
||||
LOG_DBG("Unknown command %x", val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Unknown write %x", regn);
|
||||
LOG_DBG("Unknown write %x", regn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,39 +122,39 @@ static int reg_read(const struct emul *target, int regn)
|
|||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
int val;
|
||||
|
||||
LOG_INF("read %x =", regn);
|
||||
LOG_DBG("read %x =", regn);
|
||||
val = cfg->reg[regn];
|
||||
switch (regn) {
|
||||
case BMI160_REG_CHIPID:
|
||||
LOG_INF(" * get chipid");
|
||||
LOG_DBG(" * get chipid");
|
||||
break;
|
||||
case BMI160_REG_PMU_STATUS:
|
||||
LOG_INF(" * get pmu");
|
||||
LOG_DBG(" * get pmu");
|
||||
val = data->pmu_status;
|
||||
break;
|
||||
case BMI160_REG_STATUS:
|
||||
LOG_INF(" * status");
|
||||
LOG_DBG(" * status");
|
||||
val |= BMI160_DATA_READY_BIT_MASK;
|
||||
break;
|
||||
case BMI160_REG_ACC_CONF:
|
||||
LOG_INF(" * acc conf");
|
||||
LOG_DBG(" * acc conf");
|
||||
break;
|
||||
case BMI160_REG_GYR_CONF:
|
||||
LOG_INF(" * gyr conf");
|
||||
LOG_DBG(" * gyr conf");
|
||||
break;
|
||||
case BMI160_SPI_START:
|
||||
LOG_INF(" * Bus start");
|
||||
LOG_DBG(" * Bus start");
|
||||
break;
|
||||
case BMI160_REG_ACC_RANGE:
|
||||
LOG_INF(" * acc range");
|
||||
LOG_DBG(" * acc range");
|
||||
break;
|
||||
case BMI160_REG_GYR_RANGE:
|
||||
LOG_INF(" * gyr range");
|
||||
LOG_DBG(" * gyr range");
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Unknown read %x", regn);
|
||||
LOG_DBG("Unknown read %x", regn);
|
||||
}
|
||||
LOG_INF(" = %x", val);
|
||||
LOG_DBG(" = %x", val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -206,23 +201,26 @@ static int bmi160_emul_io_spi(const struct emul *target, const struct spi_config
|
|||
break;
|
||||
case BMI160_SAMPLE_SIZE:
|
||||
if (regn & BMI160_REG_READ) {
|
||||
sample_read(rxd->buf);
|
||||
for (int i = 0; i < BMI160_SAMPLE_SIZE; ++i) {
|
||||
((uint8_t *)rxd->buf)[i] = reg_read(
|
||||
target, (regn & BMI160_REG_MASK) + i);
|
||||
}
|
||||
} else {
|
||||
LOG_INF("Unknown sample write");
|
||||
LOG_DBG("Unknown sample write");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Unknown A txd->len %d", txd->len);
|
||||
LOG_DBG("Unknown A txd->len %d", txd->len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Unknown tx->len %d", tx->len);
|
||||
LOG_DBG("Unknown tx->len %d", tx->len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Unknown tx_bufs->count %d", count);
|
||||
LOG_DBG("Unknown tx_bufs->count %d", count);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -235,7 +233,6 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m
|
|||
int addr)
|
||||
{
|
||||
struct bmi160_emul_data *data;
|
||||
unsigned int val;
|
||||
|
||||
data = target->data;
|
||||
|
||||
|
@ -257,17 +254,8 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m
|
|||
/* Now process the 'read' part of the message */
|
||||
msgs++;
|
||||
if (msgs->flags & I2C_MSG_READ) {
|
||||
switch (msgs->len) {
|
||||
case 1:
|
||||
val = reg_read(target, data->cur_reg);
|
||||
msgs->buf[0] = val;
|
||||
break;
|
||||
case BMI160_SAMPLE_SIZE:
|
||||
sample_read((void *)msgs->buf);
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unexpected msg1 length %d", msgs->len);
|
||||
return -EIO;
|
||||
for (int i = 0; i < msgs->len; ++i) {
|
||||
msgs->buf[i] = reg_read(target, data->cur_reg + i);
|
||||
}
|
||||
} else {
|
||||
if (msgs->len != 1) {
|
||||
|
@ -299,6 +287,304 @@ static struct i2c_emul_api bmi160_emul_api_i2c = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static int bmi160_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch,
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
int64_t intermediate = *value;
|
||||
q31_t scale;
|
||||
int8_t scale_shift = 0;
|
||||
int reg_lsb;
|
||||
|
||||
switch (ch) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
reg_lsb = BMI160_REG_DATA_ACC_X + (ch - SENSOR_CHAN_ACCEL_X) * 2;
|
||||
scale = 0x4e7404ea;
|
||||
|
||||
switch (FIELD_GET(GENMASK(3, 0), cfg->reg[BMI160_REG_ACC_RANGE])) {
|
||||
case BMI160_ACC_RANGE_4G:
|
||||
scale_shift = 6;
|
||||
break;
|
||||
case BMI160_ACC_RANGE_8G:
|
||||
scale_shift = 7;
|
||||
break;
|
||||
case BMI160_ACC_RANGE_16G:
|
||||
scale_shift = 8;
|
||||
break;
|
||||
default:
|
||||
scale_shift = 5;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SENSOR_CHAN_GYRO_X:
|
||||
case SENSOR_CHAN_GYRO_Y:
|
||||
case SENSOR_CHAN_GYRO_Z:
|
||||
reg_lsb = BMI160_REG_DATA_GYR_X + (ch - SENSOR_CHAN_GYRO_X) * 2;
|
||||
scale = 0x45d02bea;
|
||||
|
||||
switch (FIELD_GET(GENMASK(2, 0), cfg->reg[BMI160_REG_GYR_RANGE])) {
|
||||
case BMI160_GYR_RANGE_2000DPS:
|
||||
scale_shift = 6;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_1000DPS:
|
||||
scale_shift = 5;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_500DPS:
|
||||
scale_shift = 4;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_250DPS:
|
||||
scale_shift = 3;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_125DPS:
|
||||
scale_shift = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case SENSOR_CHAN_DIE_TEMP:
|
||||
reg_lsb = BMI160_REG_TEMPERATURE0;
|
||||
scale = 0x8000;
|
||||
scale_shift = 7;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (shift < scale_shift) {
|
||||
/* Original value doesn't have enough int bits, fix it */
|
||||
intermediate >>= scale_shift - shift;
|
||||
} else if (shift > 0 && shift > scale_shift) {
|
||||
/* Original value might be out-of-bounds, fix it (we're going to lose precision) */
|
||||
intermediate <<= shift - scale_shift;
|
||||
}
|
||||
|
||||
if (ch == SENSOR_CHAN_DIE_TEMP) {
|
||||
/* Need to subtract 23C */
|
||||
intermediate -= INT64_C(23) << (31 - scale_shift);
|
||||
}
|
||||
|
||||
intermediate =
|
||||
CLAMP(DIV_ROUND_CLOSEST(intermediate * INT16_MAX, scale), INT16_MIN, INT16_MAX);
|
||||
|
||||
cfg->reg[reg_lsb] = FIELD_GET(GENMASK64(7, 0), intermediate);
|
||||
cfg->reg[reg_lsb + 1] = FIELD_GET(GENMASK64(15, 8), intermediate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmi160_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch,
|
||||
q31_t *lower, q31_t *upper, q31_t *epsilon,
|
||||
int8_t *shift)
|
||||
{
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
|
||||
switch (ch) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
case SENSOR_CHAN_ACCEL_XYZ: {
|
||||
uint8_t acc_range = cfg->reg[BMI160_REG_ACC_RANGE];
|
||||
|
||||
switch (acc_range) {
|
||||
case BMI160_ACC_RANGE_2G:
|
||||
*shift = 5;
|
||||
break;
|
||||
case BMI160_ACC_RANGE_4G:
|
||||
*shift = 6;
|
||||
break;
|
||||
case BMI160_ACC_RANGE_8G:
|
||||
*shift = 7;
|
||||
break;
|
||||
case BMI160_ACC_RANGE_16G:
|
||||
*shift = 8;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
int64_t intermediate = ((int64_t)(2 * 9.80665 * INT32_MAX)) >> 5;
|
||||
|
||||
*upper = intermediate;
|
||||
*lower = -(*upper);
|
||||
*epsilon = intermediate * 2 / (1 << (16 - *shift));
|
||||
return 0;
|
||||
}
|
||||
case SENSOR_CHAN_GYRO_X:
|
||||
case SENSOR_CHAN_GYRO_Y:
|
||||
case SENSOR_CHAN_GYRO_Z:
|
||||
case SENSOR_CHAN_GYRO_XYZ: {
|
||||
uint8_t gyro_range = cfg->reg[BMI160_REG_GYR_RANGE];
|
||||
|
||||
switch (gyro_range) {
|
||||
case BMI160_GYR_RANGE_125DPS:
|
||||
*shift = 2;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_250DPS:
|
||||
*shift = 3;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_500DPS:
|
||||
*shift = 4;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_1000DPS:
|
||||
*shift = 5;
|
||||
break;
|
||||
case BMI160_GYR_RANGE_2000DPS:
|
||||
*shift = 6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int64_t intermediate = (int64_t)(125 * 3.141592654 * INT32_MAX / 180) >> 2;
|
||||
|
||||
*upper = intermediate;
|
||||
*lower = -(*upper);
|
||||
*epsilon = intermediate * 2 / (1 << (16 - *shift));
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor_channel ch,
|
||||
const q31_t *values, int8_t shift)
|
||||
{
|
||||
if (ch != SENSOR_CHAN_ACCEL_XYZ && ch != SENSOR_CHAN_GYRO_XYZ) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
q31_t scale;
|
||||
int8_t scale_shift = 0;
|
||||
|
||||
if (values[0] == 0 && values[1] == 0 && values[2] == 0) {
|
||||
if (ch == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_ACC_OFS_EN_POS);
|
||||
} else {
|
||||
cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_GYR_OFS_EN_POS);
|
||||
}
|
||||
} else {
|
||||
if (ch == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_ACC_OFS_EN_POS);
|
||||
} else {
|
||||
cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_GYR_OFS_EN_POS);
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
/*
|
||||
* bits = (values[i]mps2 / 9.80665g/mps2) / 0.0039g
|
||||
* = values[i] / 0.038245935mps2/bit
|
||||
* 0.038245935 in Q31 format is 0x4e53e28 with shift 0
|
||||
*/
|
||||
scale = 0x4e53e28;
|
||||
} else {
|
||||
/*
|
||||
* bits = (values[i]rad/s * 180 / pi) / 0.061deg/s
|
||||
* = values[i] / 0.001064651rad/s
|
||||
*/
|
||||
scale = 0x22e2f0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int64_t intermediate = values[i];
|
||||
|
||||
if (shift > scale_shift) {
|
||||
/* Input uses a bigger scale, we need to increase its value to match */
|
||||
intermediate <<= (shift - scale_shift);
|
||||
} else if (shift < scale_shift) {
|
||||
/* Scale uses a bigger shift, we need to decrease its value to match */
|
||||
scale >>= (scale_shift - shift);
|
||||
}
|
||||
|
||||
int64_t reg_value = intermediate / scale;
|
||||
|
||||
__ASSERT_NO_MSG(ch != SENSOR_CHAN_ACCEL_XYZ ||
|
||||
(reg_value >= INT8_MIN && reg_value <= INT8_MAX));
|
||||
__ASSERT_NO_MSG(ch != SENSOR_CHAN_GYRO_XYZ ||
|
||||
(reg_value >= -0x1ff - 1 && reg_value <= 0x1ff));
|
||||
if (ch == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
cfg->reg[BMI160_REG_OFFSET_ACC_X + i] = reg_value & 0xff;
|
||||
} else {
|
||||
cfg->reg[BMI160_REG_OFFSET_GYR_X + i] = reg_value & 0xff;
|
||||
cfg->reg[BMI160_REG_OFFSET_EN] =
|
||||
(cfg->reg[BMI160_REG_OFFSET_EN] & ~GENMASK(i * 2 + 1, i * 2)) |
|
||||
(reg_value & GENMASK(9, 8));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmi160_emul_backend_set_attribute(const struct emul *target, enum sensor_channel ch,
|
||||
enum sensor_attribute attribute, const void *value)
|
||||
{
|
||||
if (attribute == SENSOR_ATTR_OFFSET &&
|
||||
(ch == SENSOR_CHAN_ACCEL_XYZ || ch == SENSOR_CHAN_GYRO_XYZ)) {
|
||||
const struct sensor_three_axis_attribute *attribute_value = value;
|
||||
|
||||
return bmi160_emul_backend_set_offset(target, ch, attribute_value->values,
|
||||
attribute_value->shift);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bmi160_emul_backend_get_attribute_metadata(const struct emul *target,
|
||||
enum sensor_channel ch,
|
||||
enum sensor_attribute attribute, q31_t *min,
|
||||
q31_t *max, q31_t *increment, int8_t *shift)
|
||||
{
|
||||
ARG_UNUSED(target);
|
||||
switch (ch) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
case SENSOR_CHAN_ACCEL_XYZ:
|
||||
if (attribute == SENSOR_ATTR_OFFSET) {
|
||||
/* Offset uses 3.9mg per bit in an 8 bit register:
|
||||
* 0.0039g * 9.8065m/s2: yields the increment in SI units
|
||||
* * INT8_MIN (or MAX) : yields the minimum (or maximum) values
|
||||
* * INT32_MAX >> 3 : converts to q31 format within range [-8, 8]
|
||||
*/
|
||||
*min = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MIN * INT32_MAX) >> 3);
|
||||
*max = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MAX * INT32_MAX) >> 3);
|
||||
*increment = (q31_t)((int64_t)(0.0039 * 9.8065 * INT32_MAX) >> 3);
|
||||
*shift = 3;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
case SENSOR_CHAN_GYRO_X:
|
||||
case SENSOR_CHAN_GYRO_Y:
|
||||
case SENSOR_CHAN_GYRO_Z:
|
||||
case SENSOR_CHAN_GYRO_XYZ:
|
||||
if (attribute == SENSOR_ATTR_OFFSET) {
|
||||
/* Offset uses 0.061deg/s per bit in an 10 bit register:
|
||||
* 0.061deg/s * pi / 180: yields the increment in SI units
|
||||
* * INT10_MIN (or MAX) : yields the minimum (or maximum) values
|
||||
* * INT32_MAX : converts to q31 format within range [-1, 1]
|
||||
*/
|
||||
*min = (q31_t)(0.061 * 3.141593 / 180.0 * -512 * INT32_MAX);
|
||||
*max = (q31_t)(0.061 * 3.141593 / 180.0 * 511 * INT32_MAX);
|
||||
*increment = (q31_t)(0.061 * 3.141593 / 180.0 * INT32_MAX);
|
||||
*shift = 0;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct emul_sensor_backend_api backend_api = {
|
||||
.set_channel = bmi160_emul_backend_set_channel,
|
||||
.get_sample_range = bmi160_emul_backend_get_sample_range,
|
||||
.set_attribute = bmi160_emul_backend_set_attribute,
|
||||
.get_attribute_metadata = bmi160_emul_backend_get_attribute_metadata,
|
||||
};
|
||||
|
||||
static int emul_bosch_bmi160_init(const struct emul *target, const struct device *parent)
|
||||
{
|
||||
const struct bmi160_emul_cfg *cfg = target->cfg;
|
||||
|
@ -320,22 +606,19 @@ static int emul_bosch_bmi160_init(const struct emul *target, const struct device
|
|||
|
||||
#define BMI160_EMUL_DEFINE(n, bus_api) \
|
||||
EMUL_DT_INST_DEFINE(n, emul_bosch_bmi160_init, &bmi160_emul_data_##n, \
|
||||
&bmi160_emul_cfg_##n, &bus_api, NULL)
|
||||
&bmi160_emul_cfg_##n, &bus_api, &backend_api)
|
||||
|
||||
/* Instantiation macros used when a device is on a SPI bus */
|
||||
#define BMI160_EMUL_SPI(n) \
|
||||
BMI160_EMUL_DATA(n) \
|
||||
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
|
||||
.reg = bmi160_emul_reg_##n, \
|
||||
.chipsel = \
|
||||
DT_INST_REG_ADDR(n) }; \
|
||||
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
|
||||
.reg = bmi160_emul_reg_##n, .chipsel = DT_INST_REG_ADDR(n)}; \
|
||||
BMI160_EMUL_DEFINE(n, bmi160_emul_api_spi)
|
||||
|
||||
#define BMI160_EMUL_I2C(n) \
|
||||
BMI160_EMUL_DATA(n) \
|
||||
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \
|
||||
.reg = bmi160_emul_reg_##n, \
|
||||
.addr = DT_INST_REG_ADDR(n) }; \
|
||||
static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = {.reg = bmi160_emul_reg_##n, \
|
||||
.addr = DT_INST_REG_ADDR(n)}; \
|
||||
BMI160_EMUL_DEFINE(n, bmi160_emul_api_i2c)
|
||||
|
||||
/*
|
||||
|
|
98
drivers/sensor/bmi160/emul_bmi160.h
Normal file
98
drivers/sensor/bmi160/emul_bmi160.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_
|
||||
|
||||
#include <zephyr/drivers/emul.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check if I2C messages are touching a given register (R or W)
|
||||
*
|
||||
* @param[in] msgs The I2C messages in question
|
||||
* @param[in] num_msgs The number of messages in the @p msgs array
|
||||
* @param[in] reg The register to check for
|
||||
* @return True if @p reg is either read or written to
|
||||
* @return False otherwise
|
||||
*/
|
||||
__maybe_unused static bool emul_bmi160_i2c_is_touching_reg(struct i2c_msg *msgs, int num_msgs,
|
||||
uint32_t reg)
|
||||
{
|
||||
if (num_msgs != 2) {
|
||||
return false;
|
||||
}
|
||||
if (msgs[0].len != 1) {
|
||||
return false;
|
||||
}
|
||||
if (i2c_is_read_op(msgs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t start_reg = msgs[0].buf[0];
|
||||
uint8_t read_len = msgs[1].len;
|
||||
|
||||
return (start_reg <= reg) && (reg < start_reg + read_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if I2C messages are reading a specific register.
|
||||
*
|
||||
* @param[in] msgs The I2C messages in question
|
||||
* @param[in] num_msgs The number of messages in the @p msgs array
|
||||
* @param[in] reg The register to check for
|
||||
* @return True if @p reg is read
|
||||
* @return False otherwise
|
||||
*/
|
||||
__maybe_unused static bool emul_bmi160_i2c_is_reading_reg(struct i2c_msg *msgs, int num_msgs,
|
||||
uint32_t reg)
|
||||
{
|
||||
if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) {
|
||||
return false;
|
||||
}
|
||||
return i2c_is_read_op(&msgs[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if I2C messages are writing to a specific register.
|
||||
*
|
||||
* @param[in] msgs The I2C messages in question
|
||||
* @param[in] num_msgs The number of messages in the @p msgs array
|
||||
* @param[in] reg The register to check for
|
||||
* @return True if @p reg is written
|
||||
* @return False otherwise
|
||||
*/
|
||||
__maybe_unused static bool emul_bmi160_i2c_is_writing_reg(struct i2c_msg *msgs, int num_msgs,
|
||||
uint32_t reg)
|
||||
{
|
||||
if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) {
|
||||
return false;
|
||||
}
|
||||
return !i2c_is_read_op(&msgs[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the internal register value of the emulator
|
||||
*
|
||||
* @param[in] target The emulator in question
|
||||
* @param[in] reg_number The register number to start reading at
|
||||
* @param[out] out Buffer to store the values into
|
||||
* @param[in] count The number of registers to read
|
||||
* @return 0 on success
|
||||
* @return < 0 on error
|
||||
*/
|
||||
int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out,
|
||||
size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ */
|
|
@ -104,7 +104,7 @@ static int f75303_emul_init(const struct emul *target, const struct device *pare
|
|||
}
|
||||
|
||||
static int f75303_emul_set_channel(const struct emul *target, enum sensor_channel chan,
|
||||
q31_t value, int8_t shift)
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
struct f75303_emul_data *data = target->data;
|
||||
int64_t scaled_value;
|
||||
|
@ -129,7 +129,7 @@ static int f75303_emul_set_channel(const struct emul *target, enum sensor_channe
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
scaled_value = (int64_t)value << shift;
|
||||
scaled_value = (int64_t)*value << shift;
|
||||
millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1);
|
||||
reg_value = CLAMP(millicelsius / 125, 0, 0x7ff);
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ static int icm42688_emul_backend_get_sample_range(const struct emul *target, enu
|
|||
}
|
||||
|
||||
static int icm42688_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch,
|
||||
q31_t value, int8_t shift)
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
if (!target || !target->data) {
|
||||
return -EINVAL;
|
||||
|
@ -341,7 +341,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen
|
|||
uint8_t reg_addr;
|
||||
int32_t reg_val;
|
||||
int64_t value_unshifted =
|
||||
shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift);
|
||||
shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift);
|
||||
|
||||
switch (ch) {
|
||||
case SENSOR_CHAN_DIE_TEMP:
|
||||
|
|
|
@ -174,6 +174,18 @@ struct emul {
|
|||
*/
|
||||
#define EMUL_DT_GET(node_id) (&EMUL_DT_NAME_GET(node_id))
|
||||
|
||||
/**
|
||||
* @brief Utility macro to obtain an optional reference to an emulator
|
||||
*
|
||||
* If the node identifier referes to a node with status `okay`, this returns `EMUL_DT_GET(node_id)`.
|
||||
* Otherwise, it returns `NULL`.
|
||||
*
|
||||
* @param node_id A devicetree node identifier
|
||||
* @return a @ref emul reference for the node identifier, which may be `NULL`.
|
||||
*/
|
||||
#define EMUL_DT_GET_OR_NULL(node_id) \
|
||||
COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay), (EMUL_DT_GET(node_id)), (NULL))
|
||||
|
||||
/**
|
||||
* @brief Set up a list of emulators
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <zephyr/drivers/emul.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/drivers/sensor_attribute_types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -26,11 +27,18 @@
|
|||
*/
|
||||
__subsystem struct emul_sensor_backend_api {
|
||||
/** Sets a given fractional value for a given sensor channel. */
|
||||
int (*set_channel)(const struct emul *target, enum sensor_channel ch, q31_t value,
|
||||
int (*set_channel)(const struct emul *target, enum sensor_channel ch, const q31_t *value,
|
||||
int8_t shift);
|
||||
/** Retrieve a range of sensor values to use with test. */
|
||||
int (*get_sample_range)(const struct emul *target, enum sensor_channel ch, q31_t *lower,
|
||||
q31_t *upper, q31_t *epsilon, int8_t *shift);
|
||||
/** Set the attribute value(s) of a given chanel. */
|
||||
int (*set_attribute)(const struct emul *target, enum sensor_channel ch,
|
||||
enum sensor_attribute attribute, const void *value);
|
||||
/** Get metadata about an attribute. */
|
||||
int (*get_attribute_metadata)(const struct emul *target, enum sensor_channel ch,
|
||||
enum sensor_attribute attribute, q31_t *min, q31_t *max,
|
||||
q31_t *increment, int8_t *shift);
|
||||
};
|
||||
/**
|
||||
* @endcond
|
||||
|
@ -61,7 +69,7 @@ static inline bool emul_sensor_backend_is_supported(const struct emul *target)
|
|||
* @return -ERANGE if provided value is not in the sensor's supported range
|
||||
*/
|
||||
static inline int emul_sensor_backend_set_channel(const struct emul *target, enum sensor_channel ch,
|
||||
q31_t value, int8_t shift)
|
||||
const q31_t *value, int8_t shift)
|
||||
{
|
||||
if (!target || !target->backend_api) {
|
||||
return -ENOTSUP;
|
||||
|
@ -108,6 +116,68 @@ static inline int emul_sensor_backend_get_sample_range(const struct emul *target
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the emulator's attribute values
|
||||
*
|
||||
* @param[in] target Pointer to emulator instance to operate on
|
||||
* @param[in] ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP`
|
||||
* @param[in] attribute The attribute to set
|
||||
* @param[in] value the value to use (cast according to the channel/attribute pair)
|
||||
* @return 0 is successful
|
||||
* @return < 0 on error
|
||||
*/
|
||||
static inline int emul_sensor_backend_set_attribute(const struct emul *target,
|
||||
enum sensor_channel ch,
|
||||
enum sensor_attribute attribute,
|
||||
const void *value)
|
||||
{
|
||||
if (!target || !target->backend_api) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api;
|
||||
|
||||
if (api->set_attribute == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return api->set_attribute(target, ch, attribute, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get metadata about an attribute.
|
||||
*
|
||||
* Information provided by this function includes the minimum/maximum values of the attribute as
|
||||
* well as the increment (value per LSB) which can be used as an epsilon when comparing results.
|
||||
*
|
||||
* @param[in] target Pointer to emulator instance to operate on
|
||||
* @param[in] ch The channel to request info for. If \p ch is unsupported, return '-ENOTSUP'
|
||||
* @param[in] attribute The attribute to request info for. If \p attribute is unsupported, return
|
||||
* '-ENOTSUP'
|
||||
* @param[out] min The minimum value the attribute can be set to
|
||||
* @param[out] max The maximum value the attribute can be set to
|
||||
* @param[out] increment The value that the attribute increses by for every LSB
|
||||
* @param[out] shift The shift for \p min, \p max, and \p increment
|
||||
* @return 0 on SUCCESS
|
||||
* @return < 0 on error
|
||||
*/
|
||||
static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target,
|
||||
enum sensor_channel ch,
|
||||
enum sensor_attribute attribute,
|
||||
q31_t *min, q31_t *max,
|
||||
q31_t *increment, int8_t *shift)
|
||||
{
|
||||
if (!target || !target->backend_api) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api;
|
||||
|
||||
if (api->get_attribute_metadata == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return api->get_attribute_metadata(target, ch, attribute, min, max, increment, shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
43
include/zephyr/drivers/sensor_attribute_types.h
Normal file
43
include/zephyr/drivers/sensor_attribute_types.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H
|
||||
|
||||
#include <zephyr/dsp/types.h>
|
||||
#include <zephyr/dsp/print_format.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used by the following channel/attribute pairs:
|
||||
* - SENSOR_CHAN_ACCEL_XYZ
|
||||
* - SENSOR_ATTR_OFFSET
|
||||
* - SENSOR_CHAN_GYRO_XYZ
|
||||
* - SENSOR_ATTR_OFFSET
|
||||
* - SENSOR_CHAN_MAGN_XYZ
|
||||
* - SENSOR_ATTR_OFFSET
|
||||
*/
|
||||
struct sensor_three_axis_attribute {
|
||||
int8_t shift;
|
||||
union {
|
||||
struct {
|
||||
q31_t x;
|
||||
q31_t y;
|
||||
q31_t z;
|
||||
};
|
||||
q31_t values[3];
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H */
|
|
@ -158,7 +158,7 @@ static void run_generic_test(const struct device *dev)
|
|||
enum sensor_channel ch = iodev_all_channels[i];
|
||||
|
||||
rv = emul_sensor_backend_set_channel(
|
||||
emul, ch, channel_table[ch].expected_values[iteration],
|
||||
emul, ch, &channel_table[ch].expected_values[iteration],
|
||||
channel_table[ch].expected_value_shift);
|
||||
zassert_ok(
|
||||
rv,
|
||||
|
|
Loading…
Reference in a new issue