From fee89bfe7ce9c90d45355806467c6cbbb5cae328 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Sat, 30 Jul 2016 08:51:44 -0400 Subject: [PATCH] The call to i2c_smbus_write_byte_data() can fail and the return value was not being checked. This can cause incorrect values to be returned by the driver. With this change, when calling bmp180_temperature(), bmp180_pressure() and bmp180_altitude(), the return value will either be LONG_MIN or -FLT_MAX, depending on the return data type if the operation failed. The caller can call bmp180_get_last_errno() to get the errno of the failed operation. I am encountering this situation with my BMP180 sensor. It is currently outdoors and I believe that moisture may be causing an issue with the sensor. `i2cdetect 1` does not show the sensor, however the test program will return values like: t = 12.800000, p = 99977, a= 112.836433 --- README.md | 22 +++++++++++++++++++++- src/bmp180.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/bmp180.h | 2 ++ src/test.c | 22 +++++++++++++++++++++- 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 04aa1f4..4d8425d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Raspberry Pi C driver and Python bindings for the sensor BMP180. #include "bmp180.h" #include #include +#include +#include int main(int argc, char **argv){ char *i2c_device = "/dev/i2c-1"; @@ -19,11 +21,29 @@ int main(int argc, char **argv){ void *bmp = bmp180_init(address, i2c_device); if(bmp != NULL){ - int i; + int i, error; for(i = 0; i < 10; i++) { float t = bmp180_temperature(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading temperature: %s\n", strerror(error)); + exit(1); + } + long p = bmp180_pressure(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading pressure: %s\n", strerror(error)); + exit(1); + } + float alt = bmp180_altitude(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading altitude: %s\n", strerror(error)); + exit(1); + } + printf("t = %f, p = %lu, a = %f\n", t, p, alt); usleep(2 * 1000 * 1000); } diff --git a/src/bmp180.c b/src/bmp180.c index 9b1d3b8..4643600 100644 --- a/src/bmp180.c +++ b/src/bmp180.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #endif @@ -160,6 +162,9 @@ typedef struct { int32_t mb; int32_t mc; int32_t md; + + /* Last errno */ + int error; } bmp180_t; @@ -289,7 +294,13 @@ void bmp180_read_eprom(void *_bmp) { */ int32_t bmp180_read_raw_temperature(void *_bmp) { bmp180_t* bmp = TO_BMP(_bmp); - i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, BMP180_TMP_READ_CMD); + + bmp->error = i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, BMP180_TMP_READ_CMD); + if (bmp->error < 0) { + DEBUG("error: i2c_smbus_write_byte_data failed with error %d\n", bmp->error); + bmp->error *= -1; + return -1; + } usleep(BMP180_TMP_READ_WAIT_US); int32_t data = i2c_smbus_read_word_data(bmp->file, BMP180_REG_TMP) & 0xFFFF; @@ -329,7 +340,12 @@ int32_t bmp180_read_raw_pressure(void *_bmp, uint8_t oss) { break; } - i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, cmd); + bmp->error = i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, cmd); + if (bmp->error < 0) { + DEBUG("error: i2c_smbus_write_byte_data failed with error %d\n", bmp->error); + bmp->error *= -1; + return -1; + } usleep(wait); @@ -421,6 +437,7 @@ void *bmp180_init(int address, const char* i2c_device_filepath) { DEBUG("device: open ok\n"); + bmp->error = 0; return _bmp; } @@ -449,6 +466,22 @@ void bmp180_close(void *_bmp) { } +/** + * Determine if the last BMP180 operation was successful. + * + * @param bmp180 sensor + * + * @ret 0 if the last operation was successful; otherwise the errno from the + * last failed operation + */ + +int bmp180_get_last_errno(void *_bmp) +{ + bmp180_t* bmp = TO_BMP(_bmp); + return bmp->error; +} + + /** * Returns the measured temperature in celsius. * @@ -461,6 +494,9 @@ float bmp180_temperature(void *_bmp) { float T; UT = bmp180_read_raw_temperature(_bmp); + if (bmp->error != 0) { + return -FLT_MAX; // error + } DEBUG("UT=%lu\n",UT); @@ -485,7 +521,14 @@ long bmp180_pressure(void *_bmp) { unsigned long B4, B7; UT = bmp180_read_raw_temperature(_bmp); + if (bmp->error != 0) { + return LONG_MIN; // error + } + UP = bmp180_read_raw_pressure(_bmp, bmp->oss); + if (bmp->error != 0) { + return LONG_MIN; // error + } X1 = ((UT - bmp->ac6) * bmp->ac5) >> 15; X2 = (bmp->mc << 11) / (X1 + bmp->md); @@ -530,8 +573,14 @@ long bmp180_pressure(void *_bmp) { * @return altitude */ float bmp180_altitude(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); float p, alt; + p = bmp180_pressure(_bmp); + if (bmp->error != 0) { + return -FLT_MAX; // error + } + alt = 44330 * (1 - pow(( (p/100) / BMP180_SEA_LEVEL),1/5.255)); return alt; diff --git a/src/bmp180.h b/src/bmp180.h index 75aa2c9..68cc5b5 100644 --- a/src/bmp180.h +++ b/src/bmp180.h @@ -42,5 +42,7 @@ float bmp180_temperature(void *_bmp); float bmp180_altitude(void *_bmp); +int bmp180_get_last_errno(void *_bmp); + void bmp180_dump_eprom(void *_bmp, bmp180_eprom_t *eprom); diff --git a/src/test.c b/src/test.c index ae5f964..667d233 100644 --- a/src/test.c +++ b/src/test.c @@ -1,6 +1,8 @@ #include "bmp180.h" #include #include +#include +#include int main(int argc, char **argv){ char *i2c_device = "/dev/i2c-1"; @@ -15,11 +17,29 @@ int main(int argc, char **argv){ bmp180_set_oss(bmp, 1); if(bmp != NULL){ - int i; + int i, error; for(i = 0; i < 10; i++) { float t = bmp180_temperature(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading temperature: %s\n", strerror(error)); + exit(1); + } + long p = bmp180_pressure(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading pressure: %s\n", strerror(error)); + exit(1); + } + float alt = bmp180_altitude(bmp); + error = bmp180_get_last_errno(bmp); + if (error != 0) { + printf("Error reading altitude: %s\n", strerror(error)); + exit(1); + } + printf("t = %f, p = %lu, a= %f\n", t, p, alt); usleep(2 * 1000 * 1000); }