| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * resarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| |
| #include "os/mynewt.h" |
| #include "hal/hal_i2c.h" |
| #include "i2cn/i2cn.h" |
| #include "sensor/sensor.h" |
| #include "sensor/accel.h" |
| #include "sensor/mag.h" |
| #include "sensor/quat.h" |
| #include "sensor/euler.h" |
| #include "sensor/gyro.h" |
| #include "sensor/temperature.h" |
| #include "bno055/bno055.h" |
| #include "bno055_priv.h" |
| #include "modlog/modlog.h" |
| #include "stats/stats.h" |
| #include <syscfg/syscfg.h> |
| |
| /* Define the stats section and records */ |
| STATS_SECT_START(bno055_stat_section) |
| STATS_SECT_ENTRY(errors) |
| STATS_SECT_END |
| |
| /* Define stat names for querying */ |
| STATS_NAME_START(bno055_stat_section) |
| STATS_NAME(bno055_stat_section, errors) |
| STATS_NAME_END(bno055_stat_section) |
| |
| /* Global variable used to hold stats data */ |
| STATS_SECT_DECL(bno055_stat_section) g_bno055stats; |
| |
| #define BNO055_LOG(lvl_, ...) \ |
| MODLOG_ ## lvl_(MYNEWT_VAL(BNO055_LOG_MODULE), __VA_ARGS__) |
| |
| /* Exports for the sensor API.*/ |
| static int bno055_sensor_read(struct sensor *, sensor_type_t, |
| sensor_data_func_t, void *, uint32_t); |
| static int bno055_sensor_get_config(struct sensor *, sensor_type_t, |
| struct sensor_cfg *); |
| |
| static const struct sensor_driver g_bno055_sensor_driver = { |
| bno055_sensor_read, |
| bno055_sensor_get_config |
| }; |
| |
| /** |
| * Writes a single byte to the specified register |
| * |
| * @param The Sesnsor interface |
| * @param The register address to write to |
| * @param The value to write |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| bno055_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value) |
| { |
| int rc; |
| uint8_t payload[2] = { reg, value}; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 2, |
| .buffer = payload |
| }; |
| |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC, 1, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, |
| "Failed to write to 0x%02X:0x%02X with value 0x%02X\n", |
| data_struct.address, reg, value); |
| STATS_INC(g_bno055stats, errors); |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * Writes a multiple bytes to the specified register (MAX: 22 bytes) |
| * |
| * @param The Sesnsor interface |
| * @param The register address to write to |
| * @param The data buffer to write from |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| bno055_writelen(struct sensor_itf *itf, uint8_t reg, uint8_t *buffer, |
| uint8_t len) |
| { |
| int rc; |
| uint8_t payload[23] = { reg, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0}; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = payload |
| }; |
| |
| if (len > (sizeof(payload) - 1)) { |
| return OS_EINVAL; |
| } |
| |
| memcpy(&payload[1], buffer, len); |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(BNO055_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| data_struct.address); |
| STATS_INC(g_bno055stats, errors); |
| goto err; |
| } |
| |
| memset(payload, 0, sizeof(payload)); |
| data_struct.len = len; |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, |
| len, MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n", |
| data_struct.address, reg); |
| STATS_INC(g_bno055stats, errors);; |
| } |
| |
| err: |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Reads a single byte from the specified register |
| * |
| * @param The Sensor interface |
| * @param The register address to read from |
| * @param Pointer to where the register value should be written |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| bno055_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value) |
| { |
| int rc; |
| uint8_t payload; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = &payload |
| }; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(BNO055_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Register write */ |
| payload = reg; |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 0, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, |
| "I2C register write failed at address 0x%02X:0x%02X\n", |
| data_struct.address, reg); |
| STATS_INC(g_bno055stats, errors); |
| goto err; |
| } |
| |
| /* Read one byte back */ |
| payload = 0; |
| rc = i2cn_master_read(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| *value = payload; |
| if (rc) { |
| BNO055_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n", |
| data_struct.address, reg); |
| STATS_INC(g_bno055stats, errors); |
| } |
| |
| err: |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Read data from the sensor of variable length (MAX: 8 bytes) |
| * |
| * @param The Sensor interface |
| * @param Register to read from |
| * @param Bufer to read into |
| * @param Length of the buffer |
| * |
| * @return 0 on success and non-zero on failure |
| */ |
| static int |
| bno055_readlen(struct sensor_itf *itf, uint8_t reg, uint8_t *buffer, |
| uint8_t len) |
| { |
| int rc; |
| uint8_t payload[23] = { reg, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0}; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = payload |
| }; |
| |
| /* Clear the supplied buffer */ |
| memset(buffer, 0, len); |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(BNO055_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| data_struct.address); |
| STATS_INC(g_bno055stats, errors); |
| goto err; |
| } |
| |
| /* Read len bytes back */ |
| memset(payload, 0, sizeof(payload)); |
| data_struct.len = len; |
| rc = i2cn_master_read(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(BNO055_I2C_RETRIES)); |
| if (rc) { |
| BNO055_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n", |
| data_struct.address, reg); |
| STATS_INC(g_bno055stats, errors); |
| } |
| |
| /* Copy the I2C results into the supplied buffer */ |
| memcpy(buffer, payload, len); |
| |
| err: |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Setting operation mode for the bno055 sensor |
| * |
| * @param The sensor interface |
| * @param Operation mode for the sensor |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_opr_mode(struct sensor_itf *itf, uint8_t mode) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_OPR_MODE_ADDR, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 19)/1000 + 1); |
| |
| rc = bno055_write8(itf, BNO055_OPR_MODE_ADDR, mode); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Refer table 3-6 in the datasheet for the delay values */ |
| os_time_delay((OS_TICKS_PER_SEC * 7)/1000 + 1); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Setting power mode for the bno055 sensor |
| * |
| * @param The sensor interface |
| * @param power mode for the sensor |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_pwr_mode(struct sensor_itf *itf, uint8_t mode) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_PWR_MODE_ADDR, mode); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 1)/1000 + 1); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Read current power mode of the sensor |
| * |
| * @param The Sensor interface |
| * @param ptr to mode variableto fill up |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_pwr_mode(struct sensor_itf *itf, uint8_t *mode) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_PWR_MODE_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *mode = val; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Setting units for the bno055 sensor |
| * |
| * @param The Sensor interface |
| * @param power mode for the sensor |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_units(struct sensor_itf *itf, uint8_t val) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_UNIT_SEL_ADDR, val); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get units of the sensor |
| * |
| * @param The sensor interface |
| * @param ptr to the units variable |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_units(struct sensor_itf *itf, uint8_t *units) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_UNIT_SEL_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *units = val; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Read current operational mode of the sensor |
| * |
| * @param The Sensor interface |
| * @param ptr to mode variable to fill up |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_opr_mode(struct sensor_itf *itf, uint8_t *mode) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_OPR_MODE_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *mode = val; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| static int |
| bno055_default_cfg(struct bno055_cfg *cfg) |
| { |
| cfg->bc_opr_mode = BNO055_OPR_MODE_ACCONLY; |
| cfg->bc_pwr_mode = BNO055_PWR_MODE_NORMAL; |
| cfg->bc_units = BNO055_DO_FORMAT_ANDROID| |
| BNO055_ACC_UNIT_MS2| |
| BNO055_ANGRATE_UNIT_DPS| |
| BNO055_EULER_UNIT_DEG| |
| BNO055_TEMP_UNIT_DEGC; |
| cfg->bc_placement = BNO055_AXIS_CFG_P1; |
| cfg->bc_acc_range = BNO055_ACC_CFG_RNG_4G; |
| cfg->bc_acc_bw = BNO055_ACC_CFG_BW_6_25HZ; |
| cfg->bc_acc_res = 14; |
| cfg->bc_gyro_range = BNO055_GYR_CFG_RNG_2000DPS; |
| cfg->bc_gyro_bw = BNO055_GYR_CFG_BW_32HZ; |
| cfg->bc_gyro_res = 16; |
| cfg->bc_mag_odr = BNO055_MAG_CFG_ODR_2HZ; |
| cfg->bc_mag_xy_rep = 15; |
| cfg->bc_mag_z_rep = 16; |
| cfg->bc_mag_res = BNO055_MAG_RES_13_13_15; |
| cfg->bc_mask = SENSOR_TYPE_ACCELEROMETER; |
| |
| return 0; |
| } |
| |
| /** |
| * Expects to be called back through os_dev_create(). |
| * |
| * @param The device object associated with this accelerometer |
| * @param Argument passed to OS device init, unused |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| bno055_init(struct os_dev *dev, void *arg) |
| { |
| struct bno055 *bno055; |
| struct sensor *sensor; |
| int rc; |
| |
| if (!arg || !dev) { |
| rc = SYS_ENODEV; |
| goto err; |
| } |
| |
| bno055 = (struct bno055 *) dev; |
| |
| rc = bno055_default_cfg(&bno055->cfg); |
| if (rc) { |
| goto err; |
| } |
| |
| sensor = &bno055->sensor; |
| |
| /* Initialise the stats entry */ |
| rc = stats_init( |
| STATS_HDR(g_bno055stats), |
| STATS_SIZE_INIT_PARMS(g_bno055stats, STATS_SIZE_32), |
| STATS_NAME_INIT_PARMS(bno055_stat_section)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| /* Register the entry with the stats registry */ |
| rc = stats_register(dev->od_name, STATS_HDR(g_bno055stats)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| |
| rc = sensor_init(sensor, dev); |
| if (rc != 0) { |
| goto err; |
| } |
| |
| /* Add the accelerometer/magnetometer driver */ |
| rc = sensor_set_driver(sensor, SENSOR_TYPE_ACCELEROMETER | |
| SENSOR_TYPE_MAGNETIC_FIELD | SENSOR_TYPE_GYROSCOPE | |
| SENSOR_TYPE_TEMPERATURE | SENSOR_TYPE_ROTATION_VECTOR | |
| SENSOR_TYPE_GRAVITY | SENSOR_TYPE_LINEAR_ACCEL | |
| SENSOR_TYPE_EULER, (struct sensor_driver *) &g_bno055_sensor_driver); |
| if (rc != 0) { |
| goto err; |
| } |
| |
| /* Set the interface */ |
| rc = sensor_set_interface(sensor, arg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = sensor_mgr_register(sensor); |
| if (rc != 0) { |
| goto err; |
| } |
| |
| return (0); |
| err: |
| return (rc); |
| } |
| |
| /** |
| * Get chip ID from the sensor |
| * |
| * @param The sensor interface |
| * @param Pointer to the variable to fill up chip ID in |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_chip_id(struct sensor_itf *itf, uint8_t *id) |
| { |
| int rc; |
| uint8_t idtmp; |
| |
| /* Check if we can read the chip address */ |
| rc = bno055_read8(itf, BNO055_CHIP_ID_ADDR, &idtmp); |
| if (rc) { |
| goto err; |
| } |
| |
| *id = idtmp; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Use external crystal 32.768KHz |
| * |
| * @param The Sensor interface |
| * @param operational mode of the sensor |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| bno055_set_ext_xtal_use(struct sensor_itf *itf, uint8_t use_xtal, uint8_t mode) |
| { |
| int rc; |
| |
| if (mode != BNO055_OPR_MODE_CONFIG) { |
| /* Switch to config mode */ |
| rc = bno055_set_opr_mode(itf, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 25)/1000 + 1); |
| |
| rc = bno055_write8(itf, BNO055_PAGE_ID_ADDR, 0); |
| if (rc) { |
| goto err; |
| } |
| |
| if (use_xtal) { |
| /* Use External Clock */ |
| rc = bno055_write8(itf, BNO055_SYS_TRIGGER_ADDR, BNO055_SYS_TRIGGER_CLK_SEL); |
| if (rc) { |
| goto err; |
| } |
| } else { |
| /* Use Internal clock */ |
| rc = bno055_write8(itf, BNO055_SYS_TRIGGER_ADDR, 0x00); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 10)/1000 + 1); |
| |
| /* Reset to previous operating mode */ |
| rc = bno055_set_opr_mode(itf, mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bno055_placement_cfg(struct sensor_itf *itf, uint8_t placement) |
| { |
| uint8_t remap_cfg; |
| uint8_t remap_sign; |
| int rc; |
| |
| rc = SYS_EOK; |
| |
| switch(placement) { |
| |
| case BNO055_AXIS_CFG_P0: |
| remap_cfg = BNO055_REMAP_CONFIG_P0; |
| remap_sign = BNO055_REMAP_SIGN_P0; |
| break; |
| case BNO055_AXIS_CFG_P1: |
| remap_cfg = BNO055_REMAP_CONFIG_P1; |
| remap_sign = BNO055_REMAP_SIGN_P1; |
| break; |
| case BNO055_AXIS_CFG_P2: |
| remap_cfg = BNO055_REMAP_CONFIG_P2; |
| remap_sign = BNO055_REMAP_SIGN_P2; |
| break; |
| case BNO055_AXIS_CFG_P3: |
| remap_cfg = BNO055_REMAP_CONFIG_P3; |
| remap_sign = BNO055_REMAP_SIGN_P3; |
| break; |
| case BNO055_AXIS_CFG_P4: |
| remap_cfg = BNO055_REMAP_CONFIG_P4; |
| remap_sign = BNO055_REMAP_SIGN_P4; |
| break; |
| case BNO055_AXIS_CFG_P5: |
| remap_cfg = BNO055_REMAP_CONFIG_P5; |
| remap_sign = BNO055_REMAP_SIGN_P5; |
| break; |
| case BNO055_AXIS_CFG_P6: |
| remap_cfg = BNO055_REMAP_CONFIG_P6; |
| remap_sign = BNO055_REMAP_SIGN_P6; |
| break; |
| case BNO055_AXIS_CFG_P7: |
| remap_cfg = BNO055_REMAP_CONFIG_P7; |
| remap_sign = BNO055_REMAP_SIGN_P7; |
| break; |
| default: |
| BNO055_LOG(ERROR, "Invalid Axis config, Assuming P1(default) \n"); |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = bno055_write8(itf, BNO055_AXIS_MAP_CONFIG_ADDR, remap_cfg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_write8(itf, BNO055_AXIS_MAP_SIGN_ADDR, remap_sign); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bno055_acc_cfg(struct sensor_itf *itf, struct bno055_cfg *cfg) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_ACCEL_CONFIG_ADDR, cfg->bc_acc_range| |
| cfg->bc_acc_bw|cfg->bc_acc_opr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bno055_mag_cfg(struct sensor_itf *itf, struct bno055_cfg *cfg) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_MAG_CONFIG_ADDR, cfg->bc_mag_odr| |
| cfg->bc_mag_pwr_mode|cfg->bc_mag_opr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bno055_gyro_cfg(struct sensor_itf *itf, struct bno055_cfg *cfg) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_GYRO_CONFIG_ADDR, cfg->bc_gyro_range| |
| cfg->bc_gyro_bw|cfg->bc_gyro_opr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bno055_config(struct bno055 *bno055, struct bno055_cfg *cfg) |
| { |
| int rc; |
| uint8_t id; |
| uint8_t mode; |
| struct sensor_itf *itf; |
| |
| itf = SENSOR_GET_ITF(&(bno055->sensor)); |
| |
| /* Check if we can read the chip address */ |
| rc = bno055_get_chip_id(itf, &id); |
| if (rc) { |
| goto err; |
| } |
| |
| if (id != BNO055_ID) { |
| os_time_delay((OS_TICKS_PER_SEC * 100)/1000 + 1); |
| |
| rc = bno055_get_chip_id(itf, &id); |
| if (rc) { |
| goto err; |
| } |
| |
| if(id != BNO055_ID) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| } |
| |
| /* Reset sensor */ |
| rc = bno055_write8(itf, BNO055_SYS_TRIGGER_ADDR, |
| BNO055_SYS_TRIGGER_RST_SYS); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay(OS_TICKS_PER_SEC); |
| |
| rc = bno055_set_opr_mode(itf, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Set to normal power mode */ |
| rc = bno055_set_pwr_mode(itf, cfg->bc_pwr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| bno055->cfg.bc_pwr_mode = cfg->bc_pwr_mode; |
| |
| /** |
| * As per Section 5.5 in the BNO055 Datasheet, |
| * external crystal should be used for accurate |
| * results |
| */ |
| rc = bno055_set_ext_xtal_use(itf, cfg->bc_use_ext_xtal, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| bno055->cfg.bc_use_ext_xtal = cfg->bc_use_ext_xtal; |
| |
| /* Setting units and data output format */ |
| rc = bno055_set_units(itf, cfg->bc_units); |
| if (rc) { |
| goto err; |
| } |
| |
| bno055->cfg.bc_units = cfg->bc_units; |
| |
| /* Change mode to requested mode */ |
| rc = bno055_set_opr_mode(itf, cfg->bc_opr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay(OS_TICKS_PER_SEC/2); |
| |
| rc = bno055_get_opr_mode(itf, &mode); |
| if (rc) { |
| goto err; |
| } |
| |
| if (cfg->bc_opr_mode != mode) { |
| |
| /* Trying to set operation mode again */ |
| rc = bno055_set_opr_mode(itf, cfg->bc_opr_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_get_opr_mode(itf, &mode); |
| |
| if (rc) { |
| goto err; |
| } |
| |
| if (cfg->bc_opr_mode != mode) { |
| BNO055_LOG(ERROR, "Config mode and read mode do not match.\n"); |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| } |
| |
| bno055->cfg.bc_opr_mode = cfg->bc_opr_mode; |
| |
| rc = bno055_acc_cfg(itf, cfg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = sensor_set_type_mask(&(bno055->sensor), cfg->bc_mask); |
| if (rc) { |
| goto err; |
| } |
| |
| bno055->cfg.bc_mask = cfg->bc_mask; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get quat data from sensor |
| * |
| * @param The sensor ineterface |
| * @param sensor quat data to be filled up |
| * @return 0 on success, non-zero on error |
| */ |
| int |
| bno055_get_quat_data(struct sensor_itf *itf, void *datastruct) |
| { |
| uint8_t buffer[8]; |
| double scale; |
| int rc; |
| struct sensor_quat_data *sqd; |
| |
| sqd = (struct sensor_quat_data *)datastruct; |
| |
| /* As per Section 3.6.5.5 Orientation (Quaternion) */ |
| scale = (1.0 / (1<<14)); |
| |
| memset (buffer, 0, 8); |
| |
| /* Read quat data */ |
| rc = bno055_readlen(itf, BNO055_QUATERNION_DATA_W_LSB_ADDR, buffer, 8); |
| |
| if (rc) { |
| goto err; |
| } |
| |
| sqd->sqd_w = ((((uint16_t)buffer[1]) << 8) | ((uint16_t)buffer[0])) * scale; |
| sqd->sqd_x = ((((uint16_t)buffer[3]) << 8) | ((uint16_t)buffer[2])) * scale; |
| sqd->sqd_y = ((((uint16_t)buffer[5]) << 8) | ((uint16_t)buffer[4])) * scale; |
| sqd->sqd_z = ((((uint16_t)buffer[7]) << 8) | ((uint16_t)buffer[6])) * scale; |
| |
| sqd->sqd_w_is_valid = 1; |
| sqd->sqd_x_is_valid = 1; |
| sqd->sqd_y_is_valid = 1; |
| sqd->sqd_z_is_valid = 1; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Find register based on sensor type |
| * |
| * @return register address |
| */ |
| static int |
| bno055_find_reg(sensor_type_t type, uint8_t *reg) |
| { |
| int rc; |
| |
| rc = SYS_EOK; |
| switch(type) { |
| case SENSOR_TYPE_ACCELEROMETER: |
| *reg = BNO055_ACCEL_DATA_X_LSB_ADDR; |
| break; |
| case SENSOR_TYPE_GYROSCOPE: |
| *reg = BNO055_GYRO_DATA_X_LSB_ADDR; |
| break; |
| case SENSOR_TYPE_MAGNETIC_FIELD: |
| *reg = BNO055_MAG_DATA_X_LSB_ADDR; |
| break; |
| case SENSOR_TYPE_EULER: |
| *reg = BNO055_EULER_H_LSB_ADDR; |
| break; |
| case SENSOR_TYPE_LINEAR_ACCEL: |
| *reg = BNO055_LINEAR_ACCEL_DATA_X_LSB_ADDR; |
| break; |
| case SENSOR_TYPE_GRAVITY: |
| *reg = BNO055_GRAVITY_DATA_X_LSB_ADDR; |
| break; |
| default: |
| BNO055_LOG(ERROR, "Not supported sensor type: %d\n", (int)type); |
| rc = SYS_EINVAL; |
| break; |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * Get vector data from sensor |
| * |
| * @param The sensor ineterface |
| * @param pointer to the structure to be filled up |
| * @param Type of sensor |
| * @return 0 on success, non-zero on error |
| */ |
| int |
| bno055_get_vector_data(struct sensor_itf *itf, void *datastruct, int type) |
| { |
| |
| uint8_t payload[6]; |
| int16_t x, y, z; |
| struct sensor_mag_data *smd; |
| struct sensor_accel_data *sad; |
| struct sensor_euler_data *sed; |
| uint8_t reg; |
| uint8_t units; |
| float acc_div; |
| float gyro_div; |
| float euler_div; |
| |
| int rc; |
| |
| memset (payload, 0, 6); |
| |
| x = y = z = 0; |
| |
| rc = bno055_find_reg(type, ®); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_readlen(itf, reg, payload, 6); |
| if (rc) { |
| goto err; |
| } |
| |
| x = ((int16_t)payload[0]) | (((int16_t)payload[1]) << 8); |
| y = ((int16_t)payload[2]) | (((int16_t)payload[3]) << 8); |
| z = ((int16_t)payload[4]) | (((int16_t)payload[5]) << 8); |
| |
| rc = bno055_get_units(itf, &units); |
| if (rc) { |
| goto err; |
| } |
| |
| acc_div = units & BNO055_ACC_UNIT_MG ? 1.0:100.0; |
| gyro_div = units & BNO055_ANGRATE_UNIT_RPS ? 900.0:16.0; |
| euler_div = units & BNO055_EULER_UNIT_RAD ? 900.0:16.0; |
| |
| /** |
| * Convert the value to an appropriate range (section 3.6.4) |
| */ |
| switch(type) { |
| case SENSOR_TYPE_MAGNETIC_FIELD: |
| smd = datastruct; |
| /* 1uT = 16 LSB */ |
| smd->smd_x = ((double)x)/16.0; |
| smd->smd_y = ((double)y)/16.0; |
| smd->smd_z = ((double)z)/16.0; |
| |
| smd->smd_x_is_valid = 1; |
| smd->smd_y_is_valid = 1; |
| smd->smd_z_is_valid = 1; |
| |
| break; |
| case SENSOR_TYPE_GYROSCOPE: |
| sad = datastruct; |
| /* 1rps = 900 LSB */ |
| sad->sad_x = ((double)x)/gyro_div; |
| sad->sad_y = ((double)y)/gyro_div; |
| sad->sad_z = ((double)z)/gyro_div; |
| |
| sad->sad_x_is_valid = 1; |
| sad->sad_y_is_valid = 1; |
| sad->sad_z_is_valid = 1; |
| break; |
| case SENSOR_TYPE_EULER: |
| sed = datastruct; |
| /* 1 degree = 16 LSB */ |
| sed->sed_h = ((double)x)/euler_div; |
| sed->sed_r = ((double)y)/euler_div; |
| sed->sed_p = ((double)z)/euler_div; |
| |
| sed->sed_h_is_valid = 1; |
| sed->sed_r_is_valid = 1; |
| sed->sed_p_is_valid = 1; |
| break; |
| case SENSOR_TYPE_ACCELEROMETER: |
| case SENSOR_TYPE_LINEAR_ACCEL: |
| case SENSOR_TYPE_GRAVITY: |
| sad = datastruct; |
| /* 1m/s^2 = 100 LSB */ |
| sad->sad_x = ((double)x)/acc_div; |
| sad->sad_y = ((double)y)/acc_div; |
| sad->sad_z = ((double)z)/acc_div; |
| |
| sad->sad_x_is_valid = 1; |
| sad->sad_y_is_valid = 1; |
| sad->sad_z_is_valid = 1; |
| break; |
| default: |
| BNO055_LOG(ERROR, "Not supported sensor type: %d\n", type); |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get temperature from bno055 sensor |
| * |
| * @param The Sensor interface |
| * @param pointer to the temperature variable to be filled up |
| * @return 0 on success, non-zero on error |
| */ |
| int |
| bno055_get_temp(struct sensor_itf *itf, uint8_t *temp) |
| { |
| int rc; |
| uint8_t units; |
| uint8_t div; |
| |
| rc = bno055_read8(itf, BNO055_TEMP_ADDR, temp); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_get_units(itf, &units); |
| if (rc) { |
| goto err; |
| } |
| |
| div = units & BNO055_TEMP_UNIT_DEGF ? 2 : 1; |
| |
| *temp = *temp/div; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get temperature data from bno055 sensor and mark it valid |
| * |
| * @param The sensor interface |
| * @param pointer to the temperature data structure |
| * @return 0 on success, non-zero on error |
| */ |
| static int |
| bno055_get_temp_data(struct sensor_itf *itf, struct sensor_temp_data *std) |
| { |
| int rc; |
| uint8_t temp; |
| |
| rc = bno055_get_temp(itf, &temp); |
| if (rc) { |
| goto err; |
| } |
| |
| std->std_temp = temp; |
| std->std_temp_is_valid = 1; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get sensor data of specific type. This function also allocates a buffer |
| * to fill up the data in. |
| * |
| * @param Sensor structure used by the SensorAPI |
| * @param Sensor type |
| * @param Data function provided by the caler of the API |
| * @param Argument for the data function |
| * @param Timeout if any for reading |
| * @return 0 on success, non-zero on error |
| */ |
| static int |
| bno055_sensor_read(struct sensor *sensor, sensor_type_t type, |
| sensor_data_func_t data_func, void *data_arg, uint32_t timeout) |
| { |
| int rc; |
| struct sensor_itf *itf; |
| |
| union { |
| struct sensor_quat_data sqd; |
| struct sensor_euler_data sed; |
| struct sensor_accel_data sad; |
| struct sensor_accel_data slad; |
| struct sensor_accel_data sgrd; |
| struct sensor_mag_data smd; |
| struct sensor_gyro_data sgd; |
| struct sensor_temp_data std; |
| } databuf; |
| |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| if (type & SENSOR_TYPE_ROTATION_VECTOR) { |
| /* Quaternion is a rotation vector */ |
| rc = bno055_get_quat_data(itf, &databuf.sqd); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf, SENSOR_TYPE_ROTATION_VECTOR); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_TEMPERATURE) { |
| rc = bno055_get_temp_data(itf, &databuf.std); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.std, SENSOR_TYPE_TEMPERATURE); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_EULER) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.sed, SENSOR_TYPE_EULER); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.sed, SENSOR_TYPE_EULER); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_ACCELEROMETER) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.sad, SENSOR_TYPE_ACCELEROMETER); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.sad, SENSOR_TYPE_ACCELEROMETER); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_LINEAR_ACCEL) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.slad, SENSOR_TYPE_LINEAR_ACCEL); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.slad, SENSOR_TYPE_LINEAR_ACCEL); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_MAGNETIC_FIELD) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.smd, SENSOR_TYPE_MAGNETIC_FIELD); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.smd, SENSOR_TYPE_MAGNETIC_FIELD); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_GYROSCOPE) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.sgd, SENSOR_TYPE_GYROSCOPE); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.sgd, SENSOR_TYPE_GYROSCOPE); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| if (type & SENSOR_TYPE_GRAVITY) { |
| /* Get vector data, accel or gravity values */ |
| rc = bno055_get_vector_data(itf, &databuf.sgrd, SENSOR_TYPE_GRAVITY); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &databuf.sgrd, SENSOR_TYPE_GRAVITY); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Gets system status, test results and errors if any from the sensor |
| * |
| * @param The sensor interface |
| * @param ptr to system status |
| * @param ptr to self test result |
| * @param ptr to system error |
| */ |
| int |
| bno055_get_sys_status(struct sensor_itf *itf, uint8_t *system_status, |
| uint8_t *self_test_result, uint8_t *system_error) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_PAGE_ID_ADDR, 0); |
| if (rc) { |
| goto err; |
| } |
| /** |
| * System Status (see section 4.3.58) |
| * --------------------------------- |
| * bit 0: Idle |
| * bit 1: System Error |
| * bit 2: Initializing Peripherals |
| * bit 3: System Iniitalization |
| * bit 4: Executing Self-Test |
| * bit 5: Sensor fusion algorithm running |
| * bit 6: System running without fusion algorithms |
| */ |
| |
| if (system_status != 0) { |
| rc = bno055_read8(itf, BNO055_SYS_STAT_ADDR, system_status); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| /** |
| * Self Test Results (see section ) |
| * -------------------------------- |
| * 1: test passed, 0: test failed |
| * bit 0: Accelerometer self test |
| * bit 1: Magnetometer self test |
| * bit 2: Gyroscope self test |
| * bit 3: MCU self test |
| * |
| * 0x0F : All Good |
| */ |
| |
| if (self_test_result != 0) { |
| rc = bno055_read8(itf, BNO055_SELFTEST_RESULT_ADDR, self_test_result); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| /** |
| * System Error (see section 4.3.59) |
| * --------------------------------- |
| * bit 0 : No error |
| * bit 1 : Peripheral initialization error |
| * bit 2 : System initialization error |
| * bit 3 : Self test result failed |
| * bit 4 : Register map value out of range |
| * bit 5 : Register map address out of range |
| * bit 6 : Register map write error |
| * bit 7 : BNO low power mode not available for selected operat ion mode |
| * bit 8 : Accelerometer power mode not available |
| * bit 9 : Fusion algorithm configuration error |
| * bit 10 : Sensor configuration error |
| */ |
| |
| if (system_error != 0) { |
| rc = bno055_read8(itf, BNO055_SYS_ERR_ADDR, system_error); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 200)/1000 + 1); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get Revision info for different sensors in the bno055 |
| * |
| * @param The sensor interface |
| * @param pass the pointer to the revision structure |
| * @return 0 on success, non-zero on error |
| */ |
| int |
| bno055_get_rev_info(struct sensor_itf *itf, struct bno055_rev_info *ri) |
| { |
| uint8_t sw_rev_l, sw_rev_h; |
| int rc; |
| |
| memset(ri, 0, sizeof(struct bno055_rev_info)); |
| |
| /* Check the accelerometer revision */ |
| rc = bno055_read8(itf, BNO055_ACCEL_REV_ID_ADDR, &(ri->bri_accel_rev)); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Check the magnetometer revision */ |
| rc = bno055_read8(itf, BNO055_MAG_REV_ID_ADDR, &(ri->bri_mag_rev)); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Check the gyroscope revision */ |
| rc = bno055_read8(itf, BNO055_GYRO_REV_ID_ADDR, &(ri->bri_gyro_rev)); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_read8(itf, BNO055_BL_REV_ID_ADDR, &(ri->bri_bl_rev)); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Check the SW revision */ |
| rc = bno055_read8(itf, BNO055_SW_REV_ID_LSB_ADDR, &sw_rev_l); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_read8(itf, BNO055_SW_REV_ID_MSB_ADDR, &sw_rev_h); |
| if (rc) { |
| goto err; |
| } |
| |
| ri->bri_sw_rev = (((uint16_t)sw_rev_h) << 8) | ((uint16_t)sw_rev_l); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Gets current calibration status |
| * |
| * @param The sensor interface |
| * @param Calibration info structure to fill up calib state |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_calib_status(struct sensor_itf *itf, struct bno055_calib_info *bci) |
| { |
| uint8_t status; |
| int rc; |
| |
| rc = bno055_read8(itf, BNO055_CALIB_STAT_ADDR, &status); |
| if (rc) { |
| goto err; |
| } |
| |
| bci->bci_sys = (status >> 6) & 0x03; |
| bci->bci_gyro = (status >> 4) & 0x03; |
| bci->bci_accel = (status >> 2) & 0x03; |
| bci->bci_mag = status & 0x03; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Checks if bno055 is fully calibrated |
| * |
| * @param The sensor interface |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_is_calib(struct sensor_itf *itf) |
| { |
| struct bno055_calib_info bci; |
| int rc; |
| |
| rc = bno055_get_calib_status(itf, &bci); |
| if (rc) { |
| goto err; |
| } |
| |
| if (bci.bci_sys< 3 || bci.bci_gyro < 3 || bci.bci_accel < 3 || bci.bci_mag < 3) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Reads the sensor's offset registers into a byte array |
| * |
| * @param The sensor interface |
| * @param byte array to return offsets into |
| * @return 0 on success, non-zero on failure |
| * |
| */ |
| int |
| bno055_get_raw_sensor_offsets(struct sensor_itf *itf, uint8_t *offsets) |
| { |
| uint8_t prev_mode; |
| int rc; |
| |
| rc = SYS_EOK; |
| if (!bno055_is_calib(itf)) { |
| rc = bno055_get_opr_mode(itf, &prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_set_opr_mode(itf, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_readlen(itf, BNO055_ACCEL_OFFSET_X_LSB_ADDR, offsets, |
| BNO055_NUM_OFFSET_REGISTERS); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_set_opr_mode(itf, prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| } |
| err: |
| return rc; |
| } |
| |
| /** |
| * |
| * Reads the sensor's offset registers into an offset struct |
| * |
| * @param The sensor interface |
| * @param structure to fill up offsets data |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_sensor_offsets(struct sensor_itf *itf, |
| struct bno055_sensor_offsets *offsets) |
| { |
| uint8_t payload[22]; |
| int rc; |
| |
| |
| rc = bno055_get_raw_sensor_offsets(itf, payload); |
| if (rc) { |
| goto err; |
| } |
| |
| offsets->bso_acc_off_x = (payload[1] << 8) | payload[0]; |
| offsets->bso_acc_off_y = (payload[3] << 8) | payload[2]; |
| offsets->bso_acc_off_z = (payload[5] << 8) | payload[4]; |
| |
| offsets->bso_gyro_off_x = (payload[7] << 8) | payload[6]; |
| offsets->bso_gyro_off_y = (payload[9] << 8) | payload[8]; |
| offsets->bso_gyro_off_z = (payload[11] << 8) | payload[10]; |
| |
| offsets->bso_mag_off_x = (payload[13] << 8) | payload[12]; |
| offsets->bso_mag_off_y = (payload[15] << 8) | payload[14]; |
| offsets->bso_mag_off_z = (payload[17] << 8) | payload[16]; |
| |
| offsets->bso_acc_radius = (payload[19] << 8) | payload[18]; |
| offsets->bso_mag_radius = (payload[21] << 8) | payload[20]; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| |
| /** |
| * |
| * Writes calibration data to the sensor's offset registers |
| * |
| * @param The sensor interface |
| * @param calibration data |
| * @param calibration data length |
| * @return 0 on success, non-zero on success |
| */ |
| int |
| bno055_set_sensor_raw_offsets(struct sensor_itf *itf, uint8_t* calibdata, |
| uint8_t len) |
| { |
| uint8_t prev_mode; |
| int rc; |
| |
| if (len != 22) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = bno055_get_opr_mode(itf, &prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_set_opr_mode(itf, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((25 * OS_TICKS_PER_SEC)/1000 + 1); |
| |
| rc = bno055_writelen(itf, BNO055_ACCEL_OFFSET_X_LSB_ADDR, calibdata, len); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_set_opr_mode(itf, prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * |
| * Writes to the sensor's offset registers from an offset struct |
| * |
| * @param The sensor interface |
| * @param pointer to the offset structure |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_sensor_offsets(struct sensor_itf *itf, |
| struct bno055_sensor_offsets *offsets) |
| { |
| uint8_t prev_mode; |
| int rc; |
| |
| rc = bno055_get_opr_mode(itf, &prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bno055_set_opr_mode(itf, BNO055_OPR_MODE_CONFIG); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((25 * OS_TICKS_PER_SEC)/1000 + 1); |
| |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_X_LSB_ADDR, (offsets->bso_acc_off_x) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_X_MSB_ADDR, (offsets->bso_acc_off_x >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_Y_LSB_ADDR, (offsets->bso_acc_off_y) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_Y_MSB_ADDR, (offsets->bso_acc_off_y >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_Z_LSB_ADDR, (offsets->bso_acc_off_z) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_OFFSET_Z_MSB_ADDR, (offsets->bso_acc_off_z >> 8) & 0x0FF); |
| |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_X_LSB_ADDR, (offsets->bso_gyro_off_x) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_X_MSB_ADDR, (offsets->bso_gyro_off_x >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_Y_LSB_ADDR, (offsets->bso_gyro_off_y) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_Y_MSB_ADDR, (offsets->bso_gyro_off_y >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_Z_LSB_ADDR, (offsets->bso_gyro_off_z) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_GYRO_OFFSET_Z_MSB_ADDR, (offsets->bso_gyro_off_z >> 8) & 0x0FF); |
| |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_X_LSB_ADDR, (offsets->bso_mag_off_x) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_X_MSB_ADDR, (offsets->bso_mag_off_x >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_Y_LSB_ADDR, (offsets->bso_mag_off_y) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_Y_MSB_ADDR, (offsets->bso_mag_off_y >> 8) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_Z_LSB_ADDR, (offsets->bso_mag_off_z) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_OFFSET_Z_MSB_ADDR, (offsets->bso_mag_off_z >> 8) & 0x0FF); |
| |
| rc |= bno055_write8(itf, BNO055_ACCEL_RADIUS_LSB_ADDR, (offsets->bso_acc_radius) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_ACCEL_RADIUS_MSB_ADDR, (offsets->bso_acc_radius >> 8) & 0x0FF); |
| |
| rc |= bno055_write8(itf, BNO055_MAG_RADIUS_LSB_ADDR, (offsets->bso_mag_radius) & 0x0FF); |
| rc |= bno055_write8(itf, BNO055_MAG_RADIUS_MSB_ADDR, (offsets->bso_mag_radius >> 8) & 0x0FF); |
| |
| rc |= bno055_set_opr_mode(itf, prev_mode); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get threshold for interrupts |
| * |
| * @param The sensor interface |
| * @param ptr to threshold |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_int_thresh(struct sensor_itf *itf, uint32_t intr, uint8_t *thresh) |
| { |
| int rc; |
| uint8_t val; |
| uint8_t mask; |
| uint8_t reg; |
| |
| mask = 0; |
| switch(intr) { |
| case BNO055_INT_ACC_HG: |
| reg = BNO055_ACCEL_HIGH_G_THRES_ADDR; |
| break; |
| case BNO055_INT_ACC_SM: |
| case BNO055_INT_ACC_NM: |
| reg = BNO055_ACCEL_NO_MOTION_THRES_ADDR; |
| break; |
| case BNO055_INT_ACC_AM: |
| reg = BNO055_ACCEL_ANY_MOTION_THRES_ADDR; |
| break; |
| case BNO055_INT_GYR_AM: |
| reg = BNO055_GYRO_ANY_MOTION_THRES_ADDR; |
| mask = 0x3F; |
| break; |
| case BNO055_INT_GYR_HR_X_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_X_SET_ADDR; |
| mask = 0x1F; |
| break; |
| case BNO055_INT_GYR_HR_Y_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_Y_SET_ADDR; |
| mask = 0x1F; |
| break; |
| case BNO055_INT_GYR_HR_Z_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_Z_SET_ADDR; |
| mask = 0x1F; |
| break; |
| default: |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *thresh = val | mask; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set threshold for interrupts |
| * |
| * @param The sensor interface |
| * @param threshold |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_int_thresh(struct sensor_itf *itf, uint32_t intr, uint8_t thresh) |
| { |
| int rc; |
| uint8_t mask; |
| uint8_t val; |
| uint8_t reg; |
| |
| mask = val = 0; |
| switch(intr) { |
| case BNO055_INT_ACC_HG: |
| reg = BNO055_ACCEL_HIGH_G_THRES_ADDR; |
| break; |
| case BNO055_INT_ACC_SM: |
| case BNO055_INT_ACC_NM: |
| reg = BNO055_ACCEL_NO_MOTION_THRES_ADDR; |
| break; |
| case BNO055_INT_ACC_AM: |
| reg = BNO055_ACCEL_ANY_MOTION_THRES_ADDR; |
| break; |
| case BNO055_INT_GYR_AM: |
| reg = BNO055_GYRO_ANY_MOTION_THRES_ADDR; |
| mask = 0x3F; |
| break; |
| case BNO055_INT_GYR_HR_X_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_X_SET_ADDR; |
| mask = 0x1F; |
| break; |
| case BNO055_INT_GYR_HR_Y_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_Y_SET_ADDR; |
| mask = 0x1F; |
| break; |
| case BNO055_INT_GYR_HR_Z_AXIS: |
| reg = BNO055_GYRO_HIGHRATE_Z_SET_ADDR; |
| mask = 0x1F; |
| break; |
| default: |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| if (mask && thresh > mask) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| if (mask) { |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| thresh = thresh | val; |
| |
| rc = bno055_write8(itf, reg, thresh); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get interrupt trigger delay |
| * |
| * @param The sensor interface |
| * @param ptr to duration |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_int_duration(struct sensor_itf *itf, uint32_t intr, uint8_t *duration) |
| { |
| int rc; |
| uint8_t val; |
| uint8_t mask; |
| uint8_t shift; |
| uint8_t reg; |
| |
| mask = val = shift = 0; |
| switch(intr) { |
| case BNO055_INT_GYR_HR_X_AXIS: |
| reg = BNO055_GYRO_DURN_X_ADDR; |
| break; |
| case BNO055_INT_GYR_HR_Y_AXIS: |
| reg = BNO055_GYRO_DURN_Y_ADDR; |
| break; |
| case BNO055_INT_GYR_HR_Z_AXIS: |
| reg = BNO055_GYRO_DURN_Z_ADDR; |
| break; |
| case BNO055_INT_ACC_HG: |
| reg = BNO055_ACCEL_HIGH_G_DURN_ADDR; |
| break; |
| case BNO055_INT_ACC_NM: |
| reg = BNO055_ACCEL_NO_MOTION_SET_ADDR; |
| mask = 0x3F; |
| shift = 1; |
| break; |
| case BNO055_INT_ACC_AM: |
| reg = BNO055_ACCEL_INTR_SETTINGS_ADDR; |
| mask = 0x3; |
| break; |
| case BNO055_INT_GYR_AM: |
| reg = BNO055_GYRO_INTR_SETTINGS_ADDR; |
| mask = 0xc; |
| shift = 2; |
| break; |
| default: |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *duration = val | mask; |
| |
| if (shift) { |
| *duration >>= shift; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set interrupt trigger delay |
| * |
| * @param The sensor interface |
| * @param ptr to duration |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_int_duration(struct sensor_itf *itf, uint32_t intr, uint8_t duration) |
| { |
| int rc; |
| uint8_t val; |
| uint8_t mask; |
| uint8_t shift; |
| uint8_t reg; |
| |
| val = mask = shift = 0; |
| switch(intr) { |
| case BNO055_INT_GYR_HR_X_AXIS: |
| reg = BNO055_GYRO_DURN_X_ADDR; |
| break; |
| case BNO055_INT_GYR_HR_Y_AXIS: |
| reg = BNO055_GYRO_DURN_Y_ADDR; |
| break; |
| case BNO055_INT_GYR_HR_Z_AXIS: |
| reg = BNO055_GYRO_DURN_Z_ADDR; |
| break; |
| case BNO055_INT_ACC_HG: |
| reg = BNO055_ACCEL_HIGH_G_DURN_ADDR; |
| break; |
| case BNO055_INT_ACC_NM: |
| reg = BNO055_ACCEL_NO_MOTION_SET_ADDR; |
| mask = 0x3F; |
| shift = 1; |
| break; |
| case BNO055_INT_ACC_AM: |
| reg = BNO055_ACCEL_INTR_SETTINGS_ADDR; |
| mask = 0x3; |
| break; |
| case BNO055_INT_GYR_AM: |
| reg = BNO055_GYRO_INTR_SETTINGS_ADDR; |
| mask = 0x3; |
| shift = 2; |
| break; |
| default: |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| if (mask && duration > mask) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| if (shift) { |
| duration <<= shift; |
| } |
| |
| if (mask) { |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| val |= duration; |
| |
| rc = bno055_write8(itf, reg, duration); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Enable axis interrupt, |
| * |
| * @param The sensor interface |
| * @param interrupt axis |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_enable_int_axis(struct sensor_itf *itf, uint32_t intr_axis, uint8_t enable) |
| { |
| int rc; |
| uint8_t reg; |
| uint8_t val; |
| uint8_t intr; |
| |
| intr = 0; |
| if (intr_axis & BNO055_INT_ACC_AM || intr_axis & BNO055_INT_ACC_NM) { |
| reg = BNO055_ACCEL_INTR_SETTINGS_ADDR; |
| intr = (intr_axis >> BNO055_INT_ACC_AM_POS) & 0xFF; |
| } |
| |
| if (intr_axis & BNO055_INT_ACC_HG) { |
| reg = BNO055_ACCEL_INTR_SETTINGS_ADDR; |
| intr = (intr_axis >> BNO055_INT_ACC_HG_POS) & 0xFF; |
| } |
| |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| intr = enable ? intr | val : intr & val; |
| |
| rc = bno055_write8(itf, reg, intr); |
| if (rc) { |
| goto err; |
| } |
| |
| if (intr_axis & BNO055_INT_GYR_AM) { |
| reg = BNO055_GYRO_INTR_SETTINGS_ADDR; |
| intr = (intr_axis >> BNO055_INT_GYR_AM_POS) & 0xFF; |
| } |
| |
| if (intr_axis & BNO055_INT_GYR_HR) { |
| reg = BNO055_GYRO_INTR_SETTINGS_ADDR; |
| intr = (intr_axis >> BNO055_INT_GYR_HR_POS) & 0xFF; |
| } |
| |
| rc = bno055_read8(itf, reg, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| intr = enable ? intr | val : intr & val; |
| |
| rc = bno055_write8(itf, reg, intr); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get acc int settings |
| * |
| * @param The sensor interface |
| * @param ptr to int settings |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_acc_int_settings(struct sensor_itf *itf, uint8_t *settings) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_ACCEL_INTR_SETTINGS_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *settings = val; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set acc int settings |
| * |
| * @param The sensor interface |
| * @param int settings |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_acc_int_settings(struct sensor_itf *itf, uint8_t settings) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_ACCEL_INTR_SETTINGS_ADDR, settings); |
| if (rc) { |
| goto err; |
| } |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get enabled/disabled interrupts |
| * |
| * @param The sensor interface |
| * @param ptr to interrupt mask |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_int_enable(struct sensor_itf *itf, uint8_t *intr) |
| { |
| int rc; |
| uint8_t val; |
| uint8_t mask; |
| |
| rc = bno055_read8(itf, BNO055_INT_EN_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| mask = (val & BNO055_INT_EN_ACC_AM ? BNO055_INT_ACC_AM : 0); |
| mask |= (val & BNO055_INT_EN_ACC_HG ? BNO055_INT_ACC_HG : 0); |
| mask |= (val & BNO055_INT_EN_GYR_HR ? BNO055_INT_GYR_HR : 0); |
| mask |= (val & BNO055_INT_EN_GYR_AM ? BNO055_INT_GYR_AM : 0); |
| |
| if (val & BNO055_INT_EN_ACC_NM) { |
| val = 0; |
| rc = bno055_read8(itf, BNO055_ACCEL_NO_MOTION_SET_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| mask |= (val & BNO055_ACCEL_SMNM ? BNO055_INT_ACC_SM : BNO055_INT_ACC_NM); |
| } |
| |
| *intr = mask; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Enable/Disable interrupts |
| * |
| * @param The sensor interface |
| * @param Interrupt mask |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_int_enable(struct sensor_itf *itf, uint8_t intr, uint8_t enable) |
| { |
| int rc; |
| uint8_t mask; |
| uint8_t smnm; |
| uint8_t val; |
| |
| mask = (intr & BNO055_INT_ACC_AM ? BNO055_INT_EN_ACC_AM : 0); |
| mask |= (intr & BNO055_INT_ACC_HG ? BNO055_INT_EN_ACC_HG : 0); |
| mask |= (intr & BNO055_INT_GYR_HR ? BNO055_INT_EN_GYR_HR : 0); |
| mask |= (intr & BNO055_INT_GYR_AM ? BNO055_INT_EN_GYR_AM : 0); |
| |
| /* Both of them can't be set */ |
| if (intr & BNO055_INT_ACC_NM && intr & BNO055_INT_ACC_SM) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| smnm = 0; |
| if (intr & BNO055_INT_ACC_SM) { |
| smnm = 0xF0 | BNO055_ACCEL_SMNM; |
| mask |= BNO055_INT_EN_ACC_NM; |
| } else if (intr & BNO055_INT_ACC_NM) { |
| smnm = 0xF0; |
| mask |= BNO055_INT_EN_ACC_NM; |
| } |
| |
| if (smnm) { |
| smnm &= 0x0F; |
| rc = bno055_read8(itf, BNO055_ACCEL_NO_MOTION_SET_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| val |= smnm; |
| rc = bno055_write8(itf, BNO055_ACCEL_NO_MOTION_SET_ADDR, val); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| val = 0; |
| rc = bno055_read8(itf, BNO055_INT_EN_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| if (enable) { |
| val |= mask; |
| } else { |
| val &= ~mask; |
| } |
| |
| rc = bno055_write8(itf, BNO055_INT_EN_ADDR, val); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get interrupt status |
| * |
| * @param The sensor interface |
| * @param ptr to interrupt status to fill up |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_int_status(struct sensor_itf *itf, uint8_t *int_mask) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_INTR_STAT_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *int_mask = val; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set interrupt mask |
| * |
| * @param The sensor interface |
| * @param Interrupt mask |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_set_int_mask(struct sensor_itf *itf, uint8_t int_mask) |
| { |
| int rc; |
| |
| rc = bno055_write8(itf, BNO055_INT_MASK_ADDR, int_mask); |
| if (rc) { |
| goto err; |
| } |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get interrupt mask |
| * |
| * @param The sensor interface |
| * @param ptr to interrupt mask |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| bno055_get_int_mask(struct sensor_itf *itf, uint8_t *int_mask) |
| { |
| int rc; |
| uint8_t val; |
| |
| rc = bno055_read8(itf, BNO055_INT_MASK_ADDR, &val); |
| if (rc) { |
| goto err; |
| } |
| |
| *int_mask = val; |
| err: |
| return rc; |
| } |
| |
| static int |
| bno055_sensor_get_config(struct sensor *sensor, sensor_type_t type, |
| struct sensor_cfg *cfg) |
| { |
| int rc; |
| |
| if ((type != SENSOR_TYPE_ACCELEROMETER) && |
| (type != SENSOR_TYPE_MAGNETIC_FIELD) && |
| (type != SENSOR_TYPE_TEMPERATURE) && |
| (type != SENSOR_TYPE_ROTATION_VECTOR) && |
| (type != SENSOR_TYPE_LINEAR_ACCEL) && |
| (type != SENSOR_TYPE_GRAVITY) && |
| (type != SENSOR_TYPE_EULER)) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| if (type != SENSOR_TYPE_TEMPERATURE) { |
| cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT_TRIPLET; |
| } else { |
| cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |