Added support for barometer sensor BMP085 from Bosch
authortomas <tomas@ubu32.(none)>
Wed, 6 Aug 2014 10:04:15 +0000 (12:04 +0200)
committertomas <tomas@ubu32.(none)>
Wed, 6 Aug 2014 10:04:15 +0000 (12:04 +0200)
README
src/barometer.c
src/collectd.conf.pod

diff --git a/README b/README
index 0e2a677..654ee74 100644 (file)
--- a/README
+++ b/README
@@ -33,8 +33,8 @@ Features
       Statistics about Ascent, a free server for the game `World of Warcraft'.
 
     - barometer
-      Using digital barometer sensor MPL115A2 or MPL3115 from Freescale provides
-      absolute barometric pressure, air pressure reduced to sea level and temperature.
+      Reads absolute barometric pressure, air pressure reduced to sea level and temperature.
+      Supported sensors are MPL115A2 and MPL3115 from Freescale and BMP085 from Bosch.
 
     - battery
       Batterycharge, -current and voltage of ACPI and PMU based laptop
index 95b05f4..0fa9a33 100644 (file)
 #define MPL3115_NUM_CONV_VALS       5
 
 
+/* ------------ BMP085 defines ------------ */
+/* I2C address of the BMP085 sensor */
+#define BMP085_I2C_ADDRESS          0x77
+
+/* register addresses */            
+#define BMP085_ADDR_ID_REG          0xD0
+#define BMP085_ADDR_VERSION         0xD1
+
+#define BMP085_ADDR_CONV            0xF6
+
+#define BMP085_ADDR_CTRL_REG        0xF4
+#define BMP085_ADDR_COEFFS          0xAA
+
+/* register sizes */                
+#define BMP085_NUM_COEFFS           22
+
+/* commands, values */
+#define BMP085_CHIP_ID              0x55
+
+#define BMP085_CMD_CONVERT_TEMP     0x2E
+
+#define BMP085_CMD_CONVERT_PRESS_0  0x34
+#define BMP085_CMD_CONVERT_PRESS_1  0x74
+#define BMP085_CMD_CONVERT_PRESS_2  0xB4
+#define BMP085_CMD_CONVERT_PRESS_3  0xF4
+
+/* in us */
+#define BMP085_TIME_CNV_TEMP        4500
+
+#define BMP085_TIME_CNV_PRESS_0     4500
+#define BMP085_TIME_CNV_PRESS_1     7500
+#define BMP085_TIME_CNV_PRESS_2    13500
+#define BMP085_TIME_CNV_PRESS_3    25500
+
+
 /* ------------ Normalization ------------ */
 /* Mean sea level pressure normalization methods */
 #define MSLP_NONE          0
 /** Temperature reference history depth for averaging. See #get_reference_temperature */
 #define REF_TEMP_AVG_NUM   5
 
+
 /* ------------------------------------------ */
+
+/** Supported sensor types */
+enum Sensor_type {
+    Sensor_none = 0,
+    Sensor_MPL115,
+    Sensor_MPL3115,
+    Sensor_BMP085
+};
+
 static const char *config_keys[] =
 {
     "Device",
@@ -146,9 +191,15 @@ static int    config_normalize    = 0;     /**< normalization method */
 static _Bool  configured          = 0;     /**< the whole plugin config status */
                                   
 static int    i2c_bus_fd          = -1;    /**< I2C bus device FD */
-                                  
-static _Bool  is_MPL3115          = 0;    /**< is this MPL3115? */
-static __s32  oversample_MPL3115  = 0;    /**< MPL3115 CTRL1 oversample setting */
+
+static enum Sensor_type sensor_type = Sensor_none; /**< detected/used sensor type */
+
+static __s32  mpl3115_oversample  = 0;    /**< MPL3115 CTRL1 oversample setting */
+
+// BMP085 configuration
+static unsigned      bmp085_oversampling; /**< BMP085 oversampling (0-3) */
+static unsigned long bmp085_timeCnvPress; /**< BMP085 conversion time for pressure in us */
+static __u8          bmp085_cmdCnvPress;  /**< BMP085 pressure conversion command */
 
 
 /* MPL115 conversion coefficients */
@@ -159,6 +210,21 @@ static double mpl115_coeffC12;
 static double mpl115_coeffC11;
 static double mpl115_coeffC22;
 
+/* BMP085 conversion coefficients */
+static short bmp085_AC1;
+static short bmp085_AC2;
+static short bmp085_AC3;
+static unsigned short bmp085_AC4;
+static unsigned short bmp085_AC5;
+static unsigned short bmp085_AC6;
+static short bmp085_B1;
+static short bmp085_B2;
+static short bmp085_MB;
+static short bmp085_MC;
+static short bmp085_MD;
+
+
+
 /* ------------------------ averaging ring buffer ------------------------ */
 /*  Used only for MPL115. MPL3115 supports real oversampling in the device so */
 /*  no need for any postprocessing. */
@@ -484,9 +550,45 @@ static int get_reference_temperature(double * result)
     return 0;
 }
 
+
 /* ------------------------ MPL115 access ------------------------ */
 
 /** 
+ * Detect presence of a MPL115 pressure sensor.
+ *
+ * Unfortunately there seems to be no ID register so we just try to read first
+ * conversion coefficient from device at MPL115 address and hope it is really
+ * MPL115. We should use this check as the last resort (which would be the typical
+ * case anyway since MPL115 is the least accurate sensor).
+ * As a sideeffect will leave set I2C slave address.
+ * 
+ * @return 1 if MPL115, 0 otherwise
+ */
+static int MPL115_detect(void)
+{
+    __s32 res;
+    char errbuf[1024];
+
+    if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
+    {
+        ERROR("barometer: MPL115_detect problem setting i2c slave address to 0x%02X: %s",
+              MPL115_I2C_ADDRESS,
+              sstrerror (errno, errbuf, sizeof (errbuf)));
+        return 0 ;
+    }
+
+    res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
+    if(res >= 0)
+    {
+        DEBUG ("barometer: MPL115_detect - positive detection");
+        return 1;
+    }
+
+    DEBUG ("barometer: MPL115_detect - negative detection");
+    return 0;
+}
+
+/** 
  * Read the MPL115 sensor conversion coefficients.
  *
  * These are (device specific) constants so we can read them just once.
@@ -510,7 +612,7 @@ static int MPL115_read_coeffs(void)
                                         mpl115_coeffs);
     if (res < 0)
     {
-        ERROR ("barometer: read_mpl115_coeffs - problem reading data: %s",
+        ERROR ("barometer: MPL115_read_coeffs - problem reading data: %s",
                sstrerror (errno, errbuf, sizeof (errbuf)));
         return -1;
     }
@@ -567,7 +669,7 @@ static int MPL115_read_coeffs(void)
     mpl115_coeffC22 /= 32.0; //16-11=5
     mpl115_coeffC22 /= 33554432.0;          /* 10+15=25 fract */
 
-    DEBUG("barometer: read_mpl115_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
+    DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
           mpl115_coeffA0, 
           mpl115_coeffB1, 
           mpl115_coeffB2, 
@@ -578,7 +680,7 @@ static int MPL115_read_coeffs(void)
 }
 
 
-/*
+/**
  * Convert raw adc values to real data using the sensor coefficients.
  *
  * @param adc_pressure adc pressure value to be converted
@@ -598,7 +700,7 @@ static void MPL115_convert_adc_to_real(double   adc_pressure,
     
     *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
     *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
-    DEBUG ("barometer: convert_adc_to_real - got %lf hPa, %lf C",
+    DEBUG ("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C",
            *pressure,
            *temperature);
 }
@@ -709,12 +811,23 @@ static int MPL115_read_averaged(double * pressure, double * temperature)
 
 /** 
  * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
+ *
+ * As a sideeffect will leave set I2C slave address.
  * 
  * @return 1 if MPL3115, 0 otherwise
  */
 static int MPL3115_detect(void)
 {
     __s32 res;
+    char errbuf[1024];
+
+    if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0)
+    {
+        ERROR("barometer: MPL3115_detect problem setting i2c slave address to 0x%02X: %s",
+              MPL3115_I2C_ADDRESS,
+              sstrerror (errno, errbuf, sizeof (errbuf)));
+        return 0 ;
+    }
 
     res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
     if(res == MPL3115_WHO_AM_I_RESP)
@@ -739,45 +852,45 @@ static void MPL3115_adjust_oversampling(void)
     if(config_oversample > 100)
     {
         new_val = 128;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_128;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
     }
     else if(config_oversample > 48)
     {
         new_val = 64;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_64;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
     }
     else if(config_oversample > 24)
     {
         new_val = 32;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_32;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
     }
     else if(config_oversample > 12)
     {
         new_val = 16;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_16;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
     }
     else if(config_oversample > 6)
     {
         new_val = 8;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_8;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
     }
     else if(config_oversample > 3)
     {
         new_val = 4;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_4;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
     }
     else if(config_oversample > 1)
     {
         new_val = 2;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_2;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
     }
     else
     {
         new_val = 1;
-        oversample_MPL3115 = MPL3115_CTRL_REG1_OST_1;
+        mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
     }
 
-    DEBUG("barometer: correcting oversampling for MPL3115 from %d to %d",
+    DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
           config_oversample, 
           new_val);
     config_oversample = new_val;
@@ -859,7 +972,7 @@ static int MPL3115_read(double * pressure, double * temperature)
     
     tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
     *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
-    DEBUG ("barometer: MPL3115_read, absolute pressure = %lf hPa", *pressure);
+    DEBUG ("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
     
     if(data[3] > 0x7F)
     {
@@ -873,7 +986,7 @@ static int MPL3115_read(double * pressure, double * temperature)
     }
     
     *temperature += (double)(data[4]) / 256.0;
-    DEBUG ("barometer: MPL3115_read, temperature = %lf C", *temperature);
+    DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
     
     return 0;
 }
@@ -938,7 +1051,7 @@ static int MPL3115_init_sensor(void)
     /* Set to barometer with an OSR */ 
     res = i2c_smbus_write_byte_data(i2c_bus_fd, 
                                     MPL3115_REG_CTRL_REG1, 
-                                    oversample_MPL3115);
+                                    mpl3115_oversample);
     if (res < 0)
     {
         ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
@@ -949,6 +1062,327 @@ static int MPL3115_init_sensor(void)
     return 0;
 }
 
+/* ------------------------ 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;
+}
 
 /* ------------------------ Common functionality ------------------------ */
 
@@ -1047,7 +1481,7 @@ static int collectd_barometer_config (const char *key, const char *value)
         if (oversampling_tmp < 1 || oversampling_tmp > 1024)
         {
             WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
-                     " Allowed values are 1 to 1024 (for MPL115) or 128 (for MPL3115).",
+                     " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for MPL3115) or 1 to 8 (for BMP085).",
                      oversampling_tmp);
             return 1;
         }
@@ -1103,7 +1537,7 @@ static int collectd_barometer_shutdown(void)
 {
     DEBUG ("barometer: collectd_barometer_shutdown");
 
-    if(!is_MPL3115)
+    if(sensor_type == Sensor_MPL115)
     {
         averaging_delete (&pressure_averaging);
         averaging_delete (&temperature_averaging);
@@ -1268,6 +1702,69 @@ static int MPL3115_collectd_barometer_read (void)
 
 
 /** 
+ * Plugin read callback for BMP085.
+ * 
+ *  Dispatching will create values:
+ *  - <hostname>/barometer-bmp085/pressure-normalized
+ *  - <hostname>/barometer-bmp085/pressure-absolute
+ *  - <hostname>/barometer-bmp085/temperature
+ *
+ * @return Zero when successful.
+ */
+static int BMP085_collectd_barometer_read (void)
+{
+    int result = 0;
+    
+    double pressure        = 0.0;
+    double temperature     = 0.0;
+    double norm_pressure   = 0.0;
+    
+    value_list_t vl = VALUE_LIST_INIT;
+    value_t      values[1];
+    
+    DEBUG("barometer: BMP085_collectd_barometer_read");
+    
+    if (!configured)
+    {
+        return -1;
+    }
+    
+    result = BMP085_read(&pressure, &temperature);
+    if(result)
+        return result;
+
+    norm_pressure = abs_to_mean_sea_level_pressure(pressure);
+
+    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+    sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
+    sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
+
+    vl.values_len = 1;
+    vl.values = values;
+
+    /* dispatch normalized air pressure */
+    sstrncpy (vl.type, "pressure", sizeof (vl.type));
+    sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
+    values[0].gauge = norm_pressure;
+    plugin_dispatch_values (&vl);
+
+    /* dispatch absolute air pressure */
+    sstrncpy (vl.type, "pressure", sizeof (vl.type));
+    sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
+    values[0].gauge = pressure;
+    plugin_dispatch_values (&vl);
+
+    /* dispatch sensor temperature */
+    sstrncpy (vl.type, "temperature", sizeof (vl.type));
+    sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+    values[0].gauge = temperature;
+    plugin_dispatch_values (&vl);
+
+    return 0;
+}
+
+
+/** 
  * Initialization callback
  * 
  * Check config, initialize I2C bus access, conversion coefficients and averaging
@@ -1313,28 +1810,26 @@ static int collectd_barometer_init (void)
         return -1;
     }
 
-    if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
-    {
-        ERROR("barometer: collectd_barometer_init problem setting i2c slave address to 0x%02X: %s",
-              MPL115_I2C_ADDRESS,
-              sstrerror (errno, errbuf, sizeof (errbuf)));
-        return -1;
-    }
-
-    /* detect sensor type - MPL115 or MPL3115 */
-    is_MPL3115 = MPL3115_detect();
+    /* detect sensor type - this will also set slave address */
+    sensor_type = Detect_sensor_type();
 
     /* init correct sensor type */
-    if(is_MPL3115) /* MPL3115 */
+    switch(sensor_type)
+    {
+/* MPL3115 */
+    case Sensor_MPL3115:
     {
         MPL3115_adjust_oversampling();
-
+        
         if(MPL3115_init_sensor())
             return -1;
-
+        
         plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
     }
-    else /* MPL115 */
+    break;
+
+/* MPL115 */
+    case Sensor_MPL115:
     {
         if (averaging_create (&pressure_averaging, config_oversample))
         {
@@ -1350,9 +1845,29 @@ static int collectd_barometer_init (void)
         
         if (MPL115_read_coeffs() < 0)
             return -1;
-
+        
         plugin_register_read ("barometer", MPL115_collectd_barometer_read);
     }
+    break;
+
+/* BMP085 */
+    case Sensor_BMP085:
+    {
+        BMP085_adjust_oversampling();
+
+        if (BMP085_read_coeffs() < 0)
+            return -1;
+
+        plugin_register_read ("barometer", BMP085_collectd_barometer_read);
+    }
+    break;
+
+/* anything else -> error */
+    default:
+        ERROR("barometer: collectd_barometer_init - no supported sensor found");
+        return -1;
+    }
+        
 
     configured = 1;
     return 0;
index cc556a0..08dfb6d 100644 (file)
@@ -1,4 +1,4 @@
-=encoding UTF-8
+encoding UTF-8
 
 =head1 NAME
 
@@ -814,14 +814,28 @@ and are checked by default depends on the distribution you use.
 
 =head2 Plugin C<barometer>
 
-This plugin reads absolute air pressure using digital barometer sensor MPL115A2
-or MPL3115 from Freescale (sensor attached to any I2C bus available in
-the computer, for HW details see 
-I<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL115A> or
-I<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL3115A2>).
-The sensor type - one fo these two - is detected automatically by the plugin
-and indicated in the plugin_instance (typically you will see subdirectory
-"barometer-mpl115" or "barometer-mpl3115").
+This plugin reads absolute air pressure using digital barometer sensor on a I2C
+bus. Supported sensors are:
+
+=over 5
+
+=item I<MPL115A2> from Freescale,
+see L<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL115A>.
+
+
+=item I<MPL3115> from Freescale
+see L<http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPL3115A2>.
+
+
+=item I<BMP085> from Bosch Sensortec
+
+=back
+
+The sensor type - one of the above - is detected automatically by the plugin
+and indicated in the plugin_instance (you will see subdirectory
+"barometer-mpl115" or "barometer-mpl3115", or "barometer-bmp085"). The order of
+detection is BMP085 -> MPL3115 -> MPL115A2, the first one found will be used
+(only one sensor can be used by the plugin).
 
 The plugin provides absolute barometric pressure, air pressure reduced to sea
 level (several possible approximations) and as an auxiliary value also internal
@@ -832,7 +846,7 @@ It was developed and tested under Linux only. The only platform dependency is
 the standard Linux i2c-dev interface (the particular bus driver has to
 support the SM Bus command subset).
 
-The reduction or normalization to mean sea level pressure requires (depedning on
+The reduction or normalization to mean sea level pressure requires (depending on
 selected method/approximation) also altitude and reference to temperature sensor(s).
 When multiple temperature sensors are configured the minumum of their values is
 always used (expecting that the warmer ones are affected by e.g. direct sun light
@@ -854,6 +868,8 @@ Synopsis:
 
 =item B<Device> I<device>
 
+The only mandatory configuration parameter.
+
 Device name of the I2C bus to which the sensor is connected. Note that typically
 you need to have loaded the i2c-dev module.
 Using i2c-tools you can check/list i2c buses available on your system by:
@@ -869,19 +885,29 @@ connected and detected on address 0x60.
 
 =item B<Oversampling> I<value>
 
-For MPL115 this is the size of the averaging window. To filter out sensor noise
-a simple averaging using floating window of configurable size is used. The plugin
+Optional parameter controlling the oversampling/accuracy. Default value
+is 1 providing fastest and least accurate reading.
+
+For I<MPL115> this is the size of the averaging window. To filter out sensor noise
+a simple averaging using floating window of this configurable size is used. The plugin
 will use average of the last C<value> measurements (value of 1 means no averaging).
 Minimal size is 1, maximal 1024.
 
-For MPL3115 this is the oversampling value. The actual oversampling is performed
+For I<MPL3115> this is the oversampling value. The actual oversampling is performed
 by the sensor and the higher value the higher accuracy and longer conversion time
 (although nothing to worry about in the collectd context). Supported values are:
 1, 2, 4, 8, 16, 32, 64 and 128. Any other value is adjusted by the plugin to
-the closest supported one. Default is 128.
+the closest supported one.
+
+For I<BMP085> this is the oversampling value. The actual oversampling is performed
+by the sensor and the higher value the higher accuracy and longer conversion time
+(although nothing to worry about in the collectd context). Supported values are:
+1, 2, 4, 8. Any other value is adjusted by the plugin to the closest supported one.
 
 =item B<PressureOffset> I<offset>
 
+Optional parameter for MPL3115 only.
+
 You can further calibrate the sensor by supplying pressure and/or temperature offsets.
 This is added to the measured/caclulated value (i.e. if the measured value is too high
 then use negative offset).
@@ -889,6 +915,8 @@ In hPa, default is 0.0.
 
 =item B<TemperatureOffset> I<offset>
 
+Optional parameter for MPL3115 only.
+
 You can further calibrate the sensor by supplying pressure and/or temperature offsets.
 This is added to the measured/caclulated value (i.e. if the measured value is too high
 then use negative offset).
@@ -896,24 +924,26 @@ In C, default is 0.0.
 
 =item B<Normalization> I<method>
 
-Normalization method - what approximation/model is used to compute mean sea
+Optional parameter, default value is 0.
+
+Normalization method - what approximation/model is used to compute the mean sea
 level pressure from the air absolute pressure.
 
 Supported values of the C<method> (integer between from 0 to 2) are:
 
 =over 5
 
-=item B<0> - no conversion, absolute pressrure is simply copied over. For this method you
+=item B<0> - no conversion, absolute pressure is simply copied over. For this method you
        do not need to configure C<Altitude> or C<TemperatureSensor>.
 
 =item B<1> - international formula for conversion ,
-See I<http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation>.
+See L<http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation>.
 For this method you have to configure C<Altitude> but do not need C<TemperatureSensor>
 (uses fixed global temperature average instead).
 
 =item B<2> - formula as recommended by the Deutsche Wetterdienst (German
 Meteorological Service).
-See I<http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie>
+See L<http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie>
 For this method you have to configure both  C<Altitude> and C<TemperatureSensor>.
 
 =back
@@ -925,8 +955,9 @@ The altitude (in meters) of the location where you meassure the pressure.
 
 =item B<TemperatureSensor> I<reference>
 
-Temperature sensor which should be used as a reference when normalizing the pressure.
-When specified more sensors a minumum is found and uses each time.
+Temperature sensor(s) which should be used as a reference when normalizing the pressure
+using C<Normalization> method 2.
+When specified more sensors a minumum is found and used each time.
 The temperature reading directly from this pressure sensor/plugin
 is typically not suitable as the pressure sensor
 will be probably inside while we want outside temperature.