+ 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;