diff --git a/sensors/barometer/README.md b/sensors/barometer/README.md index 34b8ae7..4fff0e2 100644 --- a/sensors/barometer/README.md +++ b/sensors/barometer/README.md @@ -13,6 +13,7 @@ void application_init() { // 1. The sensor doesn't respond on i2c bus // 2. DevID register returns wrong value // 3. Calibration registers cannot be read successfully + return; } } diff --git a/sensors/barometer/bmp280.c b/sensors/barometer/bmp280.c index 076f7a2..6f7a1cf 100644 --- a/sensors/barometer/bmp280.c +++ b/sensors/barometer/bmp280.c @@ -87,19 +87,22 @@ static BarometerBmp280Instance bmp280; int8_t bmp280Init() { + bmp280.stale_counter = 0; + bmp280.dev_id_confirmed = false; + if (_checkDeviceId() < 0) { - return LIBPERIPH_BPM280_INIT_CHECK_DEV_ID_ERROR; + return -LIBPERIPH_BPM280_INIT_CHECK_DEV_ID_ERROR; } if (_setCtrlMeas() < 0) { - return LIBPERIPH_BPM280_INIT_SET_CTRL_MEAS_ERROR; + return -LIBPERIPH_BPM280_INIT_SET_CTRL_MEAS_ERROR; } if (_calibrate() < 0) { - return LIBPERIPH_BPM280_INIT_CALIBRATION_ERROR; + return -LIBPERIPH_BPM280_INIT_CALIBRATION_ERROR; } - return (bmp280IsInitialized()) ? LIBPERIPH_BPM280_OK : LIBPERIPH_BPM280_INIT_WRONG_DEV_ID; + return (bmp280IsInitialized()) ? LIBPERIPH_BPM280_OK : -LIBPERIPH_BPM280_INIT_WRONG_DEV_ID; } bool bmp280IsInitialized() { @@ -107,26 +110,28 @@ bool bmp280IsInitialized() { } int8_t bmp280GetData(BarometerMeasurements* out_data) { - if (bmp280CollectData() < 0) { - return -1; + int8_t res = bmp280CollectData(); + if (res < 0) { + return res; } - if (bmp280ParseCollectedData(out_data) < 0) { - return -1; + res = bmp280ParseCollectedData(out_data); + if (res < 0) { + return res; } - return 0; + return bmp280VerifyData(out_data); } int8_t bmp280CollectData() { uint8_t tx[1] = {PRESS_REG}; if (i2cTransmit(I2C_ID, tx, 1) < 0) { - return LIBPERIPH_BPM280_NO_RESPONSE; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } BMP280_measurement_registers_t data = {}; if (i2cReceive(I2C_ID + 1, (uint8_t*)&data, 6) < 0) { - return LIBPERIPH_BPM280_NO_RESPONSE; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } BarometerMeasurements temp = { @@ -148,7 +153,7 @@ int8_t bmp280CollectData() { int8_t bmp280ParseCollectedData(BarometerMeasurements* out_data) { if (out_data == NULL) { - return -1; + return -LIBPERIPH_BPM280_INTERNAL_ERROR; } float ofs = bmp280.raw.temperature - bmp280.calib.t[0]; @@ -159,29 +164,29 @@ int8_t bmp280ParseCollectedData(BarometerMeasurements* out_data) { float x1 = (tf * bmp280.calib.p[5] + bmp280.calib.p[4]) * tf + bmp280.calib.p[3]; float x2 = (tf * bmp280.calib.p[2] + bmp280.calib.p[1]) * tf + bmp280.calib.p[0]; if (x2 == 0) { - return -1; + return -LIBPERIPH_BPM280_INTERNAL_ERROR; } float pf = (bmp280.raw.pressure + x1) / x2; out_data->pressure = (pf * bmp280.calib.p[8] + bmp280.calib.p[7]) * pf + bmp280.calib.p[6]; - return 0; + return LIBPERIPH_BPM280_OK; } int8_t bmp280VerifyData(const BarometerMeasurements* data) { if (data->pressure < 30000 || data->pressure > 110000) { - return -1; // out of bound + return -LIBPERIPH_BPM280_VERIFICATION_PRESSURE_OUT_OF_BOUND; } if (data->temperature < 233 || data->temperature > 368) { - return -1; // out of bound + return -LIBPERIPH_BPM280_VERIFICATION_TEMPERATURE_OUT_OF_BOUND; } if (bmp280.stale_counter >= 10) { - return -1; // stale + return -LIBPERIPH_BPM280_VERIFICATION_STALE; } - return 0; + return LIBPERIPH_BPM280_OK; } @@ -192,17 +197,17 @@ int8_t bmp280VerifyData(const BarometerMeasurements* data) { static int8_t _checkDeviceId() { uint8_t tx[1] = {ID_REG}; if (i2cTransmit(I2C_ID, tx, 1) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } uint8_t rx[1] = {0}; if (i2cReceive(I2C_ID, rx, 1) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } bmp280.dev_id_confirmed = (rx[0] == DEVICE_ID) ? true : false; - return 0; + return LIBPERIPH_BPM280_OK; } /** @@ -211,15 +216,15 @@ static int8_t _checkDeviceId() { static int8_t _setCtrlMeas() { uint8_t tx[2] = {CTRL_MEAS_REG, CTRL_MEAS_SETTINGS}; if (i2cTransmit(I2C_ID, tx, 2) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } uint8_t rx[1] = {0}; if (i2cReceive(I2C_ID, rx, 1) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } - return 0; + return LIBPERIPH_BPM280_OK; } /** @@ -228,12 +233,12 @@ static int8_t _setCtrlMeas() { static int8_t _calibrate() { uint8_t tx[1] = {0x88}; if (i2cTransmit(I2C_ID, tx, 1) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } TrimmingParameters_t params; if (i2cReceive(I2C_ID, (uint8_t*)(¶ms), 24) < 0) { - return -1; + return -LIBPERIPH_BPM280_I2C_NO_RESPONSE; } bmp280.calib.t[0] = params.dig_T1 * powf(2, 4); @@ -252,5 +257,5 @@ static int8_t _calibrate() { bmp280.calib.p[7] = params.dig_P8 * powf(2, -19) + 1.0f; bmp280.calib.p[8] = params.dig_P9 * powf(2, -35); - return 0; + return LIBPERIPH_BPM280_OK; } diff --git a/sensors/barometer/bmp280.h b/sensors/barometer/bmp280.h index 5a74955..7586d45 100644 --- a/sensors/barometer/bmp280.h +++ b/sensors/barometer/bmp280.h @@ -17,19 +17,31 @@ extern "C" { #define BMP280_MAX_MEASUREMENT_FREQUENCY 50 -#define LIBPERIPH_BPM280_OK 0 -#define LIBPERIPH_BPM280_NO_RESPONSE -1 -#define LIBPERIPH_BPM280_BAD_RESPONSE -2 -#define LIBPERIPH_BPM280_INIT_CHECK_DEV_ID_ERROR -10 -#define LIBPERIPH_BPM280_INIT_SET_CTRL_MEAS_ERROR -11 -#define LIBPERIPH_BPM280_INIT_CALIBRATION_ERROR -12 -#define LIBPERIPH_BPM280_INIT_WRONG_DEV_ID -13 +typedef enum { + LIBPERIPH_BPM280_OK = 0, + LIBPERIPH_BPM280_UNKNOWN_ERRROR = 1, + + LIBPERIPH_BPM280_I2C_NO_RESPONSE = 2, + + LIBPERIPH_BPM280_INIT_CHECK_DEV_ID_ERROR = 10, + LIBPERIPH_BPM280_INIT_SET_CTRL_MEAS_ERROR = 11, + LIBPERIPH_BPM280_INIT_CALIBRATION_ERROR = 12, + LIBPERIPH_BPM280_INIT_WRONG_DEV_ID = 13, + + LIBPERIPH_BPM280_VERIFICATION_PRESSURE_OUT_OF_BOUND = 20, + LIBPERIPH_BPM280_VERIFICATION_TEMPERATURE_OUT_OF_BOUND = 21, + LIBPERIPH_BPM280_VERIFICATION_STALE = 22, + + LIBPERIPH_BPM280_INTERNAL_ERROR = 127, +} Bpm280ErrorCode; + typedef struct { float pressure; float temperature; } BarometerMeasurements; + /** * @brief Initialize the device including: * 1. Check device ID @@ -44,31 +56,19 @@ bool bmp280IsInitialized(); /** - * @brief Collect data from i2c and parse it + * @brief Collect data from i2c, parse it and verify * @param[out] out_data - pressure in Pascal and temperature in Kelvin * @return LIBPERIPH_BPM280_OK on success, otherwise error code < 0 + * @note Sequentially call bmp280CollectData, bmp280ParseCollectedData and bmp280VerifyData. */ int8_t bmp280GetData(BarometerMeasurements* out_data); /** - * @brief Collect data - * @return LIBPERIPH_BPM280_OK on success, otherwise error code < 0 - */ -int8_t bmp280CollectData(); - - -/** - * @param[out] out_data - Barometer parsed measurements - * @return LIBPERIPH_BPM280_OK on success, otherwise error code < 0 - */ -int8_t bmp280ParseCollectedData(BarometerMeasurements* out_data); - - -/** + * @brief Alternatively, you can collect, parse and verify the measurements separately * @param[in] data - barometer measurements * @return LIBPERIPH_BPM280_OK on success, otherwise error code < 0 - * @note A few checks: + * @note The verification consist of: * 1. Verify that the Pressure in range within [30.000, 110.000] Pascal * (equiv. to +9000 .. -500 m above/below sea level) * @@ -77,6 +77,8 @@ int8_t bmp280ParseCollectedData(BarometerMeasurements* out_data); * * 3. Verify that the measurements are not stale */ +int8_t bmp280CollectData(); +int8_t bmp280ParseCollectedData(BarometerMeasurements* out_data); int8_t bmp280VerifyData(const BarometerMeasurements* data); #ifdef __cplusplus diff --git a/tests/sensors/test_bmp280.cpp b/tests/sensors/test_bmp280.cpp index 2f6411a..dd248b7 100644 --- a/tests/sensors/test_bmp280.cpp +++ b/tests/sensors/test_bmp280.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 Dmitry Ponomarev + * Copyright (C) 2021-2024 Dmitry Ponomarev * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. @@ -13,27 +13,51 @@ struct Bmp280 : public SitlI2CSensor { Bmp280() : SitlI2CSensor(0xC4) {} int8_t callback_on_i2c_transmit(uint8_t id, const uint8_t tx[], uint8_t len) override { + if (len > 0) { + latest_reg = tx[0]; + } return i2c_tx_status; } int8_t callback_on_i2c_receive(uint8_t id, uint8_t* rx, uint8_t len) override { + if (latest_reg == 0xF7 && len == 6) { + // we can fill pressure and temperature here + } return i2c_rx_status; } + uint8_t latest_reg = 0; int8_t i2c_tx_status = 0; int8_t i2c_rx_status = 0; }; static Bmp280 bmp280; -TEST(BMP280, test_bmp280ParseCollectedData_normal) { +TEST(BMP280, test_bmp280IsInitialized) { + ASSERT_FALSE(bmp280IsInitialized()); +} + +TEST(BMP280, test_bmp280GetData) { bmp280.i2c_tx_status = 0; bmp280.i2c_rx_status = 0; bmp280Init(); - ASSERT_TRUE(bmp280CollectData() >= 0); BarometerMeasurements data; - bmp280ParseCollectedData(&data); + ASSERT_EQ(bmp280GetData(&data), -LIBPERIPH_BPM280_VERIFICATION_PRESSURE_OUT_OF_BOUND); +} + +TEST(BMP280, test_bmp280ParseCollectedData) { + bmp280.i2c_tx_status = 0; + bmp280.i2c_rx_status = 0; + bmp280Init(); + ASSERT_EQ(bmp280CollectData(), LIBPERIPH_BPM280_OK); + BarometerMeasurements data; + + // Normal + ASSERT_EQ(bmp280ParseCollectedData(&data), LIBPERIPH_BPM280_OK); + + // Bad argument + ASSERT_EQ(bmp280ParseCollectedData(NULL), -LIBPERIPH_BPM280_INTERNAL_ERROR); } TEST(BMP280, test_bmp280CollectData_no_rx_response) { @@ -54,8 +78,25 @@ TEST(BMP280, test_bmp280CollectData_no_tx_response) { ASSERT_FALSE(bmp280CollectData() >= 0); } -TEST(BMP280, test_bmp280IsInitialized) { - ASSERT_FALSE(bmp280IsInitialized()); +TEST(BMP280, test_bmp280VerifyData) { + bmp280Init(); // reset internal state + BarometerMeasurements data; + + // Normal + data = BarometerMeasurements{100000, 273}; + ASSERT_EQ(bmp280VerifyData(&data), LIBPERIPH_BPM280_OK); + + // Pressure out of bound + data = BarometerMeasurements{29999, 273}; + ASSERT_EQ(bmp280VerifyData(&data), -LIBPERIPH_BPM280_VERIFICATION_PRESSURE_OUT_OF_BOUND); + data = BarometerMeasurements{110001, 273}; + ASSERT_EQ(bmp280VerifyData(&data), -LIBPERIPH_BPM280_VERIFICATION_PRESSURE_OUT_OF_BOUND); + + // Temperature out of bound + data = BarometerMeasurements{100000, 232}; + ASSERT_EQ(bmp280VerifyData(&data), -LIBPERIPH_BPM280_VERIFICATION_TEMPERATURE_OUT_OF_BOUND); + data = BarometerMeasurements{100000, 369}; + ASSERT_EQ(bmp280VerifyData(&data), -LIBPERIPH_BPM280_VERIFICATION_TEMPERATURE_OUT_OF_BOUND); }