From 862f0474ecaea7bb52579a10f1a09d9f0bf99521 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Tue, 13 Jul 2021 19:14:34 +0200 Subject: [PATCH] Implemented error handling and performance improvements --- Adafruit_BMP085_U.cpp | 280 +++++++++++++++++++++++++++--------------- Adafruit_BMP085_U.h | 14 ++- 2 files changed, 196 insertions(+), 98 deletions(-) diff --git a/Adafruit_BMP085_U.cpp b/Adafruit_BMP085_U.cpp index 6544e33..282c73c 100644 --- a/Adafruit_BMP085_U.cpp +++ b/Adafruit_BMP085_U.cpp @@ -38,6 +38,14 @@ #include #endif +//#define DEBUG_OUTPUT +#ifdef DEBUG_OUTPUT +#include +#define DBGPRNT(format, ...) ESP_LOGW("BMP085", format, ##__VA_ARGS__) +#else +#define DBGPRNT(format, ...) +#endif + #include #include @@ -52,6 +60,14 @@ static uint8_t _bmp085Mode; #define BMP085_USE_DATASHEET_VALS \ (0) //!< Set to 1 for sanity check, when true, will use values from datasheet +#if ARDUINO >= 100 +#define WIRE_WRITE Wire.write +#define WIRE_READ Wire.read +#else +#define WIRE_WRITE Wire.send +#define WIRE_READ Wire.receive +#endif + /*************************************************************************** PRIVATE FUNCTIONS ***************************************************************************/ @@ -61,16 +77,15 @@ static uint8_t _bmp085Mode; @brief Writes an 8 bit value over I2C */ /**************************************************************************/ -static void writeCommand(byte reg, byte value) { +static bool writeCommand(byte reg, byte value) { + bool succ{true}; + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); -#if ARDUINO >= 100 - Wire.write((uint8_t)reg); - Wire.write((uint8_t)value); -#else - Wire.send(reg); - Wire.send(value); -#endif - Wire.endTransmission(); + if (WIRE_WRITE((uint8_t)reg) != 1) { DBGPRNT("fail"); succ = false; } + if (WIRE_WRITE((uint8_t)value) != 1) { DBGPRNT("fail"); succ = false; } + if (const auto result = Wire.endTransmission(); result != I2C_ERROR_OK) { DBGPRNT("fail %hhu", result); succ = false; } + + return succ; } /**************************************************************************/ @@ -78,21 +93,21 @@ static void writeCommand(byte reg, byte value) { @brief Reads an 8 bit value over I2C */ /**************************************************************************/ -static void read8(byte reg, uint8_t *value) { +static bool read8(byte reg, uint8_t *value) { + bool succ{true}; + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); -#if ARDUINO >= 100 - Wire.write((uint8_t)reg); -#else - Wire.send(reg); -#endif - Wire.endTransmission(); - Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1); -#if ARDUINO >= 100 - *value = Wire.read(); -#else - *value = Wire.receive(); -#endif + if (WIRE_WRITE((uint8_t)reg) != 1) { DBGPRNT("fail"); succ = false; } + if (const auto result = Wire.endTransmission(); result != I2C_ERROR_OK) { DBGPRNT("fail %hhu", result); succ = false; } + + if (const auto result = Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1); result != 1) { DBGPRNT("fail %hhu", result); succ = false; } + if (const auto result = WIRE_READ(); result == -1) { DBGPRNT("fail %i", result); succ = false; } + else *value = result; + + //if (const auto result = Wire.endTransmission(); result != I2C_ERROR_OK) { DBGPRNT("fail %hhu", result); succ = false; } Wire.endTransmission(); + + return succ; } /**************************************************************************/ @@ -100,21 +115,24 @@ static void read8(byte reg, uint8_t *value) { @brief Reads a 16 bit value over I2C */ /**************************************************************************/ -static void read16(byte reg, uint16_t *value) { +static bool read16(byte reg, uint16_t *value) { + bool succ{true}; + Wire.beginTransmission((uint8_t)BMP085_ADDRESS); -#if ARDUINO >= 100 - Wire.write((uint8_t)reg); -#else - Wire.send(reg); -#endif - Wire.endTransmission(); - Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2); -#if ARDUINO >= 100 - *value = (Wire.read() << 8) | Wire.read(); -#else - *value = (Wire.receive() << 8) | Wire.receive(); -#endif + if (WIRE_WRITE((uint8_t)reg) != 1) { DBGPRNT("fail"); succ = false; } + if (const auto result = Wire.endTransmission(); result != I2C_ERROR_OK) { DBGPRNT("fail %hhu", result); succ = false; } + + if (const auto result = Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2); result != 2) { DBGPRNT("fail %hhu", result); succ = false; } + const auto result0 = WIRE_READ(); + const auto result1 = WIRE_READ(); + if (result0 == -1) { DBGPRNT("fail %i", result0); succ = false; } + else if (result1 == -1) { DBGPRNT("fail %i", result1); succ = false; } + else { *value = (result0 << 8) | result1; } + + //if (const auto result = Wire.endTransmission(); result != I2C_ERROR_OK) { DBGPRNT("fail %hhu", result); succ = false; } Wire.endTransmission(); + + return succ; } /**************************************************************************/ @@ -122,10 +140,12 @@ static void read16(byte reg, uint16_t *value) { @brief Reads a signed 16 bit value over I2C */ /**************************************************************************/ -static void readS16(byte reg, int16_t *value) { +static bool readS16(byte reg, int16_t *value) { + bool succ{true}; uint16_t i; - read16(reg, &i); - *value = (int16_t)i; + if (!read16(reg, &i)) { DBGPRNT("fail"); succ = false; } + else *value = (int16_t)i; + return succ; } /**************************************************************************/ @@ -133,7 +153,8 @@ static void readS16(byte reg, int16_t *value) { @brief Reads the factory-set coefficients */ /**************************************************************************/ -static void readCoefficients(void) { +static bool readCoefficients(void) { + bool succ{true}; #if BMP085_USE_DATASHEET_VALS _bmp085_coeffs.ac1 = 408; _bmp085_coeffs.ac2 = -72; @@ -148,18 +169,19 @@ static void readCoefficients(void) { _bmp085_coeffs.md = 2868; _bmp085Mode = 0; #else - readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1); - readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2); - readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3); - read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4); - read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5); - read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6); - readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1); - readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2); - readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb); - readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc); - readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md); + if (!readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3)) { DBGPRNT("fail"); succ = false; } + if (!read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4)) { DBGPRNT("fail"); succ = false; } + if (!read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5)) { DBGPRNT("fail"); succ = false; } + if (!read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc)) { DBGPRNT("fail"); succ = false; } + if (!readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md)) { DBGPRNT("fail"); succ = false; } #endif + return succ; } /**************************************************************************/ @@ -167,15 +189,19 @@ static void readCoefficients(void) { */ /**************************************************************************/ -static void readRawTemperature(int32_t *temperature) { +static std::optional readRawTemperature() { #if BMP085_USE_DATASHEET_VALS - *temperature = 27898; + return 27898; #else - uint16_t t; - writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD); + bool succ{true}; + if (!writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD)) { DBGPRNT("fail"); succ = false; } delay(5); - read16(BMP085_REGISTER_TEMPDATA, &t); - *temperature = t; + uint16_t t; + if (!read16(BMP085_REGISTER_TEMPDATA, &t)) { DBGPRNT("fail"); succ = false; } + if (succ) + return t; + else + return std::nullopt; #endif } @@ -184,16 +210,14 @@ static void readRawTemperature(int32_t *temperature) { */ /**************************************************************************/ -static void readRawPressure(int32_t *pressure) { +static std::optional readRawPressure() { #if BMP085_USE_DATASHEET_VALS - *pressure = 23843; + return 23843; #else - uint8_t p8; - uint16_t p16; - int32_t p32; + bool succ{true}; - writeCommand(BMP085_REGISTER_CONTROL, - BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6)); + if (!writeCommand(BMP085_REGISTER_CONTROL, + BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6))) { DBGPRNT("fail"); succ = false; } switch (_bmp085Mode) { case BMP085_MODE_ULTRALOWPOWER: delay(5); @@ -210,13 +234,25 @@ static void readRawPressure(int32_t *pressure) { break; } - read16(BMP085_REGISTER_PRESSUREDATA, &p16); - p32 = (uint32_t)p16 << 8; - read8(BMP085_REGISTER_PRESSUREDATA + 2, &p8); - p32 += p8; - p32 >>= (8 - _bmp085Mode); + int32_t p32{}; - *pressure = p32; + { + uint16_t p16; + if (!read16(BMP085_REGISTER_PRESSUREDATA, &p16)) { DBGPRNT("fail"); succ = false; } + else if (succ) p32 += (uint32_t)p16 << 8; + } + + { + uint8_t p8; + if (!read8(BMP085_REGISTER_PRESSUREDATA + 2, &p8)) { DBGPRNT("fail"); succ = false; } + else if (succ) p32 += p8; + } + + if (succ) { + p32 >>= (8 - _bmp085Mode); + return p32; + } else + return std::nullopt; #endif } @@ -258,7 +294,8 @@ Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) { bool Adafruit_BMP085_Unified::begin(bool skipWireBegin, bmp085_mode_t mode) { // Enable I2C if (!skipWireBegin) - Wire.begin(); + if (!Wire.begin()) + { DBGPRNT("fail"); return false; } /* Mode boundary check */ if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0)) { @@ -267,16 +304,14 @@ bool Adafruit_BMP085_Unified::begin(bool skipWireBegin, bmp085_mode_t mode) { /* Make sure we have the right device */ uint8_t id; - read8(BMP085_REGISTER_CHIPID, &id); - if (id != 0x55) { - return false; - } + if (!read8(BMP085_REGISTER_CHIPID, &id)) { DBGPRNT("fail"); return false; } + if (id != 0x55) { DBGPRNT("fail"); return false; } /* Set the mode indicator */ _bmp085Mode = mode; /* Coefficients need to be read once */ - readCoefficients(); + if (!readCoefficients()) { DBGPRNT("fail"); return false; } return true; } @@ -286,14 +321,33 @@ bool Adafruit_BMP085_Unified::begin(bool skipWireBegin, bmp085_mode_t mode) { @brief Gets the compensated pressure level in kPa */ /**************************************************************************/ -void Adafruit_BMP085_Unified::getPressure(float *pressure) { - int32_t ut = 0, up = 0, compp = 0; - int32_t x1, x2, b5, b6, x3, b3, p; - uint32_t b4, b7; +std::optional Adafruit_BMP085_Unified::getPressure() { + int32_t ut; /* Get the raw pressure and temperature values */ - readRawTemperature(&ut); - readRawPressure(&up); + if (const auto rawTemp = readRawTemperature()) + ut = *rawTemp; + else + { DBGPRNT("fail"); return std::nullopt; } + + int32_t up; + + if (const auto rawPress = readRawPressure()) + up = *rawPress; + else + { DBGPRNT("fail"); return std::nullopt; } + + return getPressure(ut, up); +} + +/**************************************************************************/ +/*! + @brief Gets the compensated pressure level in kPa +*/ +/**************************************************************************/ +float Adafruit_BMP085_Unified::getPressure(int32_t ut, int32_t up) { + int32_t x1, x2, b5, b6, x3, b3, p; + uint32_t b4, b7; /* Temperature compensation */ b5 = computeB5(ut); @@ -319,10 +373,32 @@ void Adafruit_BMP085_Unified::getPressure(float *pressure) { x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; - compp = p + ((x1 + x2 + 3791) >> 4); + float compp = p + ((x1 + x2 + 3791) >> 4); /* Assign compensated pressure value */ - *pressure = compp; + return compp / 100.f; +} + +std::optional Adafruit_BMP085_Unified::getTemperatureAndPressure() { + int32_t ut; + + /* Get the raw pressure and temperature values */ + if (const auto rawTemp = readRawTemperature()) + ut = *rawTemp; + else + { DBGPRNT("fail"); return std::nullopt; } + + int32_t up; + + if (const auto rawPress = readRawPressure()) + up = *rawPress; + else + { DBGPRNT("fail"); return std::nullopt; } + + return TemperatureAndPressure { + .temperature = getTemperature(ut), + .pressure = getPressure(ut, up) + }; } /**************************************************************************/ @@ -330,12 +406,7 @@ void Adafruit_BMP085_Unified::getPressure(float *pressure) { @brief Reads the temperatures in degrees Celsius */ /**************************************************************************/ -void Adafruit_BMP085_Unified::getTemperature(float *temp) { - int32_t UT, B5; // following ds convention - float t; - - readRawTemperature(&UT); - +std::optional Adafruit_BMP085_Unified::getTemperature() { #if BMP085_USE_DATASHEET_VALS // use datasheet numbers! UT = 27898; @@ -343,13 +414,31 @@ void Adafruit_BMP085_Unified::getTemperature(float *temp) { _bmp085_coeffs.ac5 = 32757; _bmp085_coeffs.mc = -8711; _bmp085_coeffs.md = 2868; +#else + int32_t UT; + if (const auto rawTemp = readRawTemperature()) + UT = *rawTemp; + else + { DBGPRNT("fail"); return std::nullopt; } #endif + return getTemperature(UT); +} + +/**************************************************************************/ +/*! + @brief Reads the temperatures in degrees Celsius +*/ +/**************************************************************************/ +float Adafruit_BMP085_Unified::getTemperature(int32_t UT) { + int32_t B5; // following ds convention + float t; + B5 = computeB5(UT); t = (B5 + 8) >> 4; t /= 10; - *temp = t; + return t; } /**************************************************************************/ @@ -466,18 +555,17 @@ sensor_t Adafruit_BMP085_Unified::getSensor() { */ /**************************************************************************/ std::optional Adafruit_BMP085_Unified::getEvent() { + const auto pressure = getPressure(); + if (!pressure) + return std::nullopt; + sensors_event_t event; event.version = sizeof(sensors_event_t); event.sensor_id = _sensorID; event.type = SENSOR_TYPE_PRESSURE; event.timestamp = espchrono::millis_clock::now(); - - { - float pressure_kPa; - getPressure(&pressure_kPa); - event.pressure = pressure_kPa / 100.0F; - } + event.pressure = *pressure; return event; } diff --git a/Adafruit_BMP085_U.h b/Adafruit_BMP085_U.h index 2c35273..3262a54 100644 --- a/Adafruit_BMP085_U.h +++ b/Adafruit_BMP085_U.h @@ -99,13 +99,23 @@ public: * @param temp Temperature * @return Returns the temperature */ - void getTemperature(float *temp); + std::optional getTemperature(); + + float getTemperature(int32_t UT); + /*! * @brief Gets the pressure over I2C from the BMP085 * @param pressure Pressure * @return Returns the pressure */ - void getPressure(float *pressure); + std::optional getPressure(); + + float getPressure(int32_t ut, int32_t up); + + struct TemperatureAndPressure { float temperature, pressure; }; + + std::optional getTemperatureAndPressure(); + /*! * @brief Calculates absolute pressure * @param seaLevel Pressure at sea level