+/* ------------------------ BMP085 access ------------------------ */
+
+/**
+ * Detect presence of a BMP085 pressure sensor by checking its ID register
+ *
+ * As a sideeffect will leave set I2C slave address.
+ *
+ * @return 1 if BMP085, 0 otherwise
+ */
+static int BMP085_detect(void)
+{
+ __s32 res;
+ char errbuf[1024];
+
+ if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0)
+ {
+ ERROR("barometer: BMP085_detect - problem setting i2c slave address to 0x%02X: %s",
+ BMP085_I2C_ADDRESS,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 0 ;
+ }
+
+ res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
+ if(res == BMP085_CHIP_ID)
+ {
+ DEBUG ("barometer: BMP085_detect - positive detection");
+
+ /* get version */
+ res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION );
+ if (res < 0)
+ {
+ ERROR("barometer: BMP085_detect - problem checking chip version: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 0 ;
+ }
+ DEBUG ("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
+ res & 0x0f,
+ (res & 0xf0) >> 4);
+ return 1;
+ }
+
+ DEBUG ("barometer: BMP085_detect - negative detection");
+ return 0;
+}
+
+
+/**
+ * Adjusts oversampling settings to values supported by BMP085
+ *
+ * BMP085 supports only 1,2,4 or 8 samples.
+ */
+static void BMP085_adjust_oversampling(void)
+{
+ int new_val = 0;
+
+ if( config_oversample > 6 ) /* 8 */
+ {
+ new_val = 8;
+ bmp085_oversampling = 3;
+ bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
+ bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
+ }
+ else if( config_oversample > 3 ) /* 4 */
+ {
+ new_val = 4;
+ bmp085_oversampling = 2;
+ bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
+ bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
+ }
+ else if( config_oversample > 1 ) /* 2 */
+ {
+ new_val = 2;
+ bmp085_oversampling = 1;
+ bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
+ bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
+ }
+ else /* 1 */
+ {
+ new_val = 1;
+ bmp085_oversampling = 0;
+ bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
+ bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
+ }
+
+ DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from %d to %d",
+ config_oversample,
+ new_val);
+ config_oversample = new_val;
+}
+
+
+/**
+ * Read the BMP085 sensor conversion coefficients.
+ *
+ * These are (device specific) constants so we can read them just once.
+ *
+ * @return Zero when successful
+ */
+static int BMP085_read_coeffs(void)
+{
+ __s32 res;
+ __u8 coeffs[BMP085_NUM_COEFFS];
+ char errbuf[1024];
+
+ res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
+ BMP085_ADDR_COEFFS,
+ BMP085_NUM_COEFFS,
+ coeffs);
+ if (res < 0)
+ {
+ ERROR ("barometer: BMP085_read_coeffs - problem reading data: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return -1;
+ }
+
+ bmp085_AC1 = ((int16_t) coeffs[0] <<8) | (int16_t) coeffs[1];
+ bmp085_AC2 = ((int16_t) coeffs[2] <<8) | (int16_t) coeffs[3];
+ bmp085_AC3 = ((int16_t) coeffs[4] <<8) | (int16_t) coeffs[5];
+ bmp085_AC4 = ((uint16_t) coeffs[6] <<8) | (uint16_t) coeffs[7];
+ bmp085_AC5 = ((uint16_t) coeffs[8] <<8) | (uint16_t) coeffs[9];
+ bmp085_AC6 = ((uint16_t) coeffs[10] <<8) | (uint16_t) coeffs[11];
+ bmp085_B1 = ((int16_t) coeffs[12] <<8) | (int16_t) coeffs[13];
+ bmp085_B2 = ((int16_t) coeffs[14] <<8) | (int16_t) coeffs[15];
+ bmp085_MB = ((int16_t) coeffs[16] <<8) | (int16_t) coeffs[17];
+ bmp085_MC = ((int16_t) coeffs[18] <<8) | (int16_t) coeffs[19];
+ bmp085_MD = ((int16_t) coeffs[20] <<8) | (int16_t) coeffs[21];
+
+ DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"\
+ " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
+ bmp085_AC1,
+ bmp085_AC2,
+ bmp085_AC3,
+ bmp085_AC4,
+ bmp085_AC5,
+ bmp085_AC6,
+ bmp085_B1,
+ bmp085_B2,
+ bmp085_MB,
+ bmp085_MC,
+ bmp085_MD);
+
+ return 0;
+}
+
+
+/**
+ * Convert raw BMP085 adc values to real data using the sensor coefficients.
+ *
+ * @param adc_pressure adc pressure value to be converted
+ * @param adc_temp adc temperature value to be converted
+ * @param pressure computed real pressure
+ * @param temperature computed real temperature
+ */
+static void BMP085_convert_adc_to_real(long adc_pressure,
+ long adc_temperature,
+ double * pressure,
+ double * temperature)
+
+{
+ long X1, X2, X3;
+ long B3, B5, B6;
+ unsigned long B4, B7;
+
+ long T;
+ long P;
+
+
+ /* calculate real temperature */
+ X1 = ( (adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
+ X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
+
+ /* B5, T */
+ B5 = X1 + X2;
+ T = (B5 + 8) >> 4;
+ *temperature = (double)T * 0.1;
+
+ /* calculate real pressure */
+ /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept */
+
+ /* B6, B3 */
+ B6 = B5 - 4000;
+ X1 = ((bmp085_B2 * ((B6 * B6)>>12)) >> 11 );
+ X2 = (((long)bmp085_AC2 * B6) >> 11);
+ X3 = X1 + X2;
+ B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
+
+ /* B4 */
+ X1 = (((long)bmp085_AC3*B6) >> 13);
+ X2 = (bmp085_B1*((B6*B6) >> 12) ) >> 16;
+ X3 = ((X1 + X2) + 2 ) >> 2;
+ B4 = ((long)bmp085_AC4* (unsigned long)(X3 + 32768)) >> 15;
+
+ /* B7, P */
+ B7 = (unsigned long)(adc_pressure - B3)*(50000>>bmp085_oversampling);
+ if( B7 < 0x80000000 )
+ {
+ P = (B7 << 1) / B4;
+ }
+ else
+ {
+ P = (B7/B4) << 1;
+ }
+ X1 = (P >> 8) * (P >> 8);
+ X1 = (X1 * 3038) >> 16;
+ X2 = ((-7357) * P) >> 16;
+ P = P + ( ( X1 + X2 + 3791 ) >> 4);
+
+ *pressure = P / 100.0; // in [hPa]
+ DEBUG ("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C",
+ *pressure,
+ *temperature);
+}
+
+
+/**
+ * Read compensated sensor measurements
+ *
+ * @param pressure averaged measured pressure
+ * @param temperature averaged measured temperature
+ *
+ * @return Zero when successful
+ */
+static int BMP085_read(double * pressure, double * temperature)
+{
+ __s32 res;
+ __u8 measBuff[3];
+
+ long adc_pressure;
+ long adc_temperature;
+
+ char errbuf[1024];
+
+ /* start conversion of temperature */
+ res = i2c_smbus_write_byte_data( i2c_bus_fd,
+ BMP085_ADDR_CTRL_REG,
+ BMP085_CMD_CONVERT_TEMP );
+ if (res < 0)
+ {
+ ERROR ("barometer: BMP085_read - problem requesting temperature conversion: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 1;
+ }
+
+ usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
+
+ res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
+ BMP085_ADDR_CONV,
+ 2,
+ measBuff);
+ if (res < 0)
+ {
+ ERROR ("barometer: BMP085_read - problem reading temperature data: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 1;
+ }
+
+ adc_temperature = ( (unsigned short)measBuff[0] << 8 ) + measBuff[1];
+
+
+ /* get presure */
+ res = i2c_smbus_write_byte_data( i2c_bus_fd,
+ BMP085_ADDR_CTRL_REG,
+ bmp085_cmdCnvPress );
+ if (res < 0)
+ {
+ ERROR ("barometer: BMP085_read - problem requesting pressure conversion: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 1;
+ }
+
+ usleep(bmp085_timeCnvPress); /* wait for the conversion */
+
+ res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
+ BMP085_ADDR_CONV,
+ 3,
+ measBuff );
+ if (res < 0)
+ {
+ ERROR ("barometer: BMP085_read - problem reading pressure data: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return 1;
+ }
+
+ adc_pressure = (long)((((ulong)measBuff[0]<<16) | ((ulong)measBuff[1]<<8) | (ulong)measBuff[2] ) >> (8 - bmp085_oversampling));
+
+
+ DEBUG ("barometer: BMP085_read - raw pressure ADC value = %ld, " \
+ "raw temperature ADC value = %ld",
+ adc_pressure,
+ adc_temperature);
+
+ BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
+
+ return 0;
+}
+
+
+
+/* ------------------------ Sensor detection ------------------------ */
+/**
+ * Detect presence of a supported sensor.
+ *
+ * As a sideeffect will leave set I2C slave address.
+ * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
+ * first sensor beeing found.
+ *
+ * @return detected sensor type
+ */
+enum Sensor_type Detect_sensor_type(void)
+{
+ if(BMP085_detect())
+ return Sensor_BMP085;
+
+ else if(MPL3115_detect())
+ return Sensor_MPL3115;
+
+ else if(MPL115_detect())
+ return Sensor_MPL115;
+
+ return Sensor_none;
+}