bmpx8x: rewrite in C; FTI; C++ wraps C

This driver has been rewritten from scratch.

See docs/apichanges.md for a list of API compatibility changes
compared to the original driver.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
Jon Trulson
2017-04-04 17:48:41 -06:00
parent 8d43c431f2
commit c57a0d2c30
17 changed files with 1346 additions and 424 deletions

View File

@ -1,5 +1,10 @@
set (libname "bmpx8x")
set (libdescription "Bosch BMP & GY65 Atmospheric Pressure Sensor Library")
set (module_src ${libname}.cxx)
set (module_hpp ${libname}.hpp)
upm_module_init(mraa interfaces)
upm_mixed_module_init (NAME bmpx8x
DESCRIPTION "Pressure and temperature sensor"
C_HDR bmpx8x.h bmpx8x_defs.h
C_SRC bmpx8x.c
CPP_HDR bmpx8x.hpp
CPP_SRC bmpx8x.cxx
FTI_SRC bmpx8x_fti.c
CPP_WRAPS_C
REQUIRES mraa interfaces)
target_link_libraries(${libnamec} m)

360
src/bmpx8x/bmpx8x.c Normal file
View File

@ -0,0 +1,360 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <assert.h>
#include "upm_utilities.h"
#include "upm_math.h"
#include "bmpx8x.h"
// UT is uncompensated temperature
static int32_t _bmpx8x_computeB5(const bmpx8x_context dev, int32_t UT)
{
assert(dev != NULL);
int32_t X1 = (UT - (int32_t)dev->ac6) * ((int32_t)dev->ac5) >> 15;
int32_t X2 = ((int32_t)dev->mc << 11) / (X1+(int32_t)dev->md);
return X1 + X2;
}
static upm_result_t _bmpx8x_read_calibration_data(const bmpx8x_context dev)
{
assert(dev != NULL);
const int dataLen = 22;
uint8_t calData[dataLen];
if (bmpx8x_read_regs(dev, BMPX8X_CAL_AC1, calData, dataLen) != dataLen)
return UPM_ERROR_OPERATION_FAILED;
dev->ac1 = (int16_t)( (calData[0] << 8) | calData[1] );
dev->ac2 = (int16_t)( (calData[2] << 8) | calData[3] );
dev->ac3 = (int16_t)( (calData[4] << 8) | calData[5] );
dev->ac4 = (uint16_t)( (calData[6] << 8) | calData[7] );
dev->ac5 = (uint16_t)( (calData[8] << 8) | calData[9] );
dev->ac6 = (uint16_t)( (calData[10] << 8) | calData[11] );
dev->b1 = (int16_t)( (calData[12] << 8) | calData[13] );
dev->b2 = (int16_t)( (calData[14] << 8) | calData[15] );
dev->mb = (int16_t)( (calData[16] << 8) | calData[17] );
dev->mc = (int16_t)( (calData[18] << 8) | calData[19] );
dev->md = (int16_t)( (calData[20] << 8) | calData[21] );
return UPM_SUCCESS;
}
// init
bmpx8x_context bmpx8x_init(int bus, int addr)
{
bmpx8x_context dev =
(bmpx8x_context)malloc(sizeof(struct _bmpx8x_context));
if (!dev)
return NULL;
// zero out context
memset((void *)dev, 0, sizeof(struct _bmpx8x_context));
// make sure MRAA is initialized
if (mraa_init() != MRAA_SUCCESS)
{
printf("%s: mraa_init() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
if (!(dev->i2c = mraa_i2c_init(bus)))
{
printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
if (mraa_i2c_address(dev->i2c, addr))
{
printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
// check the chip id
uint8_t chipID = bmpx8x_get_chip_id(dev);
if (chipID != BMPX8X_DEFAULT_CHIPID)
{
printf("%s: invalid chip id: %02x. Expected %02x\n",
__FUNCTION__, chipID, BMPX8X_DEFAULT_CHIPID);
bmpx8x_close(dev);
return NULL;
}
// call devinit with a default ultrahigh resolution mode
if (bmpx8x_devinit(dev, BMPX8X_OSS_ULTRAHIGHRES))
{
printf("%s: bmpx8x_devinit() failed.\n", __FUNCTION__);
bmpx8x_close(dev);
return NULL;
}
return dev;
}
void bmpx8x_close(bmpx8x_context dev)
{
assert(dev != NULL);
if (dev->i2c)
mraa_i2c_stop(dev->i2c);
free(dev);
}
upm_result_t bmpx8x_devinit(const bmpx8x_context dev,
BMPX8X_OSS_T oss)
{
assert(dev != NULL);
// first read calibration data
if (_bmpx8x_read_calibration_data(dev))
{
printf("%s: _bmpx8x_read_calibration_data() failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// now set our oversampling mode
bmpx8x_set_oversampling(dev, oss);
return UPM_SUCCESS;
}
uint8_t bmpx8x_get_chip_id(const bmpx8x_context dev)
{
assert(dev != NULL);
return bmpx8x_read_reg(dev, BMPX8X_CHIP_ID);
}
upm_result_t bmpx8x_reset(const bmpx8x_context dev)
{
assert(dev != NULL);
if (bmpx8x_write_reg(dev, BMPX8X_RESET, BMPX8X_RESET_BYTE))
return UPM_ERROR_OPERATION_FAILED;
upm_delay(1);
return UPM_SUCCESS;
}
void bmpx8x_set_oversampling(const bmpx8x_context dev,
BMPX8X_OSS_T oss)
{
assert(dev != NULL);
dev->oversampling = oss;
}
upm_result_t bmpx8x_update(const bmpx8x_context dev)
{
assert(dev != NULL);
const int maxLen = 3; // maximum number of bytes we will read
uint8_t buffer[maxLen];
// first we need to read the temperature
// send the measurement command, and sleep the required time
// before reading it
if (bmpx8x_write_reg(dev, BMPX8X_CTRL_MEAS, BMPX8X_CMD_READ_TEMP))
{
printf("%s: bmpx8x_write_reg(tempcmd) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
upm_delay_ms(5);
if (bmpx8x_read_regs(dev, BMPX8X_OUTDATA_MSB, buffer, maxLen) != maxLen)
{
printf("%s: bmpx8x_read_regs(temp) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// we only need the first 2 bytes, uncompensated temperature
int32_t UT = (int32_t)( (buffer[0] << 8) | buffer[1] );
// now read in the uncompensated pressure - the delay time depends
// on the oversampling value
uint8_t reg = BMPX8X_CMD_READ_PRESSURE |
(dev->oversampling << _BMPX8X_CTRL_MEAS_OSS_SHIFT);
if (bmpx8x_write_reg(dev, BMPX8X_CTRL_MEAS, reg))
{
printf("%s: bmpx8x_write_reg(prescmd) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
switch(dev->oversampling)
{
case BMPX8X_OSS_ULTRALOWPOWER:
upm_delay_ms(5);
break;
case BMPX8X_OSS_STANDARD:
upm_delay_ms(8);
break;
case BMPX8X_OSS_HIGHRES:
upm_delay_ms(14);
break;
case BMPX8X_OSS_ULTRAHIGHRES:
upm_delay_ms(26);
break;
}
if (bmpx8x_read_regs(dev, BMPX8X_OUTDATA_MSB, buffer, maxLen) != maxLen)
{
printf("%s: bmpx8x_read_regs(pres) failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// uncompensated pressure
int32_t UP = ( (buffer[0] << 16) | (buffer[1] << 8) | buffer[2] );
UP >>= (8 - dev->oversampling);
// now, compensate and store
int32_t B3, B5, B6, X1, X2, X3, p;
uint32_t B4, B7;
// temperature
B5 = _bmpx8x_computeB5(dev, UT);
dev->temperature = (float)( (B5 + 8) >> 4 );
dev->temperature /= 10.0;
// pressure
B6 = B5 - 4000;
X1 = ((int32_t)dev->b2 * ( (B6 * B6)>>12 )) >> 11;
X2 = ((int32_t)dev->ac2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)dev->ac1*4 + X3) << dev->oversampling) + 2) / 4;
X1 = ((int32_t)dev->ac3 * B6) >> 13;
X2 = ((int32_t)dev->b1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)dev->ac4 * (uint32_t)(X3 + 32768)) >> 15;
B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> dev->oversampling );
if (B7 < 0x80000000)
p = (B7 * 2) / B4;
else
p = (B7 / B4) * 2;
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
dev->pressure = p + ((X1 + X2 + (int32_t)3791)>>4);
return UPM_SUCCESS;
}
int bmpx8x_get_pressure(const bmpx8x_context dev)
{
assert(dev != NULL);
return dev->pressure;
}
float bmpx8x_get_temperature(const bmpx8x_context dev)
{
assert(dev != NULL);
return dev->temperature;
}
int bmpx8x_get_sealevel_pressure(const bmpx8x_context dev,
float altitude)
{
assert(dev != NULL);
return ((float)dev->pressure / powf(1.0-altitude/44330.0, 5.255));
}
float bmpx8x_get_altitude(const bmpx8x_context dev, int sealevel)
{
assert(dev != NULL);
// avoid potential divide-by-0, and set the default to 101325 Pa
if (sealevel <= 0)
sealevel = 101325;
return 44307.69 * (1.0 - powf((float)dev->pressure / (float)sealevel,
0.190284));
}
uint8_t bmpx8x_read_reg(const bmpx8x_context dev, uint8_t reg)
{
assert(dev != NULL);
return (uint8_t)mraa_i2c_read_byte_data(dev->i2c, reg);
}
int bmpx8x_read_regs(const bmpx8x_context dev, uint8_t reg,
uint8_t *buffer, int len)
{
assert(dev != NULL);
if (mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len) != len)
return -1;
return len;
}
upm_result_t bmpx8x_write_reg(const bmpx8x_context dev,
uint8_t reg, uint8_t val)
{
assert(dev != NULL);
if (mraa_i2c_write_byte_data(dev->i2c, val, reg))
{
printf("%s: mraa_i2c_write_byte_data() failed.\n",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}

View File

@ -1,6 +1,11 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -31,202 +36,85 @@
#include "bmpx8x.hpp"
using namespace upm;
using namespace std;
BMPX8X::BMPX8X (int bus, int devAddr, uint8_t mode) : m_controlAddr(devAddr), m_i2ControlCtx(bus) {
m_name = "BMPX8X";
mraa::Result ret = m_i2ControlCtx.address(m_controlAddr);
if (ret != mraa::SUCCESS) {
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_i2c_address() failed");
return;
}
if (i2cReadReg_8 (0xD0) != 0x55) {
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid chip ID");
return;
}
if (mode > BMP085_ULTRAHIGHRES) {
mode = BMP085_ULTRAHIGHRES;
}
oversampling = mode;
/* read calibration data */
ac1 = i2cReadReg_16 (BMP085_CAL_AC1);
ac2 = i2cReadReg_16 (BMP085_CAL_AC2);
ac3 = i2cReadReg_16 (BMP085_CAL_AC3);
ac4 = i2cReadReg_16 (BMP085_CAL_AC4);
ac5 = i2cReadReg_16 (BMP085_CAL_AC5);
ac6 = i2cReadReg_16 (BMP085_CAL_AC6);
b1 = i2cReadReg_16 (BMP085_CAL_B1);
b2 = i2cReadReg_16 (BMP085_CAL_B2);
mb = i2cReadReg_16 (BMP085_CAL_MB);
mc = i2cReadReg_16 (BMP085_CAL_MC);
md = i2cReadReg_16 (BMP085_CAL_MD);
BMPX8X::BMPX8X (int bus, int addr) :
m_bmpx8x(bmpx8x_init(bus, addr))
{
if (!m_bmpx8x)
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_init() failed");
}
int32_t
BMPX8X::getPressure () {
int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
uint32_t B4, B7;
UT = getTemperatureRaw();
UP = getPressureRaw();
B5 = computeB5(UT);
// do pressure calcs
B6 = B5 - 4000;
X1 = ((int32_t)b2 * ( (B6 * B6)>>12 )) >> 11;
X2 = ((int32_t)ac2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)ac1*4 + X3) << oversampling) + 2) / 4;
X1 = ((int32_t)ac3 * B6) >> 13;
X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling );
if (B7 < 0x80000000) {
p = (B7 * 2) / B4
;
} else {
p = (B7 / B4) * 2;
}
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
p = p + ((X1 + X2 + (int32_t)3791)>>4);
return p;
BMPX8X::~BMPX8X()
{
bmpx8x_close(m_bmpx8x);
}
int32_t
BMPX8X::getPressureRaw () {
uint32_t raw;
i2cWriteReg (BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6));
if (oversampling == BMP085_ULTRALOWPOWER) {
usleep(5000);
} else if (oversampling == BMP085_STANDARD) {
usleep(8000);
} else if (oversampling == BMP085_HIGHRES) {
usleep(14000);
} else {
usleep(26000);
}
raw = i2cReadReg_16 (BMP085_PRESSUREDATA);
raw <<= 8;
raw |= i2cReadReg_8 (BMP085_PRESSUREDATA + 2);
raw >>= (8 - oversampling);
return raw;
void BMPX8X::init(BMPX8X_OSS_T oss)
{
if (bmpx8x_devinit(m_bmpx8x, oss))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_devinit() failed");
}
int16_t
BMPX8X::getTemperatureRaw () {
i2cWriteReg (BMP085_CONTROL, BMP085_READTEMPCMD);
usleep(5000);
return i2cReadReg_16 (BMP085_TEMPDATA);
void BMPX8X::update()
{
if (bmpx8x_update(m_bmpx8x))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_update() failed");
}
float
BMPX8X::getTemperature () {
int32_t UT, B5; // following ds convention
float temp;
UT = getTemperatureRaw ();
B5 = computeB5 (UT);
temp = (B5 + 8) >> 4;
temp /= 10;
return temp;
void BMPX8X::reset()
{
if (bmpx8x_reset(m_bmpx8x))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_reset() failed");
}
int32_t
BMPX8X::getSealevelPressure(float altitudeMeters) {
float pressure = getPressure ();
return (int32_t)(pressure / pow(1.0-altitudeMeters/44330, 5.255));
void BMPX8X::setOversampling(BMPX8X_OSS_T oss)
{
bmpx8x_set_oversampling(m_bmpx8x, oss);
}
float
BMPX8X::getAltitude (float sealevelPressure) {
float altitude;
float pressure = getPressure ();
altitude = 44330 * (1.0 - pow(pressure /sealevelPressure,0.1903));
return altitude;
uint8_t BMPX8X::readReg(uint8_t reg)
{
return bmpx8x_read_reg(m_bmpx8x, reg);
}
int BMPX8X::readRegs(uint8_t reg, uint8_t *buffer, int len)
{
int rv = bmpx8x_read_regs(m_bmpx8x, reg, buffer, len);
if (rv < 0)
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_read_regs() failed");
int
BMPX8X::getTemperatureCelsius() {
return static_cast<int>(getTemperature() + 0.5);
return rv;
}
const char*
BMPX8X::getModuleName() {
return m_name.c_str();
void BMPX8X::writeReg(uint8_t reg, uint8_t val)
{
if (bmpx8x_write_reg(m_bmpx8x, reg, val))
throw std::runtime_error(string(__FUNCTION__)
+ ": bmpx8x_write_reg() failed");
}
int32_t
BMPX8X::computeB5(int32_t UT) {
int32_t X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) >> 15;
int32_t X2 = ((int32_t)mc << 11) / (X1+(int32_t)md);
return X1 + X2;
int BMPX8X::getPressure()
{
return bmpx8x_get_pressure(m_bmpx8x);
}
mraa::Result
BMPX8X::i2cWriteReg (uint8_t reg, uint8_t value) {
mraa::Result error = mraa::SUCCESS;
uint8_t data[2] = { reg, value };
error = m_i2ControlCtx.address (m_controlAddr);
error = m_i2ControlCtx.write (data, 2);
return error;
float BMPX8X::getTemperature()
{
return bmpx8x_get_temperature(m_bmpx8x);
}
uint16_t
BMPX8X::i2cReadReg_16 (int reg) {
uint16_t data;
m_i2ControlCtx.address(m_controlAddr);
m_i2ControlCtx.writeByte(reg);
m_i2ControlCtx.address(m_controlAddr);
m_i2ControlCtx.read((uint8_t *)&data, 0x2);
uint8_t high = (data & 0xFF00) >> 8;
data = (data << 8) & 0xFF00;
data |= high;
return data;
int BMPX8X::getSealevelPressure(float altitudeMeters)
{
return bmpx8x_get_sealevel_pressure(m_bmpx8x, altitudeMeters);
}
uint8_t
BMPX8X::i2cReadReg_8 (int reg) {
uint8_t data;
m_i2ControlCtx.address(m_controlAddr);
m_i2ControlCtx.writeByte(reg);
m_i2ControlCtx.address(m_controlAddr);
m_i2ControlCtx.read(&data, 0x1);
return data;
float BMPX8X::getAltitude(int sealevelPressure)
{
return bmpx8x_get_altitude(m_bmpx8x, sealevelPressure);
}

230
src/bmpx8x/bmpx8x.h Normal file
View File

@ -0,0 +1,230 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <unistd.h>
#include <string.h>
#include <mraa/i2c.h>
#include "upm.h"
#include "bmpx8x_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file bmpx8x.h
* @library bmpx8x
* @brief C API for the bmpx8x driver
*
* @include bmpx8x.c
*/
/**
* Device context
*/
typedef struct _bmpx8x_context {
mraa_i2c_context i2c;
// our oversampling (precision)
BMPX8X_OSS_T oversampling;
// compensated temperature and pressure
float temperature;
int pressure;
// compensation coefficients
int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t mb;
int16_t mc;
int16_t md;
} *bmpx8x_context;
/**
* BMPX8X initialization.
*
* By default, the device is initialized to it's highest accuracy
* (BMP085_OSS_ULTRAHIGHRES).
*
* @param bus I2C bus number.
* @param addr I2C address of the device.
* @return Device context, or NULL if an error occurred.
*/
bmpx8x_context bmpx8x_init(int bus, int addr);
/**
* BMPX8X close function.
*
* @param dev Device context.
*/
void bmpx8x_close(bmpx8x_context dev);
/**
* Return the chip ID.
*
* @param dev The device context.
* @return The chip ID.
*/
uint8_t bmpx8x_get_chip_id(const bmpx8x_context dev);
/**
* Initialize the device, read calibration data, and start
* operation. This function is called from bmpx8x_init() so it
* will not typically need to be called by a user unless the
* device is reset. This method will call
* bmpx8x_set_oversampling() with the passed parameter.
*
* @param dev The device context.
* @param oss One of the BMPX8X_OSS_T values. The default set
* at bmpx8x_init() time is BMP085_OSS_ULTRAHIGHRES.
* @return UPM result.
*/
upm_result_t bmpx8x_devinit(const bmpx8x_context dev,
BMPX8X_OSS_T oss);
/**
* Perform a device reset. The device will be reset as if it was
* just powered on. All compensation values will be lost. You
* should call bmpx8x_devinit() afterward, or perform the same
* steps that bmpx8x_devinit() performs before attempting to use
* the device.
*
* @param dev The device context.
* @return UPM result.
*/
upm_result_t bmpx8x_reset(const bmpx8x_context dev);
/**
* Update the internal stored values from sensor data.
*
* @param dev The device context.
* @return UPM result.
*/
upm_result_t bmpx8x_update(const bmpx8x_context dev);
/**
* Set the oversampling (precision mode) of the device. Higher
* precision requires more time to complete.
*
* @param dev The device context.
* @param oss The desired oversampling mode, one of the
* BMPX8X_OSS_T values.
*/
void bmpx8x_set_oversampling(const bmpx8x_context dev,
BMPX8X_OSS_T oss);
/**
* Returns the pressure in Pascals. bmpx8x_update() must have
* been called prior to calling this function.
*
* @param dev Device context.
* @return The pressure in Pascals.
*/
int bmpx8x_get_pressure(const bmpx8x_context dev);
/**
* Returns the temperature in degrees Celsius. bmpx8x_update()
* must have been called prior to calling this function.
*
* @param dev Device context.
* @return The temperature in degrees Celsius.
*/
float bmpx8x_get_temperature(const bmpx8x_context dev);
/**
* With a given current altitude, calculate pressure at sea level.
* bmpx8x_update() must have been called prior to calling this
* function.
*
* @param dev Device context.
* @param altitude Current altitude in Meters.
* @return The pressure in Pascals at sea level.
*/
int bmpx8x_get_sealevel_pressure(const bmpx8x_context dev,
float altitude);
/**
* With a given sea level, calculate altitude in meters.
* bmpx8x_update() must have been called prior to calling this
* function.
*
* @param dev Device context.
* @param sealevel Sea level pressure in Pascals. If a negative
* number, or zero is supplied, a default sealevel of 101325 Pa
* will be used instead.
* @return The current altitude in Meters.
*/
float bmpx8x_get_altitude(const bmpx8x_context dev, int sealevel);
/**
* Read a register.
*
* @param dev The device context.
* @param reg The register to read.
* @return The value of the register.
*/
uint8_t bmpx8x_read_reg(const bmpx8x_context dev, uint8_t reg);
/**
* Read contiguous registers into a buffer.
*
* @param dev The device context.
* @param buffer The buffer to store the results.
* @param len The number of registers to read.
* @return The number of bytes read, or -1 on error.
*/
int bmpx8x_read_regs(const bmpx8x_context dev, uint8_t reg,
uint8_t *buffer, int len);
/**
* Write to a register.
*
* @param dev The device context.
* @param reg The register to write to.
* @param val The value to write.
* @return UPM result.
*/
upm_result_t bmpx8x_write_reg(const bmpx8x_context dev,
uint8_t reg, uint8_t val);
#ifdef __cplusplus
}
#endif

View File

@ -1,10 +1,11 @@
/*
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
* Contributions: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2014 Intel Corporation.
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Credits to Adafruit.
* Based on Adafruit BMP085 library.
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -28,182 +29,218 @@
#pragma once
#include <string>
#include <mraa/i2c.hpp>
#include <math.h>
#include "bmpx8x.h"
#include "interfaces/iPressureSensor.hpp"
#include "interfaces/iTemperatureSensor.hpp"
#define ADDR 0x77 // device address
// registers address
#define BMP085_ULTRALOWPOWER 0
#define BMP085_STANDARD 1
#define BMP085_HIGHRES 2
#define BMP085_ULTRAHIGHRES 3
#define BMP085_CAL_AC1 0xAA // R Calibration data (16 bits)
#define BMP085_CAL_AC2 0xAC // R Calibration data (16 bits)
#define BMP085_CAL_AC3 0xAE // R Calibration data (16 bits)
#define BMP085_CAL_AC4 0xB0 // R Calibration data (16 bits)
#define BMP085_CAL_AC5 0xB2 // R Calibration data (16 bits)
#define BMP085_CAL_AC6 0xB4 // R Calibration data (16 bits)
#define BMP085_CAL_B1 0xB6 // R Calibration data (16 bits)
#define BMP085_CAL_B2 0xB8 // R Calibration data (16 bits)
#define BMP085_CAL_MB 0xBA // R Calibration data (16 bits)
#define BMP085_CAL_MC 0xBC // R Calibration data (16 bits)
#define BMP085_CAL_MD 0xBE // R Calibration data (16 bits)
#define BMP085_CONTROL 0xF4
#define BMP085_TEMPDATA 0xF6
#define BMP085_PRESSUREDATA 0xF6
#define BMP085_READTEMPCMD 0x2E
#define BMP085_READPRESSURECMD 0x34
#define HIGH 1
#define LOW 0
namespace upm {
/**
* @brief Bosch BMP & GY65 Atmospheric Pressure Sensor library
* @defgroup bmpx8x libupm-bmpx8x
* @ingroup seeed adafruit sparkfun i2c pressure
*/
/**
* @brief Bosch BMP & GY65 Atmospheric Pressure Sensor library
* @defgroup bmpx8x libupm-bmpx8x @ingroup seeed adafruit sparkfun i2c
* pressure
*/
/**
* @library bmpx8x
* @sensor bmpx8x
* @comname BMP Atmospheric Pressure Sensor
* @altname GY65 BMP085 BMP180 BMP183
* @type pressure
* @man seeed adafruit sparkfun
* @con i2c
* @web https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf
* @web https://www.bosch-sensortec.com/bst/products/all_products/bmp180
* @web https://cdn-shop.adafruit.com/datasheets/1900_BMP183.pdf
*
* @brief API for the GY65/BMP085 and BMP180 Atmospheric Pressure Sensors
*
* Bosch GY65/BMP085 and BMP180 are high-precision, ultra-low
* power consumption pressure sensors. They operate in the range of
* 30,000-110,000 Pa.
*
* This module has been tested on the GY65/BMP085 and BMP180 sensors.
*
* @image html bmp085.jpeg
* @snippet bmpx8x.cxx Interesting
*/
/**
* @library bmpx8x
* @sensor bmpx8x
* @comname BMP Atmospheric Pressure Sensor
* @altname GY65 BMP085 BMP180 BMP183
* @type pressure
* @man seeed adafruit sparkfun
* @con i2c
* @web https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf
* @web https://www.bosch-sensortec.com/bst/products/all_products/bmp180
* @web https://cdn-shop.adafruit.com/datasheets/1900_BMP183.pdf
*
* @brief API for the GY65/BMP085 and BMP180 Atmospheric Pressure Sensors
*
* Bosch GY65/BMP085 and BMP180 are high-precision, ultra-low
* power consumption pressure sensors. They operate in the range of
* 30,000-110,000 Pa.
*
* This module has been tested on the GY65/BMP085 and BMP180 sensors.
*
* @image html bmp085.jpeg
* @snippet bmpx8x.cxx Interesting
*/
class BMPX8X : public IPressureSensor, public ITemperatureSensor {
class BMPX8X : public IPressureSensor, public ITemperatureSensor {
public:
/**
* Instantiates a BMPX8X object
*
* @param bus Number of the used bus
* @param devAddr Address of the used I2C device
* @param mode BMP085 mode
* @param bus I2C bus to use.
* @param addr The I2C address of the device.
* @throws std::runtime_error on failure.
*/
BMPX8X (int bus, int devAddr=0x77, uint8_t mode=BMP085_ULTRAHIGHRES);
BMPX8X(int bus=BMPX8X_DEFAULT_I2C_BUS,
int addr=BMPX8X_DEFAULT_I2C_ADDR);
/**
* BMPX8X object destructor; basically, it closes the I2C connection.
* ~BMPX8X ();
* LE: there is no need for the destructor, as the I2C connection
* will be closed when the m_i2ControlCtx variable will go out of
* scope (when all the BMPX8X objects will be destroyed)
* BMPX8X object destructor.
*/
/**
* Returns the calculated pressure
*/
int32_t getPressure ();
virtual ~BMPX8X();
/**
* Query the device and update the internal state. This
* method must be called before calling getPressure(),
* getTemperature(), getSealevelPressure(), and getAltitude()
* to retrieve values.
*
* Gets raw pressure data
* @throws std::runtime_error on failure.
*/
int32_t getPressureRaw ();
void update();
/**
* Gets raw temperature data from the sensor
*/
int16_t getTemperatureRaw ();
/**
* Returns the calculated temperature
*/
float getTemperature ();
/**
* With a given absolute altitude, sea level can be calculated
* Reset the device to power-on defaults. All calibration
* data is lost when the device is reset, so you should call
* init() before attempting to use the device.
*
* @param altitudeMeters Altitude
* @throws std::runtime_error on failure.
*/
int32_t getSealevelPressure(float altitudeMeters = 0);
void reset();
/**
* With a given sea level, altitude in meters can be calculated
* Initialize the device, read calibration data, and start
* operation. This function is called from the constructor,
* so it will not typically need to be called by a user unless
* the device is reset.
*
* @param sealevelPressure Sea level
* @param oss One of the BMPX8X_OSS_T values. The
* default is BMPX8X_OSS_ULTRAHIGHRES.
* @throws std::runtime_error on failure.
*/
float getAltitude (float sealevelPressure = 101325);
void init(BMPX8X_OSS_T oss=BMPX8X_OSS_ULTRAHIGHRES);
/**
* Return latest calculated temperature value in Celsius
* See ITemperatureSensor
*/
int getTemperatureCelsius();
/**
* Return latest calculated pressure value in Pascals
* See IPressureSensor
*/
int getPressurePa() { return getPressure(); };
/**
* Returns name of module. This is the string in library name
* after libupm_
* @return name of module
*/
const char* getModuleName();
/**
* Calculates B5 (check the spec for more information)
* Set the oversampling (precision mode) of the device.
* Higher precision requires more time to complete. This call
* takes effect the next time update() is called.
*
* @param UT
* @param oss One of the BMPX8X_OSS_T values. The
* default is BMPX8X_OSS_ULTRAHIGHRES.
*/
int32_t computeB5 (int32_t UT);
void setOversampling(BMPX8X_OSS_T oss=BMPX8X_OSS_ULTRAHIGHRES);
/**
* Reads a two-byte register
* Returns the calculated pressure in Pascals. update() must
* have been called prior to calling this function.
*
* @param reg Address of the register
* @returns The pressure in Pascals.
*/
uint16_t i2cReadReg_16 (int reg);
int getPressure();
/**
* Writes to a one-byte register
* Returns the calculated temperature in Celsius. update()
* must have been called prior to calling this function.
*
* @param reg Address of the register
* @param value Byte to be written
* @returns The temperature in Celsius.
*/
mraa::Result i2cWriteReg (uint8_t reg, uint8_t value);
float getTemperature();
/**
* Reads a one-byte register
* Using the supplied altitude in meters, compute the pressure
* at sea level in Pascals. update() must have been called
* prior to calling this function.
*
* @param reg Address of the register
* @param meters The altitude in meters.
* @returns The computed sea level pressure in Pascals.
*/
uint8_t i2cReadReg_8 (int reg);
int getSealevelPressure(float meters);
/**
* Using the current calculated altitude, compute the pressure
* at sea level in Pascals. update() must have been called
* prior to calling this function.
*
* @returns The computed sea level pressure in Pascals.
*/
int getSealevelPressure()
{
return getSealevelPressure(getAltitude());
}
/**
* Calculate the current altitude in meters, given a sea level
* pressure in Pascals. The default sea level pressure is
* 101325 Pascals. update() must have been called prior to
* calling this function.
*
* @param sealevelPressure The pressure at sea level in
* Pascals. The default is 101325 Pascals.
* @returns the computed altitude in meters.
*/
float getAltitude(int sealevelPressure = 101325);
/**
* Return latest calculated temperature value in Celsius. See
* ITemperatureSensor.
*
* @return The current temperature in Celsius.
*/
int getTemperatureCelsius()
{
update();
return (int)getTemperature();
}
/**
* Return latest calculated pressure value in Pascals. See
* IPressureSensor.
*
* @return The current pressure in Pascals.
*/
int getPressurePa()
{
update();
return getPressure();
}
/**
* Returns the name of module.
*
* @return The name of the module.
*/
const char *getModuleName()
{
return "BMPX8X";
}
protected:
// our underlying C context.
bmpx8x_context m_bmpx8x;
/**
* Read a register.
*
* @param reg The register to read.
* @return The value of the register.
*/
uint8_t readReg(uint8_t reg);
/**
* Read contiguous registers into a buffer.
*
* @param buffer The buffer to store the results.
* @param len The number of registers to read.
* @return The number of bytes read.
* @throws std::runtime_error on failure.
*/
int readRegs(uint8_t reg, uint8_t *buffer, int len);
/**
* Write to a register.
*
* @param reg The register to write to.
* @param val The value to write.
* @throws std::runtime_error on failure.
*/
void writeReg(uint8_t reg, uint8_t val);
private:
std::string m_name;
int m_controlAddr;
mraa::I2c m_i2ControlCtx;
uint8_t oversampling;
int16_t ac1, ac2, ac3, b1, b2, mb, mc, md;
uint16_t ac4, ac5, ac6;
};
};
}

110
src/bmpx8x/bmpx8x_defs.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* This driver was rewritten based on the original driver written by:
* Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#define BMPX8X_DEFAULT_I2C_BUS 0
#define BMPX8X_DEFAULT_I2C_ADDR 0x77
#define BMPX8X_DEFAULT_CHIPID 0x55
// special reset byte
#define BMPX8X_RESET_BYTE 0xb6
#ifdef __cplusplus
extern "C" {
#endif
/**
* BMPX8X registers.
*/
typedef enum {
BMPX8X_CAL_AC1 = 0xaa, // Calibration data (16
// bits, msb/lsb)
BMPX8X_CAL_AC2 = 0xac,
BMPX8X_CAL_AC3 = 0xae,
BMPX8X_CAL_AC4 = 0xb0,
BMPX8X_CAL_AC5 = 0xb2,
BMPX8X_CAL_AC6 = 0xb4,
BMPX8X_CAL_B1 = 0xb6,
BMPX8X_CAL_B2 = 0xb8,
BMPX8X_CAL_MB = 0xba,
BMPX8X_CAL_MC = 0xbc,
BMPX8X_CAL_MD = 0xbe,
BMPX8X_CTRL_MEAS = 0xf4, // command reg
BMPX8X_OUTDATA_MSB = 0xf6,
BMPX8X_OUTDATA_LSB = 0xf7,
BMPX8X_OUTDATA_XLSB = 0xf8,
BMPX8X_RESET = 0xe0,
BMPX8X_CHIP_ID = 0xd0
} BMPX8X_REGS_T;
/**
* BMPX8X_CTRL_MEAS register bits
*/
typedef enum {
BMPX8X_CTRL_MEAS_CMD0 = 0x01, // measurement command
BMPX8X_CTRL_MEAS_CMD1 = 0x02,
BMPX8X_CTRL_MEAS_CMD2 = 0x04,
BMPX8X_CTRL_MEAS_CMD3 = 0x08,
BMPX8X_CTRL_MEAS_CMD4 = 0x10,
_BMPX8X_CTRL_MEAS_CMD_MASK = 31,
_BMPX8X_CTRL_MEAS_CMD_SHIFT = 0,
BMPX8X_CTRL_MEAS_SCO = 0x20, // start conversion status
BMPX8X_CTRL_MEAS_OSS0 = 0x40, // oversampling (precision)
BMPX8X_CTRL_MEAS_OSS1 = 0x80,
_BMPX8X_CTRL_MEAS_OSS_MASK = 3,
_BMPX8X_CTRL_MEAS_OSS_SHIFT = 6,
} BMPX8X_CTRL_MEAS_BITS_T;
/**
* BMPX8X_CTRL_MEAS_CMD commands.
*/
typedef enum {
BMPX8X_CMD_READ_TEMP = 0x2e,
BMPX8X_CMD_READ_PRESSURE = 0x34
} BMPX8X_CMD_T;
/**
* BMPX8X_CTRL_MEAS_OSS, Oversampling ratio values.
*/
typedef enum {
BMPX8X_OSS_ULTRALOWPOWER = 0,
BMPX8X_OSS_STANDARD = 1,
BMPX8X_OSS_HIGHRES = 2,
BMPX8X_OSS_ULTRAHIGHRES = 3
} BMPX8X_OSS_T;
#ifdef __cplusplus
}
#endif

137
src/bmpx8x/bmpx8x_fti.c Normal file
View File

@ -0,0 +1,137 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "bmpx8x.h"
#include "upm_fti.h"
/**
* This file implements the Function Table Interface (FTI) for this sensor
*/
const char upm_bmpx8x_name[] = "BMPX8X";
const char upm_bmpx8x_description[] = "BMPX8X Pressure and Temperature Sensor";
const upm_protocol_t upm_bmpx8x_protocol[] = {UPM_I2C};
const upm_sensor_t upm_bmpx8x_category[] = {UPM_TEMPERATURE, UPM_PRESSURE};
// forward declarations
const void* upm_bmpx8x_get_ft(upm_sensor_t sensor_type);
void* upm_bmpx8x_init_name();
void upm_bmpx8x_close(void *dev);
upm_result_t upm_bmpx8x_get_pressure(void *dev, float *value);
upm_result_t upm_bmpx8x_get_temperature(void *dev, float *value,
upm_temperature_u unit);
const upm_sensor_descriptor_t upm_bmpx8x_get_descriptor()
{
upm_sensor_descriptor_t usd;
usd.name = upm_bmpx8x_name;
usd.description = upm_bmpx8x_description;
usd.protocol_size = 1;
usd.protocol = upm_bmpx8x_protocol;
usd.category_size = 2;
usd.category = upm_bmpx8x_category;
return usd;
}
static const upm_sensor_ft ft =
{
.upm_sensor_init_name = upm_bmpx8x_init_name,
.upm_sensor_close = upm_bmpx8x_close,
};
static const upm_temperature_ft tft =
{
.upm_temperature_get_value = upm_bmpx8x_get_temperature,
};
static const upm_pressure_ft pft =
{
.upm_pressure_get_value = upm_bmpx8x_get_pressure,
};
const void* upm_bmpx8x_get_ft(upm_sensor_t sensor_type)
{
switch(sensor_type)
{
case UPM_SENSOR:
return &ft;
case UPM_PRESSURE:
return &pft;
case UPM_TEMPERATURE:
return &tft;
default:
return NULL;
}
}
void* upm_bmpx8x_init_name()
{
return NULL;
}
void upm_bmpx8x_close(void *dev)
{
bmpx8x_close((bmpx8x_context)dev);
}
upm_result_t upm_bmpx8x_get_pressure(void *dev, float *value)
{
upm_result_t rv;
if ((rv = bmpx8x_update((bmpx8x_context)dev)))
return rv;
*value = bmpx8x_get_pressure((bmpx8x_context)dev);
return UPM_SUCCESS;
}
upm_result_t upm_bmpx8x_get_temperature(void *dev, float *value,
upm_temperature_u unit)
{
upm_result_t rv;
if ((rv = bmpx8x_update((bmpx8x_context)dev)))
return rv;
// always in C
float temp = bmpx8x_get_temperature((bmpx8x_context)dev);
switch (unit)
{
case CELSIUS:
*value = temp;
return UPM_SUCCESS;
case KELVIN:
*value = temp + 273.15;
return UPM_SUCCESS;
case FAHRENHEIT:
*value = temp * (9.0/5.0) + 32.0;
return UPM_SUCCESS;
}
return UPM_SUCCESS;
}

View File

@ -8,6 +8,7 @@
#include "bmpx8x.hpp"
%}
%include "bmpx8x_defs.h"
%include "bmpx8x.hpp"
%pragma(java) jniclasscode=%{

View File

@ -5,4 +5,5 @@
#include "bmpx8x.hpp"
%}
%include "bmpx8x_defs.h"
%include "bmpx8x.hpp"

View File

@ -5,6 +5,7 @@
%include "stdint.i"
%include "bmpx8x_defs.h"
%include "bmpx8x.hpp"
%{
#include "bmpx8x.hpp"