AP_Compass: HMC5843: be agnostic to I2C bus

Like was done to inertial AK8963 and inertial sensor move the decision
regarding the I2C bus to the caller. We don't allow changing the address
because apparently HMC5843 doesn't support different addresses.

Changing only the bus could be more easily done but this prepares the
ground for using HMC5843 on an AuxiliarBus.

The need for a more generic abstraction is evidenced by this commit: a
"SerialBus" in AP_HAL would be a nice addition rather than letting each
driver to provide its own. However the methods are a little bit
different from what we have in AK8963. It's safer to do the simple
conversion now and later on to add the abstraction changing everybody to
use it.
This commit is contained in:
Lucas De Marchi 2015-08-07 19:54:58 -03:00 committed by Andrew Tridgell
parent 3eb6be64c9
commit c66c9c41f2
3 changed files with 111 additions and 29 deletions

View File

@ -31,7 +31,7 @@
extern const AP_HAL::HAL& hal;
#define COMPASS_ADDRESS 0x1E
#define HMC5843_I2C_ADDR 0x1E
#define ConfigRegA 0x00
#define ConfigRegB 0x01
#define magGain 0x20
@ -58,10 +58,10 @@ extern const AP_HAL::HAL& hal;
#define DataOutputRate_75HZ 0x06
// constructor
AP_Compass_HMC5843::AP_Compass_HMC5843(Compass &compass):
AP_Compass_HMC5843::AP_Compass_HMC5843(Compass &compass, AP_HMC5843_SerialBus *bus) :
AP_Compass_Backend(compass),
_bus(bus),
_retry_time(0),
_i2c_sem(NULL),
_mag_x(0),
_mag_y(0),
_mag_z(0),
@ -74,24 +74,41 @@ AP_Compass_HMC5843::AP_Compass_HMC5843(Compass &compass):
_product_id(0)
{}
// detect the sensor
AP_Compass_Backend *AP_Compass_HMC5843::detect(Compass &compass)
AP_Compass_HMC5843::~AP_Compass_HMC5843()
{
AP_Compass_HMC5843 *sensor = new AP_Compass_HMC5843(compass);
if (sensor == NULL) {
return NULL;
delete _bus;
}
// detect the sensor
AP_Compass_Backend *AP_Compass_HMC5843::detect_i2c(Compass &compass,
AP_HAL::I2CDriver *i2c)
{
AP_HMC5843_SerialBus *bus = new AP_HMC5843_SerialBus_I2C(i2c, HMC5843_I2C_ADDR);
if (!bus)
return nullptr;
return _detect(compass, bus);
}
AP_Compass_Backend *AP_Compass_HMC5843::_detect(Compass &compass,
AP_HMC5843_SerialBus *bus)
{
AP_Compass_HMC5843 *sensor = new AP_Compass_HMC5843(compass, bus);
if (!sensor) {
delete bus;
return nullptr;
}
if (!sensor->init()) {
delete sensor;
return NULL;
return nullptr;
}
return sensor;
}
// read_register - read a register value
bool AP_Compass_HMC5843::read_register(uint8_t address, uint8_t *value)
{
if (hal.i2c->readRegister((uint8_t)COMPASS_ADDRESS, address, value) != 0) {
if (_bus->register_read(address, value) != 0) {
_retry_time = hal.scheduler->millis() + 1000;
return false;
}
@ -101,7 +118,7 @@ bool AP_Compass_HMC5843::read_register(uint8_t address, uint8_t *value)
// write_register - update a register value
bool AP_Compass_HMC5843::write_register(uint8_t address, uint8_t value)
{
if (hal.i2c->writeRegister((uint8_t)COMPASS_ADDRESS, address, value) != 0) {
if (_bus->register_write(address, value) != 0) {
_retry_time = hal.scheduler->millis() + 1000;
return false;
}
@ -113,8 +130,8 @@ bool AP_Compass_HMC5843::read_raw()
{
uint8_t buff[6];
if (hal.i2c->readRegisters(COMPASS_ADDRESS, 0x03, 6, buff) != 0) {
hal.i2c->setHighSpeed(false);
if (_bus->register_read(0x03, buff, 6) != 0) {
_bus->set_high_speed(false);
_retry_time = hal.scheduler->millis() + 1000;
return false;
}
@ -156,12 +173,12 @@ void AP_Compass_HMC5843::accumulate(void)
return;
}
if (!_i2c_sem->take(1)) {
if (!_bus_sem->take(1)) {
// the bus is busy - try again later
return;
}
bool result = read_raw();
_i2c_sem->give();
_bus_sem->give();
if (result) {
// the _mag_N values are in the range -2048 to 2047, so we can
@ -230,8 +247,8 @@ AP_Compass_HMC5843::init()
hal.scheduler->suspend_timer_procs();
hal.scheduler->delay(10);
_i2c_sem = hal.i2c->get_semaphore();
if (!_i2c_sem->take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
_bus_sem = _bus->get_semaphore();
if (!_bus_sem->take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
hal.scheduler->panic(PSTR("Failed to get HMC5843 semaphore"));
}
@ -261,7 +278,7 @@ AP_Compass_HMC5843::init()
}
_initialised = true;
_i2c_sem->give();
_bus_sem->give();
hal.scheduler->resume_timer_procs();
// perform an initial read
@ -278,7 +295,7 @@ AP_Compass_HMC5843::init()
return true;
errout:
_i2c_sem->give();
_bus_sem->give();
hal.scheduler->resume_timer_procs();
return false;
}
@ -395,7 +412,7 @@ void AP_Compass_HMC5843::read()
}
if (!re_initialise()) {
_retry_time = hal.scheduler->millis() + 1000;
hal.i2c->setHighSpeed(false);
_bus->set_high_speed(false);
return;
}
}
@ -403,7 +420,7 @@ void AP_Compass_HMC5843::read()
if (_accum_count == 0) {
accumulate();
if (_retry_time != 0) {
hal.i2c->setHighSpeed(false);
_bus->set_high_speed(false);
return;
}
}
@ -424,3 +441,29 @@ void AP_Compass_HMC5843::read()
publish_field(field, _compass_instance);
_retry_time = 0;
}
AP_HMC5843_SerialBus_I2C::AP_HMC5843_SerialBus_I2C(AP_HAL::I2CDriver *i2c, uint8_t addr)
: _i2c(i2c)
, _addr(addr)
{
}
void AP_HMC5843_SerialBus_I2C::set_high_speed(bool val)
{
_i2c->setHighSpeed(val);
}
uint8_t AP_HMC5843_SerialBus_I2C::register_read(uint8_t reg, uint8_t *buf, uint8_t size)
{
return _i2c->readRegisters(_addr, reg, size, buf);
}
uint8_t AP_HMC5843_SerialBus_I2C::register_write(uint8_t reg, uint8_t val)
{
return _i2c->writeRegister(_addr, reg, val);
}
AP_HAL::Semaphore* AP_HMC5843_SerialBus_I2C::get_semaphore()
{
return _i2c->get_semaphore();
}

View File

@ -9,9 +9,17 @@
#include "Compass.h"
#include "AP_Compass_Backend.h"
class AP_HMC5843_SerialBus;
class AP_Compass_HMC5843 : public AP_Compass_Backend
{
private:
static AP_Compass_Backend *_detect(Compass &compass,
AP_HMC5843_SerialBus *bus);
AP_HMC5843_SerialBus *_bus;
AP_HAL::Semaphore *_bus_sem = nullptr;
float _scaling[3] = {0};
bool _initialised;
bool read_raw(void);
@ -24,7 +32,6 @@ private:
bool _detect_version();
uint32_t _retry_time; // when unhealthy the millis() value to retry at
AP_HAL::Semaphore* _i2c_sem;
int16_t _mag_x;
int16_t _mag_y;
@ -39,13 +46,45 @@ private:
uint8_t _product_id;
public:
AP_Compass_HMC5843(Compass &compass);
// detect the sensor
static AP_Compass_Backend *detect_i2c(Compass &compass,
AP_HAL::I2CDriver *i2c);
AP_Compass_HMC5843(Compass &compass, AP_HMC5843_SerialBus *bus);
~AP_Compass_HMC5843();
bool init(void);
void read(void);
void accumulate(void);
// detect the sensor
static AP_Compass_Backend *detect(Compass &compass);
};
class AP_HMC5843_SerialBus
{
public:
virtual ~AP_HMC5843_SerialBus() { };
virtual void set_high_speed(bool val) = 0;
virtual uint8_t register_read(uint8_t reg, uint8_t *buf, uint8_t size) = 0;
uint8_t register_read(uint8_t reg, uint8_t *val)
{
return register_read(reg, val, 1);
}
virtual uint8_t register_write(uint8_t reg, uint8_t val) = 0;
virtual AP_HAL::Semaphore* get_semaphore() = 0;
};
class AP_HMC5843_SerialBus_I2C : public AP_HMC5843_SerialBus
{
public:
AP_HMC5843_SerialBus_I2C(AP_HAL::I2CDriver *i2c, uint8_t addr);
void set_high_speed(bool val) override;
uint8_t register_read(uint8_t reg, uint8_t *buf, uint8_t size) override;
uint8_t register_write(uint8_t reg, uint8_t val) override;
AP_HAL::Semaphore* get_semaphore() override;
private:
AP_HAL::I2CDriver *_i2c;
uint8_t _addr;
};
#endif

View File

@ -341,12 +341,12 @@ void Compass::_detect_backends(void)
}
#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX && CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_NONE && CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_BEBOP
_add_backend(AP_Compass_HMC5843::detect(*this));
_add_backend(AP_Compass_HMC5843::detect_i2c(*this, hal.i2c));
_add_backend(AP_Compass_AK8963::detect_mpu9250(*this));
#elif HAL_COMPASS_DEFAULT == HAL_COMPASS_HIL
_add_backend(AP_Compass_HIL::detect(*this));
#elif HAL_COMPASS_DEFAULT == HAL_COMPASS_HMC5843
_add_backend(AP_Compass_HMC5843::detect(*this));
_add_backend(AP_Compass_HMC5843::detect_i2c(*this, hal.i2c));
#elif HAL_COMPASS_DEFAULT == HAL_COMPASS_AK8963_I2C && HAL_INS_AK8963_I2C_BUS == 1
_add_backend(AP_Compass_AK8963::detect_i2c(*this, hal.i2c1,
HAL_COMPASS_AK8963_I2C_ADDR));