diff options
Diffstat (limited to 'zephyr/emul/emul_bmi.c')
-rw-r--r-- | zephyr/emul/emul_bmi.c | 1116 |
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; - } -} |