From c57a0d2c307e2ddfeacffa1ace7bccea9ef4af3f Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Tue, 4 Apr 2017 17:48:41 -0600 Subject: [PATCH] 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 --- docs/apichanges.md | 80 +++++-- examples/c++/bmpx8x.cxx | 76 ++++--- examples/c/CMakeLists.txt | 1 + examples/c/bmpx8x.c | 88 ++++++++ examples/java/BMPX8XSample.java | 47 +++-- examples/javascript/bmpx8x.js | 44 ++-- examples/python/bmpx8x.py | 34 +-- src/bmpx8x/CMakeLists.txt | 15 +- src/bmpx8x/bmpx8x.c | 360 ++++++++++++++++++++++++++++++++ src/bmpx8x/bmpx8x.cxx | 234 ++++++--------------- src/bmpx8x/bmpx8x.h | 230 ++++++++++++++++++++ src/bmpx8x/bmpx8x.hpp | 311 +++++++++++++++------------ src/bmpx8x/bmpx8x_defs.h | 110 ++++++++++ src/bmpx8x/bmpx8x_fti.c | 137 ++++++++++++ src/bmpx8x/javaupm_bmpx8x.i | 1 + src/bmpx8x/jsupm_bmpx8x.i | 1 + src/bmpx8x/pyupm_bmpx8x.i | 1 + 17 files changed, 1346 insertions(+), 424 deletions(-) create mode 100644 examples/c/bmpx8x.c create mode 100644 src/bmpx8x/bmpx8x.c create mode 100644 src/bmpx8x/bmpx8x.h create mode 100644 src/bmpx8x/bmpx8x_defs.h create mode 100644 src/bmpx8x/bmpx8x_fti.c diff --git a/docs/apichanges.md b/docs/apichanges.md index a834e7ac..d89cd1e0 100644 --- a/docs/apichanges.md +++ b/docs/apichanges.md @@ -6,6 +6,54 @@ compatibility between releases: # current master + * **bmpx8x** This driver has been rewritten from scratch in C, with a + C++ wrapper. + + All exported symbols have been renamed for consistancy and to + avoid symbol collisions by having a *BMPX8X_* prefix. As an example, + *ADDR* has been renamed to *BMPX8X_DEFAULT_I2C_ADDR*. Most C + ported drivers follow this rule. + + The *getPressureRaw()* and *getTemperatureRaw()* functions have + been removed. This functionality was only needed internally to + the driver. + + The constructor no longer accepts a mode argument. Only the I2C + bus and I2C address are accepted. By default, the device will be + configured for it's maximum resolution *BMPX8X_OSS_ULTRAHIGHRES*, + the previous default. You can use the new method + *setOversampling()* to change the mode to something else if + desired. + + The methods related to calibration, like *computeB5()* are no + longer exposed. + + New methods, *init()* and *reset()* have been added. *reset()* + resets the device to a freshly powered up state. *init()* can be + used to re-initialize the device after a reset (reload calibration + data) and set a default oversampling mode. + + A new method, *update()* has been added. This method will update + all internal state from the device, and **must** be called before + querying the pressure, temperature, sealevel and altitude values. + + The *getSeaLevelPressure()* method has been split into two + overloaded methods. One which **requires** an argument in meters + (previously, a default was provided), and another which does not + accept arguments at all and computes the sea level pressure based + on current altitude. + + The *i2cReadReg_16()*, *i2CWriteReg()* and *i2cReadReg_8()* have + been replaced with *readReg()*, *readRegs()*, and *writeReg()*, in + line with other I2C/SPI drivers of this type. They are marked + protected (in C++) now as well. Please see the updated + documentation and examples for this driver. + + * **mma7660** This driver has been rewritten in C. Some exported + symbols have been changed, for example, *MMA7660_I2C_BUS* was renamed + to *MMA7660_DEFAULT_I2C_BUS*. See updated documentation and examples + for other changes. + * **bmx055, bmi055, bmc150, bma250e, bmg160, bmm150** This driver has been split up. The *bma250e*, *bmg160*, *bmm150* drivers have been rewritten in C (with C++ wrappers) and now reside in their own @@ -15,14 +63,14 @@ compatibility between releases: and *bmc150* are still contained within the *bmx055* library, and also use the new libraries for their functionality. - In addition, for all of these drivers some private methods are no - longer exposed (such as the compensation routines). + In addition, for all of these drivers some private methods are no + longer exposed (such as the compensation routines). - The C++ driver methods that once returned pointers to a floating - point array now return *std::vectors* of the appropriate type. The - SWIG language examples for these drivers have been modified to use - these methods instead of the C pointer based SWIG methods previously - used. + The C++ driver methods that once returned pointers to a floating + point array now return *std::vectors* of the appropriate type. + The SWIG language examples for these drivers have been modified to + use these methods instead of the C pointer based SWIG methods + previously used. * **sainsmartks** This driver has been renamed to *lcdks* (LCD Keypad Shield) and moved into it's own library. It uses the *lcm1602* @@ -40,16 +88,16 @@ compatibility between releases: *jhd1313m1* drivers had their C++ headers renamed to use a **.hxx** suffix. - In this version of UPM, the *lcm1602* and *jhd1313m1* drivers have - been removed from the lcd/i2clcd library. In addition, the header - files for the new implementation have been renamed from their **.hxx** - suffix to the normal **.hpp** suffix. + In this version of UPM, the *lcm1602* and *jhd1313m1* drivers have + been removed from the lcd/i2clcd library. In addition, the header + files for the new implementation have been renamed from their + **.hxx** suffix to the normal **.hpp** suffix. - A change was also made to the new *lcm1602* and *jhd1313m1* C++ - drivers. The *createChar()* function now accepts a byte vector - *std::vector* rather than the *char ** pointer that was - used previously. This should make it easier to use with the SWIG - language bindings (Python, Javascript, and especially Java). + A change was also made to the new *lcm1602* and *jhd1313m1* C++ + drivers. The *createChar()* function now accepts a byte vector + *std::vector* rather than the *char ** pointer that was + used previously. This should make it easier to use with the SWIG + language bindings (Python, Javascript, and especially Java). * **bmp280/bme280** Some private methods are no longer exposed (such as the calibration and compensation routines). In addition, diff --git a/examples/c++/bmpx8x.cxx b/examples/c++/bmpx8x.cxx index f4ebf7de..294a52a2 100644 --- a/examples/c++/bmpx8x.cxx +++ b/examples/c++/bmpx8x.cxx @@ -1,6 +1,11 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * This driver was rewritten based on the original driver written by: * Author: Yevgeniy Kiveisha - * 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 @@ -24,57 +29,50 @@ #include #include -#include "bmpx8x.hpp" #include -int doWork = 0; -upm::BMPX8X *sensor = NULL; +#include "bmpx8x.hpp" -void -sig_handler(int signo) +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) { - printf("got signal\n"); - if (signo == SIGINT) { - printf("exiting application\n"); - doWork = 1; - } + if (signo == SIGINT) + shouldRun = false; } -int -main(int argc, char **argv) +int main(int argc, char **argv) { - //! [Interesting] - uint32_t presure = 0; - float temperature = 0; - float altitude = 0; - uint32_t sealevel = 0; + signal(SIGINT, sig_handler); +//! [Interesting] - // Instantiate a BMPX8X sensor on I2C - sensor = new upm::BMPX8X(0, ADDR); + // Instantiate a BMPX8X sensor on I2C using defaults. + upm::BMPX8X sensor; // Print the pressure, altitude, sea level, and - // temperature values every 0.1 seconds - while (!doWork) { - presure = sensor->getPressure (); - temperature = sensor->getTemperature (); - altitude = sensor->getAltitude (); - sealevel = sensor->getSealevelPressure (); + // temperature values every 0.5 seconds + while (shouldRun) + { + sensor.update(); - std::cout << "pressure value = " << - presure << - ", altitude value = " << - altitude << - ", sealevel value = " << - sealevel << - ", temperature = " << - temperature << std::endl; - usleep (100000); + cout << "Pressure: " + << sensor.getPressure() + << " Pa, Temperature: " + << sensor.getTemperature() + << " C, Altitude: " + << sensor.getAltitude() + << " m, Sea level: " + << sensor.getSealevelPressure() + << " Pa" + << endl; + + usleep(500000); } - //! [Interesting] - std::cout << "exiting application" << std::endl; - - delete sensor; + cout << "Exiting..." << endl; +//! [Interesting] return 0; } diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 0072f9f8..00f681f3 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -157,6 +157,7 @@ add_example (bmg160) add_example (bma250e) add_example (bmm150) add_example (rsc) +add_example (bmpx8x) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/bmpx8x.c b/examples/c/bmpx8x.c new file mode 100644 index 00000000..88339f3c --- /dev/null +++ b/examples/c/bmpx8x.c @@ -0,0 +1,88 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 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 + * "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 +#include +#include + +#include "upm_utilities.h" +#include "bmpx8x.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); +//! [Interesting] + + // Instantiate a BMPX8X instance using default i2c bus and address + bmpx8x_context sensor = bmpx8x_init(BMPX8X_DEFAULT_I2C_BUS, + BMPX8X_DEFAULT_I2C_ADDR); + + if (!sensor) + { + printf("bmpx8x_init() failed.\n"); + return 1; + } + + // Print the pressure, altitude, sea level, and + // temperature values every 0.5 seconds + while (shouldRun) + { + if (bmpx8x_update(sensor)) + { + printf("bmpx8x_update() failed\n"); + bmpx8x_close(sensor); + return 1; + } + + // assume sea level pressure is 101325 Pa. + float altitude = bmpx8x_get_altitude(sensor, 101325); + int sealevel = bmpx8x_get_sealevel_pressure(sensor, altitude); + + printf("Pressure: %d Pa, Temperature: %f C, " + "Altitude %f m, Sea level %d Pa\n", + bmpx8x_get_pressure(sensor), + bmpx8x_get_temperature(sensor), + altitude, + sealevel); + + upm_delay_ms(500); + } + + printf("Exiting...\n"); + bmpx8x_close(sensor); + +//! [Interesting] + return 0; +} diff --git a/examples/java/BMPX8XSample.java b/examples/java/BMPX8XSample.java index c8031215..b0377f28 100644 --- a/examples/java/BMPX8XSample.java +++ b/examples/java/BMPX8XSample.java @@ -1,6 +1,7 @@ /* * Author: Stefan Andritoiu - * Copyright (c) 2015 Intel Corporation. + * Author: Jon Trulson + * Copyright (c) 2015-2017 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -22,27 +23,33 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -//NOT TESTED!!! public class BMPX8XSample { - public static void main(String[] args) throws InterruptedException { - // ! [Interesting] - // Instantiate a BMPX8X sensor on I2C - upm_bmpx8x.BMPX8X sensor = new upm_bmpx8x.BMPX8X(0); + public static void main(String[] args) throws InterruptedException { +// ! [Interesting] - // Print the pressure, altitude, sea level, and - // temperature values every second - while (true) { - System.out.println("Pressure: " + sensor.getPressure()); - System.out.println("Altitude: " + sensor.getAltitude()); - System.out.println("Sealevel pressure: " - + sensor.getSealevelPressure()); - System.out.println("Temperature: " + sensor.getTemperature()); - System.out.println(); + // Instantiate a BMPX8X sensor on I2C using defaults. + upm_bmpx8x.BMPX8X sensor = new upm_bmpx8x.BMPX8X(); - Thread.sleep(1000); - } - // ! [Interesting] - } + // Print the pressure, altitude, sea level, and + // temperature values every .5 seconds + while (true) + { + sensor.update(); -} \ No newline at end of file + System.out.println("Pressure: " + + sensor.getPressure() + + " Pa, Temperature: " + + sensor.getTemperature() + + " C, Altitude: " + + sensor.getAltitude() + + " m, Sea level: " + + sensor.getSealevelPressure() + + " Pa"); + + Thread.sleep(500); + } +// ! [Interesting] + } + +} diff --git a/examples/javascript/bmpx8x.js b/examples/javascript/bmpx8x.js index 96b52b87..d4101b85 100644 --- a/examples/javascript/bmpx8x.js +++ b/examples/javascript/bmpx8x.js @@ -1,6 +1,7 @@ /* * Author: Zion Orent -* Copyright (c) 2014 Intel Corporation. +* Author: Jon Trulson +* Copyright (c) 2014-2017 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -22,31 +23,34 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -//Load Barometer module -var bmpx8x = require('jsupm_bmpx8x'); -// load this on i2c -var myBarometerObj = new bmpx8x.BMPX8X(0, bmpx8x.ADDR); -var pressure, temperature, altitude, sealevel; +var sensorObj = require('jsupm_bmpx8x'); + +// Instantiate a BMPX8X sensor on I2C using defaults. +var sensor = new sensorObj.BMPX8X(); // Print the pressure, altitude, sea level, and -// temperature values every 0.1 seconds +// temperature values every 0.5 seconds setInterval(function() { - var pressure = myBarometerObj.getPressure(); - var temperature = myBarometerObj.getTemperature(); - var altitude = myBarometerObj.getAltitude(); - var sealevel = myBarometerObj.getSealevelPressure(); + sensor.update(); - var BMPX8Xresults = "pressure value = " + pressure; - BMPX8Xresults += ", altitude value = " + altitude; - BMPX8Xresults += ", sealevel value = " + sealevel; - BMPX8Xresults += ", temperature = " + temperature; - console.log(BMPX8Xresults); -}, 100); + console.log("Pressure: " + + sensor.getPressure() + + " Pa, Temperature: " + + sensor.getTemperature() + + " C, Altitude: " + + sensor.getAltitude() + + " m, Sea level: " + + sensor.getSealevelPressure() + + " Pa"); +}, 500); -// Print message when exiting +// exit on ^C process.on('SIGINT', function() { - console.log("Exiting..."); - process.exit(0); + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); }); diff --git a/examples/python/bmpx8x.py b/examples/python/bmpx8x.py index 0a5eba80..dc79a834 100755 --- a/examples/python/bmpx8x.py +++ b/examples/python/bmpx8x.py @@ -1,6 +1,7 @@ #!/usr/bin/python # Author: Zion Orent -# Copyright (c) 2015 Intel Corporation. +# Author: Jon Trulson +# Copyright (c) 2014-2017 Intel Corporation. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,15 +27,18 @@ import time, sys, signal, atexit from upm import pyupm_bmpx8x as upmBmpx8x def main(): - # Load Barometer module on i2c - myBarometer = upmBmpx8x.BMPX8X(0, upmBmpx8x.ADDR); + # Load Barometer module on i2c using default values + sensor = upmBmpx8x.BMPX8X(0); ## Exit handlers ## - # This function stops python from printing a stacktrace when you hit control-C + + # This function stops python from printing a stacktrace when you hit + # control-C def SIGINTHandler(signum, frame): raise SystemExit - # This function lets you run code on exit, including functions from myBarometer + # This function lets you run code on exit, including functions + # from sensor def exitHandler(): print("Exiting") sys.exit(0) @@ -46,17 +50,19 @@ def main(): # Print the pressure, altitude, sea level, and # temperature values every 0.1 seconds while(1): - outputStr = ("pressure value = {0}" - ", altitude value = {1}" - ", sealevel value = {2}" - ", temperature = {3}".format( - myBarometer.getPressure(), - myBarometer.getTemperature(), - myBarometer.getAltitude(), - myBarometer.getSealevelPressure())) + sensor.update() + + outputStr = ("Pressure: {0}" + " Pa, Temperature: {1}" + " C, Altitude: {2}" + " m, Sea Level: {3} Pa".format( + sensor.getPressure(), + sensor.getTemperature(), + sensor.getAltitude(), + sensor.getSealevelPressure())) print(outputStr) - time.sleep(.1) + time.sleep(.5) if __name__ == '__main__': main() diff --git a/src/bmpx8x/CMakeLists.txt b/src/bmpx8x/CMakeLists.txt index 1b75a6f4..8b3ce578 100644 --- a/src/bmpx8x/CMakeLists.txt +++ b/src/bmpx8x/CMakeLists.txt @@ -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) diff --git a/src/bmpx8x/bmpx8x.c b/src/bmpx8x/bmpx8x.c new file mode 100644 index 00000000..71ad6a7b --- /dev/null +++ b/src/bmpx8x/bmpx8x.c @@ -0,0 +1,360 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * This driver was rewritten based on the original driver written by: + * Author: Yevgeniy Kiveisha + * + * 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 +#include + +#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; +} diff --git a/src/bmpx8x/bmpx8x.cxx b/src/bmpx8x/bmpx8x.cxx index 7e221952..36144907 100644 --- a/src/bmpx8x/bmpx8x.cxx +++ b/src/bmpx8x/bmpx8x.cxx @@ -1,6 +1,11 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * This driver was rewritten based on the original driver written by: * Author: Yevgeniy Kiveisha - * 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(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); } diff --git a/src/bmpx8x/bmpx8x.h b/src/bmpx8x/bmpx8x.h new file mode 100644 index 00000000..aa4fa9c3 --- /dev/null +++ b/src/bmpx8x/bmpx8x.h @@ -0,0 +1,230 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * This driver was rewritten based on the original driver written by: + * Author: Yevgeniy Kiveisha + * + * 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 +#include + +#include + +#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 diff --git a/src/bmpx8x/bmpx8x.hpp b/src/bmpx8x/bmpx8x.hpp index 0065d93c..2df79617 100644 --- a/src/bmpx8x/bmpx8x.hpp +++ b/src/bmpx8x/bmpx8x.hpp @@ -1,10 +1,11 @@ /* - * Author: Yevgeniy Kiveisha - * Contributions: Jon Trulson - * Copyright (c) 2014 Intel Corporation. + * Author: Jon Trulson + * 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 + * + * 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 -#include -#include + +#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; -}; + }; } diff --git a/src/bmpx8x/bmpx8x_defs.h b/src/bmpx8x/bmpx8x_defs.h new file mode 100644 index 00000000..1fe4a2ba --- /dev/null +++ b/src/bmpx8x/bmpx8x_defs.h @@ -0,0 +1,110 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * This driver was rewritten based on the original driver written by: + * Author: Yevgeniy Kiveisha + * + * 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 diff --git a/src/bmpx8x/bmpx8x_fti.c b/src/bmpx8x/bmpx8x_fti.c new file mode 100644 index 00000000..a45f66d9 --- /dev/null +++ b/src/bmpx8x/bmpx8x_fti.c @@ -0,0 +1,137 @@ +/* + * Author: Jon Trulson + * 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; +} diff --git a/src/bmpx8x/javaupm_bmpx8x.i b/src/bmpx8x/javaupm_bmpx8x.i index bada4d5b..fd4f5bd8 100644 --- a/src/bmpx8x/javaupm_bmpx8x.i +++ b/src/bmpx8x/javaupm_bmpx8x.i @@ -8,6 +8,7 @@ #include "bmpx8x.hpp" %} +%include "bmpx8x_defs.h" %include "bmpx8x.hpp" %pragma(java) jniclasscode=%{ diff --git a/src/bmpx8x/jsupm_bmpx8x.i b/src/bmpx8x/jsupm_bmpx8x.i index de9c9493..cf8b82d8 100644 --- a/src/bmpx8x/jsupm_bmpx8x.i +++ b/src/bmpx8x/jsupm_bmpx8x.i @@ -5,4 +5,5 @@ #include "bmpx8x.hpp" %} +%include "bmpx8x_defs.h" %include "bmpx8x.hpp" diff --git a/src/bmpx8x/pyupm_bmpx8x.i b/src/bmpx8x/pyupm_bmpx8x.i index c514e0ff..a69f1b0f 100644 --- a/src/bmpx8x/pyupm_bmpx8x.i +++ b/src/bmpx8x/pyupm_bmpx8x.i @@ -5,6 +5,7 @@ %include "stdint.i" +%include "bmpx8x_defs.h" %include "bmpx8x.hpp" %{ #include "bmpx8x.hpp"