diff --git a/drivers/sensor/ccs811/ccs811.c b/drivers/sensor/ccs811/ccs811.c index a6cc701a56d..c878ba62a88 100644 --- a/drivers/sensor/ccs811/ccs811.c +++ b/drivers/sensor/ccs811/ccs811.c @@ -86,6 +86,7 @@ int ccs811_baseline_fetch(struct device *dev) if (rc <= 0) { rc = baseline; } + return rc; } @@ -104,6 +105,74 @@ int ccs811_baseline_update(struct device *dev, return rc; } +int ccs811_envdata_update(struct device *dev, + const struct sensor_value *temperature, + const struct sensor_value *humidity) +{ + struct ccs811_data *drv_data = dev->driver_data; + int rc; + u8_t buf[5] = { CCS811_REG_ENV_DATA }; + + /* + * Environment data are represented in a broken whole/fraction + * system that specified a 9-bit fractional part to represent + * milli-units. Since 1000 is greater than 512, the device + * actually only pays attention to the top bit, treating it as + * indicating 0.5. So we only write the first octet (7-bit + * while plus 1-bit half). + * + * Humidity is simple: scale it by two and round to the + * nearest half. Assume the fractional part is not + * negative. + */ + if (humidity) { + int value = 2 * humidity->val1; + + value += (250000 + humidity->val2) / 500000; + if (value < 0) { + value = 0; + } else if (value > (2 * 100)) { + value = 2 * 100; + } + LOG_DBG("HUM %d.%06d becomes %d", + humidity->val1, humidity->val2, value); + buf[1] = value; + } else { + buf[1] = 2 * 50; + } + + /* + * Temperature is offset from -25 Cel. Values below minimum + * store as zero. Default is 25 Cel. Again we round to the + * nearest half, complicated by Zephyr's signed representation + * of the fractional part. + */ + if (temperature) { + int value = 2 * temperature->val1; + + if (temperature->val2 < 0) { + value += (250000 + temperature->val2) / 500000; + } else { + value += (-250000 + temperature->val2) / 500000; + } + if (value < (2 * -25)) { + value = 0; + } else { + value += 2 * 25; + } + LOG_DBG("TEMP %d.%06d becomes %d", + temperature->val1, temperature->val2, value); + buf[3] = value; + } else { + buf[3] = 2 * (25 + 25); + } + + set_wake(drv_data, true); + rc = i2c_write(drv_data->i2c, buf, sizeof(buf), DT_INST_0_AMS_CCS811_BASE_ADDRESS); + set_wake(drv_data, false); + return rc; +} + static int ccs811_sample_fetch(struct device *dev, enum sensor_channel chan) { struct ccs811_data *drv_data = dev->driver_data; diff --git a/drivers/sensor/ccs811/ccs811.h b/drivers/sensor/ccs811/ccs811.h index bb8aea453ce..486cff71915 100644 --- a/drivers/sensor/ccs811/ccs811.h +++ b/drivers/sensor/ccs811/ccs811.h @@ -17,6 +17,7 @@ #define CCS811_REG_MEAS_MODE 0x01 #define CCS811_REG_ALG_RESULT_DATA 0x02 #define CCS811_REG_RAW_DATA 0x03 +#define CCS811_REG_ENV_DATA 0x05 #define CCS811_REG_THRESHOLDS 0x10 #define CCS811_REG_BASELINE 0x11 #define CCS811_REG_HW_ID 0x20 diff --git a/include/drivers/sensor/ccs811.h b/include/drivers/sensor/ccs811.h index eefcf103af5..47e4074c957 100644 --- a/include/drivers/sensor/ccs811.h +++ b/include/drivers/sensor/ccs811.h @@ -20,6 +20,7 @@ extern "C" { #endif #include +#include /** * @brief Fetch the current value of the BASELINE register. @@ -51,6 +52,24 @@ int ccs811_baseline_fetch(struct device *dev); */ int ccs811_baseline_update(struct device *dev, u16_t baseline); +/** + * @brief Update the ENV_DATA register. + * + * Accurate calculation of gas levels requires accurate environment + * data. Measurements are only accurate to 0.5 Cel and 0.5 %RH. + * + * @param dev Pointer to the sensor device + * + * @param temperature the current temperature at the sensor + * + * @param humidity the current humidity at the sensor + * + * @return 0 if successful, negative errno code if failure. + */ +int ccs811_envdata_update(struct device *dev, + const struct sensor_value *temperature, + const struct sensor_value *humidity); + #ifdef __cplusplus } #endif