/* * Author: Aditya Nagal * Copyright (c) 2014 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "bme280.h" #include "bme280driver.h" /************** I2C buffer length ******/ #define I2C_BUFFER_LEN 26 using namespace upm; /*----------------------------------------------------------------------------* * struct bme280_t parameters can be accessed by using bme280 * bme280_t having the following parameters * Bus write function pointer: BME280_WR_FUNC_PTR Bus read function pointer: BME280_RD_FUNC_PTR * Delay function pointer: delay_msec * I2C address: dev_addr * Chip id of the sensor: chip_id *---------------------------------------------------------------------------*/ struct bme280_t bme280; static struct bme280_t *p_bme280; /**< pointer to BME280 */ mraa::I2c* BME280::m_i2c = NULL; int BME280::m_bus = 0; BME280::BME280 (int bus, int devAddr) { m_bus = bus; if( m_i2c == NULL) { m_i2c = new mraa::I2c(m_bus); m_i2c->address(BME280_I2C_ADDRESS1); //Based on the requirement, configure I2C interface. I2C_routine(); /*--------------------------------------------------------------------------* * This function used to assign the value/reference of * the following parameters * I2C address * Bus Write * Bus read * Chip id *-------------------------------------------------------------------------*/ bme280_init(&bme280); } } BME280::~BME280() { delete m_i2c; } /* This function is an example for reading sensor temperature * \param: None * \return: compensated temperature */ int32_t BME280::getTemperatureInternal(void) { /* The variable used to read uncompensated temperature*/ int32_t v_data_uncomp_tem_int32 = getTemperatureRawInternal(); /*------------------------------------------------------------------* ************ START READ TRUE PRESSURE, TEMPERATURE AND HUMIDITY DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the true temperature*/ /* Input value as uncompensated temperature and output format*/ int32_t v_actual_temp_int32 = bme280_compensate_temperature_int32(v_data_uncomp_tem_int32); /*--------------------------------------------------------------------* ************ END READ TRUE TEMPERATURE ******** *-------------------------------------------------------------------------*/ return v_actual_temp_int32; } /* This function is an example for reading sensor pressure * \param: None * \return: compensated pressure */ int32_t BME280::getPressureInternal(void) { /* The variable used to read uncompensated pressure*/ int32_t v_data_uncomp_pres_int32 = getPressureRawInternal(); /*------------------------------------------------------------------* ************ START READ TRUE PRESSURE DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the true pressure*/ /* Input value as uncompensated pressure */ uint32_t v_actual_press_uint32 = bme280_compensate_pressure_int32(v_data_uncomp_pres_int32); /*--------------------------------------------------------------------* ************ END READ TRUE PRESSURE ******** *-------------------------------------------------------------------------*/ return v_actual_press_uint32; } /* This function is an example for reading sensor humidity * \param: None * \return: compensated humidity */ int32_t BME280::getHumidityInternal(void) { /* The variable used to read uncompensated pressure*/ int32_t v_data_uncomp_hum_int32 = getHumidityRawInternal(); /*------------------------------------------------------------------* ************ START READ TRUE HUMIDITY DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the true humidity*/ /* Input value as uncompensated humidity and output format*/ uint32_t v_actual_humity_uint32 = bme280_compensate_humidity_int32(v_data_uncomp_hum_int32); /*--------------------------------------------------------------------* ************ END READ TRUE HUMIDITY ******** *-------------------------------------------------------------------------*/ return v_actual_humity_uint32; } /* This function is an example for reading sensor temperature * \param: None * \return: uncompensated temperature */ int32_t BME280::getTemperatureRawInternal(void) { /* The variable used to read uncompensated temperature*/ int32_t v_data_uncomp_tem_int32 = BME280_INIT_VALUE; /* For initialization it is required to set the mode of * the sensor as "NORMAL" * data acquisition/read/write is possible in this mode * by using the below API able to set the power mode as NORMAL*/ /* Set the power mode as NORMAL*/ bme280_set_power_mode(BME280_NORMAL_MODE); /* For reading the temperature data it is required to * set the OSS setting of temperature * In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH" * register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write * the "BME280_CTRLMEAS_REG" register in the function*/ /* set the temperature oversampling*/ bme280_set_oversamp_temperature(BME280_OVERSAMP_4X); /************************* END INITIALIZATION *************************/ /*------------------------------------------------------------------* ************ START READ UNCOMPENSATED TEMPERATURE DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the uncompensated temperature*/ bme280_read_uncomp_temperature(&v_data_uncomp_tem_int32); /*--------------------------------------------------------------------* ************ END READ UNCOMPENSATED TEMPERATURE ******** *-------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------* ************************* START DE-INITIALIZATION *********************** *-------------------------------------------------------------------------*/ /* For de-initialization it is required to set the mode of * the sensor as "SLEEP" * the device reaches the lowest power consumption only * In SLEEP mode no measurements are performed * All registers are accessible * by using the below API able to set the power mode as SLEEP*/ /* Set the power mode as SLEEP*/ bme280_set_power_mode(BME280_SLEEP_MODE); /*---------------------------------------------------------------------* ************************* END DE-INITIALIZATION ********************** *---------------------------------------------------------------------*/ return v_data_uncomp_tem_int32; } /* This function is an example for reading sensor pressure * \param: None * \return: uncompensated pressure */ int32_t BME280::getPressureRawInternal(void) { /* The variable used to read uncompensated pressure*/ int32_t v_data_uncomp_pres_int32 = BME280_INIT_VALUE; /* For initialization it is required to set the mode of * the sensor as "NORMAL" * data acquisition/read/write is possible in this mode * by using the below API able to set the power mode as NORMAL*/ /* Set the power mode as NORMAL*/ bme280_set_power_mode(BME280_NORMAL_MODE); /* For reading the pressure data it is required to * set the OSS setting of humidity, pressure and temperature * The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity * data acquisition options of the device. * changes to this registers only become effective after a write operation to * "BME280_CTRLMEAS_REG" register. * In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH" * register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write * the "BME280_CTRLMEAS_REG" register in the function*/ /* set the pressure oversampling*/ bme280_set_oversamp_pressure(BME280_OVERSAMP_2X); /************************* END INITIALIZATION *************************/ /*------------------------------------------------------------------* ************ START READ UNCOMPENSATED PRESSURE DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the uncompensated pressure*/ bme280_read_uncomp_pressure(&v_data_uncomp_pres_int32); /*--------------------------------------------------------------------* ************ END READ UNCOMPENSATED PRESSURE ******** *-------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------* ************************* START DE-INITIALIZATION *********************** *-------------------------------------------------------------------------*/ /* For de-initialization it is required to set the mode of * the sensor as "SLEEP" * the device reaches the lowest power consumption only * In SLEEP mode no measurements are performed * All registers are accessible * by using the below API able to set the power mode as SLEEP*/ /* Set the power mode as SLEEP*/ bme280_set_power_mode(BME280_SLEEP_MODE); /*---------------------------------------------------------------------* ************************* END DE-INITIALIZATION ********************** *---------------------------------------------------------------------*/ return v_data_uncomp_pres_int32; } /* This function is an example for reading sensor humidity * \param: None * \return: uncompensated humidity */ int32_t BME280::getHumidityRawInternal(void) { /* The variable used to read uncompensated pressure*/ int32_t v_data_uncomp_hum_int32 = BME280_INIT_VALUE; /* For initialization it is required to set the mode of * the sensor as "NORMAL" * data acquisition/read/write is possible in this mode * by using the below API able to set the power mode as NORMAL*/ /* Set the power mode as NORMAL*/ bme280_set_power_mode(BME280_NORMAL_MODE); /* For reading humidity data it is required to * set the OSS setting of humidity * The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity * data acquisition options of the device. * changes to this registers only become effective after a write operation to * "BME280_CTRLMEAS_REG" register. * In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH" * register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write * the "BME280_CTRLMEAS_REG" register in the function*/ bme280_set_oversamp_humidity(BME280_OVERSAMP_1X); /************************* END INITIALIZATION *************************/ /*------------------------------------------------------------------* ************ START READ HUMIDITY DATA ******** *---------------------------------------------------------------------*/ /* API is used to read the uncompensated humidity*/ bme280_read_uncomp_humidity(&v_data_uncomp_hum_int32); /*--------------------------------------------------------------------* ************ END READ UNCOMPENSATED PRESSURE AND TEMPERATURE******** *-------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------* ************************* START DE-INITIALIZATION *********************** *-------------------------------------------------------------------------*/ /* For de-initialization it is required to set the mode of * the sensor as "SLEEP" * the device reaches the lowest power consumption only * In SLEEP mode no measurements are performed * All registers are accessible * by using the below API able to set the power mode as SLEEP*/ /* Set the power mode as SLEEP*/ bme280_set_power_mode(BME280_SLEEP_MODE); /*---------------------------------------------------------------------* ************************* END DE-INITIALIZATION ********************** *---------------------------------------------------------------------*/ return v_data_uncomp_hum_int32; } /*--------------------------------------------------------------------------* * The following function is used to map the I2C bus read, write, delay and * device address with global structure bme280 *-------------------------------------------------------------------------*/ int8_t BME280::I2C_routine() { /*--------------------------------------------------------------------------* * By using bme280 the following structure parameter can be accessed * Bus write function pointer: BME280_WR_FUNC_PTR * Bus read function pointer: BME280_RD_FUNC_PTR * Delay function pointer: delay_msec * I2C address: dev_addr *--------------------------------------------------------------------------*/ // bme280.bus_write = &BME280::BME280_I2C_bus_write; bme280.bus_write = BME280_I2C_bus_write; //bme280.bus_write = BME280_I2C_bus_write_dummy; bme280.bus_read = BME280_I2C_bus_read; bme280.dev_addr = BME280_I2C_ADDRESS1; bme280.delay_msec = BME280_delay_msek; return BME280_INIT_VALUE; } /*-------------------------------------------------------------------* * The device address defined in the bme280.h file *-----------------------------------------------------------------------*/ int32_t BME280::i2c_write_string(uint8_t dev_addr,uint8_t* ptr, uint8_t cnt) { mraa::Result ret; m_i2c->address(dev_addr); if((ret = m_i2c->write((const uint8_t*) (ptr), cnt)) != 0) { UPM_THROW("I2C write error"); } } /* \Brief: The function is used as I2C bus write * \Return : Status of the I2C write * \param dev_addr : The device address of the sensor * \param reg_addr : Address of the first register, will data is going to be written * \param reg_data : It is a value hold in the array, * will be used for write the value into the register * \param cnt : The no of byte of data to be write */ int8_t BME280::BME280_I2C_bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t cnt) { int32_t iError = BME280_INIT_VALUE; static uint8_t array[I2C_BUFFER_LEN]; for (int i=0; iaddress(dev_addr); if( m_i2c->readBytesReg(reg_addr, ptr, cnt) != cnt) { UPM_THROW("bme280 register read failed"); } return 0; } /* \Brief: The function is used as I2C bus read * \Return : Status of the I2C read * \param dev_addr : The device address of the sensor * \param reg_addr : Address of the first register, will data is going to be read * \param reg_data : This data read from the sensor, which is hold in an array * \param cnt : The no of data byte of to be read */ int8_t BME280::BME280_I2C_bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t cnt) { int32_t iError = BME280_INIT_VALUE; uint8_t array[I2C_BUFFER_LEN] = {BME280_INIT_VALUE}; uint8_t stringpos = BME280_INIT_VALUE; array[BME280_INIT_VALUE] = reg_addr; i2c_write_read_string(dev_addr,reg_addr,array,cnt); for (stringpos = BME280_INIT_VALUE; stringpos < cnt; stringpos++) { *(reg_data + stringpos) = array[stringpos]; } return (int8_t)iError; } /* Brief : The delay routine * \param : delay in ms */ void BME280::BME280_delay_msek(uint16_t mseconds) { struct timespec sleepTime; sleepTime.tv_sec = mseconds / 1000; // Number of seconds sleepTime.tv_nsec = ( mseconds % 1000 ) * 1000000; // Convert fractional seconds to nanoseconds // Iterate nanosleep in a loop until the total sleep time is the original // value of the seconds parameter while ( ( nanosleep( &sleepTime, &sleepTime ) != 0 ) && ( errno == EINTR ) ); } /** * Get temperature measurement. */ uint16_t BME280::getTemperatureRaw (){ return BME280::getTemperatureRawInternal(); } /** * Get temperature measurement. */ int BME280::getTemperatureCelcius (){ return (BME280::getTemperatureInternal() + 50) /100; } /** * Get relative humidity measurement. */ uint16_t BME280::getHumidityRaw (){ return BME280::getHumidityRawInternal(); } /** * Get relative humidity measurement. */ int BME280::getHumidityRelative (){ return (BME280::getHumidityInternal() + 500) / 1000; } /** * Return pressure */ uint32_t BME280::getPressureRaw(){ return BME280::getPressureRawInternal(); } /** * Return calculated pressure (Pa) */ int BME280::getPressurePa(){ return BME280::getPressureInternal(); }