uses BBC micro:bit to measure and display indoor air quality using Bosch BME680 and/or Sensirion SGP30

Dependencies:   microbit

uses Bosch BME680 and/or Sensirion SGP30 sensors to measure indor air quality

sensors should be connected to BBC micro:bit using i2c

commands are received and data is being sent using uBit / nordic radio protocol

display ---

last line always indicates: - first dot: bme680 detected - second dot: sgp30 detected - third dot: sgp 30 setting humidity/temperature - fourth dor: sgp30 measuring - fith dot: bme680 measuring

the detect dots should be in a stable state (not blinking) the measuring dots should be blinking (constant light means: measurement failed)

if only one bme680 is present: - first 3 lines indicate gas resistence (air quality / more dots == worse quality) - fourth line indicates humidity level

if only sgp30 is present: - first two lines indicate SGP30 VOC level - third and fourth line indicate sgp30 CO2 level

if both sensors are present: - first line indicates SGP30 VOC level - second line line indicates sgp30 CO2 level - third line indicates bme680 gas resistence (air quality) - fourth line indicates bme 680 humidity level

buttons - B display state, switches betweeen - full bright - low light - display off

AB reset sgp30 baseline in non volatile storage

data logging -- during measurements the minimum and mximum values for each measured value (temperature, air pressure, humidity,gas resistance, VOC, CO2) are being stored in non volatile storage those (and the last measurement results) are being shown when btn A has been pressed

