diff --git a/dts/bindings/analog,adau1860.yaml b/dts/bindings/adi,adau1860.yaml similarity index 86% rename from dts/bindings/analog,adau1860.yaml rename to dts/bindings/adi,adau1860.yaml index 394419b6..2f91a5c7 100644 --- a/dts/bindings/analog,adau1860.yaml +++ b/dts/bindings/adi,adau1860.yaml @@ -6,7 +6,7 @@ include: [sensor-device.yaml, i2c-device.yaml] -compatible: "analog,adau1860" +compatible: "adi,adau1860" properties: enable-gpios: diff --git a/include/sensor_sink.h b/include/sensor_sink.h new file mode 100644 index 00000000..9be9641d --- /dev/null +++ b/include/sensor_sink.h @@ -0,0 +1,20 @@ +#ifndef SENSOR_SINK_H +#define SENSOR_SINK_H + +#include "openearable_common.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int sensor_sink_put(const struct sensor_msg *msg); + +int sensor_sink_write_sd(const void *const *data_blocks, const size_t *lengths, + size_t block_count); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/ParseInfo/DefaultSensors.h b/src/ParseInfo/DefaultSensors.h index e6e3ef21..374ce136 100644 --- a/src/ParseInfo/DefaultSensors.h +++ b/src/ParseInfo/DefaultSensors.h @@ -17,14 +17,14 @@ // ============= Microphones ============= #define MICRO_CHANNEL_COUNT 2 -SensorComponent microComponenents[MICRO_CHANNEL_COUNT] = { +SensorComponent microComponents[MICRO_CHANNEL_COUNT] = { { .name = "INNER", .unit = "ADC", .parseType = PARSE_TYPE_UINT16 }, - { .name = "Outer", .unit = "ADC", .parseType = PARSE_TYPE_UINT16 }, + { .name = "OUTER", .unit = "ADC", .parseType = PARSE_TYPE_UINT16 }, }; #define MICRO_GROUP_COUNT 1 SensorComponentGroup microGroups[MICRO_GROUP_COUNT] = { - { .name = "MICROPHONE", .componentCount = MICRO_CHANNEL_COUNT, .components = microComponenents }, + { .name = "MICROPHONE", .componentCount = MICRO_CHANNEL_COUNT, .components = microComponents }, }; // ============= IMU ============= diff --git a/src/ParseInfo/ParseType.h b/src/ParseInfo/ParseType.h index 01dc819a..e92361f7 100644 --- a/src/ParseInfo/ParseType.h +++ b/src/ParseInfo/ParseType.h @@ -15,7 +15,7 @@ enum ParseType { PARSE_TYPE_DOUBLE, }; -const int parseTypeSizes[] = { +static const int parseTypeSizes[] = { 1, // PARSE_TYPE_INT8 1, // PARSE_TYPE_UINT8 diff --git a/src/SensorManager/ANCDamping.cpp b/src/SensorManager/ANCDamping.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/src/SensorManager/ANCDamping.h b/src/SensorManager/ANCDamping.h deleted file mode 100644 index e69de29b..00000000 diff --git a/src/SensorManager/BMA580/BMA580_Sensor.cpp b/src/SensorManager/BMA580/BMA580_Sensor.cpp index 779f69ed..746b1f3e 100644 --- a/src/SensorManager/BMA580/BMA580_Sensor.cpp +++ b/src/SensorManager/BMA580/BMA580_Sensor.cpp @@ -32,8 +32,6 @@ * */ #include -// #include -// #include #include "bma5.h" #include "BMA580_Sensor.h" @@ -63,7 +61,7 @@ BMA5_INTF_RET_TYPE bma5_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t l int ret; BMA580_dev_inf * dev_info = (BMA580_dev_inf *) intf_ptr; - dev_info->i2c_dev->aquire(); + dev_info->i2c_dev->acquire(); ret = i2c_burst_read(dev_info->i2c_dev->master, dev_info->addr, reg_addr, reg_data, len); if (ret) LOG_WRN("I2C read failed: %d\n", ret); @@ -79,7 +77,7 @@ BMA5_INTF_RET_TYPE bma5_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uin { BMA580_dev_inf * dev_info = (BMA580_dev_inf *) intf_ptr; - dev_info->i2c_dev->aquire(); + dev_info->i2c_dev->acquire(); int ret = i2c_burst_write(dev_info->i2c_dev->master, dev_info->addr, reg_addr, reg_data, len); if (ret) LOG_WRN("I2C write failed: %d", ret); @@ -236,7 +234,10 @@ int8_t BMA580::get_accel_and_int_settings(struct bma5_dev *dev) } /*! - * @brief This internal API gets FIFO configurations. + * @brief This internal API sets FIFO configurations and verifies the readback + * matches what we asked for. The chip silently clamps fifo_size when the + * feature engine is enabled (datasheet section 4.6.1.5), so a missing log here + * is the only way to notice that condition without a logic analyzer. */ int8_t BMA580::get_fifo_conf(const struct bma5_fifo_conf *fifo_conf, struct bma5_dev *dev) { @@ -252,13 +253,18 @@ int8_t BMA580::get_fifo_conf(const struct bma5_fifo_conf *fifo_conf, struct bma5 rslt = bma5_get_fifo_conf(&read_fifo_conf, dev); bma5_check_rslt("bma5_get_fifo_conf", rslt); + /* Verify that the chip accepted the size we asked for. */ + if (read_fifo_conf.fifo_size != fifo_conf->fifo_size) { + LOG_ERR("FIFO size mismatch: requested 0x%02X, readback 0x%02X " + "(feature engine likely still enabled)", + fifo_conf->fifo_size, read_fifo_conf.fifo_size); + } + return rslt; } int BMA580::init(int odr, int fifo_watermark_level) { int8_t rslt; - struct bma580_int_map int_map, get_int_map; - //struct bma5_fifo_conf fifo_conf; /* Assign context parameter selection */ enum bma5_context context = BMA5_HEARABLE; @@ -276,19 +282,20 @@ int BMA580::init(int odr, int fifo_watermark_level) { bma5_check_rslt("bma580_init", rslt); LOG_DBG("Chip ID :0x%X", dev.chip_id); - /* Map generic interrupts to hardware interrupt pin of the sensor */ - rslt = bma580_get_int_map(&int_map, &dev); - bma5_check_rslt("bma580_get_int_map", rslt); - - /* Set FIFO full interrupt to INT2 */ - //int_map.fifo_full_int_map = BMA580_FIFO_FULL_INT_MAP_INT2; - int_map.fifo_wm_int_map = BMA580_FIFO_WM_INT_MAP_INT1; - - rslt = bma580_set_int_map(&int_map, &dev); - bma5_check_rslt("bma580_set_int_map", rslt); - - rslt = bma580_get_int_map(&get_int_map, &dev); - bma5_check_rslt("bma580_get_int_map", rslt); + /* Disable the feature engine. The BMA580 powers up with feat_eng enabled + * (FEAT_ENG_CONF reset value = 0x01), and feat_eng shares its 1024-byte + * RAM with the FIFO. While feat_eng is enabled the FIFO is capped at + * 512 bytes and any write of fifo_size = 0x03 (1024 B) is silently + * clamped to 0x02 (512 B) — verified empirically via the readback log + * in get_fifo_conf(). We don't use any feature-engine features + * (VAD, tap, generic interrupts, FOC, self-wakeup), so disabling it is + * safe and gives the FIFO its full 1024 bytes. */ + rslt = bma5_set_feat_eng_conf(BMA5_FEAT_ENG_CTRL_DISABLE, &dev); + bma5_check_rslt("bma5_set_feat_eng_conf", rslt); + + /* INT1/INT2 hardware interrupt pins are unused — FIFO is drained by a + * timer-based poll in BoneConduction::update_sensor, so we don't map + * the watermark or full interrupts to any pin. */ rslt = get_accel_and_int_settings(&dev); bma5_check_rslt("get_accel_and_int_settings", rslt); @@ -297,17 +304,14 @@ int BMA580::init(int odr, int fifo_watermark_level) { rslt = bma5_get_fifo_conf(&fifo_conf, &dev); bma5_check_rslt("bma5_get_fifo_conf", rslt); - rslt = bma5_get_fifo_conf(&fifo_conf, &dev); - bma5_check_rslt("bma5_get_fifo_conf", rslt); - fifo_conf.fifo_cfg = BMA5_FIFO_CFG_ENABLE; fifo_conf.fifo_acc_x = BMA5_FIFO_ACC_X_ENABLE; fifo_conf.fifo_acc_y = BMA5_FIFO_ACC_Y_ENABLE; fifo_conf.fifo_acc_z = BMA5_FIFO_ACC_Z_ENABLE; fifo_conf.fifo_compression = BMA5_FIFO_COMPRESSION_ACC_16BIT; fifo_conf.fifo_sensor_time = BMA5_FIFO_SENSOR_TIME_OFF; - fifo_conf.fifo_size = BMA5_FIFO_SIZE_MAX_512_BYTES; - fifo_conf.fifo_stop_on_full = BMA5_ENABLE; //BMA5_ENABLE + fifo_conf.fifo_size = BMA5_FIFO_SIZE_MAX_1024_BYTES; + fifo_conf.fifo_stop_on_full = BMA5_DISABLE; rslt = get_fifo_conf(&fifo_conf, &dev); bma5_check_rslt("get_fifo_conf", rslt); @@ -335,32 +339,19 @@ int BMA580::stop() { int BMA580::read(bma5_sens_fifo_axes_data_16_bit *fifo_accel_data) { int8_t rslt = BMA5_OK; - uint8_t n_status = 1; - struct bma580_int_status_types int_status = { 0 }; fifoframe.fifo_avail_frames = 0; - int_status.int_src = BMA580_INT_STATUS_INT1; - - /* Get fifo full interrupt 2 status */ - rslt = bma580_get_int_status(&int_status, n_status, &dev); - bma5_check_rslt("bma580_get_int_status", rslt); + /* Read whatever is in the FIFO — don't wait for watermark interrupt. + * When using a timer-based read at the FIFO fill rate, the watermark + * may not have triggered yet due to clock drift between the nRF5340 + * and BMA580. Reading unconditionally avoids this race. */ + rslt = bma5_read_fifo_data(&fifoframe, &fifo_conf, &dev); + bma5_check_rslt("bma5_read_fifo_data", rslt); - if (int_status.int_status.fifo_wm_int_status & BMA5_ENABLE) + if (rslt == BMA5_OK && fifoframe.fifo_avail_len > 0) { - /* Read FIFO data */ - rslt = bma5_read_fifo_data(&fifoframe, &fifo_conf, &dev); - bma5_check_rslt("bma5_read_fifo_data", rslt); - - /* Set fifo full interrupt 2 status */ - rslt = bma580_set_int_status(&int_status, n_status, &dev); - bma5_check_rslt("bma580_get_int_status\n", rslt); - - if (rslt == BMA5_OK) - { - /* Parse the FIFO data to extract accelerometer and sensortime data from the FIFO buffer */ - (void)bma5_extract_acc_sens_time_16_bit(fifo_accel_data, &fifoframe, &fifo_conf, &dev); - } + (void)bma5_extract_acc_sens_time_16_bit(fifo_accel_data, &fifoframe, &fifo_conf, &dev); } return fifoframe.fifo_avail_frames; diff --git a/src/SensorManager/BMA580/BMA580_Sensor.h b/src/SensorManager/BMA580/BMA580_Sensor.h index d8c0574d..0e153558 100644 --- a/src/SensorManager/BMA580/BMA580_Sensor.h +++ b/src/SensorManager/BMA580/BMA580_Sensor.h @@ -37,14 +37,13 @@ #include #include "bma5.h" -//#include "Wire.h" #include /******************************************************************************/ /*! Macro definition */ /*! FIFO raw data buffer size */ -#define BMA580_FIFO_RAW_DATA_BUFFER_SIZE UINT16_C(520) +#define BMA580_FIFO_RAW_DATA_BUFFER_SIZE UINT16_C(1032) /*! Number of accel frames to be extracted from FIFO * Calculation: diff --git a/src/SensorManager/BMP388/Adafruit_BMP3XX.cpp b/src/SensorManager/BMP388/Adafruit_BMP3XX.cpp index 95748ee2..1fb492bb 100644 --- a/src/SensorManager/BMP388/Adafruit_BMP3XX.cpp +++ b/src/SensorManager/BMP388/Adafruit_BMP3XX.cpp @@ -59,7 +59,7 @@ Adafruit_BMP3XX::Adafruit_BMP3XX(void) { } bool Adafruit_BMP3XX::detect(int address) { - dev_inf.i2c_dev->aquire(); + dev_inf.i2c_dev->acquire(); uint8_t dummy = 0; int ret = i2c_write(dev_inf.i2c_dev->master, &dummy, 0, address); dev_inf.i2c_dev->release(); @@ -140,7 +140,6 @@ bool Adafruit_BMP3XX::_init(void) { printk("P9 = %i\n", the_sensor.calib_data.reg_calib_data.par_p9); printk("P10 = %i\n", the_sensor.calib_data.reg_calib_data.par_p10); printk("P11 = %i\n", the_sensor.calib_data.reg_calib_data.par_p11); - // printk("T lin = %i\n", the_sensor.calib_data.reg_calib_data.t_lin); #endif setTemperatureOversampling(BMP3_NO_OVERSAMPLING); @@ -148,8 +147,17 @@ bool Adafruit_BMP3XX::_init(void) { setIIRFilterCoeff(BMP3_IIR_FILTER_DISABLE); setOutputDataRate(BMP3_ODR_25_HZ); - // don't do anything till we request a reading - the_sensor.settings.op_mode = BMP3_MODE_FORCED; + the_sensor.settings.temp_en = BMP3_ENABLE; + the_sensor.settings.press_en = BMP3_ENABLE; + uint16_t settings_sel = BMP3_SEL_TEMP_EN | BMP3_SEL_PRESS_EN | BMP3_SEL_ODR; + int8_t settings_rslt = bmp3_set_sensor_settings(settings_sel, &the_sensor); + if (settings_rslt != BMP3_OK) + return false; + + the_sensor.settings.op_mode = BMP3_MODE_NORMAL; + settings_rslt = bmp3_set_op_mode(&the_sensor); + if (settings_rslt != BMP3_OK) + return false; return true; } @@ -218,86 +226,24 @@ float Adafruit_BMP3XX::readAltitude(float seaLevel) { */ /**************************************************************************/ bool Adafruit_BMP3XX::performReading(void) { - //g_i2c_dev = i2c_dev; - //g_spi_dev = spi_dev; int8_t rslt; - /* Used to select the settings user needs to change */ - uint16_t settings_sel = 0; - /* Variable used to select the sensor component */ - uint8_t sensor_comp = 0; - - /* Select the pressure and temperature sensor to be enabled */ - the_sensor.settings.temp_en = BMP3_ENABLE; - settings_sel |= BMP3_SEL_TEMP_EN; - sensor_comp |= BMP3_TEMP; - if (_tempOSEnabled) { - settings_sel |= BMP3_SEL_TEMP_OS; - } - - the_sensor.settings.press_en = BMP3_ENABLE; - settings_sel |= BMP3_SEL_PRESS_EN; - sensor_comp |= BMP3_PRESS; - if (_presOSEnabled) { - settings_sel |= BMP3_SEL_PRESS_OS; - } - - if (_filterEnabled) { - settings_sel |= BMP3_SEL_IIR_FILTER; - } - - if (_ODREnabled) { - settings_sel |= BMP3_SEL_ODR; - } - - // set interrupt to data ready - // settings_sel |= BMP3_DRDY_EN_SEL | BMP3_LEVEL_SEL | BMP3_LATCH_SEL; - - /* Set the desired sensor configuration */ -#ifdef BMP3XX_DEBUG - printk("Setting sensor settings\n"); -#endif - rslt = bmp3_set_sensor_settings(settings_sel, &the_sensor); - - if (rslt != BMP3_OK) - return false; - - /* Set the power mode */ - the_sensor.settings.op_mode = BMP3_MODE_FORCED; -#ifdef BMP3XX_DEBUG - printk("Setting power mode\n"); -#endif - rslt = bmp3_set_op_mode(&the_sensor); - if (rslt != BMP3_OK) - return false; - - /* Variable used to store the compensated data */ struct bmp3_data data; - /* Temperature and Pressure data are read and stored in the bmp3_data instance - */ -#ifdef BMP3XX_DEBUG - printk("Getting sensor data\n"); -#endif - rslt = bmp3_get_sensor_data(sensor_comp, &data, &the_sensor); + rslt = bmp3_get_sensor_data(BMP3_TEMP | BMP3_PRESS, &data, &the_sensor); if (rslt != BMP3_OK) return false; - /* -#ifdef BMP3XX_DEBUG - Serial.println(F("Analyzing sensor data")); -#endif - rslt = analyze_sensor_data(&data); - if (rslt != BMP3_OK) - return false; - */ - - /* Save the temperature and pressure data */ temperature = data.temperature; pressure = data.pressure; return true; } +bool Adafruit_BMP3XX::sleep(void) { + the_sensor.settings.op_mode = BMP3_MODE_SLEEP; + return bmp3_set_op_mode(&the_sensor) == BMP3_OK; +} + /**************************************************************************/ /*! @brief Setter for Temperature oversampling @@ -403,7 +349,7 @@ int8_t i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, BMP3XX_dev_inf * dev_info = (BMP3XX_dev_inf *) intf_ptr; - dev_info->i2c_dev->aquire(); + dev_info->i2c_dev->acquire(); int ret = i2c_burst_read(dev_info->i2c_dev->master, dev_info->addr, reg_addr, reg_data, len); if (ret) LOG_WRN("I2C read failed: %d\n", ret); @@ -422,7 +368,7 @@ int8_t i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { BMP3XX_dev_inf * dev_info = (BMP3XX_dev_inf *) intf_ptr; - dev_info->i2c_dev->aquire(); + dev_info->i2c_dev->acquire(); int ret = i2c_burst_write(dev_info->i2c_dev->master, dev_info->addr, reg_addr, reg_data, len); if (ret) LOG_WRN("I2C write failed: %d", ret); diff --git a/src/SensorManager/BMP388/Adafruit_BMP3XX.h b/src/SensorManager/BMP388/Adafruit_BMP3XX.h index a9843b00..85866533 100644 --- a/src/SensorManager/BMP388/Adafruit_BMP3XX.h +++ b/src/SensorManager/BMP388/Adafruit_BMP3XX.h @@ -23,11 +23,6 @@ #define __BMP3XX_H__ #include "bmp3.h" - -//#include "../Adafruit_BusIO/Adafruit_I2CDevice.h" -//#include "Adafruit_SPIDevice.h" - -//#include "Wire.h" #include /*========================================================================= @@ -35,7 +30,6 @@ -----------------------------------------------------------------------*/ #define BMP3XX_DEFAULT_ADDRESS (0x76) ///< The default I2C address /*=========================================================================*/ -//#define BMP3XX_DEFAULT_SPIFREQ (1000000) ///< The default SPI Clock speed /** Adafruit_BMP3XX Class for both I2C and SPI usage. * Wraps the Bosch library for Arduino usage @@ -68,6 +62,10 @@ class Adafruit_BMP3XX { /// Perform a reading in blocking mode bool performReading(void); + /// Put the sensor into sleep mode (stops conversions). + /// Call before cutting power to avoid leaving the chip mid-conversion. + bool sleep(void); + /// Temperature (Celsius) assigned after calling performReading() double temperature; /// Pressure (Pascals) assigned after calling performReading() diff --git a/src/SensorManager/BMX160/BMX160_Sensor.cpp b/src/SensorManager/BMX160/BMX160_Sensor.cpp new file mode 100644 index 00000000..c9c8ef63 --- /dev/null +++ b/src/SensorManager/BMX160/BMX160_Sensor.cpp @@ -0,0 +1,285 @@ +#include "BMX160_Sensor.h" + +#include "bmi160.h" +#include "bmi160_defs.h" + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(BMX160, 3); + +/* BMX160 combo chip: I2C address 0x68, BMM150 accessed via BMI160 aux bus. + * Mag-interface register layout (per BMI160 datasheet): + * 0x4B MAG_IF_0 aux device I2C address + * 0x4C MAG_IF_1 control (bit7 = manual mode) + * 0x4D MAG_IF_2 read register address + * 0x4E MAG_IF_3 write data + * 0x4F MAG_IF_4 write register address + * BMX160 has BMM150 wired internally at aux address 0x10 which is the + * reset default in MAG_IF_0, so we don't need to set it explicitly. + * The configuration sequence below mirrors the working DFRobot driver + * and puts BMM150 into "data mode" so its X/Y/Z/Rhall are auto-shadowed + * into BMI160 data registers 0x04..0x0B. */ +#define BMX160_I2C_ADDR 0x68 +#define BMX160_DATA_MAG_ADDR 0x04 +#define BMX160_MAG_IF_1 0x4C +#define BMX160_MAG_IF_2 0x4D +#define BMX160_MAG_IF_3 0x4E +#define BMX160_MAG_IF_4 0x4F +#define BMX160_MAG_CONF 0x44 +#define BMX160_CMD_REG 0x7E + +/* Scaling factors chosen to preserve the unit output of the legacy + * DFRobot driver (accel in m/s^2 at 2G, gyro in deg/s scaled as if + * 250 dps, mag in uT). Gyro scale matches what the legacy driver + * reported even though the chip is actually running at 2000 dps — + * preserving this so downstream consumers see no step change. */ +#define BMX160_ACCEL_LSB_TO_MS2_2G (0.000061035f * 9.81f) +#define BMX160_GYRO_LSB_TO_DPS_250 (0.0076220f) +#define BMX160_MAG_LSB_TO_UT (0.3f) + +/* Static context so Bosch callbacks can reach the bus. Bosch's callback + * typedef doesn't take a user context pointer, so we stash it here. */ +static TWIM * s_i2c = &I2C3; + +static int8_t bmi160_i2c_read(uint8_t dev_addr, uint8_t reg_addr, + uint8_t *data, uint16_t len) +{ + s_i2c->acquire(); + int ret = i2c_burst_read(s_i2c->master, dev_addr, reg_addr, data, len); + s_i2c->release(); + if (ret) { + LOG_WRN("BMX160 I2C read failed: %d (reg 0x%02X len %u)", + ret, reg_addr, len); + return -1; + } + return 0; +} + +static int8_t bmi160_i2c_write(uint8_t dev_addr, uint8_t reg_addr, + uint8_t *data, uint16_t len) +{ + s_i2c->acquire(); + int ret = i2c_burst_write(s_i2c->master, dev_addr, reg_addr, data, len); + s_i2c->release(); + if (ret) { + LOG_WRN("BMX160 I2C write failed: %d (reg 0x%02X len %u)", + ret, reg_addr, len); + return -1; + } + return 0; +} + +static void bmi160_delay_ms(uint32_t period) +{ + k_msleep(period); +} + +int8_t BMX160::configure_magnetometer() +{ +#ifndef CONFIG_IMU_ENABLE_MAGNETOMETER + /* Magnetometer gated off: keep the BMM150 subsystem in suspend so it + * doesn't burn ~170 uA for readings that the speaker magnet swamps + * anyway. The data registers will stay at reset (zero); the drain + * path skips read_mag_latched() and zero-fills the mag fields. */ + uint8_t mag_suspend = BMI160_AUX_SUSPEND_MODE; + int8_t rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &mag_suspend, 1, &dev); + if (rslt != BMI160_OK) { + LOG_WRN("mag suspend CMD failed: %d", rslt); + } + return rslt; +#else + /* Power on the internal BMM150 subsystem. CMD 0x19 = aux/mag interface + * normal power mode. bmi160_set_sens_conf only issues CMDs for accel + * and gyro; without this write the MAG_IF writes below go to a + * powered-off magnetometer and produce all-zero readings. */ + uint8_t mag_normal = BMI160_AUX_NORMAL_MODE; + int8_t rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &mag_normal, 1, &dev); + if (rslt != BMI160_OK) { + LOG_WRN("mag power-on CMD failed: %d", rslt); + return rslt; + } + k_msleep(10); + + /* Replicates DFRobot_BMX160::setMagnConf() register sequence. The + * BMM150 init dance puts the magnetometer into "data mode" where + * BMI160's MAG_IF interface auto-polls BMM150 at the configured + * rate and shadows the result to data registers 0x04..0x0B. */ + struct { + uint8_t reg; + uint8_t val; + uint32_t post_delay_ms; + } seq[] = { + { BMX160_MAG_IF_1, 0x80, 50 }, /* enter aux setup mode */ + { BMX160_MAG_IF_4, 0x01, 0 }, /* BMM150 sleep */ + { BMX160_MAG_IF_3, 0x4B, 0 }, + { BMX160_MAG_IF_4, 0x04, 0 }, /* REPXY regular preset */ + { BMX160_MAG_IF_3, 0x51, 0 }, + { BMX160_MAG_IF_4, 0x0E, 0 }, /* REPZ regular preset */ + { BMX160_MAG_IF_3, 0x52, 0 }, + { BMX160_MAG_IF_4, 0x02, 0 }, /* put BMM150 in forced-mode */ + { BMX160_MAG_IF_3, 0x4C, 0 }, + { BMX160_MAG_IF_2, 0x42, 0 }, /* read start addr = DATAX_LSB */ + { BMX160_MAG_CONF, 0x08, 0 }, /* ODR = 100 Hz */ + { BMX160_MAG_IF_1, 0x03, 50 }, /* data mode, 8-byte burst */ + }; + for (size_t i = 0; i < sizeof(seq) / sizeof(seq[0]); i++) { + rslt = bmi160_set_regs(seq[i].reg, &seq[i].val, 1, &dev); + if (rslt != BMI160_OK) { + LOG_WRN("mag setup step %u failed: %d", (unsigned)i, rslt); + return rslt; + } + if (seq[i].post_delay_ms) k_msleep(seq[i].post_delay_ms); + } + return BMI160_OK; +#endif +} + +int BMX160::read_mag_latched(float out_mag[3]) +{ + /* Single 6-byte read from BMI160's shadowed mag data (X/Y/Z LSB+MSB, + * skipping Rhall). BMM150 is running at 100 Hz via data mode so this + * returns the most recent sample with no extra transactions per IMU + * sample. */ + uint8_t buf[6] = { 0 }; + int8_t rslt = bmi160_get_regs(BMX160_DATA_MAG_ADDR, buf, 6, &dev); + if (rslt != BMI160_OK) return rslt; + + int16_t x = (int16_t)((uint16_t)buf[1] << 8 | buf[0]); + int16_t y = (int16_t)((uint16_t)buf[3] << 8 | buf[2]); + int16_t z = (int16_t)((uint16_t)buf[5] << 8 | buf[4]); + out_mag[0] = (float)x * BMX160_MAG_LSB_TO_UT; + out_mag[1] = (float)y * BMX160_MAG_LSB_TO_UT; + out_mag[2] = (float)z * BMX160_MAG_LSB_TO_UT; + return 0; +} + +int BMX160::init(uint8_t accel_odr_reg, uint8_t gyro_odr_reg, + uint16_t fifo_watermark_bytes) +{ + s_i2c->begin(); + + dev.id = BMX160_I2C_ADDR; + dev.intf = BMI160_I2C_INTF; + dev.read = bmi160_i2c_read; + dev.write = bmi160_i2c_write; + dev.delay_ms = bmi160_delay_ms; + dev.read_write_len = 128; + + int8_t rslt = bmi160_init(&dev); + if (rslt != BMI160_OK) { + LOG_ERR("bmi160_init failed: %d (chip_id=0x%02X)", rslt, dev.chip_id); + return rslt; + } + + dev.accel_cfg.odr = accel_odr_reg; + dev.accel_cfg.range = BMI160_ACCEL_RANGE_2G; + dev.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4; + dev.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE; + + dev.gyro_cfg.odr = gyro_odr_reg; + dev.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS; + dev.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE; + dev.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE; + + rslt = bmi160_set_sens_conf(&dev); + if (rslt != BMI160_OK) { + LOG_ERR("bmi160_set_sens_conf failed: %d", rslt); + return rslt; + } + + _accel_lsb_to_ms2 = BMX160_ACCEL_LSB_TO_MS2_2G; + _gyro_lsb_to_dps = BMX160_GYRO_LSB_TO_DPS_250; + + /* BMM150 magnetometer setup through BMI160 aux interface */ + (void)configure_magnetometer(); + + /* Headered FIFO with accel + gyro (mag is read separately). */ + fifo_frame.data = fifo_buf; + fifo_frame.length = BMX160_FIFO_RAW_DATA_BUFFER_SIZE; + fifo_frame.fifo_time_enable = 0; + fifo_frame.fifo_header_enable = BMI160_FIFO_HEAD_ENABLE; + fifo_frame.fifo_data_enable = BMI160_FIFO_G_A_ENABLE; + dev.fifo = &fifo_frame; + + /* BMI160 FIFO watermark reg is in units of 4 bytes. */ + uint8_t wm = (uint8_t)MIN(fifo_watermark_bytes / 4, 0xFFU); + rslt = bmi160_set_fifo_wm(wm, &dev); + if (rslt != BMI160_OK) LOG_WRN("bmi160_set_fifo_wm: %d", rslt); + + /* Enable A+G in FIFO + headered mode. Flush first. */ + rslt = bmi160_set_fifo_flush(&dev); + if (rslt != BMI160_OK) LOG_WRN("bmi160_set_fifo_flush: %d", rslt); + + uint8_t fifo_cfg = BMI160_FIFO_ACCEL | BMI160_FIFO_GYRO | BMI160_FIFO_HEADER; + rslt = bmi160_set_fifo_config(fifo_cfg, BMI160_ENABLE, &dev); + if (rslt != BMI160_OK) { + LOG_ERR("bmi160_set_fifo_config: %d", rslt); + return rslt; + } + + return BMI160_OK; +} + +int BMX160::start() +{ + /* sens_conf already put accel/gyro in NORMAL mode. Flush stale frames. */ + int8_t rslt = bmi160_set_fifo_flush(&dev); + if (rslt != BMI160_OK) LOG_WRN("start: fifo flush: %d", rslt); + return rslt; +} + +int BMX160::stop() +{ + /* Park accel and gyro in suspend to drop power. */ + dev.accel_cfg.power = BMI160_ACCEL_SUSPEND_MODE; + dev.gyro_cfg.power = BMI160_GYRO_SUSPEND_MODE; + return bmi160_set_sens_conf(&dev); +} + +int BMX160::read(BMX160Sample *out, int max_samples) +{ + if (out == nullptr || max_samples <= 0) return 0; + + /* Read whatever is in the FIFO — timer-polled at the batch rate. */ + fifo_frame.length = BMX160_FIFO_RAW_DATA_BUFFER_SIZE; + int8_t rslt = bmi160_get_fifo_data(&dev); + if (rslt != BMI160_OK) { + LOG_WRN("bmi160_get_fifo_data: %d", rslt); + return 0; + } + + uint8_t accel_len = BMX160_FIFO_MAX_FRAMES; + uint8_t gyro_len = BMX160_FIFO_MAX_FRAMES; + (void)bmi160_extract_accel(accel_frames, &accel_len, &dev); + (void)bmi160_extract_gyro(gyro_frames, &gyro_len, &dev); + + /* Accel/gyro frame counts should match in A+G headered mode; if + * they diverge (shouldn't in steady state, but can at startup or + * overflow), use the smaller count so we never emit a sample with + * mismatched halves. */ + int n = MIN((int)accel_len, (int)gyro_len); + if (n > max_samples) n = max_samples; + + float mag[3] = { 0, 0, 0 }; +#ifdef CONFIG_IMU_ENABLE_MAGNETOMETER + if (n > 0) { + (void)read_mag_latched(mag); + } +#endif + + for (int i = 0; i < n; i++) { + out[i].accel[0] = (float)accel_frames[i].x * _accel_lsb_to_ms2; + out[i].accel[1] = (float)accel_frames[i].y * _accel_lsb_to_ms2; + out[i].accel[2] = (float)accel_frames[i].z * _accel_lsb_to_ms2; + out[i].gyro[0] = (float)gyro_frames[i].x * _gyro_lsb_to_dps; + out[i].gyro[1] = (float)gyro_frames[i].y * _gyro_lsb_to_dps; + out[i].gyro[2] = (float)gyro_frames[i].z * _gyro_lsb_to_dps; + out[i].mag[0] = mag[0]; + out[i].mag[1] = mag[1]; + out[i].mag[2] = mag[2]; + } + return n; +} diff --git a/src/SensorManager/BMX160/BMX160_Sensor.h b/src/SensorManager/BMX160/BMX160_Sensor.h new file mode 100644 index 00000000..36d93ac1 --- /dev/null +++ b/src/SensorManager/BMX160/BMX160_Sensor.h @@ -0,0 +1,39 @@ +#ifndef _BMX160_SENSOR_H +#define _BMX160_SENSOR_H + +#include +#include "bmi160.h" +#include + +#define BMX160_FIFO_RAW_DATA_BUFFER_SIZE UINT16_C(1024) +#define BMX160_FIFO_MAX_FRAMES UINT16_C(128) + +struct BMX160Sample { + float accel[3]; + float gyro[3]; + float mag[3]; +}; + +class BMX160 { +public: + int init(uint8_t accel_odr_reg, uint8_t gyro_odr_reg, uint16_t fifo_watermark_bytes); + int start(); + int stop(); + int read(BMX160Sample *out, int max_samples); + +private: + struct bmi160_dev dev; + struct bmi160_fifo_frame fifo_frame; + uint8_t fifo_buf[BMX160_FIFO_RAW_DATA_BUFFER_SIZE] = { 0 }; + + struct bmi160_sensor_data accel_frames[BMX160_FIFO_MAX_FRAMES]; + struct bmi160_sensor_data gyro_frames[BMX160_FIFO_MAX_FRAMES]; + + float _accel_lsb_to_ms2; + float _gyro_lsb_to_dps; + + int8_t configure_magnetometer(); + int read_mag_latched(float out_mag[3]); +}; + +#endif diff --git a/src/SensorManager/BMX160/CMakeLists.txt b/src/SensorManager/BMX160/CMakeLists.txt index d287a1d4..ea1b8e71 100644 --- a/src/SensorManager/BMX160/CMakeLists.txt +++ b/src/SensorManager/BMX160/CMakeLists.txt @@ -5,5 +5,6 @@ # target_sources(app PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/DFRobot_BMX160.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bmi160.c + ${CMAKE_CURRENT_SOURCE_DIR}/BMX160_Sensor.cpp ) diff --git a/src/SensorManager/BMX160/DFRobot_BMX160.cpp b/src/SensorManager/BMX160/DFRobot_BMX160.cpp deleted file mode 100644 index 22234e83..00000000 --- a/src/SensorManager/BMX160/DFRobot_BMX160.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/*! - * @file DFRobot_BMX160.cpp - * @brief define DFRobot_BMX160 class infrastructure, the implementation of basic methods - * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) - * @license The MIT License (MIT) - * @author [luoyufeng] (yufeng.luo@dfrobot.com) - * @maintainer [Fary](feng.yang@dfrobot.com) - * @version V1.0 - * @date 2021-10-20 - * @url https://github.com/DFRobot/DFRobot_BMX160 - */ -#include "DFRobot_BMX160.h" - -#include -LOG_MODULE_REGISTER(BMX160, CONFIG_MAIN_LOG_LEVEL); - -#define delay(ms) k_msleep(ms) -#define malloc(a) k_malloc(a) - -DFRobot_BMX160::DFRobot_BMX160(TWIM *i2c) : _i2c(i2c) -{ - Obmx160 = (sBmx160Dev_t *)malloc(sizeof(sBmx160Dev_t)); - Oaccel = ( sBmx160SensorData_t*)malloc(sizeof( sBmx160SensorData_t)); - Ogyro = ( sBmx160SensorData_t*)malloc(sizeof( sBmx160SensorData_t)); - Omagn = ( sBmx160SensorData_t*)malloc(sizeof( sBmx160SensorData_t)); -} - -const uint8_t int_mask_lookup_table[13] = { - BMX160_INT1_SLOPE_MASK, - BMX160_INT1_SLOPE_MASK, - BMX160_INT2_LOW_STEP_DETECT_MASK, - BMX160_INT1_DOUBLE_TAP_MASK, - BMX160_INT1_SINGLE_TAP_MASK, - BMX160_INT1_ORIENT_MASK, - BMX160_INT1_FLAT_MASK, - BMX160_INT1_HIGH_G_MASK, - BMX160_INT1_LOW_G_MASK, - BMX160_INT1_NO_MOTION_MASK, - BMX160_INT2_DATA_READY_MASK, - BMX160_INT2_FIFO_FULL_MASK, - BMX160_INT2_FIFO_WM_MASK -}; - -bool DFRobot_BMX160::begin() -{ - _i2c->begin(); - - if (scan() == true){ - softReset(); - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x11); - delay(50); - /* Set gyro to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x15); - delay(100); - /* Set mag to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x19); - delay(10); - setMagnConf(); - return true; - } else return false; -} - -void DFRobot_BMX160::setLowPower(){ - softReset(); - delay(100); - setMagnConf(); - delay(100); - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x12); - delay(100); - /* Set gyro to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x17); - delay(100); - /* Set mag to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x1B); - delay(100); -} - -void DFRobot_BMX160::wakeUp(){ - softReset(); - delay(100); - setMagnConf(); - delay(100); - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x11); - delay(100); - /* Set gyro to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x15); - delay(100); - /* Set mag to normal mode */ - writeBmxReg(BMX160_COMMAND_REG_ADDR, 0x19); - delay(100); -} - -bool DFRobot_BMX160::softReset() -{ - int8_t rslt=BMX160_OK; - if (Obmx160 == NULL){ - rslt = BMX160_E_NULL_PTR; - } - rslt = _softReset(Obmx160); - if (rslt == 0) - return true; - else - return false; -} - -int8_t DFRobot_BMX160:: _softReset(sBmx160Dev_t *dev) -{ - int8_t rslt=BMX160_OK; - uint8_t data = BMX160_SOFT_RESET_CMD; - if (dev==NULL){ - rslt = BMX160_E_NULL_PTR; - } - writeBmxReg(BMX160_COMMAND_REG_ADDR, data); - delay(BMX160_SOFT_RESET_DELAY_MS); - if (rslt == BMX160_OK){ - DFRobot_BMX160::defaultParamSettg(dev); - } - return rslt; -} - -void DFRobot_BMX160::defaultParamSettg(sBmx160Dev_t *dev) -{ - // Initializing accel and gyro params with - dev->gyroCfg.bw = BMX160_GYRO_BW_NORMAL_MODE; - dev->gyroCfg.odr = BMX160_GYRO_ODR_100HZ; - dev->gyroCfg.power = BMX160_GYRO_SUSPEND_MODE; - dev->gyroCfg.range = BMX160_GYRO_RANGE_2000_DPS; - - dev->accelCfg.bw = BMX160_ACCEL_BW_NORMAL_AVG4; - dev->accelCfg.odr = BMX160_ACCEL_ODR_100HZ; - dev->accelCfg.power = BMX160_ACCEL_SUSPEND_MODE; - dev->accelCfg.range = BMX160_ACCEL_RANGE_2G; - - dev->magnCfg.odr = BMX160_MAGN_ODR_100HZ; - dev->magnCfg.power = BMX160_MAGN_SUSPEND_MODE; - - dev->prevMagnCfg = dev->magnCfg; - dev->prevGyroCfg = dev->gyroCfg; - dev->prevAccelCfg = dev->accelCfg; -} - -void DFRobot_BMX160::setMagnConf() -{ - // puts magnetometer into mag_if setup mode - writeBmxReg(BMX160_MAGN_IF_0_ADDR, 0x80); - delay(50); - // Sleep mode - writeBmxReg(BMX160_MAGN_IF_3_ADDR, 0x01); - writeBmxReg(BMX160_MAGN_IF_2_ADDR, 0x4B); - // REPXY regular preset - writeBmxReg(BMX160_MAGN_IF_3_ADDR, 0x04); - writeBmxReg(BMX160_MAGN_IF_2_ADDR, 0x51); - // REPZ regular preset - writeBmxReg(BMX160_MAGN_IF_3_ADDR, 0x0E); - writeBmxReg(BMX160_MAGN_IF_2_ADDR, 0x52); - // Prepare MAG_IF[1-3] for mag_if data mode - writeBmxReg(BMX160_MAGN_IF_3_ADDR, 0x02); - writeBmxReg(BMX160_MAGN_IF_2_ADDR, 0x4C); - writeBmxReg(BMX160_MAGN_IF_1_ADDR, 0x42); - // sets the sampling rate t0 100Hz - writeBmxReg(BMX160_MAGN_CONFIG_ADDR, 0x08); - // puts magnetometer into mag_if data mode sets data length of read burst operation to 8 bytes - writeBmxReg(BMX160_MAGN_IF_0_ADDR, 0x03); - delay(50); -} - -void DFRobot_BMX160::setGyroRange(eGyroRange_t bits){ - switch (bits){ - case eGyroRange_125DPS: - gyroRange = BMX160_GYRO_SENSITIVITY_125DPS; - break; - case eGyroRange_250DPS: - gyroRange = BMX160_GYRO_SENSITIVITY_250DPS; - break; - case eGyroRange_500DPS: - gyroRange = BMX160_GYRO_SENSITIVITY_500DPS; - break; - case eGyroRange_1000DPS: - gyroRange = BMX160_GYRO_SENSITIVITY_1000DPS; - break; - case eGyroRange_2000DPS: - gyroRange = BMX160_GYRO_SENSITIVITY_2000DPS; - break; - default: - gyroRange = BMX160_GYRO_SENSITIVITY_250DPS; - break; - } -} - -void DFRobot_BMX160::setAccelRange(eAccelRange_t bits){ - switch (bits){ - case eAccelRange_2G: - accelRange = BMX160_ACCEL_MG_LSB_2G * EARTH_ACC; - break; - case eAccelRange_4G: - accelRange = BMX160_ACCEL_MG_LSB_4G * EARTH_ACC; - break; - case eAccelRange_8G: - accelRange = BMX160_ACCEL_MG_LSB_8G * EARTH_ACC; - break; - case eAccelRange_16G: - accelRange = BMX160_ACCEL_MG_LSB_16G * EARTH_ACC; - break; - default: - accelRange = BMX160_ACCEL_MG_LSB_2G * EARTH_ACC; - break; - } - - writeBmxReg(BMX160_ACCEL_RANGE_ADDR, bits); -} - -void DFRobot_BMX160::setMagnODR(uint8_t val){ - writeBmxReg(BMX160_MAGN_CONFIG_ADDR, BMX160_MAGN_ODR_MASK & val); -} - -void DFRobot_BMX160::setGyroODR(uint8_t val){ - writeBmxReg(BMX160_GYRO_CONFIG_ADDR, BMX160_GYRO_ODR_MASK & val); -} - -void DFRobot_BMX160::setAccelODR(uint8_t val){ - writeBmxReg(BMX160_ACCEL_CONFIG_ADDR, BMX160_ACCEL_ODR_MASK & val); -} - -void DFRobot_BMX160::getAllData(sBmx160SensorData_t *magn, sBmx160SensorData_t *gyro, sBmx160SensorData_t *accel){ - - uint8_t data[23] = {0}; - int16_t x=0,y=0,z=0; - // put your main code here, to run repeatedly: - readReg(BMX160_MAG_DATA_ADDR, data, 23); - if(magn){ - x = (int16_t) (((uint16_t)data[1] << 8) | data[0]); - y = (int16_t) (((uint16_t)data[3] << 8) | data[2]); - z = (int16_t) (((uint16_t)data[5] << 8) | data[4]); - magn->x = x * BMX160_MAGN_UT_LSB; - magn->y = y * BMX160_MAGN_UT_LSB; - magn->z = z * BMX160_MAGN_UT_LSB; - } - if(gyro){ - x = (int16_t) (((uint16_t)data[9] << 8) | data[8]); - y = (int16_t) (((uint16_t)data[11] << 8) | data[10]); - z = (int16_t) (((uint16_t)data[13] << 8) | data[12]); - gyro->x = x * gyroRange; - gyro->y = y * gyroRange; - gyro->z = z * gyroRange; - } - if(accel){ - x = (int16_t) (((uint16_t)data[15] << 8) | data[14]); - y = (int16_t) (((uint16_t)data[17] << 8) | data[16]); - z = (int16_t) (((uint16_t)data[19] << 8) | data[18]); - accel->x = x * accelRange; - accel->y = y * accelRange; - accel->z = z * accelRange; - } -} - -void DFRobot_BMX160::writeBmxReg(uint8_t reg, uint8_t value) -{ - uint8_t buffer[1] = {value}; - writeReg(reg, buffer, 1); -} - -void DFRobot_BMX160::writeReg(uint8_t reg, uint8_t *pBuf, uint16_t len) -{ - _i2c->aquire(); - - int ret = i2c_burst_write(_i2c->master, _addr, reg, pBuf, len); - if (ret) LOG_WRN("I2C write failed: %d", ret); - - _i2c->release(); -} - -void DFRobot_BMX160::readReg(uint8_t reg, uint8_t *pBuf, uint16_t len) -{ - _i2c->aquire(); - - int ret = i2c_burst_read(_i2c->master, _addr, reg, pBuf, len); - if (ret) LOG_WRN("I2C read failed: %d", ret); - - _i2c->release(); -} - -bool DFRobot_BMX160::scan() -{ - _i2c->aquire(); - - uint8_t dummy = 0; - int ret = i2c_write(_i2c->master, &dummy, 0, _addr); - - _i2c->release(); - - return (ret == 0); -} diff --git a/src/SensorManager/BMX160/DFRobot_BMX160.h b/src/SensorManager/BMX160/DFRobot_BMX160.h deleted file mode 100644 index 3e08f7ef..00000000 --- a/src/SensorManager/BMX160/DFRobot_BMX160.h +++ /dev/null @@ -1,1121 +0,0 @@ -/*! - * @file DFRobot_BMX160.h - * @brief DFRobot_BMX160 class infrastructure - * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) - * @license The MIT License (MIT) - * @author [luoyufeng] (yufeng.luo@dfrobot.com) - * @maintainer [Fary](feng.yang@dfrobot.com) - * @version V1.0 - * @date 2021-10-20 - * @url https://github.com/DFRobot/DFRobot_BMX160 - */ -//#include -#include - -#define LITTLE_ENDIAN 1 - -/** Mask definitions */ -#define BMX160_MAGN_ODR_MASK 0x0F -#define BMX160_ACCEL_BW_MASK 0x70 -#define BMX160_ACCEL_ODR_MASK 0x0F -#define BMX160_ACCEL_UNDERSAMPLING_MASK 0x80 -#define BMX160_ACCEL_RANGE_MASK 0x0F -#define BMX160_GYRO_BW_MASK 0x30 -#define BMX160_GYRO_ODR_MASK 0x0F -#define BMX160_GYRO_RANGE_MSK 0x07 - -/** Mask definitions for INT_EN registers */ -#define BMX160_ANY_MOTION_X_INT_EN_MASK 0x01 -#define BMX160_HIGH_G_X_INT_EN_MASK 0x01 -#define BMX160_NO_MOTION_X_INT_EN_MASK 0x01 -#define BMX160_ANY_MOTION_Y_INT_EN_MASK 0x02 -#define BMX160_HIGH_G_Y_INT_EN_MASK 0x02 -#define BMX160_NO_MOTION_Y_INT_EN_MASK 0x02 -#define BMX160_ANY_MOTION_Z_INT_EN_MASK 0x04 -#define BMX160_HIGH_G_Z_INT_EN_MASK 0x04 -#define BMX160_NO_MOTION_Z_INT_EN_MASK 0x04 -#define BMX160_SIG_MOTION_INT_EN_MASK 0x07 -#define BMX160_ANY_MOTION_ALL_INT_EN_MASK 0x07 -#define BMX160_STEP_DETECT_INT_EN_MASK 0x08 -#define BMX160_DOUBLE_TAP_INT_EN_MASK 0x10 -#define BMX160_SINGLE_TAP_INT_EN_MASK 0x20 -#define BMX160_FIFO_FULL_INT_EN_MASK 0x20 -#define BMX160_ORIENT_INT_EN_MASK 0x40 -#define BMX160_FIFO_WATERMARK_INT_EN_MASK 0x40 -#define BMX160_LOW_G_INT_EN_MASK 0x08 -#define BMX160_STEP_DETECT_EN_MASK 0x08 -#define BMX160_FLAT_INT_EN_MASK 0x80 -#define BMX160_DATA_RDY_INT_EN_MASK 0x10 - -/** Mask definitions for INT_OUT_CTRL register */ -#define BMX160_INT1_EDGE_CTRL_MASK 0x01 -#define BMX160_INT1_OUTPUT_MODE_MASK 0x04 -#define BMX160_INT1_OUTPUT_TYPE_MASK 0x02 -#define BMX160_INT1_OUTPUT_EN_MASK 0x08 -#define BMX160_INT2_EDGE_CTRL_MASK 0x10 -#define BMX160_INT2_OUTPUT_MODE_MASK 0x40 -#define BMX160_INT2_OUTPUT_TYPE_MASK 0x20 -#define BMX160_INT2_OUTPUT_EN_MASK 0x80 - -/** Mask definitions for INT_LATCH register */ -#define BMX160_INT1_INPUT_EN_MASK 0x10 -#define BMX160_INT2_INPUT_EN_MASK 0x20 -#define BMX160_INT_LATCH_MASK 0x0F - -/** Mask definitions for INT_MAP register */ -#define BMX160_INT1_LOW_G_MASK 0x01 -#define BMX160_INT1_HIGH_G_MASK 0x02 -#define BMX160_INT1_SLOPE_MASK 0x04 -#define BMX160_INT1_NO_MOTION_MASK 0x08 -#define BMX160_INT1_DOUBLE_TAP_MASK 0x10 -#define BMX160_INT1_SINGLE_TAP_MASK 0x20 -#define BMX160_INT1_FIFO_FULL_MASK 0x20 -#define BMX160_INT1_FIFO_WM_MASK 0x40 -#define BMX160_INT1_ORIENT_MASK 0x40 -#define BMX160_INT1_FLAT_MASK 0x80 -#define BMX160_INT1_DATA_READY_MASK 0x80 -#define BMX160_INT2_LOW_G_MASK 0x01 -#define BMX160_INT1_LOW_STEP_DETECT_MASK 0x01 -#define BMX160_INT2_LOW_STEP_DETECT_MASK 0x01 -#define BMX160_INT2_HIGH_G_MASK 0x02 -#define BMX160_INT2_FIFO_FULL_MASK 0x02 -#define BMX160_INT2_FIFO_WM_MASK 0x04 -#define BMX160_INT2_SLOPE_MASK 0x04 -#define BMX160_INT2_DATA_READY_MASK 0x08 -#define BMX160_INT2_NO_MOTION_MASK 0x08 -#define BMX160_INT2_DOUBLE_TAP_MASK 0x10 -#define BMX160_INT2_SINGLE_TAP_MASK 0x20 -#define BMX160_INT2_ORIENT_MASK 0x40 -#define BMX160_INT2_FLAT_MASK 0x80 - -/** Mask definitions for INT_DATA register */ -#define BMX160_TAP_SRC_INT_MASK 0x08 -#define BMX160_LOW_HIGH_SRC_INT_MASK 0x80 -#define BMX160_MOTION_SRC_INT_MASK 0x80 - -/** Mask definitions for INT_MOTION register */ -#define BMX160_SLOPE_INT_DUR_MASK 0x03 -#define BMX160_NO_MOTION_INT_DUR_MASK 0xFC -#define BMX160_NO_MOTION_SEL_BIT_MASK 0x01 - -/** Mask definitions for INT_TAP register */ -#define BMX160_TAP_DUR_MASK 0x07 -#define BMX160_TAP_SHOCK_DUR_MASK 0x40 -#define BMX160_TAP_QUIET_DUR_MASK 0x80 -#define BMX160_TAP_THRES_MASK 0x1F - -/** Mask definitions for INT_FLAT register */ -#define BMX160_FLAT_THRES_MASK 0x3F -#define BMX160_FLAT_HOLD_TIME_MASK 0x30 -#define BMX160_FLAT_HYST_MASK 0x07 - -/** Mask definitions for INT_LOWHIGH register */ -#define BMX160_LOW_G_HYST_MASK 0x03 -#define BMX160_LOW_G_LOW_MODE_MASK 0x04 -#define BMX160_HIGH_G_HYST_MASK 0xC0 - -/** Mask definitions for INT_SIG_MOTION register */ -#define BMX160_SIG_MOTION_SEL_MASK 0x02 -#define BMX160_SIG_MOTION_SKIP_MASK 0x0C -#define BMX160_SIG_MOTION_PROOF_MASK 0x30 - -/** Mask definitions for INT_ORIENT register */ -#define BMX160_ORIENT_MODE_MASK 0x03 -#define BMX160_ORIENT_BLOCK_MASK 0x0C -#define BMX160_ORIENT_HYST_MASK 0xF0 -#define BMX160_ORIENT_THETA_MASK 0x3F -#define BMX160_ORIENT_UD_ENABLE 0x40 -#define BMX160_AXES_EN_MASK 0x80 - -/** Mask definitions for FIFO_CONFIG register */ -#define BMX160_FIFO_GYRO 0x80 -#define BMX160_FIFO_ACCEL 0x40 -#define BMX160_FIFO_MAGN 0x20 -#define BMX160_FIFO_TAG_INT1 0x08 -#define BMX160_FIFO_TAG_INT2 0x04 -#define BMX160_FIFO_TIME 0x02 -#define BMX160_FIFO_HEADER 0x10 -#define BMX160_FIFO_CONFIG_1_MASK 0xFE - - -/** Mask definitions for STEP_CONF register */ -#define BMX160_STEP_COUNT_EN_BIT_MASK 0x08 -#define BMX160_STEP_DETECT_MIN_THRES_MASK 0x18 -#define BMX160_STEP_DETECT_STEPTIME_MIN_MASK 0x07 -#define BMX160_STEP_MIN_BUF_MASK 0x07 - -/** Mask definition for FIFO Header Data Tag */ -#define BMX160_FIFO_TAG_INTR_MASK 0xFC - -/** Fifo byte counter mask definitions */ -#define BMX160_FIFO_BYTE_COUNTER_MASK 0x07 - -/** Enable/disable bit value */ -#define BMX160_ENABLE 0x01 -#define BMX160_DISABLE 0x00 - -/** Latch Duration */ -#define BMX160_LATCH_DUR_NONE 0x00 -#define BMX160_LATCH_DUR_312_5_MICRO_SEC 0x01 -#define BMX160_LATCH_DUR_625_MICRO_SEC 0x02 -#define BMX160_LATCH_DUR_1_25_MILLI_SEC 0x03 -#define BMX160_LATCH_DUR_2_5_MILLI_SEC 0x04 -#define BMX160_LATCH_DUR_5_MILLI_SEC 0x05 -#define BMX160_LATCH_DUR_10_MILLI_SEC 0x06 -#define BMX160_LATCH_DUR_20_MILLI_SEC 0x07 -#define BMX160_LATCH_DUR_40_MILLI_SEC 0x08 -#define BMX160_LATCH_DUR_80_MILLI_SEC 0x09 -#define BMX160_LATCH_DUR_160_MILLI_SEC 0x0A -#define BMX160_LATCH_DUR_320_MILLI_SEC 0x0B -#define BMX160_LATCH_DUR_640_MILLI_SEC 0x0C -#define BMX160_LATCH_DUR_1_28_SEC 0x0D -#define BMX160_LATCH_DUR_2_56_SEC 0x0E -#define BMX160_LATCHED 0x0F - -/** bmx160 Register map */ -#define BMX160_CHIP_ID_ADDR 0x00 -#define BMX160_ERROR_REG_ADDR 0x02 -#define BMX160_MAG_DATA_ADDR 0x04 -#define BMX160_GYRO_DATA_ADDR 0x0C -#define BMX160_ACCEL_DATA_ADDR 0x12 -#define BMX160_STATUS_ADDR 0x1B -#define BMX160_INT_STATUS_ADDR 0x1C -#define BMX160_FIFO_LENGTH_ADDR 0x22 -#define BMX160_FIFO_DATA_ADDR 0x24 -#define BMX160_ACCEL_CONFIG_ADDR 0x40 -#define BMX160_ACCEL_RANGE_ADDR 0x41 -#define BMX160_GYRO_CONFIG_ADDR 0x42 -#define BMX160_GYRO_RANGE_ADDR 0x43 -#define BMX160_MAGN_CONFIG_ADDR 0x44 -#define BMX160_FIFO_DOWN_ADDR 0x45 -#define BMX160_FIFO_CONFIG_0_ADDR 0x46 -#define BMX160_FIFO_CONFIG_1_ADDR 0x47 -#define BMX160_MAGN_RANGE_ADDR 0x4B -#define BMX160_MAGN_IF_0_ADDR 0x4C -#define BMX160_MAGN_IF_1_ADDR 0x4D -#define BMX160_MAGN_IF_2_ADDR 0x4E -#define BMX160_MAGN_IF_3_ADDR 0x4F -#define BMX160_INT_ENABLE_0_ADDR 0x50 -#define BMX160_INT_ENABLE_1_ADDR 0x51 -#define BMX160_INT_ENABLE_2_ADDR 0x52 -#define BMX160_INT_OUT_CTRL_ADDR 0x53 -#define BMX160_INT_LATCH_ADDR 0x54 -#define BMX160_INT_MAP_0_ADDR 0x55 -#define BMX160_INT_MAP_1_ADDR 0x56 -#define BMX160_INT_MAP_2_ADDR 0x57 -#define BMX160_INT_DATA_0_ADDR 0x58 -#define BMX160_INT_DATA_1_ADDR 0x59 -#define BMX160_INT_LOWHIGH_0_ADDR 0x5A -#define BMX160_INT_LOWHIGH_1_ADDR 0x5B -#define BMX160_INT_LOWHIGH_2_ADDR 0x5C -#define BMX160_INT_LOWHIGH_3_ADDR 0x5D -#define BMX160_INT_LOWHIGH_4_ADDR 0x5E -#define BMX160_INT_MOTION_0_ADDR 0x5F -#define BMX160_INT_MOTION_1_ADDR 0x60 -#define BMX160_INT_MOTION_2_ADDR 0x61 -#define BMX160_INT_MOTION_3_ADDR 0x62 -#define BMX160_INT_TAP_0_ADDR 0x63 -#define BMX160_INT_TAP_1_ADDR 0x64 -#define BMX160_INT_ORIENT_0_ADDR 0x65 -#define BMX160_INT_ORIENT_1_ADDR 0x66 -#define BMX160_INT_FLAT_0_ADDR 0x67 -#define BMX160_INT_FLAT_1_ADDR 0x68 -#define BMX160_FOC_CONF_ADDR 0x69 -#define BMX160_CONF_ADDR 0x6A - -#define BMX160_IF_CONF_ADDR 0x6B -#define BMX160_SELF_TEST_ADDR 0x6D -#define BMX160_OFFSET_ADDR 0x71 -#define BMX160_OFFSET_CONF_ADDR 0x77 -#define BMX160_INT_STEP_CNT_0_ADDR 0x78 -#define BMX160_INT_STEP_CONFIG_0_ADDR 0x7A -#define BMX160_INT_STEP_CONFIG_1_ADDR 0x7B -#define BMX160_COMMAND_REG_ADDR 0x7E -#define BMX160_SPI_COMM_TEST_ADDR 0x7F -#define BMX160_INTL_PULLUP_CONF_ADDR 0x85 - -/** Error code definitions */ -#define BMX160_OK 0 -#define BMX160_E_NULL_PTR -1 -#define BMX160_E_COM_FAIL -2 -#define BMX160_E_DEV_NOT_FOUND -3 -#define BMX160_E_OUT_OF_RANGE -4 -#define BMX160_E_INVALID_INPUT -5 -#define BMX160_E_ACCEL_ODR_BW_INVALID -6 -#define BMX160_E_GYRO_ODR_BW_INVALID -7 -#define BMX160_E_LWP_PRE_FLTR_INT_INVALID -8 -#define BMX160_E_LWP_PRE_FLTR_INVALID -9 -#define BMX160_E_MAGN_NOT_FOUND -10 -#define BMX160_FOC_FAILURE -11 -#define BMX160_ERR_CHOOSE -12 - -/**\name API warning codes */ -#define BMX160_W_GYRO_SELF_TEST_FAIL (1) -#define BMX160_W_ACCEl_SELF_TEST_FAIL (2) - -/** bmx160 unique chip identifier */ -#define BMX160_CHIP_ID 0xD8 - -/** Soft reset command */ -#define BMX160_SOFT_RESET_CMD 0xb6 -#define BMX160_SOFT_RESET_DELAY_MS 15 -/** Start FOC command */ -#define BMX160_START_FOC_CMD 0x03 -/** NVM backup enabling command */ -#define BMX160_NVM_BACKUP_EN 0xA0 - -/* Delay in ms settings */ -#define BMX160_ACCEL_DELAY_MS 5 -#define BMX160_GYRO_DELAY_MS 81 -#define BMX160_ONE_MS_DELAY 1 -#define BMX160_MAGN_COM_DELAY 10 -#define BMX160_GYRO_SELF_TEST_DELAY 20 -#define BMX160_ACCEL_SELF_TEST_DELAY 50 - -/** Self test configurations */ -#define BMX160_ACCEL_SELF_TEST_CONFIG 0x2C -#define BMX160_ACCEL_SELF_TEST_POSITIVE_EN 0x0D -#define BMX160_ACCEL_SELF_TEST_NEGATIVE_EN 0x09 -#define BMX160_ACCEL_SELF_TEST_LIMIT 8192 - -/** Power mode settings */ -/* Accel power mode */ -#define BMX160_ACCEL_NORMAL_MODE 0x11 -#define BMX160_ACCEL_LOWPOWER_MODE 0x12 -#define BMX160_ACCEL_SUSPEND_MODE 0x10 - -/* Gyro power mode */ -#define BMX160_GYRO_SUSPEND_MODE 0x14 -#define BMX160_GYRO_NORMAL_MODE 0x15 -#define BMX160_GYRO_FASTSTARTUP_MODE 0x17 - -/* Magn power mode */ -#define BMX160_MAGN_SUSPEND_MODE 0x18 -#define BMX160_MAGN_NORMAL_MODE 0x19 -#define BMX160_MAGN_LOWPOWER_MODE 0x1A - -/** Range settings */ -/* Accel Range */ -#define BMX160_ACCEL_RANGE_2G 0x03 -#define BMX160_ACCEL_RANGE_4G 0x05 -#define BMX160_ACCEL_RANGE_8G 0x08 -#define BMX160_ACCEL_RANGE_16G 0x0C - -/* Gyro Range */ -#define BMX160_GYRO_RANGE_2000_DPS 0x00 -#define BMX160_GYRO_RANGE_1000_DPS 0x01 -#define BMX160_GYRO_RANGE_500_DPS 0x02 -#define BMX160_GYRO_RANGE_250_DPS 0x03 -#define BMX160_GYRO_RANGE_125_DPS 0x04 - - -#define BMX160_ACCEL_MG_LSB_2G 0.000061035F ///< Macro for mg per LSB at +/- 2g sensitivity (1 LSB = 0.000061035mg) */ -#define BMX160_ACCEL_MG_LSB_4G 0.000122070F ///< Macro for mg per LSB at +/- 4g sensitivity (1 LSB = 0.000122070mg) */ -#define BMX160_ACCEL_MG_LSB_8G 0.000244141F ///< Macro for mg per LSB at +/- 8g sensitivity (1 LSB = 0.000244141mg) */ -#define BMX160_ACCEL_MG_LSB_16G 0.000488281F ///< Macro for mg per LSB at +/- 16g sensitivity (1 LSB = 0.000488281mg) */ - -#define BMX160_GYRO_SENSITIVITY_125DPS 0.0038110F ///< Gyroscope sensitivity at 125dps */ -#define BMX160_GYRO_SENSITIVITY_250DPS 0.0076220F ///< Gyroscope sensitivity at 250dps */ -#define BMX160_GYRO_SENSITIVITY_500DPS 0.0152439F ///< Gyroscope sensitivity at 500dps */ -#define BMX160_GYRO_SENSITIVITY_1000DPS 0.0304878F ///< Gyroscope sensitivity at 1000dps */ -#define BMX160_GYRO_SENSITIVITY_2000DPS 0.0609756F ///< Gyroscope sensitivity at 2000dps */ - -/** Bandwidth settings */ -/* Accel Bandwidth */ -#define BMX160_ACCEL_BW_OSR4_AVG1 0x00 -#define BMX160_ACCEL_BW_OSR2_AVG2 0x01 -#define BMX160_ACCEL_BW_NORMAL_AVG4 0x02 -#define BMX160_ACCEL_BW_RES_AVG8 0x03 -#define BMX160_ACCEL_BW_RES_AVG16 0x04 -#define BMX160_ACCEL_BW_RES_AVG32 0x05 -#define BMX160_ACCEL_BW_RES_AVG64 0x06 -#define BMX160_ACCEL_BW_RES_AVG128 0x07 - -#define BMX160_GYRO_BW_OSR4_MODE 0x00 -#define BMX160_GYRO_BW_OSR2_MODE 0x01 -#define BMX160_GYRO_BW_NORMAL_MODE 0x02 - -#define BMX160_MAGN_UT_LSB (0.3F) ///< Macro for micro tesla (uT) per LSB (1 LSB = 0.1uT) */ -/* Output Data Rate settings */ -/* Accel Output data rate */ -#define BMX160_ACCEL_ODR_RESERVED 0x00 -#define BMX160_ACCEL_ODR_0_78HZ 0x01 -#define BMX160_ACCEL_ODR_1_56HZ 0x02 -#define BMX160_ACCEL_ODR_3_12HZ 0x03 -#define BMX160_ACCEL_ODR_6_25HZ 0x04 -#define BMX160_ACCEL_ODR_12_5HZ 0x05 -#define BMX160_ACCEL_ODR_25HZ 0x06 -#define BMX160_ACCEL_ODR_50HZ 0x07 -#define BMX160_ACCEL_ODR_100HZ 0x08 -#define BMX160_ACCEL_ODR_200HZ 0x09 -#define BMX160_ACCEL_ODR_400HZ 0x0A -#define BMX160_ACCEL_ODR_800HZ 0x0B -#define BMX160_ACCEL_ODR_1600HZ 0x0C -#define BMX160_ACCEL_ODR_RESERVED0 0x0D -#define BMX160_ACCEL_ODR_RESERVED1 0x0E -#define BMX160_ACCEL_ODR_RESERVED2 0x0F - -/* Gyro Output data rate */ -#define BMX160_GYRO_ODR_RESERVED 0x00 -#define BMX160_GYRO_ODR_25HZ 0x06 -#define BMX160_GYRO_ODR_50HZ 0x07 -#define BMX160_GYRO_ODR_100HZ 0x08 -#define BMX160_GYRO_ODR_200HZ 0x09 -#define BMX160_GYRO_ODR_400HZ 0x0A -#define BMX160_GYRO_ODR_800HZ 0x0B -#define BMX160_GYRO_ODR_1600HZ 0x0C -#define BMX160_GYRO_ODR_3200HZ 0x0D - -/* Magnetometer sensor Output data rate */ -#define BMX160_MAGN_ODR_RESERVED 0x00 -#define BMX160_MAGN_ODR_0_78HZ 0x01 -#define BMX160_MAGN_ODR_1_56HZ 0x02 -#define BMX160_MAGN_ODR_3_12HZ 0x03 -#define BMX160_MAGN_ODR_6_25HZ 0x04 -#define BMX160_MAGN_ODR_12_5HZ 0x05 -#define BMX160_MAGN_ODR_25HZ 0x06 -#define BMX160_MAGN_ODR_50HZ 0x07 -#define BMX160_MAGN_ODR_100HZ 0x08 -#define BMX160_MAGN_ODR_200HZ 0x09 -#define BMX160_MAGN_ODR_400HZ 0x0A -#define BMX160_MAGN_ODR_800HZ 0x0B - -/* Maximum limits definition */ -#define BMX160_MAGN_ODR_MAX 14 -#define BMX160_MAGN_BW_MAX 2 -#define BMX160_MAGN_RANGE_MAX 8 -#define BMX160_GYRO_ODR_MAX 13 -#define BMX160_GYRO_BW_MAX 2 -#define BMX160_GYRO_RANGE_MAX 4 -#define BMX160_ACCEL_ODR_MAX 15 -#define BMX160_ACCEL_BW_MAX 2 -#define BMX160_ACCEL_RANGE_MAX 12 - - - -/** FIFO_CONFIG Definitions */ -#define BMX160_FIFO_TIME_ENABLE 0x02 -#define BMX160_FIFO_TAG_INT2_ENABLE 0x04 -#define BMX160_FIFO_TAG_INT1_ENABLE 0x08 -#define BMX160_FIFO_HEAD_ENABLE 0x10 -#define BMX160_FIFO_M_ENABLE 0x20 -#define BMX160_FIFO_A_ENABLE 0x40 -#define BMX160_FIFO_M_A_ENABLE 0x60 -#define BMX160_FIFO_G_ENABLE 0x80 -#define BMX160_FIFO_M_G_ENABLE 0xA0 -#define BMX160_FIFO_G_A_ENABLE 0xC0 -#define BMX160_FIFO_M_G_A_ENABLE 0xE0 - - -/* Accel, gyro and magn. sensor length and also their combined - * length definitions in FIFO */ -#define BMX160_FIFO_G_LENGTH 6 -#define BMX160_FIFO_A_LENGTH 6 -#define BMX160_FIFO_M_LENGTH 8 -#define BMX160_FIFO_GA_LENGTH 12 -#define BMX160_FIFO_MA_LENGTH 14 -#define BMX160_FIFO_MG_LENGTH 14 -#define BMX160_FIFO_MGA_LENGTH 20 - - -/** FIFO Header Data definitions */ -#define BMX160_FIFO_HEAD_SKIP_FRAME 0x40 -#define BMX160_FIFO_HEAD_SENSOR_TIME 0x44 -#define BMX160_FIFO_HEAD_INPUT_CONFIG 0x48 -#define BMX160_FIFO_HEAD_OVER_READ 0x80 -#define BMX160_FIFO_HEAD_A 0x84 -#define BMX160_FIFO_HEAD_G 0x88 -#define BMX160_FIFO_HEAD_G_A 0x8C -#define BMX160_FIFO_HEAD_M 0x90 -#define BMX160_FIFO_HEAD_M_A 0x94 -#define BMX160_FIFO_HEAD_M_G 0x98 -#define BMX160_FIFO_HEAD_M_G_A 0x9C - - -/** FIFO sensor time length definitions */ -#define BMX160_SENSOR_TIME_LENGTH 3) - - -/** FIFO DOWN selection */ -/* Accel fifo down-sampling values*/ -#define BMX160_ACCEL_FIFO_DOWN_ZERO 0x00 -#define BMX160_ACCEL_FIFO_DOWN_ONE 0x10 -#define BMX160_ACCEL_FIFO_DOWN_TWO 0x20 -#define BMX160_ACCEL_FIFO_DOWN_THREE 0x30 -#define BMX160_ACCEL_FIFO_DOWN_FOUR 0x40 -#define BMX160_ACCEL_FIFO_DOWN_FIVE 0x50 -#define BMX160_ACCEL_FIFO_DOWN_SIX 0x60 -#define BMX160_ACCEL_FIFO_DOWN_SEVEN 0x70 - -/* Gyro fifo down-smapling values*/ -#define BMX160_GYRO_FIFO_DOWN_ZERO 0x00 -#define BMX160_GYRO_FIFO_DOWN_ONE 0x01 -#define BMX160_GYRO_FIFO_DOWN_TWO 0x02 -#define BMX160_GYRO_FIFO_DOWN_THREE 0x03 -#define BMX160_GYRO_FIFO_DOWN_FOUR 0x04 -#define BMX160_GYRO_FIFO_DOWN_FIVE 0x05 -#define BMX160_GYRO_FIFO_DOWN_SIX 0x06 -#define BMX160_GYRO_FIFO_DOWN_SEVEN 0x07 - - -#define BMX160_ACCEL_FIFO_FILT_EN 0x80 //< Accel Fifo filter enable*/ - -#define BMX160_GYRO_FIFO_FILT_EN 0x08 //< Gyro Fifo filter enable*/ - -/** Definitions to check validity of FIFO frames */ -#define FIFO_CONFIG_MSB_CHECK 0x80 -#define FIFO_CONFIG_LSB_CHECK 0x00 - -/*! bmx160 accel FOC configurations */ -#define BMX160_FOC_ACCEL_DISABLED 0x00 -#define BMX160_FOC_ACCEL_POSITIVE_G 0x01 -#define BMX160_FOC_ACCEL_NEGATIVE_G 0x02 -#define BMX160_FOC_ACCEL_0G 0x03 - -/** Array Parameter DefinItions */ -#define BMX160_SENSOR_TIME_LSB_BYTE 0 -#define BMX160_SENSOR_TIME_XLSB_BYTE 1 -#define BMX160_SENSOR_TIME_MSB_BYTE 2 - - -/** Interface settings */ -#define BMX160_SPI_INTF 1 -#define BMX160_I2C_INTF 0 -#define BMX160_SPI_RD_MASK 0x80 -#define BMX160_SPI_WR_MASK 0x7F - -/* Sensor & time select definition*/ -#define BMX160_MAG_SEL 0x01 -#define BMX160_GYRO_SEL 0x02 -#define BMX160_ACCEL_SEL 0x03 -#define BMX160_TIME_SEL 0x04 - - -#define BMX160_SEN_SEL_MASK 0x07 //< Sensor select mask*/ -#define BMX160_ERR_REG_MASK 0x0F //< Error code mask */ -#define BMX160_I2C_ADDR 0x68 //< bmx160 I2C address */ -#define BMX160_MAGN_BMM150_I2C_ADDR 0x10 //< bmx160 secondary IF address */ - -/** bmx160 Length definitions */ -#define BMX160_ONE 1 -#define BMX160_TWO 2 -#define BMX160_THREE 3 -#define BMX160_FOUR 4 -#define BMX160_FIVE 5 - - -#define BMX160_FIFO_LEVEL_MARGIN 16 //< bmx160 fifo level Margin */ -#define BMX160_FIFO_FLUSH_VALUE 0xB0 //< bmx160 fifo flush Command */ - -/** bmx160 offset values for xyz axes of accel */ -#define BMX160_ACCEL_MIN_OFFSET -128 -#define BMX160_ACCEL_MAX_OFFSET 127 - -/** bmx160 offset values for xyz axes of gyro */ -#define BMX160_GYRO_MIN_OFFSET -512 -#define BMX160_GYRO_MAX_OFFSET 511 - -/** bmx160 fifo full interrupt position and mask */ -#define BMX160_FIFO_FULL_INT_POS 5 -#define BMX160_FIFO_FULL_INT_MSK 0x20 -#define BMX160_FIFO_WTM_INT_POS 6 -#define BMX160_FIFO_WTM_INT_MSK 0x40 - -#define BMX160_FIFO_FULL_INT_PIN1_POS 5 -#define BMX160_FIFO_FULL_INT_PIN1_MSK 0x20 -#define BMX160_FIFO_FULL_INT_PIN2_POS 1 -#define BMX160_FIFO_FULL_INT_PIN2_MSK 0x02 - -#define BMX160_FIFO_WTM_INT_PIN1_POS 6 -#define BMX160_FIFO_WTM_INT_PIN1_MSK 0x40 -#define BMX160_FIFO_WTM_INT_PIN2_POS 2 -#define BMX160_FIFO_WTM_INT_PIN2_MSK 0x04 - -#define BMX160_MANUAL_MODE_EN_POS 7 -#define BMX160_MANUAL_MODE_EN_MSK 0x80 -#define BMX160_MAGN_READ_BURST_POS 0 -#define BMX160_MAGN_READ_BURST_MSK 0x03 - -#define BMX160_GYRO_SELF_TEST_POS 4 -#define BMX160_GYRO_SELF_TEST_MSK 0x10 -#define BMX160_GYRO_SELF_TEST_STATUS_POS 1 -#define BMX160_GYRO_SELF_TEST_STATUS_MSK 0x02 - -#define BMX160_GYRO_FOC_EN_POS 6 -#define BMX160_GYRO_FOC_EN_MSK 0x40 - -#define BMX160_ACCEL_FOC_X_CONF_POS 4 -#define BMX160_ACCEL_FOC_X_CONF_MSK 0x30 - -#define BMX160_ACCEL_FOC_Y_CONF_POS 2 -#define BMX160_ACCEL_FOC_Y_CONF_MSK 0x0C - -#define BMX160_ACCEL_FOC_Z_CONF_MSK 0x03 - -#define BMX160_FOC_STATUS_POS 3 -#define BMX160_FOC_STATUS_MSK 0x08 - -#define BMX160_GYRO_OFFSET_X_MSK 0x03 - -#define BMX160_GYRO_OFFSET_Y_POS 2 -#define BMX160_GYRO_OFFSET_Y_MSK 0x0C - -#define BMX160_GYRO_OFFSET_Z_POS 4 -#define BMX160_GYRO_OFFSET_Z_MSK 0x30 - -#define BMX160_GYRO_OFFSET_EN_POS 7 -#define BMX160_GYRO_OFFSET_EN_MSK 0x80 - -#define BMX160_ACCEL_OFFSET_EN_POS 6 -#define BMX160_ACCEL_OFFSET_EN_MSK 0x40 - - -#define BMX160_GYRO_OFFSET_POS 8 -#define BMX160_GYRO_OFFSET_MSK 0x0300 - -#define BMX160_NVM_UPDATE_POS 1 -#define BMX160_NVM_UPDATE_MSK 0x02 - -#define BMX160_NVM_STATUS_POS 4 -#define BMX160_NVM_STATUS_MSK 0x10 - -/* BIT SLICE GET AND SET FUNCTIONS */ -#define BMX160_GET_BITS(regvar, bitname)\ - ((regvar & bitname##_MSK) >> bitname##_POS) -#define BMX160_SET_BITS(regvar, bitname, val)\ - ((regvar & ~bitname##_MSK) | \ - ((val<> 8) - -/** - * @struct sBmx160FifoFrame_t - * @brief This structure holds the information for usage of FIFO by the user. - */ -typedef struct { - uint8_t *data; /**< Data buffer of user defined length is to be mapped here */ - uint16_t length; /**< While calling the API "BMX160_get_fifo_data" , length stores number of bytes in FIFO to be read (specified by user as input) and after execution of the API ,number of FIFO data bytes available is provided as an output to user */ - uint8_t fifoTimeEnable; /**< FIFO time enable */ - uint8_t fifoHeaderEnable; /**< Enabling of the FIFO header to stream in header mode */ - uint8_t fifoDataEnable; /**< Streaming of the Accelerometer, Gyroscope sensor data or both in FIFO */ - uint16_t accelByteStartIdx;/**< Will be equal to length when no more frames are there to parse */ - uint16_t gyroByteStartIdx; /**< Will be equal to length when no more frames are there to parse */ - uint16_t magnByteStartIdx; /**< Will be equal to length when no more frames are there to parse */ - uint32_t sensorTime; /**< Value of FIFO sensor time time */ - uint8_t skippedFrameCount; /**< Value of Skipped frame counts */ -}sBmx160FifoFrame_t; - -/** - * @enum eBmx160AnySigMotionActiveInterruptState_t - * @brief bmx160 active state of any & sig motion interrupt. - */ -typedef enum { - eBmx160BothAnySigMotionDisabled = -1, /**< Both any & sig motion are disabled */ - eBmx160AnyMotionEnabled, /**< Any-motion selected */ - eBmx160SigMotionEnabled /**< Sig-motion selected */ -}eBmx160AnySigMotionActiveInterruptState_t; - - -/** - * @struct sBmx160Cfg_t - * @brief bmx160 sensor configuration structure - */ -typedef struct { - uint8_t power; /**< power mode */ - uint8_t odr; /**< output data rate */ - uint8_t range; /**< range */ - uint8_t bw; /**< bandwidth */ -}sBmx160Cfg_t; - - - -/* type definitions */ -typedef int8_t (*bmx160ComFptrT)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len); -typedef void (*bmx160DelayFptrT)(uint32_t period); - -/** - * @struct sBmx160Dev_t - */ -typedef struct { - uint8_t chipId; /**< Chip Id */ - uint8_t id; /**< Device Id */ - uint8_t interface; /**< 0 - I2C , 1 - SPI Interface */ - eBmx160AnySigMotionActiveInterruptState_t any_sig_sel; /**< Hold active interrupts status for any and sig motion 0 - Any-motion enable, 1 - Sig-motion enable, -1 neither any-motion nor sig-motion selected */ - sBmx160Cfg_t magnCfg; /**< Structure to configure Magnetometer sensor */ - sBmx160Cfg_t prevMagnCfg; /**< Structure to hold previous/old magn config parameters.This is used at driver level to prevent overwriting of same data, hence user does not change it in the code */ - sBmx160Cfg_t accelCfg; /**< Structure to configure Accel sensor */ - sBmx160Cfg_t prevAccelCfg; /**< Structure to hold previous/old accel config parameters.This is used at driver level to prevent overwriting of same data, hence user does not change it in the code */ - sBmx160Cfg_t gyroCfg; /**< Structure to configure Gyro sensor */ - sBmx160Cfg_t prevGyroCfg; /**< Structure to hold previous/old gyro config parameters. This is used at driver level to prevent overwriting of same data, hence user does not change it in the code */ - sBmx160FifoFrame_t *fifo; /**< FIFO related configurations */ - bmx160ComFptrT read; /**< Read function pointer */ - bmx160ComFptrT write; /**< Write function pointer */ - bmx160DelayFptrT delayMs; /**< Delay function pointer */ -}sBmx160Dev_t; - -/** - * @struct sBmx160SensorData_t - * @brief bmx160 sensor data structure which comprises of accel data - */ -typedef struct { - float x; /**< X-axis sensor data */ - float y; /**< Y-axis sensor data */ - float z; /**< Z-axis sensor data */ - uint32_t sensortime; /**< sensor time */ -}sBmx160SensorData_t; // __attribute__((packed)); - -/** - * @enum eBmx160IntChannel_t - * @brief Interrupt channel - */ - typedef enum { - BMX160_INT_CHANNEL_NONE, /**< Un-map both channels */ - BMX160_INT_CHANNEL_1, /**< interrupt Channel 1 */ - BMX160_INT_CHANNEL_2, /**< interrupt Channel 2 */ - BMX160_INT_CHANNEL_BOTH /**< Map both channels */ -}eBmx160IntChannel_t; - -/** - * @enum eBmx160IntTypes_t - * @brief Select Interrupt - */ -typedef enum { - BMX160_ACC_ANY_MOTION_INT, /**< Slope/Any-motion interrupt */ - BMX160_ACC_SIG_MOTION_INT, /**< Significant motion interrupt */ - BMX160_STEP_DETECT_INT, /**< Step detector interrupt */ - BMX160_ACC_DOUBLE_TAP_INT, /**< double tap interrupt */ - BMX160_ACC_SINGLE_TAP_INT, /**< single tap interrupt */ - BMX160_ACC_ORIENT_INT, /**< orientation interrupt */ - BMX160_ACC_FLAT_INT, /**< flat interrupt */ - BMX160_ACC_HIGH_G_INT, /**< high-g interrupt */ - BMX160_ACC_LOW_G_INT, /**< low-g interrupt */ - BMX160_ACC_SLOW_NO_MOTION_INT, /**< slow/no-motion interrupt */ - BMX160_ACC_GYRO_DATA_RDY_INT, /**< data ready interrupt */ - BMX160_ACC_GYRO_FIFO_FULL_INT, /**< fifo full interrupt */ - BMX160_ACC_GYRO_FIFO_WATERMARK_INT /**< fifo watermark interrupt */ -}eBmx160IntTypes_t; - -/** - * @struct sBmx160IntPinSettg_t - * @brief Structure configuring Interrupt pins - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint16_t outputEn :1; /**< To enable either INT1 or INT2 pin as output. 0- output disabled ,1- output enabled */ - uint16_t outputMode :1; /**< 0 - push-pull 1- open drain,only valid if outputEn is set 1 */ - uint16_t outputType :1; /**< 0 - active low , 1 - active high level.if outputEn is 1,this applies to interrupts,else PMU_trigger */ - uint16_t edgeCtrl :1; /**< 0 - level trigger , 1 - edge trigger */ - uint16_t inputEn :1; /**< To enable either INT1 or INT2 pin as input. 0 - input disabled ,1 - input enabled */ - uint16_t latchDur :4; /**< latch duration*/ -#elif BIG_ENDIAN == 1 - uint16_t latchDur : 4; /**< latch duration*/ - uint16_t inputEn : 1; /**< Latched,non-latched or temporary interrupt modes */ - uint16_t edgeCtrl : 1; /**< 1 - edge trigger, 0 - level trigger */ - uint16_t outputType : 1; /**< 0 - active low , 1 - active high level. if outputEn is 1,this applies to interrupts,else PMU_trigger */ - uint16_t outputMode : 1; /**< 0 - push-pull , 1 - open drain,only valid if outputEn is set 1 */ - uint16_t outputEn : 1; /**< To enable either INT1 or INT2 pin as output. 0 - output disabled , 1 - output enabled */ -#endif -}sBmx160IntPinSettg_t; - -/** - * @struct sBmx160AccTapIntCfg_t - * @brief Tap interrupt structure - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint16_t tapThr :5; /**< tap threshold */ - uint16_t tapShock :1; /**< tap shock */ - uint16_t tapQuiet :1; /**< tap quiet */ - uint16_t tapDur :3; /**< tap duration */ - uint16_t tapDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint16_t tapEn :1; /**< tap enable, 1 - enable, 0 - disable */ -#elif BIG_ENDIAN == 1 - uint16_t tapEn :1; /**< tap enable, 1 - enable, 0 - disable */ - uint16_t tapDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint16_t tapDur : 3; /**< tap duration */ - uint16_t tapQuiet : 1; /**< tap quiet */ - uint16_t tapShock : 1; /**< tap shock */ - uint16_t tapThr : 5; /**< tap threshold */ -#endif -}sBmx160AccTapIntCfg_t; - -/** - * @struct sBmx160AccAnyMotIntCfg_t - * @brief Slope interrupt structure - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint8_t anymotionEn :1; /**< 1 any-motion enable, 0 - any-motion disable */ - uint8_t anymotionX :1; /**< slope interrupt x, 1 - enable, 0 - disable */ - uint8_t anymotionY :1; /**< slope interrupt y, 1 - enable, 0 - disable */ - uint8_t anymotionZ :1; /**< slope interrupt z, 1 - enable, 0 - disable */ - uint8_t anymotionDur :2; /**< slope duration */ - uint8_t anymotionDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint8_t anymotionThr; /**< slope threshold */ -#elif BIG_ENDIAN == 1 - uint8_t anymotionThr; /**< slope threshold */ - uint8_t anymotionDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint8_t anymotionDur : 2; /**< slope duration */ - uint8_t anymotionZ : 1; /**< slope interrupt z, 1 - enable, 0 - disable */ - uint8_t anymotionY : 1; /**< slope interrupt y, 1 - enable, 0 - disable */ - uint8_t anymotionX : 1; /**< slope interrupt x, 1 - enable, 0 - disable */ - uint8_t anymotionEn :1; /**< 1 any-motion enable, 0 - any-motion disable */ -#endif -}sBmx160AccAnyMotIntCfg_t; - -/** - * @struct sBmx160AccSigMotIntCfg_t - * @brief Significant motion interrupt structure - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint8_t sigMotSkip :2; /**< skip time of sig-motion interrupt */ - uint8_t sigMotProof :2; /**< proof time of sig-motion interrupt */ - uint8_t sigDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint8_t sigEn :1; /**< 1 - enable sig, 0 - disable sig & enable anymotion */ - uint8_t sigMotThres; /**< sig-motion threshold */ -#elif BIG_ENDIAN == 1 - uint8_t sigMotThres; /**< sig-motion threshold */ - uint8_t sigEn :1; /**< 1 - enable sig, 0 - disable sig & enable anymotion */ - uint8_t sigDataSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint8_t sigMotProof : 2;/**< proof time of sig-motion interrupt */ - uint8_t sigMotSkip : 2; /**< skip time of sig-motion interrupt */ -#endif -}sBmx160AccSigMotIntCfg_t; - -/** - * @struct sBmx160AccStepDetectIntCfg_t - * @brief Step detector interrupt structure - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint16_t stepDetectorEn :1; /**< 1- step detector enable, 0- step detector disable */ - uint16_t minThreshold :2; /**< minimum threshold */ - uint16_t steptimeMin :3; /**< minimal detectable step time */ - uint16_t stepDetectorMode :2; /**< enable step counter mode setting */ - uint16_t stepMinBuf :3; /**< minimum step buffer size*/ -#elif BIG_ENDIAN == 1 - uint16_t stepMinBuf :3; /**< minimum step buffer size*/ - uint16_t stepDetectorMode : 2; /**< enable step counter mode setting */ - uint16_t steptimeMin : 3; /**< minimal detectable step time */ - uint16_t minThreshold : 2; /**< minimum threshold */ - uint16_t stepDetectorEn :1; /**< 1- step detector enable, 0- step detector disable */ -#endif -}sBmx160AccStepDetectIntCfg_t; - -/** - * @struct sBmx160AccNoMotionIntCfg_t - * @brief No motion interrupt structure - */ -typedef struct { -#if LITTLE_ENDIAN == 1 - uint16_t noMotionX :1; /**< no motion interrupt x */ - uint16_t noMotionY :1; /**< no motion interrupt y */ - uint16_t noMotionZ :1; /**< no motion interrupt z */ - uint16_t noMotionDur :6; /**< no motion duration */ - uint16_t noMotionSel :1; /**< no motion sel , 1 - enable no-motion ,0- enable slow-motion */ - uint16_t noMotionSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint8_t noMotionThres; /**< no motion threshold */ -#elif BIG_ENDIAN == 1 - uint8_t noMotionThres; /**< no motion threshold */ - uint16_t noMotionSrc :1; /**< data source 0- filter & 1 pre-filter*/ - uint16_t noMotionSel : 1; /**< no motion sel , 1 - enable no-motion ,0- enable slow-motion */ - uint16_t noMotionDur : 6; /**< no motion duration */ - uint16_t noMotionZ :1; /** Success / -ve value -> Error. + */ +static int8_t set_intr_pin_config(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the any-motion interrupt of the sensor. + * This interrupt occurs when accel values exceeds preset threshold + * for a certain period of time. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_any_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev); + +/*! + * @brief This API sets tap interrupts.Interrupt is fired when + * tap movements happen. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_tap_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the data ready interrupt for both accel and gyro. + * This interrupt occurs when new accel and gyro data come. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_gyro_data_ready_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the significant motion interrupt of the sensor.This + * interrupt occurs when there is change in user location. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_sig_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev); + +/*! + * @brief This API sets the no motion/slow motion interrupt of the sensor. + * Slow motion is similar to any motion interrupt.No motion interrupt + * occurs when slope bet. two accel values falls below preset threshold + * for preset duration. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_no_motion_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the step detection interrupt.This interrupt + * occurs when the single step causes accel values to go above + * preset threshold. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_step_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the orientation interrupt of the sensor.This + * interrupt occurs when there is orientation change in the sensor + * with respect to gravitational field vector g. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_orientation_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the flat interrupt of the sensor.This interrupt + * occurs in case of flat orientation + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_flat_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the low-g interrupt of the sensor.This interrupt + * occurs during free-fall. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_low_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the high-g interrupt of the sensor.The interrupt + * occurs if the absolute value of acceleration data of any enabled axis + * exceeds the programmed threshold and the sign of the value does not + * change for a preset duration. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_high_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the default configuration parameters of accel & gyro. + * Also maintain the previous state of configurations. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static void default_param_settg(struct bmi160_dev *dev); + +/*! + * @brief This API is used to validate the device structure pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t null_ptr_check(const struct bmi160_dev *dev); + +/*! + * @brief This API set the accel configuration. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_conf(struct bmi160_dev *dev); + +/*! + * @brief This API gets the accel configuration. + * + * @param[out] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t get_accel_conf(struct bmi160_dev *dev); + +/*! + * @brief This API check the accel configuration. + * + * @param[in] data : Pointer to store the updated accel config. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t check_accel_config(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the accel odr. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_accel_odr(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the accel bandwidth. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_accel_bw(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the accel range. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_accel_range(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API checks the invalid settings for ODR & Bw for Accel and Gyro. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t check_invalid_settg(const struct bmi160_dev *dev); + +/*! + * @brief This API set the gyro configuration. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_gyro_conf(struct bmi160_dev *dev); + +/*! + * @brief This API get the gyro configuration. + * + * @param[out] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t get_gyro_conf(struct bmi160_dev *dev); + +/*! + * @brief This API check the gyro configuration. + * + * @param[in] data : Pointer to store the updated gyro config. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t check_gyro_config(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the gyro odr. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_gyro_odr(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the gyro bandwidth. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_gyro_bw(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API process the gyro range. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_gyro_range(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the accel power mode. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_accel_pwr(struct bmi160_dev *dev); + +/*! + * @brief This API process the undersampling setting of Accel. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t process_under_sampling(uint8_t *data, const struct bmi160_dev *dev); + +/*! + * @brief This API sets the gyro power mode. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + */ +static int8_t set_gyro_pwr(struct bmi160_dev *dev); + +/*! + * @brief This API reads accel data along with sensor time if time is requested + * by user. Kindly refer the user guide(README.md) for more info. + * + * @param[in] len : len to read no of bytes + * @param[out] accel : Structure pointer to store accel data + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t get_accel_data(uint8_t len, struct bmi160_sensor_data *accel, const struct bmi160_dev *dev); + +/*! + * @brief This API reads accel data along with sensor time if time is requested + * by user. Kindly refer the user guide(README.md) for more info. + * + * @param[in] len : len to read no of bytes + * @param[out] gyro : Structure pointer to store accel data + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t get_gyro_data(uint8_t len, struct bmi160_sensor_data *gyro, const struct bmi160_dev *dev); + +/*! + * @brief This API reads accel and gyro data along with sensor time + * if time is requested by user. + * Kindly refer the user guide(README.md) for more info. + * + * @param[in] len : len to read no of bytes + * @param[out] accel : Structure pointer to store accel data + * @param[out] gyro : Structure pointer to store accel data + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t get_accel_gyro_data(uint8_t len, + struct bmi160_sensor_data *accel, + struct bmi160_sensor_data *gyro, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the any-motion interrupt for accel. + * + * @param[in] any_motion_int_cfg : Structure instance of + * bmi160_acc_any_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_accel_any_motion_int(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + struct bmi160_dev *dev); + +/*! + * @brief This API disable the sig-motion interrupt. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t disable_sig_motion_int(const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for any-motion interrupt. + * + * @param[in] any_motion_int_cfg : Structure instance of + * bmi160_acc_any_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_any_motion_src(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the duration and threshold of + * any-motion interrupt. + * + * @param[in] any_motion_int_cfg : Structure instance of + * bmi160_acc_any_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_any_dur_threshold(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure necessary setting of any-motion interrupt. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] any_motion_int_cfg : Structure instance of + * bmi160_acc_any_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_any_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enable the data ready interrupt. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_data_ready_int(const struct bmi160_dev *dev); + +/*! + * @brief This API enables the no motion/slow motion interrupt. + * + * @param[in] no_mot_int_cfg : Structure instance of + * bmi160_acc_no_motion_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_no_motion_int(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the interrupt PIN setting for + * no motion/slow motion interrupt. + * + * @param[in] int_config : structure instance of bmi160_int_settg. + * @param[in] no_mot_int_cfg : Structure instance of + * bmi160_acc_no_motion_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_no_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of interrupt for no motion. + * + * @param[in] no_mot_int_cfg : Structure instance of + * bmi160_acc_no_motion_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_no_motion_data_src(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the duration and threshold of + * no motion/slow motion interrupt along with selection of no/slow motion. + * + * @param[in] no_mot_int_cfg : Structure instance of + * bmi160_acc_no_motion_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_no_motion_dur_thr(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the sig-motion motion interrupt. + * + * @param[in] sig_mot_int_cfg : Structure instance of + * bmi160_acc_sig_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_sig_motion_int(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, struct bmi160_dev *dev); + +/*! + * @brief This API configure the interrupt PIN setting for + * significant motion interrupt. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] sig_mot_int_cfg : Structure instance of + * bmi160_acc_sig_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_sig_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for sig motion interrupt. + * + * @param[in] sig_mot_int_cfg : Structure instance of + * bmi160_acc_sig_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_sig_motion_data_src(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the threshold, skip and proof time of + * sig motion interrupt. + * + * @param[in] sig_mot_int_cfg : Structure instance of + * bmi160_acc_sig_mot_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_sig_dur_threshold(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the step detector interrupt. + * + * @param[in] step_detect_int_cfg : Structure instance of + * bmi160_acc_step_detect_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_step_detect_int(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the step detector parameter. + * + * @param[in] step_detect_int_cfg : Structure instance of + * bmi160_acc_step_detect_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_step_detect(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the single/double tap interrupt. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_tap_int(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the interrupt PIN setting for + * tap interrupt. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_tap_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for tap interrupt. + * + * @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_tap_data_src(const struct bmi160_acc_tap_int_cfg *tap_int_cfg, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the parameters of tap interrupt. + * Threshold, quite, shock, and duration. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] tap_int_cfg : Structure instance of bmi160_acc_tap_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_tap_param(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enable the external mode configuration. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_sec_if(const struct bmi160_dev *dev); + +/*! + * @brief This API configure the ODR of the auxiliary sensor. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_aux_odr(const struct bmi160_dev *dev); + +/*! + * @brief This API maps the actual burst read length set by user. + * + * @param[in] len : Pointer to store the read length. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t map_read_len(uint16_t *len, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the settings of auxiliary sensor. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_aux_settg(const struct bmi160_dev *dev); + +/*! + * @brief This API extract the read data from auxiliary sensor. + * + * @param[in] map_len : burst read value. + * @param[in] reg_addr : Address of register to read. + * @param[in] aux_data : Pointer to store the read data. + * @param[in] len : length to read the data. + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t extract_aux_read(uint16_t map_len, + uint8_t reg_addr, + uint8_t *aux_data, + uint16_t len, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the orient interrupt. + * + * @param[in] orient_int_cfg : Structure instance of bmi160_acc_orient_int_cfg. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_orient_int(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the necessary setting of orientation interrupt. + * + * @param[in] orient_int_cfg : Structure instance of bmi160_acc_orient_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_orient_int_settg(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the flat interrupt. + * + * @param[in] flat_int : Structure instance of bmi160_acc_flat_detect_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_flat_int(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the necessary setting of flat interrupt. + * + * @param[in] flat_int : Structure instance of bmi160_acc_flat_detect_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_flat_int_settg(const struct bmi160_acc_flat_detect_int_cfg *flat_int, + const struct bmi160_dev *dev); + +/*! + * @brief This API enables the Low-g interrupt. + * + * @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_low_g_int(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of data(filter & pre-filter) for low-g interrupt. + * + * @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_low_g_data_src(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the necessary setting of low-g interrupt. + * + * @param[in] low_g_int : Structure instance of bmi160_acc_low_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_low_g_int_settg(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev); + +/*! + * @brief This API enables the high-g interrupt. + * + * @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_high_g_int(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for high-g interrupt. + * + * @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_high_g_data_src(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the necessary setting of high-g interrupt. + * + * @param[in] high_g_int_cfg : Structure instance of bmi160_acc_high_g_int_cfg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_high_g_int_settg(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, + const struct bmi160_dev *dev); + +/*! + * @brief This API configure the behavioural setting of interrupt pin. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_int_out_ctrl(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API configure the mode(input enable, latch or non-latch) of interrupt pin. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t config_int_latch(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API performs the self test for accelerometer of BMI160 + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t perform_accel_self_test(struct bmi160_dev *dev); + +/*! + * @brief This API enables to perform the accel self test by setting proper + * configurations to facilitate accel self test + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_accel_self_test(struct bmi160_dev *dev); + +/*! + * @brief This API performs accel self test with positive excitation + * + * @param[in] accel_pos : Structure pointer to store accel data + * for positive excitation + * @param[in] dev : structure instance of bmi160_dev + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t accel_self_test_positive_excitation(struct bmi160_sensor_data *accel_pos, const struct bmi160_dev *dev); + +/*! + * @brief This API performs accel self test with negative excitation + * + * @param[in] accel_neg : Structure pointer to store accel data + * for negative excitation + * @param[in] dev : structure instance of bmi160_dev + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t accel_self_test_negative_excitation(struct bmi160_sensor_data *accel_neg, const struct bmi160_dev *dev); + +/*! + * @brief This API validates the accel self test results + * + * @param[in] accel_pos : Structure pointer to store accel data + * for positive excitation + * @param[in] accel_neg : Structure pointer to store accel data + * for negative excitation + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error / +ve value -> Self test fail + */ +static int8_t validate_accel_self_test(const struct bmi160_sensor_data *accel_pos, + const struct bmi160_sensor_data *accel_neg); + +/*! + * @brief This API performs the self test for gyroscope of BMI160 + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t perform_gyro_self_test(const struct bmi160_dev *dev); + +/*! + * @brief This API enables the self test bit to trigger self test for gyro + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_gyro_self_test(const struct bmi160_dev *dev); + +/*! + * @brief This API validates the self test results of gyro + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t validate_gyro_self_test(const struct bmi160_dev *dev); + +/*! + * @brief This API sets FIFO full interrupt of the sensor.This interrupt + * occurs when the FIFO is full and the next full data sample would cause + * a FIFO overflow, which may delete the old samples. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t set_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This enable the FIFO full interrupt engine. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API sets FIFO watermark interrupt of the sensor.The FIFO + * watermark interrupt is fired, when the FIFO fill level is above a fifo + * watermark. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t set_fifo_watermark_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This enable the FIFO watermark interrupt engine. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t enable_fifo_wtm_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to reset the FIFO related configurations + * in the fifo_frame structure. + * + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void reset_fifo_data_structure(const struct bmi160_dev *dev); + +/*! + * @brief This API is used to read number of bytes filled + * currently in FIFO buffer. + * + * @param[in] bytes_to_read : Number of bytes available in FIFO at the + * instant which is obtained from FIFO counter. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error. + * @retval Any non zero value -> Fail + * + */ +static int8_t get_fifo_byte_counter(uint16_t *bytes_to_read, struct bmi160_dev const *dev); + +/*! + * @brief This API is used to compute the number of bytes of accel FIFO data + * which is to be parsed in header-less mode + * + * @param[out] data_index : The start index for parsing data + * @param[out] data_read_length : Number of bytes to be parsed + * @param[in] acc_frame_count : Number of accelerometer frames to be read + * @param[in] dev : Structure instance of bmi160_dev. + * + */ +static void get_accel_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *acc_frame_count, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed. + * + * @param[in,out] acc : structure instance of sensor data + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] acc_idx : Index value of accelerometer data + * (x,y,z axes) frames parsed + * @param[in] frame_info : It consists of either fifo_data_enable + * parameter in header-less mode or + * frame header data in header mode + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_accel_frame(struct bmi160_sensor_data *acc, + uint16_t *idx, + uint8_t *acc_idx, + uint8_t frame_info, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data and store it in the instance of the structure bmi160_sensor_data. + * + * @param[in,out] accel_data : structure instance of sensor data + * @param[in,out] data_start_index : Index value of number of bytes parsed + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_accel_data(struct bmi160_sensor_data *accel_data, + uint16_t data_start_index, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data in header mode. + * + * @param[in,out] accel_data : Structure instance of sensor data + * @param[in,out] accel_length : Number of accelerometer frames + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void extract_accel_header_mode(struct bmi160_sensor_data *accel_data, + uint8_t *accel_length, + const struct bmi160_dev *dev); + +/*! + * @brief This API computes the number of bytes of gyro FIFO data + * which is to be parsed in header-less mode + * + * @param[out] data_index : The start index for parsing data + * @param[out] data_read_length : No of bytes to be parsed from FIFO buffer + * @param[in] gyro_frame_count : Number of Gyro data frames to be read + * @param[in] dev : Structure instance of bmi160_dev. + */ +static void get_gyro_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *gyro_frame_count, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the gyroscope's data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed. + * + * @param[in,out] gyro : structure instance of sensor data + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] gyro_idx : Index value of gyro data + * (x,y,z axes) frames parsed + * @param[in] frame_info : It consists of either fifo_data_enable + * parameter in header-less mode or + * frame header data in header mode + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_gyro_frame(struct bmi160_sensor_data *gyro, + uint16_t *idx, + uint8_t *gyro_idx, + uint8_t frame_info, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the gyro data from the + * FIFO data and store it in the instance of the structure bmi160_sensor_data. + * + * @param[in,out] gyro_data : structure instance of sensor data + * @param[in,out] data_start_index : Index value of number of bytes parsed + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_gyro_data(struct bmi160_sensor_data *gyro_data, + uint16_t data_start_index, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the gyro data from the + * FIFO data in header mode. + * + * @param[in,out] gyro_data : Structure instance of sensor data + * @param[in,out] gyro_length : Number of gyro frames + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void extract_gyro_header_mode(struct bmi160_sensor_data *gyro_data, + uint8_t *gyro_length, + const struct bmi160_dev *dev); + +/*! + * @brief This API computes the number of bytes of aux FIFO data + * which is to be parsed in header-less mode + * + * @param[out] data_index : The start index for parsing data + * @param[out] data_read_length : No of bytes to be parsed from FIFO buffer + * @param[in] aux_frame_count : Number of Aux data frames to be read + * @param[in] dev : Structure instance of bmi160_dev. + */ +static void get_aux_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *aux_frame_count, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the aux's data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed + * + * @param[in,out] aux_data : structure instance of sensor data + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] aux_index : Index value of gyro data + * (x,y,z axes) frames parsed + * @param[in] frame_info : It consists of either fifo_data_enable + * parameter in header-less mode or + * frame header data in header mode + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_aux_frame(struct bmi160_aux_data *aux_data, + uint16_t *idx, + uint8_t *aux_index, + uint8_t frame_info, + const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the aux data from the + * FIFO data and store it in the instance of the structure bmi160_aux_data. + * + * @param[in,out] aux_data : structure instance of sensor data + * @param[in,out] data_start_index : Index value of number of bytes parsed + * @param[in] dev : structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_aux_data(struct bmi160_aux_data *aux_data, uint16_t data_start_index, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse the aux data from the + * FIFO data in header mode. + * + * @param[in,out] aux_data : Structure instance of sensor data + * @param[in,out] aux_length : Number of aux frames + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void extract_aux_header_mode(struct bmi160_aux_data *aux_data, uint8_t *aux_length, + const struct bmi160_dev *dev); + +/*! + * @brief This API checks the presence of non-valid frames in the read fifo data. + * + * @param[in,out] data_index : The index of the current data to + * be parsed from fifo data + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void check_frame_validity(uint16_t *data_index, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to move the data index ahead of the + * current_frame_length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + * + * @param[in,out] data_index : Index of the FIFO data which + * is to be moved ahead of the + * current_frame_length + * @param[in] current_frame_length : Number of bytes in a particular frame + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse and store the sensor time from the + * FIFO data in the structure instance dev. + * + * @param[in,out] data_index : Index of the FIFO data which + * has the sensor time. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_sensortime_frame(uint16_t *data_index, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to parse and store the skipped_frame_count from + * the FIFO data in the structure instance dev. + * + * @param[in,out] data_index : Index of the FIFO data which + * has the skipped frame count. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static void unpack_skipped_frame(uint16_t *data_index, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to get the FOC status from the sensor + * + * @param[in,out] foc_status : Result of FOC status. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t get_foc_status(uint8_t *foc_status, struct bmi160_dev const *dev); + +/*! + * @brief This API is used to configure the offset enable bits in the sensor + * + * @param[in,out] foc_conf : Structure instance of bmi160_foc_conf which + * has the FOC and offset configurations + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t configure_offset_enable(const struct bmi160_foc_conf *foc_conf, struct bmi160_dev const *dev); + +/*! + * @brief This API is used to trigger the FOC in the sensor + * + * @param[in,out] offset : Structure instance of bmi160_offsets which + * reads and stores the offset values after FOC + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t trigger_foc(struct bmi160_offsets *offset, struct bmi160_dev const *dev); + +/*! + * @brief This API is used to map/unmap the Dataready(Accel & Gyro), FIFO full + * and FIFO watermark interrupt + * + * @param[in] int_config : Structure instance of bmi160_int_settg which + * stores the interrupt type and interrupt channel + * configurations to map/unmap the interrupt pins + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t map_hardware_interrupt(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*! + * @brief This API is used to map/unmap the Any/Sig motion, Step det/Low-g, + * Double tap, Single tap, Orientation, Flat, High-G, Nomotion interrupt pins. + * + * @param[in] int_config : Structure instance of bmi160_int_settg which + * stores the interrupt type and interrupt channel + * configurations to map/unmap the interrupt pins + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval zero -> Success / -ve value -> Error + */ +static int8_t map_feature_interrupt(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev); + +/*********************** User function definitions ****************************/ + +/*! + * @brief This API reads the data from the given register address + * of sensor. + */ +int8_t bmi160_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->read == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else if (len == 0) + { + rslt = BMI160_E_READ_WRITE_LENGTH_INVALID; + } + else + { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI160_SPI_INTF) + { + reg_addr = (reg_addr | BMI160_SPI_RD_MASK); + } + + rslt = dev->read(dev->id, reg_addr, data, len); + } + + return rslt; +} + +/*! + * @brief This API writes the given data to the register address + * of sensor. + */ +int8_t bmi160_set_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + uint8_t count = 0; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->write == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else if (len == 0) + { + rslt = BMI160_E_READ_WRITE_LENGTH_INVALID; + } + else + { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI160_SPI_INTF) + { + reg_addr = (reg_addr & BMI160_SPI_WR_MASK); + } + + if ((dev->prev_accel_cfg.power == BMI160_ACCEL_NORMAL_MODE) || + (dev->prev_gyro_cfg.power == BMI160_GYRO_NORMAL_MODE)) + { + rslt = dev->write(dev->id, reg_addr, data, len); + + /* Kindly refer bmi160 data sheet section 3.2.4 */ + dev->delay_ms(1); + + } + else + { + /*Burst write is not allowed in + * suspend & low power mode */ + for (; count < len; count++) + { + rslt = dev->write(dev->id, reg_addr, &data[count], 1); + reg_addr++; + + /* Kindly refer bmi160 data sheet section 3.2.4 */ + dev->delay_ms(1); + + } + } + + if (rslt != BMI160_OK) + { + rslt = BMI160_E_COM_FAIL; + } + } + + return rslt; +} + +/*! + * @brief This API is the entry point for sensor.It performs + * the selection of I2C/SPI read mechanism according to the + * selected interface and reads the chip-id of bmi160 sensor. + */ +int8_t bmi160_init(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data; + uint8_t try = 3; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + + /* Dummy read of 0x7F register to enable SPI Interface + * if SPI is used */ + if ((rslt == BMI160_OK) && (dev->intf == BMI160_SPI_INTF)) + { + rslt = bmi160_get_regs(BMI160_SPI_COMM_TEST_ADDR, &data, 1, dev); + } + + if (rslt == BMI160_OK) + { + /* Assign chip id as zero */ + dev->chip_id = 0; + + while ((try--) && (dev->chip_id != BMI160_CHIP_ID)) + { + /* Read chip_id */ + rslt = bmi160_get_regs(BMI160_CHIP_ID_ADDR, &dev->chip_id, 1, dev); + } + + if ((rslt == BMI160_OK) && (dev->chip_id == BMI160_CHIP_ID)) + { + dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED; + + /* Soft reset */ + rslt = bmi160_soft_reset(dev); + } + else + { + rslt = BMI160_E_DEV_NOT_FOUND; + } + } + + return rslt; +} + +/*! + * @brief This API resets and restarts the device. + * All register values are overwritten with default parameters. + */ +int8_t bmi160_soft_reset(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = BMI160_SOFT_RESET_CMD; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Reset the device */ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &data, 1, dev); + dev->delay_ms(BMI160_SOFT_RESET_DELAY_MS); + if ((rslt == BMI160_OK) && (dev->intf == BMI160_SPI_INTF)) + { + /* Dummy read of 0x7F register to enable SPI Interface + * if SPI is used */ + rslt = bmi160_get_regs(BMI160_SPI_COMM_TEST_ADDR, &data, 1, dev); + } + + if (rslt == BMI160_OK) + { + /* Update the default parameters */ + default_param_settg(dev); + } + } + + return rslt; +} + +/*! + * @brief This API configures the power mode, range and bandwidth + * of sensor. + */ +int8_t bmi160_set_sens_conf(struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = set_accel_conf(dev); + if (rslt == BMI160_OK) + { + rslt = set_gyro_conf(dev); + if (rslt == BMI160_OK) + { + /* write power mode for accel and gyro */ + rslt = bmi160_set_power_mode(dev); + if (rslt == BMI160_OK) + { + rslt = check_invalid_settg(dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API gets accel and gyro configurations. + */ +int8_t bmi160_get_sens_conf(struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = get_accel_conf(dev); + if (rslt == BMI160_OK) + { + rslt = get_gyro_conf(dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets the power mode of the sensor. + */ +int8_t bmi160_set_power_mode(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = set_accel_pwr(dev); + if (rslt == BMI160_OK) + { + rslt = set_gyro_pwr(dev); + } + } + + return rslt; +} + +/*! + * @brief This API gets the power mode of the sensor. + */ +int8_t bmi160_get_power_mode(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t power_mode = 0; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_get_regs(BMI160_PMU_STATUS_ADDR, &power_mode, 1, dev); + if (rslt == BMI160_OK) + { + /* Power mode of the accel, gyro sensor is obtained */ + dev->gyro_cfg.power = BMI160_GET_BITS(power_mode, BMI160_GYRO_POWER_MODE); + dev->accel_cfg.power = BMI160_GET_BITS(power_mode, BMI160_ACCEL_POWER_MODE); + } + } + + return rslt; +} + +/*! + * @brief This API reads sensor data, stores it in + * the bmi160_sensor_data structure pointer passed by the user. + */ +int8_t bmi160_get_sensor_data(uint8_t select_sensor, + struct bmi160_sensor_data *accel, + struct bmi160_sensor_data *gyro, + const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + uint8_t time_sel; + uint8_t sen_sel; + uint8_t len = 0; + + /*Extract the sensor and time select information*/ + sen_sel = select_sensor & BMI160_SEN_SEL_MASK; + time_sel = ((sen_sel & BMI160_TIME_SEL) >> 2); + sen_sel = sen_sel & (BMI160_ACCEL_SEL | BMI160_GYRO_SEL); + if (time_sel == 1) + { + len = 3; + } + + /* Null-pointer check */ + if (dev != NULL) + { + switch (sen_sel) + { + case BMI160_ACCEL_ONLY: + + /* Null-pointer check */ + if (accel == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = get_accel_data(len, accel, dev); + } + + break; + case BMI160_GYRO_ONLY: + + /* Null-pointer check */ + if (gyro == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = get_gyro_data(len, gyro, dev); + } + + break; + case BMI160_BOTH_ACCEL_AND_GYRO: + + /* Null-pointer check */ + if ((gyro == NULL) || (accel == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = get_accel_gyro_data(len, accel, gyro, dev); + } + + break; + default: + rslt = BMI160_E_INVALID_INPUT; + break; + } + } + else + { + rslt = BMI160_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API configures the necessary interrupt based on + * the user settings in the bmi160_int_settg structure instance. + */ +int8_t bmi160_set_int_config(struct bmi160_int_settg *int_config, struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + switch (int_config->int_type) + { + case BMI160_ACC_ANY_MOTION_INT: + + /*Any-motion interrupt*/ + rslt = set_accel_any_motion_int(int_config, dev); + break; + case BMI160_ACC_SIG_MOTION_INT: + + /* Significant motion interrupt */ + rslt = set_accel_sig_motion_int(int_config, dev); + break; + case BMI160_ACC_SLOW_NO_MOTION_INT: + + /* Slow or no motion interrupt */ + rslt = set_accel_no_motion_int(int_config, dev); + break; + case BMI160_ACC_DOUBLE_TAP_INT: + case BMI160_ACC_SINGLE_TAP_INT: + + /* Double tap and single tap Interrupt */ + rslt = set_accel_tap_int(int_config, dev); + break; + case BMI160_STEP_DETECT_INT: + + /* Step detector interrupt */ + rslt = set_accel_step_detect_int(int_config, dev); + break; + case BMI160_ACC_ORIENT_INT: + + /* Orientation interrupt */ + rslt = set_accel_orientation_int(int_config, dev); + break; + case BMI160_ACC_FLAT_INT: + + /* Flat detection interrupt */ + rslt = set_accel_flat_detect_int(int_config, dev); + break; + case BMI160_ACC_LOW_G_INT: + + /* Low-g interrupt */ + rslt = set_accel_low_g_int(int_config, dev); + break; + case BMI160_ACC_HIGH_G_INT: + + /* High-g interrupt */ + rslt = set_accel_high_g_int(int_config, dev); + break; + case BMI160_ACC_GYRO_DATA_RDY_INT: + + /* Data ready interrupt */ + rslt = set_accel_gyro_data_ready_int(int_config, dev); + break; + case BMI160_ACC_GYRO_FIFO_FULL_INT: + + /* Fifo full interrupt */ + rslt = set_fifo_full_int(int_config, dev); + break; + case BMI160_ACC_GYRO_FIFO_WATERMARK_INT: + + /* Fifo water-mark interrupt */ + rslt = set_fifo_watermark_int(int_config, dev); + break; + case BMI160_FIFO_TAG_INT_PIN: + + /* Fifo tagging feature support */ + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + break; + default: + break; + } + + return rslt; +} + +/*! + * @brief This API enables or disable the step counter feature. + * 1 - enable step counter (0 - disable) + */ +int8_t bmi160_set_step_counter(uint8_t step_cnt_enable, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_get_regs(BMI160_INT_STEP_CONFIG_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + if (step_cnt_enable == BMI160_ENABLE) + { + data |= (uint8_t)(step_cnt_enable << 3); + } + else + { + data &= ~BMI160_STEP_COUNT_EN_BIT_MASK; + } + + rslt = bmi160_set_regs(BMI160_INT_STEP_CONFIG_1_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API reads the step counter value. + */ +int8_t bmi160_read_step_counter(uint16_t *step_val, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0, 0 }; + uint16_t msb = 0; + uint8_t lsb = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_get_regs(BMI160_INT_STEP_CNT_0_ADDR, data, 2, dev); + if (rslt == BMI160_OK) + { + lsb = data[0]; + msb = data[1] << 8; + *step_val = msb | lsb; + } + } + + return rslt; +} + +/*! + * @brief This API reads the mention no of byte of data from the given + * register address of auxiliary sensor. + */ +int8_t bmi160_aux_read(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + uint16_t map_len = 0; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->read == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) + { + rslt = map_read_len(&map_len, dev); + if (rslt == BMI160_OK) + { + rslt = extract_aux_read(map_len, reg_addr, aux_data, len, dev); + } + } + else + { + rslt = BMI160_E_INVALID_INPUT; + } + } + + return rslt; +} + +/*! + * @brief This API writes the mention no of byte of data to the given + * register address of auxiliary sensor. + */ +int8_t bmi160_aux_write(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + uint8_t count = 0; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->write == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + for (; count < len; count++) + { + /* set data to write */ + rslt = bmi160_set_regs(BMI160_AUX_IF_4_ADDR, aux_data, 1, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + if (rslt == BMI160_OK) + { + /* set address to write */ + rslt = bmi160_set_regs(BMI160_AUX_IF_3_ADDR, ®_addr, 1, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + if (rslt == BMI160_OK && (count < len - 1)) + { + aux_data++; + reg_addr++; + } + } + } + } + + return rslt; +} + +/*! + * @brief This API initialize the auxiliary sensor + * in order to access it. + */ +int8_t bmi160_aux_init(const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) + { + /* Configures the auxiliary sensor interface settings */ + rslt = config_aux_settg(dev); + } + else + { + rslt = BMI160_E_INVALID_INPUT; + } + } + + return rslt; +} + +/*! + * @brief This API is used to setup the auxiliary sensor of bmi160 in auto mode + * Thus enabling the auto update of 8 bytes of data from auxiliary sensor + * to BMI160 register address 0x04 to 0x0B + */ +int8_t bmi160_set_aux_auto_mode(uint8_t *data_addr, struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + if (dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) + { + /* Write the aux. address to read in 0x4D of BMI160*/ + rslt = bmi160_set_regs(BMI160_AUX_IF_2_ADDR, data_addr, 1, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + if (rslt == BMI160_OK) + { + /* Configure the polling ODR for + * auxiliary sensor */ + rslt = config_aux_odr(dev); + if (rslt == BMI160_OK) + { + /* Disable the aux. manual mode, i.e aux. + * sensor is in auto-mode (data-mode) */ + dev->aux_cfg.manual_enable = BMI160_DISABLE; + rslt = bmi160_config_aux_mode(dev); + + /* Auxiliary sensor data is obtained + * in auto mode from this point */ + } + } + } + else + { + rslt = BMI160_E_INVALID_INPUT; + } + } + + return rslt; +} + +/*! + * @brief This API configures the 0x4C register and settings like + * Auxiliary sensor manual enable/ disable and aux burst read length. + */ +int8_t bmi160_config_aux_mode(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t aux_if[2] = { (uint8_t)(dev->aux_cfg.aux_i2c_addr * 2), 0 }; + + rslt = bmi160_get_regs(BMI160_AUX_IF_1_ADDR, &aux_if[1], 1, dev); + if (rslt == BMI160_OK) + { + /* update the Auxiliary interface to manual/auto mode */ + aux_if[1] = BMI160_SET_BITS(aux_if[1], BMI160_MANUAL_MODE_EN, dev->aux_cfg.manual_enable); + + /* update the burst read length defined by user */ + aux_if[1] = BMI160_SET_BITS_POS_0(aux_if[1], BMI160_AUX_READ_BURST, dev->aux_cfg.aux_rd_burst_len); + + /* Set the secondary interface address and manual mode + * along with burst read length */ + rslt = bmi160_set_regs(BMI160_AUX_IF_0_ADDR, &aux_if[0], 2, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + } + + return rslt; +} + +/*! + * @brief This API is used to read the raw uncompensated auxiliary sensor + * data of 8 bytes from BMI160 register address 0x04 to 0x0B + */ +int8_t bmi160_read_aux_data_auto_mode(uint8_t *aux_data, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + if ((dev->aux_cfg.aux_sensor_enable == BMI160_ENABLE) && (dev->aux_cfg.manual_enable == BMI160_DISABLE)) + { + /* Read the aux. sensor's raw data */ + rslt = bmi160_get_regs(BMI160_AUX_DATA_ADDR, aux_data, 8, dev); + } + else + { + rslt = BMI160_E_INVALID_INPUT; + } + } + + return rslt; +} + +/*! + * @brief This is used to perform self test of accel/gyro of the BMI160 sensor + */ +int8_t bmi160_perform_self_test(uint8_t select_sensor, struct bmi160_dev *dev) +{ + int8_t rslt; + int8_t self_test_rslt = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + + /* Proceed if null check is fine */ + switch (select_sensor) + { + case BMI160_ACCEL_ONLY: + rslt = perform_accel_self_test(dev); + break; + case BMI160_GYRO_ONLY: + + /* Set the power mode as normal mode */ + dev->gyro_cfg.power = BMI160_GYRO_NORMAL_MODE; + rslt = bmi160_set_power_mode(dev); + + /* Perform gyro self test */ + if (rslt == BMI160_OK) + { + /* Perform gyro self test */ + rslt = perform_gyro_self_test(dev); + } + + break; + default: + rslt = BMI160_E_INVALID_INPUT; + break; + } + + /* Check to ensure bus error does not occur */ + if (rslt >= BMI160_OK) + { + /* Store the status of self test result */ + self_test_rslt = rslt; + + /* Perform soft reset */ + rslt = bmi160_soft_reset(dev); + + } + + /* Check to ensure bus operations are success */ + if (rslt == BMI160_OK) + { + /* Restore self_test_rslt as return value */ + rslt = self_test_rslt; + } + } + + return rslt; +} + +/*! + * @brief This API reads the data from fifo buffer. + */ +int8_t bmi160_get_fifo_data(struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint16_t bytes_to_read = 0; + uint16_t user_fifo_len = 0; + + /* check the bmi160 structure as NULL*/ + if ((dev == NULL) || (dev->fifo->data == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + reset_fifo_data_structure(dev); + + /* get current FIFO fill-level*/ + rslt = get_fifo_byte_counter(&bytes_to_read, dev); + if (rslt == BMI160_OK) + { + user_fifo_len = dev->fifo->length; + if ((dev->fifo->length > bytes_to_read)) + { + /* Handling the case where user requests + * more data than available in FIFO */ + dev->fifo->length = bytes_to_read; + } + + if ((dev->fifo->fifo_time_enable == BMI160_FIFO_TIME_ENABLE) && + (bytes_to_read + BMI160_FIFO_BYTES_OVERREAD <= user_fifo_len)) + { + /* Handling case of sensor time availability*/ + dev->fifo->length = dev->fifo->length + BMI160_FIFO_BYTES_OVERREAD; + } + + /* read only the filled bytes in the FIFO Buffer */ + rslt = bmi160_get_regs(BMI160_FIFO_DATA_ADDR, dev->fifo->data, dev->fifo->length, dev); + } + } + + return rslt; +} + +/*! + * @brief This API writes fifo_flush command to command register.This + * action clears all data in the Fifo without changing fifo configuration + * settings + */ +int8_t bmi160_set_fifo_flush(const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t data = BMI160_FIFO_FLUSH_VALUE; + uint8_t reg_addr = BMI160_COMMAND_REG_ADDR; + + /* Check the bmi160_dev structure for NULL address*/ + if (dev == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev); + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO configuration in the sensor. + */ +int8_t bmi160_set_fifo_config(uint8_t config, uint8_t enable, struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint8_t data = 0; + uint8_t reg_addr = BMI160_FIFO_CONFIG_1_ADDR; + uint8_t fifo_config = config & BMI160_FIFO_CONFIG_1_MASK; + + /* Check the bmi160_dev structure for NULL address*/ + if (dev == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev); + if (rslt == BMI160_OK) + { + if (fifo_config > 0) + { + if (enable == BMI160_ENABLE) + { + data = data | fifo_config; + } + else + { + data = data & (~fifo_config); + } + } + + /* write fifo frame content configuration*/ + rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev); + if (rslt == BMI160_OK) + { + /* read fifo frame content configuration*/ + rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev); + if (rslt == BMI160_OK) + { + /* extract fifo header enabled status */ + dev->fifo->fifo_header_enable = data & BMI160_FIFO_HEAD_ENABLE; + + /* extract accel/gyr/aux. data enabled status */ + dev->fifo->fifo_data_enable = data & BMI160_FIFO_M_G_A_ENABLE; + + /* extract fifo sensor time enabled status */ + dev->fifo->fifo_time_enable = data & BMI160_FIFO_TIME_ENABLE; + } + } + } + } + + return rslt; +} + +/*! @brief This API is used to configure the down sampling ratios of + * the accel and gyro data for FIFO.Also, it configures filtered or + * pre-filtered data for accel and gyro. + * + */ +int8_t bmi160_set_fifo_down(uint8_t fifo_down, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t data = 0; + uint8_t reg_addr = BMI160_FIFO_DOWN_ADDR; + + /* Check the bmi160_dev structure for NULL address*/ + if (dev == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_get_regs(reg_addr, &data, BMI160_ONE, dev); + if (rslt == BMI160_OK) + { + data = data | fifo_down; + rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO watermark level in the sensor. + * + */ +int8_t bmi160_set_fifo_wm(uint8_t fifo_wm, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t data = fifo_wm; + uint8_t reg_addr = BMI160_FIFO_CONFIG_0_ADDR; + + /* Check the bmi160_dev structure for NULL address*/ + if (dev == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = bmi160_set_regs(reg_addr, &data, BMI160_ONE, dev); + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the accelerometer frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the "accel_data" structure instance. + */ +int8_t bmi160_extract_accel(struct bmi160_sensor_data *accel_data, uint8_t *accel_length, struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint16_t data_index = 0; + uint16_t data_read_length = 0; + uint8_t accel_index = 0; + uint8_t fifo_data_enable = 0; + + if (dev == NULL || dev->fifo == NULL || dev->fifo->data == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Parsing the FIFO data in header-less mode */ + if (dev->fifo->fifo_header_enable == 0) + { + /* Number of bytes to be parsed from FIFO */ + get_accel_len_to_parse(&data_index, &data_read_length, accel_length, dev); + for (; data_index < data_read_length;) + { + /*Check for the availability of next two bytes of FIFO data */ + check_frame_validity(&data_index, dev); + fifo_data_enable = dev->fifo->fifo_data_enable; + unpack_accel_frame(accel_data, &data_index, &accel_index, fifo_data_enable, dev); + } + + /* update number of accel data read*/ + *accel_length = accel_index; + + /*update the accel byte index*/ + dev->fifo->accel_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + extract_accel_header_mode(accel_data, accel_length, dev); + } + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the gyro frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the "gyro_data" structure instance. + */ +int8_t bmi160_extract_gyro(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length, struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint16_t data_index = 0; + uint16_t data_read_length = 0; + uint8_t gyro_index = 0; + uint8_t fifo_data_enable = 0; + + if (dev == NULL || dev->fifo->data == NULL) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Parsing the FIFO data in header-less mode */ + if (dev->fifo->fifo_header_enable == 0) + { + /* Number of bytes to be parsed from FIFO */ + get_gyro_len_to_parse(&data_index, &data_read_length, gyro_length, dev); + for (; data_index < data_read_length;) + { + /*Check for the availability of next two bytes of FIFO data */ + check_frame_validity(&data_index, dev); + fifo_data_enable = dev->fifo->fifo_data_enable; + unpack_gyro_frame(gyro_data, &data_index, &gyro_index, fifo_data_enable, dev); + } + + /* update number of gyro data read */ + *gyro_length = gyro_index; + + /* update the gyro byte index */ + dev->fifo->gyro_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + extract_gyro_header_mode(gyro_data, gyro_length, dev); + } + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the aux frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the "aux_data" structure instance. + */ +int8_t bmi160_extract_aux(struct bmi160_aux_data *aux_data, uint8_t *aux_len, struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint16_t data_index = 0; + uint16_t data_read_length = 0; + uint8_t aux_index = 0; + uint8_t fifo_data_enable = 0; + + if ((dev == NULL) || (dev->fifo->data == NULL) || (aux_data == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Parsing the FIFO data in header-less mode */ + if (dev->fifo->fifo_header_enable == 0) + { + /* Number of bytes to be parsed from FIFO */ + get_aux_len_to_parse(&data_index, &data_read_length, aux_len, dev); + for (; data_index < data_read_length;) + { + /* Check for the availability of next two + * bytes of FIFO data */ + check_frame_validity(&data_index, dev); + fifo_data_enable = dev->fifo->fifo_data_enable; + unpack_aux_frame(aux_data, &data_index, &aux_index, fifo_data_enable, dev); + } + + /* update number of aux data read */ + *aux_len = aux_index; + + /* update the aux byte index */ + dev->fifo->aux_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + extract_aux_header_mode(aux_data, aux_len, dev); + } + } + + return rslt; +} + +/*! + * @brief This API starts the FOC of accel and gyro + * + * @note FOC should not be used in low-power mode of sensor + * + * @note Accel FOC targets values of +1g , 0g , -1g + * Gyro FOC always targets value of 0 dps + */ +int8_t bmi160_start_foc(const struct bmi160_foc_conf *foc_conf, + struct bmi160_offsets *offset, + struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t data; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Set the offset enable bits */ + rslt = configure_offset_enable(foc_conf, dev); + if (rslt == BMI160_OK) + { + /* Read the FOC config from the sensor */ + rslt = bmi160_get_regs(BMI160_FOC_CONF_ADDR, &data, 1, dev); + + /* Set the FOC config for gyro */ + data = BMI160_SET_BITS(data, BMI160_GYRO_FOC_EN, foc_conf->foc_gyr_en); + + /* Set the FOC config for accel xyz axes */ + data = BMI160_SET_BITS(data, BMI160_ACCEL_FOC_X_CONF, foc_conf->foc_acc_x); + data = BMI160_SET_BITS(data, BMI160_ACCEL_FOC_Y_CONF, foc_conf->foc_acc_y); + data = BMI160_SET_BITS_POS_0(data, BMI160_ACCEL_FOC_Z_CONF, foc_conf->foc_acc_z); + if (rslt == BMI160_OK) + { + /* Set the FOC config in the sensor */ + rslt = bmi160_set_regs(BMI160_FOC_CONF_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* Procedure to trigger + * FOC and check status */ + rslt = trigger_foc(offset, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API reads and stores the offset values of accel and gyro + */ +int8_t bmi160_get_offsets(struct bmi160_offsets *offset, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[7]; + uint8_t lsb, msb; + int16_t offset_msb, offset_lsb; + int16_t offset_data; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Read the FOC config from the sensor */ + rslt = bmi160_get_regs(BMI160_OFFSET_ADDR, data, 7, dev); + + /* Accel offsets */ + offset->off_acc_x = (int8_t)data[0]; + offset->off_acc_y = (int8_t)data[1]; + offset->off_acc_z = (int8_t)data[2]; + + /* Gyro x-axis offset */ + lsb = data[3]; + msb = BMI160_GET_BITS_POS_0(data[6], BMI160_GYRO_OFFSET_X); + offset_msb = (int16_t)(msb << 14); + offset_lsb = lsb << 6; + offset_data = offset_msb | offset_lsb; + + /* Divide by 64 to get the Right shift by 6 value */ + offset->off_gyro_x = (int16_t)(offset_data / 64); + + /* Gyro y-axis offset */ + lsb = data[4]; + msb = BMI160_GET_BITS(data[6], BMI160_GYRO_OFFSET_Y); + offset_msb = (int16_t)(msb << 14); + offset_lsb = lsb << 6; + offset_data = offset_msb | offset_lsb; + + /* Divide by 64 to get the Right shift by 6 value */ + offset->off_gyro_y = (int16_t)(offset_data / 64); + + /* Gyro z-axis offset */ + lsb = data[5]; + msb = BMI160_GET_BITS(data[6], BMI160_GYRO_OFFSET_Z); + offset_msb = (int16_t)(msb << 14); + offset_lsb = lsb << 6; + offset_data = offset_msb | offset_lsb; + + /* Divide by 64 to get the Right shift by 6 value */ + offset->off_gyro_z = (int16_t)(offset_data / 64); + } + + return rslt; +} + +/*! + * @brief This API writes the offset values of accel and gyro to + * the sensor but these values will be reset on POR or soft reset. + */ +int8_t bmi160_set_offsets(const struct bmi160_foc_conf *foc_conf, + const struct bmi160_offsets *offset, + struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t data[7]; + uint8_t x_msb, y_msb, z_msb; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Update the accel offset */ + data[0] = (uint8_t)offset->off_acc_x; + data[1] = (uint8_t)offset->off_acc_y; + data[2] = (uint8_t)offset->off_acc_z; + + /* Update the LSB of gyro offset */ + data[3] = BMI160_GET_LSB(offset->off_gyro_x); + data[4] = BMI160_GET_LSB(offset->off_gyro_y); + data[5] = BMI160_GET_LSB(offset->off_gyro_z); + + /* Update the MSB of gyro offset */ + x_msb = BMI160_GET_BITS(offset->off_gyro_x, BMI160_GYRO_OFFSET); + y_msb = BMI160_GET_BITS(offset->off_gyro_y, BMI160_GYRO_OFFSET); + z_msb = BMI160_GET_BITS(offset->off_gyro_z, BMI160_GYRO_OFFSET); + data[6] = (uint8_t)(z_msb << 4 | y_msb << 2 | x_msb); + + /* Set the offset enable/disable for gyro and accel */ + data[6] = BMI160_SET_BITS(data[6], BMI160_GYRO_OFFSET_EN, foc_conf->gyro_off_en); + data[6] = BMI160_SET_BITS(data[6], BMI160_ACCEL_OFFSET_EN, foc_conf->acc_off_en); + + /* Set the offset config and values in the sensor */ + rslt = bmi160_set_regs(BMI160_OFFSET_ADDR, data, 7, dev); + } + + return rslt; +} + +/*! + * @brief This API writes the image registers values to NVM which is + * stored even after POR or soft reset + */ +int8_t bmi160_update_nvm(struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t data; + uint8_t cmd = BMI160_NVM_BACKUP_EN; + + /* Read the nvm_prog_en configuration */ + rslt = bmi160_get_regs(BMI160_CONF_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + data = BMI160_SET_BITS(data, BMI160_NVM_UPDATE, 1); + + /* Set the nvm_prog_en bit in the sensor */ + rslt = bmi160_set_regs(BMI160_CONF_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* Update NVM */ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &cmd, 1, dev); + if (rslt == BMI160_OK) + { + /* Check for NVM ready status */ + rslt = bmi160_get_regs(BMI160_STATUS_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + data = BMI160_GET_BITS(data, BMI160_NVM_STATUS); + if (data != BMI160_ENABLE) + { + /* Delay to update NVM */ + dev->delay_ms(25); + } + } + } + } + } + + return rslt; +} + +/*! + * @brief This API gets the interrupt status from the sensor. + */ +int8_t bmi160_get_int_status(enum bmi160_int_status_sel int_status_sel, + union bmi160_int_status *int_status, + struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + + /* To get the status of all interrupts */ + if (int_status_sel == BMI160_INT_STATUS_ALL) + { + rslt = bmi160_get_regs(BMI160_INT_STATUS_ADDR, &int_status->data[0], 4, dev); + } + else + { + if (int_status_sel & BMI160_INT_STATUS_0) + { + rslt = bmi160_get_regs(BMI160_INT_STATUS_ADDR, &int_status->data[0], 1, dev); + } + + if (int_status_sel & BMI160_INT_STATUS_1) + { + rslt = bmi160_get_regs(BMI160_INT_STATUS_ADDR + 1, &int_status->data[1], 1, dev); + } + + if (int_status_sel & BMI160_INT_STATUS_2) + { + rslt = bmi160_get_regs(BMI160_INT_STATUS_ADDR + 2, &int_status->data[2], 1, dev); + } + + if (int_status_sel & BMI160_INT_STATUS_3) + { + rslt = bmi160_get_regs(BMI160_INT_STATUS_ADDR + 3, &int_status->data[3], 1, dev); + } + } + + return rslt; +} + +/*********************** Local function definitions ***************************/ + +/*! + * @brief This API sets the any-motion interrupt of the sensor. + * This interrupt occurs when accel values exceeds preset threshold + * for a certain period of time. + */ +static int8_t set_accel_any_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg = &(int_config->int_type_cfg.acc_any_motion_int); + rslt = enable_accel_any_motion_int(any_motion_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_any_motion_int_settg(int_config, any_motion_int_cfg, dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets tap interrupts.Interrupt is fired when + * tap movements happen. + */ +static int8_t set_accel_tap_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_tap_int_cfg *tap_int_cfg = &(int_config->int_type_cfg.acc_tap_int); + rslt = enable_tap_int(int_config, tap_int_cfg, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_tap_int_settg(int_config, tap_int_cfg, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the data ready interrupt for both accel and gyro. + * This interrupt occurs when new accel and gyro data comes. + */ +static int8_t set_accel_gyro_data_ready_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + rslt = enable_data_ready_int(dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_hardware_interrupt(int_config, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the significant motion interrupt of the sensor.This + * interrupt occurs when there is change in user location. + */ +static int8_t set_accel_sig_motion_int(struct bmi160_int_settg *int_config, struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg = &(int_config->int_type_cfg.acc_sig_motion_int); + rslt = enable_sig_motion_int(sig_mot_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_sig_motion_int_settg(int_config, sig_mot_int_cfg, dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets the no motion/slow motion interrupt of the sensor. + * Slow motion is similar to any motion interrupt.No motion interrupt + * occurs when slope bet. two accel values falls below preset threshold + * for preset duration. + */ +static int8_t set_accel_no_motion_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg = &(int_config->int_type_cfg.acc_no_motion_int); + rslt = enable_no_motion_int(no_mot_int_cfg, dev); + if (rslt == BMI160_OK) + { + /* Configure the INT PIN settings*/ + rslt = config_no_motion_int_settg(int_config, no_mot_int_cfg, dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets the step detection interrupt.This interrupt + * occurs when the single step causes accel values to go above + * preset threshold. + */ +static int8_t set_accel_step_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg = &(int_config->int_type_cfg.acc_step_detect_int); + rslt = enable_step_detect_int(step_detect_int_cfg, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_step_detect(step_detect_int_cfg, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the orientation interrupt of the sensor.This + * interrupt occurs when there is orientation change in the sensor + * with respect to gravitational field vector g. + */ +static int8_t set_accel_orientation_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_orient_int_cfg *orient_int_cfg = &(int_config->int_type_cfg.acc_orient_int); + rslt = enable_orient_int(orient_int_cfg, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + /* map INT pin to orient interrupt */ + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + /* configure the + * orientation setting*/ + rslt = config_orient_int_settg(orient_int_cfg, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the flat interrupt of the sensor.This interrupt + * occurs in case of flat orientation + */ +static int8_t set_accel_flat_detect_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_flat_detect_int_cfg *flat_detect_int = &(int_config->int_type_cfg.acc_flat_int); + + /* enable the flat interrupt */ + rslt = enable_flat_int(flat_detect_int, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + /* map INT pin to flat interrupt */ + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + /* configure the flat setting*/ + rslt = config_flat_int_settg(flat_detect_int, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the low-g interrupt of the sensor.This interrupt + * occurs during free-fall. + */ +static int8_t set_accel_low_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_low_g_int_cfg *low_g_int = &(int_config->int_type_cfg.acc_low_g_int); + + /* Enable the low-g interrupt*/ + rslt = enable_low_g_int(low_g_int, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + /* Map INT pin to low-g interrupt */ + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + /* configure the data source + * for low-g interrupt*/ + rslt = config_low_g_data_src(low_g_int, dev); + if (rslt == BMI160_OK) + { + rslt = config_low_g_int_settg(low_g_int, dev); + } + } + } + } + } + + return rslt; +} + +/*! + * @brief This API sets the high-g interrupt of the sensor.The interrupt + * occurs if the absolute value of acceleration data of any enabled axis + * exceeds the programmed threshold and the sign of the value does not + * change for a preset duration. + */ +static int8_t set_accel_high_g_int(struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt != BMI160_OK) || (int_config == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* updating the interrupt structure to local structure */ + struct bmi160_acc_high_g_int_cfg *high_g_int_cfg = &(int_config->int_type_cfg.acc_high_g_int); + + /* Enable the high-g interrupt */ + rslt = enable_high_g_int(high_g_int_cfg, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + /* Map INT pin to high-g interrupt */ + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + /* configure the data source + * for high-g interrupt*/ + rslt = config_high_g_data_src(high_g_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_high_g_int_settg(high_g_int_cfg, dev); + } + } + } + } + } + + return rslt; +} + +/*! + * @brief This API configures the pins to fire the + * interrupt signal when it occurs. + */ +static int8_t set_intr_pin_config(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* configure the behavioural settings of interrupt pin */ + rslt = config_int_out_ctrl(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_int_latch(int_config, dev); + } + + return rslt; +} + +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmi160_dev *dev) +{ + int8_t rslt; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Device structure is fine */ + rslt = BMI160_OK; + } + + return rslt; +} + +/*! + * @brief This API sets the default configuration parameters of accel & gyro. + * Also maintain the previous state of configurations. + */ +static void default_param_settg(struct bmi160_dev *dev) +{ + /* Initializing accel and gyro params with + * default values */ + dev->accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4; + dev->accel_cfg.odr = BMI160_ACCEL_ODR_100HZ; + dev->accel_cfg.power = BMI160_ACCEL_SUSPEND_MODE; + dev->accel_cfg.range = BMI160_ACCEL_RANGE_2G; + dev->gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE; + dev->gyro_cfg.odr = BMI160_GYRO_ODR_100HZ; + dev->gyro_cfg.power = BMI160_GYRO_SUSPEND_MODE; + dev->gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS; + + /* To maintain the previous state of accel configuration */ + dev->prev_accel_cfg = dev->accel_cfg; + + /* To maintain the previous state of gyro configuration */ + dev->prev_gyro_cfg = dev->gyro_cfg; +} + +/*! + * @brief This API set the accel configuration. + */ +static int8_t set_accel_conf(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0 }; + + rslt = check_accel_config(data, dev); + if (rslt == BMI160_OK) + { + /* Write output data rate and bandwidth */ + rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, &data[0], 1, dev); + if (rslt == BMI160_OK) + { + dev->prev_accel_cfg.odr = dev->accel_cfg.odr; + dev->prev_accel_cfg.bw = dev->accel_cfg.bw; + + /* write accel range */ + rslt = bmi160_set_regs(BMI160_ACCEL_RANGE_ADDR, &data[1], 1, dev); + if (rslt == BMI160_OK) + { + dev->prev_accel_cfg.range = dev->accel_cfg.range; + } + } + } + + return rslt; +} + +/*! + * @brief This API gets the accel configuration. + */ +static int8_t get_accel_conf(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0 }; + + /* Get accel configurations */ + rslt = bmi160_get_regs(BMI160_ACCEL_CONFIG_ADDR, data, 2, dev); + if (rslt == BMI160_OK) + { + dev->accel_cfg.odr = (data[0] & BMI160_ACCEL_ODR_MASK); + dev->accel_cfg.bw = (data[0] & BMI160_ACCEL_BW_MASK) >> BMI160_ACCEL_BW_POS; + dev->accel_cfg.range = (data[1] & BMI160_ACCEL_RANGE_MASK); + } + + return rslt; +} + +/*! + * @brief This API check the accel configuration. + */ +static int8_t check_accel_config(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* read accel Output data rate and bandwidth */ + rslt = bmi160_get_regs(BMI160_ACCEL_CONFIG_ADDR, data, 2, dev); + if (rslt == BMI160_OK) + { + rslt = process_accel_odr(&data[0], dev); + if (rslt == BMI160_OK) + { + rslt = process_accel_bw(&data[0], dev); + if (rslt == BMI160_OK) + { + rslt = process_accel_range(&data[1], dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API process the accel odr. + */ +static int8_t process_accel_odr(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t odr = 0; + + if (dev->accel_cfg.odr <= BMI160_ACCEL_ODR_1600HZ) + { + if (dev->accel_cfg.odr != dev->prev_accel_cfg.odr) + { + odr = (uint8_t)dev->accel_cfg.odr; + temp = *data & ~BMI160_ACCEL_ODR_MASK; + + /* Adding output data rate */ + *data = temp | (odr & BMI160_ACCEL_ODR_MASK); + } + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API process the accel bandwidth. + */ +static int8_t process_accel_bw(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t bw = 0; + + if (dev->accel_cfg.bw <= BMI160_ACCEL_BW_RES_AVG128) + { + if (dev->accel_cfg.bw != dev->prev_accel_cfg.bw) + { + bw = (uint8_t)dev->accel_cfg.bw; + temp = *data & ~BMI160_ACCEL_BW_MASK; + + /* Adding bandwidth */ + *data = temp | ((bw << 4) & BMI160_ACCEL_BW_MASK); + } + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API process the accel range. + */ +static int8_t process_accel_range(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t range = 0; + + if (dev->accel_cfg.range <= BMI160_ACCEL_RANGE_16G) + { + if (dev->accel_cfg.range != dev->prev_accel_cfg.range) + { + range = (uint8_t)dev->accel_cfg.range; + temp = *data & ~BMI160_ACCEL_RANGE_MASK; + + /* Adding range */ + *data = temp | (range & BMI160_ACCEL_RANGE_MASK); + } + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API checks the invalid settings for ODR & Bw for + * Accel and Gyro. + */ +static int8_t check_invalid_settg(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + + /* read the error reg */ + rslt = bmi160_get_regs(BMI160_ERROR_REG_ADDR, &data, 1, dev); + data = data >> 1; + data = data & BMI160_ERR_REG_MASK; + if (data == 1) + { + rslt = BMI160_E_ACCEL_ODR_BW_INVALID; + } + else if (data == 2) + { + rslt = BMI160_E_GYRO_ODR_BW_INVALID; + } + else if (data == 3) + { + rslt = BMI160_E_LWP_PRE_FLTR_INT_INVALID; + } + else if (data == 7) + { + rslt = BMI160_E_LWP_PRE_FLTR_INVALID; + } + + return rslt; +} +static int8_t set_gyro_conf(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0 }; + + rslt = check_gyro_config(data, dev); + if (rslt == BMI160_OK) + { + /* Write output data rate and bandwidth */ + rslt = bmi160_set_regs(BMI160_GYRO_CONFIG_ADDR, &data[0], 1, dev); + if (rslt == BMI160_OK) + { + dev->prev_gyro_cfg.odr = dev->gyro_cfg.odr; + dev->prev_gyro_cfg.bw = dev->gyro_cfg.bw; + + /* Write gyro range */ + rslt = bmi160_set_regs(BMI160_GYRO_RANGE_ADDR, &data[1], 1, dev); + if (rslt == BMI160_OK) + { + dev->prev_gyro_cfg.range = dev->gyro_cfg.range; + } + } + } + + return rslt; +} + +/*! + * @brief This API gets the gyro configuration. + */ +static int8_t get_gyro_conf(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0 }; + + /* Get accel configurations */ + rslt = bmi160_get_regs(BMI160_GYRO_CONFIG_ADDR, data, 2, dev); + if (rslt == BMI160_OK) + { + dev->gyro_cfg.odr = (data[0] & BMI160_GYRO_ODR_MASK); + dev->gyro_cfg.bw = (data[0] & BMI160_GYRO_BW_MASK) >> BMI160_GYRO_BW_POS; + dev->gyro_cfg.range = (data[1] & BMI160_GYRO_RANGE_MASK); + } + + return rslt; +} + +/*! + * @brief This API check the gyro configuration. + */ +static int8_t check_gyro_config(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* read gyro Output data rate and bandwidth */ + rslt = bmi160_get_regs(BMI160_GYRO_CONFIG_ADDR, data, 2, dev); + if (rslt == BMI160_OK) + { + rslt = process_gyro_odr(&data[0], dev); + if (rslt == BMI160_OK) + { + rslt = process_gyro_bw(&data[0], dev); + if (rslt == BMI160_OK) + { + rslt = process_gyro_range(&data[1], dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API process the gyro odr. + */ +static int8_t process_gyro_odr(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t odr = 0; + + if (dev->gyro_cfg.odr <= BMI160_GYRO_ODR_3200HZ) + { + if (dev->gyro_cfg.odr != dev->prev_gyro_cfg.odr) + { + odr = (uint8_t)dev->gyro_cfg.odr; + temp = (*data & ~BMI160_GYRO_ODR_MASK); + + /* Adding output data rate */ + *data = temp | (odr & BMI160_GYRO_ODR_MASK); + } + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API process the gyro bandwidth. + */ +static int8_t process_gyro_bw(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t bw = 0; + + if (dev->gyro_cfg.bw <= BMI160_GYRO_BW_NORMAL_MODE) + { + bw = (uint8_t)dev->gyro_cfg.bw; + temp = *data & ~BMI160_GYRO_BW_MASK; + + /* Adding bandwidth */ + *data = temp | ((bw << 4) & BMI160_GYRO_BW_MASK); + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API process the gyro range. + */ +static int8_t process_gyro_range(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t temp = 0; + uint8_t range = 0; + + if (dev->gyro_cfg.range <= BMI160_GYRO_RANGE_125_DPS) + { + if (dev->gyro_cfg.range != dev->prev_gyro_cfg.range) + { + range = (uint8_t)dev->gyro_cfg.range; + temp = *data & ~BMI160_GYRO_RANGE_MASK; + + /* Adding range */ + *data = temp | (range & BMI160_GYRO_RANGE_MASK); + } + } + else + { + rslt = BMI160_E_OUT_OF_RANGE; + } + + return rslt; +} + +/*! + * @brief This API sets the accel power. + */ +static int8_t set_accel_pwr(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + uint8_t data = 0; + + if ((dev->accel_cfg.power >= BMI160_ACCEL_SUSPEND_MODE) && (dev->accel_cfg.power <= BMI160_ACCEL_LOWPOWER_MODE)) + { + if (dev->accel_cfg.power != dev->prev_accel_cfg.power) + { + rslt = process_under_sampling(&data, dev); + if (rslt == BMI160_OK) + { + /* Write accel power */ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &dev->accel_cfg.power, 1, dev); + + /* Add delay of 3.8 ms - refer data sheet table 24*/ + if (dev->prev_accel_cfg.power == BMI160_ACCEL_SUSPEND_MODE) + { + dev->delay_ms(BMI160_ACCEL_DELAY_MS); + } + + dev->prev_accel_cfg.power = dev->accel_cfg.power; + } + } + } + else + { + rslt = BMI160_E_INVALID_CONFIG; + } + + return rslt; +} + +/*! + * @brief This API process the undersampling setting of Accel. + */ +static int8_t process_under_sampling(uint8_t *data, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t pre_filter[2] = { 0 }; + + rslt = bmi160_get_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev); + if (rslt == BMI160_OK) + { + if (dev->accel_cfg.power == BMI160_ACCEL_LOWPOWER_MODE) + { + temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK; + + /* Set under-sampling parameter */ + *data = temp | ((1 << 7) & BMI160_ACCEL_UNDERSAMPLING_MASK); + + /* Write data */ + rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev); + + /* Disable the pre-filter data in low power mode */ + if (rslt == BMI160_OK) + { + /* Disable the Pre-filter data*/ + rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, pre_filter, 2, dev); + } + } + else if (*data & BMI160_ACCEL_UNDERSAMPLING_MASK) + { + temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK; + + /* Disable under-sampling parameter if already enabled */ + *data = temp; + + /* Write data */ + rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API sets the gyro power mode. + */ +static int8_t set_gyro_pwr(struct bmi160_dev *dev) +{ + int8_t rslt = 0; + + if ((dev->gyro_cfg.power == BMI160_GYRO_SUSPEND_MODE) || (dev->gyro_cfg.power == BMI160_GYRO_NORMAL_MODE) || + (dev->gyro_cfg.power == BMI160_GYRO_FASTSTARTUP_MODE)) + { + if (dev->gyro_cfg.power != dev->prev_gyro_cfg.power) + { + /* Write gyro power */ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &dev->gyro_cfg.power, 1, dev); + if (dev->prev_gyro_cfg.power == BMI160_GYRO_SUSPEND_MODE) + { + /* Delay of 80 ms - datasheet Table 24 */ + dev->delay_ms(BMI160_GYRO_DELAY_MS); + } + else if ((dev->prev_gyro_cfg.power == BMI160_GYRO_FASTSTARTUP_MODE) && + (dev->gyro_cfg.power == BMI160_GYRO_NORMAL_MODE)) + { + /* This delay is required for transition from + * fast-startup mode to normal mode - datasheet Table 3 */ + dev->delay_ms(10); + } + else + { + /* do nothing */ + } + + dev->prev_gyro_cfg.power = dev->gyro_cfg.power; + } + } + else + { + rslt = BMI160_E_INVALID_CONFIG; + } + + return rslt; +} + +/*! + * @brief This API reads accel data along with sensor time if time is requested + * by user. Kindly refer the user guide(README.md) for more info. + */ +static int8_t get_accel_data(uint8_t len, struct bmi160_sensor_data *accel, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t idx = 0; + uint8_t data_array[9] = { 0 }; + uint8_t time_0 = 0; + uint16_t time_1 = 0; + uint32_t time_2 = 0; + uint8_t lsb; + uint8_t msb; + int16_t msblsb; + + /* read accel sensor data along with time if requested */ + rslt = bmi160_get_regs(BMI160_ACCEL_DATA_ADDR, data_array, 6 + len, dev); + if (rslt == BMI160_OK) + { + /* Accel Data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->x = msblsb; /* Data in X axis */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->y = msblsb; /* Data in Y axis */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->z = msblsb; /* Data in Z axis */ + if (len == 3) + { + time_0 = data_array[idx++]; + time_1 = (uint16_t)(data_array[idx++] << 8); + time_2 = (uint32_t)(data_array[idx++] << 16); + accel->sensortime = (uint32_t)(time_2 | time_1 | time_0); + } + else + { + accel->sensortime = 0; + } + } + else + { + rslt = BMI160_E_COM_FAIL; + } + + return rslt; +} + +/*! + * @brief This API reads accel data along with sensor time if time is requested + * by user. Kindly refer the user guide(README.md) for more info. + */ +static int8_t get_gyro_data(uint8_t len, struct bmi160_sensor_data *gyro, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t idx = 0; + uint8_t data_array[15] = { 0 }; + uint8_t time_0 = 0; + uint16_t time_1 = 0; + uint32_t time_2 = 0; + uint8_t lsb; + uint8_t msb; + int16_t msblsb; + + if (len == 0) + { + /* read gyro data only */ + rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 6, dev); + if (rslt == BMI160_OK) + { + /* Gyro Data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->x = msblsb; /* Data in X axis */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->y = msblsb; /* Data in Y axis */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->z = msblsb; /* Data in Z axis */ + gyro->sensortime = 0; + } + else + { + rslt = BMI160_E_COM_FAIL; + } + } + else + { + /* read gyro sensor data along with time */ + rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev); + if (rslt == BMI160_OK) + { + /* Gyro Data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->x = msblsb; /* gyro X axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->y = msblsb; /* gyro Y axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->z = msblsb; /* gyro Z axis data */ + idx = idx + 6; + time_0 = data_array[idx++]; + time_1 = (uint16_t)(data_array[idx++] << 8); + time_2 = (uint32_t)(data_array[idx++] << 16); + gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0); + } + else + { + rslt = BMI160_E_COM_FAIL; + } + } + + return rslt; +} + +/*! + * @brief This API reads accel and gyro data along with sensor time + * if time is requested by user. + * Kindly refer the user guide(README.md) for more info. + */ +static int8_t get_accel_gyro_data(uint8_t len, + struct bmi160_sensor_data *accel, + struct bmi160_sensor_data *gyro, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t idx = 0; + uint8_t data_array[15] = { 0 }; + uint8_t time_0 = 0; + uint16_t time_1 = 0; + uint32_t time_2 = 0; + uint8_t lsb; + uint8_t msb; + int16_t msblsb; + + /* read both accel and gyro sensor data + * along with time if requested */ + rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev); + if (rslt == BMI160_OK) + { + /* Gyro Data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->x = msblsb; /* gyro X axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->y = msblsb; /* gyro Y axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + gyro->z = msblsb; /* gyro Z axis data */ + /* Accel Data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->x = (int16_t)msblsb; /* accel X axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->y = (int16_t)msblsb; /* accel Y axis data */ + lsb = data_array[idx++]; + msb = data_array[idx++]; + msblsb = (int16_t)((msb << 8) | lsb); + accel->z = (int16_t)msblsb; /* accel Z axis data */ + if (len == 3) + { + time_0 = data_array[idx++]; + time_1 = (uint16_t)(data_array[idx++] << 8); + time_2 = (uint32_t)(data_array[idx++] << 16); + accel->sensortime = (uint32_t)(time_2 | time_1 | time_0); + gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0); + } + else + { + accel->sensortime = 0; + gyro->sensortime = 0; + } + } + else + { + rslt = BMI160_E_COM_FAIL; + } + + return rslt; +} + +/*! + * @brief This API enables the any-motion interrupt for accel. + */ +static int8_t enable_accel_any_motion_int(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable any motion x, any motion y, any motion z + * in Int Enable 0 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + if (any_motion_int_cfg->anymotion_en == BMI160_ENABLE) + { + temp = data & ~BMI160_ANY_MOTION_X_INT_EN_MASK; + + /* Adding Any_motion x axis */ + data = temp | (any_motion_int_cfg->anymotion_x & BMI160_ANY_MOTION_X_INT_EN_MASK); + temp = data & ~BMI160_ANY_MOTION_Y_INT_EN_MASK; + + /* Adding Any_motion y axis */ + data = temp | ((any_motion_int_cfg->anymotion_y << 1) & BMI160_ANY_MOTION_Y_INT_EN_MASK); + temp = data & ~BMI160_ANY_MOTION_Z_INT_EN_MASK; + + /* Adding Any_motion z axis */ + data = temp | ((any_motion_int_cfg->anymotion_z << 2) & BMI160_ANY_MOTION_Z_INT_EN_MASK); + + /* any-motion feature selected*/ + dev->any_sig_sel = BMI160_ANY_MOTION_ENABLED; + } + else + { + data = data & ~BMI160_ANY_MOTION_ALL_INT_EN_MASK; + + /* neither any-motion feature nor sig-motion selected */ + dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED; + } + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API disable the sig-motion interrupt. + */ +static int8_t disable_sig_motion_int(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Disabling Significant motion interrupt if enabled */ + rslt = bmi160_get_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = (data & BMI160_SIG_MOTION_SEL_MASK); + if (temp) + { + temp = data & ~BMI160_SIG_MOTION_SEL_MASK; + data = temp; + + /* Write data to register */ + rslt = bmi160_set_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API is used to map/unmap the Any/Sig motion, Step det/Low-g, + * Double tap, Single tap, Orientation, Flat, High-G, Nomotion interrupt pins. + */ +static int8_t map_feature_interrupt(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data[3] = { 0, 0, 0 }; + uint8_t temp[3] = { 0, 0, 0 }; + + rslt = bmi160_get_regs(BMI160_INT_MAP_0_ADDR, data, 3, dev); + if (rslt == BMI160_OK) + { + temp[0] = data[0] & ~int_mask_lookup_table[int_config->int_type]; + temp[2] = data[2] & ~int_mask_lookup_table[int_config->int_type]; + switch (int_config->int_channel) + { + case BMI160_INT_CHANNEL_NONE: + data[0] = temp[0]; + data[2] = temp[2]; + break; + case BMI160_INT_CHANNEL_1: + data[0] = temp[0] | int_mask_lookup_table[int_config->int_type]; + data[2] = temp[2]; + break; + case BMI160_INT_CHANNEL_2: + data[2] = temp[2] | int_mask_lookup_table[int_config->int_type]; + data[0] = temp[0]; + break; + case BMI160_INT_CHANNEL_BOTH: + data[0] = temp[0] | int_mask_lookup_table[int_config->int_type]; + data[2] = temp[2] | int_mask_lookup_table[int_config->int_type]; + break; + default: + rslt = BMI160_E_OUT_OF_RANGE; + } + if (rslt == BMI160_OK) + { + rslt = bmi160_set_regs(BMI160_INT_MAP_0_ADDR, data, 3, dev); + } + } + + return rslt; +} + +/*! + * @brief This API is used to map/unmap the Dataready(Accel & Gyro), FIFO full + * and FIFO watermark interrupt. + */ +static int8_t map_hardware_interrupt(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + rslt = bmi160_get_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~int_mask_lookup_table[int_config->int_type]; + temp = temp & ~((uint8_t)(int_mask_lookup_table[int_config->int_type] << 4)); + switch (int_config->int_channel) + { + case BMI160_INT_CHANNEL_NONE: + data = temp; + break; + case BMI160_INT_CHANNEL_1: + data = temp | (uint8_t)((int_mask_lookup_table[int_config->int_type]) << 4); + break; + case BMI160_INT_CHANNEL_2: + data = temp | int_mask_lookup_table[int_config->int_type]; + break; + case BMI160_INT_CHANNEL_BOTH: + data = temp | int_mask_lookup_table[int_config->int_type]; + data = data | (uint8_t)((int_mask_lookup_table[int_config->int_type]) << 4); + break; + default: + rslt = BMI160_E_OUT_OF_RANGE; + } + if (rslt == BMI160_OK) + { + rslt = bmi160_set_regs(BMI160_INT_MAP_1_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for any-motion interrupt. + */ +static int8_t config_any_motion_src(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 1 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_MOTION_SRC_INT_MASK; + data = temp | ((any_motion_int_cfg->anymotion_data_src << 7) & BMI160_MOTION_SRC_INT_MASK); + + /* Write data to DATA 1 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the duration and threshold of + * any-motion interrupt. + */ +static int8_t config_any_dur_threshold(const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + uint8_t data_array[2] = { 0 }; + uint8_t dur; + + /* Configure Int Motion 0 register */ + rslt = bmi160_get_regs(BMI160_INT_MOTION_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* slope duration */ + dur = (uint8_t)any_motion_int_cfg->anymotion_dur; + temp = data & ~BMI160_SLOPE_INT_DUR_MASK; + data = temp | (dur & BMI160_MOTION_SRC_INT_MASK); + data_array[0] = data; + + /* add slope threshold */ + data_array[1] = any_motion_int_cfg->anymotion_thr; + + /* INT MOTION 0 and INT MOTION 1 address lie consecutively, + * hence writing data to respective registers at one go */ + + /* Writing to Int_motion 0 and + * Int_motion 1 Address simultaneously */ + rslt = bmi160_set_regs(BMI160_INT_MOTION_0_ADDR, data_array, 2, dev); + } + + return rslt; +} + +/*! + * @brief This API configure necessary setting of any-motion interrupt. + */ +static int8_t config_any_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_any_mot_int_cfg *any_motion_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = disable_sig_motion_int(dev); + if (rslt == BMI160_OK) + { + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_any_motion_src(any_motion_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_any_dur_threshold(any_motion_int_cfg, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API enable the data ready interrupt. + */ +static int8_t enable_data_ready_int(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable data ready interrupt in Int Enable 1 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_DATA_RDY_INT_EN_MASK; + data = temp | ((1 << 4) & BMI160_DATA_RDY_INT_EN_MASK); + + /* Writing data to INT ENABLE 1 Address */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API enables the no motion/slow motion interrupt. + */ +static int8_t enable_no_motion_int(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable no motion x, no motion y, no motion z + * in Int Enable 2 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + if (no_mot_int_cfg->no_motion_x == 1) + { + temp = data & ~BMI160_NO_MOTION_X_INT_EN_MASK; + + /* Adding No_motion x axis */ + data = temp | (1 & BMI160_NO_MOTION_X_INT_EN_MASK); + } + + if (no_mot_int_cfg->no_motion_y == 1) + { + temp = data & ~BMI160_NO_MOTION_Y_INT_EN_MASK; + + /* Adding No_motion x axis */ + data = temp | ((1 << 1) & BMI160_NO_MOTION_Y_INT_EN_MASK); + } + + if (no_mot_int_cfg->no_motion_z == 1) + { + temp = data & ~BMI160_NO_MOTION_Z_INT_EN_MASK; + + /* Adding No_motion x axis */ + data = temp | ((1 << 2) & BMI160_NO_MOTION_Z_INT_EN_MASK); + } + + /* write data to Int Enable 2 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the interrupt PIN setting for + * no motion/slow motion interrupt. + */ +static int8_t config_no_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_no_motion_data_src(no_mot_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_no_motion_dur_thr(no_mot_int_cfg, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API configure the source of interrupt for no motion. + */ +static int8_t config_no_motion_data_src(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 1 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_MOTION_SRC_INT_MASK; + data = temp | ((no_mot_int_cfg->no_motion_src << 7) & BMI160_MOTION_SRC_INT_MASK); + + /* Write data to DATA 1 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the duration and threshold of + * no motion/slow motion interrupt along with selection of no/slow motion. + */ +static int8_t config_no_motion_dur_thr(const struct bmi160_acc_no_motion_int_cfg *no_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + uint8_t temp_1 = 0; + uint8_t reg_addr; + uint8_t data_array[2] = { 0 }; + + /* Configuring INT_MOTION register */ + reg_addr = BMI160_INT_MOTION_0_ADDR; + rslt = bmi160_get_regs(reg_addr, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_NO_MOTION_INT_DUR_MASK; + + /* Adding no_motion duration */ + data = temp | ((no_mot_int_cfg->no_motion_dur << 2) & BMI160_NO_MOTION_INT_DUR_MASK); + + /* Write data to NO_MOTION 0 address */ + rslt = bmi160_set_regs(reg_addr, &data, 1, dev); + if (rslt == BMI160_OK) + { + reg_addr = BMI160_INT_MOTION_3_ADDR; + rslt = bmi160_get_regs(reg_addr, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_NO_MOTION_SEL_BIT_MASK; + + /* Adding no_motion_sel bit */ + temp_1 = (no_mot_int_cfg->no_motion_sel & BMI160_NO_MOTION_SEL_BIT_MASK); + data = (temp | temp_1); + data_array[1] = data; + + /* Adding no motion threshold */ + data_array[0] = no_mot_int_cfg->no_motion_thres; + reg_addr = BMI160_INT_MOTION_2_ADDR; + + /* writing data to INT_MOTION 2 and INT_MOTION 3 + * address simultaneously */ + rslt = bmi160_set_regs(reg_addr, data_array, 2, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API enables the sig-motion motion interrupt. + */ +static int8_t enable_sig_motion_int(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* For significant motion,enable any motion x,any motion y, + * any motion z in Int Enable 0 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + if (sig_mot_int_cfg->sig_en == BMI160_ENABLE) + { + temp = data & ~BMI160_SIG_MOTION_INT_EN_MASK; + data = temp | (7 & BMI160_SIG_MOTION_INT_EN_MASK); + + /* sig-motion feature selected*/ + dev->any_sig_sel = BMI160_SIG_MOTION_ENABLED; + } + else + { + data = data & ~BMI160_SIG_MOTION_INT_EN_MASK; + + /* neither any-motion feature nor sig-motion selected */ + dev->any_sig_sel = BMI160_BOTH_ANY_SIG_MOTION_DISABLED; + } + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the interrupt PIN setting for + * significant motion interrupt. + */ +static int8_t config_sig_motion_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_sig_motion_data_src(sig_mot_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_sig_dur_threshold(sig_mot_int_cfg, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for sig motion interrupt. + */ +static int8_t config_sig_motion_data_src(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 1 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_MOTION_SRC_INT_MASK; + data = temp | ((sig_mot_int_cfg->sig_data_src << 7) & BMI160_MOTION_SRC_INT_MASK); + + /* Write data to DATA 1 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the threshold, skip and proof time of + * sig motion interrupt. + */ +static int8_t config_sig_dur_threshold(const struct bmi160_acc_sig_mot_int_cfg *sig_mot_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data; + uint8_t temp = 0; + + /* Configuring INT_MOTION registers */ + + /* Write significant motion threshold. + * This threshold is same as any motion threshold */ + data = sig_mot_int_cfg->sig_mot_thres; + + /* Write data to INT_MOTION 1 address */ + rslt = bmi160_set_regs(BMI160_INT_MOTION_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + rslt = bmi160_get_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_SIG_MOTION_SKIP_MASK; + + /* adding skip time of sig_motion interrupt*/ + data = temp | ((sig_mot_int_cfg->sig_mot_skip << 2) & BMI160_SIG_MOTION_SKIP_MASK); + temp = data & ~BMI160_SIG_MOTION_PROOF_MASK; + + /* adding proof time of sig_motion interrupt */ + data = temp | ((sig_mot_int_cfg->sig_mot_proof << 4) & BMI160_SIG_MOTION_PROOF_MASK); + + /* configure the int_sig_mot_sel bit to select + * significant motion interrupt */ + temp = data & ~BMI160_SIG_MOTION_SEL_MASK; + data = temp | ((sig_mot_int_cfg->sig_en << 1) & BMI160_SIG_MOTION_SEL_MASK); + rslt = bmi160_set_regs(BMI160_INT_MOTION_3_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API enables the step detector interrupt. + */ +static int8_t enable_step_detect_int(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable data ready interrupt in Int Enable 2 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_STEP_DETECT_INT_EN_MASK; + data = temp | ((step_detect_int_cfg->step_detector_en << 3) & BMI160_STEP_DETECT_INT_EN_MASK); + + /* Writing data to INT ENABLE 2 Address */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_2_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the step detector parameter. + */ +static int8_t config_step_detect(const struct bmi160_acc_step_detect_int_cfg *step_detect_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data_array[2] = { 0 }; + + if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_NORMAL) + { + /* Normal mode setting */ + data_array[0] = 0x15; + data_array[1] = 0x03; + } + else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_SENSITIVE) + { + /* Sensitive mode setting */ + data_array[0] = 0x2D; + data_array[1] = 0x00; + } + else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_ROBUST) + { + /* Robust mode setting */ + data_array[0] = 0x1D; + data_array[1] = 0x07; + } + else if (step_detect_int_cfg->step_detector_mode == BMI160_STEP_DETECT_USER_DEFINE) + { + /* Non recommended User defined setting */ + /* Configuring STEP_CONFIG register */ + rslt = bmi160_get_regs(BMI160_INT_STEP_CONFIG_0_ADDR, &data_array[0], 2, dev); + if (rslt == BMI160_OK) + { + temp = data_array[0] & ~BMI160_STEP_DETECT_MIN_THRES_MASK; + + /* Adding min_threshold */ + data_array[0] = temp | ((step_detect_int_cfg->min_threshold << 3) & BMI160_STEP_DETECT_MIN_THRES_MASK); + temp = data_array[0] & ~BMI160_STEP_DETECT_STEPTIME_MIN_MASK; + + /* Adding steptime_min */ + data_array[0] = temp | ((step_detect_int_cfg->steptime_min) & BMI160_STEP_DETECT_STEPTIME_MIN_MASK); + temp = data_array[1] & ~BMI160_STEP_MIN_BUF_MASK; + + /* Adding steptime_min */ + data_array[1] = temp | ((step_detect_int_cfg->step_min_buf) & BMI160_STEP_MIN_BUF_MASK); + } + } + + /* Write data to STEP_CONFIG register */ + rslt = bmi160_set_regs(BMI160_INT_STEP_CONFIG_0_ADDR, data_array, 2, dev); + + return rslt; +} + +/*! + * @brief This API enables the single/double tap interrupt. + */ +static int8_t enable_tap_int(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable single tap or double tap interrupt in Int Enable 0 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + if (int_config->int_type == BMI160_ACC_SINGLE_TAP_INT) + { + temp = data & ~BMI160_SINGLE_TAP_INT_EN_MASK; + data = temp | ((tap_int_cfg->tap_en << 5) & BMI160_SINGLE_TAP_INT_EN_MASK); + } + else + { + temp = data & ~BMI160_DOUBLE_TAP_INT_EN_MASK; + data = temp | ((tap_int_cfg->tap_en << 4) & BMI160_DOUBLE_TAP_INT_EN_MASK); + } + + /* Write to Enable 0 Address */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the interrupt PIN setting for + * tap interrupt. + */ +static int8_t config_tap_int_settg(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_feature_interrupt(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = config_tap_data_src(tap_int_cfg, dev); + if (rslt == BMI160_OK) + { + rslt = config_tap_param(int_config, tap_int_cfg, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for tap interrupt. + */ +static int8_t config_tap_data_src(const struct bmi160_acc_tap_int_cfg *tap_int_cfg, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 0 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_TAP_SRC_INT_MASK; + data = temp | ((tap_int_cfg->tap_data_src << 3) & BMI160_TAP_SRC_INT_MASK); + + /* Write data to Data 0 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the parameters of tap interrupt. + * Threshold, quite, shock, and duration. + */ +static int8_t config_tap_param(const struct bmi160_int_settg *int_config, + const struct bmi160_acc_tap_int_cfg *tap_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data = 0; + uint8_t data_array[2] = { 0 }; + uint8_t count = 0; + uint8_t dur, shock, quiet, thres; + + /* Configure tap 0 register for tap shock,tap quiet duration + * in case of single tap interrupt */ + rslt = bmi160_get_regs(BMI160_INT_TAP_0_ADDR, data_array, 2, dev); + if (rslt == BMI160_OK) + { + data = data_array[count]; + if (int_config->int_type == BMI160_ACC_DOUBLE_TAP_INT) + { + dur = (uint8_t)tap_int_cfg->tap_dur; + temp = (data & ~BMI160_TAP_DUR_MASK); + + /* Add tap duration data in case of + * double tap interrupt */ + data = temp | (dur & BMI160_TAP_DUR_MASK); + } + + shock = (uint8_t)tap_int_cfg->tap_shock; + temp = data & ~BMI160_TAP_SHOCK_DUR_MASK; + data = temp | ((shock << 6) & BMI160_TAP_SHOCK_DUR_MASK); + quiet = (uint8_t)tap_int_cfg->tap_quiet; + temp = data & ~BMI160_TAP_QUIET_DUR_MASK; + data = temp | ((quiet << 7) & BMI160_TAP_QUIET_DUR_MASK); + data_array[count++] = data; + data = data_array[count]; + thres = (uint8_t)tap_int_cfg->tap_thr; + temp = data & ~BMI160_TAP_THRES_MASK; + data = temp | (thres & BMI160_TAP_THRES_MASK); + data_array[count++] = data; + + /* TAP 0 and TAP 1 address lie consecutively, + * hence writing data to respective registers at one go */ + + /* Writing to Tap 0 and Tap 1 Address simultaneously */ + rslt = bmi160_set_regs(BMI160_INT_TAP_0_ADDR, data_array, count, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the secondary interface. + */ +static int8_t config_sec_if(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t if_conf = 0; + uint8_t cmd = BMI160_AUX_NORMAL_MODE; + + /* set the aux power mode to normal*/ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &cmd, 1, dev); + if (rslt == BMI160_OK) + { + /* 0.5ms delay - refer datasheet table 24*/ + dev->delay_ms(1); + rslt = bmi160_get_regs(BMI160_IF_CONF_ADDR, &if_conf, 1, dev); + if_conf |= (uint8_t)(1 << 5); + if (rslt == BMI160_OK) + { + /*enable the secondary interface also*/ + rslt = bmi160_set_regs(BMI160_IF_CONF_ADDR, &if_conf, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API configure the ODR of the auxiliary sensor. + */ +static int8_t config_aux_odr(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t aux_odr; + + rslt = bmi160_get_regs(BMI160_AUX_ODR_ADDR, &aux_odr, 1, dev); + if (rslt == BMI160_OK) + { + aux_odr = (uint8_t)(dev->aux_cfg.aux_odr); + + /* Set the secondary interface ODR + * i.e polling rate of secondary sensor */ + rslt = bmi160_set_regs(BMI160_AUX_ODR_ADDR, &aux_odr, 1, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + } + + return rslt; +} + +/*! + * @brief This API maps the actual burst read length set by user. + */ +static int8_t map_read_len(uint16_t *len, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + switch (dev->aux_cfg.aux_rd_burst_len) + { + case BMI160_AUX_READ_LEN_0: + *len = 1; + break; + case BMI160_AUX_READ_LEN_1: + *len = 2; + break; + case BMI160_AUX_READ_LEN_2: + *len = 6; + break; + case BMI160_AUX_READ_LEN_3: + *len = 8; + break; + default: + rslt = BMI160_E_INVALID_INPUT; + break; + } + + return rslt; +} + +/*! + * @brief This API configure the settings of auxiliary sensor. + */ +static int8_t config_aux_settg(const struct bmi160_dev *dev) +{ + int8_t rslt; + + rslt = config_sec_if(dev); + if (rslt == BMI160_OK) + { + /* Configures the auxiliary interface settings */ + rslt = bmi160_config_aux_mode(dev); + } + + return rslt; +} + +/*! + * @brief This API extract the read data from auxiliary sensor. + */ +static int8_t extract_aux_read(uint16_t map_len, + uint8_t reg_addr, + uint8_t *aux_data, + uint16_t len, + const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + uint8_t data[8] = { 0, }; + uint8_t read_addr = BMI160_AUX_DATA_ADDR; + uint8_t count = 0; + uint8_t read_count; + uint8_t read_len = (uint8_t)map_len; + + for (; count < len;) + { + /* set address to read */ + rslt = bmi160_set_regs(BMI160_AUX_IF_2_ADDR, ®_addr, 1, dev); + dev->delay_ms(BMI160_AUX_COM_DELAY); + if (rslt == BMI160_OK) + { + rslt = bmi160_get_regs(read_addr, data, map_len, dev); + if (rslt == BMI160_OK) + { + read_count = 0; + + /* if read len is less the burst read len + * mention by user*/ + if (len < map_len) + { + read_len = (uint8_t)len; + } + else if ((len - count) < map_len) + { + read_len = (uint8_t)(len - count); + } + + for (; read_count < read_len; read_count++) + { + aux_data[count + read_count] = data[read_count]; + } + + reg_addr += (uint8_t)map_len; + count += (uint8_t)map_len; + } + else + { + rslt = BMI160_E_COM_FAIL; + break; + } + } + } + + return rslt; +} + +/*! + * @brief This API enables the orient interrupt. + */ +static int8_t enable_orient_int(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable data ready interrupt in Int Enable 0 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_ORIENT_INT_EN_MASK; + data = temp | ((orient_int_cfg->orient_en << 6) & BMI160_ORIENT_INT_EN_MASK); + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the necessary setting of orientation interrupt. + */ +static int8_t config_orient_int_settg(const struct bmi160_acc_orient_int_cfg *orient_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + uint8_t data_array[2] = { 0, 0 }; + + /* Configuring INT_ORIENT registers */ + rslt = bmi160_get_regs(BMI160_INT_ORIENT_0_ADDR, data_array, 2, dev); + if (rslt == BMI160_OK) + { + data = data_array[0]; + temp = data & ~BMI160_ORIENT_MODE_MASK; + + /* Adding Orientation mode */ + data = temp | ((orient_int_cfg->orient_mode) & BMI160_ORIENT_MODE_MASK); + temp = data & ~BMI160_ORIENT_BLOCK_MASK; + + /* Adding Orientation blocking */ + data = temp | ((orient_int_cfg->orient_blocking << 2) & BMI160_ORIENT_BLOCK_MASK); + temp = data & ~BMI160_ORIENT_HYST_MASK; + + /* Adding Orientation hysteresis */ + data = temp | ((orient_int_cfg->orient_hyst << 4) & BMI160_ORIENT_HYST_MASK); + data_array[0] = data; + data = data_array[1]; + temp = data & ~BMI160_ORIENT_THETA_MASK; + + /* Adding Orientation threshold */ + data = temp | ((orient_int_cfg->orient_theta) & BMI160_ORIENT_THETA_MASK); + temp = data & ~BMI160_ORIENT_UD_ENABLE; + + /* Adding Orient_ud_en */ + data = temp | ((orient_int_cfg->orient_ud_en << 6) & BMI160_ORIENT_UD_ENABLE); + temp = data & ~BMI160_AXES_EN_MASK; + + /* Adding axes_en */ + data = temp | ((orient_int_cfg->axes_ex << 7) & BMI160_AXES_EN_MASK); + data_array[1] = data; + + /* Writing data to INT_ORIENT 0 and INT_ORIENT 1 + * registers simultaneously */ + rslt = bmi160_set_regs(BMI160_INT_ORIENT_0_ADDR, data_array, 2, dev); + } + + return rslt; +} + +/*! + * @brief This API enables the flat interrupt. + */ +static int8_t enable_flat_int(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable flat interrupt in Int Enable 0 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_FLAT_INT_EN_MASK; + data = temp | ((flat_int->flat_en << 7) & BMI160_FLAT_INT_EN_MASK); + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the necessary setting of flat interrupt. + */ +static int8_t config_flat_int_settg(const struct bmi160_acc_flat_detect_int_cfg *flat_int, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + uint8_t data_array[2] = { 0, 0 }; + + /* Configuring INT_FLAT register */ + rslt = bmi160_get_regs(BMI160_INT_FLAT_0_ADDR, data_array, 2, dev); + if (rslt == BMI160_OK) + { + data = data_array[0]; + temp = data & ~BMI160_FLAT_THRES_MASK; + + /* Adding flat theta */ + data = temp | ((flat_int->flat_theta) & BMI160_FLAT_THRES_MASK); + data_array[0] = data; + data = data_array[1]; + temp = data & ~BMI160_FLAT_HOLD_TIME_MASK; + + /* Adding flat hold time */ + data = temp | ((flat_int->flat_hold_time << 4) & BMI160_FLAT_HOLD_TIME_MASK); + temp = data & ~BMI160_FLAT_HYST_MASK; + + /* Adding flat hysteresis */ + data = temp | ((flat_int->flat_hy) & BMI160_FLAT_HYST_MASK); + data_array[1] = data; + + /* Writing data to INT_FLAT 0 and INT_FLAT 1 + * registers simultaneously */ + rslt = bmi160_set_regs(BMI160_INT_FLAT_0_ADDR, data_array, 2, dev); + } + + return rslt; +} + +/*! + * @brief This API enables the Low-g interrupt. + */ +static int8_t enable_low_g_int(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable low-g interrupt in Int Enable 1 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_LOW_G_INT_EN_MASK; + data = temp | ((low_g_int->low_en << 3) & BMI160_LOW_G_INT_EN_MASK); + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for low-g interrupt. + */ +static int8_t config_low_g_data_src(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 0 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_LOW_HIGH_SRC_INT_MASK; + data = temp | ((low_g_int->low_data_src << 7) & BMI160_LOW_HIGH_SRC_INT_MASK); + + /* Write data to Data 0 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the necessary setting of low-g interrupt. + */ +static int8_t config_low_g_int_settg(const struct bmi160_acc_low_g_int_cfg *low_g_int, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data_array[3] = { 0, 0, 0 }; + + /* Configuring INT_LOWHIGH register for low-g interrupt */ + rslt = bmi160_get_regs(BMI160_INT_LOWHIGH_2_ADDR, &data_array[2], 1, dev); + if (rslt == BMI160_OK) + { + temp = data_array[2] & ~BMI160_LOW_G_HYST_MASK; + + /* Adding low-g hysteresis */ + data_array[2] = temp | (low_g_int->low_hyst & BMI160_LOW_G_HYST_MASK); + temp = data_array[2] & ~BMI160_LOW_G_LOW_MODE_MASK; + + /* Adding low-mode */ + data_array[2] = temp | ((low_g_int->low_mode << 2) & BMI160_LOW_G_LOW_MODE_MASK); + + /* Adding low-g threshold */ + data_array[1] = low_g_int->low_thres; + + /* Adding low-g interrupt delay */ + data_array[0] = low_g_int->low_dur; + + /* Writing data to INT_LOWHIGH 0,1,2 registers simultaneously*/ + rslt = bmi160_set_regs(BMI160_INT_LOWHIGH_0_ADDR, data_array, 3, dev); + } + + return rslt; +} + +/*! + * @brief This API enables the high-g interrupt. + */ +static int8_t enable_high_g_int(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Enable low-g interrupt in Int Enable 1 register */ + rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* Adding high-g X-axis */ + temp = data & ~BMI160_HIGH_G_X_INT_EN_MASK; + data = temp | (high_g_int_cfg->high_g_x & BMI160_HIGH_G_X_INT_EN_MASK); + + /* Adding high-g Y-axis */ + temp = data & ~BMI160_HIGH_G_Y_INT_EN_MASK; + data = temp | ((high_g_int_cfg->high_g_y << 1) & BMI160_HIGH_G_Y_INT_EN_MASK); + + /* Adding high-g Z-axis */ + temp = data & ~BMI160_HIGH_G_Z_INT_EN_MASK; + data = temp | ((high_g_int_cfg->high_g_z << 2) & BMI160_HIGH_G_Z_INT_EN_MASK); + + /* write data to Int Enable 0 register */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the source of data(filter & pre-filter) + * for high-g interrupt. + */ +static int8_t config_high_g_data_src(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + uint8_t temp = 0; + + /* Configure Int data 0 register to add source of interrupt */ + rslt = bmi160_get_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + temp = data & ~BMI160_LOW_HIGH_SRC_INT_MASK; + data = temp | ((high_g_int_cfg->high_data_src << 7) & BMI160_LOW_HIGH_SRC_INT_MASK); + + /* Write data to Data 0 address */ + rslt = bmi160_set_regs(BMI160_INT_DATA_0_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the necessary setting of high-g interrupt. + */ +static int8_t config_high_g_int_settg(const struct bmi160_acc_high_g_int_cfg *high_g_int_cfg, + const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data_array[3] = { 0, 0, 0 }; + + rslt = bmi160_get_regs(BMI160_INT_LOWHIGH_2_ADDR, &data_array[0], 1, dev); + if (rslt == BMI160_OK) + { + temp = data_array[0] & ~BMI160_HIGH_G_HYST_MASK; + + /* Adding high-g hysteresis */ + data_array[0] = temp | ((high_g_int_cfg->high_hy << 6) & BMI160_HIGH_G_HYST_MASK); + + /* Adding high-g duration */ + data_array[1] = high_g_int_cfg->high_dur; + + /* Adding high-g threshold */ + data_array[2] = high_g_int_cfg->high_thres; + rslt = bmi160_set_regs(BMI160_INT_LOWHIGH_2_ADDR, data_array, 3, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the behavioural setting of interrupt pin. + */ +static int8_t config_int_out_ctrl(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data = 0; + + /* Configuration of output interrupt signals on pins INT1 and INT2 are + * done in BMI160_INT_OUT_CTRL_ADDR register*/ + rslt = bmi160_get_regs(BMI160_INT_OUT_CTRL_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* updating the interrupt pin structure to local structure */ + const struct bmi160_int_pin_settg *intr_pin_sett = &(int_config->int_pin_settg); + + /* Configuring channel 1 */ + if (int_config->int_channel == BMI160_INT_CHANNEL_1) + { + /* Output enable */ + temp = data & ~BMI160_INT1_OUTPUT_EN_MASK; + data = temp | ((intr_pin_sett->output_en << 3) & BMI160_INT1_OUTPUT_EN_MASK); + + /* Output mode */ + temp = data & ~BMI160_INT1_OUTPUT_MODE_MASK; + data = temp | ((intr_pin_sett->output_mode << 2) & BMI160_INT1_OUTPUT_MODE_MASK); + + /* Output type */ + temp = data & ~BMI160_INT1_OUTPUT_TYPE_MASK; + data = temp | ((intr_pin_sett->output_type << 1) & BMI160_INT1_OUTPUT_TYPE_MASK); + + /* edge control */ + temp = data & ~BMI160_INT1_EDGE_CTRL_MASK; + data = temp | ((intr_pin_sett->edge_ctrl) & BMI160_INT1_EDGE_CTRL_MASK); + } + else + { + /* Configuring channel 2 */ + /* Output enable */ + temp = data & ~BMI160_INT2_OUTPUT_EN_MASK; + data = temp | ((intr_pin_sett->output_en << 7) & BMI160_INT2_OUTPUT_EN_MASK); + + /* Output mode */ + temp = data & ~BMI160_INT2_OUTPUT_MODE_MASK; + data = temp | ((intr_pin_sett->output_mode << 6) & BMI160_INT2_OUTPUT_MODE_MASK); + + /* Output type */ + temp = data & ~BMI160_INT2_OUTPUT_TYPE_MASK; + data = temp | ((intr_pin_sett->output_type << 5) & BMI160_INT2_OUTPUT_TYPE_MASK); + + /* edge control */ + temp = data & ~BMI160_INT2_EDGE_CTRL_MASK; + data = temp | ((intr_pin_sett->edge_ctrl << 4) & BMI160_INT2_EDGE_CTRL_MASK); + } + + rslt = bmi160_set_regs(BMI160_INT_OUT_CTRL_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API configure the mode(input enable, latch or non-latch) of interrupt pin. + */ +static int8_t config_int_latch(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t temp = 0; + uint8_t data = 0; + + /* Configuration of latch on pins INT1 and INT2 are done in + * BMI160_INT_LATCH_ADDR register*/ + rslt = bmi160_get_regs(BMI160_INT_LATCH_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* updating the interrupt pin structure to local structure */ + const struct bmi160_int_pin_settg *intr_pin_sett = &(int_config->int_pin_settg); + if (int_config->int_channel == BMI160_INT_CHANNEL_1) + { + /* Configuring channel 1 */ + /* Input enable */ + temp = data & ~BMI160_INT1_INPUT_EN_MASK; + data = temp | ((intr_pin_sett->input_en << 4) & BMI160_INT1_INPUT_EN_MASK); + } + else + { + /* Configuring channel 2 */ + /* Input enable */ + temp = data & ~BMI160_INT2_INPUT_EN_MASK; + data = temp | ((intr_pin_sett->input_en << 5) & BMI160_INT2_INPUT_EN_MASK); + } + + /* In case of latch interrupt,update the latch duration */ + + /* Latching holds the interrupt for the amount of latch + * duration time */ + temp = data & ~BMI160_INT_LATCH_MASK; + data = temp | (intr_pin_sett->latch_dur & BMI160_INT_LATCH_MASK); + + /* OUT_CTRL_INT and LATCH_INT address lie consecutively, + * hence writing data to respective registers at one go */ + rslt = bmi160_set_regs(BMI160_INT_LATCH_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API performs the self test for accelerometer of BMI160 + */ +static int8_t perform_accel_self_test(struct bmi160_dev *dev) +{ + int8_t rslt; + struct bmi160_sensor_data accel_pos, accel_neg; + + /* Enable Gyro self test bit */ + rslt = enable_accel_self_test(dev); + if (rslt == BMI160_OK) + { + /* Perform accel self test with positive excitation */ + rslt = accel_self_test_positive_excitation(&accel_pos, dev); + if (rslt == BMI160_OK) + { + /* Perform accel self test with negative excitation */ + rslt = accel_self_test_negative_excitation(&accel_neg, dev); + if (rslt == BMI160_OK) + { + /* Validate the self test result */ + rslt = validate_accel_self_test(&accel_pos, &accel_neg); + } + } + } + + return rslt; +} + +/*! + * @brief This API enables to perform the accel self test by setting proper + * configurations to facilitate accel self test + */ +static int8_t enable_accel_self_test(struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Set the Accel power mode as normal mode */ + dev->accel_cfg.power = BMI160_ACCEL_NORMAL_MODE; + + /* Set the sensor range configuration as 8G */ + dev->accel_cfg.range = BMI160_ACCEL_RANGE_8G; + rslt = bmi160_set_sens_conf(dev); + if (rslt == BMI160_OK) + { + /* Accel configurations are set to facilitate self test + * acc_odr - 1600Hz ; acc_bwp = 2 ; acc_us = 0 */ + reg_data = BMI160_ACCEL_SELF_TEST_CONFIG; + rslt = bmi160_set_regs(BMI160_ACCEL_CONFIG_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API performs accel self test with positive excitation + */ +static int8_t accel_self_test_positive_excitation(struct bmi160_sensor_data *accel_pos, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Enable accel self test with positive self-test excitation + * and with amplitude of deflection set as high */ + reg_data = BMI160_ACCEL_SELF_TEST_POSITIVE_EN; + rslt = bmi160_set_regs(BMI160_SELF_TEST_ADDR, ®_data, 1, dev); + if (rslt == BMI160_OK) + { + /* Read the data after a delay of 50ms - refer datasheet 2.8.1 accel self test*/ + dev->delay_ms(BMI160_ACCEL_SELF_TEST_DELAY); + rslt = bmi160_get_sensor_data(BMI160_ACCEL_ONLY, accel_pos, NULL, dev); + } + + return rslt; +} + +/*! + * @brief This API performs accel self test with negative excitation + */ +static int8_t accel_self_test_negative_excitation(struct bmi160_sensor_data *accel_neg, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Enable accel self test with negative self-test excitation + * and with amplitude of deflection set as high */ + reg_data = BMI160_ACCEL_SELF_TEST_NEGATIVE_EN; + rslt = bmi160_set_regs(BMI160_SELF_TEST_ADDR, ®_data, 1, dev); + if (rslt == BMI160_OK) + { + /* Read the data after a delay of 50ms */ + dev->delay_ms(BMI160_ACCEL_SELF_TEST_DELAY); + rslt = bmi160_get_sensor_data(BMI160_ACCEL_ONLY, accel_neg, NULL, dev); + } + + return rslt; +} + +/*! + * @brief This API validates the accel self test results + */ +static int8_t validate_accel_self_test(const struct bmi160_sensor_data *accel_pos, + const struct bmi160_sensor_data *accel_neg) +{ + int8_t rslt; + + /* Validate the results of self test */ + if (((accel_neg->x - accel_pos->x) > BMI160_ACCEL_SELF_TEST_LIMIT) && + ((accel_neg->y - accel_pos->y) > BMI160_ACCEL_SELF_TEST_LIMIT) && + ((accel_neg->z - accel_pos->z) > BMI160_ACCEL_SELF_TEST_LIMIT)) + { + /* Self test pass condition */ + rslt = BMI160_OK; + } + else + { + rslt = BMI160_W_ACCEl_SELF_TEST_FAIL; + } + + return rslt; +} + +/*! + * @brief This API performs the self test for gyroscope of BMI160 + */ +static int8_t perform_gyro_self_test(const struct bmi160_dev *dev) +{ + int8_t rslt; + + /* Enable Gyro self test bit */ + rslt = enable_gyro_self_test(dev); + if (rslt == BMI160_OK) + { + /* Validate the gyro self test a delay of 50ms */ + dev->delay_ms(50); + + /* Validate the gyro self test results */ + rslt = validate_gyro_self_test(dev); + } + + return rslt; +} + +/*! + * @brief This API enables the self test bit to trigger self test for Gyro + */ +static int8_t enable_gyro_self_test(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Enable the Gyro self test bit to trigger the self test */ + rslt = bmi160_get_regs(BMI160_SELF_TEST_ADDR, ®_data, 1, dev); + if (rslt == BMI160_OK) + { + reg_data = BMI160_SET_BITS(reg_data, BMI160_GYRO_SELF_TEST, 1); + rslt = bmi160_set_regs(BMI160_SELF_TEST_ADDR, ®_data, 1, dev); + if (rslt == BMI160_OK) + { + /* Delay to enable gyro self test */ + dev->delay_ms(15); + } + } + + return rslt; +} + +/*! + * @brief This API validates the self test results of Gyro + */ +static int8_t validate_gyro_self_test(const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Validate the Gyro self test result */ + rslt = bmi160_get_regs(BMI160_STATUS_ADDR, ®_data, 1, dev); + if (rslt == BMI160_OK) + { + + reg_data = BMI160_GET_BITS(reg_data, BMI160_GYRO_SELF_TEST_STATUS); + if (reg_data == BMI160_ENABLE) + { + /* Gyro self test success case */ + rslt = BMI160_OK; + } + else + { + rslt = BMI160_W_GYRO_SELF_TEST_FAIL; + } + } + + return rslt; +} + +/*! + * @brief This API sets FIFO full interrupt of the sensor.This interrupt + * occurs when the FIFO is full and the next full data sample would cause + * a FIFO overflow, which may delete the old samples. + */ +static int8_t set_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + /* Null-pointer check */ + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /*enable the fifo full interrupt */ + rslt = enable_fifo_full_int(int_config, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_hardware_interrupt(int_config, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This enable the FIFO full interrupt engine. + */ +static int8_t enable_fifo_full_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + + rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + data = BMI160_SET_BITS(data, BMI160_FIFO_FULL_INT, int_config->fifo_full_int_en); + + /* Writing data to INT ENABLE 1 Address */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API sets FIFO watermark interrupt of the sensor.The FIFO + * watermark interrupt is fired, when the FIFO fill level is above a fifo + * watermark. + */ +static int8_t set_fifo_watermark_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt = BMI160_OK; + + if ((dev == NULL) || (dev->delay_ms == NULL)) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Enable fifo-watermark interrupt in Int Enable 1 register */ + rslt = enable_fifo_wtm_int(int_config, dev); + if (rslt == BMI160_OK) + { + /* Configure Interrupt pins */ + rslt = set_intr_pin_config(int_config, dev); + if (rslt == BMI160_OK) + { + rslt = map_hardware_interrupt(int_config, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This enable the FIFO watermark interrupt engine. + */ +static int8_t enable_fifo_wtm_int(const struct bmi160_int_settg *int_config, const struct bmi160_dev *dev) +{ + int8_t rslt; + uint8_t data = 0; + + rslt = bmi160_get_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + data = BMI160_SET_BITS(data, BMI160_FIFO_WTM_INT, int_config->fifo_wtm_int_en); + + /* Writing data to INT ENABLE 1 Address */ + rslt = bmi160_set_regs(BMI160_INT_ENABLE_1_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API is used to reset the FIFO related configurations + * in the fifo_frame structure. + */ +static void reset_fifo_data_structure(const struct bmi160_dev *dev) +{ + /*Prepare for next FIFO read by resetting FIFO's + * internal data structures*/ + dev->fifo->accel_byte_start_idx = 0; + dev->fifo->gyro_byte_start_idx = 0; + dev->fifo->aux_byte_start_idx = 0; + dev->fifo->sensor_time = 0; + dev->fifo->skipped_frame_count = 0; +} + +/*! + * @brief This API is used to read fifo_byte_counter value (i.e) + * current fill-level in Fifo buffer. + */ +static int8_t get_fifo_byte_counter(uint16_t *bytes_to_read, struct bmi160_dev const *dev) +{ + int8_t rslt = 0; + uint8_t data[2]; + uint8_t addr = BMI160_FIFO_LENGTH_ADDR; + + rslt |= bmi160_get_regs(addr, data, 2, dev); + data[1] = data[1] & BMI160_FIFO_BYTE_COUNTER_MASK; + + /* Available data in FIFO is stored in bytes_to_read*/ + *bytes_to_read = (((uint16_t)data[1] << 8) | ((uint16_t)data[0])); + + return rslt; +} + +/*! + * @brief This API is used to compute the number of bytes of accel FIFO data + * which is to be parsed in header-less mode + */ +static void get_accel_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *acc_frame_count, + const struct bmi160_dev *dev) +{ + /* Data start index */ + *data_index = dev->fifo->accel_byte_start_idx; + if (dev->fifo->fifo_data_enable == BMI160_FIFO_A_ENABLE) + { + *data_read_length = (*acc_frame_count) * BMI160_FIFO_A_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_A_ENABLE) + { + *data_read_length = (*acc_frame_count) * BMI160_FIFO_GA_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_A_ENABLE) + { + *data_read_length = (*acc_frame_count) * BMI160_FIFO_MA_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_A_ENABLE) + { + *data_read_length = (*acc_frame_count) * BMI160_FIFO_MGA_LENGTH; + } + else + { + /* When accel is not enabled ,there will be no accel data. + * so we update the data index as complete */ + *data_index = dev->fifo->length; + } + + if (*data_read_length > dev->fifo->length) + { + /* Handling the case where more data is requested + * than that is available*/ + *data_read_length = dev->fifo->length; + } +} + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed. + */ +static void unpack_accel_frame(struct bmi160_sensor_data *acc, + uint16_t *idx, + uint8_t *acc_idx, + uint8_t frame_info, + const struct bmi160_dev *dev) +{ + switch (frame_info) + { + case BMI160_FIFO_HEAD_A: + case BMI160_FIFO_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_A_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into the structure instance "acc" */ + unpack_accel_data(&acc[*acc_idx], *idx, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_A_LENGTH; + (*acc_idx)++; + break; + case BMI160_FIFO_HEAD_G_A: + case BMI160_FIFO_G_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_GA_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "acc"*/ + unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_G_LENGTH, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_GA_LENGTH; + (*acc_idx)++; + break; + case BMI160_FIFO_HEAD_M_A: + case BMI160_FIFO_M_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_MA_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "acc"*/ + unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_M_LENGTH, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_MA_LENGTH; + (*acc_idx)++; + break; + case BMI160_FIFO_HEAD_M_G_A: + case BMI160_FIFO_M_G_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_MGA_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "acc"*/ + unpack_accel_data(&acc[*acc_idx], *idx + BMI160_FIFO_MG_LENGTH, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_MGA_LENGTH; + (*acc_idx)++; + break; + case BMI160_FIFO_HEAD_M: + case BMI160_FIFO_M_ENABLE: + (*idx) = (*idx) + BMI160_FIFO_M_LENGTH; + break; + case BMI160_FIFO_HEAD_G: + case BMI160_FIFO_G_ENABLE: + (*idx) = (*idx) + BMI160_FIFO_G_LENGTH; + break; + case BMI160_FIFO_HEAD_M_G: + case BMI160_FIFO_M_G_ENABLE: + (*idx) = (*idx) + BMI160_FIFO_MG_LENGTH; + break; + default: + break; + } +} + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data and store it in the instance of the structure bmi160_sensor_data. + */ +static void unpack_accel_data(struct bmi160_sensor_data *accel_data, + uint16_t data_start_index, + const struct bmi160_dev *dev) +{ + uint16_t data_lsb; + uint16_t data_msb; + + /* Accel raw x data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + accel_data->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Accel raw y data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + accel_data->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Accel raw z data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + accel_data->z = (int16_t)((data_msb << 8) | data_lsb); +} + +/*! + * @brief This API is used to parse the accelerometer data from the + * FIFO data in header mode. + */ +static void extract_accel_header_mode(struct bmi160_sensor_data *accel_data, + uint8_t *accel_length, + const struct bmi160_dev *dev) +{ + uint8_t frame_header = 0; + uint16_t data_index; + uint8_t accel_index = 0; + + for (data_index = dev->fifo->accel_byte_start_idx; data_index < dev->fifo->length;) + { + /* extracting Frame header */ + frame_header = (dev->fifo->data[data_index] & BMI160_FIFO_TAG_INTR_MASK); + + /*Index is moved to next byte where the data is starting*/ + data_index++; + switch (frame_header) + { + /* Accel frame */ + case BMI160_FIFO_HEAD_A: + case BMI160_FIFO_HEAD_M_A: + case BMI160_FIFO_HEAD_G_A: + case BMI160_FIFO_HEAD_M_G_A: + unpack_accel_frame(accel_data, &data_index, &accel_index, frame_header, dev); + break; + case BMI160_FIFO_HEAD_M: + move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_G: + move_next_frame(&data_index, BMI160_FIFO_G_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_M_G: + move_next_frame(&data_index, BMI160_FIFO_MG_LENGTH, dev); + break; + + /* Sensor time frame */ + case BMI160_FIFO_HEAD_SENSOR_TIME: + unpack_sensortime_frame(&data_index, dev); + break; + + /* Skip frame */ + case BMI160_FIFO_HEAD_SKIP_FRAME: + unpack_skipped_frame(&data_index, dev); + break; + + /* Input config frame */ + case BMI160_FIFO_HEAD_INPUT_CONFIG: + move_next_frame(&data_index, 1, dev); + break; + case BMI160_FIFO_HEAD_OVER_READ: + + /* Update the data index as complete in case of Over read */ + data_index = dev->fifo->length; + break; + default: + break; + } + if (*accel_length == accel_index) + { + /* Number of frames to read completed */ + break; + } + } + + /*Update number of accel data read*/ + *accel_length = accel_index; + + /*Update the accel frame index*/ + dev->fifo->accel_byte_start_idx = data_index; +} + +/*! + * @brief This API computes the number of bytes of gyro FIFO data + * which is to be parsed in header-less mode + */ +static void get_gyro_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *gyro_frame_count, + const struct bmi160_dev *dev) +{ + /* Data start index */ + *data_index = dev->fifo->gyro_byte_start_idx; + if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_ENABLE) + { + *data_read_length = (*gyro_frame_count) * BMI160_FIFO_G_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_G_A_ENABLE) + { + *data_read_length = (*gyro_frame_count) * BMI160_FIFO_GA_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_ENABLE) + { + *data_read_length = (*gyro_frame_count) * BMI160_FIFO_MG_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_A_ENABLE) + { + *data_read_length = (*gyro_frame_count) * BMI160_FIFO_MGA_LENGTH; + } + else + { + /* When gyro is not enabled ,there will be no gyro data. + * so we update the data index as complete */ + *data_index = dev->fifo->length; + } + + if (*data_read_length > dev->fifo->length) + { + /* Handling the case where more data is requested + * than that is available*/ + *data_read_length = dev->fifo->length; + } +} + +/*! + * @brief This API is used to parse the gyroscope's data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed. + */ +static void unpack_gyro_frame(struct bmi160_sensor_data *gyro, + uint16_t *idx, + uint8_t *gyro_idx, + uint8_t frame_info, + const struct bmi160_dev *dev) +{ + switch (frame_info) + { + case BMI160_FIFO_HEAD_G: + case BMI160_FIFO_G_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_G_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "gyro"*/ + unpack_gyro_data(&gyro[*gyro_idx], *idx, dev); + + /*Move the data index*/ + (*idx) = (*idx) + BMI160_FIFO_G_LENGTH; + (*gyro_idx)++; + break; + case BMI160_FIFO_HEAD_G_A: + case BMI160_FIFO_G_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_GA_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /* Unpack the data array into structure instance "gyro" */ + unpack_gyro_data(&gyro[*gyro_idx], *idx, dev); + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_GA_LENGTH; + (*gyro_idx)++; + break; + case BMI160_FIFO_HEAD_M_G_A: + case BMI160_FIFO_M_G_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_MGA_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "gyro"*/ + unpack_gyro_data(&gyro[*gyro_idx], *idx + BMI160_FIFO_M_LENGTH, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_MGA_LENGTH; + (*gyro_idx)++; + break; + case BMI160_FIFO_HEAD_M_A: + case BMI160_FIFO_M_A_ENABLE: + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_MA_LENGTH; + break; + case BMI160_FIFO_HEAD_M: + case BMI160_FIFO_M_ENABLE: + (*idx) = (*idx) + BMI160_FIFO_M_LENGTH; + break; + case BMI160_FIFO_HEAD_M_G: + case BMI160_FIFO_M_G_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_MG_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *idx = dev->fifo->length; + break; + } + + /*Unpack the data array into structure instance "gyro"*/ + unpack_gyro_data(&gyro[*gyro_idx], *idx + BMI160_FIFO_M_LENGTH, dev); + + /*Move the data index*/ + (*idx) = (*idx) + BMI160_FIFO_MG_LENGTH; + (*gyro_idx)++; + break; + case BMI160_FIFO_HEAD_A: + case BMI160_FIFO_A_ENABLE: + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_A_LENGTH; + break; + default: + break; + } +} + +/*! + * @brief This API is used to parse the gyro data from the + * FIFO data and store it in the instance of the structure bmi160_sensor_data. + */ +static void unpack_gyro_data(struct bmi160_sensor_data *gyro_data, + uint16_t data_start_index, + const struct bmi160_dev *dev) +{ + uint16_t data_lsb; + uint16_t data_msb; + + /* Gyro raw x data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + gyro_data->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyro raw y data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + gyro_data->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyro raw z data */ + data_lsb = dev->fifo->data[data_start_index++]; + data_msb = dev->fifo->data[data_start_index++]; + gyro_data->z = (int16_t)((data_msb << 8) | data_lsb); +} + +/*! + * @brief This API is used to parse the gyro data from the + * FIFO data in header mode. + */ +static void extract_gyro_header_mode(struct bmi160_sensor_data *gyro_data, + uint8_t *gyro_length, + const struct bmi160_dev *dev) +{ + uint8_t frame_header = 0; + uint16_t data_index; + uint8_t gyro_index = 0; + + for (data_index = dev->fifo->gyro_byte_start_idx; data_index < dev->fifo->length;) + { + /* extracting Frame header */ + frame_header = (dev->fifo->data[data_index] & BMI160_FIFO_TAG_INTR_MASK); + + /*Index is moved to next byte where the data is starting*/ + data_index++; + switch (frame_header) + { + /* GYRO frame */ + case BMI160_FIFO_HEAD_G: + case BMI160_FIFO_HEAD_G_A: + case BMI160_FIFO_HEAD_M_G: + case BMI160_FIFO_HEAD_M_G_A: + unpack_gyro_frame(gyro_data, &data_index, &gyro_index, frame_header, dev); + break; + case BMI160_FIFO_HEAD_A: + move_next_frame(&data_index, BMI160_FIFO_A_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_M: + move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_M_A: + move_next_frame(&data_index, BMI160_FIFO_M_LENGTH, dev); + break; + + /* Sensor time frame */ + case BMI160_FIFO_HEAD_SENSOR_TIME: + unpack_sensortime_frame(&data_index, dev); + break; + + /* Skip frame */ + case BMI160_FIFO_HEAD_SKIP_FRAME: + unpack_skipped_frame(&data_index, dev); + break; + + /* Input config frame */ + case BMI160_FIFO_HEAD_INPUT_CONFIG: + move_next_frame(&data_index, 1, dev); + break; + case BMI160_FIFO_HEAD_OVER_READ: + + /* Update the data index as complete in case of over read */ + data_index = dev->fifo->length; + break; + default: + break; + } + if (*gyro_length == gyro_index) + { + /*Number of frames to read completed*/ + break; + } + } + + /*Update number of gyro data read*/ + *gyro_length = gyro_index; + + /*Update the gyro frame index*/ + dev->fifo->gyro_byte_start_idx = data_index; +} + +/*! + * @brief This API computes the number of bytes of aux FIFO data + * which is to be parsed in header-less mode + */ +static void get_aux_len_to_parse(uint16_t *data_index, + uint16_t *data_read_length, + const uint8_t *aux_frame_count, + const struct bmi160_dev *dev) +{ + /* Data start index */ + *data_index = dev->fifo->gyro_byte_start_idx; + if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_ENABLE) + { + *data_read_length = (*aux_frame_count) * BMI160_FIFO_M_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_A_ENABLE) + { + *data_read_length = (*aux_frame_count) * BMI160_FIFO_MA_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_ENABLE) + { + *data_read_length = (*aux_frame_count) * BMI160_FIFO_MG_LENGTH; + } + else if (dev->fifo->fifo_data_enable == BMI160_FIFO_M_G_A_ENABLE) + { + *data_read_length = (*aux_frame_count) * BMI160_FIFO_MGA_LENGTH; + } + else + { + /* When aux is not enabled ,there will be no aux data. + * so we update the data index as complete */ + *data_index = dev->fifo->length; + } + + if (*data_read_length > dev->fifo->length) + { + /* Handling the case where more data is requested + * than that is available */ + *data_read_length = dev->fifo->length; + } +} + +/*! + * @brief This API is used to parse the aux's data from the + * FIFO data in both header mode and header-less mode. + * It updates the idx value which is used to store the index of + * the current data byte which is parsed + */ +static void unpack_aux_frame(struct bmi160_aux_data *aux_data, + uint16_t *idx, + uint8_t *aux_index, + uint8_t frame_info, + const struct bmi160_dev *dev) +{ + switch (frame_info) + { + case BMI160_FIFO_HEAD_M: + case BMI160_FIFO_M_ENABLE: + + /* Partial read, then skip the data */ + if ((*idx + BMI160_FIFO_M_LENGTH) > dev->fifo->length) + { + /* Update the data index as complete */ + *idx = dev->fifo->length; + break; + } + + /* Unpack the data array into structure instance */ + unpack_aux_data(&aux_data[*aux_index], *idx, dev); + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_M_LENGTH; + (*aux_index)++; + break; + case BMI160_FIFO_HEAD_M_A: + case BMI160_FIFO_M_A_ENABLE: + + /* Partial read, then skip the data */ + if ((*idx + BMI160_FIFO_MA_LENGTH) > dev->fifo->length) + { + /* Update the data index as complete */ + *idx = dev->fifo->length; + break; + } + + /* Unpack the data array into structure instance */ + unpack_aux_data(&aux_data[*aux_index], *idx, dev); + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_MA_LENGTH; + (*aux_index)++; + break; + case BMI160_FIFO_HEAD_M_G: + case BMI160_FIFO_M_G_ENABLE: + + /* Partial read, then skip the data */ + if ((*idx + BMI160_FIFO_MG_LENGTH) > dev->fifo->length) + { + /* Update the data index as complete */ + *idx = dev->fifo->length; + break; + } + + /* Unpack the data array into structure instance */ + unpack_aux_data(&aux_data[*aux_index], *idx, dev); + + /* Move the data index */ + (*idx) = (*idx) + BMI160_FIFO_MG_LENGTH; + (*aux_index)++; + break; + case BMI160_FIFO_HEAD_M_G_A: + case BMI160_FIFO_M_G_A_ENABLE: + + /*Partial read, then skip the data*/ + if ((*idx + BMI160_FIFO_MGA_LENGTH) > dev->fifo->length) + { + /* Update the data index as complete */ + *idx = dev->fifo->length; + break; + } + + /* Unpack the data array into structure instance */ + unpack_aux_data(&aux_data[*aux_index], *idx, dev); + + /*Move the data index*/ + *idx = *idx + BMI160_FIFO_MGA_LENGTH; + (*aux_index)++; + break; + case BMI160_FIFO_HEAD_G: + case BMI160_FIFO_G_ENABLE: + + /* Move the data index */ + (*idx) = (*idx) + BMI160_FIFO_G_LENGTH; + break; + case BMI160_FIFO_HEAD_G_A: + case BMI160_FIFO_G_A_ENABLE: + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_GA_LENGTH; + break; + case BMI160_FIFO_HEAD_A: + case BMI160_FIFO_A_ENABLE: + + /* Move the data index */ + *idx = *idx + BMI160_FIFO_A_LENGTH; + break; + default: + break; + } +} + +/*! + * @brief This API is used to parse the aux data from the + * FIFO data and store it in the instance of the structure bmi160_aux_data. + */ +static void unpack_aux_data(struct bmi160_aux_data *aux_data, uint16_t data_start_index, const struct bmi160_dev *dev) +{ + /* Aux data bytes */ + aux_data->data[0] = dev->fifo->data[data_start_index++]; + aux_data->data[1] = dev->fifo->data[data_start_index++]; + aux_data->data[2] = dev->fifo->data[data_start_index++]; + aux_data->data[3] = dev->fifo->data[data_start_index++]; + aux_data->data[4] = dev->fifo->data[data_start_index++]; + aux_data->data[5] = dev->fifo->data[data_start_index++]; + aux_data->data[6] = dev->fifo->data[data_start_index++]; + aux_data->data[7] = dev->fifo->data[data_start_index++]; +} + +/*! + * @brief This API is used to parse the aux data from the + * FIFO data in header mode. + */ +static void extract_aux_header_mode(struct bmi160_aux_data *aux_data, uint8_t *aux_length, const struct bmi160_dev *dev) +{ + uint8_t frame_header = 0; + uint16_t data_index; + uint8_t aux_index = 0; + + for (data_index = dev->fifo->aux_byte_start_idx; data_index < dev->fifo->length;) + { + /* extracting Frame header */ + frame_header = (dev->fifo->data[data_index] & BMI160_FIFO_TAG_INTR_MASK); + + /*Index is moved to next byte where the data is starting*/ + data_index++; + switch (frame_header) + { + /* Aux frame */ + case BMI160_FIFO_HEAD_M: + case BMI160_FIFO_HEAD_M_A: + case BMI160_FIFO_HEAD_M_G: + case BMI160_FIFO_HEAD_M_G_A: + unpack_aux_frame(aux_data, &data_index, &aux_index, frame_header, dev); + break; + case BMI160_FIFO_HEAD_G: + move_next_frame(&data_index, BMI160_FIFO_G_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_G_A: + move_next_frame(&data_index, BMI160_FIFO_GA_LENGTH, dev); + break; + case BMI160_FIFO_HEAD_A: + move_next_frame(&data_index, BMI160_FIFO_A_LENGTH, dev); + break; + + /* Sensor time frame */ + case BMI160_FIFO_HEAD_SENSOR_TIME: + unpack_sensortime_frame(&data_index, dev); + break; + + /* Skip frame */ + case BMI160_FIFO_HEAD_SKIP_FRAME: + unpack_skipped_frame(&data_index, dev); + break; + + /* Input config frame */ + case BMI160_FIFO_HEAD_INPUT_CONFIG: + move_next_frame(&data_index, 1, dev); + break; + case BMI160_FIFO_HEAD_OVER_READ: + + /* Update the data index as complete in case + * of over read */ + data_index = dev->fifo->length; + break; + default: + + /* Update the data index as complete in case of + * getting other headers like 0x00 */ + data_index = dev->fifo->length; + break; + } + if (*aux_length == aux_index) + { + /*Number of frames to read completed*/ + break; + } + } + + /* Update number of aux data read */ + *aux_length = aux_index; + + /* Update the aux frame index */ + dev->fifo->aux_byte_start_idx = data_index; +} + +/*! + * @brief This API checks the presence of non-valid frames in the read fifo data. + */ +static void check_frame_validity(uint16_t *data_index, const struct bmi160_dev *dev) +{ + if ((*data_index + 2) < dev->fifo->length) + { + /* Check if FIFO is empty */ + if ((dev->fifo->data[*data_index] == FIFO_CONFIG_MSB_CHECK) && + (dev->fifo->data[*data_index + 1] == FIFO_CONFIG_LSB_CHECK)) + { + /*Update the data index as complete*/ + *data_index = dev->fifo->length; + } + } +} + +/*! + * @brief This API is used to move the data index ahead of the + * current_frame_length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + */ +static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi160_dev *dev) +{ + /*Partial read, then move the data index to last data*/ + if ((*data_index + current_frame_length) > dev->fifo->length) + { + /*Update the data index as complete*/ + *data_index = dev->fifo->length; + } + else + { + /*Move the data index to next frame*/ + *data_index = *data_index + current_frame_length; + } +} + +/*! + * @brief This API is used to parse and store the sensor time from the + * FIFO data in the structure instance dev. + */ +static void unpack_sensortime_frame(uint16_t *data_index, const struct bmi160_dev *dev) +{ + uint32_t sensor_time_byte3 = 0; + uint16_t sensor_time_byte2 = 0; + uint8_t sensor_time_byte1 = 0; + + /*Partial read, then move the data index to last data*/ + if ((*data_index + BMI160_SENSOR_TIME_LENGTH) > dev->fifo->length) + { + /*Update the data index as complete*/ + *data_index = dev->fifo->length; + } + else + { + sensor_time_byte3 = dev->fifo->data[(*data_index) + BMI160_SENSOR_TIME_MSB_BYTE] << 16; + sensor_time_byte2 = dev->fifo->data[(*data_index) + BMI160_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = dev->fifo->data[(*data_index)]; + + /* Sensor time */ + dev->fifo->sensor_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + *data_index = (*data_index) + BMI160_SENSOR_TIME_LENGTH; + } +} + +/*! + * @brief This API is used to parse and store the skipped_frame_count from + * the FIFO data in the structure instance dev. + */ +static void unpack_skipped_frame(uint16_t *data_index, const struct bmi160_dev *dev) +{ + /*Partial read, then move the data index to last data*/ + if (*data_index >= dev->fifo->length) + { + /*Update the data index as complete*/ + *data_index = dev->fifo->length; + } + else + { + dev->fifo->skipped_frame_count = dev->fifo->data[*data_index]; + + /*Move the data index*/ + *data_index = (*data_index) + 1; + } +} + +/*! + * @brief This API is used to get the FOC status from the sensor + */ +static int8_t get_foc_status(uint8_t *foc_status, struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t data; + + /* Read the FOC status from sensor */ + rslt = bmi160_get_regs(BMI160_STATUS_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* Get the foc_status bit */ + *foc_status = BMI160_GET_BITS(data, BMI160_FOC_STATUS); + } + + return rslt; +} + +/*! + * @brief This API is used to configure the offset enable bits in the sensor + */ +static int8_t configure_offset_enable(const struct bmi160_foc_conf *foc_conf, struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t data; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt != BMI160_OK) + { + rslt = BMI160_E_NULL_PTR; + } + else + { + /* Read the FOC config from the sensor */ + rslt = bmi160_get_regs(BMI160_OFFSET_CONF_ADDR, &data, 1, dev); + if (rslt == BMI160_OK) + { + /* Set the offset enable/disable for gyro */ + data = BMI160_SET_BITS(data, BMI160_GYRO_OFFSET_EN, foc_conf->gyro_off_en); + + /* Set the offset enable/disable for accel */ + data = BMI160_SET_BITS(data, BMI160_ACCEL_OFFSET_EN, foc_conf->acc_off_en); + + /* Set the offset config in the sensor */ + rslt = bmi160_set_regs(BMI160_OFFSET_CONF_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +static int8_t trigger_foc(struct bmi160_offsets *offset, struct bmi160_dev const *dev) +{ + int8_t rslt; + uint8_t foc_status = BMI160_ENABLE; + uint8_t cmd = BMI160_START_FOC_CMD; + uint8_t timeout = 0; + uint8_t data_array[20]; + + /* Start the FOC process */ + rslt = bmi160_set_regs(BMI160_COMMAND_REG_ADDR, &cmd, 1, dev); + if (rslt == BMI160_OK) + { + /* Check the FOC status*/ + rslt = get_foc_status(&foc_status, dev); + + if ((rslt != BMI160_OK) || (foc_status != BMI160_ENABLE)) + { + while ((foc_status != BMI160_ENABLE) && (timeout < 11)) + { + /* Maximum time of 250ms is given in 10 + * steps of 25ms each - 250ms refer datasheet 2.9.1 */ + dev->delay_ms(25); + + /* Check the FOC status*/ + rslt = get_foc_status(&foc_status, dev); + timeout++; + } + + if ((rslt == BMI160_OK) && (foc_status == BMI160_ENABLE)) + { + /* Get offset values from sensor */ + rslt = bmi160_get_offsets(offset, dev); + } + else + { + /* FOC failure case */ + rslt = BMI160_E_FOC_FAILURE; + } + } + + if (rslt == BMI160_OK) + { + /* Read registers 0x04-0x17 */ + rslt = bmi160_get_regs(BMI160_GYRO_DATA_ADDR, data_array, 20, dev); + } + } + + return rslt; +} diff --git a/src/SensorManager/BMX160/bmi160.h b/src/SensorManager/BMX160/bmi160.h new file mode 100644 index 00000000..d30978f2 --- /dev/null +++ b/src/SensorManager/BMX160/bmi160.h @@ -0,0 +1,969 @@ +/** +* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmi160.h +* @date 2021-10-05 +* @version v3.9.2 +* +*/ + +/*! + * @defgroup bmi160 BMI160 + */ + +#ifndef BMI160_H_ +#define BMI160_H_ + +/*************************** C++ guard macro *****************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#include "bmi160_defs.h" +#ifdef __KERNEL__ +#include +#else +#include +#include +#include +#endif + +/*********************** User function prototypes ************************/ + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiInit Initialization + * @brief Initialize the sensor and device structure + */ + +/*! + * \ingroup bmi160ApiInit + * \page bmi160_api_bmi160_init bmi160_init + * \code + * int8_t bmi160_init(struct bmi160_dev *dev); + * \endcode + * @details This API is the entry point for sensor.It performs + * the selection of I2C/SPI read mechanism according to the + * selected interface and reads the chip-id of bmi160 sensor. + * + * @param[in,out] dev : Structure instance of bmi160_dev + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_init(struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiRegs Registers + * @brief Read data from the given register address of sensor + */ + +/*! + * \ingroup bmi160ApiRegs + * \page bmi160_api_bmi160_get_regs bmi160_get_regs + * \code + * int8_t bmi160_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev); + * \endcode + * @details This API reads the data from the given register address of sensor. + * + * @param[in] reg_addr : Register address from where the data to be read + * @param[out] data : Pointer to data buffer to store the read data. + * @param[in] len : No of bytes of data to be read. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note For most of the registers auto address increment applies, with the + * exception of a few special registers, which trap the address. For e.g., + * Register address - 0x24(BMI160_FIFO_DATA_ADDR) + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiRegs + * \page bmi160_api_bmi160_set_regs bmi160_set_regs + * \code + * int8_t bmi160_set_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev); + * \endcode + * @details This API writes the given data to the register address + * of sensor. + * + * @param[in] reg_addr : Register address from where the data to be written. + * @param[in] data : Pointer to data buffer which is to be written + * in the sensor. + * @param[in] len : No of bytes of data to write.. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiSoftreset Soft reset + * @brief Perform soft reset of the sensor + */ + +/*! + * \ingroup bmi160ApiSoftreset + * \page bmi160_api_bmi160_soft_reset bmi160_soft_reset + * \code + * int8_t bmi160_soft_reset(struct bmi160_dev *dev); + * \endcode + * @details This API resets and restarts the device. + * All register values are overwritten with default parameters. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_soft_reset(struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiConfig Configuration + * @brief Configuration of the sensor + */ + +/*! + * \ingroup bmi160ApiConfig + * \page bmi160_api_bmi160_set_sens_conf bmi160_set_sens_conf + * \code + * int8_t bmi160_set_sens_conf(struct bmi160_dev *dev); + * \endcode + * @details This API configures the power mode, range and bandwidth + * of sensor. + * + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_sens_conf(struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiConfig + * \page bmi160_api_bmi160_get_sens_conf bmi160_get_sens_conf + * \code + * int8_t bmi160_get_sens_conf(struct bmi160_dev *dev); + * \endcode + * @details This API gets accel and gyro configurations. + * + * @param[out] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_get_sens_conf(struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiPowermode Power mode + * @brief Set / Get power mode of the sensor + */ + +/*! + * \ingroup bmi160ApiPowermode + * \page bmi160_api_bmi160_set_power_mode bmi160_set_power_mode + * \code + * int8_t bmi160_set_power_mode(struct bmi160_dev *dev); + * \endcode + * @details This API sets the power mode of the sensor. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_power_mode(struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiPowermode + * \page bmi160_api_bmi160_get_power_mode bmi160_get_power_mode + * \code + * int8_t bmi160_get_power_mode(struct bmi160_dev *dev); + * \endcode + * @details This API gets the power mode of the sensor. + * + * @param[in] dev : Structure instance of bmi160_dev + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_get_power_mode(struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiData Sensor Data + * @brief Read sensor data + */ + +/*! + * \ingroup bmi160ApiData + * \page bmi160_api_bmi160_get_sensor_data bmi160_get_sensor_data + * \code + * int8_t bmi160_get_sensor_data(uint8_t select_sensor, + * struct bmi160_sensor_data *accel, + * struct bmi160_sensor_data *gyro, + * const struct bmi160_dev *dev); + * + * \endcode + * @details This API reads sensor data, stores it in + * the bmi160_sensor_data structure pointer passed by the user. + * The user can ask for accel data ,gyro data or both sensor + * data using bmi160_select_sensor enum + * + * @param[in] select_sensor : enum to choose accel,gyro or both sensor data + * @param[out] accel : Structure pointer to store accel data + * @param[out] gyro : Structure pointer to store gyro data + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_get_sensor_data(uint8_t select_sensor, + struct bmi160_sensor_data *accel, + struct bmi160_sensor_data *gyro, + const struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiInt Interrupt configuration + * @brief Set interrupt configuration of the sensor + */ + +/*! + * \ingroup bmi160ApiInt + * \page bmi160_api_bmi160_set_int_config bmi160_set_int_config + * \code + * int8_t bmi160_set_int_config(struct bmi160_int_settg *int_config, struct bmi160_dev *dev); + * \endcode + * @details This API configures the necessary interrupt based on + * the user settings in the bmi160_int_settg structure instance. + * + * @param[in] int_config : Structure instance of bmi160_int_settg. + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_int_config(struct bmi160_int_settg *int_config, struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiStepC Step counter + * @brief Step counter operations + */ + +/*! + * \ingroup bmi160ApiStepC + * \page bmi160_api_bmi160_set_step_counter bmi160_set_step_counter + * \code + * int8_t bmi160_set_step_counter(uint8_t step_cnt_enable, const struct bmi160_dev *dev); + * \endcode + * @details This API enables the step counter feature. + * + * @param[in] step_cnt_enable : value to enable or disable + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_step_counter(uint8_t step_cnt_enable, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiStepC + * \page bmi160_api_bmi160_read_step_counter bmi160_read_step_counter + * \code + * int8_t bmi160_read_step_counter(uint16_t *step_val, const struct bmi160_dev *dev); + * \endcode + * @details This API reads the step counter value. + * + * @param[in] step_val : Pointer to store the step counter value. + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_read_step_counter(uint16_t *step_val, const struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiAux Auxiliary sensor + * @brief Auxiliary sensor operations + */ + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_aux_read bmi160_aux_read + * \code + * int8_t bmi160_aux_read(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev); + * \endcode + * @details This API reads the mention no of byte of data from the given + * register address of auxiliary sensor. + * + * @param[in] reg_addr : Address of register to read. + * @param[in] aux_data : Pointer to store the read data. + * @param[in] len : No of bytes to read. + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_aux_read(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_aux_write bmi160_aux_write + * \code + * int8_t bmi160_aux_write(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev); + * \endcode + * @details This API writes the mention no of byte of data to the given + * register address of auxiliary sensor. + * + * @param[in] reg_addr : Address of register to write. + * @param[in] aux_data : Pointer to write data. + * @param[in] len : No of bytes to write. + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_aux_write(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_aux_init bmi160_aux_init + * \code + * int8_t bmi160_aux_init(const struct bmi160_dev *dev); + * \endcode + * @details This API initialize the auxiliary sensor + * in order to access it. + * + * @param[in] dev : Structure instance of bmi160_dev. + * @note : Refer user guide for detailed info. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_aux_init(const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_set_aux_auto_mode bmi160_set_aux_auto_mode + * \code + * int8_t bmi160_set_aux_auto_mode(uint8_t *data_addr, struct bmi160_dev *dev); + * \endcode + * @details This API is used to setup the auxiliary sensor of bmi160 in auto mode + * Thus enabling the auto update of 8 bytes of data from auxiliary sensor + * to BMI160 register address 0x04 to 0x0B + * + * @param[in] data_addr : Starting address of aux. sensor's data register + * (BMI160 registers 0x04 to 0x0B will be updated + * with 8 bytes of data from auxiliary sensor + * starting from this register address.) + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note : Set the value of auxiliary polling rate by setting + * dev->aux_cfg.aux_odr to the required value from the table + * before calling this API + * + *@verbatim + * dev->aux_cfg.aux_odr | Auxiliary ODR (Hz) + * -----------------------|----------------------- + * BMI160_AUX_ODR_0_78HZ | 25/32 + * BMI160_AUX_ODR_1_56HZ | 25/16 + * BMI160_AUX_ODR_3_12HZ | 25/8 + * BMI160_AUX_ODR_6_25HZ | 25/4 + * BMI160_AUX_ODR_12_5HZ | 25/2 + * BMI160_AUX_ODR_25HZ | 25 + * BMI160_AUX_ODR_50HZ | 50 + * BMI160_AUX_ODR_100HZ | 100 + * BMI160_AUX_ODR_200HZ | 200 + * BMI160_AUX_ODR_400HZ | 400 + * BMI160_AUX_ODR_800HZ | 800 + *@endverbatim + * + * @note : Other values of dev->aux_cfg.aux_odr are reserved and not for use + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_set_aux_auto_mode(uint8_t *data_addr, struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_config_aux_mode bmi160_config_aux_mode + * \code + * int8_t bmi160_config_aux_mode(const struct bmi160_dev *dev); + * \endcode + * @details This API configures the 0x4C register and settings like + * Auxiliary sensor manual enable/ disable and aux burst read length. + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_config_aux_mode(const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiAux + * \page bmi160_api_bmi160_read_aux_data_auto_mode bmi160_read_aux_data_auto_mode + * \code + * int8_t bmi160_read_aux_data_auto_mode(uint8_t *aux_data, const struct bmi160_dev *dev); + * \endcode + * @details This API is used to read the raw uncompensated auxiliary sensor + * data of 8 bytes from BMI160 register address 0x04 to 0x0B + * + * @param[in] aux_data : Pointer to user array of length 8 bytes + * Ensure that the aux_data array is of + * length 8 bytes + * @param[in] dev : Structure instance of bmi160_dev + * + * @retval zero -> Success / -ve value -> Error + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_read_aux_data_auto_mode(uint8_t *aux_data, const struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiSelfTest Self test + * @brief Perform self test of the sensor + */ + +/*! + * \ingroup bmi160ApiSelfTest + * \page bmi160_api_bmi160_perform_self_test bmi160_perform_self_test + * \code + * int8_t bmi160_perform_self_test(uint8_t select_sensor, struct bmi160_dev *dev); + * \endcode + * @details This is used to perform self test of accel/gyro of the BMI160 sensor + * + * @param[in] select_sensor : enum to choose accel or gyro for self test + * @param[in] dev : Structure instance of bmi160_dev + * + * @note self test can be performed either for accel/gyro at any instant. + * + *@verbatim + * value of select_sensor | Inference + *----------------------------------|-------------------------------- + * BMI160_ACCEL_ONLY | Accel self test enabled + * BMI160_GYRO_ONLY | Gyro self test enabled + * BMI160_BOTH_ACCEL_AND_GYRO | NOT TO BE USED + *@endverbatim + * + * @note The return value of this API gives us the result of self test. + * + * @note Performing self test does soft reset of the sensor, User can + * set the desired settings after performing the self test. + * + * @return Result of API execution status + * @retval BMI160_OK Self test success + * @retval BMI160_W_GYRO_SELF_TEST_FAIL Gyro self test fail + * @retval BMI160_W_ACCEl_SELF_TEST_FAIL Accel self test fail + */ +int8_t bmi160_perform_self_test(uint8_t select_sensor, struct bmi160_dev *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiFIFO FIFO + * @brief FIFO operations of the sensor + */ + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_get_fifo_data bmi160_get_fifo_data + * \code + * int8_t bmi160_get_fifo_data(struct bmi160_dev const *dev); + * \endcode + * @details This API reads data from the fifo buffer. + * + * @note User has to allocate the FIFO buffer along with + * corresponding fifo length from his side before calling this API + * as mentioned in the readme.md + * + * @note User must specify the number of bytes to read from the FIFO in + * dev->fifo->length , It will be updated by the number of bytes actually + * read from FIFO after calling this API + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval Zero Success + * @retval Negative Error + */ +int8_t bmi160_get_fifo_data(struct bmi160_dev const *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_set_fifo_flush bmi160_set_fifo_flush + * \code + * int8_t bmi160_set_fifo_flush(const struct bmi160_dev *dev); + * \endcode + * @details This API writes fifo_flush command to command register.This + * action clears all data in the Fifo without changing fifo configuration + * settings. + * + * @param[in] dev : Structure instance of bmi160_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_set_fifo_flush(const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_set_fifo_config bmi160_set_fifo_config + * \code + * int8_t bmi160_set_fifo_config(uint8_t config, uint8_t enable, struct bmi160_dev const *dev); + * \endcode + * @details This API sets the FIFO configuration in the sensor. + * + * @param[in] config : variable used to specify the FIFO + * configurations which are to be enabled or disabled in the sensor. + * + * @note : User can set either set one or more or all FIFO configurations + * by ORing the below mentioned macros. + * + *@verbatim + * config | Value + * ------------------------|--------------------------- + * BMI160_FIFO_TIME | 0x02 + * BMI160_FIFO_TAG_INT2 | 0x04 + * BMI160_FIFO_TAG_INT1 | 0x08 + * BMI160_FIFO_HEADER | 0x10 + * BMI160_FIFO_AUX | 0x20 + * BMI160_FIFO_ACCEL | 0x40 + * BMI160_FIFO_GYRO | 0x80 + *@endverbatim + * + * @param[in] enable : Parameter used to enable or disable the above + * FIFO configuration + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return status of bus communication result + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_set_fifo_config(uint8_t config, uint8_t enable, struct bmi160_dev const *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_set_fifo_down bmi160_set_fifo_down + * \code + * int8_t bmi160_set_fifo_down(uint8_t fifo_down, const struct bmi160_dev *dev); + * \endcode + * @details This API is used to configure the down sampling ratios of + * the accel and gyro data for FIFO.Also, it configures filtered or + * pre-filtered data for the fifo for accel and gyro. + * + * @param[in] fifo_down : variable used to specify the FIFO down + * configurations which are to be enabled or disabled in the sensor. + * + * @note The user must select one among the following macros to + * select down-sampling ratio for accel + * + *@verbatim + * config | Value + * -------------------------------------|--------------------------- + * BMI160_ACCEL_FIFO_DOWN_ZERO | 0x00 + * BMI160_ACCEL_FIFO_DOWN_ONE | 0x10 + * BMI160_ACCEL_FIFO_DOWN_TWO | 0x20 + * BMI160_ACCEL_FIFO_DOWN_THREE | 0x30 + * BMI160_ACCEL_FIFO_DOWN_FOUR | 0x40 + * BMI160_ACCEL_FIFO_DOWN_FIVE | 0x50 + * BMI160_ACCEL_FIFO_DOWN_SIX | 0x60 + * BMI160_ACCEL_FIFO_DOWN_SEVEN | 0x70 + *@endverbatim + * + * @note The user must select one among the following macros to + * select down-sampling ratio for gyro + * + *@verbatim + * config | Value + * -------------------------------------|--------------------------- + * BMI160_GYRO_FIFO_DOWN_ZERO | 0x00 + * BMI160_GYRO_FIFO_DOWN_ONE | 0x01 + * BMI160_GYRO_FIFO_DOWN_TWO | 0x02 + * BMI160_GYRO_FIFO_DOWN_THREE | 0x03 + * BMI160_GYRO_FIFO_DOWN_FOUR | 0x04 + * BMI160_GYRO_FIFO_DOWN_FIVE | 0x05 + * BMI160_GYRO_FIFO_DOWN_SIX | 0x06 + * BMI160_GYRO_FIFO_DOWN_SEVEN | 0x07 + *@endverbatim + * + * @note The user can enable filtered accel data by the following macro + * + *@verbatim + * config | Value + * -------------------------------------|--------------------------- + * BMI160_ACCEL_FIFO_FILT_EN | 0x80 + *@endverbatim + * + * @note The user can enable filtered gyro data by the following macro + * + *@verbatim + * config | Value + * -------------------------------------|--------------------------- + * BMI160_GYRO_FIFO_FILT_EN | 0x08 + *@endverbatim + * + * @note : By ORing the above mentioned macros, the user can select + * the required FIFO down config settings + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return status of bus communication result + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_set_fifo_down(uint8_t fifo_down, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_set_fifo_wm bmi160_set_fifo_wm + * \code + * int8_t bmi160_set_fifo_wm(uint8_t fifo_wm, const struct bmi160_dev *dev); + * \endcode + * @details This API sets the FIFO watermark level in the sensor. + * + * @note The FIFO watermark is issued when the FIFO fill level is + * equal or above the watermark level and units of watermark is 4 bytes. + * + * @param[in] fifo_wm : Variable used to set the FIFO water mark level + * @param[in] dev : Structure instance of bmi160_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_set_fifo_wm(uint8_t fifo_wm, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_extract_accel bmi160_extract_accel + * \code + * int8_t bmi160_extract_accel(struct bmi160_sensor_data *accel_data, uint8_t *accel_length, struct bmi160_dev const + **dev); + * \endcode + * @details This API parses and extracts the accelerometer frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the "accel_data" structure instance. + * + * @note The bmi160_extract_accel API should be called only after + * reading the FIFO data by calling the bmi160_get_fifo_data() API. + * + * @param[out] accel_data : Structure instance of bmi160_sensor_data + * where the accelerometer data in FIFO is stored. + * @param[in,out] accel_length : Number of valid accelerometer frames + * (x,y,z axes data) read out from fifo. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note accel_length is updated with the number of valid accelerometer + * frames extracted from fifo (1 accel frame = 6 bytes) at the end of + * execution of this API. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_extract_accel(struct bmi160_sensor_data *accel_data, uint8_t *accel_length, struct bmi160_dev const *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_extract_gyro bmi160_extract_gyro + * \code + * int8_t bmi160_extract_gyro(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length, struct bmi160_dev const *dev); + * \endcode + * @details This API parses and extracts the gyro frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the "gyro_data" structure instance. + * + * @note The bmi160_extract_gyro API should be called only after + * reading the FIFO data by calling the bmi160_get_fifo_data() API. + * + * @param[out] gyro_data : Structure instance of bmi160_sensor_data + * where the gyro data in FIFO is stored. + * @param[in,out] gyro_length : Number of valid gyro frames + * (x,y,z axes data) read out from fifo. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note gyro_length is updated with the number of valid gyro + * frames extracted from fifo (1 gyro frame = 6 bytes) at the end of + * execution of this API. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_extract_gyro(struct bmi160_sensor_data *gyro_data, uint8_t *gyro_length, struct bmi160_dev const *dev); + +/*! + * \ingroup bmi160ApiFIFO + * \page bmi160_api_bmi160_extract_aux bmi160_extract_aux + * \code + * int8_t bmi160_extract_aux(struct bmi160_aux_data *aux_data, uint8_t *aux_len, struct bmi160_dev const *dev); + * \endcode + * @details This API parses and extracts the aux frames from + * FIFO data read by the "bmi160_get_fifo_data" API and stores it in + * the bmi160_aux_data structure instance. + * + * @note The bmi160_extract_aux API should be called only after + * reading the FIFO data by calling the bmi160_get_fifo_data() API. + * + * @param[out] aux_data : Structure instance of bmi160_aux_data + * where the aux data in FIFO is stored. + * @param[in,out] aux_len : Number of valid aux frames (8bytes) + * read out from FIFO. + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note aux_len is updated with the number of valid aux + * frames extracted from fifo (1 aux frame = 8 bytes) at the end of + * execution of this API. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + * + */ +int8_t bmi160_extract_aux(struct bmi160_aux_data *aux_data, uint8_t *aux_len, struct bmi160_dev const *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiFOC FOC + * @brief Start FOC of accel and gyro sensors + */ + +/*! + * \ingroup bmi160ApiFOC + * \page bmi160_api_bmi160_start_foc bmi160_start_foc + * \code + * int8_t bmi160_start_foc(const struct bmi160_foc_conf *foc_conf, + * \endcode + * @details This API starts the FOC of accel and gyro + * + * @note FOC should not be used in low-power mode of sensor + * + * @note Accel FOC targets values of +1g , 0g , -1g + * Gyro FOC always targets value of 0 dps + * + * @param[in] foc_conf : Structure instance of bmi160_foc_conf which + * has the FOC configuration + * @param[in,out] offset : Structure instance to store Offset + * values read from sensor + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note Pre-requisites for triggering FOC in accel , Set the following, + * Enable the acc_off_en + * Ex : foc_conf.acc_off_en = BMI160_ENABLE; + * + * Set the desired target values of FOC to each axes (x,y,z) by using the + * following macros + * - BMI160_FOC_ACCEL_DISABLED + * - BMI160_FOC_ACCEL_POSITIVE_G + * - BMI160_FOC_ACCEL_NEGATIVE_G + * - BMI160_FOC_ACCEL_0G + * + * Ex : foc_conf.foc_acc_x = BMI160_FOC_ACCEL_0G; + * foc_conf.foc_acc_y = BMI160_FOC_ACCEL_0G; + * foc_conf.foc_acc_z = BMI160_FOC_ACCEL_POSITIVE_G; + * + * @note Pre-requisites for triggering FOC in gyro , + * Set the following parameters, + * + * Ex : foc_conf.foc_gyr_en = BMI160_ENABLE; + * foc_conf.gyro_off_en = BMI160_ENABLE; + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + */ +int8_t bmi160_start_foc(const struct bmi160_foc_conf *foc_conf, + struct bmi160_offsets *offset, + struct bmi160_dev const *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiOffsets Offsets + * @brief Set / Get offset values of accel and gyro sensors + */ + +/*! + * \ingroup bmi160ApiOffsets + * \page bmi160_api_bmi160_get_offsets bmi160_get_offsets + * \code + * int8_t bmi160_get_offsets(struct bmi160_offsets *offset, const struct bmi160_dev *dev); + * \endcode + * @details This API reads and stores the offset values of accel and gyro + * + * @param[in,out] offset : Structure instance of bmi160_offsets in which + * the offset values are read and stored + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + */ +int8_t bmi160_get_offsets(struct bmi160_offsets *offset, const struct bmi160_dev *dev); + +/*! + * \ingroup bmi160ApiOffsets + * \page bmi160_api_bmi160_set_offsets bmi160_set_offsets + * \code + * int8_t bmi160_set_offsets(const struct bmi160_foc_conf *foc_conf, + * const struct bmi160_offsets *offset, + * struct bmi160_dev const *dev); + * \endcode + * @details This API writes the offset values of accel and gyro to + * the sensor but these values will be reset on POR or soft reset. + * + * @param[in] foc_conf : Structure instance of bmi160_foc_conf which + * has the FOC configuration + * @param[in] offset : Structure instance in which user updates offset + * values which are to be written in the sensor + * @param[in] dev : Structure instance of bmi160_dev. + * + * @note Offsets can be set by user like offset->off_acc_x = 10; + * where 1LSB = 3.9mg and for gyro 1LSB = 0.061degrees/second + * + * @note BMI160 offset values for xyz axes of accel should be within range of + * BMI160_ACCEL_MIN_OFFSET (-128) to BMI160_ACCEL_MAX_OFFSET (127) + * + * @note BMI160 offset values for xyz axes of gyro should be within range of + * BMI160_GYRO_MIN_OFFSET (-512) to BMI160_GYRO_MAX_OFFSET (511) + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + */ +int8_t bmi160_set_offsets(const struct bmi160_foc_conf *foc_conf, + const struct bmi160_offsets *offset, + struct bmi160_dev const *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiNVM NVM + * @brief Write image registers values to NVM + */ + +/*! + * \ingroup bmi160ApiNVM + * \page bmi160_api_bmi160_update_nvm bmi160_update_nvm + * \code + * int8_t bmi160_update_nvm(struct bmi160_dev const *dev); + * \endcode + * @details This API writes the image registers values to NVM which is + * stored even after POR or soft reset + * + * @param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + */ +int8_t bmi160_update_nvm(struct bmi160_dev const *dev); + +/** + * \ingroup bmi160 + * \defgroup bmi160ApiInts Interrupt status + * @brief Read interrupt status from the sensor + */ + +/*! + * \ingroup bmi160ApiInts + * \page bmi160_api_bmi160_get_int_status bmi160_get_int_status + * \code + * int8_t bmi160_get_int_status(enum bmi160_int_status_sel int_status_sel, + * union bmi160_int_status *int_status, + * struct bmi160_dev const *dev); + * \endcode + * @details This API gets the interrupt status from the sensor. + * + * @param[in] int_status_sel : Enum variable to select either individual or all the + * interrupt status bits. + * @param[in] int_status : pointer variable to get the interrupt status + * from the sensor. + * param[in] dev : Structure instance of bmi160_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval Any non zero value -> Fail + */ +int8_t bmi160_get_int_status(enum bmi160_int_status_sel int_status_sel, + union bmi160_int_status *int_status, + struct bmi160_dev const *dev); + +/*************************** C++ guard macro *****************************/ +#ifdef __cplusplus +} +#endif + +#endif /* BMI160_H_ */ diff --git a/src/SensorManager/BMX160/bmi160_defs.h b/src/SensorManager/BMX160/bmi160_defs.h new file mode 100644 index 00000000..8199bd0e --- /dev/null +++ b/src/SensorManager/BMX160/bmi160_defs.h @@ -0,0 +1,1650 @@ +/** +* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bmi160_defs.h +* @date 2021-10-05 +* @version v3.9.2 +* +*/ + +#ifndef BMI160_DEFS_H_ +#define BMI160_DEFS_H_ + +/*************************** C types headers *****************************/ +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/*************************** Common macros *****************************/ + +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif + +/**@}*/ +/**\name C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +/*************************** Sensor macros *****************************/ +/* Test for an endian machine */ +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 0 +#endif + +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1 +#endif +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 1 +#endif +#else +#error "Code does not support Endian format of the processor" +#endif + +/** Mask definitions */ +#define BMI160_ACCEL_BW_MASK UINT8_C(0x70) +#define BMI160_ACCEL_ODR_MASK UINT8_C(0x0F) +#define BMI160_ACCEL_UNDERSAMPLING_MASK UINT8_C(0x80) +#define BMI160_ACCEL_RANGE_MASK UINT8_C(0x0F) +#define BMI160_GYRO_BW_MASK UINT8_C(0x30) +#define BMI160_GYRO_ODR_MASK UINT8_C(0x0F) +#define BMI160_GYRO_RANGE_MASK UINT8_C(0x07) + +#define BMI160_ACCEL_BW_POS UINT8_C(4) +#define BMI160_GYRO_BW_POS UINT8_C(4) + +/** Mask definitions for INT_EN registers */ +#define BMI160_ANY_MOTION_X_INT_EN_MASK UINT8_C(0x01) +#define BMI160_HIGH_G_X_INT_EN_MASK UINT8_C(0x01) +#define BMI160_NO_MOTION_X_INT_EN_MASK UINT8_C(0x01) +#define BMI160_ANY_MOTION_Y_INT_EN_MASK UINT8_C(0x02) +#define BMI160_HIGH_G_Y_INT_EN_MASK UINT8_C(0x02) +#define BMI160_NO_MOTION_Y_INT_EN_MASK UINT8_C(0x02) +#define BMI160_ANY_MOTION_Z_INT_EN_MASK UINT8_C(0x04) +#define BMI160_HIGH_G_Z_INT_EN_MASK UINT8_C(0x04) +#define BMI160_NO_MOTION_Z_INT_EN_MASK UINT8_C(0x04) +#define BMI160_SIG_MOTION_INT_EN_MASK UINT8_C(0x07) +#define BMI160_ANY_MOTION_ALL_INT_EN_MASK UINT8_C(0x07) +#define BMI160_STEP_DETECT_INT_EN_MASK UINT8_C(0x08) +#define BMI160_DOUBLE_TAP_INT_EN_MASK UINT8_C(0x10) +#define BMI160_SINGLE_TAP_INT_EN_MASK UINT8_C(0x20) +#define BMI160_FIFO_FULL_INT_EN_MASK UINT8_C(0x20) +#define BMI160_ORIENT_INT_EN_MASK UINT8_C(0x40) +#define BMI160_FIFO_WATERMARK_INT_EN_MASK UINT8_C(0x40) +#define BMI160_LOW_G_INT_EN_MASK UINT8_C(0x08) +#define BMI160_STEP_DETECT_EN_MASK UINT8_C(0x08) +#define BMI160_FLAT_INT_EN_MASK UINT8_C(0x80) +#define BMI160_DATA_RDY_INT_EN_MASK UINT8_C(0x10) + +/** PMU status Macros */ +#define BMI160_AUX_PMU_SUSPEND UINT8_C(0x00) +#define BMI160_AUX_PMU_NORMAL UINT8_C(0x01) +#define BMI160_AUX_PMU_LOW_POWER UINT8_C(0x02) + +#define BMI160_GYRO_PMU_SUSPEND UINT8_C(0x00) +#define BMI160_GYRO_PMU_NORMAL UINT8_C(0x01) +#define BMI160_GYRO_PMU_FSU UINT8_C(0x03) + +#define BMI160_ACCEL_PMU_SUSPEND UINT8_C(0x00) +#define BMI160_ACCEL_PMU_NORMAL UINT8_C(0x01) +#define BMI160_ACCEL_PMU_LOW_POWER UINT8_C(0x02) + +/** Mask definitions for INT_OUT_CTRL register */ +#define BMI160_INT1_EDGE_CTRL_MASK UINT8_C(0x01) +#define BMI160_INT1_OUTPUT_MODE_MASK UINT8_C(0x04) +#define BMI160_INT1_OUTPUT_TYPE_MASK UINT8_C(0x02) +#define BMI160_INT1_OUTPUT_EN_MASK UINT8_C(0x08) +#define BMI160_INT2_EDGE_CTRL_MASK UINT8_C(0x10) +#define BMI160_INT2_OUTPUT_MODE_MASK UINT8_C(0x40) +#define BMI160_INT2_OUTPUT_TYPE_MASK UINT8_C(0x20) +#define BMI160_INT2_OUTPUT_EN_MASK UINT8_C(0x80) + +/** Mask definitions for INT_LATCH register */ +#define BMI160_INT1_INPUT_EN_MASK UINT8_C(0x10) +#define BMI160_INT2_INPUT_EN_MASK UINT8_C(0x20) +#define BMI160_INT_LATCH_MASK UINT8_C(0x0F) + +/** Mask definitions for INT_MAP register */ +#define BMI160_INT1_LOW_G_MASK UINT8_C(0x01) +#define BMI160_INT1_HIGH_G_MASK UINT8_C(0x02) +#define BMI160_INT1_SLOPE_MASK UINT8_C(0x04) +#define BMI160_INT1_NO_MOTION_MASK UINT8_C(0x08) +#define BMI160_INT1_DOUBLE_TAP_MASK UINT8_C(0x10) +#define BMI160_INT1_SINGLE_TAP_MASK UINT8_C(0x20) +#define BMI160_INT1_FIFO_FULL_MASK UINT8_C(0x20) +#define BMI160_INT1_FIFO_WM_MASK UINT8_C(0x40) +#define BMI160_INT1_ORIENT_MASK UINT8_C(0x40) +#define BMI160_INT1_FLAT_MASK UINT8_C(0x80) +#define BMI160_INT1_DATA_READY_MASK UINT8_C(0x80) +#define BMI160_INT2_LOW_G_MASK UINT8_C(0x01) +#define BMI160_INT1_LOW_STEP_DETECT_MASK UINT8_C(0x01) +#define BMI160_INT2_LOW_STEP_DETECT_MASK UINT8_C(0x01) +#define BMI160_INT2_HIGH_G_MASK UINT8_C(0x02) +#define BMI160_INT2_FIFO_FULL_MASK UINT8_C(0x02) +#define BMI160_INT2_FIFO_WM_MASK UINT8_C(0x04) +#define BMI160_INT2_SLOPE_MASK UINT8_C(0x04) +#define BMI160_INT2_DATA_READY_MASK UINT8_C(0x08) +#define BMI160_INT2_NO_MOTION_MASK UINT8_C(0x08) +#define BMI160_INT2_DOUBLE_TAP_MASK UINT8_C(0x10) +#define BMI160_INT2_SINGLE_TAP_MASK UINT8_C(0x20) +#define BMI160_INT2_ORIENT_MASK UINT8_C(0x40) +#define BMI160_INT2_FLAT_MASK UINT8_C(0x80) + +/** Mask definitions for INT_DATA register */ +#define BMI160_TAP_SRC_INT_MASK UINT8_C(0x08) +#define BMI160_LOW_HIGH_SRC_INT_MASK UINT8_C(0x80) +#define BMI160_MOTION_SRC_INT_MASK UINT8_C(0x80) + +/** Mask definitions for INT_MOTION register */ +#define BMI160_SLOPE_INT_DUR_MASK UINT8_C(0x03) +#define BMI160_NO_MOTION_INT_DUR_MASK UINT8_C(0xFC) +#define BMI160_NO_MOTION_SEL_BIT_MASK UINT8_C(0x01) + +/** Mask definitions for INT_TAP register */ +#define BMI160_TAP_DUR_MASK UINT8_C(0x07) +#define BMI160_TAP_SHOCK_DUR_MASK UINT8_C(0x40) +#define BMI160_TAP_QUIET_DUR_MASK UINT8_C(0x80) +#define BMI160_TAP_THRES_MASK UINT8_C(0x1F) + +/** Mask definitions for INT_FLAT register */ +#define BMI160_FLAT_THRES_MASK UINT8_C(0x3F) +#define BMI160_FLAT_HOLD_TIME_MASK UINT8_C(0x30) +#define BMI160_FLAT_HYST_MASK UINT8_C(0x07) + +/** Mask definitions for INT_LOWHIGH register */ +#define BMI160_LOW_G_HYST_MASK UINT8_C(0x03) +#define BMI160_LOW_G_LOW_MODE_MASK UINT8_C(0x04) +#define BMI160_HIGH_G_HYST_MASK UINT8_C(0xC0) + +/** Mask definitions for INT_SIG_MOTION register */ +#define BMI160_SIG_MOTION_SEL_MASK UINT8_C(0x02) +#define BMI160_SIG_MOTION_SKIP_MASK UINT8_C(0x0C) +#define BMI160_SIG_MOTION_PROOF_MASK UINT8_C(0x30) + +/** Mask definitions for INT_ORIENT register */ +#define BMI160_ORIENT_MODE_MASK UINT8_C(0x03) +#define BMI160_ORIENT_BLOCK_MASK UINT8_C(0x0C) +#define BMI160_ORIENT_HYST_MASK UINT8_C(0xF0) +#define BMI160_ORIENT_THETA_MASK UINT8_C(0x3F) +#define BMI160_ORIENT_UD_ENABLE UINT8_C(0x40) +#define BMI160_AXES_EN_MASK UINT8_C(0x80) + +/** Mask definitions for FIFO_CONFIG register */ +#define BMI160_FIFO_GYRO UINT8_C(0x80) +#define BMI160_FIFO_ACCEL UINT8_C(0x40) +#define BMI160_FIFO_AUX UINT8_C(0x20) +#define BMI160_FIFO_TAG_INT1 UINT8_C(0x08) +#define BMI160_FIFO_TAG_INT2 UINT8_C(0x04) +#define BMI160_FIFO_TIME UINT8_C(0x02) +#define BMI160_FIFO_HEADER UINT8_C(0x10) +#define BMI160_FIFO_CONFIG_1_MASK UINT8_C(0xFE) + +/** Mask definitions for STEP_CONF register */ +#define BMI160_STEP_COUNT_EN_BIT_MASK UINT8_C(0x08) +#define BMI160_STEP_DETECT_MIN_THRES_MASK UINT8_C(0x18) +#define BMI160_STEP_DETECT_STEPTIME_MIN_MASK UINT8_C(0x07) +#define BMI160_STEP_MIN_BUF_MASK UINT8_C(0x07) + +/** Mask definition for FIFO Header Data Tag */ +#define BMI160_FIFO_TAG_INTR_MASK UINT8_C(0xFC) + +/** Fifo byte counter mask definitions */ +#define BMI160_FIFO_BYTE_COUNTER_MASK UINT8_C(0x07) + +/** Enable/disable bit value */ +#define BMI160_ENABLE UINT8_C(0x01) +#define BMI160_DISABLE UINT8_C(0x00) + +/** Latch Duration */ +#define BMI160_LATCH_DUR_NONE UINT8_C(0x00) +#define BMI160_LATCH_DUR_312_5_MICRO_SEC UINT8_C(0x01) +#define BMI160_LATCH_DUR_625_MICRO_SEC UINT8_C(0x02) +#define BMI160_LATCH_DUR_1_25_MILLI_SEC UINT8_C(0x03) +#define BMI160_LATCH_DUR_2_5_MILLI_SEC UINT8_C(0x04) +#define BMI160_LATCH_DUR_5_MILLI_SEC UINT8_C(0x05) +#define BMI160_LATCH_DUR_10_MILLI_SEC UINT8_C(0x06) +#define BMI160_LATCH_DUR_20_MILLI_SEC UINT8_C(0x07) +#define BMI160_LATCH_DUR_40_MILLI_SEC UINT8_C(0x08) +#define BMI160_LATCH_DUR_80_MILLI_SEC UINT8_C(0x09) +#define BMI160_LATCH_DUR_160_MILLI_SEC UINT8_C(0x0A) +#define BMI160_LATCH_DUR_320_MILLI_SEC UINT8_C(0x0B) +#define BMI160_LATCH_DUR_640_MILLI_SEC UINT8_C(0x0C) +#define BMI160_LATCH_DUR_1_28_SEC UINT8_C(0x0D) +#define BMI160_LATCH_DUR_2_56_SEC UINT8_C(0x0E) +#define BMI160_LATCHED UINT8_C(0x0F) + +/** BMI160 Register map */ +#define BMI160_CHIP_ID_ADDR UINT8_C(0x00) +#define BMI160_ERROR_REG_ADDR UINT8_C(0x02) +#define BMI160_PMU_STATUS_ADDR UINT8_C(0x03) +#define BMI160_AUX_DATA_ADDR UINT8_C(0x04) +#define BMI160_GYRO_DATA_ADDR UINT8_C(0x0C) +#define BMI160_ACCEL_DATA_ADDR UINT8_C(0x12) +#define BMI160_STATUS_ADDR UINT8_C(0x1B) +#define BMI160_INT_STATUS_ADDR UINT8_C(0x1C) +#define BMI160_FIFO_LENGTH_ADDR UINT8_C(0x22) +#define BMI160_FIFO_DATA_ADDR UINT8_C(0x24) +#define BMI160_ACCEL_CONFIG_ADDR UINT8_C(0x40) +#define BMI160_ACCEL_RANGE_ADDR UINT8_C(0x41) +#define BMI160_GYRO_CONFIG_ADDR UINT8_C(0x42) +#define BMI160_GYRO_RANGE_ADDR UINT8_C(0x43) +#define BMI160_AUX_ODR_ADDR UINT8_C(0x44) +#define BMI160_FIFO_DOWN_ADDR UINT8_C(0x45) +#define BMI160_FIFO_CONFIG_0_ADDR UINT8_C(0x46) +#define BMI160_FIFO_CONFIG_1_ADDR UINT8_C(0x47) +#define BMI160_AUX_IF_0_ADDR UINT8_C(0x4B) +#define BMI160_AUX_IF_1_ADDR UINT8_C(0x4C) +#define BMI160_AUX_IF_2_ADDR UINT8_C(0x4D) +#define BMI160_AUX_IF_3_ADDR UINT8_C(0x4E) +#define BMI160_AUX_IF_4_ADDR UINT8_C(0x4F) +#define BMI160_INT_ENABLE_0_ADDR UINT8_C(0x50) +#define BMI160_INT_ENABLE_1_ADDR UINT8_C(0x51) +#define BMI160_INT_ENABLE_2_ADDR UINT8_C(0x52) +#define BMI160_INT_OUT_CTRL_ADDR UINT8_C(0x53) +#define BMI160_INT_LATCH_ADDR UINT8_C(0x54) +#define BMI160_INT_MAP_0_ADDR UINT8_C(0x55) +#define BMI160_INT_MAP_1_ADDR UINT8_C(0x56) +#define BMI160_INT_MAP_2_ADDR UINT8_C(0x57) +#define BMI160_INT_DATA_0_ADDR UINT8_C(0x58) +#define BMI160_INT_DATA_1_ADDR UINT8_C(0x59) +#define BMI160_INT_LOWHIGH_0_ADDR UINT8_C(0x5A) +#define BMI160_INT_LOWHIGH_1_ADDR UINT8_C(0x5B) +#define BMI160_INT_LOWHIGH_2_ADDR UINT8_C(0x5C) +#define BMI160_INT_LOWHIGH_3_ADDR UINT8_C(0x5D) +#define BMI160_INT_LOWHIGH_4_ADDR UINT8_C(0x5E) +#define BMI160_INT_MOTION_0_ADDR UINT8_C(0x5F) +#define BMI160_INT_MOTION_1_ADDR UINT8_C(0x60) +#define BMI160_INT_MOTION_2_ADDR UINT8_C(0x61) +#define BMI160_INT_MOTION_3_ADDR UINT8_C(0x62) +#define BMI160_INT_TAP_0_ADDR UINT8_C(0x63) +#define BMI160_INT_TAP_1_ADDR UINT8_C(0x64) +#define BMI160_INT_ORIENT_0_ADDR UINT8_C(0x65) +#define BMI160_INT_ORIENT_1_ADDR UINT8_C(0x66) +#define BMI160_INT_FLAT_0_ADDR UINT8_C(0x67) +#define BMI160_INT_FLAT_1_ADDR UINT8_C(0x68) +#define BMI160_FOC_CONF_ADDR UINT8_C(0x69) +#define BMI160_CONF_ADDR UINT8_C(0x6A) + +#define BMI160_IF_CONF_ADDR UINT8_C(0x6B) +#define BMI160_SELF_TEST_ADDR UINT8_C(0x6D) +#define BMI160_OFFSET_ADDR UINT8_C(0x71) +#define BMI160_OFFSET_CONF_ADDR UINT8_C(0x77) +#define BMI160_INT_STEP_CNT_0_ADDR UINT8_C(0x78) +#define BMI160_INT_STEP_CONFIG_0_ADDR UINT8_C(0x7A) +#define BMI160_INT_STEP_CONFIG_1_ADDR UINT8_C(0x7B) +#define BMI160_COMMAND_REG_ADDR UINT8_C(0x7E) +#define BMI160_SPI_COMM_TEST_ADDR UINT8_C(0x7F) +#define BMI160_INTL_PULLUP_CONF_ADDR UINT8_C(0x85) + +/** Error code definitions */ +#define BMI160_OK INT8_C(0) +#define BMI160_E_NULL_PTR INT8_C(-1) +#define BMI160_E_COM_FAIL INT8_C(-2) +#define BMI160_E_DEV_NOT_FOUND INT8_C(-3) +#define BMI160_E_OUT_OF_RANGE INT8_C(-4) +#define BMI160_E_INVALID_INPUT INT8_C(-5) +#define BMI160_E_ACCEL_ODR_BW_INVALID INT8_C(-6) +#define BMI160_E_GYRO_ODR_BW_INVALID INT8_C(-7) +#define BMI160_E_LWP_PRE_FLTR_INT_INVALID INT8_C(-8) +#define BMI160_E_LWP_PRE_FLTR_INVALID INT8_C(-9) +#define BMI160_E_AUX_NOT_FOUND INT8_C(-10) +#define BMI160_E_FOC_FAILURE INT8_C(-11) +#define BMI160_E_READ_WRITE_LENGTH_INVALID INT8_C(-12) +#define BMI160_E_INVALID_CONFIG INT8_C(-13) + +/**\name API warning codes */ +#define BMI160_W_GYRO_SELF_TEST_FAIL INT8_C(1) +#define BMI160_W_ACCEl_SELF_TEST_FAIL INT8_C(2) + +/** Chip identifier. + * Standalone BMI160 reports 0xD1; the BMX160 combo part reports 0xD8. + * This fork uses the BMX160 value so bmi160_init() binds to the combo IC. + */ +#define BMI160_CHIP_ID UINT8_C(0xD8) + +/** Soft reset command */ +#define BMI160_SOFT_RESET_CMD UINT8_C(0xb6) +#define BMI160_SOFT_RESET_DELAY_MS UINT8_C(1) + +/** Start FOC command */ +#define BMI160_START_FOC_CMD UINT8_C(0x03) + +/** NVM backup enabling command */ +#define BMI160_NVM_BACKUP_EN UINT8_C(0xA0) + +/* Delay in ms settings */ +#define BMI160_ACCEL_DELAY_MS UINT8_C(5) +#define BMI160_GYRO_DELAY_MS UINT8_C(80) +#define BMI160_ONE_MS_DELAY UINT8_C(1) +#define BMI160_AUX_COM_DELAY UINT8_C(10) +#define BMI160_GYRO_SELF_TEST_DELAY UINT8_C(20) +#define BMI160_ACCEL_SELF_TEST_DELAY UINT8_C(50) + +/** Self test configurations */ +#define BMI160_ACCEL_SELF_TEST_CONFIG UINT8_C(0x2C) +#define BMI160_ACCEL_SELF_TEST_POSITIVE_EN UINT8_C(0x0D) +#define BMI160_ACCEL_SELF_TEST_NEGATIVE_EN UINT8_C(0x09) +#define BMI160_ACCEL_SELF_TEST_LIMIT UINT16_C(8192) + +/** Power mode settings */ +/* Accel power mode */ +#define BMI160_ACCEL_NORMAL_MODE UINT8_C(0x11) +#define BMI160_ACCEL_LOWPOWER_MODE UINT8_C(0x12) +#define BMI160_ACCEL_SUSPEND_MODE UINT8_C(0x10) + +/* Gyro power mode */ +#define BMI160_GYRO_SUSPEND_MODE UINT8_C(0x14) +#define BMI160_GYRO_NORMAL_MODE UINT8_C(0x15) +#define BMI160_GYRO_FASTSTARTUP_MODE UINT8_C(0x17) + +/* Aux power mode */ +#define BMI160_AUX_SUSPEND_MODE UINT8_C(0x18) +#define BMI160_AUX_NORMAL_MODE UINT8_C(0x19) +#define BMI160_AUX_LOWPOWER_MODE UINT8_C(0x1A) + +/** Range settings */ +/* Accel Range */ +#define BMI160_ACCEL_RANGE_2G UINT8_C(0x03) +#define BMI160_ACCEL_RANGE_4G UINT8_C(0x05) +#define BMI160_ACCEL_RANGE_8G UINT8_C(0x08) +#define BMI160_ACCEL_RANGE_16G UINT8_C(0x0C) + +/* Gyro Range */ +#define BMI160_GYRO_RANGE_2000_DPS UINT8_C(0x00) +#define BMI160_GYRO_RANGE_1000_DPS UINT8_C(0x01) +#define BMI160_GYRO_RANGE_500_DPS UINT8_C(0x02) +#define BMI160_GYRO_RANGE_250_DPS UINT8_C(0x03) +#define BMI160_GYRO_RANGE_125_DPS UINT8_C(0x04) + +/** Bandwidth settings */ +/* Accel Bandwidth */ +#define BMI160_ACCEL_BW_OSR4_AVG1 UINT8_C(0x00) +#define BMI160_ACCEL_BW_OSR2_AVG2 UINT8_C(0x01) +#define BMI160_ACCEL_BW_NORMAL_AVG4 UINT8_C(0x02) +#define BMI160_ACCEL_BW_RES_AVG8 UINT8_C(0x03) +#define BMI160_ACCEL_BW_RES_AVG16 UINT8_C(0x04) +#define BMI160_ACCEL_BW_RES_AVG32 UINT8_C(0x05) +#define BMI160_ACCEL_BW_RES_AVG64 UINT8_C(0x06) +#define BMI160_ACCEL_BW_RES_AVG128 UINT8_C(0x07) + +#define BMI160_GYRO_BW_OSR4_MODE UINT8_C(0x00) +#define BMI160_GYRO_BW_OSR2_MODE UINT8_C(0x01) +#define BMI160_GYRO_BW_NORMAL_MODE UINT8_C(0x02) + +/* Output Data Rate settings */ +/* Accel Output data rate */ +#define BMI160_ACCEL_ODR_RESERVED UINT8_C(0x00) +#define BMI160_ACCEL_ODR_0_78HZ UINT8_C(0x01) +#define BMI160_ACCEL_ODR_1_56HZ UINT8_C(0x02) +#define BMI160_ACCEL_ODR_3_12HZ UINT8_C(0x03) +#define BMI160_ACCEL_ODR_6_25HZ UINT8_C(0x04) +#define BMI160_ACCEL_ODR_12_5HZ UINT8_C(0x05) +#define BMI160_ACCEL_ODR_25HZ UINT8_C(0x06) +#define BMI160_ACCEL_ODR_50HZ UINT8_C(0x07) +#define BMI160_ACCEL_ODR_100HZ UINT8_C(0x08) +#define BMI160_ACCEL_ODR_200HZ UINT8_C(0x09) +#define BMI160_ACCEL_ODR_400HZ UINT8_C(0x0A) +#define BMI160_ACCEL_ODR_800HZ UINT8_C(0x0B) +#define BMI160_ACCEL_ODR_1600HZ UINT8_C(0x0C) +#define BMI160_ACCEL_ODR_RESERVED0 UINT8_C(0x0D) +#define BMI160_ACCEL_ODR_RESERVED1 UINT8_C(0x0E) +#define BMI160_ACCEL_ODR_RESERVED2 UINT8_C(0x0F) + +/* Gyro Output data rate */ +#define BMI160_GYRO_ODR_RESERVED UINT8_C(0x00) +#define BMI160_GYRO_ODR_25HZ UINT8_C(0x06) +#define BMI160_GYRO_ODR_50HZ UINT8_C(0x07) +#define BMI160_GYRO_ODR_100HZ UINT8_C(0x08) +#define BMI160_GYRO_ODR_200HZ UINT8_C(0x09) +#define BMI160_GYRO_ODR_400HZ UINT8_C(0x0A) +#define BMI160_GYRO_ODR_800HZ UINT8_C(0x0B) +#define BMI160_GYRO_ODR_1600HZ UINT8_C(0x0C) +#define BMI160_GYRO_ODR_3200HZ UINT8_C(0x0D) + +/* Auxiliary sensor Output data rate */ +#define BMI160_AUX_ODR_RESERVED UINT8_C(0x00) +#define BMI160_AUX_ODR_0_78HZ UINT8_C(0x01) +#define BMI160_AUX_ODR_1_56HZ UINT8_C(0x02) +#define BMI160_AUX_ODR_3_12HZ UINT8_C(0x03) +#define BMI160_AUX_ODR_6_25HZ UINT8_C(0x04) +#define BMI160_AUX_ODR_12_5HZ UINT8_C(0x05) +#define BMI160_AUX_ODR_25HZ UINT8_C(0x06) +#define BMI160_AUX_ODR_50HZ UINT8_C(0x07) +#define BMI160_AUX_ODR_100HZ UINT8_C(0x08) +#define BMI160_AUX_ODR_200HZ UINT8_C(0x09) +#define BMI160_AUX_ODR_400HZ UINT8_C(0x0A) +#define BMI160_AUX_ODR_800HZ UINT8_C(0x0B) + +/** FIFO_CONFIG Definitions */ +#define BMI160_FIFO_TIME_ENABLE UINT8_C(0x02) +#define BMI160_FIFO_TAG_INT2_ENABLE UINT8_C(0x04) +#define BMI160_FIFO_TAG_INT1_ENABLE UINT8_C(0x08) +#define BMI160_FIFO_HEAD_ENABLE UINT8_C(0x10) +#define BMI160_FIFO_M_ENABLE UINT8_C(0x20) +#define BMI160_FIFO_A_ENABLE UINT8_C(0x40) +#define BMI160_FIFO_M_A_ENABLE UINT8_C(0x60) +#define BMI160_FIFO_G_ENABLE UINT8_C(0x80) +#define BMI160_FIFO_M_G_ENABLE UINT8_C(0xA0) +#define BMI160_FIFO_G_A_ENABLE UINT8_C(0xC0) +#define BMI160_FIFO_M_G_A_ENABLE UINT8_C(0xE0) + +/* Macro to specify the number of bytes over-read from the + * FIFO in order to get the sensor time at the end of FIFO */ +#ifndef BMI160_FIFO_BYTES_OVERREAD +#define BMI160_FIFO_BYTES_OVERREAD UINT8_C(25) +#endif + +/* Accel, gyro and aux. sensor length and also their combined + * length definitions in FIFO */ +#define BMI160_FIFO_G_LENGTH UINT8_C(6) +#define BMI160_FIFO_A_LENGTH UINT8_C(6) +#define BMI160_FIFO_M_LENGTH UINT8_C(8) +#define BMI160_FIFO_GA_LENGTH UINT8_C(12) +#define BMI160_FIFO_MA_LENGTH UINT8_C(14) +#define BMI160_FIFO_MG_LENGTH UINT8_C(14) +#define BMI160_FIFO_MGA_LENGTH UINT8_C(20) + +/** FIFO Header Data definitions */ +#define BMI160_FIFO_HEAD_SKIP_FRAME UINT8_C(0x40) +#define BMI160_FIFO_HEAD_SENSOR_TIME UINT8_C(0x44) +#define BMI160_FIFO_HEAD_INPUT_CONFIG UINT8_C(0x48) +#define BMI160_FIFO_HEAD_OVER_READ UINT8_C(0x80) +#define BMI160_FIFO_HEAD_A UINT8_C(0x84) +#define BMI160_FIFO_HEAD_G UINT8_C(0x88) +#define BMI160_FIFO_HEAD_G_A UINT8_C(0x8C) +#define BMI160_FIFO_HEAD_M UINT8_C(0x90) +#define BMI160_FIFO_HEAD_M_A UINT8_C(0x94) +#define BMI160_FIFO_HEAD_M_G UINT8_C(0x98) +#define BMI160_FIFO_HEAD_M_G_A UINT8_C(0x9C) + +/** FIFO sensor time length definitions */ +#define BMI160_SENSOR_TIME_LENGTH UINT8_C(3) + +/** FIFO DOWN selection */ +/* Accel fifo down-sampling values*/ +#define BMI160_ACCEL_FIFO_DOWN_ZERO UINT8_C(0x00) +#define BMI160_ACCEL_FIFO_DOWN_ONE UINT8_C(0x10) +#define BMI160_ACCEL_FIFO_DOWN_TWO UINT8_C(0x20) +#define BMI160_ACCEL_FIFO_DOWN_THREE UINT8_C(0x30) +#define BMI160_ACCEL_FIFO_DOWN_FOUR UINT8_C(0x40) +#define BMI160_ACCEL_FIFO_DOWN_FIVE UINT8_C(0x50) +#define BMI160_ACCEL_FIFO_DOWN_SIX UINT8_C(0x60) +#define BMI160_ACCEL_FIFO_DOWN_SEVEN UINT8_C(0x70) + +/* Gyro fifo down-smapling values*/ +#define BMI160_GYRO_FIFO_DOWN_ZERO UINT8_C(0x00) +#define BMI160_GYRO_FIFO_DOWN_ONE UINT8_C(0x01) +#define BMI160_GYRO_FIFO_DOWN_TWO UINT8_C(0x02) +#define BMI160_GYRO_FIFO_DOWN_THREE UINT8_C(0x03) +#define BMI160_GYRO_FIFO_DOWN_FOUR UINT8_C(0x04) +#define BMI160_GYRO_FIFO_DOWN_FIVE UINT8_C(0x05) +#define BMI160_GYRO_FIFO_DOWN_SIX UINT8_C(0x06) +#define BMI160_GYRO_FIFO_DOWN_SEVEN UINT8_C(0x07) + +/* Accel Fifo filter enable*/ +#define BMI160_ACCEL_FIFO_FILT_EN UINT8_C(0x80) + +/* Gyro Fifo filter enable*/ +#define BMI160_GYRO_FIFO_FILT_EN UINT8_C(0x08) + +/** Definitions to check validity of FIFO frames */ +#define FIFO_CONFIG_MSB_CHECK UINT8_C(0x80) +#define FIFO_CONFIG_LSB_CHECK UINT8_C(0x00) + +/*! BMI160 accel FOC configurations */ +#define BMI160_FOC_ACCEL_DISABLED UINT8_C(0x00) +#define BMI160_FOC_ACCEL_POSITIVE_G UINT8_C(0x01) +#define BMI160_FOC_ACCEL_NEGATIVE_G UINT8_C(0x02) +#define BMI160_FOC_ACCEL_0G UINT8_C(0x03) + +/** Array Parameter DefinItions */ +#define BMI160_SENSOR_TIME_LSB_BYTE UINT8_C(0) +#define BMI160_SENSOR_TIME_XLSB_BYTE UINT8_C(1) +#define BMI160_SENSOR_TIME_MSB_BYTE UINT8_C(2) + +/** Interface settings */ +#define BMI160_SPI_INTF UINT8_C(1) +#define BMI160_I2C_INTF UINT8_C(0) +#define BMI160_SPI_RD_MASK UINT8_C(0x80) +#define BMI160_SPI_WR_MASK UINT8_C(0x7F) + +/* Sensor & time select definition*/ +#define BMI160_ACCEL_SEL UINT8_C(0x01) +#define BMI160_GYRO_SEL UINT8_C(0x02) +#define BMI160_TIME_SEL UINT8_C(0x04) + +/* Sensor select mask*/ +#define BMI160_SEN_SEL_MASK UINT8_C(0x07) + +/* Error code mask */ +#define BMI160_ERR_REG_MASK UINT8_C(0x0F) + +/* BMI160 I2C address */ +#define BMI160_I2C_ADDR UINT8_C(0x68) + +/* BMI160 secondary IF address */ +#define BMI160_AUX_BMM150_I2C_ADDR UINT8_C(0x10) + +/** BMI160 Length definitions */ +#define BMI160_ONE UINT8_C(1) +#define BMI160_TWO UINT8_C(2) +#define BMI160_THREE UINT8_C(3) +#define BMI160_FOUR UINT8_C(4) +#define BMI160_FIVE UINT8_C(5) + +/** BMI160 fifo level Margin */ +#define BMI160_FIFO_LEVEL_MARGIN UINT8_C(16) + +/** BMI160 fifo flush Command */ +#define BMI160_FIFO_FLUSH_VALUE UINT8_C(0xB0) + +/** BMI160 offset values for xyz axes of accel */ +#define BMI160_ACCEL_MIN_OFFSET INT8_C(-128) +#define BMI160_ACCEL_MAX_OFFSET INT8_C(127) + +/** BMI160 offset values for xyz axes of gyro */ +#define BMI160_GYRO_MIN_OFFSET INT16_C(-512) +#define BMI160_GYRO_MAX_OFFSET INT16_C(511) + +/** BMI160 fifo full interrupt position and mask */ +#define BMI160_FIFO_FULL_INT_POS UINT8_C(5) +#define BMI160_FIFO_FULL_INT_MSK UINT8_C(0x20) +#define BMI160_FIFO_WTM_INT_POS UINT8_C(6) +#define BMI160_FIFO_WTM_INT_MSK UINT8_C(0x40) + +#define BMI160_FIFO_FULL_INT_PIN1_POS UINT8_C(5) +#define BMI160_FIFO_FULL_INT_PIN1_MSK UINT8_C(0x20) +#define BMI160_FIFO_FULL_INT_PIN2_POS UINT8_C(1) +#define BMI160_FIFO_FULL_INT_PIN2_MSK UINT8_C(0x02) + +#define BMI160_FIFO_WTM_INT_PIN1_POS UINT8_C(6) +#define BMI160_FIFO_WTM_INT_PIN1_MSK UINT8_C(0x40) +#define BMI160_FIFO_WTM_INT_PIN2_POS UINT8_C(2) +#define BMI160_FIFO_WTM_INT_PIN2_MSK UINT8_C(0x04) + +#define BMI160_MANUAL_MODE_EN_POS UINT8_C(7) +#define BMI160_MANUAL_MODE_EN_MSK UINT8_C(0x80) +#define BMI160_AUX_READ_BURST_POS UINT8_C(0) +#define BMI160_AUX_READ_BURST_MSK UINT8_C(0x03) + +#define BMI160_GYRO_SELF_TEST_POS UINT8_C(4) +#define BMI160_GYRO_SELF_TEST_MSK UINT8_C(0x10) +#define BMI160_GYRO_SELF_TEST_STATUS_POS UINT8_C(1) +#define BMI160_GYRO_SELF_TEST_STATUS_MSK UINT8_C(0x02) + +#define BMI160_GYRO_FOC_EN_POS UINT8_C(6) +#define BMI160_GYRO_FOC_EN_MSK UINT8_C(0x40) + +#define BMI160_ACCEL_FOC_X_CONF_POS UINT8_C(4) +#define BMI160_ACCEL_FOC_X_CONF_MSK UINT8_C(0x30) + +#define BMI160_ACCEL_FOC_Y_CONF_POS UINT8_C(2) +#define BMI160_ACCEL_FOC_Y_CONF_MSK UINT8_C(0x0C) + +#define BMI160_ACCEL_FOC_Z_CONF_MSK UINT8_C(0x03) + +#define BMI160_FOC_STATUS_POS UINT8_C(3) +#define BMI160_FOC_STATUS_MSK UINT8_C(0x08) + +#define BMI160_GYRO_OFFSET_X_MSK UINT8_C(0x03) + +#define BMI160_GYRO_OFFSET_Y_POS UINT8_C(2) +#define BMI160_GYRO_OFFSET_Y_MSK UINT8_C(0x0C) + +#define BMI160_GYRO_OFFSET_Z_POS UINT8_C(4) +#define BMI160_GYRO_OFFSET_Z_MSK UINT8_C(0x30) + +#define BMI160_GYRO_OFFSET_EN_POS UINT8_C(7) +#define BMI160_GYRO_OFFSET_EN_MSK UINT8_C(0x80) + +#define BMI160_ACCEL_OFFSET_EN_POS UINT8_C(6) +#define BMI160_ACCEL_OFFSET_EN_MSK UINT8_C(0x40) + +#define BMI160_GYRO_OFFSET_POS UINT16_C(8) +#define BMI160_GYRO_OFFSET_MSK UINT16_C(0x0300) + +#define BMI160_NVM_UPDATE_POS UINT8_C(1) +#define BMI160_NVM_UPDATE_MSK UINT8_C(0x02) + +#define BMI160_NVM_STATUS_POS UINT8_C(4) +#define BMI160_NVM_STATUS_MSK UINT8_C(0x10) + +#define BMI160_MAG_POWER_MODE_MSK UINT8_C(0x03) + +#define BMI160_ACCEL_POWER_MODE_MSK UINT8_C(0x30) +#define BMI160_ACCEL_POWER_MODE_POS UINT8_C(4) + +#define BMI160_GYRO_POWER_MODE_MSK UINT8_C(0x0C) +#define BMI160_GYRO_POWER_MODE_POS UINT8_C(2) + +/* BIT SLICE GET AND SET FUNCTIONS */ +#define BMI160_GET_BITS(regvar, bitname) \ + ((regvar & bitname##_MSK) >> bitname##_POS) +#define BMI160_SET_BITS(regvar, bitname, val) \ + ((regvar & ~bitname##_MSK) | \ + ((val << bitname##_POS) & bitname##_MSK)) + +#define BMI160_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + (data & bitname##_MSK)) + +#define BMI160_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +/**\name UTILITY MACROS */ +#define BMI160_SET_LOW_BYTE UINT16_C(0x00FF) +#define BMI160_SET_HIGH_BYTE UINT16_C(0xFF00) + +#define BMI160_GET_LSB(var) (uint8_t)(var & BMI160_SET_LOW_BYTE) +#define BMI160_GET_MSB(var) (uint8_t)((var & BMI160_SET_HIGH_BYTE) >> 8) + +/*****************************************************************************/ +/* type definitions */ + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific read functions of the user + */ +typedef int8_t (*bmi160_read_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len); + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific write functions of the user + */ +typedef int8_t (*bmi160_write_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *read_data, uint16_t len); +typedef void (*bmi160_delay_fptr_t)(uint32_t period); + +/*************************** Data structures *********************************/ + +/*! + * @brief bmi160 interrupt status selection enum. + */ +enum bmi160_int_status_sel { + BMI160_INT_STATUS_0 = 1, + BMI160_INT_STATUS_1 = 2, + BMI160_INT_STATUS_2 = 4, + BMI160_INT_STATUS_3 = 8, + BMI160_INT_STATUS_ALL = 15 +}; + +/*! + * @brief bmi160 interrupt status bits structure + */ +struct bmi160_int_status_bits +{ +#ifdef LITTLE_ENDIAN + + uint32_t step : 1; + uint32_t sigmot : 1; + uint32_t anym : 1; + + /* pmu trigger will be handled later */ + uint32_t pmu_trigger_reserved : 1; + uint32_t d_tap : 1; + uint32_t s_tap : 1; + uint32_t orient : 1; + uint32_t flat_int : 1; + uint32_t reserved : 2; + uint32_t high_g : 1; + uint32_t low_g : 1; + uint32_t drdy : 1; + uint32_t ffull : 1; + uint32_t fwm : 1; + uint32_t nomo : 1; + uint32_t anym_first_x : 1; + uint32_t anym_first_y : 1; + uint32_t anym_first_z : 1; + uint32_t anym_sign : 1; + uint32_t tap_first_x : 1; + uint32_t tap_first_y : 1; + uint32_t tap_first_z : 1; + uint32_t tap_sign : 1; + uint32_t high_first_x : 1; + uint32_t high_first_y : 1; + uint32_t high_first_z : 1; + uint32_t high_sign : 1; + uint32_t orient_1_0 : 2; + uint32_t orient_2 : 1; + uint32_t flat : 1; +#else + uint32_t high_first_x : 1; + uint32_t high_first_y : 1; + uint32_t high_first_z : 1; + uint32_t high_sign : 1; + uint32_t orient_1_0 : 2; + uint32_t orient_2 : 1; + uint32_t flat : 1; + uint32_t anym_first_x : 1; + uint32_t anym_first_y : 1; + uint32_t anym_first_z : 1; + uint32_t anym_sign : 1; + uint32_t tap_first_x : 1; + uint32_t tap_first_y : 1; + uint32_t tap_first_z : 1; + uint32_t tap_sign : 1; + uint32_t reserved : 2; + uint32_t high_g : 1; + uint32_t low_g : 1; + uint32_t drdy : 1; + uint32_t ffull : 1; + uint32_t fwm : 1; + uint32_t nomo : 1; + uint32_t step : 1; + uint32_t sigmot : 1; + uint32_t anym : 1; + + /* pmu trigger will be handled later */ + uint32_t pmu_trigger_reserved : 1; + uint32_t d_tap : 1; + uint32_t s_tap : 1; + uint32_t orient : 1; + uint32_t flat_int : 1; +#endif +}; + +/*! + * @brief bmi160 interrupt status structure + */ +union bmi160_int_status +{ + uint8_t data[4]; + struct bmi160_int_status_bits bit; +}; + +/*! + * @brief bmi160 sensor data structure which comprises of accel data + */ +struct bmi160_sensor_data +{ + /*! X-axis sensor data */ + int16_t x; + + /*! Y-axis sensor data */ + int16_t y; + + /*! Z-axis sensor data */ + int16_t z; + + /*! sensor time */ + uint32_t sensortime; +}; + +/*! + * @brief bmi160 aux data structure which comprises of 8 bytes of accel data + */ +struct bmi160_aux_data +{ + /*! Auxiliary data */ + uint8_t data[8]; +}; + +/*! + * @brief bmi160 FOC configuration structure + */ +struct bmi160_foc_conf +{ + /*! Enabling FOC in gyro + * Assignable macros : + * - BMI160_ENABLE + * - BMI160_DISABLE + */ + uint8_t foc_gyr_en; + + /*! Accel FOC configurations + * Assignable macros : + * - BMI160_FOC_ACCEL_DISABLED + * - BMI160_FOC_ACCEL_POSITIVE_G + * - BMI160_FOC_ACCEL_NEGATIVE_G + * - BMI160_FOC_ACCEL_0G + */ + uint8_t foc_acc_x; + uint8_t foc_acc_y; + uint8_t foc_acc_z; + + /*! Enabling offset compensation for accel in data registers + * Assignable macros : + * - BMI160_ENABLE + * - BMI160_DISABLE + */ + uint8_t acc_off_en; + + /*! Enabling offset compensation for gyro in data registers + * Assignable macros : + * - BMI160_ENABLE + * - BMI160_DISABLE + */ + uint8_t gyro_off_en; +}; + +/*! + * @brief bmi160 accel gyro offsets + */ +struct bmi160_offsets +{ + /*! Accel offset for x axis */ + int8_t off_acc_x; + + /*! Accel offset for y axis */ + int8_t off_acc_y; + + /*! Accel offset for z axis */ + int8_t off_acc_z; + + /*! Gyro offset for x axis */ + int16_t off_gyro_x; + + /*! Gyro offset for y axis */ + int16_t off_gyro_y; + + /*! Gyro offset for z axis */ + int16_t off_gyro_z; +}; + +/*! + * @brief FIFO aux. sensor data structure + */ +struct bmi160_aux_fifo_data +{ + /*! The value of aux. sensor x LSB data */ + uint8_t aux_x_lsb; + + /*! The value of aux. sensor x MSB data */ + uint8_t aux_x_msb; + + /*! The value of aux. sensor y LSB data */ + uint8_t aux_y_lsb; + + /*! The value of aux. sensor y MSB data */ + uint8_t aux_y_msb; + + /*! The value of aux. sensor z LSB data */ + uint8_t aux_z_lsb; + + /*! The value of aux. sensor z MSB data */ + uint8_t aux_z_msb; + + /*! The value of aux. sensor r for BMM150 LSB data */ + uint8_t aux_r_y2_lsb; + + /*! The value of aux. sensor r for BMM150 MSB data */ + uint8_t aux_r_y2_msb; +}; + +/*! + * @brief bmi160 sensor select structure + */ +enum bmi160_select_sensor { + BMI160_ACCEL_ONLY = 1, + BMI160_GYRO_ONLY, + BMI160_BOTH_ACCEL_AND_GYRO +}; + +/*! + * @brief bmi160 sensor step detector mode structure + */ +enum bmi160_step_detect_mode { + BMI160_STEP_DETECT_NORMAL, + BMI160_STEP_DETECT_SENSITIVE, + BMI160_STEP_DETECT_ROBUST, + + /*! Non recommended User defined setting */ + BMI160_STEP_DETECT_USER_DEFINE +}; + +/*! + * @brief enum for auxiliary burst read selection + */ +enum bmi160_aux_read_len { + BMI160_AUX_READ_LEN_0, + BMI160_AUX_READ_LEN_1, + BMI160_AUX_READ_LEN_2, + BMI160_AUX_READ_LEN_3 +}; + +/*! + * @brief bmi160 sensor configuration structure + */ +struct bmi160_cfg +{ + /*! power mode */ + uint8_t power; + + /*! output data rate */ + uint8_t odr; + + /*! range */ + uint8_t range; + + /*! bandwidth */ + uint8_t bw; +}; + +/*! + * @brief Aux sensor configuration structure + */ +struct bmi160_aux_cfg +{ + /*! Aux sensor, 1 - enable 0 - disable */ + uint8_t aux_sensor_enable : 1; + + /*! Aux manual/auto mode status */ + uint8_t manual_enable : 1; + + /*! Aux read burst length */ + uint8_t aux_rd_burst_len : 2; + + /*! output data rate */ + uint8_t aux_odr : 4; + + /*! i2c addr of auxiliary sensor */ + uint8_t aux_i2c_addr; +}; + +/*! + * @brief bmi160 interrupt channel selection structure + */ +enum bmi160_int_channel { + /*! Un-map both channels */ + BMI160_INT_CHANNEL_NONE, + + /*! interrupt Channel 1 */ + BMI160_INT_CHANNEL_1, + + /*! interrupt Channel 2 */ + BMI160_INT_CHANNEL_2, + + /*! Map both channels */ + BMI160_INT_CHANNEL_BOTH +}; +enum bmi160_int_types { + /*! Slope/Any-motion interrupt */ + BMI160_ACC_ANY_MOTION_INT, + + /*! Significant motion interrupt */ + BMI160_ACC_SIG_MOTION_INT, + + /*! Step detector interrupt */ + BMI160_STEP_DETECT_INT, + + /*! double tap interrupt */ + BMI160_ACC_DOUBLE_TAP_INT, + + /*! single tap interrupt */ + BMI160_ACC_SINGLE_TAP_INT, + + /*! orientation interrupt */ + BMI160_ACC_ORIENT_INT, + + /*! flat interrupt */ + BMI160_ACC_FLAT_INT, + + /*! high-g interrupt */ + BMI160_ACC_HIGH_G_INT, + + /*! low-g interrupt */ + BMI160_ACC_LOW_G_INT, + + /*! slow/no-motion interrupt */ + BMI160_ACC_SLOW_NO_MOTION_INT, + + /*! data ready interrupt */ + BMI160_ACC_GYRO_DATA_RDY_INT, + + /*! fifo full interrupt */ + BMI160_ACC_GYRO_FIFO_FULL_INT, + + /*! fifo watermark interrupt */ + BMI160_ACC_GYRO_FIFO_WATERMARK_INT, + + /*! fifo tagging feature support */ + BMI160_FIFO_TAG_INT_PIN +}; + +/*! + * @brief bmi160 active state of any & sig motion interrupt. + */ +enum bmi160_any_sig_motion_active_interrupt_state { + /*! Both any & sig motion are disabled */ + BMI160_BOTH_ANY_SIG_MOTION_DISABLED = -1, + + /*! Any-motion selected */ + BMI160_ANY_MOTION_ENABLED, + + /*! Sig-motion selected */ + BMI160_SIG_MOTION_ENABLED +}; +struct bmi160_acc_tap_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! tap threshold */ + uint16_t tap_thr : 5; + + /*! tap shock */ + uint16_t tap_shock : 1; + + /*! tap quiet */ + uint16_t tap_quiet : 1; + + /*! tap duration */ + uint16_t tap_dur : 3; + + /*! data source 0- filter & 1 pre-filter*/ + uint16_t tap_data_src : 1; + + /*! tap enable, 1 - enable, 0 - disable */ + uint16_t tap_en : 1; +#else + + /*! tap enable, 1 - enable, 0 - disable */ + uint16_t tap_en : 1; + + /*! data source 0- filter & 1 pre-filter*/ + uint16_t tap_data_src : 1; + + /*! tap duration */ + uint16_t tap_dur : 3; + + /*! tap quiet */ + uint16_t tap_quiet : 1; + + /*! tap shock */ + uint16_t tap_shock : 1; + + /*! tap threshold */ + uint16_t tap_thr : 5; +#endif +}; +struct bmi160_acc_any_mot_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! 1 any-motion enable, 0 - any-motion disable */ + uint8_t anymotion_en : 1; + + /*! slope interrupt x, 1 - enable, 0 - disable */ + uint8_t anymotion_x : 1; + + /*! slope interrupt y, 1 - enable, 0 - disable */ + uint8_t anymotion_y : 1; + + /*! slope interrupt z, 1 - enable, 0 - disable */ + uint8_t anymotion_z : 1; + + /*! slope duration */ + uint8_t anymotion_dur : 2; + + /*! data source 0- filter & 1 pre-filter*/ + uint8_t anymotion_data_src : 1; + + /*! slope threshold */ + uint8_t anymotion_thr; +#else + + /*! slope threshold */ + uint8_t anymotion_thr; + + /*! data source 0- filter & 1 pre-filter*/ + uint8_t anymotion_data_src : 1; + + /*! slope duration */ + uint8_t anymotion_dur : 2; + + /*! slope interrupt z, 1 - enable, 0 - disable */ + uint8_t anymotion_z : 1; + + /*! slope interrupt y, 1 - enable, 0 - disable */ + uint8_t anymotion_y : 1; + + /*! slope interrupt x, 1 - enable, 0 - disable */ + uint8_t anymotion_x : 1; + + /*! 1 any-motion enable, 0 - any-motion disable */ + uint8_t anymotion_en : 1; +#endif +}; +struct bmi160_acc_sig_mot_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! skip time of sig-motion interrupt */ + uint8_t sig_mot_skip : 2; + + /*! proof time of sig-motion interrupt */ + uint8_t sig_mot_proof : 2; + + /*! data source 0- filter & 1 pre-filter*/ + uint8_t sig_data_src : 1; + + /*! 1 - enable sig, 0 - disable sig & enable anymotion */ + uint8_t sig_en : 1; + + /*! sig-motion threshold */ + uint8_t sig_mot_thres; +#else + + /*! sig-motion threshold */ + uint8_t sig_mot_thres; + + /*! 1 - enable sig, 0 - disable sig & enable anymotion */ + uint8_t sig_en : 1; + + /*! data source 0- filter & 1 pre-filter*/ + uint8_t sig_data_src : 1; + + /*! proof time of sig-motion interrupt */ + uint8_t sig_mot_proof : 2; + + /*! skip time of sig-motion interrupt */ + uint8_t sig_mot_skip : 2; +#endif +}; +struct bmi160_acc_step_detect_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! 1- step detector enable, 0- step detector disable */ + uint16_t step_detector_en : 1; + + /*! minimum threshold */ + uint16_t min_threshold : 2; + + /*! minimal detectable step time */ + uint16_t steptime_min : 3; + + /*! enable step counter mode setting */ + uint16_t step_detector_mode : 2; + + /*! minimum step buffer size*/ + uint16_t step_min_buf : 3; +#else + + /*! minimum step buffer size*/ + uint16_t step_min_buf : 3; + + /*! enable step counter mode setting */ + uint16_t step_detector_mode : 2; + + /*! minimal detectable step time */ + uint16_t steptime_min : 3; + + /*! minimum threshold */ + uint16_t min_threshold : 2; + + /*! 1- step detector enable, 0- step detector disable */ + uint16_t step_detector_en : 1; +#endif +}; +struct bmi160_acc_no_motion_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! no motion interrupt x */ + uint16_t no_motion_x : 1; + + /*! no motion interrupt y */ + uint16_t no_motion_y : 1; + + /*! no motion interrupt z */ + uint16_t no_motion_z : 1; + + /*! no motion duration */ + uint16_t no_motion_dur : 6; + + /*! no motion sel , 1 - enable no-motion ,0- enable slow-motion */ + uint16_t no_motion_sel : 1; + + /*! data source 0- filter & 1 pre-filter*/ + uint16_t no_motion_src : 1; + + /*! no motion threshold */ + uint8_t no_motion_thres; +#else + + /*! no motion threshold */ + uint8_t no_motion_thres; + + /*! data source 0- filter & 1 pre-filter*/ + uint16_t no_motion_src : 1; + + /*! no motion sel , 1 - enable no-motion ,0- enable slow-motion */ + uint16_t no_motion_sel : 1; + + /*! no motion duration */ + uint16_t no_motion_dur : 6; + + /* no motion interrupt z */ + uint16_t no_motion_z : 1; + + /*! no motion interrupt y */ + uint16_t no_motion_y : 1; + + /*! no motion interrupt x */ + uint16_t no_motion_x : 1; +#endif +}; +struct bmi160_acc_orient_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! thresholds for switching between the different orientations */ + uint16_t orient_mode : 2; + + /*! blocking_mode */ + uint16_t orient_blocking : 2; + + /*! Orientation interrupt hysteresis */ + uint16_t orient_hyst : 4; + + /*! Orientation interrupt theta */ + uint16_t orient_theta : 6; + + /*! Enable/disable Orientation interrupt */ + uint16_t orient_ud_en : 1; + + /*! exchange x- and z-axis in algorithm ,0 - z, 1 - x */ + uint16_t axes_ex : 1; + + /*! 1 - orient enable, 0 - orient disable */ + uint8_t orient_en : 1; +#else + + /*! 1 - orient enable, 0 - orient disable */ + uint8_t orient_en : 1; + + /*! exchange x- and z-axis in algorithm ,0 - z, 1 - x */ + uint16_t axes_ex : 1; + + /*! Enable/disable Orientation interrupt */ + uint16_t orient_ud_en : 1; + + /*! Orientation interrupt theta */ + uint16_t orient_theta : 6; + + /*! Orientation interrupt hysteresis */ + uint16_t orient_hyst : 4; + + /*! blocking_mode */ + uint16_t orient_blocking : 2; + + /*! thresholds for switching between the different orientations */ + uint16_t orient_mode : 2; +#endif +}; +struct bmi160_acc_flat_detect_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! flat threshold */ + uint16_t flat_theta : 6; + + /*! flat interrupt hysteresis */ + uint16_t flat_hy : 3; + + /*! delay time for which the flat value must remain stable for the + * flat interrupt to be generated */ + uint16_t flat_hold_time : 2; + + /*! 1 - flat enable, 0 - flat disable */ + uint16_t flat_en : 1; +#else + + /*! 1 - flat enable, 0 - flat disable */ + uint16_t flat_en : 1; + + /*! delay time for which the flat value must remain stable for the + * flat interrupt to be generated */ + uint16_t flat_hold_time : 2; + + /*! flat interrupt hysteresis */ + uint16_t flat_hy : 3; + + /*! flat threshold */ + uint16_t flat_theta : 6; +#endif +}; +struct bmi160_acc_low_g_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! low-g interrupt trigger delay */ + uint8_t low_dur; + + /*! low-g interrupt trigger threshold */ + uint8_t low_thres; + + /*! hysteresis of low-g interrupt */ + uint8_t low_hyst : 2; + + /*! 0 - single-axis mode ,1 - axis-summing mode */ + uint8_t low_mode : 1; + + /*! data source 0- filter & 1 pre-filter */ + uint8_t low_data_src : 1; + + /*! 1 - enable low-g, 0 - disable low-g */ + uint8_t low_en : 1; +#else + + /*! 1 - enable low-g, 0 - disable low-g */ + uint8_t low_en : 1; + + /*! data source 0- filter & 1 pre-filter */ + uint8_t low_data_src : 1; + + /*! 0 - single-axis mode ,1 - axis-summing mode */ + uint8_t low_mode : 1; + + /*! hysteresis of low-g interrupt */ + uint8_t low_hyst : 2; + + /*! low-g interrupt trigger threshold */ + uint8_t low_thres; + + /*! low-g interrupt trigger delay */ + uint8_t low_dur; +#endif +}; +struct bmi160_acc_high_g_int_cfg +{ +#ifdef LITTLE_ENDIAN + + /*! High-g interrupt x, 1 - enable, 0 - disable */ + uint8_t high_g_x : 1; + + /*! High-g interrupt y, 1 - enable, 0 - disable */ + uint8_t high_g_y : 1; + + /*! High-g interrupt z, 1 - enable, 0 - disable */ + uint8_t high_g_z : 1; + + /*! High-g hysteresis */ + uint8_t high_hy : 2; + + /*! data source 0- filter & 1 pre-filter */ + uint8_t high_data_src : 1; + + /*! High-g threshold */ + uint8_t high_thres; + + /*! High-g duration */ + uint8_t high_dur; +#else + + /*! High-g duration */ + uint8_t high_dur; + + /*! High-g threshold */ + uint8_t high_thres; + + /*! data source 0- filter & 1 pre-filter */ + uint8_t high_data_src : 1; + + /*! High-g hysteresis */ + uint8_t high_hy : 2; + + /*! High-g interrupt z, 1 - enable, 0 - disable */ + uint8_t high_g_z : 1; + + /*! High-g interrupt y, 1 - enable, 0 - disable */ + uint8_t high_g_y : 1; + + /*! High-g interrupt x, 1 - enable, 0 - disable */ + uint8_t high_g_x : 1; +#endif +}; +struct bmi160_int_pin_settg +{ +#ifdef LITTLE_ENDIAN + + /*! To enable either INT1 or INT2 pin as output. + * 0- output disabled ,1- output enabled */ + uint16_t output_en : 1; + + /*! 0 - push-pull 1- open drain,only valid if output_en is set 1 */ + uint16_t output_mode : 1; + + /*! 0 - active low , 1 - active high level. + * if output_en is 1,this applies to interrupts,else PMU_trigger */ + uint16_t output_type : 1; + + /*! 0 - level trigger , 1 - edge trigger */ + uint16_t edge_ctrl : 1; + + /*! To enable either INT1 or INT2 pin as input. + * 0 - input disabled ,1 - input enabled */ + uint16_t input_en : 1; + + /*! latch duration*/ + uint16_t latch_dur : 4; +#else + + /*! latch duration*/ + uint16_t latch_dur : 4; + + /*! Latched,non-latched or temporary interrupt modes */ + uint16_t input_en : 1; + + /*! 1 - edge trigger, 0 - level trigger */ + uint16_t edge_ctrl : 1; + + /*! 0 - active low , 1 - active high level. + * if output_en is 1,this applies to interrupts,else PMU_trigger */ + uint16_t output_type : 1; + + /*! 0 - push-pull , 1 - open drain,only valid if output_en is set 1 */ + uint16_t output_mode : 1; + + /*! To enable either INT1 or INT2 pin as output. + * 0 - output disabled , 1 - output enabled */ + uint16_t output_en : 1; +#endif +}; +union bmi160_int_type_cfg +{ + /*! Tap interrupt structure */ + struct bmi160_acc_tap_int_cfg acc_tap_int; + + /*! Slope interrupt structure */ + struct bmi160_acc_any_mot_int_cfg acc_any_motion_int; + + /*! Significant motion interrupt structure */ + struct bmi160_acc_sig_mot_int_cfg acc_sig_motion_int; + + /*! Step detector interrupt structure */ + struct bmi160_acc_step_detect_int_cfg acc_step_detect_int; + + /*! No motion interrupt structure */ + struct bmi160_acc_no_motion_int_cfg acc_no_motion_int; + + /*! Orientation interrupt structure */ + struct bmi160_acc_orient_int_cfg acc_orient_int; + + /*! Flat interrupt structure */ + struct bmi160_acc_flat_detect_int_cfg acc_flat_int; + + /*! Low-g interrupt structure */ + struct bmi160_acc_low_g_int_cfg acc_low_g_int; + + /*! High-g interrupt structure */ + struct bmi160_acc_high_g_int_cfg acc_high_g_int; +}; +struct bmi160_int_settg +{ + /*! Interrupt channel */ + enum bmi160_int_channel int_channel; + + /*! Select Interrupt */ + enum bmi160_int_types int_type; + + /*! Structure configuring Interrupt pins */ + struct bmi160_int_pin_settg int_pin_settg; + + /*! Union configures required interrupt */ + union bmi160_int_type_cfg int_type_cfg; + + /*! FIFO FULL INT 1-enable, 0-disable */ + uint8_t fifo_full_int_en : 1; + + /*! FIFO WTM INT 1-enable, 0-disable */ + uint8_t fifo_wtm_int_en : 1; +}; + +/*! + * @brief This structure holds the information for usage of + * FIFO by the user. + */ +struct bmi160_fifo_frame +{ + /*! Data buffer of user defined length is to be mapped here */ + uint8_t *data; + + /*! While calling the API "bmi160_get_fifo_data" , length stores + * number of bytes in FIFO to be read (specified by user as input) + * and after execution of the API ,number of FIFO data bytes + * available is provided as an output to user + */ + uint16_t length; + + /*! FIFO time enable */ + uint8_t fifo_time_enable; + + /*! Enabling of the FIFO header to stream in header mode */ + uint8_t fifo_header_enable; + + /*! Streaming of the Accelerometer, Gyroscope + * sensor data or both in FIFO */ + uint8_t fifo_data_enable; + + /*! Will be equal to length when no more frames are there to parse */ + uint16_t accel_byte_start_idx; + + /*! Will be equal to length when no more frames are there to parse */ + uint16_t gyro_byte_start_idx; + + /*! Will be equal to length when no more frames are there to parse */ + uint16_t aux_byte_start_idx; + + /*! Value of FIFO sensor time time */ + uint32_t sensor_time; + + /*! Value of Skipped frame counts */ + uint8_t skipped_frame_count; +}; +struct bmi160_dev +{ + /*! Chip Id */ + uint8_t chip_id; + + /*! Device Id */ + uint8_t id; + + /*! 0 - I2C , 1 - SPI Interface */ + uint8_t intf; + + /*! Hold active interrupts status for any and sig motion + * 0 - Any-motion enable, 1 - Sig-motion enable, + * -1 neither any-motion nor sig-motion selected */ + enum bmi160_any_sig_motion_active_interrupt_state any_sig_sel; + + /*! Structure to configure Accel sensor */ + struct bmi160_cfg accel_cfg; + + /*! Structure to hold previous/old accel config parameters. + * This is used at driver level to prevent overwriting of same + * data, hence user does not change it in the code */ + struct bmi160_cfg prev_accel_cfg; + + /*! Structure to configure Gyro sensor */ + struct bmi160_cfg gyro_cfg; + + /*! Structure to hold previous/old gyro config parameters. + * This is used at driver level to prevent overwriting of same + * data, hence user does not change it in the code */ + struct bmi160_cfg prev_gyro_cfg; + + /*! Structure to configure the auxiliary sensor */ + struct bmi160_aux_cfg aux_cfg; + + /*! Structure to hold previous/old aux config parameters. + * This is used at driver level to prevent overwriting of same + * data, hence user does not change it in the code */ + struct bmi160_aux_cfg prev_aux_cfg; + + /*! FIFO related configurations */ + struct bmi160_fifo_frame *fifo; + + /*! Read function pointer */ + bmi160_read_fptr_t read; + + /*! Write function pointer */ + bmi160_write_fptr_t write; + + /*! Delay function pointer */ + bmi160_delay_fptr_t delay_ms; + + /*! User set read/write length */ + uint16_t read_write_len; +}; + +#endif /* BMI160_DEFS_H_ */ diff --git a/src/SensorManager/Baro.cpp b/src/SensorManager/Baro.cpp index 955b9519..178e82b5 100644 --- a/src/SensorManager/Baro.cpp +++ b/src/SensorManager/Baro.cpp @@ -1,15 +1,17 @@ #include "Baro.h" #include "SensorManager.h" +#include "sensor_sink.h" #include -#include #include #include LOG_MODULE_DECLARE(BMP388); static struct sensor_msg msg_baro; +static uint32_t baro_calls, baro_max_us; +static uint64_t baro_total_us; Adafruit_BMP3XX Baro::bmp; @@ -17,7 +19,6 @@ Baro Baro::sensor; static int baro_initial_discard = 1; -// Initialisierung der SampleRateSettings für Baro (BMP3) const SampleRateSetting<18> Baro::sample_rates = { { BMP3_ODR_0_001_HZ, BMP3_ODR_0_003_HZ, BMP3_ODR_0_006_HZ, BMP3_ODR_0_01_HZ, BMP3_ODR_0_02_HZ, BMP3_ODR_0_05_HZ, BMP3_ODR_0_1_HZ, BMP3_ODR_0_2_HZ, @@ -35,9 +36,15 @@ const SampleRateSetting<18> Baro::sample_rates = { }; void Baro::update_sensor(struct k_work *work) { + if (!sensor._running) return; + uint64_t t0 = micros(); + int ret; - bmp.performReading(); + if (!bmp.performReading()) { + LOG_WRN("BMP388 read failed"); + return; + } if (baro_initial_discard > 0) { baro_initial_discard--; @@ -51,14 +58,16 @@ void Baro::update_sensor(struct k_work *work) { msg_baro.data.size = 2 * sizeof(float); msg_baro.data.time = micros(); - float data[2] = {bmp.temperature, bmp.pressure}; + float data[2] = {(float)bmp.temperature, (float)bmp.pressure}; memcpy(msg_baro.data.data, data, 2 * sizeof(float)); - ret = k_msgq_put(sensor_queue, &msg_baro, K_NO_WAIT); - if (ret) { - LOG_WRN("sensor msg queue full"); - } + sensor_sink_put(&msg_baro); + + uint32_t elapsed = (uint32_t)(micros() - t0); + baro_calls++; + baro_total_us += elapsed; + if (elapsed > baro_max_us) baro_max_us = elapsed; } /** @@ -69,7 +78,7 @@ void Baro::sensor_timer_handler(struct k_timer *dummy) k_work_submit_to_queue(&sensor_work_q, &sensor.sensor_work); }; -bool Baro::init(struct k_msgq * queue) { +bool Baro::init() { if (!_active) { pm_device_runtime_get(ls_1_8); _active = true; @@ -82,8 +91,6 @@ bool Baro::init(struct k_msgq * queue) { return false; } - sensor_queue = queue; - k_work_init(&sensor.sensor_work, update_sensor); k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); @@ -94,9 +101,6 @@ void Baro::start(int sample_rate_idx) { baro_initial_discard = 1; k_timeout_t t = K_USEC(1e6 / sample_rates.true_sample_rates[sample_rate_idx]); - - //bmp.set_interrogation_rate(setting.reg_val); - //bmp.start(); k_timer_start(&sensor.sensor_timer, K_NO_WAIT, t); @@ -109,7 +113,17 @@ void Baro::stop() { _running = false; + uint32_t avg = baro_calls ? (uint32_t)(baro_total_us / baro_calls) : 0; + LOG_INF("baro: calls=%u avg=%u us max=%u us total=%u ms", + baro_calls, avg, baro_max_us, (uint32_t)(baro_total_us / 1000)); + baro_calls = 0; baro_total_us = 0; baro_max_us = 0; + k_timer_stop(&sensor.sensor_timer); + k_work_cancel(&sensor.sensor_work); + + /* Put BMP388 into sleep before cutting V_LS so the chip isn't mid- + * conversion when i2c3 drops. Suspect for the i2c3 dropout regression. */ + if (!bmp.sleep()) LOG_WRN("BMP388 sleep failed"); pm_device_runtime_put(ls_1_8); } \ No newline at end of file diff --git a/src/SensorManager/Baro.h b/src/SensorManager/Baro.h index 42c81058..4bc7a60e 100644 --- a/src/SensorManager/Baro.h +++ b/src/SensorManager/Baro.h @@ -12,7 +12,7 @@ class Baro : public EdgeMlSensor { public: static Baro sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; diff --git a/src/SensorManager/BoneConduction.cpp b/src/SensorManager/BoneConduction.cpp index dbbad21c..35ca1aea 100644 --- a/src/SensorManager/BoneConduction.cpp +++ b/src/SensorManager/BoneConduction.cpp @@ -1,6 +1,7 @@ #include "BoneConduction.h" #include "SensorManager.h" +#include "sensor_sink.h" #include "math.h" #include "stdlib.h" @@ -11,6 +12,18 @@ LOG_MODULE_DECLARE(BMA580); BoneConduction BoneConduction::sensor; static struct sensor_msg msg_bc; +static uint32_t bc_queue_full_count; + +static struct { + uint32_t timer_fires; + uint32_t early_returns; + uint32_t reads; + uint32_t read_errors; + uint32_t total_samples; + uint32_t max_samples; + uint32_t exec_max_us; + uint64_t exec_total_us; +} bc_stats; const SampleRateSetting<10> BoneConduction::sample_rates = { { BMA5_ACC_ODR_HZ_12P5, BMA5_ACC_ODR_HZ_25, BMA5_ACC_ODR_HZ_50, BMA5_ACC_ODR_HZ_100, @@ -22,43 +35,56 @@ const SampleRateSetting<10> BoneConduction::sample_rates = { { 12.5, 25.0, 50.0, 100.0, 200.0, 400.0, 800.0, 1600.0, 3200.0, 6400.0 } // true_sample_rates }; -bool BoneConduction::init(struct k_msgq * queue) { +bool BoneConduction::init() { if (!_active) { pm_device_runtime_get(ls_1_8); + pm_device_runtime_get(ls_3_3); + k_msleep(50); _active = true; } - - if (bma580.init() != 0) { // hardware I2C mode, can pass in address & alt Wire + + if (bma580.init() != 0) { LOG_WRN("Could not find a valid bone conduction sensor, check wiring!"); _active = false; pm_device_runtime_put(ls_1_8); + pm_device_runtime_put(ls_3_3); return false; } - sensor_queue = queue; - k_work_init(&sensor.sensor_work, update_sensor); k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); return true; } -void BoneConduction::reset() { - // Reset pulse oximeter state -} - void BoneConduction::update_sensor(struct k_work *work) { - uint64_t _time_stamp = micros(); + if (!sensor._running) return; + uint64_t t0 = micros(); + + bc_stats.timer_fires++; + + BoneConduction::sensor._sample_count += (t0 - BoneConduction::sensor._last_time_stamp) / BoneConduction::sensor.t_sample_us; + BoneConduction::sensor._last_time_stamp = t0; - BoneConduction::sensor._sample_count += (_time_stamp - BoneConduction::sensor._last_time_stamp) / BoneConduction::sensor.t_sample_us; - BoneConduction::sensor._last_time_stamp = _time_stamp; - if (BoneConduction::sensor._sample_count < BoneConduction::sensor._num_samples_buffered * (1.f - CONFIG_SENSOR_CLOCK_ACCURACY / 100.f)) { + bc_stats.early_returns++; return; } int num_samples = sensor.bma580.read(sensor.fifo_acc_data); + if (num_samples < 0) { + bc_stats.read_errors++; + LOG_WRN("BMA580 read failed: %d", num_samples); + return; + } + + bc_stats.reads++; + bc_stats.total_samples += num_samples; + if ((uint32_t)num_samples > bc_stats.max_samples) { + bc_stats.max_samples = num_samples; + } + if (num_samples > 0) { BoneConduction::sensor._sample_count = MAX(0, BoneConduction::sensor._num_samples_buffered - num_samples); } @@ -78,7 +104,7 @@ void BoneConduction::update_sensor(struct k_work *work) { msg_bc.data.size = to_write * _size + sizeof(uint16_t); uint64_t dt_us = (uint64_t)((double)(num_samples - written) * (double)BoneConduction::sensor.t_sample_us); - msg_bc.data.time = _time_stamp - dt_us; + msg_bc.data.time = t0 - dt_us; if (to_write > 1) { uint16_t t_diff = BoneConduction::sensor.t_sample_us; @@ -90,13 +116,19 @@ void BoneConduction::update_sensor(struct k_work *work) { memcpy(&msg_bc.data.data, &sensor.fifo_acc_data[written], _size); } - int ret = k_msgq_put(sensor_queue, &msg_bc, K_NO_WAIT); + int ret = sensor_sink_put(&msg_bc); if (ret) { - LOG_WRN("sensor msg queue full"); + bc_queue_full_count++; } written += to_write; } + + uint32_t elapsed = (uint32_t)(micros() - t0); + bc_stats.exec_total_us += elapsed; + if (elapsed > bc_stats.exec_max_us) { + bc_stats.exec_max_us = elapsed; + } } /** @@ -111,14 +143,15 @@ void BoneConduction::start(int sample_rate_idx) { t_sample_us = 1e6 / sample_rates.true_sample_rates[sample_rate_idx]; - k_timeout_t t = K_USEC(t_sample_us); - int word_size = 3 * sizeof(int16_t) + 1; - _num_samples_buffered = MIN(MAX(1, (int) (CONFIG_SENSOR_LATENCY_MS * 1e3 / t_sample_us)), 512 / word_size - 8); // Buffer size is 512 bytes - + int fifo_capacity = 1024 / word_size; + int latency_samples = (int)(CONFIG_SENSOR_LATENCY_MS * 1e3 / t_sample_us); + _num_samples_buffered = MIN(MAX(1, latency_samples), fifo_capacity / 2); + bma580.init(sample_rates.reg_vals[sample_rate_idx], _num_samples_buffered * word_size); bma580.start(); + k_timeout_t t = K_USEC(t_sample_us * _num_samples_buffered); k_timer_start(&sensor.sensor_timer, K_NO_WAIT, t); _running = true; @@ -132,9 +165,23 @@ void BoneConduction::stop() { _running = false; + uint32_t exec_avg = bc_stats.reads ? (uint32_t)(bc_stats.exec_total_us / bc_stats.reads) : 0; + uint32_t samples_avg = bc_stats.reads ? bc_stats.total_samples / bc_stats.reads : 0; + LOG_INF("bone_acc: timer=%u early_ret=%u reads=%u errors=%u queue_drops=%u", + bc_stats.timer_fires, bc_stats.early_returns, bc_stats.reads, + bc_stats.read_errors, bc_queue_full_count); + LOG_INF("bone_acc: total_samples=%u avg=%u max=%u", + bc_stats.total_samples, samples_avg, bc_stats.max_samples); + LOG_INF("bone_acc: exec_avg=%u us exec_max=%u us", + exec_avg, bc_stats.exec_max_us); + memset(&bc_stats, 0, sizeof(bc_stats)); + bc_queue_full_count = 0; + k_timer_stop(&sensor.sensor_timer); + k_work_cancel(&sensor.sensor_work); bma580.stop(); pm_device_runtime_put(ls_1_8); + pm_device_runtime_put(ls_3_3); } \ No newline at end of file diff --git a/src/SensorManager/BoneConduction.h b/src/SensorManager/BoneConduction.h index f285d2be..7ca54989 100644 --- a/src/SensorManager/BoneConduction.h +++ b/src/SensorManager/BoneConduction.h @@ -4,7 +4,6 @@ #include #include -//#include "MAX30102/MAX30102.h" #include "BMA580/BMA580_Sensor.h" #include "EdgeMLSensor.h" @@ -17,12 +16,10 @@ class BoneConduction : public EdgeMlSensor { public: static BoneConduction sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; - void reset(); - const static SampleRateSetting<10> sample_rates; private: diff --git a/src/SensorManager/CMakeLists.txt b/src/SensorManager/CMakeLists.txt index 36f09f91..a79bc822 100644 --- a/src/SensorManager/CMakeLists.txt +++ b/src/SensorManager/CMakeLists.txt @@ -7,7 +7,7 @@ add_subdirectory(BMA580) target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/SensorManager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/EdgeMLSensor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sensor_sink.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Baro.cpp ${CMAKE_CURRENT_SOURCE_DIR}/IMU.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PPG.cpp @@ -15,4 +15,5 @@ target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/BoneConduction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microphone.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microphone.c + ${CMAKE_CURRENT_SOURCE_DIR}/sensor_shell.c ) diff --git a/src/SensorManager/EdgeMLSensor.cpp b/src/SensorManager/EdgeMLSensor.cpp deleted file mode 100644 index 8e69638e..00000000 --- a/src/SensorManager/EdgeMLSensor.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "EdgeMLSensor.h" - -k_msgq * EdgeMlSensor::sensor_queue; \ No newline at end of file diff --git a/src/SensorManager/EdgeMLSensor.h b/src/SensorManager/EdgeMLSensor.h index 875ee7cd..50022e7b 100644 --- a/src/SensorManager/EdgeMLSensor.h +++ b/src/SensorManager/EdgeMLSensor.h @@ -3,21 +3,6 @@ #include -/* -#define _EXTRACT_SAMPLE_RATES(samplerates, i, num_samplerates) \ -#if ((i) < num_samplerates) \ - "samplerates[" ## i ## "].sample_rate" ## "," ## _EXTRACT_SAMPLE_RATES(samplerates, (i+1), num_samplerates) \ -#else \ - "}" \ -#endif - -#define EXTRACT_SAMPLE_RATES(samplerates, num_samplerates) "{" ## _EXTRACT_SAMPLE_RATES(samplerates, 0, num_samplerates)*/ - -/*struct sample_rate_setting { - int reg_val; - float sample_rate; -};*/ - template struct SampleRateSetting { uint8_t reg_vals[N]; @@ -27,12 +12,9 @@ struct SampleRateSetting { class EdgeMlSensor { public: - //virtual static EdgeMlSensor sensor; - virtual bool init(struct k_msgq * queue) = 0; + virtual bool init() = 0; virtual void start(int sample_rate_idx) = 0; virtual void stop() = 0; - //virtual void end() = 0; - //virtual void update_sensor(struct k_work * work) = 0; bool is_running() { return _running; @@ -46,22 +28,13 @@ class EdgeMlSensor { _ble_stream = enable; } - /** - * @brief Submit a k_work on timer expiry. - */ - /*void sensor_timer_handler(struct k_timer *dummy) - { - k_work_submit(&sensor_work); - };*/ - protected: k_work sensor_work; k_timer sensor_timer; - static k_msgq * sensor_queue; bool _sd_logging = false; bool _ble_stream = true; bool _running = false; }; -#endif \ No newline at end of file +#endif diff --git a/src/SensorManager/IMU.cpp b/src/SensorManager/IMU.cpp index 1f0a59e8..9ea04eb8 100644 --- a/src/SensorManager/IMU.cpp +++ b/src/SensorManager/IMU.cpp @@ -1,110 +1,171 @@ #include "IMU.h" #include "SensorManager.h" +#include "sensor_sink.h" #include -#include #include #include LOG_MODULE_DECLARE(BMX160); static struct sensor_msg msg_imu; - -DFRobot_BMX160 IMU::imu(&I2C3); - +static uint32_t imu_queue_full_count; + +static struct { + uint32_t timer_fires; + uint32_t reads; + uint32_t total_samples; + uint32_t max_samples; + uint32_t exec_max_us; + uint64_t exec_total_us; +} imu_stats; + +BMX160 IMU::imu; IMU IMU::sensor; +BMX160Sample IMU::_batch[64]; +/* Register values match BMI160's ACCEL_ODR_* encoding used for both the + * accel and gyro (same layout). Legacy IMU.cpp used BMX160_GYRO_ODR_* + * macros, which had identical numeric values. */ const SampleRateSetting<6> IMU::sample_rates = { - { BMX160_GYRO_ODR_25HZ, BMX160_GYRO_ODR_50HZ, BMX160_GYRO_ODR_100HZ, - BMX160_GYRO_ODR_200HZ, BMX160_GYRO_ODR_400HZ, BMX160_GYRO_ODR_800HZ }, + { BMI160_GYRO_ODR_25HZ, BMI160_GYRO_ODR_50HZ, BMI160_GYRO_ODR_100HZ, + BMI160_GYRO_ODR_200HZ, BMI160_GYRO_ODR_400HZ, BMI160_GYRO_ODR_800HZ }, - { 25, 50, 100, 200, 400, 800 }, + { 25, 50, 100, 200, 400, 800 }, - { 25.0, 50.0, 100.0, 200.0, 400.0, 800.0 } + { 25.0, 50.0, 100.0, 200.0, 400.0, 800.0 } }; -void IMU::update_sensor(struct k_work *work) { - int ret; +/* Fixed ceiling on frames drained per tick. One FIFO full of A+G headered + * frames (13 bytes each) is ~78 frames; we reserve some stack-safe margin. */ +#define IMU_MAX_SAMPLES_PER_READ 64 - sBmx160SensorData_t magno_data; - sBmx160SensorData_t gyro_data; - sBmx160SensorData_t accel_data; +void IMU::update_sensor(struct k_work *work) +{ + if (!sensor._running) return; + uint64_t t0 = micros(); + imu_stats.timer_fires++; - imu.getAllData(&magno_data, &gyro_data, &accel_data); + int n = imu.read(_batch, IMU_MAX_SAMPLES_PER_READ); + + if (n <= 0) { + uint32_t elapsed = (uint32_t)(micros() - t0); + imu_stats.exec_total_us += elapsed; + if (elapsed > imu_stats.exec_max_us) imu_stats.exec_max_us = elapsed; + return; + } - size_t size = 3 * sizeof(float); - - msg_imu.sd = sensor._sd_logging; - msg_imu.stream = sensor._ble_stream; + imu_stats.reads++; + imu_stats.total_samples += n; + if ((uint32_t)n > imu_stats.max_samples) imu_stats.max_samples = n; - msg_imu.data.id = ID_IMU; - msg_imu.data.size = 3 * size; - msg_imu.data.time = micros(); + /* Preserve the legacy per-sample message format: 36 bytes of + * (accel[3], gyro[3], mag[3]) floats, one message per IMU sample. + * Timestamps are spaced backwards from t0 by sensor._t_sample_us so + * downstream consumers see monotonic sample cadence even when we drain + * multiple frames in one tick. */ + const size_t axis_sz = 3 * sizeof(float); + for (int i = 0; i < n; i++) { + msg_imu.sd = sensor._sd_logging; + msg_imu.stream = sensor._ble_stream; - memcpy(msg_imu.data.data, &accel_data,size); - memcpy(msg_imu.data.data + size, &gyro_data, size); - memcpy(msg_imu.data.data + 2 * size, &magno_data, size); + msg_imu.data.id = ID_IMU; + msg_imu.data.size = 3 * axis_sz; + + uint64_t dt_us = (uint64_t)((n - 1 - i)) * sensor.t_sample_us; + msg_imu.data.time = t0 - dt_us; + + memcpy(msg_imu.data.data, _batch[i].accel, axis_sz); + memcpy(msg_imu.data.data + axis_sz, _batch[i].gyro, axis_sz); + memcpy(msg_imu.data.data + 2 * axis_sz, _batch[i].mag, axis_sz); + + int ret = sensor_sink_put(&msg_imu); + if (ret) imu_queue_full_count++; + } - ret = k_msgq_put(sensor_queue, &msg_imu, K_NO_WAIT); - if (ret) { - LOG_WRN("sensor msg queue full"); - } + uint32_t elapsed = (uint32_t)(micros() - t0); + imu_stats.exec_total_us += elapsed; + if (elapsed > imu_stats.exec_max_us) imu_stats.exec_max_us = elapsed; } -/** -* @brief Submit a k_work on timer expiry. -*/ void IMU::sensor_timer_handler(struct k_timer *dummy) { - k_work_submit_to_queue(&sensor_work_q, &sensor.sensor_work); -}; + k_work_submit_to_queue(&sensor_work_q, &sensor.sensor_work); +} -bool IMU::init(struct k_msgq * queue) { - if (!_active) { - pm_device_runtime_get(ls_1_8); - _active = true; - } - - if (!imu.begin()) { // hardware I2C mode, can pass in address & alt Wire - LOG_ERR("Could not find a valid BMX160 sensor, check wiring!"); - pm_device_runtime_put(ls_1_8); - _active = false; - return false; +bool IMU::init() +{ + if (!_active) { + pm_device_runtime_get(ls_1_8); + _active = true; } - imu.setAccelRange(eAccelRange_2G); + /* A placeholder ODR/watermark — real config happens in start(). We just + * need the chip alive here so begin() succeeds and we can report a valid + * init. */ + if (imu.init(BMI160_ACCEL_ODR_100HZ, BMI160_GYRO_ODR_100HZ, + 4 * sizeof(int16_t) * 3) != 0) { + LOG_ERR("Could not find a valid BMX160 sensor, check wiring!"); + pm_device_runtime_put(ls_1_8); + _active = false; + return false; + } - sensor_queue = queue; - - k_work_init(&sensor.sensor_work, update_sensor); - k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); + k_work_init(&sensor.sensor_work, update_sensor); + k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); - return true; + return true; } -void IMU::start(int sample_rate_idx) { - if (!_active) return; +void IMU::start(int sample_rate_idx) +{ + if (!_active) return; + + t_sample_us = (uint32_t)(1e6 / sample_rates.true_sample_rates[sample_rate_idx]); - k_timeout_t t = K_USEC(1e6 / sample_rates.true_sample_rates[sample_rate_idx]); + /* Size the FIFO watermark so the timer fires ~every + * CONFIG_SENSOR_LATENCY_MS worth of samples. A headered A+G frame + * is 13 bytes (1 header + 6 accel + 6 gyro). The BMI160 FIFO is + * 1024 bytes, so keep the buffered count within 1024/13 frames with + * a small safety margin. */ + const int frame_bytes = 1 + 12; + const int max_frames_in_fifo = 1024 / frame_bytes - 4; + _num_samples_buffered = MIN(MAX(1, (int)(CONFIG_SENSOR_LATENCY_MS * 1e3 / t_sample_us)), + MIN(max_frames_in_fifo, IMU_MAX_SAMPLES_PER_READ)); - imu.setAccelODR(sample_rates.reg_vals[sample_rate_idx]); + uint8_t odr_reg = sample_rates.reg_vals[sample_rate_idx]; + /* Re-init both ODRs (same reg value) and FIFO watermark in bytes. */ + imu.init(odr_reg, odr_reg, _num_samples_buffered * frame_bytes); + imu.start(); - _running = true; + /* Fire at FIFO-drain rate. */ + k_timeout_t t = K_USEC(t_sample_us * _num_samples_buffered); + k_timer_start(&sensor.sensor_timer, K_NO_WAIT, t); - k_timer_start(&sensor.sensor_timer, K_NO_WAIT, t); + _running = true; } -void IMU::stop() { +void IMU::stop() +{ if (!_active) return; _active = false; + _running = false; - _running = false; + uint32_t avg = imu_stats.reads ? (uint32_t)(imu_stats.exec_total_us / imu_stats.reads) : 0; + uint32_t samples_avg = imu_stats.reads ? imu_stats.total_samples / imu_stats.reads : 0; + LOG_INF("imu: timer=%u reads=%u queue_drops=%u", + imu_stats.timer_fires, imu_stats.reads, imu_queue_full_count); + LOG_INF("imu: total_samples=%u avg=%u max=%u exec_avg=%u us exec_max=%u us", + imu_stats.total_samples, samples_avg, imu_stats.max_samples, + avg, imu_stats.exec_max_us); + memset(&imu_stats, 0, sizeof(imu_stats)); + imu_queue_full_count = 0; - k_timer_stop(&sensor.sensor_timer); + k_timer_stop(&sensor.sensor_timer); + k_work_cancel(&sensor.sensor_work); - // turn off imu (?) - imu.softReset(); + imu.stop(); pm_device_runtime_put(ls_1_8); -} \ No newline at end of file +} diff --git a/src/SensorManager/IMU.h b/src/SensorManager/IMU.h index 001a50e0..c8d4e5ce 100644 --- a/src/SensorManager/IMU.h +++ b/src/SensorManager/IMU.h @@ -4,27 +4,28 @@ #include "EdgeMLSensor.h" #include "openearable_common.h" -#include "BMX160/DFRobot_BMX160.h" +#include "BMX160/BMX160_Sensor.h" class IMU : public EdgeMlSensor { public: static IMU sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; const static SampleRateSetting<6> sample_rates; private: - static DFRobot_BMX160 imu; - - //const static int num_sample_rates = 6; - //const static sample_rate_setting sample_rates[num_sample_rates]; + static BMX160 imu; static void sensor_timer_handler(struct k_timer *dummy); - static void update_sensor(struct k_work *work); + bool _active = false; + uint32_t t_sample_us = 0; + int _num_samples_buffered = 1; + + static BMX160Sample _batch[64]; }; -#endif \ No newline at end of file +#endif diff --git a/src/SensorManager/Kconfig b/src/SensorManager/Kconfig index 191b98a3..eb8a8c54 100644 --- a/src/SensorManager/Kconfig +++ b/src/SensorManager/Kconfig @@ -3,87 +3,95 @@ menu "SensorManager" #----------------------------------------------------------------------------# menu "Thread priorities" -config SENSOR_PUB_THREAD_PRIO - int "Priority for power measurement thread" - default 5 - help - This thread will publish sensor events to zbus. - config SENSOR_WORK_QUEUE_PRIO - int "Priority for power measurement thread" + int "Priority for sensor polling work queue" default 5 help - This thread will publish sensor events to zbus. + This work queue thread periodically polls hardware sensors via I2C and enqueues data. config SENSOR_GATT_NOTIFY_THREAD_PRIO - int "Priority for volume message subscribe thread" + int "Priority for sensor GATT notification thread" default 6 help - This is a preemptible thread. - This thread will subscribe to sensor events from zbus. + This preemptible thread subscribes to sensor events and pushes + them as BLE GATT notifications to connected clients. config SENSOR_SD_THREAD_PRIO - int "Priority for volume message subscribe thread" + int "Priority for SD card sensor logging thread" default 5 help - This is a preemptible thread. - This thread will subscribe to sensor events from zbus. + This preemptible thread drains the ring buffer and writes + sensor data in bulk to the SD card. Same priority as the sensor + work queue so the SPI busy-wait yields to sensor reads via + k_msleep(0). endmenu # Thread priorities #----------------------------------------------------------------------------# menu "Stack sizes" -config SENSOR_PUB_STACK_SIZE - int "Stack size for power measurement thread" - default 2048 - config SENSOR_WORK_QUEUE_STACK_SIZE - int "Stack size for power measurement thread" + int "Stack size for sensor polling work queue thread" default 1024 config SENSOR_GATT_NOTIFY_STACK_SIZE - int "Stack size" + int "Stack size for sensor GATT notification thread" default 2048 config SENSOR_SD_STACK_SIZE - int "Stack size" + int "Stack size for SD card sensor logging thread" default 8192 endmenu # Stack sizes #----------------------------------------------------------------------------# -menu "Zbus" - -config SENSOR_SD_SUB_QUEUE_SIZE - int "Queue size for button subscriber" - default 256 +menu "Queues" config SENSOR_GATT_SUB_QUEUE_SIZE - int "Queue size for content control subscriber" - default 256 + int "Queue size for GATT notification sensor subscriber" + default 64 -endmenu # Zbus +endmenu # Queues #-----------------------------------------------------------------------------# menu "Buffer management" config SENSOR_CLOCK_ACCURACY - int "Clock accuracy" + int "Sensor clock accuracy (percentage)" default 5 help - This is the clock accuracy in percent. The default value is 5 percent. - This value is used to calculate the time difference between the - sensor and the system clock. The value is used to calculate the - time difference between the sensor and the system clock. + Typical worst-case clock accuracy percentage. This value is used to + account for drift between the sensor's hardware clock and the MCU's + system clock when calculating timestamps. config SENSOR_LATENCY_MS - int "Latency" + int "Sensor reporting latency limit (ms)" default 40 help - This is the latency in milliseconds. The default value is 40 ms. - This value is used to calaculate the buffer size of the sensors - that use an internal buffer. + Maximum acceptable latency for sensor events in milliseconds. + This value determines the required hardware FIFO sizes for sensors + that buffer data before asserting an interrupt. endmenu # Buffer management -endmenu # Modules \ No newline at end of file +#-----------------------------------------------------------------------------# +menu "IMU (BMX160)" + +config IMU_ENABLE_MAGNETOMETER + bool "Enable the BMX160 internal magnetometer (BMM150)" + default n + help + When enabled, the internal BMM150 magnetometer is powered on via + CMD_REG = AUX_NORMAL_MODE, configured for 100 Hz data mode, and + read once per FIFO drain to populate the mag fields in the IMU + sample. + + When disabled, the magnetometer subsystem is kept in suspend + (~170 uA saved), the aux config sequence is skipped, and the + mag fields in each IMU message are zero-filled. The earpiece + speaker magnet dominates the local field so absolute mag readings + are near-useless; the legacy driver also applied an ~8x scale + inflation, so leaving this disabled is usually the right choice. + +endmenu # IMU + +endmenu # Modules diff --git a/src/SensorManager/MAXM86161/MAXM86161.cpp b/src/SensorManager/MAXM86161/MAXM86161.cpp index 7a199066..f03d4b1a 100644 --- a/src/SensorManager/MAXM86161/MAXM86161.cpp +++ b/src/SensorManager/MAXM86161/MAXM86161.cpp @@ -49,14 +49,7 @@ int MAXM86161::init(enum sample_rate sample_rate) // Set integration time and ADC range with ALC and ADD _write_to_reg(REG_PPG_CONFIG1, 0x0F); - // Set sample rate and averaging - // cmd[0] = 0x12; cmd[1] = 0x50; // 8Hz with no averaging - // cmd[1] = 0x08; 50 Hz with no averaging - //_write_to_reg(REG_PPG_CONFIG2, 0x08); _write_to_reg(REG_PPG_CONFIG2, sample_rate << POS_PPG_SR); - - // Set LED settling, digital filter, burst rate, burst enable - // No Burst mode with default settling _write_to_reg(REG_PPG_CONFIG3, 0x40); // Set Photodiode bias to 0pF to 65pF @@ -256,116 +249,12 @@ int MAXM86161::set_ppg_tint(int time) } /*******************************************************************************/ -int MAXM86161::alc_on(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_PPG_CONFIG1, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _clear_one_bit(REG_PPG_CONFIG1, POS_ALC_DIS); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_PPG_CONFIG1, existing_reg_values); - - return status; -} - -int MAXM86161::alc_off(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_PPG_CONFIG1, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _set_one_bit(REG_PPG_CONFIG1, POS_ALC_DIS); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_PPG_CONFIG1, existing_reg_values); - - return status; -} - - -int MAXM86161::picket_off(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_PICKET_FENCE, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _clear_one_bit(REG_PICKET_FENCE, POS_PICKET_DIS); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_PICKET_FENCE, existing_reg_values); - - return status; -} - -int MAXM86161::picket_on(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_PICKET_FENCE, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _set_one_bit(REG_PICKET_FENCE, POS_PICKET_DIS); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_PICKET_FENCE, existing_reg_values); - - return status; -} - -int MAXM86161::new_value_read_on(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_IRQ_ENABLE1, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _set_one_bit(REG_IRQ_ENABLE1, POS_DATA_RDY_EN); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_IRQ_ENABLE1, existing_reg_values); - - return status; -} - -int MAXM86161::new_value_read_off(void) -{ - int existing_reg_values; - int status; - - // Get value of register - _read_from_reg(REG_IRQ_ENABLE1, existing_reg_values); - - // Set the bit to stop the device - existing_reg_values = _clear_one_bit(REG_IRQ_ENABLE1, POS_DATA_RDY_EN); - - // Send the Shutdown command to the device - status = _write_to_reg(REG_IRQ_ENABLE1, existing_reg_values); - - return status; -} - - /*******************************************************************************/ // Function to read from a registry int MAXM86161::_read_from_reg(int address, int &data) { int ret; - _i2c->aquire(); + _i2c->acquire(); uint8_t buffer; ret = i2c_burst_read(_i2c->master, _addr, address, &buffer, sizeof(buffer)); @@ -377,11 +266,9 @@ int MAXM86161::_read_from_reg(int address, int &data) { return ret; //Fail } -// Function to write to a registry -// TODO Check about mfio -> might not need it. int MAXM86161::_write_to_reg(int address, int value) { - _i2c->aquire(); + _i2c->acquire(); uint8_t buffer = value; int ret = i2c_burst_write(_i2c->master, _addr, address, &buffer, sizeof(buffer)); @@ -397,7 +284,7 @@ int MAXM86161::_read_block(int address, int length, uint8_t *data) { int ret; - _i2c->aquire(); + _i2c->acquire(); ret = i2c_burst_read(_i2c->master, _addr, address, data, length); if (ret) LOG_WRN("I2C read failed: %d\n", ret); @@ -435,8 +322,9 @@ int MAXM86161::_clear_interrupt(void) int MAXM86161::read_interrupt_state(int &value) { - int status; - status = _read_from_reg(REG_IRQ_STATUS2, value); + int status, unused; + // Status2 must be read first to latch Status1 (per datasheet) + status = _read_from_reg(REG_IRQ_STATUS2, unused); status = _read_from_reg(REG_IRQ_STATUS1, value); return status; } diff --git a/src/SensorManager/MAXM86161/MAXM86161.h b/src/SensorManager/MAXM86161/MAXM86161.h index 3037dd78..cac9a2bd 100644 --- a/src/SensorManager/MAXM86161/MAXM86161.h +++ b/src/SensorManager/MAXM86161/MAXM86161.h @@ -4,7 +4,6 @@ #ifndef __MAXM86161_H_ #define __MAXM86161_H_ -//#include #include #include @@ -68,26 +67,6 @@ class MAXM86161 { /** @brief Set the integration time for the photodiode */ int set_ppg_tint(int time); - // Setting adjustments - /** @brief Set the ALC on */ - int alc_on(void); - /** @brief Set the ALC off */ - int alc_off(void); - /** @brief Set the picket fence detection on */ - int picket_on(void); - /** @brief Set the picket fence detection off */ - int picket_off(void); - /** @brief Set the interrupt to trigger with new values in FIFO */ - int new_value_read_on(void); - /** @brief Stop the interrupt from triggering with new values in FIFO */ - int new_value_read_off(void); - - // void read_fifo(int* red, int* green, int* ir); - // char read_package_temp(); - - // Functions not yet working - // char read_status(); - int read_interrupt_state(int &value); int set_watermark(int level); @@ -198,7 +177,7 @@ class MAXM86161 { #define REG_S1_HI_RES_DAC1 0x2C #define REG_S2_HI_RES_DAC1 0x2D #define REG_S3_HI_RES_DAC1 0x2E -#define REG_S4_HI_RES_DAC1 0x2D +#define REG_S4_HI_RES_DAC1 0x2F // per MAXM86161 datasheet Table 2 #define REG_S5_HI_RES_DAC1 0x30 #define REG_S6_HI_RES_DAC1 0x31 diff --git a/src/SensorManager/MLX90632/MLX90632.cpp b/src/SensorManager/MLX90632/MLX90632.cpp index ab98e9de..53351f43 100644 --- a/src/SensorManager/MLX90632/MLX90632.cpp +++ b/src/SensorManager/MLX90632/MLX90632.cpp @@ -25,32 +25,10 @@ along with this program. If not, see . */ -/* - TODO: - check EEPROM write - check timing - how fast to take reading? Setting the SOC twice may be doubling time - set emissivity -*/ - -//Declare global variables for the calibration values -double P_R; -double P_G; -double P_T; -double P_O; -double Ea; -double Eb; -double Fa; -double Fb; -double Ga; -double Gb; -double Ka; -double Ha; -double Hb; - -double TOdut = 25.0; //Assume 25C for first iteration -double TO0 = 25.0; //object temp from previous calculation -double TA0 = 25.0; //ambient temp from previous calculation -double sensorTemp; //Internal temp of the MLX sensor +/* Calibration constants and iteration state live as float class members in + * MLX90632.h — see the datasheet's object-temperature formula. Float keeps + * the math on the Cortex-M33 single-precision FPU instead of emulated + * double. */ #include "MLX90632.h" @@ -100,7 +78,7 @@ bool MLX90632::begin(uint8_t deviceAddress, TWIM &i2c, status &returnError) uint16_t thisVersion; returnError = readRegister16(EE_VERSION, thisVersion); - LOG_WRN("Sensor EEPROM version (usually 0x205): 0x%X",thisVersion); + LOG_DBG("Sensor EEPROM version (usually 0x205): 0x%X",thisVersion); //Wait for eeprom_busy to clear uint16_t counter = 0; @@ -118,36 +96,37 @@ bool MLX90632::begin(uint8_t deviceAddress, TWIM &i2c, status &returnError) setMode(MODE_SLEEP); //Before reading EEPROM sensor needs to stop taking readings - //Load all the static calibration factors + //Load all the static calibration factors. ldexpf(x, n) is x * 2^n — exact + //for these power-of-two scalings and avoids the pow() library call. int16_t tempValue16; int32_t tempValue32; readRegister32(EE_P_R, (uint32_t&)tempValue32); - P_R = (double)tempValue32 * pow(2, -8); + P_R = ldexpf((float)tempValue32, -8); readRegister32(EE_P_G, (uint32_t&)tempValue32); - P_G = (double)tempValue32 * pow(2, -20); + P_G = ldexpf((float)tempValue32, -20); readRegister32(EE_P_T, (uint32_t&)tempValue32); - P_T = (double)tempValue32 * pow(2, -44); + P_T = ldexpf((float)tempValue32, -44); readRegister32(EE_P_O, (uint32_t&)tempValue32); - P_O = (double)tempValue32 * pow(2, -8); + P_O = ldexpf((float)tempValue32, -8); readRegister32(EE_Ea, (uint32_t&)tempValue32); - Ea = (double)tempValue32 * pow(2, -16); + Ea = ldexpf((float)tempValue32, -16); readRegister32(EE_Eb, (uint32_t&)tempValue32); - Eb = (double)tempValue32 * pow(2, -8); + Eb = ldexpf((float)tempValue32, -8); readRegister32(EE_Fa, (uint32_t&)tempValue32); - Fa = (double)tempValue32 * pow(2, -46); + Fa = ldexpf((float)tempValue32, -46); readRegister32(EE_Fb, (uint32_t&)tempValue32); - Fb = (double)tempValue32 * pow(2, -36); + Fb = ldexpf((float)tempValue32, -36); readRegister32(EE_Ga, (uint32_t&)tempValue32); - Ga = (double)tempValue32 * pow(2, -36); - + Ga = ldexpf((float)tempValue32, -36); + readRegister16(EE_Gb, (uint16_t&)tempValue16); - Gb = (double)tempValue16 * pow(2, -10); + Gb = ldexpf((float)tempValue16, -10); readRegister16(EE_Ka, (uint16_t&)tempValue16); - Ka = (double)tempValue16 * pow(2, -10); + Ka = ldexpf((float)tempValue16, -10); readRegister16(EE_Ha, (uint16_t&)tempValue16); - Ha = (double)tempValue16 * pow(2, -14); //Ha! + Ha = ldexpf((float)tempValue16, -14); //Ha! readRegister16(EE_Hb, (uint16_t&)tempValue16); - Hb = (double)tempValue16 * pow(2, -14); + Hb = ldexpf((float)tempValue16, -14); LOG_DBG("MLX90632 online"); @@ -168,63 +147,43 @@ float MLX90632::getObjectTemp(status& returnError) { returnError = SENSOR_SUCCESS; - //If the sensor is not in continuous mode then the tell sensor to take reading - if(getMode() != MODE_CONTINUOUS) setSOC(); + if (getMode() != MODE_CONTINUOUS) setSOC(); - // do not check blocking! - if (dataAvailable() == false) - { - LOG_WRN("Data available timeout"); - returnError = SENSOR_TIMEOUT_ERROR; - return (0.0); //Error - } + // Single status read for data availability and cycle position + uint16_t statusReg = getStatus(); - //Check when new_data = 1 - /*uint16_t counter = 0; - while (dataAvailable() == false) + if (!(statusReg & (1 << BIT_NEW_DATA))) { - k_msleep(1); - counter++; - if (counter == MAX_WAIT) - { LOG_WRN("Data available timeout"); returnError = SENSOR_TIMEOUT_ERROR; - return (0.0); //Error - } - }*/ + return (0.0); + } - //Write new_data = 0 - clearNewData(); + // Clear new_data flag + writeRegister16(REG_STATUS, statusReg & ~(1 << BIT_NEW_DATA)); gatherSensorTemp(returnError); if (returnError != SENSOR_SUCCESS) { LOG_WRN("Sensor temperature not found"); - if(returnError == SENSOR_TIMEOUT_ERROR) LOG_WRN("Timeout"); - return (0.0); //Error + return (0.0); } int16_t lowerRAM = 0; int16_t upperRAM = 0; - //Get RAM_6 and RAM_9 int16_t sixRAM; readRegister16(RAM_6, (uint16_t&)sixRAM); int16_t nineRAM; readRegister16(RAM_9, (uint16_t&)nineRAM); - //Read cycle_pos to get measurement pointer - int cyclePosition = getCyclePosition(); + int cyclePosition = (statusReg >> BIT_CYCLE_POS) & 0x1F; - //If cycle_pos = 1 - //Calculate TA and TO based on RAM_4, RAM_5, RAM_6, RAM_9 if (cyclePosition == 1) { readRegister16(RAM_4, (uint16_t&)lowerRAM); readRegister16(RAM_5, (uint16_t&)upperRAM); } - //If cycle_pos = 2 - //Calculate TA and TO based on RAM_7, RAM_8, RAM_6, RAM_9 else if (cyclePosition == 2) { readRegister16(RAM_7, (uint16_t&)lowerRAM); @@ -232,33 +191,27 @@ float MLX90632::getObjectTemp(status& returnError) } else { - LOG_WRN("Found a cycle position that was not 1 or 2"); + LOG_DBG("Found a cycle position that was not 1 or 2"); readRegister16(RAM_4, (uint16_t&)lowerRAM); readRegister16(RAM_5, (uint16_t&)upperRAM); } - //Object temp requires 3 iterations + // Iterative object temperature computation (3 iterations for convergence) for (uint8_t i = 0 ; i < 3 ; i++) { - double VRta = nineRAM + Gb * (sixRAM / 12.0); + float VRta = nineRAM + Gb * (sixRAM / 12.0f); + float AMB = (sixRAM / 12.0f) / VRta * 524288.0f; + float S = (lowerRAM + upperRAM) / 2.0f; + float VRto = nineRAM + Ka * (sixRAM / 12.0f); + float Sto = (S / 12.0f) / VRto * 524288.0f; + float TAdut = (AMB - Eb) / Ea + 25.0f; + float ambientTempK = TAdut + 273.15f; - double AMB = (sixRAM / 12.0) / VRta * pow(2, 19); + float bigFraction = Sto / (Fa * Ha * (1.0f + Ga * (TOdut - TO0) + Fb * (TAdut - TA0))); - double sensorTemp = P_O + (AMB - P_R) / P_G + P_T * pow((AMB - P_R), 2); - - float S = (float)(lowerRAM + upperRAM) / 2.0; - double VRto = nineRAM + Ka * (sixRAM / 12.0); - double Sto = (S / 12.0) / VRto * (double)pow(2, 19); - - double TAdut = (AMB - Eb) / Ea + 25.0; - - double ambientTempK = TAdut + 273.15; - - double bigFraction = Sto / (1 * Fa * Ha * (1 + Ga * (TOdut - TO0) + Fb * (TAdut - TA0))); - - double objectTemp = bigFraction + pow(ambientTempK, 4); - objectTemp = pow(objectTemp, 0.25); //Take 4th root - objectTemp = objectTemp - 273.15 - Hb; + float objectTemp = bigFraction + ambientTempK * ambientTempK * ambientTempK * ambientTempK; + objectTemp = sqrtf(sqrtf(objectTemp)); + objectTemp = objectTemp - 273.15f - Hb; TO0 = objectTemp; } @@ -320,11 +273,12 @@ float MLX90632::gatherSensorTemp(status &returnError) int16_t nineRAM; readRegister16(RAM_9, (uint16_t&)nineRAM); - double VRta = nineRAM + Gb * (sixRAM / 12.0); + float VRta = nineRAM + Gb * (sixRAM / 12.0f); - double AMB = (sixRAM / 12.0) / VRta * pow(2, 19); + float AMB = (sixRAM / 12.0f) / VRta * 524288.0f; // 2^19 - double sensorTemp = P_O + (AMB - P_R) / P_G + P_T * pow((AMB - P_R), 2); + float dAMB = AMB - P_R; + float sensorTemp = P_O + dAMB / P_G + P_T * dAMB * dAMB; return(sensorTemp); } @@ -456,7 +410,7 @@ MLX90632::status MLX90632::readRegister16(uint16_t addr, uint16_t &outputPointer { MLX90632::status returnError = SENSOR_SUCCESS; //By default, return success - _i2c->aquire(); + _i2c->acquire(); // 32-Bit-Adresse in ein Byte-Array umwandeln (Big-Endian) uint8_t addr_buf[2] = { @@ -466,7 +420,7 @@ MLX90632::status MLX90632::readRegister16(uint16_t addr, uint16_t &outputPointer uint8_t buffer[2]; - // Adresse senden und Daten lesen + // Send address and read data int ret = i2c_write_read(_i2c->master, _deviceAddress, addr_buf, sizeof(addr_buf), buffer, sizeof(buffer)); if (ret) { returnError = SENSOR_I2C_ERROR; @@ -485,7 +439,7 @@ MLX90632::status MLX90632::readRegister32(uint16_t addr, uint32_t &outputPointer { MLX90632::status returnError = SENSOR_SUCCESS; //By default, return success - _i2c->aquire(); + _i2c->acquire(); uint8_t addr_buf[2] = { (uint8_t)((addr >> 8) & 0xFF), @@ -494,7 +448,7 @@ MLX90632::status MLX90632::readRegister32(uint16_t addr, uint32_t &outputPointer uint8_t buffer[4]; - // Adresse senden und Daten lesen + // Send address and read data int ret = i2c_write_read(_i2c->master, _deviceAddress, addr_buf, sizeof(addr_buf), buffer, sizeof(buffer)); uint16_t lower = (uint16_t)buffer[0] << 8 | buffer[1]; @@ -517,7 +471,7 @@ MLX90632::status MLX90632::writeRegister16(uint16_t addr, uint16_t val) { MLX90632::status returnError = SENSOR_SUCCESS; //By default, return success - _i2c->aquire(); + _i2c->acquire(); struct i2c_msg msg[2]; @@ -557,22 +511,15 @@ MLX90632::status MLX90632::writeRegister16(uint16_t addr, uint16_t val) //This should work but doesn't. It seems the IC is very sensitive to I2C traffic while //the sensor is recording the new EEPROM. void MLX90632::writeEEPROM(uint16_t addr, uint16_t val) { - - //unlock EEPROM writeRegister16(0x3005, 0x554C); - writeRegister16(addr, 0x00); - // wait for EEPROM - while (eepromBusy()) k_msleep(1); + for (int i = 0; i < MAX_WAIT && eepromBusy(); i++) k_msleep(1); - // unlock EEPROM writeRegister16(0x3005, 0x554C); - writeRegister16(addr, val); - // wait for EEPROM - while (eepromBusy()) k_msleep(1); + for (int i = 0; i < MAX_WAIT && eepromBusy(); i++) k_msleep(1); } void MLX90632::reset() { diff --git a/src/SensorManager/MLX90632/MLX90632.h b/src/SensorManager/MLX90632/MLX90632.h index 411659ea..35048aac 100644 --- a/src/SensorManager/MLX90632/MLX90632.h +++ b/src/SensorManager/MLX90632/MLX90632.h @@ -27,7 +27,6 @@ #pragma once -//#include #include //The default I2C address for the MLX90632 on the SparkX breakout is 0x3B. 0x3A is also possible. @@ -165,4 +164,14 @@ class MLX90632 { TWIM *_i2c = &I2C3; //The generic connection to user's chosen I2C hardware uint8_t _deviceAddress = DT_REG_ADDR(DT_NODELABEL(mlx90632)); //Keeps track of I2C address. setI2CAddress changes this. Either 0x3A or 0x3B (default) + /* Calibration constants loaded from EEPROM. Kept as float so that + * the Cortex-M33 single-precision FPU handles the temperature math + * natively — double math would be emulated in software. */ + float P_R = 0, P_G = 0, P_T = 0, P_O = 0; + float Ea = 0, Eb = 0, Fa = 0, Fb = 0, Ga = 0; + float Gb = 0, Ka = 0, Ha = 0, Hb = 0; + + float TOdut = 25.0f; + float TO0 = 25.0f; + float TA0 = 25.0f; }; \ No newline at end of file diff --git a/src/SensorManager/Microphone.cpp b/src/SensorManager/Microphone.cpp index fe907e2d..fefd759c 100644 --- a/src/SensorManager/Microphone.cpp +++ b/src/SensorManager/Microphone.cpp @@ -11,8 +11,6 @@ #include "ADAU1860.h" -//#include - #ifdef __cplusplus extern "C" { #endif @@ -26,7 +24,6 @@ extern void empty_fifo(); #endif #include -//LOG_MODULE_DECLARE(BMX160); LOG_MODULE_REGISTER(microphone, CONFIG_LOG_DEFAULT_LEVEL); extern struct data_fifo fifo_rx; @@ -41,14 +38,9 @@ const SampleRateSetting<1> Microphone::sample_rates = { { 48000.0 } }; -bool Microphone::init(struct k_msgq * queue) { - +bool Microphone::init() { _active = true; - sensor_queue = queue; - - set_sensor_queue(queue); - init_fifo(); return true; @@ -63,7 +55,7 @@ void Microphone::start(int sample_rate_idx) { record_to_sd(true); - audio_datapath_aquire(&fifo_rx); + audio_datapath_acquire(&fifo_rx); _running = true; } diff --git a/src/SensorManager/Microphone.h b/src/SensorManager/Microphone.h index d5c63c6d..5e80b71e 100644 --- a/src/SensorManager/Microphone.h +++ b/src/SensorManager/Microphone.h @@ -9,7 +9,7 @@ class Microphone : public EdgeMlSensor { public: static Microphone sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; diff --git a/src/SensorManager/PPG.cpp b/src/SensorManager/PPG.cpp index 33132b3e..dbbb3390 100644 --- a/src/SensorManager/PPG.cpp +++ b/src/SensorManager/PPG.cpp @@ -1,6 +1,7 @@ #include "PPG.h" #include "SensorManager.h" +#include "sensor_sink.h" #include "math.h" #include "stdlib.h" @@ -15,6 +16,17 @@ PPG PPG::sensor; MAXM86161 PPG::ppg(&I2C2); static struct sensor_msg msg_ppg; +static uint32_t ppg_queue_full_count; +static uint32_t ppg_calls, ppg_max_us; +static uint64_t ppg_total_us; + +/* External LDO enable for the PPG AFE. Separate from ls_1_8/ls_3_3 — must + * be driven LOW in stop() so the LDO actually turns off. */ +static const struct gpio_dt_spec ppg_ldo_en = { + .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), + .pin = 6, + .dt_flags = GPIO_ACTIVE_HIGH, +}; const SampleRateSetting<16> PPG::sample_rates = { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x0A, 0x0B, @@ -27,38 +39,33 @@ const SampleRateSetting<16> PPG::sample_rates = { 32.000, 64.000, 128.000, 256.000, 512.000, 1024.000, 2048.000, 4096.000}, }; -bool PPG::init(struct k_msgq * queue) { +bool PPG::init() { if (!_active) { pm_device_runtime_get(ls_1_8); pm_device_runtime_get(ls_3_3); - const struct gpio_dt_spec LDO_EN = { - .port = DEVICE_DT_GET(DT_NODELABEL(gpio0)), - .pin = 6, - .dt_flags = GPIO_ACTIVE_HIGH - }; - - int ret = gpio_pin_configure_dt(&LDO_EN, GPIO_OUTPUT_ACTIVE); + int ret = gpio_pin_configure_dt(&ppg_ldo_en, GPIO_OUTPUT_ACTIVE); if (ret != 0) { - LOG_WRN("Failed to set GPOUT as input.\n"); + LOG_WRN("Failed to enable PPG LDO: %d", ret); + pm_device_runtime_put(ls_1_8); + pm_device_runtime_put(ls_3_3); return false; } k_msleep(5); - _active = true; - } - + _active = true; + } + if (ppg.init() != 0) { // hardware I2C mode, can pass in address & alt Wire - LOG_WRN("Could not find a valid PPG sensor, check wiring!"); + LOG_WRN("Could not find a valid PPG sensor, check wiring!"); _active = false; + gpio_pin_set_dt(&ppg_ldo_en, 0); pm_device_runtime_put(ls_1_8); pm_device_runtime_put(ls_3_3); - return false; + return false; } - sensor_queue = queue; - k_work_init(&sensor.sensor_work, update_sensor); k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); @@ -66,15 +73,19 @@ bool PPG::init(struct k_msgq * queue) { } void PPG::update_sensor(struct k_work *work) { + if (!sensor._running) return; + uint64_t t0 = micros(); int int_status; int status; - uint64_t _time_stamp = micros(); - - PPG::sensor._sample_count += (_time_stamp - PPG::sensor._last_time_stamp) / PPG::sensor.t_sample_us; - PPG::sensor._last_time_stamp = _time_stamp; + PPG::sensor._sample_count += (t0 - PPG::sensor._last_time_stamp) / PPG::sensor.t_sample_us; + PPG::sensor._last_time_stamp = t0; if (PPG::sensor._sample_count < PPG::sensor._num_samples_buffered * (1.f - CONFIG_SENSOR_CLOCK_ACCURACY / 100.f)) { + uint32_t elapsed = (uint32_t)(micros() - t0); + ppg_calls++; + ppg_total_us += elapsed; + if (elapsed > ppg_max_us) ppg_max_us = elapsed; return; } @@ -104,7 +115,7 @@ void PPG::update_sensor(struct k_work *work) { msg_ppg.data.size = to_write * _size + sizeof(uint16_t); const uint64_t dt_us = (uint64_t)((double)(num_samples - written) * (double)PPG::sensor.t_sample_us); - msg_ppg.data.time = _time_stamp - dt_us; + msg_ppg.data.time = t0 - dt_us; if (to_write > 1) { uint16_t t_diff = PPG::sensor.t_sample_us; @@ -116,14 +127,19 @@ void PPG::update_sensor(struct k_work *work) { memcpy(&msg_ppg.data.data, &sensor.data_buffer[written], _size); } - int ret = k_msgq_put(sensor_queue, &msg_ppg, K_NO_WAIT); + int ret = sensor_sink_put(&msg_ppg); if (ret) { - LOG_WRN("sensor msg queue full"); + ppg_queue_full_count++; } written += to_write; } } + + uint32_t elapsed = (uint32_t)(micros() - t0); + ppg_calls++; + ppg_total_us += elapsed; + if (elapsed > ppg_max_us) ppg_max_us = elapsed; } /** @@ -138,14 +154,13 @@ void PPG::start(int sample_rate_idx) { t_sample_us = 1e6 / sample_rates.true_sample_rates[sample_rate_idx]; - k_timeout_t t = K_USEC(t_sample_us); - _num_samples_buffered = MIN(MAX(1, (int) (CONFIG_SENSOR_LATENCY_MS * 1e3 / t_sample_us)), FIFO_SIZE / LED_NUM - 2); - + ppg.set_interrogation_rate(sample_rates.reg_vals[sample_rate_idx]); ppg.set_watermark(FIFO_SIZE - _num_samples_buffered * LED_NUM); ppg.start(); + k_timeout_t t = K_USEC(t_sample_us * _num_samples_buffered); k_timer_start(&sensor.sensor_timer, K_NO_WAIT, t); _running = true; @@ -159,10 +174,21 @@ void PPG::stop() { _running = false; + uint32_t avg = ppg_calls ? (uint32_t)(ppg_total_us / ppg_calls) : 0; + LOG_INF("ppg: calls=%u avg=%u us max=%u us total=%u ms queue_drops=%u", + ppg_calls, avg, ppg_max_us, (uint32_t)(ppg_total_us / 1000), ppg_queue_full_count); + ppg_calls = 0; ppg_total_us = 0; ppg_max_us = 0; ppg_queue_full_count = 0; + k_timer_stop(&sensor.sensor_timer); + k_work_cancel(&sensor.sensor_work); ppg.stop(); + /* Drop the external LDO enable before cutting the load switches — + * the LDO stays powered by ls_3_3, so dropping ls_3_3 alone leaves the + * LDO in an undefined state. */ + gpio_pin_set_dt(&ppg_ldo_en, 0); + pm_device_runtime_put(ls_1_8); pm_device_runtime_put(ls_3_3); } \ No newline at end of file diff --git a/src/SensorManager/PPG.h b/src/SensorManager/PPG.h index 2fe4264f..69407405 100644 --- a/src/SensorManager/PPG.h +++ b/src/SensorManager/PPG.h @@ -6,7 +6,6 @@ #include #include -//#include "MAX30102/MAX30102.h" #include "MAXM86161/MAXM86161.h" #include "EdgeMLSensor.h" @@ -19,11 +18,9 @@ enum led_order { class PPG : public EdgeMlSensor { public: - //PulseOximeter(int _samplerate); - static PPG sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; diff --git a/src/SensorManager/SensorManager.cpp b/src/SensorManager/SensorManager.cpp index 1c8a994b..8fc7ca54 100644 --- a/src/SensorManager/SensorManager.cpp +++ b/src/SensorManager/SensorManager.cpp @@ -5,8 +5,6 @@ #include "macros_common.h" #include "openearable_common.h" -#include - #include "IMU.h" #include "Baro.h" #include "PPG.h" @@ -25,76 +23,41 @@ #include #include -#include LOG_MODULE_DECLARE(sensor_manager); std::set ble_sensors = {}; std::set sd_sensors = {}; -//extern struct k_msgq sensor_queue; - EdgeMlSensor * get_sensor(enum sensor_id id); static sensor_manager_state _state; -K_MSGQ_DEFINE(sensor_queue, sizeof(struct sensor_msg), 256, 4); K_MSGQ_DEFINE(config_queue, sizeof(struct sensor_config), 16, 4); K_THREAD_STACK_DEFINE(sensor_work_q_stack, CONFIG_SENSOR_WORK_QUEUE_STACK_SIZE); -ZBUS_CHAN_DEFINE(sensor_chan, struct sensor_msg, NULL, NULL, ZBUS_OBSERVERS_EMPTY, - ZBUS_MSG_INIT(0)); - static struct k_poll_signal sensor_manager_sig; static struct k_poll_event sensor_manager_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &sensor_manager_sig); -struct sensor_msg msg; - -struct k_thread sensor_publish; - -static k_tid_t sensor_pub_id; - static struct k_work config_work; struct k_work_q sensor_work_q; -K_THREAD_STACK_DEFINE(sensor_publish_thread_stack, CONFIG_SENSOR_PUB_STACK_SIZE); - int active_sensors = 0; static void config_work_handler(struct k_work *work); -void sensor_chan_update(void *p1, void *p2, void *p3) { - int ret; - - while (1) { - ret = k_poll(&sensor_manager_evt, 1, K_FOREVER); - - k_msgq_get(&sensor_queue, &msg, K_FOREVER); - - ret = zbus_chan_pub(&sensor_chan, &msg, K_FOREVER); //K_NO_WAIT - if (ret) { - LOG_ERR("Failed to publish sensor msg, ret: %d", ret); - } - } -} - void init_sensor_manager() { _state = INIT; active_sensors = 0; k_work_queue_init(&sensor_work_q); - k_work_queue_start(&sensor_work_q, sensor_work_q_stack, K_THREAD_STACK_SIZEOF(sensor_work_q_stack), K_PRIO_PREEMPT(CONFIG_SENSOR_WORK_QUEUE_PRIO), NULL); - sensor_pub_id = k_thread_create(&sensor_publish, sensor_publish_thread_stack, CONFIG_SENSOR_PUB_STACK_SIZE, - sensor_chan_update, NULL, NULL, NULL, - K_PRIO_PREEMPT(CONFIG_SENSOR_PUB_THREAD_PRIO), 0, K_FOREVER); // Thread ist initial suspendiert - k_work_init(&config_work, config_work_handler); k_poll_signal_init(&sensor_manager_sig); @@ -107,17 +70,11 @@ void start_sensor_manager() { LOG_DBG("Starting sensor manager"); - //empty message queue - k_msgq_purge(&sensor_queue); k_work_queue_unplug(&sensor_work_q); ble_sensors.clear(); sd_sensors.clear(); - if (_state == INIT) { - k_thread_start(sensor_pub_id); - } - k_poll_signal_raise(&sensor_manager_sig, 0); _state = RUNNING; @@ -139,15 +96,13 @@ void stop_sensor_manager() { k_work_queue_drain(&sensor_work_q, true); - //k_thread_suspend(sensor_pub_id); k_poll_signal_reset(&sensor_manager_sig); _state = SUSPENDED; - // End SDLogger and close current log file sdlogger.end(); - - //k_msgq_purge(&config_queue); + sd_sensors.clear(); + state_indicator.set_sd_state(SD_IDLE); } EdgeMlSensor * get_sensor(enum sensor_id id) { @@ -169,17 +124,8 @@ EdgeMlSensor * get_sensor(enum sensor_id id) { } } -// Worker-Funktion für die Sensor-Konfiguration -static void config_work_handler(struct k_work *work) { - int ret; - struct sensor_config config; - - ret = k_msgq_get(&config_queue, &config, K_NO_WAIT); - if (ret != 0) { - LOG_INF("No config available"); - } - - float sampleRate = getSampleRateForSensorId(config.sensorId, config.sampleRateIndex); +static void process_sensor_config(struct sensor_config &config) { + float sampleRate = getSampleRateForSensorId(config.sensorId, config.sampleRateIndex); if (sampleRate <= 0) { LOG_ERR("Invalid sample rate %f for sensor %i", sampleRate, config.sensorId); return; @@ -205,23 +151,12 @@ static void config_work_handler(struct k_work *work) { sensor->sd_logging(config.storageOptions & DATA_STORAGE); sensor->ble_stream(config.storageOptions & DATA_STREAMING); - if (config.storageOptions & (DATA_STORAGE | DATA_STREAMING)) { - if (sensor->init(&sensor_queue)) { - if (active_sensors == 0) start_sensor_manager(); - sensor->start(config.sampleRateIndex); - if (sensor->is_running()) { - active_sensors++; - } - } - } - if (config.storageOptions & DATA_STORAGE) { sd_sensors.insert(config.sensorId); if (!sdlogger.is_active()) { const char *recording_name_prefix = get_sensor_recording_name(); LOG_INF("Starting SDLogger with recording name prefix: %s", recording_name_prefix); - // Start SDLogger with timestamp-based filename std::string filename = recording_name_prefix + std::to_string(micros()); int ret = sdlogger.begin(filename); if (ret == 0) state_indicator.set_sd_state(SD_RECORDING); @@ -235,11 +170,19 @@ static void config_work_handler(struct k_work *work) { } } + if (config.storageOptions & (DATA_STORAGE | DATA_STREAMING)) { + if (sensor->init()) { + if (active_sensors == 0) start_sensor_manager(); + sensor->start(config.sampleRateIndex); + if (sensor->is_running()) { + active_sensors++; + } + } + } + if (config.storageOptions & DATA_STREAMING) ble_sensors.insert(config.sensorId); else if (ble_sensors.find(config.sensorId) != ble_sensors.end()) { ble_sensors.erase(config.sensorId); - - // TODO: if (ble_sensors.empty()) ... } set_sensor_config_status(config); @@ -247,6 +190,14 @@ static void config_work_handler(struct k_work *work) { if (active_sensors == 0) stop_sensor_manager(); } +static void config_work_handler(struct k_work *work) { + struct sensor_config config; + + while (k_msgq_get(&config_queue, &config, K_NO_WAIT) == 0) { + process_sensor_config(config); + } +} + void config_sensor(struct sensor_config * config) { int ret = k_msgq_put(&config_queue, config, K_NO_WAIT); if (ret) { @@ -254,7 +205,5 @@ void config_sensor(struct sensor_config * config) { return; } - //k_work_queue_drain(&sensor_work_q, true); k_work_submit(&config_work); - //k_work_queue_unplug(&sensor_work_q); -} \ No newline at end of file +} diff --git a/src/SensorManager/Temp.cpp b/src/SensorManager/Temp.cpp index 24862dfd..9da95db4 100644 --- a/src/SensorManager/Temp.cpp +++ b/src/SensorManager/Temp.cpp @@ -1,6 +1,7 @@ #include "Temp.h" #include "SensorManager.h" +#include "sensor_sink.h" #include "math.h" #include "stdlib.h" @@ -13,6 +14,8 @@ Temp Temp::sensor; MLX90632 Temp::temp; static struct sensor_msg msg_temp; +static uint32_t temp_calls, temp_max_us; +static uint64_t temp_total_us; const SampleRateSetting<8> Temp::sample_rates = { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, // reg_vals @@ -20,8 +23,7 @@ const SampleRateSetting<8> Temp::sample_rates = { { 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0 } // true_sample_rates }; -bool Temp::init(struct k_msgq * queue) { - +bool Temp::init() { if (!_active) { pm_device_runtime_get(ls_1_8); pm_device_runtime_get(ls_3_3); @@ -38,18 +40,22 @@ bool Temp::init(struct k_msgq * queue) { return false; } - sensor_queue = queue; - k_work_init(&sensor.sensor_work, update_sensor); k_timer_init(&sensor.sensor_timer, sensor_timer_handler, NULL); - _active = true; - return true; } void Temp::update_sensor(struct k_work *work) { - if (!temp.dataAvailable()) return; + if (!sensor._running) return; + uint64_t t0 = micros(); + if (!temp.dataAvailable()) { + uint32_t elapsed = (uint32_t)(micros() - t0); + temp_calls++; + temp_total_us += elapsed; + if (elapsed > temp_max_us) temp_max_us = elapsed; + return; + } MLX90632::status returnError; float temperature = temp.getObjectTemp(returnError); @@ -68,10 +74,12 @@ void Temp::update_sensor(struct k_work *work) { memcpy(msg_temp.data.data, &temperature, sizeof(float)); - int ret = k_msgq_put(sensor_queue, &msg_temp, K_NO_WAIT); - if (ret) { - LOG_WRN("sensor msg queue full"); - } + sensor_sink_put(&msg_temp); + + uint32_t elapsed = (uint32_t)(micros() - t0); + temp_calls++; + temp_total_us += elapsed; + if (elapsed > temp_max_us) temp_max_us = elapsed; } /** @@ -84,7 +92,10 @@ void Temp::sensor_timer_handler(struct k_timer *dummy) { void Temp::start(int sample_rate_idx) { if (!_active) return; - k_timeout_t t = K_USEC(1e6 / sample_rates.true_sample_rates[sample_rate_idx]); + // Poll at 2x the sensor rate to avoid missing data-ready windows + // due to clock drift between the MCU timer and the MLX90632's + // internal oscillator. + k_timeout_t t = K_USEC(1e6 / sample_rates.true_sample_rates[sample_rate_idx] / 2); temp.setSampleRateRegVal(sample_rates.reg_vals[sample_rate_idx]); temp.continuousMode(); @@ -100,7 +111,13 @@ void Temp::stop() { _running = false; + uint32_t avg = temp_calls ? (uint32_t)(temp_total_us / temp_calls) : 0; + LOG_INF("temp: calls=%u avg=%u us max=%u us total=%u ms", + temp_calls, avg, temp_max_us, (uint32_t)(temp_total_us / 1000)); + temp_calls = 0; temp_total_us = 0; temp_max_us = 0; + k_timer_stop(&sensor.sensor_timer); + k_work_cancel(&sensor.sensor_work); temp.sleepMode(); diff --git a/src/SensorManager/Temp.h b/src/SensorManager/Temp.h index 5b3ce0c6..769c7f1d 100644 --- a/src/SensorManager/Temp.h +++ b/src/SensorManager/Temp.h @@ -14,7 +14,7 @@ class Temp : public EdgeMlSensor { public: static Temp sensor; - bool init(struct k_msgq * queue) override; + bool init() override; void start(int sample_rate_idx) override; void stop() override; diff --git a/src/SensorManager/sensor_shell.c b/src/SensorManager/sensor_shell.c new file mode 100644 index 00000000..c60c40de --- /dev/null +++ b/src/SensorManager/sensor_shell.c @@ -0,0 +1,308 @@ +/* + * Shell commands for sensor management and stress testing. + * Provides the same functionality as the phone app's BLE sensor config, + * accessible via RTT or CDC ACM console. + * + * Usage: + * sensor start [sd|stream|all] + * sensor stop + * sensor info + * sensor stress [duration_s] + * sensor nominal [duration_s] + */ + +#include +#include +#include +#include + +#include "openearable_common.h" +#include "SensorManager.h" +#include "SensorScheme.h" + +struct sensor_name_map { + const char *name; + enum sensor_id id; +}; + +static const struct sensor_name_map sensor_names[] = { + { "imu", ID_IMU }, + { "baro", ID_TEMP_BARO }, + { "micro", ID_MICRO }, + { "ppg", ID_PPG }, + { "temp", ID_OPTTEMP }, + { "bone", ID_BONE_CONDUCTION }, +}; + +#define SENSOR_COUNT ARRAY_SIZE(sensor_names) + +static int lookup_sensor(const char *name, enum sensor_id *id) +{ + for (size_t i = 0; i < SENSOR_COUNT; i++) { + if (strcmp(name, sensor_names[i].name) == 0) { + *id = sensor_names[i].id; + return 0; + } + } + return -EINVAL; +} + +static const char *sensor_id_to_name(enum sensor_id id) +{ + for (size_t i = 0; i < SENSOR_COUNT; i++) { + if (sensor_names[i].id == id) { + return sensor_names[i].name; + } + } + return "unknown"; +} + +static uint8_t parse_storage_opts(const char *opt) +{ + if (opt == NULL || strcmp(opt, "sd") == 0) { + return DATA_STORAGE; + } else if (strcmp(opt, "stream") == 0) { + return DATA_STREAMING; + } else if (strcmp(opt, "all") == 0) { + return DATA_STORAGE | DATA_STREAMING; + } + return 0; +} + +static void configure_one_sensor(enum sensor_id id, uint8_t rate_idx, uint8_t storage) +{ + struct sensor_config cfg = { + .sensorId = (uint8_t)id, + .sampleRateIndex = rate_idx, + .storageOptions = storage, + }; + config_sensor(&cfg); +} + +/* sensor start [sd|stream|all] */ +static int cmd_sensor_start(const struct shell *sh, size_t argc, char **argv) +{ + enum sensor_id id; + + if (argc < 3) { + shell_error(sh, "Usage: sensor start [sd|stream|all]"); + shell_print(sh, "Sensors: imu, baro, micro, ppg, temp, bone"); + return -EINVAL; + } + + if (lookup_sensor(argv[1], &id) != 0) { + shell_error(sh, "Unknown sensor '%s'", argv[1]); + shell_print(sh, "Valid: imu, baro, micro, ppg, temp, bone"); + return -EINVAL; + } + + uint8_t rate_idx = (uint8_t)atoi(argv[2]); + uint8_t storage = parse_storage_opts(argc > 3 ? argv[3] : NULL); + + if (storage == 0) { + shell_error(sh, "Invalid storage option '%s'. Use: sd, stream, all", argv[3]); + return -EINVAL; + } + + float rate = getSampleRateForSensorId((uint8_t)id, rate_idx); + shell_print(sh, "Starting %s: rate_idx=%u (%.1f Hz), opts=0x%02x", + sensor_id_to_name(id), rate_idx, (double)rate, storage); + + configure_one_sensor(id, rate_idx, storage); + return 0; +} + +/* sensor stop */ +static int cmd_sensor_stop(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Usage: sensor stop "); + return -EINVAL; + } + + if (strcmp(argv[1], "all") == 0) { + stop_sensor_manager(); + shell_print(sh, "All sensors stopped"); + return 0; + } + + enum sensor_id id; + + if (lookup_sensor(argv[1], &id) != 0) { + shell_error(sh, "Unknown sensor '%s'", argv[1]); + return -EINVAL; + } + + /* storageOptions=0 tells config_work_handler to stop the sensor */ + configure_one_sensor(id, 0, 0); + shell_print(sh, "Stopped %s", sensor_id_to_name(id)); + return 0; +} + +/* sensor info */ +static int cmd_sensor_info(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + struct ParseInfoScheme *scheme = getParseInfoScheme(); + + shell_print(sh, "%-8s %-6s %-10s %s", "Sensor", "ID", "Rates", "Options"); + shell_print(sh, "--------------------------------------------"); + + for (uint8_t i = 0; i < scheme->sensorCount; i++) { + struct SensorScheme *ss = getSensorSchemeForId(scheme->sensorIds[i]); + if (ss == NULL) { + continue; + } + + /* Build rate list string */ + char rates[64] = ""; + if (ss->configOptions.availableOptions & FREQUENCIES_DEFINED) { + size_t pos = 0; + for (uint8_t j = 0; j < ss->configOptions.frequencyOptions.frequencyCount && pos < sizeof(rates) - 8; j++) { + int n = snprintf(rates + pos, sizeof(rates) - pos, + "%s%.0f", + j > 0 ? "," : "", + (double)ss->configOptions.frequencyOptions.frequencies[j]); + if (n > 0) { + pos += n; + } + } + } + + shell_print(sh, "%-8s %-6u %-10s freq|sd|stream", + ss->name ? ss->name : sensor_id_to_name(ss->id), + ss->id, rates); + } + + return 0; +} + +/* sensor stress [duration_s] */ +static int cmd_sensor_stress(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Usage: sensor stress [duration_s]"); + return -EINVAL; + } + + uint8_t storage = parse_storage_opts(argv[1]); + if (storage == 0) { + shell_error(sh, "Invalid option '%s'. Use: sd, stream, all", argv[1]); + return -EINVAL; + } + + int duration_s = (argc > 2) ? atoi(argv[2]) : 0; + + shell_print(sh, "Starting all sensors at max rate, opts=0x%02x", storage); + + /* Start each sensor at its highest rate index */ + struct ParseInfoScheme *scheme = getParseInfoScheme(); + + for (uint8_t i = 0; i < scheme->sensorCount; i++) { + struct SensorScheme *ss = getSensorSchemeForId(scheme->sensorIds[i]); + if (ss == NULL) { + continue; + } + + uint8_t max_idx = 0; + if (ss->configOptions.availableOptions & FREQUENCIES_DEFINED) { + max_idx = ss->configOptions.frequencyOptions.frequencyCount - 1; + } + + float rate = getSampleRateForSensorId(ss->id, max_idx); + shell_print(sh, " %s: rate_idx=%u (%.1f Hz)", + ss->name ? ss->name : sensor_id_to_name(ss->id), + max_idx, (double)rate); + + configure_one_sensor(ss->id, max_idx, storage); + + /* Small delay between configs to avoid flooding the queue */ + k_msleep(50); + } + + if (duration_s > 0) { + shell_print(sh, "Running for %d seconds...", duration_s); + k_sleep(K_SECONDS(duration_s)); + stop_sensor_manager(); + shell_print(sh, "Stress test complete, all sensors stopped"); + } else { + shell_print(sh, "Sensors running. Use 'sensor stop all' to stop."); + } + + return 0; +} + +struct nominal_rate { + enum sensor_id id; + uint8_t rate_idx; +}; + +static const struct nominal_rate nominal_rates[] = { + { ID_IMU, 2 }, /* 100 Hz */ + { ID_PPG, 0 }, /* 25 Hz */ + { ID_OPTTEMP, 3 }, /* 4 Hz */ + { ID_TEMP_BARO, 14 }, /* 25 Hz */ + { ID_BONE_CONDUCTION, 9 }, /* 6400 Hz (max) */ + { ID_MICRO, 0 }, /* 48000 Hz */ +}; + +/* sensor nominal [duration_s] */ +static int cmd_sensor_nominal(const struct shell *sh, size_t argc, char **argv) +{ + if (argc < 2) { + shell_error(sh, "Usage: sensor nominal [duration_s]"); + return -EINVAL; + } + + uint8_t storage = parse_storage_opts(argv[1]); + if (storage == 0) { + shell_error(sh, "Invalid option '%s'. Use: sd, stream, all", argv[1]); + return -EINVAL; + } + + int duration_s = (argc > 2) ? atoi(argv[2]) : 0; + + shell_print(sh, "Starting all sensors at nominal rates, opts=0x%02x", storage); + + for (size_t i = 0; i < ARRAY_SIZE(nominal_rates); i++) { + const struct nominal_rate *nr = &nominal_rates[i]; + float rate = getSampleRateForSensorId((uint8_t)nr->id, nr->rate_idx); + shell_print(sh, " %s: rate_idx=%u (%.1f Hz)", + sensor_id_to_name(nr->id), nr->rate_idx, (double)rate); + + configure_one_sensor(nr->id, nr->rate_idx, storage); + k_msleep(50); + } + + if (duration_s > 0) { + shell_print(sh, "Running for %d seconds...", duration_s); + k_sleep(K_SECONDS(duration_s)); + stop_sensor_manager(); + shell_print(sh, "Nominal test complete, all sensors stopped"); + } else { + shell_print(sh, "Sensors running. Use 'sensor stop all' to stop."); + } + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sensor_cmds, + SHELL_CMD_ARG(start, NULL, + "Start a sensor: sensor start [sd|stream|all]", + cmd_sensor_start, 3, 1), + SHELL_CMD_ARG(stop, NULL, + "Stop a sensor: sensor stop ", + cmd_sensor_stop, 2, 0), + SHELL_CMD(info, NULL, "Show available sensors and sample rates", cmd_sensor_info), + SHELL_CMD_ARG(stress, NULL, + "Stress test: sensor stress [duration_s]", + cmd_sensor_stress, 2, 1), + SHELL_CMD_ARG(nominal, NULL, + "Nominal rates: sensor nominal [duration_s]", + cmd_sensor_nominal, 2, 1), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(sensor, &sensor_cmds, "Sensor management commands", NULL); diff --git a/src/SensorManager/sensor_sink.cpp b/src/SensorManager/sensor_sink.cpp new file mode 100644 index 00000000..71dc97ee --- /dev/null +++ b/src/SensorManager/sensor_sink.cpp @@ -0,0 +1,26 @@ +#include "sensor_sink.h" +#include "SDLogger.h" +#include "sensor_service.h" + +extern "C" int sensor_sink_put(const struct sensor_msg *msg) +{ + int ret = 0; + + if (msg->sd) { + int r = sdlogger.write_sensor_data(msg->data); + if (r < 0) ret = r; + } + + if (msg->stream) { + int r = sensor_gatt_queue_put(&msg->data); + if (r < 0 && ret == 0) ret = r; + } + + return ret; +} + +extern "C" int sensor_sink_write_sd(const void *const *data_blocks, + const size_t *lengths, size_t block_count) +{ + return sdlogger.write_sensor_data(data_blocks, lengths, block_count); +} diff --git a/src/Wire/TWIM.cpp b/src/Wire/TWIM.cpp index 057dada0..099e84a9 100644 --- a/src/Wire/TWIM.cpp +++ b/src/Wire/TWIM.cpp @@ -7,8 +7,6 @@ LOG_MODULE_REGISTER(twim, CONFIG_AUDIO_DATAPATH_LOG_LEVEL); TWIM::TWIM(const struct device * _device) : master(_device) {} void TWIM::begin() { - int ret; - if (_active) return; _active = true; @@ -42,7 +40,7 @@ void TWIM::setClock(uint32_t speed) { } } -void TWIM::aquire() { +void TWIM::acquire() { k_mutex_lock(&mutex, K_FOREVER); } diff --git a/src/Wire/TWIM.h b/src/Wire/TWIM.h index 3f6dbb7d..7bd5ea34 100644 --- a/src/Wire/TWIM.h +++ b/src/Wire/TWIM.h @@ -32,7 +32,7 @@ class TWIM virtual void setClock(uint32_t speed = I2C_SPEED_FAST); - void aquire(); + void acquire(); void release(); const struct device * master = NULL; diff --git a/src/Wire/Wire.cpp b/src/Wire/Wire.cpp index 79a20c05..79f4d69d 100644 --- a/src/Wire/Wire.cpp +++ b/src/Wire/Wire.cpp @@ -152,7 +152,7 @@ void arduino::MbedI2C::onRequest(voidFuncPtr cb) { onRequestCb = cb; } -void arduino::MbedI2C::aquire() { +void arduino::MbedI2C::acquire() { k_mutex_lock(&mutex, K_FOREVER); } diff --git a/src/Wire/Wire.h b/src/Wire/Wire.h index e7ae786d..be097d20 100644 --- a/src/Wire/Wire.h +++ b/src/Wire/Wire.h @@ -56,7 +56,7 @@ class MbedI2C //: public HardwareI2C virtual void flush(); virtual int available(); - void aquire(); + void acquire(); void release(); const struct device * master = NULL; diff --git a/src/bluetooth/gatt_services/device_info.c b/src/bluetooth/gatt_services/device_info.c index 3cbb548a..c87aaebd 100644 --- a/src/bluetooth/gatt_services/device_info.c +++ b/src/bluetooth/gatt_services/device_info.c @@ -1,6 +1,8 @@ #include "device_info.h" #include +#include + #include #include @@ -17,7 +19,7 @@ static ssize_t read_device_identifier(struct bt_conn *conn, uint16_t len, uint16_t offset) { - snprintf(device_identifier, sizeof(device_identifier), "0x%08X", oe_boot_state.device_id); + snprintf(device_identifier, sizeof(device_identifier), "0x%08X", (uint32_t)oe_boot_state.device_id); return bt_gatt_attr_read(conn, attr, buf, len, offset, device_identifier, sizeof(device_identifier)); diff --git a/src/bluetooth/gatt_services/sensor_service.c b/src/bluetooth/gatt_services/sensor_service.c index 17e9cd25..ade03282 100644 --- a/src/bluetooth/gatt_services/sensor_service.c +++ b/src/bluetooth/gatt_services/sensor_service.c @@ -15,16 +15,12 @@ static struct k_thread thread_data_notify; static k_tid_t thread_id_notify; -ZBUS_SUBSCRIBER_DEFINE(sensor_gatt_sub, CONFIG_BUTTON_MSG_SUB_QUEUE_SIZE); - -ZBUS_CHAN_DECLARE(sensor_chan); ZBUS_CHAN_DECLARE(bt_mgmt_chan); static K_THREAD_STACK_DEFINE(thread_stack_notify, CONFIG_SENSOR_GATT_NOTIFY_STACK_SIZE); K_MSGQ_DEFINE(gatt_queue, sizeof(struct sensor_data), CONFIG_SENSOR_GATT_SUB_QUEUE_SIZE, 4); -//static struct sensor_msg msg; static struct sensor_data sensor_data; static struct sensor_config config; @@ -38,14 +34,11 @@ static struct sensor_config *active_sensor_configs; static size_t active_sensor_configs_size = 0; static void connect_evt_handler(const struct zbus_channel *chan); -ZBUS_LISTENER_DEFINE(bt_mgmt_evt_listen2, connect_evt_handler); //static - -void sensor_queue_listener_cb(const struct zbus_channel *chan); -ZBUS_LISTENER_DEFINE(sensor_queue_listener, sensor_queue_listener_cb); +ZBUS_LISTENER_DEFINE(bt_mgmt_evt_listen2, connect_evt_handler); static bool connection_complete = false; -int notify_count = 0; +static struct k_sem notify_sem; int MAX_NOTIFIES_IN_FLIGHT = 4; @@ -196,12 +189,7 @@ BT_GATT_CHARACTERISTIC(BT_UUID_SENSOR_RECORDING_NAME, ); static void notify_complete() { - notify_count--; - - if (notify_count < 0) { - notify_count = 0; - LOG_WRN("Notify count went below zero!"); - } + k_sem_give(¬ify_sem); } static void notification_task(void) { @@ -225,33 +213,20 @@ static void notification_task(void) { params.func = notify_complete; params.user_data = NULL; - while(notify_count >= MAX_NOTIFIES_IN_FLIGHT) { - k_yield(); // maybe replace with k_sleep? - } - - notify_count++; + k_sem_take(¬ify_sem, K_FOREVER); ret = bt_gatt_notify_cb(NULL, ¶ms); if (ret != 0) { LOG_WRN("Failed to send data: %d.\n", ret); + k_sem_give(¬ify_sem); } } } } -void sensor_queue_listener_cb(const struct zbus_channel *chan) { - int ret; - const struct sensor_msg * msg; - - msg = (struct sensor_msg *)zbus_chan_const_msg(&sensor_chan); - - if (msg->stream) { - ret = k_msgq_put(&gatt_queue, &msg->data, K_NO_WAIT); - - if (ret) { - LOG_WRN("ble sensor stream queue full"); - } - } +int sensor_gatt_queue_put(const struct sensor_data *data) +{ + return k_msgq_put(&gatt_queue, data, K_NO_WAIT); } int init_sensor_config_status() { @@ -330,6 +305,8 @@ int set_sensor_config_status(struct sensor_config config) { int init_sensor_service() { int ret; + k_sem_init(¬ify_sem, MAX_NOTIFIES_IN_FLIGHT, MAX_NOTIFIES_IN_FLIGHT); + thread_id_notify = k_thread_create( &thread_data_notify, thread_stack_notify, CONFIG_SENSOR_GATT_NOTIFY_STACK_SIZE, (k_thread_entry_t)notification_task, NULL, @@ -341,12 +318,6 @@ int init_sensor_service() { return ret; } - ret = zbus_chan_add_obs(&sensor_chan, &sensor_queue_listener, ZBUS_ADD_OBS_TIMEOUT_MS); - if (ret) { - LOG_ERR("Failed to add sensor sub"); - return ret; - } - ret = zbus_chan_add_obs(&bt_mgmt_chan, &bt_mgmt_evt_listen2, ZBUS_ADD_OBS_TIMEOUT_MS); if (ret) { LOG_ERR("Failed to add bt_mgmt listener"); diff --git a/src/bluetooth/gatt_services/sensor_service.h b/src/bluetooth/gatt_services/sensor_service.h index 239062fe..95bd8573 100644 --- a/src/bluetooth/gatt_services/sensor_service.h +++ b/src/bluetooth/gatt_services/sensor_service.h @@ -33,10 +33,8 @@ extern "C" { int init_sensor_service(); const char *get_sensor_recording_name(); -//int send_sensor_data(); //struct sensor_data * data); - +int sensor_gatt_queue_put(const struct sensor_data *data); int set_sensor_config_status(struct sensor_config config); - void temp_disable_notifies(bool disable); #ifdef __cplusplus diff --git a/src/drivers/ADAU1860.cpp b/src/drivers/ADAU1860.cpp index 3d3e2d88..1c22d766 100644 --- a/src/drivers/ADAU1860.cpp +++ b/src/drivers/ADAU1860.cpp @@ -524,9 +524,9 @@ bool ADAU1860::readReg(uint32_t reg, uint8_t * buffer, uint16_t len) { msg[1].len = len; msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP; - _i2c->aquire(); + _i2c->acquire(); - // Adresse senden und Daten lesen + // Send address and read data ret = i2c_transfer(_i2c->master, msg, 2, address); if (ret) { LOG_WRN("I2C read failed: %d", ret); @@ -556,7 +556,7 @@ void ADAU1860::writeReg(uint32_t reg, uint8_t *buffer, uint16_t len) { msg[1].len = len; msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP; - _i2c->aquire(); + _i2c->acquire(); ret = i2c_transfer(_i2c->master, msg, 2, address); if (ret) { diff --git a/src/modules/audio_i2s.h b/src/modules/audio_i2s.h index ea217ee3..7eaacc0e 100644 --- a/src/modules/audio_i2s.h +++ b/src/modules/audio_i2s.h @@ -88,4 +88,9 @@ void audio_i2s_blk_comp_cb_register(i2s_blk_comp_callback_t blk_comp_callback); */ void audio_i2s_init(void); +struct audio_rx_data { + char data[FRAME_SIZE_BYTES]; + size_t size; +}; + #endif /* _AUDIO_I2S_H_ */ diff --git a/src/utils/macros/macros_custom.h b/src/utils/macros/macros_custom.h index 5e102938..8a1dd605 100644 --- a/src/utils/macros/macros_custom.h +++ b/src/utils/macros/macros_custom.h @@ -15,7 +15,7 @@ ZBUS_SUBSCRIBER_DEFINE(name ## _sub, CONFIG_BUTTON_MSG_SUB_QUEUE_SIZE); \ ZBUS_CHAN_DECLARE(name ## _chan); \ static K_THREAD_STACK_DEFINE(thread_stack, CONFIG_BUTTON_MSG_SUB_STACK_SIZE); \ \ -static void write_ ## name ## _gatt(void)\ +static void write_ ## name ## _gatt(void)\ {\ int ret;\ const struct zbus_channel *chan;\