Manuel Caballero / BME680

Dependents:   MERGE Sensor_iAQ_sgp30_bme_si7051 POCBreath_V2_smd_commercial

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BME680.cpp Source File

BME680.cpp

00001 /**
00002  * @brief       BME680.cpp
00003  * @details     Low power gas, pressure, temperature & humidity sensor.
00004  *              Function file.
00005  *
00006  *
00007  * @return      N/A
00008  *
00009  * @author      Manuel Caballero
00010  * @date        21/July/2018
00011  * @version     21/July/2018    The ORIGIN
00012  * @pre         This is just a port from Bosh driver to mBed ( c++ )
00013  * @warning     N/A
00014  * @pre         This code belongs to Nimbus Centre ( http://www.nimbus.cit.ie ).
00015  */
00016 /**\mainpage
00017  * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
00018  *
00019  * Redistribution and use in source and binary forms, with or without
00020  * modification, are permitted provided that the following conditions are met:
00021  *
00022  * Redistributions of source code must retain the above copyright
00023  * notice, this list of conditions and the following disclaimer.
00024  *
00025  * Redistributions in binary form must reproduce the above copyright
00026  * notice, this list of conditions and the following disclaimer in the
00027  * documentation and/or other materials provided with the distribution.
00028  *
00029  * Neither the name of the copyright holder nor the names of the
00030  * contributors may be used to endorse or promote products derived from
00031  * this software without specific prior written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00034  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
00035  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00036  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00037  * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
00038  * OR CONTRIBUTORS BE LIABLE FOR ANY
00039  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
00040  * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
00041  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00042  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00043  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00045  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00046  * ANY WAY OUT OF THE USE OF THIS
00047  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00048  *
00049  * The information provided is believed to be accurate and reliable.
00050  * The copyright holder assumes no responsibility
00051  * for the consequences of use
00052  * of such information nor for any infringement of patents or
00053  * other rights of third parties which may result from its use.
00054  * No license is granted by implication or otherwise under any patent or
00055  * patent rights of the copyright holder.
00056  *
00057  * File     bme680.c
00058  * @date    19 Jun 2018
00059  * @version 3.5.9
00060  *
00061  */
00062 
00063 /*! @file bme680.c
00064  @brief Sensor driver for BME680 sensor */
00065 #include "BME680.h"
00066 
00067 BME680::BME680 ( PinName sda, PinName scl, uint32_t freq )
00068     : _i2c          ( sda, scl )
00069 {
00070     _i2c.frequency  ( freq );
00071 }
00072 
00073 
00074 BME680::~BME680()
00075 {
00076 }
00077 
00078 
00079 /****************** Global Function Definitions *******************************/
00080 /*!
00081  *@brief This API is the entry point.
00082  *It reads the chip-id and calibration data from the sensor.
00083  */
00084 int8_t BME680::bme680_init(struct bme680_dev *dev)
00085 {
00086     int8_t rslt;
00087 
00088     /* Check for null pointer in the device structure*/
00089     rslt = null_ptr_check(dev);
00090     if (rslt == BME680_OK) {
00091         /* Soft reset to restore it to default values*/
00092         rslt = bme680_soft_reset(dev);
00093         if (rslt == BME680_OK) {
00094             rslt = bme680_get_regs(BME680_CHIP_ID_ADDR, &dev->chip_id , 1, dev);
00095             if (rslt == BME680_OK) {
00096                 if (dev->chip_id  == BME680_CHIP_ID) {
00097                     /* Get the Calibration data */
00098                     rslt = get_calib_data(dev);
00099                 } else {
00100                     rslt = BME680_E_DEV_NOT_FOUND;
00101                 }
00102             }
00103         }
00104     }
00105 
00106     return rslt;
00107 }
00108 
00109 /*!
00110  * @brief This API reads the data from the given register address of the sensor.
00111  */
00112 int8_t BME680::bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev)
00113 {
00114     int8_t rslt;
00115 
00116     /* Check for null pointer in the device structure*/
00117     rslt = null_ptr_check(dev);
00118     if (rslt == BME680_OK) {
00119         if (dev->intf  == BME680_SPI_INTF ) {
00120             /* Set the memory page */
00121             rslt = set_mem_page(reg_addr, dev);
00122             if (rslt == BME680_OK)
00123                 reg_addr = reg_addr | BME680_SPI_RD_MSK;
00124         }
00125         dev->com_rslt  = dev->read (dev->dev_id , reg_addr, reg_data, len);
00126         if (dev->com_rslt  != 0)
00127             rslt = BME680_E_COM_FAIL;
00128     }
00129 
00130     return rslt;
00131 }
00132 
00133 /*!
00134  * @brief This API writes the given data to the register address
00135  * of the sensor.
00136  */
00137 int8_t BME680::bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev)
00138 {
00139     int8_t rslt;
00140     /* Length of the temporary buffer is 2*(length of register)*/
00141     uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = { 0 };
00142     uint16_t index;
00143 
00144     /* Check for null pointer in the device structure*/
00145     rslt = null_ptr_check(dev);
00146     if (rslt == BME680_OK) {
00147         if ((len > 0) && (len < BME680_TMP_BUFFER_LENGTH / 2)) {
00148             /* Interleave the 2 arrays */
00149             for (index = 0; index < len; index++) {
00150                 if (dev->intf  == BME680_SPI_INTF ) {
00151                     /* Set the memory page */
00152                     rslt = set_mem_page(reg_addr[index], dev);
00153                     tmp_buff[(2 * index)] = reg_addr[index] & BME680_SPI_WR_MSK;
00154                 } else {
00155                     tmp_buff[(2 * index)] = reg_addr[index];
00156                 }
00157                 tmp_buff[(2 * index) + 1] = reg_data[index];
00158             }
00159             /* Write the interleaved array */
00160             if (rslt == BME680_OK) {
00161                 dev->com_rslt  = dev->write (dev->dev_id , tmp_buff[0], &tmp_buff[1], (2 * len) - 1);
00162                 if (dev->com_rslt  != 0)
00163                     rslt = BME680_E_COM_FAIL;
00164             }
00165         } else {
00166             rslt = BME680_E_INVALID_LENGTH;
00167         }
00168     }
00169 
00170     return rslt;
00171 }
00172 
00173 /*!
00174  * @brief This API performs the soft reset of the sensor.
00175  */
00176 int8_t BME680::bme680_soft_reset(struct bme680_dev *dev)
00177 {
00178     int8_t rslt;
00179     uint8_t reg_addr = BME680_SOFT_RESET_ADDR;
00180     /* 0xb6 is the soft reset command */
00181     uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD;
00182 
00183     /* Check for null pointer in the device structure*/
00184     rslt = null_ptr_check(dev);
00185     if (rslt == BME680_OK) {
00186         if (dev->intf  == BME680_SPI_INTF )
00187             rslt = get_mem_page(dev);
00188 
00189         /* Reset the device */
00190         if (rslt == BME680_OK) {
00191             rslt = bme680_set_regs(&reg_addr, &soft_rst_cmd, 1, dev);
00192             /* Wait for 5ms */
00193             dev->delay_ms (BME680_RESET_PERIOD);
00194 
00195             if (rslt == BME680_OK) {
00196                 /* After reset get the memory page */
00197                 if (dev->intf  == BME680_SPI_INTF )
00198                     rslt = get_mem_page(dev);
00199             }
00200         }
00201     }
00202 
00203     return rslt;
00204 }
00205 
00206 /*!
00207  * @brief This API is used to set the oversampling, filter and T,P,H, gas selection
00208  * settings in the sensor.
00209  */
00210 int8_t BME680::bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev)
00211 {
00212     int8_t rslt;
00213     uint8_t reg_addr;
00214     uint8_t data = 0;
00215     uint8_t count = 0;
00216     uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = { 0 };
00217     uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 };
00218     uint8_t intended_power_mode = dev->power_mode ; /* Save intended power mode */
00219 
00220     /* Check for null pointer in the device structure*/
00221     rslt = null_ptr_check(dev);
00222     if (rslt == BME680_OK) {
00223         if (desired_settings & BME680_GAS_MEAS_SEL)
00224             rslt = set_gas_config(dev);
00225 
00226         dev->power_mode  = BME680_SLEEP_MODE;
00227         if (rslt == BME680_OK)
00228             rslt = bme680_set_sensor_mode(dev);
00229 
00230         /* Selecting the filter */
00231         if (desired_settings & BME680_FILTER_SEL) {
00232             rslt = boundary_check(&dev->tph_sett .filter , BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127, dev);
00233             reg_addr = BME680_CONF_ODR_FILT_ADDR;
00234 
00235             if (rslt == BME680_OK)
00236                 rslt = bme680_get_regs(reg_addr, &data, 1, dev);
00237 
00238             if (desired_settings & BME680_FILTER_SEL)
00239                 data = BME680_SET_BITS(data, BME680_FILTER, dev->tph_sett .filter );
00240 
00241             reg_array[count] = reg_addr; /* Append configuration */
00242             data_array[count] = data;
00243             count++;
00244         }
00245 
00246         /* Selecting heater control for the sensor */
00247         if (desired_settings & BME680_HCNTRL_SEL) {
00248             rslt = boundary_check(&dev->gas_sett .heatr_ctrl , BME680_ENABLE_HEATER,
00249                                   BME680_DISABLE_HEATER, dev);
00250             reg_addr = BME680_CONF_HEAT_CTRL_ADDR;
00251 
00252             if (rslt == BME680_OK)
00253                 rslt = bme680_get_regs(reg_addr, &data, 1, dev);
00254             data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, dev->gas_sett .heatr_ctrl );
00255 
00256             reg_array[count] = reg_addr; /* Append configuration */
00257             data_array[count] = data;
00258             count++;
00259         }
00260 
00261         /* Selecting heater T,P oversampling for the sensor */
00262         if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) {
00263             rslt = boundary_check(&dev->tph_sett .os_temp , BME680_OS_NONE, BME680_OS_16X, dev);
00264             reg_addr = BME680_CONF_T_P_MODE_ADDR;
00265 
00266             if (rslt == BME680_OK)
00267                 rslt = bme680_get_regs(reg_addr, &data, 1, dev);
00268 
00269             if (desired_settings & BME680_OST_SEL)
00270                 data = BME680_SET_BITS(data, BME680_OST, dev->tph_sett .os_temp );
00271 
00272             if (desired_settings & BME680_OSP_SEL)
00273                 data = BME680_SET_BITS(data, BME680_OSP, dev->tph_sett .os_pres );
00274 
00275             reg_array[count] = reg_addr;
00276             data_array[count] = data;
00277             count++;
00278         }
00279 
00280         /* Selecting humidity oversampling for the sensor */
00281         if (desired_settings & BME680_OSH_SEL) {
00282             rslt = boundary_check(&dev->tph_sett .os_hum , BME680_OS_NONE, BME680_OS_16X, dev);
00283             reg_addr = BME680_CONF_OS_H_ADDR;
00284 
00285             if (rslt == BME680_OK)
00286                 rslt = bme680_get_regs(reg_addr, &data, 1, dev);
00287             data = BME680_SET_BITS_POS_0(data, BME680_OSH, dev->tph_sett .os_hum );
00288 
00289             reg_array[count] = reg_addr; /* Append configuration */
00290             data_array[count] = data;
00291             count++;
00292         }
00293 
00294         /* Selecting the runGas and NB conversion settings for the sensor */
00295         if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) {
00296             rslt = boundary_check(&dev->gas_sett .run_gas , BME680_RUN_GAS_DISABLE,
00297                                   BME680_RUN_GAS_ENABLE, dev);
00298             if (rslt == BME680_OK) {
00299                 /* Validate boundary conditions */
00300                 rslt = boundary_check(&dev->gas_sett .nb_conv , BME680_NBCONV_MIN,
00301                                       BME680_NBCONV_MAX, dev);
00302             }
00303 
00304             reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR;
00305 
00306             if (rslt == BME680_OK)
00307                 rslt = bme680_get_regs(reg_addr, &data, 1, dev);
00308 
00309             if (desired_settings & BME680_RUN_GAS_SEL)
00310                 data = BME680_SET_BITS(data, BME680_RUN_GAS, dev->gas_sett .run_gas );
00311 
00312             if (desired_settings & BME680_NBCONV_SEL)
00313                 data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, dev->gas_sett .nb_conv );
00314 
00315             reg_array[count] = reg_addr; /* Append configuration */
00316             data_array[count] = data;
00317             count++;
00318         }
00319 
00320         if (rslt == BME680_OK)
00321             rslt = bme680_set_regs(reg_array, data_array, count, dev);
00322 
00323         /* Restore previous intended power mode */
00324         dev->power_mode  = intended_power_mode;
00325     }
00326 
00327     return rslt;
00328 }
00329 
00330 /*!
00331  * @brief This API is used to get the oversampling, filter and T,P,H, gas selection
00332  * settings in the sensor.
00333  */
00334 int8_t BME680::bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev)
00335 {
00336     int8_t rslt;
00337     /* starting address of the register array for burst read*/
00338     uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR;
00339     uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 };
00340 
00341     /* Check for null pointer in the device structure*/
00342     rslt = null_ptr_check(dev);
00343     if (rslt == BME680_OK) {
00344         rslt = bme680_get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH, dev);
00345 
00346         if (rslt == BME680_OK) {
00347             if (desired_settings & BME680_GAS_MEAS_SEL)
00348                 rslt = get_gas_config(dev);
00349 
00350             /* get the T,P,H ,Filter,ODR settings here */
00351             if (desired_settings & BME680_FILTER_SEL)
00352                 dev->tph_sett .filter  = BME680_GET_BITS(data_array[BME680_REG_FILTER_INDEX],
00353                                                        BME680_FILTER);
00354 
00355             if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) {
00356                 dev->tph_sett .os_temp  = BME680_GET_BITS(data_array[BME680_REG_TEMP_INDEX], BME680_OST);
00357                 dev->tph_sett .os_pres  = BME680_GET_BITS(data_array[BME680_REG_PRES_INDEX], BME680_OSP);
00358             }
00359 
00360             if (desired_settings & BME680_OSH_SEL)
00361                 dev->tph_sett .os_hum  = BME680_GET_BITS_POS_0(data_array[BME680_REG_HUM_INDEX],
00362                                        BME680_OSH);
00363 
00364             /* get the gas related settings */
00365             if (desired_settings & BME680_HCNTRL_SEL)
00366                 dev->gas_sett .heatr_ctrl  = BME680_GET_BITS_POS_0(data_array[BME680_REG_HCTRL_INDEX],
00367                                            BME680_HCTRL);
00368 
00369             if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) {
00370                 dev->gas_sett .nb_conv  = BME680_GET_BITS_POS_0(data_array[BME680_REG_NBCONV_INDEX],
00371                                         BME680_NBCONV);
00372                 dev->gas_sett .run_gas  = BME680_GET_BITS(data_array[BME680_REG_RUN_GAS_INDEX],
00373                                                         BME680_RUN_GAS);
00374             }
00375         }
00376     } else {
00377         rslt = BME680_E_NULL_PTR;
00378     }
00379 
00380     return rslt;
00381 }
00382 
00383 /*!
00384  * @brief This API is used to set the power mode of the sensor.
00385  */
00386 int8_t BME680::bme680_set_sensor_mode(struct bme680_dev *dev)
00387 {
00388     int8_t rslt;
00389     uint8_t tmp_pow_mode;
00390     uint8_t pow_mode = 0;
00391     uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR;
00392 
00393     /* Check for null pointer in the device structure*/
00394     rslt = null_ptr_check(dev);
00395     if (rslt == BME680_OK) {
00396         /* Call repeatedly until in sleep */
00397         do {
00398             rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1, dev);
00399             if (rslt == BME680_OK) {
00400                 /* Put to sleep before changing mode */
00401                 pow_mode = (tmp_pow_mode & BME680_MODE_MSK);
00402 
00403                 if (pow_mode != BME680_SLEEP_MODE) {
00404                     tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */
00405                     rslt = bme680_set_regs(&reg_addr, &tmp_pow_mode, 1, dev);
00406                     dev->delay_ms (BME680_POLL_PERIOD_MS);
00407                 }
00408             }
00409         } while (pow_mode != BME680_SLEEP_MODE);
00410 
00411         /* Already in sleep */
00412         if (dev->power_mode  != BME680_SLEEP_MODE) {
00413             tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (dev->power_mode  & BME680_MODE_MSK);
00414             if (rslt == BME680_OK)
00415                 rslt = bme680_set_regs(&reg_addr, &tmp_pow_mode, 1, dev);
00416         }
00417     }
00418 
00419     return rslt;
00420 }
00421 
00422 /*!
00423  * @brief This API is used to get the power mode of the sensor.
00424  */
00425 int8_t BME680::bme680_get_sensor_mode(struct bme680_dev *dev)
00426 {
00427     int8_t rslt;
00428     uint8_t mode;
00429 
00430     /* Check for null pointer in the device structure*/
00431     rslt = null_ptr_check(dev);
00432     if (rslt == BME680_OK) {
00433         rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1, dev);
00434         /* Masking the other register bit info*/
00435         dev->power_mode  = mode & BME680_MODE_MSK;
00436     }
00437 
00438     return rslt;
00439 }
00440 
00441 /*!
00442  * @brief This API is used to set the profile duration of the sensor.
00443  */
00444 void BME680::bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev)
00445 {
00446     uint32_t tph_dur; /* Calculate in us */
00447     uint32_t meas_cycles;
00448     uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16};
00449 
00450     meas_cycles = os_to_meas_cycles[dev->tph_sett .os_temp ];
00451     meas_cycles += os_to_meas_cycles[dev->tph_sett .os_pres ];
00452     meas_cycles += os_to_meas_cycles[dev->tph_sett .os_hum ];
00453 
00454     /* TPH measurement duration */
00455     tph_dur = meas_cycles * UINT32_C(1963);
00456     tph_dur += UINT32_C(477 * 4); /* TPH switching duration */
00457     tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */
00458     tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/
00459     tph_dur /= UINT32_C(1000); /* Convert to ms */
00460 
00461     tph_dur += UINT32_C(1); /* Wake up duration of 1ms */
00462     /* The remaining time should be used for heating */
00463     dev->gas_sett .heatr_dur  = duration - (uint16_t) tph_dur;
00464 }
00465 
00466 /*!
00467  * @brief This API is used to get the profile duration of the sensor.
00468  */
00469 void BME680::bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev)
00470 {
00471     uint32_t tph_dur; /* Calculate in us */
00472     uint32_t meas_cycles;
00473     uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16};
00474 
00475     meas_cycles = os_to_meas_cycles[dev->tph_sett .os_temp ];
00476     meas_cycles += os_to_meas_cycles[dev->tph_sett .os_pres ];
00477     meas_cycles += os_to_meas_cycles[dev->tph_sett .os_hum ];
00478 
00479     /* TPH measurement duration */
00480     tph_dur = meas_cycles * UINT32_C(1963);
00481     tph_dur += UINT32_C(477 * 4); /* TPH switching duration */
00482     tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */
00483     tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/
00484     tph_dur /= UINT32_C(1000); /* Convert to ms */
00485 
00486     tph_dur += UINT32_C(1); /* Wake up duration of 1ms */
00487 
00488     *duration = (uint16_t) tph_dur;
00489 
00490     /* Get the gas duration only when the run gas is enabled */
00491     if (dev->gas_sett .run_gas ) {
00492         /* The remaining time should be used for heating */
00493         *duration += dev->gas_sett .heatr_dur ;
00494     }
00495 }
00496 
00497 /*!
00498  * @brief This API reads the pressure, temperature and humidity and gas data
00499  * from the sensor, compensates the data and store it in the bme680_data
00500  * structure instance passed by the user.
00501  */
00502 int8_t BME680::bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev)
00503 {
00504     int8_t rslt;
00505 
00506     /* Check for null pointer in the device structure*/
00507     rslt = null_ptr_check(dev);
00508     if (rslt == BME680_OK) {
00509         /* Reading the sensor data in forced mode only */
00510         rslt = read_field_data(data, dev);
00511         if (rslt == BME680_OK) {
00512             if (data->status  & BME680_NEW_DATA_MSK)
00513                 dev->new_fields  = 1;
00514             else
00515                 dev->new_fields  = 0;
00516         }
00517     }
00518 
00519     return rslt;
00520 }
00521 
00522 /*!
00523  * @brief This internal API is used to read the calibrated data from the sensor.
00524  */
00525 int8_t BME680::get_calib_data(struct bme680_dev *dev)
00526 {
00527     int8_t rslt;
00528     uint8_t coeff_array[BME680_COEFF_SIZE] = { 0 };
00529     uint8_t temp_var = 0; /* Temporary variable */
00530 
00531     /* Check for null pointer in the device structure*/
00532     rslt = null_ptr_check(dev);
00533     if (rslt == BME680_OK) {
00534         rslt = bme680_get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN, dev);
00535         /* Append the second half in the same array */
00536         if (rslt == BME680_OK)
00537             rslt = bme680_get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN]
00538                                    , BME680_COEFF_ADDR2_LEN, dev);
00539 
00540         /* Temperature related coefficients */
00541         dev->calib .par_t1  = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T1_MSB_REG],
00542                                         coeff_array[BME680_T1_LSB_REG]));
00543         dev->calib .par_t2  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T2_MSB_REG],
00544                                        coeff_array[BME680_T2_LSB_REG]));
00545         dev->calib .par_t3  = (int8_t) (coeff_array[BME680_T3_REG]);
00546 
00547         /* Pressure related coefficients */
00548         dev->calib .par_p1  = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P1_MSB_REG],
00549                                         coeff_array[BME680_P1_LSB_REG]));
00550         dev->calib .par_p2  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P2_MSB_REG],
00551                                        coeff_array[BME680_P2_LSB_REG]));
00552         dev->calib .par_p3  = (int8_t) coeff_array[BME680_P3_REG];
00553         dev->calib .par_p4  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P4_MSB_REG],
00554                                        coeff_array[BME680_P4_LSB_REG]));
00555         dev->calib .par_p5  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P5_MSB_REG],
00556                                        coeff_array[BME680_P5_LSB_REG]));
00557         dev->calib .par_p6  = (int8_t) (coeff_array[BME680_P6_REG]);
00558         dev->calib .par_p7  = (int8_t) (coeff_array[BME680_P7_REG]);
00559         dev->calib .par_p8  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P8_MSB_REG],
00560                                        coeff_array[BME680_P8_LSB_REG]));
00561         dev->calib .par_p9  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P9_MSB_REG],
00562                                        coeff_array[BME680_P9_LSB_REG]));
00563         dev->calib .par_p10  = (uint8_t) (coeff_array[BME680_P10_REG]);
00564 
00565         /* Humidity related coefficients */
00566         dev->calib .par_h1  = (uint16_t) (((uint16_t) coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL)
00567                                         | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK));
00568         dev->calib .par_h2  = (uint16_t) (((uint16_t) coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL)
00569                                         | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL));
00570         dev->calib .par_h3  = (int8_t) coeff_array[BME680_H3_REG];
00571         dev->calib .par_h4  = (int8_t) coeff_array[BME680_H4_REG];
00572         dev->calib .par_h5  = (int8_t) coeff_array[BME680_H5_REG];
00573         dev->calib .par_h6  = (uint8_t) coeff_array[BME680_H6_REG];
00574         dev->calib .par_h7  = (int8_t) coeff_array[BME680_H7_REG];
00575 
00576         /* Gas heater related coefficients */
00577         dev->calib .par_gh1  = (int8_t) coeff_array[BME680_GH1_REG];
00578         dev->calib .par_gh2  = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG],
00579                                         coeff_array[BME680_GH2_LSB_REG]));
00580         dev->calib .par_gh3  = (int8_t) coeff_array[BME680_GH3_REG];
00581 
00582         /* Other coefficients */
00583         if (rslt == BME680_OK) {
00584             rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1, dev);
00585 
00586             dev->calib .res_heat_range  = ((temp_var & BME680_RHRANGE_MSK) / 16);
00587             if (rslt == BME680_OK) {
00588                 rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1, dev);
00589 
00590                 dev->calib .res_heat_val  = (int8_t) temp_var;
00591                 if (rslt == BME680_OK)
00592                     rslt = bme680_get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1, dev);
00593             }
00594         }
00595         dev->calib .range_sw_err  = ((int8_t) temp_var & (int8_t) BME680_RSERROR_MSK) / 16;
00596     }
00597 
00598     return rslt;
00599 }
00600 
00601 /*!
00602  * @brief This internal API is used to set the gas configuration of the sensor.
00603  */
00604 int8_t BME680::set_gas_config(struct bme680_dev *dev)
00605 {
00606     int8_t rslt;
00607 
00608     /* Check for null pointer in the device structure*/
00609     rslt = null_ptr_check(dev);
00610     if (rslt == BME680_OK) {
00611 
00612         uint8_t reg_addr[2] = {0};
00613         uint8_t reg_data[2] = {0};
00614 
00615         if (dev->power_mode  == BME680_FORCED_MODE) {
00616             reg_addr[0] = BME680_RES_HEAT0_ADDR;
00617             reg_data[0] = calc_heater_res(dev->gas_sett .heatr_temp , dev);
00618             reg_addr[1] = BME680_GAS_WAIT0_ADDR;
00619             reg_data[1] = calc_heater_dur(dev->gas_sett .heatr_dur );
00620             dev->gas_sett .nb_conv  = 0;
00621         } else {
00622             rslt = BME680_W_DEFINE_PWR_MODE;
00623         }
00624         if (rslt == BME680_OK)
00625             rslt = bme680_set_regs(reg_addr, reg_data, 2, dev);
00626     }
00627 
00628     return rslt;
00629 }
00630 
00631 /*!
00632  * @brief This internal API is used to get the gas configuration of the sensor.
00633  * @note heatr_temp and heatr_dur values are currently register data
00634  * and not the actual values set
00635  */
00636 int8_t BME680::get_gas_config(struct bme680_dev *dev)
00637 {
00638     int8_t rslt;
00639     /* starting address of the register array for burst read*/
00640     uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START;
00641     uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START;
00642     uint8_t reg_data = 0;
00643 
00644     /* Check for null pointer in the device structure*/
00645     rslt = null_ptr_check(dev);
00646     if (rslt == BME680_OK) {
00647         if (BME680_SPI_INTF  == dev->intf ) {
00648             /* Memory page switch the SPI address*/
00649             rslt = set_mem_page(reg_addr1, dev);
00650         }
00651 
00652         if (rslt == BME680_OK) {
00653             rslt = bme680_get_regs(reg_addr1, &reg_data, 1, dev);
00654             if (rslt == BME680_OK) {
00655                 dev->gas_sett .heatr_temp  = reg_data;
00656                 rslt = bme680_get_regs(reg_addr2, &reg_data, 1, dev);
00657                 if (rslt == BME680_OK) {
00658                     /* Heating duration register value */
00659                     dev->gas_sett .heatr_dur  = reg_data;
00660                 }
00661             }
00662         }
00663     }
00664 
00665     return rslt;
00666 }
00667 
00668 #ifndef BME680_FLOAT_POINT_COMPENSATION
00669 
00670 /*!
00671  * @brief This internal API is used to calculate the temperature value.
00672  */
00673 int16_t BME680::calc_temperature(uint32_t temp_adc, struct bme680_dev *dev)
00674 {
00675     int64_t var1;
00676     int64_t var2;
00677     int64_t var3;
00678     int16_t calc_temp;
00679 
00680     var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib .par_t1  << 1);
00681     var2 = (var1 * (int32_t) dev->calib .par_t2 ) >> 11;
00682     var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
00683     var3 = ((var3) * ((int32_t) dev->calib .par_t3  << 4)) >> 14;
00684     dev->calib .t_fine  = (int32_t) (var2 + var3);
00685     calc_temp = (int16_t) (((dev->calib .t_fine  * 5) + 128) >> 8);
00686 
00687     return calc_temp;
00688 }
00689 
00690 /*!
00691  * @brief This internal API is used to calculate the pressure value.
00692  */
00693 uint32_t BME680::calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev)
00694 {
00695     int32_t var1;
00696     int32_t var2;
00697     int32_t var3;
00698     int32_t pressure_comp;
00699 
00700     var1 = (((int32_t)dev->calib .t_fine ) >> 1) - 64000;
00701     var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *
00702             (int32_t)dev->calib .par_p6 ) >> 2;
00703     var2 = var2 + ((var1 * (int32_t)dev->calib .par_p5 ) << 1);
00704     var2 = (var2 >> 2) + ((int32_t)dev->calib .par_p4  << 16);
00705     var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
00706              ((int32_t)dev->calib .par_p3  << 5)) >> 3) +
00707            (((int32_t)dev->calib .par_p2  * var1) >> 1);
00708     var1 = var1 >> 18;
00709     var1 = ((32768 + var1) * (int32_t)dev->calib .par_p1 ) >> 15;
00710     pressure_comp = 1048576 - pres_adc;
00711     pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));
00712     if (pressure_comp >= BME680_MAX_OVERFLOW_VAL)
00713         pressure_comp = ((pressure_comp / var1) << 1);
00714     else
00715         pressure_comp = ((pressure_comp << 1) / var1);
00716     var1 = ((int32_t)dev->calib .par_p9  * (int32_t)(((pressure_comp >> 3) *
00717             (pressure_comp >> 3)) >> 13)) >> 12;
00718     var2 = ((int32_t)(pressure_comp >> 2) *
00719             (int32_t)dev->calib .par_p8 ) >> 13;
00720     var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *
00721             (int32_t)(pressure_comp >> 8) *
00722             (int32_t)dev->calib .par_p10 ) >> 17;
00723 
00724     pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +
00725                     ((int32_t)dev->calib .par_p7  << 7)) >> 4);
00726 
00727     return (uint32_t)pressure_comp;
00728 
00729 }
00730 
00731 /*!
00732  * @brief This internal API is used to calculate the humidity value.
00733  */
00734 uint32_t BME680::calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev)
00735 {
00736     int32_t var1;
00737     int32_t var2;
00738     int32_t var3;
00739     int32_t var4;
00740     int32_t var5;
00741     int32_t var6;
00742     int32_t temp_scaled;
00743     int32_t calc_hum;
00744 
00745     temp_scaled = (((int32_t) dev->calib .t_fine  * 5) + 128) >> 8;
00746     var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) dev->calib .par_h1  * 16)))
00747            - (((temp_scaled * (int32_t) dev->calib .par_h3 ) / ((int32_t) 100)) >> 1);
00748     var2 = ((int32_t) dev->calib .par_h2 
00749             * (((temp_scaled * (int32_t) dev->calib .par_h4 ) / ((int32_t) 100))
00750                + (((temp_scaled * ((temp_scaled * (int32_t) dev->calib .par_h5 ) / ((int32_t) 100))) >> 6)
00751                   / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10;
00752     var3 = var1 * var2;
00753     var4 = (int32_t) dev->calib .par_h6  << 7;
00754     var4 = ((var4) + ((temp_scaled * (int32_t) dev->calib .par_h7 ) / ((int32_t) 100))) >> 4;
00755     var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
00756     var6 = (var4 * var5) >> 1;
00757     calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12;
00758 
00759     if (calc_hum > 100000) /* Cap at 100%rH */
00760         calc_hum = 100000;
00761     else if (calc_hum < 0)
00762         calc_hum = 0;
00763 
00764     return (uint32_t) calc_hum;
00765 }
00766 
00767 /*!
00768  * @brief This internal API is used to calculate the Gas Resistance value.
00769  */
00770 uint32_t BME680::calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev)
00771 {
00772     int64_t var1;
00773     uint64_t var2;
00774     int64_t var3;
00775     uint32_t calc_gas_res;
00776     /**Look up table 1 for the possible gas range values */
00777     uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647),
00778                                   UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777),
00779                                   UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228),
00780                                   UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647)
00781                                 };
00782     /**Look up table 2 for the possible gas range values */
00783     uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000),
00784                                   UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016),
00785                                   UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000),
00786                                   UINT32_C(250000), UINT32_C(125000)
00787                                 };
00788 
00789     var1 = (int64_t) ((1340 + (5 * (int64_t) dev->calib .range_sw_err )) *
00790                       ((int64_t) lookupTable1[gas_range])) >> 16;
00791     var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1);
00792     var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9);
00793     calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2);
00794 
00795     return calc_gas_res;
00796 }
00797 
00798 /*!
00799  * @brief This internal API is used to calculate the Heat Resistance value.
00800  */
00801 uint8_t BME680::calc_heater_res(uint16_t temp, const struct bme680_dev *dev)
00802 {
00803     uint8_t heatr_res;
00804     int32_t var1;
00805     int32_t var2;
00806     int32_t var3;
00807     int32_t var4;
00808     int32_t var5;
00809     int32_t heatr_res_x100;
00810 
00811     if (temp > 400) /* Cap temperature */
00812         temp = 400;
00813 
00814     var1 = (((int32_t) dev->amb_temp  * dev->calib .par_gh3 ) / 1000) * 256;
00815     var2 = (dev->calib .par_gh1  + 784) * (((((dev->calib .par_gh2  + 154009) * temp * 5) / 100) + 3276800) / 10);
00816     var3 = var1 + (var2 / 2);
00817     var4 = (var3 / (dev->calib .res_heat_range  + 4));
00818     var5 = (131 * dev->calib .res_heat_val ) + 65536;
00819     heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34);
00820     heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100);
00821 
00822     return heatr_res;
00823 }
00824 
00825 #else
00826 
00827 
00828 /*!
00829  * @brief This internal API is used to calculate the
00830  * temperature value in float format
00831  */
00832 float BME680::calc_temperature(uint32_t temp_adc, struct bme680_dev *dev)
00833 {
00834     float var1 = 0;
00835     float var2 = 0;
00836     float calc_temp = 0;
00837 
00838     /* calculate var1 data */
00839     var1  = ((((float)temp_adc / 16384.0f) - ((float)dev->calib .par_t1  / 1024.0f))
00840              * ((float)dev->calib .par_t2 ));
00841 
00842     /* calculate var2 data */
00843     var2  = (((((float)temp_adc / 131072.0f) - ((float)dev->calib .par_t1  / 8192.0f)) *
00844               (((float)temp_adc / 131072.0f) - ((float)dev->calib .par_t1  / 8192.0f))) *
00845              ((float)dev->calib .par_t3  * 16.0f));
00846 
00847     /* t_fine value*/
00848     dev->calib .t_fine  = (var1 + var2);
00849 
00850     /* compensated temperature data*/
00851     calc_temp  = ((dev->calib .t_fine ) / 5120.0f);
00852 
00853     return calc_temp;
00854 }
00855 
00856 /*!
00857  * @brief This internal API is used to calculate the
00858  * pressure value in float format
00859  */
00860 float BME680::calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev)
00861 {
00862     float var1 = 0;
00863     float var2 = 0;
00864     float var3 = 0;
00865     float calc_pres = 0;
00866 
00867     var1 = (((float)dev->calib .t_fine  / 2.0f) - 64000.0f);
00868     var2 = var1 * var1 * (((float)dev->calib .par_p6 ) / (131072.0f));
00869     var2 = var2 + (var1 * ((float)dev->calib .par_p5 ) * 2.0f);
00870     var2 = (var2 / 4.0f) + (((float)dev->calib .par_p4 ) * 65536.0f);
00871     var1 = (((((float)dev->calib .par_p3  * var1 * var1) / 16384.0f)
00872              + ((float)dev->calib .par_p2  * var1)) / 524288.0f);
00873     var1 = ((1.0f + (var1 / 32768.0f)) * ((float)dev->calib .par_p1 ));
00874     calc_pres = (1048576.0f - ((float)pres_adc));
00875 
00876     /* Avoid exception caused by division by zero */
00877     if ((int)var1 != 0) {
00878         calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1);
00879         var1 = (((float)dev->calib .par_p9 ) * calc_pres * calc_pres) / 2147483648.0f;
00880         var2 = calc_pres * (((float)dev->calib .par_p8 ) / 32768.0f);
00881         var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f)
00882                 * (dev->calib .par_p10  / 131072.0f));
00883         calc_pres = (calc_pres + (var1 + var2 + var3 + ((float)dev->calib .par_p7  * 128.0f)) / 16.0f);
00884     } else {
00885         calc_pres = 0;
00886     }
00887 
00888     return calc_pres;
00889 }
00890 
00891 /*!
00892  * @brief This internal API is used to calculate the
00893  * humidity value in float format
00894  */
00895 float BME680::calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev)
00896 {
00897     float calc_hum = 0;
00898     float var1 = 0;
00899     float var2 = 0;
00900     float var3 = 0;
00901     float var4 = 0;
00902     float temp_comp;
00903 
00904     /* compensated temperature data*/
00905     temp_comp  = ((dev->calib .t_fine ) / 5120.0f);
00906 
00907     var1 = (float)((float)hum_adc) - (((float)dev->calib .par_h1  * 16.0f) + (((float)dev->calib .par_h3  / 2.0f)
00908                                       * temp_comp));
00909 
00910     var2 = var1 * ((float)(((float) dev->calib.par_h2 / 262144.0f) * (1.0f + (((float)dev->calib.par_h4 / 16384.0f)
00911                            * temp_comp) + (((float)dev->calib.par_h5 / 1048576.0f) * temp_comp * temp_comp))));
00912 
00913     var3 = (float) dev->calib.par_h6 / 16384.0f;
00914 
00915     var4 = (float) dev->calib.par_h7 / 2097152.0f;
00916 
00917     calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);
00918 
00919     if (calc_hum > 100.0f)
00920         calc_hum = 100.0f;
00921     else if (calc_hum < 0.0f)
00922         calc_hum = 0.0f;
00923 
00924     return calc_hum;
00925 }
00926 
00927 /*!
00928  * @brief This internal API is used to calculate the
00929  * gas resistance value in float format
00930  */
00931 float BME680::calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev)
00932 {
00933     float calc_gas_res;
00934     float var1 = 0;
00935     float var2 = 0;
00936     float var3 = 0;
00937 
00938     const float lookup_k1_range[16] = {
00939         0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -0.8,
00940         0.0, 0.0, -0.2, -0.5, 0.0, -1.0, 0.0, 0.0
00941     };
00942     const float lookup_k2_range[16] = {
00943         0.0, 0.0, 0.0, 0.0, 0.1, 0.7, 0.0, -0.8,
00944         -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
00945     };
00946 
00947     var1 = (1340.0f + (5.0f * dev->calib.range_sw_err));
00948     var2 = (var1) * (1.0f + lookup_k1_range[gas_range]/100.0f);
00949     var3 = 1.0f + (lookup_k2_range[gas_range]/100.0f);
00950 
00951     calc_gas_res = 1.0f / (float)(var3 * (0.000000125f) * (float)(1 << gas_range) * (((((float)gas_res_adc)
00952                                   - 512.0f)/var2) + 1.0f));
00953 
00954     return calc_gas_res;
00955 }
00956 
00957 /*!
00958  * @brief This internal API is used to calculate the
00959  * heater resistance value in float format
00960  */
00961 float BME680::calc_heater_res(uint16_t temp, const struct bme680_dev *dev)
00962 {
00963     float var1 = 0;
00964     float var2 = 0;
00965     float var3 = 0;
00966     float var4 = 0;
00967     float var5 = 0;
00968     float res_heat = 0;
00969 
00970     if (temp > 400) /* Cap temperature */
00971         temp = 400;
00972 
00973     var1 = (((float)dev->calib .par_gh1  / (16.0f)) + 49.0f);
00974     var2 = ((((float)dev->calib .par_gh2  / (32768.0f)) * (0.0005f)) + 0.00235f);
00975     var3 = ((float)dev->calib .par_gh3  / (1024.0f));
00976     var4 = (var1 * (1.0f + (var2 * (float)temp)));
00977     var5 = (var4 + (var3 * (float)dev->amb_temp ));
00978     res_heat = (uint8_t)(3.4f * ((var5 * (4 / (4 + (float)dev->calib .res_heat_range )) *
00979                                   (1/(1 + ((float) dev->calib .res_heat_val  * 0.002f)))) - 25));
00980 
00981     return res_heat;
00982 }
00983 
00984 #endif
00985 
00986 /*!
00987  * @brief This internal API is used to calculate the Heat duration value.
00988  */
00989 uint8_t BME680::calc_heater_dur(uint16_t dur)
00990 {
00991     uint8_t factor = 0;
00992     uint8_t durval;
00993 
00994     if (dur >= 0xfc0) {
00995         durval = 0xff; /* Max duration*/
00996     } else {
00997         while (dur > 0x3F) {
00998             dur = dur / 4;
00999             factor += 1;
01000         }
01001         durval = (uint8_t) (dur + (factor * 64));
01002     }
01003 
01004     return durval;
01005 }
01006 
01007 /*!
01008  * @brief This internal API is used to calculate the field data of sensor.
01009  */
01010 int8_t BME680::read_field_data(struct bme680_field_data *data, struct bme680_dev *dev)
01011 {
01012     int8_t rslt;
01013     uint8_t buff[BME680_FIELD_LENGTH] = { 0 };
01014     uint8_t gas_range;
01015     uint32_t adc_temp;
01016     uint32_t adc_pres;
01017     uint16_t adc_hum;
01018     uint16_t adc_gas_res;
01019     uint8_t tries = 10;
01020 
01021     /* Check for null pointer in the device structure*/
01022     rslt = null_ptr_check(dev);
01023     do {
01024         if (rslt == BME680_OK) {
01025             rslt = bme680_get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH,
01026                                    dev);
01027 
01028             data->status  = buff[0] & BME680_NEW_DATA_MSK;
01029             data->gas_index  = buff[0] & BME680_GAS_INDEX_MSK;
01030             data->meas_index  = buff[1];
01031 
01032             /* read the raw data from the sensor */
01033             adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16)
01034                                    | ((uint32_t) buff[4] / 16));
01035             adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16)
01036                                    | ((uint32_t) buff[7] / 16));
01037             adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]);
01038             adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64));
01039             gas_range = buff[14] & BME680_GAS_RANGE_MSK;
01040 
01041             data->status  |= buff[14] & BME680_GASM_VALID_MSK;
01042             data->status  |= buff[14] & BME680_HEAT_STAB_MSK;
01043 
01044             if (data->status  & BME680_NEW_DATA_MSK) {
01045                 data->temperature  = calc_temperature(adc_temp, dev);
01046                 data->pressure  = calc_pressure(adc_pres, dev);
01047                 data->humidity  = calc_humidity(adc_hum, dev);
01048                 data->gas_resistance  = calc_gas_resistance(adc_gas_res, gas_range, dev);
01049                 break;
01050             }
01051             /* Delay to poll the data */
01052             dev->delay_ms (BME680_POLL_PERIOD_MS);
01053         }
01054         tries--;
01055     } while (tries);
01056 
01057     if (!tries)
01058         rslt = BME680_W_NO_NEW_DATA;
01059 
01060     return rslt;
01061 }
01062 
01063 /*!
01064  * @brief This internal API is used to set the memory page based on register address.
01065  */
01066 int8_t BME680::set_mem_page(uint8_t reg_addr, struct bme680_dev *dev)
01067 {
01068     int8_t rslt;
01069     uint8_t reg;
01070     uint8_t mem_page;
01071 
01072     /* Check for null pointers in the device structure*/
01073     rslt = null_ptr_check(dev);
01074     if (rslt == BME680_OK) {
01075         if (reg_addr > 0x7f)
01076             mem_page = BME680_MEM_PAGE1;
01077         else
01078             mem_page = BME680_MEM_PAGE0;
01079 
01080         if (mem_page != dev->mem_page ) {
01081             dev->mem_page  = mem_page;
01082 
01083             dev->com_rslt  = dev->read (dev->dev_id , BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, &reg, 1);
01084             if (dev->com_rslt  != 0)
01085                 rslt = BME680_E_COM_FAIL;
01086 
01087             if (rslt == BME680_OK) {
01088                 reg = reg & (~BME680_MEM_PAGE_MSK);
01089                 reg = reg | (dev->mem_page  & BME680_MEM_PAGE_MSK);
01090 
01091                 dev->com_rslt  = dev->write (dev->dev_id , BME680_MEM_PAGE_ADDR & BME680_SPI_WR_MSK,
01092                                            &reg, 1);
01093                 if (dev->com_rslt  != 0)
01094                     rslt = BME680_E_COM_FAIL;
01095             }
01096         }
01097     }
01098 
01099     return rslt;
01100 }
01101 
01102 /*!
01103  * @brief This internal API is used to get the memory page based on register address.
01104  */
01105 int8_t BME680::get_mem_page(struct bme680_dev *dev)
01106 {
01107     int8_t rslt;
01108     uint8_t reg;
01109 
01110     /* Check for null pointer in the device structure*/
01111     rslt = null_ptr_check(dev);
01112     if (rslt == BME680_OK) {
01113         dev->com_rslt  = dev->read (dev->dev_id , BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, &reg, 1);
01114         if (dev->com_rslt  != 0)
01115             rslt = BME680_E_COM_FAIL;
01116         else
01117             dev->mem_page  = reg & BME680_MEM_PAGE_MSK;
01118     }
01119 
01120     return rslt;
01121 }
01122 
01123 /*!
01124  * @brief This internal API is used to validate the boundary
01125  * conditions.
01126  */
01127 int8_t BME680::boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev)
01128 {
01129     int8_t rslt = BME680_OK;
01130 
01131     if (value != NULL) {
01132         /* Check if value is below minimum value */
01133         if (*value < min) {
01134             /* Auto correct the invalid value to minimum value */
01135             *value = min;
01136             dev->info_msg  |= BME680_I_MIN_CORRECTION;
01137         }
01138         /* Check if value is above maximum value */
01139         if (*value > max) {
01140             /* Auto correct the invalid value to maximum value */
01141             *value = max;
01142             dev->info_msg  |= BME680_I_MAX_CORRECTION;
01143         }
01144     } else {
01145         rslt = BME680_E_NULL_PTR;
01146     }
01147 
01148     return rslt;
01149 }
01150 
01151 /*!
01152  * @brief This internal API is used to validate the device structure pointer for
01153  * null conditions.
01154  */
01155 int8_t BME680::null_ptr_check(const struct bme680_dev *dev)
01156 {
01157     int8_t rslt;
01158 
01159     if ((dev == NULL) || (dev->read  == NULL) || (dev->write  == NULL) || (dev->delay_ms  == NULL)) {
01160         /* Device structure pointer is not valid */
01161         rslt = BME680_E_NULL_PTR;
01162     } else {
01163         /* Device structure is fine */
01164         rslt = BME680_OK;
01165     }
01166 
01167     return rslt;
01168 }