Committer:
jsa1969
Date:
Tue Dec 04 06:50:48 2018 +0000
Revision:
2:544117df8c65
Parent:
0:cef60cc92da0
Child:
3:6084ab9ff0c9
sgp30

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jsa1969 0:cef60cc92da0 1 #include "bme680.h"
jsa1969 0:cef60cc92da0 2
jsa1969 0:cef60cc92da0 3 Bme680::Bme680(I2cCallbacks *callbacks) {
jsa1969 2:544117df8c65 4 initialize(callbacks,0);
jsa1969 2:544117df8c65 5 }
jsa1969 2:544117df8c65 6
jsa1969 2:544117df8c65 7 Bme680::Bme680(I2cCallbacks *callbacks, uint32_t gas_resistance_max) {
jsa1969 2:544117df8c65 8 initialize(callbacks, gas_resistance_max);
jsa1969 2:544117df8c65 9 }
jsa1969 2:544117df8c65 10
jsa1969 2:544117df8c65 11 void Bme680::initialize(I2cCallbacks *callbacks, uint32_t gas_resistance_max) {
jsa1969 0:cef60cc92da0 12 _dev = new bme680_dev;
jsa1969 0:cef60cc92da0 13 _dev->dev_id = BME680_I2C_ADDR_PRIMARY<<1;
jsa1969 0:cef60cc92da0 14 _i2cCallbacks = callbacks;
jsa1969 2:544117df8c65 15 _gas_resistance_max = gas_resistance_max;
jsa1969 0:cef60cc92da0 16 }
jsa1969 0:cef60cc92da0 17
jsa1969 0:cef60cc92da0 18 int Bme680::init() {
jsa1969 0:cef60cc92da0 19 int rslt = soft_reset();
jsa1969 0:cef60cc92da0 20 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 21
jsa1969 0:cef60cc92da0 22 rslt = get_regs(BME680_CHIP_ID_ADDR, &(_dev->chip_id), 1);
jsa1969 0:cef60cc92da0 23 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 24
jsa1969 0:cef60cc92da0 25 if (_dev->chip_id == BME680_CHIP_ID) {
jsa1969 0:cef60cc92da0 26 rslt = get_calib_data();
jsa1969 0:cef60cc92da0 27 } else {
jsa1969 0:cef60cc92da0 28 rslt = BME680_E_DEV_NOT_FOUND;
jsa1969 0:cef60cc92da0 29 }
jsa1969 0:cef60cc92da0 30
jsa1969 0:cef60cc92da0 31 return rslt;
jsa1969 0:cef60cc92da0 32 }
jsa1969 0:cef60cc92da0 33
jsa1969 0:cef60cc92da0 34 int Bme680::measure(struct bme680_field_data* data, int ambTemp, uint16_t heatr_dur, uint16_t heatr_temp){
jsa1969 0:cef60cc92da0 35 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 36 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 37
jsa1969 0:cef60cc92da0 38 _dev->amb_temp = ambTemp;
jsa1969 0:cef60cc92da0 39 _dev->power_mode = BME680_FORCED_MODE;
jsa1969 0:cef60cc92da0 40
jsa1969 0:cef60cc92da0 41 _dev->tph_sett.os_hum = BME680_OS_1X;
jsa1969 0:cef60cc92da0 42 _dev->tph_sett.os_pres = BME680_OS_16X;
jsa1969 0:cef60cc92da0 43 _dev->tph_sett.os_temp = BME680_OS_2X;
jsa1969 0:cef60cc92da0 44
jsa1969 0:cef60cc92da0 45 _dev->gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
jsa1969 0:cef60cc92da0 46 _dev->gas_sett.heatr_dur = heatr_dur;
jsa1969 0:cef60cc92da0 47 _dev->gas_sett.heatr_temp = heatr_temp;
jsa1969 0:cef60cc92da0 48
jsa1969 0:cef60cc92da0 49 uint16_t settings_sel = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;
jsa1969 0:cef60cc92da0 50
jsa1969 0:cef60cc92da0 51 uint16_t profile_dur = 0;
jsa1969 0:cef60cc92da0 52 get_profile_dur(&profile_dur);
jsa1969 0:cef60cc92da0 53
jsa1969 0:cef60cc92da0 54 rslt = set_sensor_settings(settings_sel);
jsa1969 0:cef60cc92da0 55
jsa1969 0:cef60cc92da0 56 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 57 rslt = set_sensor_mode();
jsa1969 0:cef60cc92da0 58 _i2cCallbacks->delay_ms(profile_dur);
jsa1969 0:cef60cc92da0 59 rslt = get_sensor_data(data);
jsa1969 0:cef60cc92da0 60
jsa1969 0:cef60cc92da0 61 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 62 rslt = analyze_sensor_data(data);
jsa1969 0:cef60cc92da0 63 }
jsa1969 0:cef60cc92da0 64 }
jsa1969 0:cef60cc92da0 65
jsa1969 2:544117df8c65 66 if (rslt == BME680_OK && _gas_resistance_max < data->gas_resistance) {
jsa1969 2:544117df8c65 67 _gas_resistance_max = data->gas_resistance;
jsa1969 2:544117df8c65 68 }
jsa1969 0:cef60cc92da0 69
jsa1969 0:cef60cc92da0 70 return rslt;
jsa1969 0:cef60cc92da0 71 }
jsa1969 0:cef60cc92da0 72
jsa1969 2:544117df8c65 73 uint32_t Bme680::gasResistanceMax() {
jsa1969 2:544117df8c65 74 return _gas_resistance_max;
jsa1969 2:544117df8c65 75 }
jsa1969 2:544117df8c65 76
jsa1969 0:cef60cc92da0 77 int Bme680::analyze_sensor_data(struct bme680_field_data *data)
jsa1969 0:cef60cc92da0 78 {
jsa1969 0:cef60cc92da0 79 int rslt = BME680_OK;
jsa1969 0:cef60cc92da0 80 uint8_t self_test_failed = 0;
jsa1969 0:cef60cc92da0 81
jsa1969 0:cef60cc92da0 82 const int16_t MIN_TEMPERATURE = INT16_C(0); /* 0 degree Celsius */
jsa1969 0:cef60cc92da0 83 const int16_t MAX_TEMPERATURE = INT16_C(6000); /* 60 degree Celsius */
jsa1969 0:cef60cc92da0 84
jsa1969 0:cef60cc92da0 85 const uint32_t MIN_PRESSURE = UINT32_C(90000); /* 900 hecto Pascals */
jsa1969 0:cef60cc92da0 86 const uint32_t MAX_PRESSURE = UINT32_C(110000); /* 1100 hecto Pascals */
jsa1969 0:cef60cc92da0 87
jsa1969 0:cef60cc92da0 88 const uint32_t MIN_HUMIDITY = UINT32_C(1000); /* 20% relative humidity */
jsa1969 0:cef60cc92da0 89 const uint32_t MAX_HUMIDITY = UINT32_C(100000); /* 80% relative humidity*/
jsa1969 0:cef60cc92da0 90
jsa1969 0:cef60cc92da0 91 if ((data->temperature < MIN_TEMPERATURE) || (data->temperature > MAX_TEMPERATURE))
jsa1969 0:cef60cc92da0 92 self_test_failed++;
jsa1969 0:cef60cc92da0 93
jsa1969 0:cef60cc92da0 94 if ((data->pressure < MIN_PRESSURE) || (data->pressure > MAX_PRESSURE))
jsa1969 0:cef60cc92da0 95 self_test_failed++;
jsa1969 0:cef60cc92da0 96
jsa1969 0:cef60cc92da0 97 if ((data->humidity < MIN_HUMIDITY) || (data->humidity > MAX_HUMIDITY))
jsa1969 0:cef60cc92da0 98 self_test_failed++;
jsa1969 0:cef60cc92da0 99
jsa1969 0:cef60cc92da0 100 if (!(data->status & BME680_GASM_VALID_MSK))
jsa1969 0:cef60cc92da0 101 self_test_failed++;
jsa1969 0:cef60cc92da0 102
jsa1969 0:cef60cc92da0 103 if (self_test_failed)
jsa1969 0:cef60cc92da0 104 rslt = BME680_W_SELF_TEST_FAILED;
jsa1969 0:cef60cc92da0 105
jsa1969 0:cef60cc92da0 106 return rslt;
jsa1969 0:cef60cc92da0 107 }
jsa1969 0:cef60cc92da0 108
jsa1969 0:cef60cc92da0 109 int Bme680::soft_reset() {
jsa1969 0:cef60cc92da0 110 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 111 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 112
jsa1969 0:cef60cc92da0 113 uint8_t reg_addr = BME680_SOFT_RESET_ADDR;
jsa1969 0:cef60cc92da0 114 uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD;
jsa1969 0:cef60cc92da0 115 rslt = set_regs(&reg_addr, &soft_rst_cmd, 1);
jsa1969 0:cef60cc92da0 116
jsa1969 0:cef60cc92da0 117 if (rslt==BME680_OK) {
jsa1969 0:cef60cc92da0 118 _i2cCallbacks->delay_ms(BME680_RESET_PERIOD);
jsa1969 0:cef60cc92da0 119 }
jsa1969 0:cef60cc92da0 120
jsa1969 0:cef60cc92da0 121 return rslt;
jsa1969 0:cef60cc92da0 122 }
jsa1969 0:cef60cc92da0 123
jsa1969 0:cef60cc92da0 124 int Bme680::get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
jsa1969 0:cef60cc92da0 125 {
jsa1969 0:cef60cc92da0 126 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 127 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 128
jsa1969 0:cef60cc92da0 129 _dev->com_rslt = _i2cCallbacks->read(_dev->dev_id, reg_addr, reg_data, len);
jsa1969 0:cef60cc92da0 130 if (_dev->com_rslt != 0)
jsa1969 0:cef60cc92da0 131 rslt = BME680_E_COM_FAIL;
jsa1969 0:cef60cc92da0 132 return rslt;
jsa1969 0:cef60cc92da0 133 }
jsa1969 0:cef60cc92da0 134
jsa1969 0:cef60cc92da0 135
jsa1969 0:cef60cc92da0 136 /*
jsa1969 0:cef60cc92da0 137 int8_t Bme680::get_mem_page()
jsa1969 0:cef60cc92da0 138 {
jsa1969 0:cef60cc92da0 139 int8_t rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 140 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 141
jsa1969 0:cef60cc92da0 142 uint8_t reg;
jsa1969 0:cef60cc92da0 143
jsa1969 0:cef60cc92da0 144 _dev->com_rslt = _i2cCallbacks->read(_dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, &reg, 1);
jsa1969 0:cef60cc92da0 145 if (_dev->com_rslt != 0)
jsa1969 0:cef60cc92da0 146 rslt = BME680_E_COM_FAIL;
jsa1969 0:cef60cc92da0 147 else
jsa1969 0:cef60cc92da0 148 _dev->mem_page = reg & BME680_MEM_PAGE_MSK;
jsa1969 0:cef60cc92da0 149
jsa1969 0:cef60cc92da0 150 return rslt;
jsa1969 0:cef60cc92da0 151 }
jsa1969 0:cef60cc92da0 152 */
jsa1969 0:cef60cc92da0 153
jsa1969 0:cef60cc92da0 154 int Bme680::set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len)
jsa1969 0:cef60cc92da0 155 {
jsa1969 0:cef60cc92da0 156 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 157 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 158
jsa1969 0:cef60cc92da0 159 /* Length of the temporary buffer is 2*(length of register)*/
jsa1969 0:cef60cc92da0 160 uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = { 0 };
jsa1969 0:cef60cc92da0 161 uint16_t index;
jsa1969 0:cef60cc92da0 162
jsa1969 0:cef60cc92da0 163 if ((len > 0) && (len < BME680_TMP_BUFFER_LENGTH / 2)) {
jsa1969 0:cef60cc92da0 164 /* Interleave the 2 arrays */
jsa1969 0:cef60cc92da0 165 for (index = 0; index < len; index++) {
jsa1969 0:cef60cc92da0 166 tmp_buff[(2 * index)] = reg_addr[index];
jsa1969 0:cef60cc92da0 167 tmp_buff[(2 * index) + 1] = reg_data[index];
jsa1969 0:cef60cc92da0 168 }
jsa1969 0:cef60cc92da0 169 /* Write the interleaved array */
jsa1969 0:cef60cc92da0 170 _dev->com_rslt = _i2cCallbacks->write(_dev->dev_id, tmp_buff[0], &tmp_buff[1], (2 * len) - 1);
jsa1969 0:cef60cc92da0 171 if (_dev->com_rslt != 0) {
jsa1969 0:cef60cc92da0 172 rslt = BME680_E_COM_FAIL;
jsa1969 0:cef60cc92da0 173 }
jsa1969 0:cef60cc92da0 174 } else {
jsa1969 0:cef60cc92da0 175 rslt = BME680_E_INVALID_LENGTH;
jsa1969 0:cef60cc92da0 176 }
jsa1969 0:cef60cc92da0 177
jsa1969 0:cef60cc92da0 178 return rslt;
jsa1969 0:cef60cc92da0 179 }
jsa1969 0:cef60cc92da0 180
jsa1969 0:cef60cc92da0 181 int Bme680::null_ptr_check()
jsa1969 0:cef60cc92da0 182 {
jsa1969 0:cef60cc92da0 183 if (_dev == NULL || _i2cCallbacks == NULL) {
jsa1969 0:cef60cc92da0 184 /* Device structure pointer is not valid */
jsa1969 0:cef60cc92da0 185 return BME680_E_NULL_PTR;
jsa1969 0:cef60cc92da0 186 } else {
jsa1969 0:cef60cc92da0 187 /* Device structure is fine */
jsa1969 0:cef60cc92da0 188 return BME680_OK;
jsa1969 0:cef60cc92da0 189 }
jsa1969 0:cef60cc92da0 190 }
jsa1969 0:cef60cc92da0 191
jsa1969 0:cef60cc92da0 192 int Bme680::get_calib_data()
jsa1969 0:cef60cc92da0 193 {
jsa1969 0:cef60cc92da0 194 int rslt;
jsa1969 0:cef60cc92da0 195 uint8_t coeff_array[BME680_COEFF_SIZE] = { 0 };
jsa1969 0:cef60cc92da0 196 uint8_t temp_var = 0; /* Temporary variable */
jsa1969 0:cef60cc92da0 197
jsa1969 0:cef60cc92da0 198 /* Check for null pointer in the device structure*/
jsa1969 0:cef60cc92da0 199 rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 200 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 201 rslt = get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN);
jsa1969 0:cef60cc92da0 202 /* Append the second half in the same array */
jsa1969 0:cef60cc92da0 203 if (rslt == BME680_OK)
jsa1969 0:cef60cc92da0 204 rslt = get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN]
jsa1969 0:cef60cc92da0 205 , BME680_COEFF_ADDR2_LEN);
jsa1969 0:cef60cc92da0 206
jsa1969 0:cef60cc92da0 207 /* Temperature related coefficients */
jsa1969 0:cef60cc92da0 208 _dev->calib.par_t1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T1_MSB_REG],
jsa1969 0:cef60cc92da0 209 coeff_array[BME680_T1_LSB_REG]));
jsa1969 0:cef60cc92da0 210 _dev->calib.par_t2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T2_MSB_REG],
jsa1969 0:cef60cc92da0 211 coeff_array[BME680_T2_LSB_REG]));
jsa1969 0:cef60cc92da0 212 _dev->calib.par_t3 = (int8_t) (coeff_array[BME680_T3_REG]);
jsa1969 0:cef60cc92da0 213
jsa1969 0:cef60cc92da0 214 /* Pressure related coefficients */
jsa1969 0:cef60cc92da0 215 _dev->calib.par_p1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P1_MSB_REG],
jsa1969 0:cef60cc92da0 216 coeff_array[BME680_P1_LSB_REG]));
jsa1969 0:cef60cc92da0 217 _dev->calib.par_p2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P2_MSB_REG],
jsa1969 0:cef60cc92da0 218 coeff_array[BME680_P2_LSB_REG]));
jsa1969 0:cef60cc92da0 219 _dev->calib.par_p3 = (int8_t) coeff_array[BME680_P3_REG];
jsa1969 0:cef60cc92da0 220 _dev->calib.par_p4 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P4_MSB_REG],
jsa1969 0:cef60cc92da0 221 coeff_array[BME680_P4_LSB_REG]));
jsa1969 0:cef60cc92da0 222 _dev->calib.par_p5 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P5_MSB_REG],
jsa1969 0:cef60cc92da0 223 coeff_array[BME680_P5_LSB_REG]));
jsa1969 0:cef60cc92da0 224 _dev->calib.par_p6 = (int8_t) (coeff_array[BME680_P6_REG]);
jsa1969 0:cef60cc92da0 225 _dev->calib.par_p7 = (int8_t) (coeff_array[BME680_P7_REG]);
jsa1969 0:cef60cc92da0 226 _dev->calib.par_p8 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P8_MSB_REG],
jsa1969 0:cef60cc92da0 227 coeff_array[BME680_P8_LSB_REG]));
jsa1969 0:cef60cc92da0 228 _dev->calib.par_p9 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P9_MSB_REG],
jsa1969 0:cef60cc92da0 229 coeff_array[BME680_P9_LSB_REG]));
jsa1969 0:cef60cc92da0 230 _dev->calib.par_p10 = (uint8_t) (coeff_array[BME680_P10_REG]);
jsa1969 0:cef60cc92da0 231
jsa1969 0:cef60cc92da0 232 /* Humidity related coefficients */
jsa1969 0:cef60cc92da0 233 _dev->calib.par_h1 = (uint16_t) (((uint16_t) coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL)
jsa1969 0:cef60cc92da0 234 | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK));
jsa1969 0:cef60cc92da0 235 _dev->calib.par_h2 = (uint16_t) (((uint16_t) coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL)
jsa1969 0:cef60cc92da0 236 | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL));
jsa1969 0:cef60cc92da0 237 _dev->calib.par_h3 = (int8_t) coeff_array[BME680_H3_REG];
jsa1969 0:cef60cc92da0 238 _dev->calib.par_h4 = (int8_t) coeff_array[BME680_H4_REG];
jsa1969 0:cef60cc92da0 239 _dev->calib.par_h5 = (int8_t) coeff_array[BME680_H5_REG];
jsa1969 0:cef60cc92da0 240 _dev->calib.par_h6 = (uint8_t) coeff_array[BME680_H6_REG];
jsa1969 0:cef60cc92da0 241 _dev->calib.par_h7 = (int8_t) coeff_array[BME680_H7_REG];
jsa1969 0:cef60cc92da0 242
jsa1969 0:cef60cc92da0 243 /* Gas heater related coefficients */
jsa1969 0:cef60cc92da0 244 _dev->calib.par_gh1 = (int8_t) coeff_array[BME680_GH1_REG];
jsa1969 0:cef60cc92da0 245 _dev->calib.par_gh2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG],
jsa1969 0:cef60cc92da0 246 coeff_array[BME680_GH2_LSB_REG]));
jsa1969 0:cef60cc92da0 247 _dev->calib.par_gh3 = (int8_t) coeff_array[BME680_GH3_REG];
jsa1969 0:cef60cc92da0 248
jsa1969 0:cef60cc92da0 249 /* Other coefficients */
jsa1969 0:cef60cc92da0 250 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 251 rslt = get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1);
jsa1969 0:cef60cc92da0 252
jsa1969 0:cef60cc92da0 253 _dev->calib.res_heat_range = ((temp_var & BME680_RHRANGE_MSK) / 16);
jsa1969 0:cef60cc92da0 254 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 255 rslt = get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1);
jsa1969 0:cef60cc92da0 256
jsa1969 0:cef60cc92da0 257 _dev->calib.res_heat_val = (int8_t) temp_var;
jsa1969 0:cef60cc92da0 258 if (rslt == BME680_OK)
jsa1969 0:cef60cc92da0 259 rslt = get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1);
jsa1969 0:cef60cc92da0 260 }
jsa1969 0:cef60cc92da0 261 }
jsa1969 0:cef60cc92da0 262 _dev->calib.range_sw_err = ((int8_t) temp_var & (int8_t) BME680_RSERROR_MSK) / 16;
jsa1969 0:cef60cc92da0 263 }
jsa1969 0:cef60cc92da0 264
jsa1969 0:cef60cc92da0 265 return rslt;
jsa1969 0:cef60cc92da0 266 }
jsa1969 0:cef60cc92da0 267
jsa1969 0:cef60cc92da0 268 void Bme680::set_profile_dur(uint16_t duration)
jsa1969 0:cef60cc92da0 269 {
jsa1969 0:cef60cc92da0 270 uint32_t tph_dur; /* Calculate in us */
jsa1969 0:cef60cc92da0 271 uint32_t meas_cycles;
jsa1969 0:cef60cc92da0 272 uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16};
jsa1969 0:cef60cc92da0 273
jsa1969 0:cef60cc92da0 274 meas_cycles = os_to_meas_cycles[_dev->tph_sett.os_temp];
jsa1969 0:cef60cc92da0 275 meas_cycles += os_to_meas_cycles[_dev->tph_sett.os_pres];
jsa1969 0:cef60cc92da0 276 meas_cycles += os_to_meas_cycles[_dev->tph_sett.os_hum];
jsa1969 0:cef60cc92da0 277
jsa1969 0:cef60cc92da0 278 /* TPH measurement duration */
jsa1969 0:cef60cc92da0 279 tph_dur = meas_cycles * UINT32_C(1963);
jsa1969 0:cef60cc92da0 280 tph_dur += UINT32_C(477 * 4); /* TPH switching duration */
jsa1969 0:cef60cc92da0 281 tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */
jsa1969 0:cef60cc92da0 282 tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/
jsa1969 0:cef60cc92da0 283 tph_dur /= UINT32_C(1000); /* Convert to ms */
jsa1969 0:cef60cc92da0 284
jsa1969 0:cef60cc92da0 285 tph_dur += UINT32_C(1); /* Wake up duration of 1ms */
jsa1969 0:cef60cc92da0 286 /* The remaining time should be used for heating */
jsa1969 0:cef60cc92da0 287 _dev->gas_sett.heatr_dur = duration - (uint16_t) tph_dur;
jsa1969 0:cef60cc92da0 288 }
jsa1969 0:cef60cc92da0 289
jsa1969 0:cef60cc92da0 290 void Bme680::get_profile_dur(uint16_t *duration)
jsa1969 0:cef60cc92da0 291 {
jsa1969 0:cef60cc92da0 292 uint32_t tph_dur; /* Calculate in us */
jsa1969 0:cef60cc92da0 293 uint32_t meas_cycles;
jsa1969 0:cef60cc92da0 294 uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16};
jsa1969 0:cef60cc92da0 295
jsa1969 0:cef60cc92da0 296 meas_cycles = os_to_meas_cycles[_dev->tph_sett.os_temp];
jsa1969 0:cef60cc92da0 297 meas_cycles += os_to_meas_cycles[_dev->tph_sett.os_pres];
jsa1969 0:cef60cc92da0 298 meas_cycles += os_to_meas_cycles[_dev->tph_sett.os_hum];
jsa1969 0:cef60cc92da0 299
jsa1969 0:cef60cc92da0 300 /* TPH measurement duration */
jsa1969 0:cef60cc92da0 301 tph_dur = meas_cycles * UINT32_C(1963);
jsa1969 0:cef60cc92da0 302 tph_dur += UINT32_C(477 * 4); /* TPH switching duration */
jsa1969 0:cef60cc92da0 303 tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */
jsa1969 0:cef60cc92da0 304 tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/
jsa1969 0:cef60cc92da0 305 tph_dur /= UINT32_C(1000); /* Convert to ms */
jsa1969 0:cef60cc92da0 306
jsa1969 0:cef60cc92da0 307 tph_dur += UINT32_C(1); /* Wake up duration of 1ms */
jsa1969 0:cef60cc92da0 308
jsa1969 0:cef60cc92da0 309 *duration = (uint16_t) tph_dur;
jsa1969 0:cef60cc92da0 310
jsa1969 0:cef60cc92da0 311 /* Get the gas duration only when the run gas is enabled */
jsa1969 0:cef60cc92da0 312 if (_dev->gas_sett.run_gas) {
jsa1969 0:cef60cc92da0 313 /* The remaining time should be used for heating */
jsa1969 0:cef60cc92da0 314 *duration += _dev->gas_sett.heatr_dur;
jsa1969 0:cef60cc92da0 315 }
jsa1969 0:cef60cc92da0 316 }
jsa1969 0:cef60cc92da0 317
jsa1969 0:cef60cc92da0 318 int Bme680::get_sensor_data(struct bme680_field_data *data)
jsa1969 0:cef60cc92da0 319 {
jsa1969 0:cef60cc92da0 320 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 321 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 322
jsa1969 0:cef60cc92da0 323 /* Reading the sensor data in forced mode only */
jsa1969 0:cef60cc92da0 324 rslt = read_field_data(data);
jsa1969 0:cef60cc92da0 325 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 326 if (data->status & BME680_NEW_DATA_MSK)
jsa1969 0:cef60cc92da0 327 _dev->new_fields = 1;
jsa1969 0:cef60cc92da0 328 else
jsa1969 0:cef60cc92da0 329 _dev->new_fields = 0;
jsa1969 0:cef60cc92da0 330 }
jsa1969 0:cef60cc92da0 331
jsa1969 0:cef60cc92da0 332 return rslt;
jsa1969 0:cef60cc92da0 333 }
jsa1969 0:cef60cc92da0 334
jsa1969 0:cef60cc92da0 335 int Bme680::read_field_data(struct bme680_field_data *data){
jsa1969 0:cef60cc92da0 336 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 337 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 338
jsa1969 0:cef60cc92da0 339 uint8_t buff[BME680_FIELD_LENGTH] = { 0 };
jsa1969 0:cef60cc92da0 340 uint8_t gas_range;
jsa1969 0:cef60cc92da0 341 uint32_t adc_temp;
jsa1969 0:cef60cc92da0 342 uint32_t adc_pres;
jsa1969 0:cef60cc92da0 343 uint16_t adc_hum;
jsa1969 0:cef60cc92da0 344 uint16_t adc_gas_res;
jsa1969 0:cef60cc92da0 345 uint8_t tries = 10;
jsa1969 0:cef60cc92da0 346
jsa1969 0:cef60cc92da0 347 do {
jsa1969 0:cef60cc92da0 348 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 349 rslt = get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH);
jsa1969 0:cef60cc92da0 350
jsa1969 0:cef60cc92da0 351 data->status = buff[0] & BME680_NEW_DATA_MSK;
jsa1969 0:cef60cc92da0 352 data->gas_index = buff[0] & BME680_GAS_INDEX_MSK;
jsa1969 0:cef60cc92da0 353 data->meas_index = buff[1];
jsa1969 0:cef60cc92da0 354
jsa1969 0:cef60cc92da0 355 /* read the raw data from the sensor */
jsa1969 0:cef60cc92da0 356 adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16)
jsa1969 0:cef60cc92da0 357 | ((uint32_t) buff[4] / 16));
jsa1969 0:cef60cc92da0 358 adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16)
jsa1969 0:cef60cc92da0 359 | ((uint32_t) buff[7] / 16));
jsa1969 0:cef60cc92da0 360 adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]);
jsa1969 0:cef60cc92da0 361 adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64));
jsa1969 0:cef60cc92da0 362 gas_range = buff[14] & BME680_GAS_RANGE_MSK;
jsa1969 0:cef60cc92da0 363
jsa1969 0:cef60cc92da0 364 data->status |= buff[14] & BME680_GASM_VALID_MSK;
jsa1969 0:cef60cc92da0 365 data->status |= buff[14] & BME680_HEAT_STAB_MSK;
jsa1969 0:cef60cc92da0 366
jsa1969 0:cef60cc92da0 367 if (data->status & BME680_NEW_DATA_MSK) {
jsa1969 0:cef60cc92da0 368 data->temperature = calc_temperature(adc_temp);
jsa1969 0:cef60cc92da0 369 data->pressure = calc_pressure(adc_pres);
jsa1969 0:cef60cc92da0 370 data->humidity = calc_humidity(adc_hum);
jsa1969 0:cef60cc92da0 371 data->gas_resistance = calc_gas_resistance(adc_gas_res, gas_range);
jsa1969 0:cef60cc92da0 372 break;
jsa1969 0:cef60cc92da0 373 }
jsa1969 0:cef60cc92da0 374 /* Delay to poll the data */
jsa1969 0:cef60cc92da0 375 _i2cCallbacks->delay_ms(BME680_POLL_PERIOD_MS);
jsa1969 0:cef60cc92da0 376 }
jsa1969 0:cef60cc92da0 377 tries--;
jsa1969 0:cef60cc92da0 378 } while (tries);
jsa1969 0:cef60cc92da0 379
jsa1969 0:cef60cc92da0 380 if (!tries){
jsa1969 0:cef60cc92da0 381 rslt = BME680_W_NO_NEW_DATA;
jsa1969 0:cef60cc92da0 382 }
jsa1969 0:cef60cc92da0 383
jsa1969 0:cef60cc92da0 384 return rslt;
jsa1969 0:cef60cc92da0 385 }
jsa1969 0:cef60cc92da0 386
jsa1969 0:cef60cc92da0 387 int Bme680::get_sensor_mode(struct bme680_dev *dev)
jsa1969 0:cef60cc92da0 388 {
jsa1969 0:cef60cc92da0 389 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 390 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 391
jsa1969 0:cef60cc92da0 392 uint8_t mode;
jsa1969 0:cef60cc92da0 393
jsa1969 0:cef60cc92da0 394 rslt = get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1);
jsa1969 0:cef60cc92da0 395 /* Masking the other register bit info*/
jsa1969 0:cef60cc92da0 396 _dev->power_mode = mode & BME680_MODE_MSK;
jsa1969 0:cef60cc92da0 397
jsa1969 0:cef60cc92da0 398 return rslt;
jsa1969 0:cef60cc92da0 399 }
jsa1969 0:cef60cc92da0 400
jsa1969 0:cef60cc92da0 401 int Bme680::set_sensor_mode()
jsa1969 0:cef60cc92da0 402 {
jsa1969 0:cef60cc92da0 403 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 404 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 405
jsa1969 0:cef60cc92da0 406 uint8_t tmp_pow_mode;
jsa1969 0:cef60cc92da0 407 uint8_t pow_mode = 0;
jsa1969 0:cef60cc92da0 408 uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR;
jsa1969 0:cef60cc92da0 409
jsa1969 0:cef60cc92da0 410 /* Call repeatedly until in sleep */
jsa1969 0:cef60cc92da0 411 do {
jsa1969 0:cef60cc92da0 412 rslt = get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1);
jsa1969 0:cef60cc92da0 413 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 414 /* Put to sleep before changing mode */
jsa1969 0:cef60cc92da0 415 pow_mode = (tmp_pow_mode & BME680_MODE_MSK);
jsa1969 0:cef60cc92da0 416
jsa1969 0:cef60cc92da0 417 if (pow_mode != BME680_SLEEP_MODE) {
jsa1969 0:cef60cc92da0 418 tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */
jsa1969 0:cef60cc92da0 419 rslt = set_regs(&reg_addr, &tmp_pow_mode, 1);
jsa1969 0:cef60cc92da0 420 _i2cCallbacks->delay_ms(BME680_POLL_PERIOD_MS);
jsa1969 0:cef60cc92da0 421 }
jsa1969 0:cef60cc92da0 422 }
jsa1969 0:cef60cc92da0 423 } while (pow_mode != BME680_SLEEP_MODE);
jsa1969 0:cef60cc92da0 424
jsa1969 0:cef60cc92da0 425 /* Already in sleep */
jsa1969 0:cef60cc92da0 426 if (_dev->power_mode != BME680_SLEEP_MODE) {
jsa1969 0:cef60cc92da0 427 tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (_dev->power_mode & BME680_MODE_MSK);
jsa1969 0:cef60cc92da0 428 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 429 rslt = set_regs(&reg_addr, &tmp_pow_mode, 1);
jsa1969 0:cef60cc92da0 430 }
jsa1969 0:cef60cc92da0 431 }
jsa1969 0:cef60cc92da0 432
jsa1969 0:cef60cc92da0 433 return rslt;
jsa1969 0:cef60cc92da0 434 }
jsa1969 0:cef60cc92da0 435
jsa1969 0:cef60cc92da0 436 int Bme680::set_gas_config()
jsa1969 0:cef60cc92da0 437 {
jsa1969 0:cef60cc92da0 438 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 439 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 440
jsa1969 0:cef60cc92da0 441 uint8_t reg_addr[2] = {0};
jsa1969 0:cef60cc92da0 442 uint8_t reg_data[2] = {0};
jsa1969 0:cef60cc92da0 443
jsa1969 0:cef60cc92da0 444 if (_dev->power_mode == BME680_FORCED_MODE) {
jsa1969 0:cef60cc92da0 445 reg_addr[0] = BME680_RES_HEAT0_ADDR;
jsa1969 0:cef60cc92da0 446 reg_data[0] = calc_heater_res(_dev->gas_sett.heatr_temp);
jsa1969 0:cef60cc92da0 447 reg_addr[1] = BME680_GAS_WAIT0_ADDR;
jsa1969 0:cef60cc92da0 448 reg_data[1] = calc_heater_dur(_dev->gas_sett.heatr_dur);
jsa1969 0:cef60cc92da0 449 _dev->gas_sett.nb_conv = 0;
jsa1969 0:cef60cc92da0 450 } else {
jsa1969 0:cef60cc92da0 451 rslt = BME680_W_DEFINE_PWR_MODE;
jsa1969 0:cef60cc92da0 452 }
jsa1969 0:cef60cc92da0 453
jsa1969 0:cef60cc92da0 454 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 455 rslt = set_regs(reg_addr, reg_data, 2);
jsa1969 0:cef60cc92da0 456 }
jsa1969 0:cef60cc92da0 457
jsa1969 0:cef60cc92da0 458 return rslt;
jsa1969 0:cef60cc92da0 459 }
jsa1969 0:cef60cc92da0 460
jsa1969 0:cef60cc92da0 461 uint8_t Bme680::calc_heater_dur(uint16_t dur)
jsa1969 0:cef60cc92da0 462 {
jsa1969 0:cef60cc92da0 463 uint8_t factor = 0;
jsa1969 0:cef60cc92da0 464 uint8_t durval;
jsa1969 0:cef60cc92da0 465
jsa1969 0:cef60cc92da0 466 if (dur >= 0xfc0) {
jsa1969 0:cef60cc92da0 467 durval = 0xff; /* Max duration*/
jsa1969 0:cef60cc92da0 468 } else {
jsa1969 0:cef60cc92da0 469 while (dur > 0x3F) {
jsa1969 0:cef60cc92da0 470 dur = dur / 4;
jsa1969 0:cef60cc92da0 471 factor += 1;
jsa1969 0:cef60cc92da0 472 }
jsa1969 0:cef60cc92da0 473 durval = (uint8_t) (dur + (factor * 64));
jsa1969 0:cef60cc92da0 474 }
jsa1969 0:cef60cc92da0 475
jsa1969 0:cef60cc92da0 476 return durval;
jsa1969 0:cef60cc92da0 477 }
jsa1969 0:cef60cc92da0 478
jsa1969 0:cef60cc92da0 479
jsa1969 0:cef60cc92da0 480 uint8_t Bme680::calc_heater_res(uint16_t temp)
jsa1969 0:cef60cc92da0 481 {
jsa1969 0:cef60cc92da0 482 uint8_t heatr_res;
jsa1969 0:cef60cc92da0 483 int32_t var1;
jsa1969 0:cef60cc92da0 484 int32_t var2;
jsa1969 0:cef60cc92da0 485 int32_t var3;
jsa1969 0:cef60cc92da0 486 int32_t var4;
jsa1969 0:cef60cc92da0 487 int32_t var5;
jsa1969 0:cef60cc92da0 488 int32_t heatr_res_x100;
jsa1969 0:cef60cc92da0 489
jsa1969 0:cef60cc92da0 490 if (temp > 400) {
jsa1969 0:cef60cc92da0 491 temp = 400;
jsa1969 0:cef60cc92da0 492 }
jsa1969 0:cef60cc92da0 493
jsa1969 0:cef60cc92da0 494 var1 = (((int32_t) _dev->amb_temp * _dev->calib.par_gh3) / 1000) * 256;
jsa1969 0:cef60cc92da0 495 var2 = (_dev->calib.par_gh1 + 784) * (((((_dev->calib.par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10);
jsa1969 0:cef60cc92da0 496 var3 = var1 + (var2 / 2);
jsa1969 0:cef60cc92da0 497 var4 = (var3 / (_dev->calib.res_heat_range + 4));
jsa1969 0:cef60cc92da0 498 var5 = (131 * _dev->calib.res_heat_val) + 65536;
jsa1969 0:cef60cc92da0 499 heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34);
jsa1969 0:cef60cc92da0 500 heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100);
jsa1969 0:cef60cc92da0 501
jsa1969 0:cef60cc92da0 502 return heatr_res;
jsa1969 0:cef60cc92da0 503 }
jsa1969 0:cef60cc92da0 504
jsa1969 0:cef60cc92da0 505 int Bme680::boundary_check(uint8_t *value, uint8_t min, uint8_t max) {
jsa1969 0:cef60cc92da0 506 int rslt = BME680_OK;
jsa1969 0:cef60cc92da0 507
jsa1969 0:cef60cc92da0 508 if (value != NULL) {
jsa1969 0:cef60cc92da0 509 // Check if value is below minimum value
jsa1969 0:cef60cc92da0 510 if (*value < min) {
jsa1969 0:cef60cc92da0 511 // Auto correct the invalid value to minimum value
jsa1969 0:cef60cc92da0 512 *value = min;
jsa1969 0:cef60cc92da0 513 _dev->info_msg |= BME680_I_MIN_CORRECTION;
jsa1969 0:cef60cc92da0 514 }
jsa1969 0:cef60cc92da0 515 // Check if value is above maximum value
jsa1969 0:cef60cc92da0 516 if (*value > max) {
jsa1969 0:cef60cc92da0 517 // Auto correct the invalid value to maximum value
jsa1969 0:cef60cc92da0 518 *value = max;
jsa1969 0:cef60cc92da0 519 _dev->info_msg |= BME680_I_MAX_CORRECTION;
jsa1969 0:cef60cc92da0 520 }
jsa1969 0:cef60cc92da0 521 } else {
jsa1969 0:cef60cc92da0 522 rslt = BME680_E_NULL_PTR;
jsa1969 0:cef60cc92da0 523 }
jsa1969 0:cef60cc92da0 524
jsa1969 0:cef60cc92da0 525 return rslt;
jsa1969 0:cef60cc92da0 526 }
jsa1969 0:cef60cc92da0 527
jsa1969 0:cef60cc92da0 528 int Bme680::set_sensor_settings(uint16_t desired_settings)
jsa1969 0:cef60cc92da0 529 {
jsa1969 0:cef60cc92da0 530 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 531 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 532
jsa1969 0:cef60cc92da0 533 uint8_t reg_addr;
jsa1969 0:cef60cc92da0 534 uint8_t data = 0;
jsa1969 0:cef60cc92da0 535 uint8_t count = 0;
jsa1969 0:cef60cc92da0 536 uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = { 0 };
jsa1969 0:cef60cc92da0 537 uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 };
jsa1969 0:cef60cc92da0 538 uint8_t intended_power_mode = _dev->power_mode; // Save intended power mode
jsa1969 0:cef60cc92da0 539
jsa1969 0:cef60cc92da0 540 // Check for null pointer in the device structure
jsa1969 0:cef60cc92da0 541
jsa1969 0:cef60cc92da0 542 if (desired_settings & BME680_GAS_MEAS_SEL) {
jsa1969 0:cef60cc92da0 543 rslt = set_gas_config();
jsa1969 0:cef60cc92da0 544 }
jsa1969 0:cef60cc92da0 545
jsa1969 0:cef60cc92da0 546 _dev->power_mode = BME680_SLEEP_MODE;
jsa1969 0:cef60cc92da0 547 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 548 rslt = set_sensor_mode();
jsa1969 0:cef60cc92da0 549 }
jsa1969 0:cef60cc92da0 550
jsa1969 0:cef60cc92da0 551 // Selecting the filter
jsa1969 0:cef60cc92da0 552 if (desired_settings & BME680_FILTER_SEL) {
jsa1969 0:cef60cc92da0 553 rslt = boundary_check(&(_dev->tph_sett.filter), BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127);
jsa1969 0:cef60cc92da0 554 reg_addr = BME680_CONF_ODR_FILT_ADDR;
jsa1969 0:cef60cc92da0 555
jsa1969 0:cef60cc92da0 556 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 557 rslt = get_regs(reg_addr, &data, 1);
jsa1969 0:cef60cc92da0 558 }
jsa1969 0:cef60cc92da0 559
jsa1969 0:cef60cc92da0 560 if (desired_settings & BME680_FILTER_SEL) {
jsa1969 0:cef60cc92da0 561 data = BME680_SET_BITS(data, BME680_FILTER, _dev->tph_sett.filter);
jsa1969 0:cef60cc92da0 562 }
jsa1969 0:cef60cc92da0 563
jsa1969 0:cef60cc92da0 564 reg_array[count] = reg_addr; // Append configuration
jsa1969 0:cef60cc92da0 565 data_array[count] = data;
jsa1969 0:cef60cc92da0 566 count++;
jsa1969 0:cef60cc92da0 567 }
jsa1969 0:cef60cc92da0 568
jsa1969 0:cef60cc92da0 569 // Selecting heater control for the sensor
jsa1969 0:cef60cc92da0 570 if (desired_settings & BME680_HCNTRL_SEL) {
jsa1969 0:cef60cc92da0 571 rslt = boundary_check(&(_dev->gas_sett.heatr_ctrl), BME680_ENABLE_HEATER,
jsa1969 0:cef60cc92da0 572 BME680_DISABLE_HEATER);
jsa1969 0:cef60cc92da0 573 reg_addr = BME680_CONF_HEAT_CTRL_ADDR;
jsa1969 0:cef60cc92da0 574
jsa1969 0:cef60cc92da0 575 if (rslt == BME680_OK){
jsa1969 0:cef60cc92da0 576 rslt = get_regs(reg_addr, &data, 1);
jsa1969 0:cef60cc92da0 577 }
jsa1969 0:cef60cc92da0 578
jsa1969 0:cef60cc92da0 579 data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, _dev->gas_sett.heatr_ctrl);
jsa1969 0:cef60cc92da0 580
jsa1969 0:cef60cc92da0 581 reg_array[count] = reg_addr; // Append configuration
jsa1969 0:cef60cc92da0 582 data_array[count] = data;
jsa1969 0:cef60cc92da0 583 count++;
jsa1969 0:cef60cc92da0 584 }
jsa1969 0:cef60cc92da0 585
jsa1969 0:cef60cc92da0 586 // Selecting heater T,P oversampling for the sensor
jsa1969 0:cef60cc92da0 587 if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) {
jsa1969 0:cef60cc92da0 588 rslt = boundary_check(&(_dev->tph_sett.os_temp), BME680_OS_NONE, BME680_OS_16X);
jsa1969 0:cef60cc92da0 589 reg_addr = BME680_CONF_T_P_MODE_ADDR;
jsa1969 0:cef60cc92da0 590
jsa1969 0:cef60cc92da0 591 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 592 rslt = get_regs(reg_addr, &data, 1);
jsa1969 0:cef60cc92da0 593 }
jsa1969 0:cef60cc92da0 594
jsa1969 0:cef60cc92da0 595 if (desired_settings & BME680_OST_SEL) {
jsa1969 0:cef60cc92da0 596 data = BME680_SET_BITS(data, BME680_OST, _dev->tph_sett.os_temp);
jsa1969 0:cef60cc92da0 597 }
jsa1969 0:cef60cc92da0 598
jsa1969 0:cef60cc92da0 599 if (desired_settings & BME680_OSP_SEL) {
jsa1969 0:cef60cc92da0 600 data = BME680_SET_BITS(data, BME680_OSP, _dev->tph_sett.os_pres);
jsa1969 0:cef60cc92da0 601 }
jsa1969 0:cef60cc92da0 602
jsa1969 0:cef60cc92da0 603 reg_array[count] = reg_addr;
jsa1969 0:cef60cc92da0 604 data_array[count] = data;
jsa1969 0:cef60cc92da0 605 count++;
jsa1969 0:cef60cc92da0 606 }
jsa1969 0:cef60cc92da0 607
jsa1969 0:cef60cc92da0 608 // Selecting humidity oversampling for the sensor
jsa1969 0:cef60cc92da0 609 if (desired_settings & BME680_OSH_SEL) {
jsa1969 0:cef60cc92da0 610 rslt = boundary_check(&(_dev->tph_sett.os_hum), BME680_OS_NONE, BME680_OS_16X);
jsa1969 0:cef60cc92da0 611 reg_addr = BME680_CONF_OS_H_ADDR;
jsa1969 0:cef60cc92da0 612
jsa1969 0:cef60cc92da0 613 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 614 rslt = get_regs(reg_addr, &data, 1);
jsa1969 0:cef60cc92da0 615 }
jsa1969 0:cef60cc92da0 616
jsa1969 0:cef60cc92da0 617 data = BME680_SET_BITS_POS_0(data, BME680_OSH, _dev->tph_sett.os_hum);
jsa1969 0:cef60cc92da0 618
jsa1969 0:cef60cc92da0 619 reg_array[count] = reg_addr; // Append configuration
jsa1969 0:cef60cc92da0 620 data_array[count] = data;
jsa1969 0:cef60cc92da0 621 count++;
jsa1969 0:cef60cc92da0 622 }
jsa1969 0:cef60cc92da0 623
jsa1969 0:cef60cc92da0 624 // Selecting the runGas and NB conversion settings for the sensor
jsa1969 0:cef60cc92da0 625 if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) {
jsa1969 0:cef60cc92da0 626 rslt = boundary_check(&(_dev->gas_sett.run_gas), BME680_RUN_GAS_DISABLE,
jsa1969 0:cef60cc92da0 627 BME680_RUN_GAS_ENABLE);
jsa1969 0:cef60cc92da0 628
jsa1969 0:cef60cc92da0 629 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 630 // Validate boundary conditions
jsa1969 0:cef60cc92da0 631 rslt = boundary_check(&(_dev->gas_sett.nb_conv), BME680_NBCONV_MIN,
jsa1969 0:cef60cc92da0 632 BME680_NBCONV_MAX);
jsa1969 0:cef60cc92da0 633 }
jsa1969 0:cef60cc92da0 634
jsa1969 0:cef60cc92da0 635 reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR;
jsa1969 0:cef60cc92da0 636
jsa1969 0:cef60cc92da0 637 if (rslt == BME680_OK)
jsa1969 0:cef60cc92da0 638 rslt = get_regs(reg_addr, &data, 1);
jsa1969 0:cef60cc92da0 639
jsa1969 0:cef60cc92da0 640 if (desired_settings & BME680_RUN_GAS_SEL)
jsa1969 0:cef60cc92da0 641 data = BME680_SET_BITS(data, BME680_RUN_GAS, _dev->gas_sett.run_gas);
jsa1969 0:cef60cc92da0 642
jsa1969 0:cef60cc92da0 643 if (desired_settings & BME680_NBCONV_SEL)
jsa1969 0:cef60cc92da0 644 data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, _dev->gas_sett.nb_conv);
jsa1969 0:cef60cc92da0 645
jsa1969 0:cef60cc92da0 646 reg_array[count] = reg_addr; // Append configuration
jsa1969 0:cef60cc92da0 647 data_array[count] = data;
jsa1969 0:cef60cc92da0 648 count++;
jsa1969 0:cef60cc92da0 649 }
jsa1969 0:cef60cc92da0 650
jsa1969 0:cef60cc92da0 651 if (rslt == BME680_OK)
jsa1969 0:cef60cc92da0 652 rslt = set_regs(reg_array, data_array, count);
jsa1969 0:cef60cc92da0 653
jsa1969 0:cef60cc92da0 654 // Restore previous intended power mode
jsa1969 0:cef60cc92da0 655 _dev->power_mode = intended_power_mode;
jsa1969 0:cef60cc92da0 656
jsa1969 0:cef60cc92da0 657 return rslt;
jsa1969 0:cef60cc92da0 658 }
jsa1969 0:cef60cc92da0 659
jsa1969 0:cef60cc92da0 660 int Bme680::get_sensor_settings(uint16_t desired_settings)
jsa1969 0:cef60cc92da0 661 {
jsa1969 0:cef60cc92da0 662 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 663 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 664
jsa1969 0:cef60cc92da0 665 /* starting address of the register array for burst read*/
jsa1969 0:cef60cc92da0 666 uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR;
jsa1969 0:cef60cc92da0 667 uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 };
jsa1969 0:cef60cc92da0 668
jsa1969 0:cef60cc92da0 669
jsa1969 0:cef60cc92da0 670 rslt = get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH);
jsa1969 0:cef60cc92da0 671
jsa1969 0:cef60cc92da0 672 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 673 if (desired_settings & BME680_GAS_MEAS_SEL)
jsa1969 0:cef60cc92da0 674 rslt = get_gas_config();
jsa1969 0:cef60cc92da0 675
jsa1969 0:cef60cc92da0 676 /* get the T,P,H ,Filter,ODR settings here */
jsa1969 0:cef60cc92da0 677 if (desired_settings & BME680_FILTER_SEL)
jsa1969 0:cef60cc92da0 678 _dev->tph_sett.filter = BME680_GET_BITS(data_array[BME680_REG_FILTER_INDEX],
jsa1969 0:cef60cc92da0 679 BME680_FILTER);
jsa1969 0:cef60cc92da0 680
jsa1969 0:cef60cc92da0 681 if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) {
jsa1969 0:cef60cc92da0 682 _dev->tph_sett.os_temp = BME680_GET_BITS(data_array[BME680_REG_TEMP_INDEX], BME680_OST);
jsa1969 0:cef60cc92da0 683 _dev->tph_sett.os_pres = BME680_GET_BITS(data_array[BME680_REG_PRES_INDEX], BME680_OSP);
jsa1969 0:cef60cc92da0 684 }
jsa1969 0:cef60cc92da0 685
jsa1969 0:cef60cc92da0 686 if (desired_settings & BME680_OSH_SEL)
jsa1969 0:cef60cc92da0 687 _dev->tph_sett.os_hum = BME680_GET_BITS_POS_0(data_array[BME680_REG_HUM_INDEX],
jsa1969 0:cef60cc92da0 688 BME680_OSH);
jsa1969 0:cef60cc92da0 689
jsa1969 0:cef60cc92da0 690 /* get the gas related settings */
jsa1969 0:cef60cc92da0 691 if (desired_settings & BME680_HCNTRL_SEL)
jsa1969 0:cef60cc92da0 692 _dev->gas_sett.heatr_ctrl = BME680_GET_BITS_POS_0(data_array[BME680_REG_HCTRL_INDEX],
jsa1969 0:cef60cc92da0 693 BME680_HCTRL);
jsa1969 0:cef60cc92da0 694
jsa1969 0:cef60cc92da0 695 if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) {
jsa1969 0:cef60cc92da0 696 _dev->gas_sett.nb_conv = BME680_GET_BITS_POS_0(data_array[BME680_REG_NBCONV_INDEX],
jsa1969 0:cef60cc92da0 697 BME680_NBCONV);
jsa1969 0:cef60cc92da0 698 _dev->gas_sett.run_gas = BME680_GET_BITS(data_array[BME680_REG_RUN_GAS_INDEX],
jsa1969 0:cef60cc92da0 699 BME680_RUN_GAS);
jsa1969 0:cef60cc92da0 700 }
jsa1969 0:cef60cc92da0 701 }
jsa1969 0:cef60cc92da0 702
jsa1969 0:cef60cc92da0 703 return rslt;
jsa1969 0:cef60cc92da0 704 }
jsa1969 0:cef60cc92da0 705
jsa1969 0:cef60cc92da0 706 int Bme680::get_gas_config()
jsa1969 0:cef60cc92da0 707 {
jsa1969 0:cef60cc92da0 708 int rslt = null_ptr_check();
jsa1969 0:cef60cc92da0 709 if (rslt!=BME680_OK) return rslt;
jsa1969 0:cef60cc92da0 710
jsa1969 0:cef60cc92da0 711 /* starting address of the register array for burst read*/
jsa1969 0:cef60cc92da0 712 uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START;
jsa1969 0:cef60cc92da0 713 uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START;
jsa1969 0:cef60cc92da0 714 uint8_t reg_data = 0;
jsa1969 0:cef60cc92da0 715
jsa1969 0:cef60cc92da0 716 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 717 rslt = get_regs(reg_addr1, &reg_data, 1);
jsa1969 0:cef60cc92da0 718 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 719 _dev->gas_sett.heatr_temp = reg_data;
jsa1969 0:cef60cc92da0 720 rslt = get_regs(reg_addr2, &reg_data, 1);
jsa1969 0:cef60cc92da0 721 if (rslt == BME680_OK) {
jsa1969 0:cef60cc92da0 722 /* Heating duration register value */
jsa1969 0:cef60cc92da0 723 _dev->gas_sett.heatr_dur = reg_data;
jsa1969 0:cef60cc92da0 724 }
jsa1969 0:cef60cc92da0 725 }
jsa1969 0:cef60cc92da0 726 }
jsa1969 0:cef60cc92da0 727
jsa1969 0:cef60cc92da0 728 return rslt;
jsa1969 0:cef60cc92da0 729 }
jsa1969 0:cef60cc92da0 730
jsa1969 0:cef60cc92da0 731 int16_t Bme680::calc_temperature(uint32_t temp_adc)
jsa1969 0:cef60cc92da0 732 {
jsa1969 0:cef60cc92da0 733 int64_t var1;
jsa1969 0:cef60cc92da0 734 int64_t var2;
jsa1969 0:cef60cc92da0 735 int64_t var3;
jsa1969 0:cef60cc92da0 736 int16_t calc_temp;
jsa1969 0:cef60cc92da0 737
jsa1969 0:cef60cc92da0 738 var1 = ((int32_t) temp_adc >> 3) - ((int32_t) _dev->calib.par_t1 << 1);
jsa1969 0:cef60cc92da0 739 var2 = (var1 * (int32_t) _dev->calib.par_t2) >> 11;
jsa1969 0:cef60cc92da0 740 var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
jsa1969 0:cef60cc92da0 741 var3 = ((var3) * ((int32_t) _dev->calib.par_t3 << 4)) >> 14;
jsa1969 0:cef60cc92da0 742 _dev->calib.t_fine = (int32_t) (var2 + var3);
jsa1969 0:cef60cc92da0 743 calc_temp = (int16_t) (((_dev->calib.t_fine * 5) + 128) >> 8);
jsa1969 0:cef60cc92da0 744
jsa1969 0:cef60cc92da0 745 return calc_temp;
jsa1969 0:cef60cc92da0 746 }
jsa1969 0:cef60cc92da0 747
jsa1969 0:cef60cc92da0 748 uint32_t Bme680::calc_pressure(uint32_t pres_adc)
jsa1969 0:cef60cc92da0 749 {
jsa1969 0:cef60cc92da0 750 int32_t var1 = 0;
jsa1969 0:cef60cc92da0 751 int32_t var2 = 0;
jsa1969 0:cef60cc92da0 752 int32_t var3 = 0;
jsa1969 0:cef60cc92da0 753 int32_t pressure_comp = 0;
jsa1969 0:cef60cc92da0 754
jsa1969 0:cef60cc92da0 755 var1 = (((int32_t)_dev->calib.t_fine) >> 1) - 64000;
jsa1969 0:cef60cc92da0 756 var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *
jsa1969 0:cef60cc92da0 757 (int32_t)_dev->calib.par_p6) >> 2;
jsa1969 0:cef60cc92da0 758 var2 = var2 + ((var1 * (int32_t)_dev->calib.par_p5) << 1);
jsa1969 0:cef60cc92da0 759 var2 = (var2 >> 2) + ((int32_t)_dev->calib.par_p4 << 16);
jsa1969 0:cef60cc92da0 760 var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
jsa1969 0:cef60cc92da0 761 ((int32_t)_dev->calib.par_p3 << 5)) >> 3) +
jsa1969 0:cef60cc92da0 762 (((int32_t)_dev->calib.par_p2 * var1) >> 1);
jsa1969 0:cef60cc92da0 763 var1 = var1 >> 18;
jsa1969 0:cef60cc92da0 764 var1 = ((32768 + var1) * (int32_t)_dev->calib.par_p1) >> 15;
jsa1969 0:cef60cc92da0 765 pressure_comp = 1048576 - pres_adc;
jsa1969 0:cef60cc92da0 766 pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));
jsa1969 0:cef60cc92da0 767 if (pressure_comp >= BME680_MAX_OVERFLOW_VAL)
jsa1969 0:cef60cc92da0 768 pressure_comp = ((pressure_comp / (uint32_t)var1) << 1);
jsa1969 0:cef60cc92da0 769 else
jsa1969 0:cef60cc92da0 770 pressure_comp = ((pressure_comp << 1) / (uint32_t)var1);
jsa1969 0:cef60cc92da0 771 var1 = ((int32_t)_dev->calib.par_p9 * (int32_t)(((pressure_comp >> 3) *
jsa1969 0:cef60cc92da0 772 (pressure_comp >> 3)) >> 13)) >> 12;
jsa1969 0:cef60cc92da0 773 var2 = ((int32_t)(pressure_comp >> 2) *
jsa1969 0:cef60cc92da0 774 (int32_t)_dev->calib.par_p8) >> 13;
jsa1969 0:cef60cc92da0 775 var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *
jsa1969 0:cef60cc92da0 776 (int32_t)(pressure_comp >> 8) *
jsa1969 0:cef60cc92da0 777 (int32_t)_dev->calib.par_p10) >> 17;
jsa1969 0:cef60cc92da0 778
jsa1969 0:cef60cc92da0 779 pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +
jsa1969 0:cef60cc92da0 780 ((int32_t)_dev->calib.par_p7 << 7)) >> 4);
jsa1969 0:cef60cc92da0 781
jsa1969 0:cef60cc92da0 782 return (uint32_t)pressure_comp;
jsa1969 0:cef60cc92da0 783
jsa1969 0:cef60cc92da0 784 }
jsa1969 0:cef60cc92da0 785
jsa1969 0:cef60cc92da0 786 uint32_t Bme680::calc_humidity(uint16_t hum_adc)
jsa1969 0:cef60cc92da0 787 {
jsa1969 0:cef60cc92da0 788 int32_t var1;
jsa1969 0:cef60cc92da0 789 int32_t var2;
jsa1969 0:cef60cc92da0 790 int32_t var3;
jsa1969 0:cef60cc92da0 791 int32_t var4;
jsa1969 0:cef60cc92da0 792 int32_t var5;
jsa1969 0:cef60cc92da0 793 int32_t var6;
jsa1969 0:cef60cc92da0 794 int32_t temp_scaled;
jsa1969 0:cef60cc92da0 795 int32_t calc_hum;
jsa1969 0:cef60cc92da0 796
jsa1969 0:cef60cc92da0 797 temp_scaled = (((int32_t) _dev->calib.t_fine * 5) + 128) >> 8;
jsa1969 0:cef60cc92da0 798 var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) _dev->calib.par_h1 * 16)))
jsa1969 0:cef60cc92da0 799 - (((temp_scaled * (int32_t) _dev->calib.par_h3) / ((int32_t) 100)) >> 1);
jsa1969 0:cef60cc92da0 800 var2 = ((int32_t) _dev->calib.par_h2
jsa1969 0:cef60cc92da0 801 * (((temp_scaled * (int32_t) _dev->calib.par_h4) / ((int32_t) 100))
jsa1969 0:cef60cc92da0 802 + (((temp_scaled * ((temp_scaled * (int32_t) _dev->calib.par_h5) / ((int32_t) 100))) >> 6)
jsa1969 0:cef60cc92da0 803 / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10;
jsa1969 0:cef60cc92da0 804 var3 = var1 * var2;
jsa1969 0:cef60cc92da0 805 var4 = (int32_t) _dev->calib.par_h6 << 7;
jsa1969 0:cef60cc92da0 806 var4 = ((var4) + ((temp_scaled * (int32_t) _dev->calib.par_h7) / ((int32_t) 100))) >> 4;
jsa1969 0:cef60cc92da0 807 var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
jsa1969 0:cef60cc92da0 808 var6 = (var4 * var5) >> 1;
jsa1969 0:cef60cc92da0 809 calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12;
jsa1969 0:cef60cc92da0 810
jsa1969 0:cef60cc92da0 811 if (calc_hum > 100000) /* Cap at 100%rH */
jsa1969 0:cef60cc92da0 812 calc_hum = 100000;
jsa1969 0:cef60cc92da0 813 else if (calc_hum < 0)
jsa1969 0:cef60cc92da0 814 calc_hum = 0;
jsa1969 0:cef60cc92da0 815
jsa1969 0:cef60cc92da0 816 return (uint32_t) calc_hum;
jsa1969 0:cef60cc92da0 817 }
jsa1969 0:cef60cc92da0 818
jsa1969 0:cef60cc92da0 819 uint32_t Bme680::calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range)
jsa1969 0:cef60cc92da0 820 {
jsa1969 0:cef60cc92da0 821 int64_t var1;
jsa1969 0:cef60cc92da0 822 uint64_t var2;
jsa1969 0:cef60cc92da0 823 int64_t var3;
jsa1969 0:cef60cc92da0 824 uint32_t calc_gas_res;
jsa1969 0:cef60cc92da0 825 /**Look up table 1 for the possible gas range values */
jsa1969 0:cef60cc92da0 826 uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647),
jsa1969 0:cef60cc92da0 827 UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777),
jsa1969 0:cef60cc92da0 828 UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228),
jsa1969 0:cef60cc92da0 829 UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) };
jsa1969 0:cef60cc92da0 830 /**Look up table 2 for the possible gas range values */
jsa1969 0:cef60cc92da0 831 uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000),
jsa1969 0:cef60cc92da0 832 UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016),
jsa1969 0:cef60cc92da0 833 UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000),
jsa1969 0:cef60cc92da0 834 UINT32_C(250000), UINT32_C(125000) };
jsa1969 0:cef60cc92da0 835
jsa1969 0:cef60cc92da0 836 var1 = (int64_t) ((1340 + (5 * (int64_t) _dev->calib.range_sw_err)) *
jsa1969 0:cef60cc92da0 837 ((int64_t) lookupTable1[gas_range])) >> 16;
jsa1969 0:cef60cc92da0 838 var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1);
jsa1969 0:cef60cc92da0 839 var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9);
jsa1969 0:cef60cc92da0 840 calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2);
jsa1969 0:cef60cc92da0 841
jsa1969 0:cef60cc92da0 842 return calc_gas_res;
jsa1969 0:cef60cc92da0 843 }
jsa1969 0:cef60cc92da0 844
jsa1969 0:cef60cc92da0 845