From c4325e4d5e639b6a00198b80f9b6b1c9bbc14e33 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 12 Mar 2020 08:46:56 +0100 Subject: [PATCH] drivers/bme680: add SAUL capabilities --- drivers/Makefile.dep | 3 + drivers/bme680/bme680_saul.c | 210 +++++++++++++++++++++++++ drivers/bme680/include/bme680_params.h | 21 +++ drivers/include/bme680.h | 2 +- 4 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 drivers/bme680/bme680_saul.c diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4785c7a9de..4f98703452 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -97,6 +97,9 @@ endif ifneq (,$(filter bme680_%,$(USEMODULE))) USEPKG += driver_bme680 USEMODULE += bme680 + ifneq (,$(filter saul%,$(USEMODULE))) + USEMODULE += xtimer + endif endif ifneq (,$(filter bme680_i2c,$(USEMODULE))) diff --git a/drivers/bme680/bme680_saul.c b/drivers/bme680/bme680_saul.c new file mode 100644 index 0000000000..024d22f401 --- /dev/null +++ b/drivers/bme680/bme680_saul.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_bme680 + * @brief SAUL adaption for BME680 devices + * @author Gunar Schorcht + * @file + */ + +#include +#include +#include + +#include "phydat.h" +#include "saul.h" +#include "bme680.h" +#include "bme680_params.h" +#include "xtimer.h" + +extern bme680_t bme680_devs_saul[BME680_NUMOF]; + +/** + * Temperature, pressure, humidity and gas sensor values are fetched by separate + * saul functions. To avoid multiple waiting for the sensor, we read all sensor + * values once, if necessary, and store them in local variables to provide them + * in the separate saul read functions. + */ +static bool _temp_valid[BME680_NUMOF] = { false }; +static bool _press_valid[BME680_NUMOF] = { false }; +static bool _hum_valid[BME680_NUMOF] = { false }; +static bool _gas_valid[BME680_NUMOF] = { false }; +static int16_t _temp[BME680_NUMOF]; +static int16_t _press[BME680_NUMOF]; +static int16_t _hum[BME680_NUMOF]; +static uint32_t _gas[BME680_NUMOF]; + +static unsigned _dev2index (const bme680_t *dev) +{ + /* + * returns the index of the device in bme680_devs_saul[] or BME680_NUMOF + * if not found + */ + for (unsigned i = 0; i < BME680_NUMOF; i++) { + if (dev == &bme680_devs_saul[i]) { + return i; + } + } + return BME680_NUMOF; +} + +static int read(int dev) +{ + /* measure and read sensor values */ + int res; + if ((res = bme680_force_measurement(&bme680_devs_saul[dev])) != BME680_OK) { + return res; + } + int drt; + if ((drt = bme680_get_duration(&bme680_devs_saul[dev])) < 0) { + return BME680_INVALID; + } + xtimer_usleep(drt * US_PER_MS); + + bme680_field_data_t data; + if ((res = bme680_get_data(&bme680_devs_saul[dev], &data)) != BME680_OK) { + return res; + } + +#if MODULE_BME680_FP + _temp[dev] = data.temperature * 100; + _press[dev] = data.pressure / 100; + _hum[dev] = data.humidity * 100; +#else + _temp[dev] = data.temperature; + _press[dev] = data.pressure / 100; + _hum[dev] = data.humidity / 10; +#endif + _gas[dev] = (data.status & BME680_GASM_VALID_MSK) ? data.gas_resistance : 0; + + /* mark sensor values as valid */ + _temp_valid[dev] = true; + _press_valid[dev] = true; + _hum_valid[dev] = true; + _gas_valid[dev] = true; + return BME680_OK; +} + +static int read_temp(const void *dev, phydat_t *data) +{ + /* find the device index */ + unsigned dev_index = _dev2index((const bme680_t *)dev); + if (dev_index == BME680_NUMOF) { + /* return with error if device index could not be found */ + return -ECANCELED; + } + + /* either local variable is valid or fetching it was successful */ + if (_temp_valid[dev_index] || read(dev_index) == BME680_OK) { + /* mark local variable as invalid */ + _temp_valid[dev_index] = false; + + data->val[0] = _temp[dev_index]; + data->unit = UNIT_TEMP_C; + data->scale = -2; + return 1; + } + return -ECANCELED; +} + +static int read_press(const void *dev, phydat_t *data) +{ + /* find the device index */ + unsigned dev_index = _dev2index((const bme680_t *)dev); + if (dev_index == BME680_NUMOF) { + /* return with error if device index could not be found */ + return -ECANCELED; + } + + /* either local variable is valid or fetching it was successful */ + if (_press_valid[dev_index] || read(dev_index) == BME680_OK) { + /* mark local variable as invalid */ + _press_valid[dev_index] = false; + + data->val[0] = _press[dev_index]; + data->unit = UNIT_PA; + data->scale = 2; + return 1; + } + return -ECANCELED; +} + +static int read_hum(const void *dev, phydat_t *data) +{ + /* find the device index */ + unsigned dev_index = _dev2index((const bme680_t *)dev); + if (dev_index == BME680_NUMOF) { + /* return with error if device index could not be found */ + return -ECANCELED; + } + + /* either local variable is valid or fetching it was successful */ + if (_hum_valid[dev_index] || read(dev_index) == BME680_OK) { + /* mark local variable as invalid */ + _hum_valid[dev_index] = false; + + data->val[0] = _hum[dev_index]; + data->unit = UNIT_PERCENT; + data->scale = -2; + return 1; + } + return -ECANCELED; +} + +static int read_gas(const void *dev, phydat_t *data) +{ + /* find the device index */ + unsigned dev_index = _dev2index((const bme680_t *)dev); + if (dev_index == BME680_NUMOF) { + /* return with error if device index could not be found */ + return -ECANCELED; + } + + /* either local variable is valid or fetching it was successful */ + if (_gas_valid[dev_index] || read(dev_index) == BME680_OK) { + /* mark local variable as invalid */ + _gas_valid[dev_index] = false; + + if (_gas[dev_index] > INT16_MAX) { + data->val[0] = _gas[dev_index] / 1000; + data->scale = 3; + } + else { + data->val[0] = _gas[dev_index]; + data->scale = 0; + } + data->unit = UNIT_OHM; + return 1; + } + return -ECANCELED; +} + +const saul_driver_t bme680_saul_driver_temperature = { + .read = read_temp, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP +}; + +const saul_driver_t bme680_saul_driver_pressure = { + .read = read_press, + .write = saul_notsup, + .type = SAUL_SENSE_PRESS +}; + +const saul_driver_t bme680_saul_driver_humidity = { + .read = read_hum, + .write = saul_notsup, + .type = SAUL_SENSE_HUM +}; + +const saul_driver_t bme680_saul_driver_gas = { + .read = read_gas, + .write = saul_notsup, + .type = SAUL_SENSE_GAS +}; diff --git a/drivers/bme680/include/bme680_params.h b/drivers/bme680/include/bme680_params.h index 5dfafd0674..e4f1ee4907 100644 --- a/drivers/bme680/include/bme680_params.h +++ b/drivers/bme680/include/bme680_params.h @@ -23,6 +23,7 @@ #include "board.h" #include "bme680.h" +#include "saul_reg.h" #ifdef __cplusplus extern "C" { @@ -96,6 +97,18 @@ extern "C" { .intf.spi.dev = BME680_PARAM_SPI_DEV, \ .intf.spi.nss_pin = BME680_PARAM_SPI_NSS_PIN, \ } + +/** + * @brief Default SAUL meta information + */ +#ifndef BME680_SAUL_INFO +#if MODULE_BME680_I2C && MODULE_BME680_SPI +#define BME680_SAUL_INFO { .name = "bme680:0" }, \ + { .name = "bme680:1" }, +#else /* MODULE_BME680_I2C && MODULE_BME680_SPI */ +#define BME680_SAUL_INFO { .name = "bme680" } +#endif /* MODULE_BME680_I2C && MODULE_BME680_SPI */ +#endif /* BME680_SAUL_INFO */ /**@}*/ /** @@ -111,6 +124,14 @@ static const bme680_params_t bme680_params[] = #endif }; +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t bme680_saul_info[] = +{ + BME680_SAUL_INFO +}; + /** * @brief The number of configured sensors */ diff --git a/drivers/include/bme680.h b/drivers/include/bme680.h index 9844220870..8271a86db9 100644 --- a/drivers/include/bme680.h +++ b/drivers/include/bme680.h @@ -10,7 +10,7 @@ /** * @defgroup drivers_bme680 BME680 Temperature/Humidity/Pressure/Gas sensor * @ingroup drivers_sensors - * @brief Driver for the Bosch BME680 sensor + * @brief Driver for the Bosch BME680 sensor * * ### Introduction *