blob: f7ed245db73bc12d0a99357ae8a0c362c2004a81 [file] [log] [blame]
/*
* 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, &reg);
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;
}