commit b726d03136d0df8e02520f1c7b6a36a055d7dc78 Author: imi415 Date: Fri Jul 22 09:29:28 2022 +0800 Initial commit. diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d0e0eda --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: Google +IndentWidth: 4 +AlignConsecutiveMacros: Consecutive +AlignConsecutiveDeclarations: true +AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: false +BreakBeforeBraces: Custom +BraceWrapping: + AfterEnum: false + AfterStruct: false + SplitEmptyFunction: false +ColumnLimit: 120 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..07d99c4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.15) + +project(imsensors) + +option(IMSENSORS_FLOAT_SUPPORT "Enable floating point support" OFF) + +set(IMSENSORS_SRCS + "src/dht/dht_bme280.c" +) + +set(IMSENSORS_INCS + "include/imsensors" + "include/imsensors/dht" +) + +set(IMSENSORS_INTF_INCS + "include" +) + +set(IMSENSORS_DEFS + +) + +set(IMSENSORS_FLOAT_DEFS + "IMS_CFG_DHT_BME280_ENABLE_FLOAT" + "IMS_CFG_DHT_AHT10_ENABLE_FLOAT" +) + +add_library(${PROJECT_NAME} ${IMSENSORS_SRCS}) + +target_include_directories(${PROJECT_NAME} + PRIVATE ${IMSENSORS_INCS} + PUBLIC ${IMSENSORS_INTF_INCS} +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE ${IMSENSORS_DEFS} +) + +if(IMSENSORS_FLOAT_SUPPORT) + target_compile_definitions(${PROJECT_NAME} PRIVATE ${IMSENSORS_FLOAT_DEFS}) +endif() \ No newline at end of file diff --git a/include/imsensors/dht/dht_aht10.h b/include/imsensors/dht/dht_aht10.h new file mode 100644 index 0000000..f83ddef --- /dev/null +++ b/include/imsensors/dht/dht_aht10.h @@ -0,0 +1,42 @@ +#ifndef AHT10_H +#define AHT10_H + +#include + +#define AHT10_SKIP_BUSY_CHECK + +typedef enum { + AHT10_OK, + AHT10_FAIL, +} aht10_ret_t; + +typedef struct { + uint8_t *tx_data; + uint8_t *rx_data; + uint16_t tx_size; + uint16_t rx_size; +} aht10_xfer_desc_t; + +typedef aht10_ret_t (*aht10_i2c_xfer_t)(void *pdev, aht10_xfer_desc_t *xfer); +typedef aht10_ret_t (*aht10_delay_t)(void *pdev, uint32_t delay_msec); + +typedef struct { + double temperature; + double humidity; +} aht10_result_t; + +typedef struct { + aht10_i2c_xfer_t xfer; + aht10_delay_t delay; +} aht10_cb_t; + +typedef struct { + aht10_cb_t cb; + void *user_data; +} aht10_t; + +aht10_ret_t aht10_init(aht10_t *aht); +aht10_ret_t aht10_measure(aht10_t *aht, aht10_result_t *result); + + +#endif \ No newline at end of file diff --git a/include/imsensors/dht/dht_bme280.h b/include/imsensors/dht/dht_bme280.h new file mode 100644 index 0000000..ee3bcc8 --- /dev/null +++ b/include/imsensors/dht/dht_bme280.h @@ -0,0 +1,88 @@ +#ifndef ims_bme280_DHT_H +#define ims_bme280_DHT_H + +#include "sensors_common.h" + +typedef enum { + IMS_BME280_MODE_SLEEP, + IMS_BME280_MODE_FORCED, + IMS_BME280_MODE_NORMAL, +} ims_bme280_mode_t; + +typedef enum { + IMS_BME280_OSRS_SKIP, + IMS_BME280_OSRS_1, + IMS_BME280_OSRS_2, + IMS_BME280_OSRS_4, + IMS_BME280_OSRS_8, + IMS_BME280_OSRS_16, +} ims_bme280_osrs_config_t; + +typedef enum { + IMS_BME280_FILTER_OFF, + IMS_BME280_FILTER_2, + IMS_BME280_FILTER_4, + IMS_BME280_FILTER_8, + IMS_BME280_FILTER_16, +} ims_bme280_fiter_config_t; + +typedef enum { + IMS_BME280_PRESET_WEATHER, + IMS_BME280_PRESET_HUMIDITY, + IMS_BME280_PRESET_INDOOR_NAV, + IMS_BME280_PRESET_GAMING, +} ims_bme280_mode_preset_t; + +typedef struct { + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; +} ims_bme280_trim_t; + +typedef struct { + ims_bme280_mode_t mode; + ims_bme280_osrs_config_t osrs_t; + ims_bme280_osrs_config_t osrs_p; + ims_bme280_osrs_config_t osrs_h; + uint8_t t_sb; + ims_bme280_fiter_config_t filter; +} ims_bme280_config_t; + +typedef struct { + double temperature; + double pressure; + double humidity; +} ims_bme280_result_t; + +typedef struct { + ims_i2c_xfer_t i2c_xfer; +} ims_bme280_cb_t; + +typedef struct { + void *user_data; + ims_bme280_trim_t trim; + ims_bme280_cb_t cb; + int32_t t_fine; +} ims_bme280_t; + +ims_ret_t ims_bme280_init(ims_bme280_t *bme); +ims_ret_t ims_bme280_preset_config(ims_bme280_config_t *config, ims_bme280_mode_preset_t preset); +ims_ret_t ims_bme280_apply_config(ims_bme280_t *bme, ims_bme280_config_t *config); +ims_ret_t ims_bme280_measure(ims_bme280_t *bme, ims_bme280_result_t *result); + +#endif \ No newline at end of file diff --git a/include/imsensors/sensors_common.h b/include/imsensors/sensors_common.h new file mode 100644 index 0000000..d2cde6e --- /dev/null +++ b/include/imsensors/sensors_common.h @@ -0,0 +1,24 @@ +#ifndef SENSORS_COMMON_H +#define SENSORS_COMMON_H + +#include + +typedef enum { + IMS_SUCCESS, + IMS_FAIL, +} ims_ret_t; + +typedef struct { + uint8_t *tx_data; + uint8_t *rx_data; + uint16_t tx_size; + uint16_t rx_size; +} ims_i2c_xfer_desc_t; + +/* I2C xfer functions */ +typedef ims_ret_t (*ims_i2c_xfer_t)(void *pdev, uint16_t addr, ims_i2c_xfer_desc_t *xfer); + +/* Delay */ +typedef ims_ret_t (*ims_delay_t)(void *pdev, uint32_t delay_msec); + +#endif \ No newline at end of file diff --git a/src/dht/dht_aht10.c b/src/dht/dht_aht10.c new file mode 100644 index 0000000..b2879b3 --- /dev/null +++ b/src/dht/dht_aht10.c @@ -0,0 +1,135 @@ +#include + +/* Private header */ +#include "aht10.h" + +#define AHT10_STATUS_CALIBRATED_MASK (1U << 3U) +#define AHT10_STATUS_BUSY_MASK (1U << 7U) + +#define AHT10_ERROR_CHECK(x) \ + if (x != AHT10_OK) return AHT10_FAIL + +typedef struct { + uint8_t status; + uint32_t temperature; + uint32_t humidity; +} aht10_raw_t; + +static aht10_ret_t aht10_software_reset(aht10_t *aht) { + /* Reset and initialize device */ + + uint8_t tx_data[3] = {0xBA}; + + aht10_xfer_desc_t xfer = { + .tx_data = tx_data, + .tx_size = 1U, + .rx_data = NULL, + .rx_size = 0U, + }; + + AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer)); + + AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 20)); + + tx_data[0] = 0xE1; + tx_data[1] = 0x08; + tx_data[2] = 0x00; + + xfer.tx_size = 3U; + + AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer)); + + return AHT10_OK; +} + +static aht10_ret_t aht10_start_measurement(aht10_t *aht) { + /* Start measurement */ + + uint8_t tx_data[3] = {0xAC, 0x33, 0x00}; + + aht10_xfer_desc_t xfer = { + .tx_data = tx_data, + .tx_size = 3U, + .rx_data = NULL, + .rx_size = 0U, + }; + + AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer)); + + return AHT10_OK; +} + +static aht10_ret_t aht10_read_result(aht10_t *aht, aht10_raw_t *raw) { + /* Read conversion result */ + + uint8_t tx_data[] = {0x71}; + uint8_t rx_data[6]; + + aht10_xfer_desc_t xfer = { + .tx_data = tx_data, + .tx_size = 1U, + .rx_data = rx_data, + .rx_size = 6U, + }; + + AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer)); + + raw->humidity = rx_data[1] << 12U; + raw->humidity |= rx_data[2] << 4U; + raw->humidity |= rx_data[3] >> 4U; + + raw->temperature = (rx_data[3] & 0x0FU) << 16U; + raw->temperature |= rx_data[4] << 8U; + raw->temperature |= rx_data[5]; + + raw->status = rx_data[0]; + + return AHT10_OK; +} + +aht10_ret_t aht10_init(aht10_t *aht) { + /* Check if we need initialization */ + + /* Delay 40ms after POR */ + AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 40)); + + aht10_raw_t raw; + + /* Check 0x71 status byte, if uncalibrated then reset and calibrate it. */ + AHT10_ERROR_CHECK(aht10_read_result(aht, &raw)); + if ((raw.status & AHT10_STATUS_CALIBRATED_MASK) == 0) { + AHT10_ERROR_CHECK(aht10_software_reset(aht)); + } + + return AHT10_OK; +} + +aht10_ret_t aht10_measure(aht10_t *aht, aht10_result_t *result) { + /* Start a measurement and read back result... */ + + AHT10_ERROR_CHECK(aht10_start_measurement(aht)); + + AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 80)); + + aht10_raw_t raw; + + uint8_t max_retries = 5U; + + do { + AHT10_ERROR_CHECK(aht10_read_result(aht, &raw)); + max_retries--; + if (max_retries == 0) { + return AHT10_FAIL; + } + } +#ifndef AHT10_SKIP_BUSY_CHECK + while (raw.status & AHT10_STATUS_BUSY_MASK); +#else + while (0); +#endif + + result->temperature = ((double)raw.temperature * 200.0 / 1048576.0) - 50.0; + result->humidity = (double)raw.humidity * 100.0 / 1048576.0; + + return AHT10_OK; +} \ No newline at end of file diff --git a/src/dht/dht_bme280.c b/src/dht/dht_bme280.c new file mode 100644 index 0000000..a74f464 --- /dev/null +++ b/src/dht/dht_bme280.c @@ -0,0 +1,226 @@ +#include "dht_bme280.h" + +#include + +#ifdef IMS_CFG_DHT_BME280_ENABLE_FLOAT +#define ims_bme280_compensate_T ims_bme280_compensate_T_double +#define ims_bme280_compensate_P ims_bme280_compensate_P_double +#define ims_bme280_compensate_H ims_bme280_compensate_H_double +#else +#define ims_bme280_compensate_T ims_bme280_compensate_T_int32 +#define ims_bme280_compensate_P ims_bme280_compensate_P_int32 +#define ims_bme280_compensate_H ims_bme280_compensate_H_int32 +#endif + +#define IMS_BME280_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) + +static double ims_bme280_compensate_T_double(ims_bme280_t *bme, int32_t adc_T); +static double ims_bme280_compensate_P_double(ims_bme280_t *bme, int32_t adc_P); +static double ims_bme280_compensate_H_double(ims_bme280_t *bme, int32_t adc_H); + +static ims_ret_t ims_bme280_reset(ims_bme280_t *bme) { + return bme->cb.write_register_cb(bme->user_data, 0xE0, 0xB6); +} + +static ims_ret_t ims_bme280_read_trim_data(ims_bme280_t *bme) { + ims_ret_t ret; + uint8_t rx_buf[2]; + ret = bme->cb.read_register_cb(bme->user_data, 0x88, rx_buf, 0x02); // T1 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_T1 = IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x8A, rx_buf, 0x02); // T2 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_T2 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x8C, rx_buf, 0x02); // T3 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_T3 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x8E, rx_buf, 0x02); // P1 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P1 = IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x90, rx_buf, 0x02); // P2 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P2 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x92, rx_buf, 0x02); // P3 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P3 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x94, rx_buf, 0x02); // P4 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P4 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x96, rx_buf, 0x02); // P5 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P5 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x98, rx_buf, 0x02); // P5 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P6 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x9A, rx_buf, 0x02); // P7 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P7 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x9C, rx_buf, 0x02); // P8 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P8 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0x9E, rx_buf, 0x02); // P9 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_P9 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0xA1, rx_buf, 0x01); // H1 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H1 = rx_buf[0]; + + ret = bme->cb.read_register_cb(bme->user_data, 0xE1, rx_buf, 0x02); // H2 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H2 = (int16_t)IMS_BME280_CONCAT_BYTES(rx_buf[1], rx_buf[0]); + + ret = bme->cb.read_register_cb(bme->user_data, 0xE3, rx_buf, 0x01); // H3 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H3 = (uint8_t)rx_buf[0]; + + ret = bme->cb.read_register_cb(bme->user_data, 0xE4, rx_buf, 0x02); // H4 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H4 = (int16_t)(((int8_t)rx_buf[0] << 0x04) | (rx_buf[1] & 0x0F)); + + ret = bme->cb.read_register_cb(bme->user_data, 0xE5, rx_buf, 0x02); // H5 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H5 = (int16_t)(((int8_t)rx_buf[1] << 0x04) | (rx_buf[0] >> 0x04)); + + ret = bme->cb.read_register_cb(bme->user_data, 0xE7, rx_buf, 0x01); // H6 + if (ret == IMS_FAIL) return ret; + bme->trim.dig_H6 = (int8_t)rx_buf[0]; + return IMS_SUCCESS; +} + +ims_ret_t bme280_init(ims_bme280_t *bme) { + if (!bme) return IMS_FAIL; + if (ims_bme280_reset(bme) == IMS_FAIL) return IMS_FAIL; + bme->cb.delay_cb(bme->user_data, 100); + if (ims_bme280_read_trim_data(bme) == IMS_FAIL) return IMS_FAIL; + return IMS_SUCCESS; +} + +ims_ret_t bme280_preset_config(ims_bme280_config_t *config, ims_bme280_mode_preset_t preset) { + switch (preset) { + case IMS_BME280_PRESET_WEATHER: + config->mode = IMS_BME280_MODE_FORCED; + config->osrs_t = IMS_BME280_OSRS_1; + config->osrs_p = IMS_BME280_OSRS_1; + config->osrs_h = IMS_BME280_OSRS_1; + config->filter = IMS_BME280_FILTER_OFF; + break; + case IMS_BME280_PRESET_HUMIDITY: + config->mode = IMS_BME280_MODE_FORCED; + config->osrs_t = IMS_BME280_OSRS_1; + config->osrs_p = IMS_BME280_OSRS_SKIP; + config->osrs_h = IMS_BME280_OSRS_1; + config->filter = IMS_BME280_FILTER_OFF; + break; + case IMS_BME280_PRESET_INDOOR_NAV: + config->mode = IMS_BME280_MODE_NORMAL; + config->osrs_t = IMS_BME280_OSRS_2; + config->osrs_p = IMS_BME280_OSRS_16; + config->osrs_h = IMS_BME280_OSRS_1; + config->filter = IMS_BME280_FILTER_16; + break; + case IMS_BME280_PRESET_GAMING: + config->mode = IMS_BME280_MODE_NORMAL; + config->osrs_t = IMS_BME280_OSRS_1; + config->osrs_p = IMS_BME280_OSRS_4; + config->osrs_h = IMS_BME280_OSRS_SKIP; + config->filter = IMS_BME280_FILTER_4; + break; + } + return IMS_SUCCESS; +} + +ims_ret_t bme280_apply_config(ims_bme280_t *bme, ims_bme280_config_t *config) { + uint8_t reg_config = config->filter << 0x02; + uint8_t reg_ctrl_measure = (uint8_t)((config->osrs_t << 0x05) | (config->osrs_p << 0x02) | config->mode); + uint8_t reg_ctrl_hum = config->osrs_h; + bme->cb.write_register_cb(bme->user_data, 0xF5, reg_config); + bme->cb.write_register_cb(bme->user_data, 0xF2, reg_ctrl_hum); + bme->cb.write_register_cb(bme->user_data, 0xF4, reg_ctrl_measure); + return IMS_SUCCESS; +} + +ims_ret_t bme280_measure(ims_bme280_t *bme, ims_bme280_result_t *result) { + uint32_t raw_P = 0x00; + uint32_t raw_T = 0x00; + uint32_t raw_H = 0x00; + uint8_t measure_data[8]; + uint8_t status = 0; + uint8_t ctrl_meas; + uint8_t loop_count = 0; + if (bme->cb.read_register_cb(bme->user_data, 0xF4, &ctrl_meas, 0x01) != IMS_SUCCESS) return IMS_FAIL; + + bme->cb.write_register_cb(bme->user_data, 0xF4, ctrl_meas | IMS_BME280_MODE_FORCED); + do { + if (bme->cb.read_register_cb(bme->user_data, 0xF3, &status, 0x01) != IMS_SUCCESS) return IMS_FAIL; + loop_count++; + bme->cb.delay_cb(bme->user_data, 100); + } while (status & 0x08 && (loop_count < 12)); + + if (bme->cb.read_register_cb(bme->user_data, 0xF7, measure_data, 0x08) != IMS_SUCCESS) return IMS_FAIL; + raw_P = + ((uint32_t)measure_data[0] << 12) | ((uint32_t)measure_data[1] << 0x04) | ((uint32_t)measure_data[2] >> 0x04); + raw_T = + ((uint32_t)measure_data[3] << 12) | ((uint32_t)measure_data[4] << 0x04) | ((uint32_t)measure_data[5] >> 0x04); + raw_H = ((uint32_t)measure_data[6] << 8) | ((uint32_t)measure_data[7]); + result->temperature = ims_bme280_compensate_T(bme, raw_T); + result->pressure = ims_bme280_compensate_P(bme, raw_P); + result->humidity = ims_bme280_compensate_H(bme, raw_H); + return IMS_SUCCESS; +} + +static double ims_bme280_compensate_T_double(ims_bme280_t *bme, int32_t adc_T) { + double var1, var2, T; + var1 = (((double)adc_T) / 16384.0 - ((double)bme->trim.dig_T1) / 1024.0) * ((double)bme->trim.dig_T2); + var2 = ((((double)adc_T) / 131072.0 - ((double)bme->trim.dig_T1) / 8192.0) * + (((double)adc_T) / 131072.0 - ((double)bme->trim.dig_T1) / 8192.0)) * + ((double)bme->trim.dig_T3); + bme->t_fine = (int32_t)(var1 + var2); + T = (var1 + var2) / 5120.0; + return T; +} + +static double ims_bme280_compensate_P_double(ims_bme280_t *bme, int32_t adc_P) { + double var1, var2, p; + var1 = ((double)bme->t_fine / 2.0) - 64000.0; + var2 = var1 * var1 * ((double)bme->trim.dig_P6) / 32768.0; + var2 = var2 + var1 * ((double)bme->trim.dig_P5) * 2.0; + var2 = (var2 / 4.0) + (((double)bme->trim.dig_P4) * 65536.0); + var1 = (((double)bme->trim.dig_P3) * var1 * var1 / 524288.0 + ((double)bme->trim.dig_P2) * var1) / 524288.0; + var1 = (1.0 + var1 / 32768.0) * ((double)bme->trim.dig_P1); + if (var1 == 0.0) { + return 0; // avoid exception caused by division by zero + } + p = 1048576.0 - (double)adc_P; + p = (p - (var2 / 4096.0)) * 6250.0 / var1; + var1 = ((double)bme->trim.dig_P9) * p * p / 2147483648.0; + var2 = p * ((double)bme->trim.dig_P8) / 32768.0; + p = p + (var1 + var2 + ((double)bme->trim.dig_P7)) / 16.0; + return p; +} + +static double ims_bme280_compensate_H_double(ims_bme280_t *bme, int32_t adc_H) { + double var_H; + var_H = (((double)bme->t_fine) - 76800.0); + var_H = (adc_H - (((double)bme->trim.dig_H4) * 64.0 + ((double)bme->trim.dig_H5) / 16384.0 * var_H)) * + (((double)bme->trim.dig_H2) / 65536.0 * + (1.0 + ((double)bme->trim.dig_H6) / 67108864.0 * var_H * + (1.0 + ((double)bme->trim.dig_H3) / 67108864.0 * var_H))); + var_H = var_H * (1.0 - ((double)bme->trim.dig_H1) * var_H / 524288.0); + if (var_H > 100.0) + var_H = 100.0; + else if (var_H < 0.0) + var_H = 0.0; + return var_H; +}