summaryrefslogtreecommitdiff
path: root/zephyr/emul/emul_bmi.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /zephyr/emul/emul_bmi.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14395.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'zephyr/emul/emul_bmi.c')
-rw-r--r--zephyr/emul/emul_bmi.c1116
1 files changed, 0 insertions, 1116 deletions
diff --git a/zephyr/emul/emul_bmi.c b/zephyr/emul/emul_bmi.c
deleted file mode 100644
index 7923fe0eb5..0000000000
--- a/zephyr/emul/emul_bmi.c
+++ /dev/null
@@ -1,1116 +0,0 @@
-/* Copyright 2021 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#define DT_DRV_COMPAT zephyr_bmi
-
-#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
-#include <logging/log.h>
-LOG_MODULE_REGISTER(emul_bmi);
-
-#include <device.h>
-#include <emul.h>
-#include <drivers/i2c.h>
-#include <drivers/i2c_emul.h>
-
-#include "emul/emul_common_i2c.h"
-#include "emul/emul_bmi.h"
-
-#include "driver/accelgyro_bmi160.h"
-#include "driver/accelgyro_bmi260.h"
-#include "driver/accelgyro_bmi_common.h"
-
-#define BMI_DATA_FROM_I2C_EMUL(_emul) \
- CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \
- struct bmi_emul_data, common)
-
-/** Run-time data used by the emulator */
-struct bmi_emul_data {
- /** Common I2C data */
- struct i2c_common_emul_data common;
-
- /** Current state of all emulated BMI registers */
- uint8_t reg[BMI_EMUL_MAX_REG];
- /** Internal offset values used in calculations */
- int16_t off_acc_x;
- int16_t off_acc_y;
- int16_t off_acc_z;
- int16_t off_gyr_x;
- int16_t off_gyr_y;
- int16_t off_gyr_z;
- /** Internal values of sensors */
- int32_t acc_x;
- int32_t acc_y;
- int32_t acc_z;
- int32_t gyr_x;
- int32_t gyr_y;
- int32_t gyr_z;
- /** Current state of NVM where offset and configuration can be saved */
- uint8_t nvm[BMI_EMUL_MAX_NVM_REGS];
-
- /** Return error when trying to write to RO register */
- bool error_on_ro_write;
- /** Return error when trying to write 1 to reserved bit */
- bool error_on_rsvd_write;
- /**
- * If effect of command is vissable after simulated time from issuing
- * command
- */
- bool simulate_command_exec_time;
- /** Return error when trying to read WO register */
- bool error_on_wo_read;
-
- /** Value of data byte in ongoing write message */
- uint8_t write_byte;
-
- /** List of FIFO frames */
- struct bmi_emul_frame *fifo_frame;
- /** First FIFO frame in byte format */
- uint8_t fifo[21];
- /** Number of FIFO frames that were skipped */
- uint8_t fifo_skip;
- /** Currently accessed byte of first frame */
- int fifo_frame_byte;
- /** Length of first frame */
- int fifo_frame_len;
-
- /** Last time when emulator was resetted in sensor time units */
- int64_t zero_time;
- /** Time when current command should end */
- uint32_t cmd_end_time;
-
- /** Emulated model of BMI */
- int type;
- /** Pointer to data specific for emulated model of BMI */
- const struct bmi_emul_type_data *type_data;
-};
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val)
-{
- struct bmi_emul_data *data;
-
- if (reg < 0 || reg > BMI_EMUL_MAX_REG) {
- return;
- }
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
- data->reg[reg] = val;
-}
-
-/** Check description in emul_bmi.h */
-uint8_t bmi_emul_get_reg(struct i2c_emul *emul, int reg)
-{
- struct bmi_emul_data *data;
-
- if (reg < 0 || reg > BMI_EMUL_MAX_REG) {
- return 0;
- }
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- return data->reg[reg];
-}
-
-/**
- * @brief Convert @p val to two's complement representation. It makes sure that
- * bit representation is correct even on platforms which represent
- * signed inteager in different format. Unsigned bit representation
- * allows to use well defined bitwise operations on returned value.
- *
- * @param val Inteager that is converted
- *
- * @return two's complement representation of @p val
- */
-static uint32_t bmi_emul_val_to_twos_comp(int32_t val)
-{
- uint32_t twos_comp_val;
-
- /* Make sure that value is converted to twos compliment format */
- if (val < 0) {
- twos_comp_val = (uint32_t)(-val);
- twos_comp_val = ~twos_comp_val + 1;
- } else {
- twos_comp_val = (uint32_t)val;
- }
-
- return twos_comp_val;
-}
-
-/**
- * @brief Convert accelerometer value from NVM format (8bit, 0x01 == 3.9mg)
- * to internal offset format (16bit, 0x01 == 0.061mg).
- *
- * @param nvm Value in NVM format (8bit, 0x01 == 3.9mg). This is binary
- * representation of two's complement signed number.
- *
- * @return offset Internal representation of @p nvm (16bit, 0x01 == 0.061mg)
- */
-static int16_t bmi_emul_acc_nvm_to_off(uint8_t nvm)
-{
- int16_t offset;
- int8_t sign;
-
- if (nvm & BIT(7)) {
- sign = -1;
- /* NVM value is in two's complement format */
- nvm = ~nvm + 1;
- } else {
- sign = 1;
- }
-
- offset = (int16_t)nvm;
- /* LSB in NVM is 3.9mg, while LSB in internal offset is 0.061mg */
- offset *= sign * 64;
-
- return offset;
-}
-
-/**
- * @brief Convert gyroscope value from NVM format (10bit, 0x01 == 0.061 °/s)
- * to internal offset format (16bit, 0x01 == 0.0038 °/s)
- *
- * @param nvm Value in NVM format (10bit, 0x01 == 0.061 °/s). This is binary
- * representation of two's complement signed number.
- *
- * @return offset Internal representation of @p nvm (16bit, 0x01 == 0.0038 °/s)
- */
-static int16_t bmi_emul_gyr_nvm_to_off(uint16_t nvm)
-{
- int16_t offset;
- int8_t sign;
-
- if (nvm & BIT(9)) {
- sign = -1;
- /* NVM value is in two's complement format */
- nvm = ~nvm + 1;
- } else {
- sign = 1;
- }
-
- /* Mask 10 bits which holds value */
- nvm &= 0x3ff;
-
- offset = (int16_t)nvm;
- /* LSB in NVM is 0.061°/s, while LSB in internal offset is 0.0038°/s */
- offset *= sign * 16;
-
- return offset;
-}
-
-/**
- * @brief Convert accelerometer value from internal offset format
- * (16bit, 0x01 == 0.061mg) to NVM format (8bit, 0x01 == 7.8mg).
- * Function makes sure that NVM value is representation of two's
- * complement signed number.
- *
- * @param val Value in internal offset format (16bit, 0x01 == 0.061mg).
- *
- * @return nvm NVM format representation of @p val (8bit, 0x01 == 3.9mg)
- */
-static uint8_t bmi_emul_acc_off_to_nvm(int16_t off)
-{
- uint32_t twos_comp_val;
- uint8_t nvm = 0;
-
- twos_comp_val = bmi_emul_val_to_twos_comp(off);
-
- /*
- * LSB in internal representation has value 0.061mg, while in NVM
- * LSB is 3.9mg. Skip 0.06mg, 0.12mg, 0.24mg, 0.48mg, 0.97mg and
- * 1.9mg bits.
- */
- nvm |= (twos_comp_val >> 6) & 0x7f;
- /* Set sign bit */
- nvm |= (twos_comp_val & BIT(31)) ? BIT(7) : 0x00;
-
- return nvm;
-}
-
-/**
- * @brief Convert gyroscope value from internal offset format
- * (16bit, 0x01 == 0.0038°/s) to NVM format (10bit, 0x01 == 0.061°/s).
- * Function makes sure that NVM value is representation of two's
- * complement signed number.
- *
- * @param val Value in internal offset format (16bit, 0x01 == 0.0038°/s).
- *
- * @return nvm NVM format representation of @p val (10bit, 0x01 == 0.061°/s)
- */
-static uint16_t bmi_emul_gyr_off_to_nvm(int16_t off)
-{
- uint32_t twos_comp_val;
- uint16_t nvm = 0;
-
- twos_comp_val = bmi_emul_val_to_twos_comp(off);
-
- /*
- * LSB in internal representation has value 0.0038°/s, while in NVM
- * LSB is 0.061°/s. Skip 0.0038°/s, 0.0076°/s, 0.015°/s, and
- * 0.03°/s bits.
- */
- nvm |= (twos_comp_val >> 4) & 0x1ff;
- /* Set sign bit */
- nvm |= (twos_comp_val & BIT(31)) ? BIT(9) : 0x00;
-
- return nvm;
-}
-
-/** Check description in emul_bmi.h */
-int16_t bmi_emul_get_off(struct i2c_emul *emul, enum bmi_emul_axis axis)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- switch (axis) {
- case BMI_EMUL_ACC_X:
- return data->off_acc_x;
- case BMI_EMUL_ACC_Y:
- return data->off_acc_y;
- case BMI_EMUL_ACC_Z:
- return data->off_acc_z;
- case BMI_EMUL_GYR_X:
- return data->off_gyr_x;
- case BMI_EMUL_GYR_Y:
- return data->off_gyr_y;
- case BMI_EMUL_GYR_Z:
- return data->off_gyr_z;
- }
-
- return 0;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_off(struct i2c_emul *emul, enum bmi_emul_axis axis,
- int16_t val)
-{
- struct bmi_emul_data *data;
- uint16_t gyr_off;
- uint8_t gyr98_shift;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- switch (axis) {
- case BMI_EMUL_ACC_X:
- data->off_acc_x = val;
- data->reg[data->type_data->acc_off_reg] =
- bmi_emul_acc_off_to_nvm(data->off_acc_x);
- break;
- case BMI_EMUL_ACC_Y:
- data->off_acc_y = val;
- data->reg[data->type_data->acc_off_reg + 1] =
- bmi_emul_acc_off_to_nvm(data->off_acc_y);
- break;
- case BMI_EMUL_ACC_Z:
- data->off_acc_z = val;
- data->reg[data->type_data->acc_off_reg + 2] =
- bmi_emul_acc_off_to_nvm(data->off_acc_z);
- break;
- case BMI_EMUL_GYR_X:
- data->off_gyr_x = val;
- gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_x);
- data->reg[data->type_data->gyr_off_reg] = gyr_off & 0xff;
- gyr98_shift = 0;
- data->reg[data->type_data->gyr98_off_reg] &=
- ~(0x3 << gyr98_shift);
- data->reg[data->type_data->gyr98_off_reg] |=
- (gyr_off & 0x300) >> (8 - gyr98_shift);
- break;
- case BMI_EMUL_GYR_Y:
- data->off_gyr_y = val;
- gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_y);
- data->reg[data->type_data->gyr_off_reg + 1] = gyr_off & 0xff;
- gyr98_shift = 2;
- data->reg[data->type_data->gyr98_off_reg] &=
- ~(0x3 << gyr98_shift);
- data->reg[data->type_data->gyr98_off_reg] |=
- (gyr_off & 0x300) >> (8 - gyr98_shift);
- break;
- case BMI_EMUL_GYR_Z:
- data->off_gyr_z = val;
- gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_z);
- data->reg[data->type_data->gyr_off_reg + 2] = gyr_off & 0xff;
- gyr98_shift = 4;
- data->reg[data->type_data->gyr98_off_reg] &=
- ~(0x3 << gyr98_shift);
- data->reg[data->type_data->gyr98_off_reg] |=
- (gyr_off & 0x300) >> (8 - gyr98_shift);
- break;
- }
-}
-
-/** Check description in emul_bmi.h */
-int32_t bmi_emul_get_value(struct i2c_emul *emul, enum bmi_emul_axis axis)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- switch (axis) {
- case BMI_EMUL_ACC_X:
- return data->acc_x;
- case BMI_EMUL_ACC_Y:
- return data->acc_y;
- case BMI_EMUL_ACC_Z:
- return data->acc_z;
- case BMI_EMUL_GYR_X:
- return data->gyr_x;
- case BMI_EMUL_GYR_Y:
- return data->gyr_y;
- case BMI_EMUL_GYR_Z:
- return data->gyr_z;
- }
-
- return 0;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_value(struct i2c_emul *emul, enum bmi_emul_axis axis,
- int32_t val)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- switch (axis) {
- case BMI_EMUL_ACC_X:
- data->acc_x = val;
- break;
- case BMI_EMUL_ACC_Y:
- data->acc_y = val;
- break;
- case BMI_EMUL_ACC_Z:
- data->acc_z = val;
- break;
- case BMI_EMUL_GYR_X:
- data->gyr_x = val;
- break;
- case BMI_EMUL_GYR_Y:
- data->gyr_y = val;
- break;
- case BMI_EMUL_GYR_Z:
- data->gyr_z = val;
- break;
- }
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
- data->error_on_ro_write = set;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
- data->error_on_rsvd_write = set;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_err_on_wo_read(struct i2c_emul *emul, bool set)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
- data->error_on_wo_read = set;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_simulate_cmd_exec_time(struct i2c_emul *emul, bool set)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
- data->simulate_command_exec_time = set;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_skipped_frames(struct i2c_emul *emul, uint8_t skip)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- data->fifo_skip = skip;
-}
-
-/**
- * @brief Convert current time to sensor time (39 us units)
- *
- * @return time in 39 us units
- */
-static int64_t bmi_emul_get_sensortime(void)
-{
- return k_uptime_ticks() * 1000000 / 39 / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
-}
-
-/**
- * @brief Set registers at address @p reg with sensor time that elapsed since
- * last reset of emulator
- *
- * @param emul Pointer to BMI emulator
- * @param reg Pointer to 3 byte array, where current sensor time should be
- * stored
- */
-static void bmi_emul_set_sensortime_reg(struct i2c_emul *emul, uint8_t *reg)
-{
- struct bmi_emul_data *data;
- uint32_t twos_comp_val;
- int64_t time;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- time = bmi_emul_get_sensortime();
-
- twos_comp_val = bmi_emul_val_to_twos_comp(time - data->zero_time);
-
- *reg = twos_comp_val & 0xff;
- *(reg + 1) = (twos_comp_val >> 8) & 0xff;
- *(reg + 2) = (twos_comp_val >> 16) & 0xff;
-}
-
-/**
- * @brief Convert given sensor axis @p val from internal units to register
- * units. It shifts value by @p shift bits to the right to account
- * range set in emulator's registers. Result is saved at address @p reg
- *
- * @param emul Pointer to BMI emulator
- * @param val Accelerometer or gyroscope value in internal units
- * @param reg Pointer to 2 byte array, where sensor value should be stored
- * @param shift How many bits should be shift to the right
- */
-static void bmi_emul_set_data_reg(struct i2c_emul *emul, int32_t val,
- uint8_t *reg, int shift)
-{
- struct bmi_emul_data *data;
- uint32_t twos_comp_val;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- twos_comp_val = bmi_emul_val_to_twos_comp(val);
-
- /* Shift unused bits because of selected range */
- twos_comp_val >>= shift;
-
- *reg = twos_comp_val & 0xff;
- *(reg + 1) = (twos_comp_val >> 8) & 0xff;
-}
-
-/**
- * @brief Compute length of given FIFO @p frame. If frame is null then length
- * of empty frame is returned.
- *
- * @param emul Pointer to BMI emulator
- * @param frame Pointer to FIFO frame
- * @param tag_time Indicate if sensor time should be included in empty frame
- * @param header Indicate if header should be included in frame
- *
- * @return length of frame
- */
-static uint8_t bmi_emul_get_frame_len(struct i2c_emul *emul,
- struct bmi_emul_frame *frame,
- bool tag_time, bool header)
-{
- struct bmi_emul_data *data;
- int len;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- /* Empty FIFO frame */
- if (frame == NULL) {
- if (tag_time && header) {
- /* Header of sensortime + sensortime + empty FIFO */
- return 5;
- }
-
- /* Empty fifo */
- return 1;
- }
-
- /* Config FIFO frame */
- if (frame->type & BMI_EMUL_FRAME_CONFIG) {
- if (header) {
- /* Header + byte of data */
- len = 2;
- if (data->type_data->sensortime_follow_config_frame) {
- /* Sensortime data */
- len += 3;
- }
-
- return len;
- }
-
- /* This frame doesn't exist in headerless mode */
- return 0;
- }
-
- /* Sensor data FIFO frame */
- if (header) {
- len = 1;
- } else {
- len = 0;
- }
-
- if (frame->type & BMI_EMUL_FRAME_ACC) {
- len += 6;
- }
- if (frame->type & BMI_EMUL_FRAME_MAG) {
- len += 8;
- }
- if (frame->type & BMI_EMUL_FRAME_GYR) {
- len += 6;
- }
-
- return len;
-}
-
-/**
- * @brief Set given FIFO @p frame as current frame in fifo field of emulator
- * data structure
- *
- * @param emul Pointer to BMI emulator
- * @param frame Pointer to FIFO frame
- * @param tag_time Indicate if sensor time should be included in empty frame
- * @param header Indicate if header should be included in frame
- * @param acc_shift How many bits should be right shifted from accelerometer
- * data
- * @param gyr_shift How many bits should be right shifted from gyroscope data
- */
-static void bmi_emul_set_current_frame(struct i2c_emul *emul,
- struct bmi_emul_frame *frame,
- bool tag_time, bool header,
- int acc_shift, int gyr_shift)
-{
- struct bmi_emul_data *data;
- int i = 0;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- data->fifo_frame_byte = 0;
- data->fifo_frame_len = bmi_emul_get_frame_len(emul, frame, tag_time,
- header);
- /* Empty FIFO frame */
- if (frame == NULL) {
- if (tag_time && header) {
- /* Header */
- data->fifo[0] = BMI_EMUL_FIFO_HEAD_TIME;
- bmi_emul_set_sensortime_reg(emul, &(data->fifo[1]));
- i = 4;
- }
-
- /* Empty header */
- data->fifo[i] = BMI_EMUL_FIFO_HEAD_EMPTY;
-
- return;
- }
-
- /* Config FIFO frame */
- if (frame->type & BMI_EMUL_FRAME_CONFIG) {
- /* Header */
- data->fifo[0] = BMI_EMUL_FIFO_HEAD_CONFIG;
- data->fifo[1] = frame->config;
- if (data->type_data->sensortime_follow_config_frame) {
- bmi_emul_set_sensortime_reg(emul, &(data->fifo[2]));
- }
-
- return;
- }
-
- /* Sensor data FIFO frame */
- if (header) {
- data->fifo[0] = BMI_EMUL_FIFO_HEAD_DATA;
- data->fifo[0] |= frame->type & BMI_EMUL_FRAME_MAG ?
- BMI_EMUL_FIFO_HEAD_DATA_MAG : 0;
- data->fifo[0] |= frame->type & BMI_EMUL_FRAME_GYR ?
- BMI_EMUL_FIFO_HEAD_DATA_GYR : 0;
- data->fifo[0] |= frame->type & BMI_EMUL_FRAME_ACC ?
- BMI_EMUL_FIFO_HEAD_DATA_ACC : 0;
- data->fifo[0] |= frame->tag & BMI_EMUL_FIFO_HEAD_DATA_TAG_MASK;
- i = 1;
- }
-
- if (frame->type & BMI_EMUL_FRAME_MAG) {
- bmi_emul_set_data_reg(emul, frame->mag_x, &(data->fifo[i]), 0);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->mag_y, &(data->fifo[i]), 0);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->mag_z, &(data->fifo[i]), 0);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->rhall, &(data->fifo[i]), 0);
- i += 2;
- }
-
- if (frame->type & BMI_EMUL_FRAME_GYR) {
- bmi_emul_set_data_reg(emul, frame->gyr_x, &(data->fifo[i]),
- gyr_shift);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->gyr_y, &(data->fifo[i]),
- gyr_shift);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->gyr_z, &(data->fifo[i]),
- gyr_shift);
- i += 2;
- }
-
- if (frame->type & BMI_EMUL_FRAME_ACC) {
- bmi_emul_set_data_reg(emul, frame->acc_x, &(data->fifo[i]),
- acc_shift);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->acc_y, &(data->fifo[i]),
- acc_shift);
- i += 2;
- bmi_emul_set_data_reg(emul, frame->acc_z, &(data->fifo[i]),
- acc_shift);
- i += 2;
- }
-}
-
-/**
- * @brief Update internal sensors offset values using values from emulated
- * registers.
- *
- * @param emul Pointer to BMI emulator
- */
-static void bmi_emul_updata_int_off(struct i2c_emul *emul)
-{
- struct bmi_emul_data *data;
- uint16_t gyr_nvm;
- uint8_t gyr98;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- data->off_acc_x = bmi_emul_acc_nvm_to_off(
- data->reg[data->type_data->acc_off_reg]);
- data->off_acc_y = bmi_emul_acc_nvm_to_off(
- data->reg[data->type_data->acc_off_reg + 1]);
- data->off_acc_z = bmi_emul_acc_nvm_to_off(
- data->reg[data->type_data->acc_off_reg + 2]);
-
- gyr98 = data->reg[data->type_data->gyr98_off_reg];
-
- gyr_nvm = data->reg[data->type_data->gyr_off_reg];
- gyr_nvm |= (gyr98 & 0x3) << 8;
- data->off_gyr_x = bmi_emul_gyr_nvm_to_off(gyr_nvm);
- gyr_nvm = data->reg[data->type_data->gyr_off_reg + 1];
- gyr_nvm |= (gyr98 & 0xc) << 6;
- data->off_gyr_y = bmi_emul_gyr_nvm_to_off(gyr_nvm);
- gyr_nvm = data->reg[data->type_data->gyr_off_reg + 2];
- gyr_nvm |= (gyr98 & 0x30) << 4;
- data->off_gyr_z = bmi_emul_gyr_nvm_to_off(gyr_nvm);
-}
-
-/**
- * @brief Restore registers backed in NVM to emulator's registers. Each model
- * of BMI may have different set of NVM backed registers.
- *
- * @param emul Pointer to BMI emulator
- */
-static void bmi_emul_restore_nvm(struct i2c_emul *emul)
-{
- struct bmi_emul_data *data;
- int i;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- ASSERT(data->type_data->nvm_len <= BMI_EMUL_MAX_NVM_REGS);
-
- /* Restore registers values */
- for (i = 0; i < data->type_data->nvm_len; i++) {
- data->reg[data->type_data->nvm_reg[i]] = data->nvm[i];
- }
-
- bmi_emul_updata_int_off(emul);
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_flush_fifo(struct i2c_emul *emul, bool tag_time, bool header)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- data->fifo_skip = 0;
- data->fifo_frame = NULL;
- /*
- * Gyroscope and accelerometer shift (last two arguments)
- * are not important for NULL (empty) FIFO frame.
- */
- bmi_emul_set_current_frame(emul, NULL, tag_time, header, 0, 0);
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_reset_common(struct i2c_emul *emul, bool tag_time, bool header)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- /* Restore registers backed in NVM */
- bmi_emul_restore_nvm(emul);
-
- /* Flush FIFO */
- bmi_emul_flush_fifo(emul, tag_time, header);
-
- /* Reset sensor timer */
- data->zero_time = bmi_emul_get_sensortime();
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_set_cmd_end_time(struct i2c_emul *emul, int time)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- data->cmd_end_time = k_uptime_get_32() + time;
-}
-
-/** Check description in emul_bmi.h */
-bool bmi_emul_is_cmd_end(struct i2c_emul *emul)
-{
- struct bmi_emul_data *data;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- /* We are simulating command execution time and it doesn't expired */
- if (data->simulate_command_exec_time &&
- data->cmd_end_time > k_uptime_get_32()) {
- return false;
- }
-
- return true;
-}
-
-/**
- * @brief Handle I2C write message. BMI model specific write function is called.
- * It is checked if accessed register isn't RO and reserved bits are set
- * to 0. Write set value of reg field of bmi emulator data ignoring
- * reserved bits. If required internal sensor offset values are updated.
- *
- * @param emul Pointer to BMI emulator
- * @param reg Register which is written
- * @param val Value being written to @p reg
- * @param byte Number of handled bytes in this write command
- *
- * @return 0 on success
- * @return -EIO on error
- */
-static int bmi_emul_handle_write(struct i2c_emul *emul, int reg, uint8_t val,
- int byte)
-{
- struct bmi_emul_data *data;
- uint8_t rsvd_mask;
- int ret;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- ret = data->type_data->handle_write(data->reg, emul, reg, byte, val);
- reg = data->type_data->access_reg(emul, reg, byte, false /* = read */);
- if (ret != 0) {
- if (ret == BMI_EMUL_ACCESS_E) {
- if (!data->error_on_ro_write) {
- return 0;
- }
- LOG_ERR("Writing to reg 0x%x which is RO", reg);
- }
-
- return -EIO;
- }
-
- rsvd_mask = data->type_data->rsvd_mask[reg];
-
- if (data->error_on_rsvd_write && rsvd_mask & val) {
- LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x",
- val, reg, rsvd_mask);
- return -EIO;
- }
-
- /* Ignore all reserved bits */
- val &= ~rsvd_mask;
- val |= data->reg[reg] & rsvd_mask;
-
- data->reg[reg] = val;
-
- if ((reg >= data->type_data->acc_off_reg &&
- reg <= data->type_data->acc_off_reg + 2) ||
- (reg >= data->type_data->gyr_off_reg &&
- reg <= data->type_data->gyr_off_reg + 2) ||
- reg == data->type_data->gyr98_off_reg) {
- /*
- * Internal offset value should be updated to new value of
- * offset registers
- */
- bmi_emul_updata_int_off(emul);
- }
-
- return 0;
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_state_to_reg(struct i2c_emul *emul, int acc_shift,
- int gyr_shift, int acc_reg, int gyr_reg,
- int sensortime_reg, bool acc_off_en,
- bool gyr_off_en)
-{
- struct bmi_emul_data *data;
- int32_t val[3];
- int i;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- if (gyr_off_en) {
- val[0] = data->gyr_x - data->off_gyr_x;
- val[1] = data->gyr_y - data->off_gyr_y;
- val[2] = data->gyr_z - data->off_gyr_z;
- } else {
- val[0] = data->gyr_x;
- val[1] = data->gyr_y;
- val[2] = data->gyr_z;
- }
-
- for (i = 0; i < 3; i++) {
- bmi_emul_set_data_reg(emul, val[i],
- &(data->reg[gyr_reg + i * 2]), gyr_shift);
- }
-
- if (acc_off_en) {
- val[0] = data->acc_x - data->off_acc_x;
- val[1] = data->acc_y - data->off_acc_y;
- val[2] = data->acc_z - data->off_acc_z;
- } else {
- val[0] = data->acc_x;
- val[1] = data->acc_y;
- val[2] = data->acc_z;
- }
-
- for (i = 0; i < 3; i++) {
- bmi_emul_set_data_reg(emul, val[i],
- &(data->reg[acc_reg + i * 2]), acc_shift);
- }
-
- bmi_emul_set_sensortime_reg(emul, &(data->reg[sensortime_reg]));
-}
-
-/** Check description in emul_bmi.h */
-void bmi_emul_append_frame(struct i2c_emul *emul, struct bmi_emul_frame *frame)
-{
- struct bmi_emul_data *data;
- struct bmi_emul_frame *tmp_frame;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- if (data->fifo_frame == NULL) {
- data->fifo_frame = frame;
- } else {
- tmp_frame = data->fifo_frame;
- while (tmp_frame->next != NULL) {
- tmp_frame = tmp_frame->next;
- }
- tmp_frame->next = frame;
- }
-}
-
-/** Check description in emul_bmi.h */
-uint16_t bmi_emul_fifo_len(struct i2c_emul *emul, bool tag_time, bool header)
-{
- struct bmi_emul_frame *frame;
- struct bmi_emul_data *data;
- uint16_t len = 0;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- if (data->fifo_skip != 0 && header) {
- len += 2;
- }
-
- frame = data->fifo_frame;
- while (frame != NULL) {
- len += bmi_emul_get_frame_len(emul, frame, tag_time, header);
- frame = frame->next;
- }
-
- len += bmi_emul_get_frame_len(emul, NULL, tag_time, header);
- /* Do not count last empty frame byte */
- len--;
-
- return len;
-}
-
-/** Check description in emul_bmi.h */
-uint8_t bmi_emul_get_fifo_data(struct i2c_emul *emul, int byte,
- bool tag_time, bool header, int acc_shift,
- int gyr_shift)
-{
- struct bmi_emul_data *data;
- int ret;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- if (byte == 0) {
- /* Repeat uncompleated read of frame */
- bmi_emul_set_current_frame(emul, data->fifo_frame, tag_time,
- header, acc_shift, gyr_shift);
-
- /* Return header for skip frame */
- if (data->fifo_skip != 0 && header) {
- return BMI_EMUL_FIFO_HEAD_SKIP;
- }
- }
-
- if (data->fifo_skip != 0 && byte == 1 && header) {
- /* Return number of skipped frames */
- ret = data->fifo_skip;
- data->fifo_skip = 0;
-
- return ret;
- }
-
- /* Get next valid frame */
- while (data->fifo_frame_byte >= data->fifo_frame_len) {
- /* No data */
- if (data->fifo_frame == NULL) {
- return 0;
- }
- data->fifo_frame = data->fifo_frame->next;
- bmi_emul_set_current_frame(emul, data->fifo_frame, tag_time,
- header, acc_shift, gyr_shift);
- }
-
- return data->fifo[data->fifo_frame_byte++];
-}
-
-/**
- * @brief Handle I2C read message. BMI model specific read function is called.
- * It is checked if accessed register isn't WO.
- *
- * @param emul Pointer to BMI emulator
- * @param reg Register address to read
- * @param buf Pointer where result should be stored
- * @param byte Byte which is accessed during block read
- *
- * @return 0 on success
- * @return -EIO on error
- */
-static int bmi_emul_handle_read(struct i2c_emul *emul, int reg, uint8_t *buf,
- int byte)
-{
- struct bmi_emul_data *data;
- int ret;
-
- data = BMI_DATA_FROM_I2C_EMUL(emul);
-
- ret = data->type_data->handle_read(data->reg, emul, reg, byte, buf);
- reg = data->type_data->access_reg(emul, reg, byte, true /* = read */);
- if (ret == BMI_EMUL_ACCESS_E && data->error_on_wo_read) {
- LOG_ERR("Reading reg 0x%x which is WO", reg);
- } else if (ret != 0) {
- return ret;
- }
-
- return 0;
-}
-
-/* Device instantiation */
-
-static struct i2c_emul_api bmi_emul_api = {
- .transfer = i2c_common_emul_transfer,
-};
-
-/**
- * @brief Set up a new BMI emulator
- *
- * This should be called for each BMI device that needs to be
- * emulated. It registers it with the I2C emulation controller.
- *
- * @param emul Emulation information
- * @param parent Device to emulate
- *
- * @return 0 indicating success (always)
- */
-static int bmi_emul_init(const struct emul *emul,
- const struct device *parent)
-{
- const struct i2c_common_emul_cfg *cfg = emul->cfg;
- struct i2c_common_emul_data *data = cfg->data;
- struct bmi_emul_data *bmi_data;
- int ret;
-
- data->emul.api = &bmi_emul_api;
- data->emul.addr = cfg->addr;
- data->i2c = parent;
- data->cfg = cfg;
- i2c_common_emul_init(data);
-
- bmi_data = CONTAINER_OF(data, struct bmi_emul_data, common);
-
- switch (bmi_data->type) {
- case BMI_EMUL_160:
- bmi_data->type_data = get_bmi160_emul_type_data();
- break;
- case BMI_EMUL_260:
- bmi_data->type_data = get_bmi260_emul_type_data();
- break;
- }
-
- /* Set callback access_reg to type specific function */
- data->access_reg = bmi_data->type_data->access_reg;
-
- ret = i2c_emul_register(parent, emul->dev_label, &data->emul);
-
- bmi_data->type_data->reset(bmi_data->reg, &data->emul);
-
- return ret;
-}
-
-#define BMI_EMUL(n) \
- static struct bmi_emul_data bmi_emul_data_##n = { \
- .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\
- .error_on_wo_read = DT_INST_PROP(n, error_on_wo_read), \
- .error_on_rsvd_write = DT_INST_PROP(n, \
- error_on_reserved_bit_write), \
- .simulate_command_exec_time = DT_INST_PROP(n, \
- simulate_command_exec_time), \
- .type = DT_STRING_TOKEN(DT_DRV_INST(n), device_model), \
- .common = { \
- .start_write = NULL, \
- .write_byte = bmi_emul_handle_write, \
- .finish_write = NULL, \
- .start_read = NULL, \
- .read_byte = bmi_emul_handle_read, \
- .finish_read = NULL, \
- .access_reg = NULL, \
- }, \
- }; \
- \
- static const struct i2c_common_emul_cfg bmi_emul_cfg_##n = { \
- .i2c_label = DT_INST_BUS_LABEL(n), \
- .dev_label = DT_INST_LABEL(n), \
- .data = &bmi_emul_data_##n.common, \
- .addr = DT_INST_REG_ADDR(n), \
- }; \
- EMUL_DEFINE(bmi_emul_init, DT_DRV_INST(n), &bmi_emul_cfg_##n, \
- &bmi_emul_data_##n)
-
-DT_INST_FOREACH_STATUS_OKAY(BMI_EMUL)
-
-#define BMI_EMUL_CASE(n) \
- case DT_INST_DEP_ORD(n): return &bmi_emul_data_##n.common.emul;
-
-/** Check description in emul_bmi.h */
-struct i2c_emul *bmi_emul_get(int ord)
-{
- switch (ord) {
- DT_INST_FOREACH_STATUS_OKAY(BMI_EMUL_CASE)
-
- default:
- return NULL;
- }
-}