diff --git a/src/barometer.c b/src/barometer.c
index 95b05f4e2bda9af43b9e9a600fa43b62ccd44330..aaedd70afd075a51293b354c7a792a5f3e81d7ec 100644 (file)
--- a/src/barometer.c
+++ b/src/barometer.c
/* ------------ MPL115 defines ------------ */
/* I2C address of the MPL115 sensor */
#define MPL115_I2C_ADDRESS 0x60
-
-/* register addresses */
+
+/* register addresses */
#define MPL115_ADDR_CONV 0x00
#define MPL115_ADDR_COEFFS 0x04
-
-/* register sizes */
+
+/* register sizes */
#define MPL115_NUM_CONV 4
#define MPL115_NUM_COEFFS 12
-
-/* commands / addresses */
+
+/* commands / addresses */
#define MPL115_CMD_CONVERT_PRESS 0x10
#define MPL115_CMD_CONVERT_TEMP 0x11
#define MPL115_CMD_CONVERT_BOTH 0x12
-
+
#define MPL115_CONVERSION_RETRIES 5
#define MPL3115_PT_DATA_DREM 0x04
#define MPL3115_PT_DATA_PDEF 0x02
#define MPL3115_PT_DATA_TDEF 0x01
-
+
#define MPL3115_DR_STATUS_TDR 0x02
#define MPL3115_DR_STATUS_PDR 0x04
#define MPL3115_DR_STATUS_PTDR 0x08
#define MPL3115_DR_STATUS_DR (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
-
+
#define MPL3115_DR_STATUS_TOW 0x20
#define MPL3115_DR_STATUS_POW 0x40
#define MPL3115_DR_STATUS_PTOW 0x80
#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",
};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
-
+
static char * config_device = NULL; /**< I2C bus device */
static int config_oversample = 1; /**< averaging window */
static double config_altitude = NAN; /**< altitude */
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 */
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. */
static averaging_t temperature_averaging = { NULL, 0, 0L, 0 };
-/**
+/**
* Create / allocate averaging buffer
*
* The buffer is initialized with zeros.
*
* @return Zero when successful
*/
-static int averaging_create(averaging_t * avg, int size)
+static int averaging_create(averaging_t *avg, int size)
{
- int a;
-
- avg->ring_buffer = (long int *) malloc(size * sizeof(*avg));
+ avg->ring_buffer = calloc ((size_t) size, sizeof (*avg->ring_buffer));
if (avg->ring_buffer == NULL)
{
ERROR ("barometer: averaging_create - ring buffer allocation of size %d failed",
return -1;
}
- for (a=0; a<size; ++a)
- {
- avg->ring_buffer[a] = 0L;
- }
-
avg->ring_buffer_size = size;
avg->ring_buffer_sum = 0L;
avg->ring_buffer_head = 0;
avg->ring_buffer[avg->ring_buffer_head] = sample;
avg->ring_buffer_head = (avg->ring_buffer_head+1) % avg->ring_buffer_size;
result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
-
- DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
- sample,
+
+ DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
+ sample,
result);
return result;
list = list->next;
continue;
}
-
+
for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
{
DEBUG ("barometer: get_reference_temperature - history %d: %lf",
}
list = list->next;
} /* while sensor list */
-
+
if(*result == NAN)
{
ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
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.
*/
static int MPL115_read_coeffs(void)
{
- uint8_t mpl115_coeffs[MPL115_NUM_COEFFS];
+ uint8_t mpl115_coeffs[MPL115_NUM_COEFFS] = { 0 };
int32_t res;
int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
int16_t sia0, sib1, sib2, sic12, sic11, sic22;
-
+
char errbuf[1024];
- res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
- MPL115_ADDR_COEFFS,
- MPL115_NUM_COEFFS,
+ res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
+ MPL115_ADDR_COEFFS,
+ STATIC_ARRAY_SIZE (mpl115_coeffs),
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;
}
-
+
/* Using perhaps less elegant/efficient code, but more readable. */
/* a0: 16total 1sign 12int 4fract 0pad */
sia0MSB = mpl115_coeffs[0];
sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
mpl115_coeffA0 = (double) (sia0);
mpl115_coeffA0 /= 8.0; /* 3 fract bits */
-
+
/* b1: 16total 1sign 2int 13fract 0pad */
sib1MSB= mpl115_coeffs[2];
sib1LSB= mpl115_coeffs[3];
sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
mpl115_coeffB1 = (double) (sib1);
mpl115_coeffB1 /= 8192.0; /* 13 fract */
-
+
/* b2: 16total 1sign 1int 14fract 0pad */
sib2MSB= mpl115_coeffs[4];
sib2LSB= mpl115_coeffs[5];
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",
- mpl115_coeffA0,
- mpl115_coeffB1,
- mpl115_coeffB2,
- mpl115_coeffC12,
- mpl115_coeffC11,
+ DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
+ mpl115_coeffA0,
+ mpl115_coeffB1,
+ mpl115_coeffB2,
+ mpl115_coeffC12,
+ mpl115_coeffC11,
mpl115_coeffC22);
return 0;
}
-/*
+/**
* Convert raw adc values to real data using the sensor coefficients.
*
* @param adc_pressure adc pressure value to be converted
Pcomp = mpl115_coeffA0 + \
(mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
(mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
-
+
*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);
}
-/**
+/**
* Read sensor averegaed measurements
*
* @param pressure averaged measured pressure
*/
static int MPL115_read_averaged(double * pressure, double * temperature)
{
- uint8_t mpl115_conv[MPL115_NUM_CONV];
+ uint8_t mpl115_conv[MPL115_NUM_CONV] = { 0 };
int8_t res;
int retries;
int conv_pressure;
*pressure = 0.0;
*temperature = 0.0;
-
+
/* start conversion of both temp and presure */
retries = MPL115_CONVERSION_RETRIES;
while (retries>0)
{
res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
MPL115_ADDR_CONV,
- MPL115_NUM_CONV,
- mpl115_conv);
+ STATIC_ARRAY_SIZE (mpl115_conv),
+ mpl115_conv);
if (res >= 0)
break;
return -1;
}
}
-
+
conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
adc_temperature,
*pressure,
*temperature);
-
+
return 0;
}
/* ------------------------ MPL3115 access ------------------------ */
-/**
+/**
* 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)
return 0;
}
-/**
+/**
* Adjusts oversampling to values supported by MPL3115
*
- * MPL3115 supports only power of 2 in the range 1 to 128.
+ * MPL3115 supports only power of 2 in the range 1 to 128.
*/
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",
- config_oversample,
+ DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
+ config_oversample,
new_val);
config_oversample = new_val;
}
-/**
- * Read sensor averegaed measurements
+/**
+ * Read sensor averaged measurements
*
* @param pressure averaged measured pressure
* @param temperature averaged measured temperature
__u8 data[MPL3115_NUM_CONV_VALS];
long int tmp_value = 0;
char errbuf[1024];
-
+
/* Set Active - activate the device from standby */
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
if (res < 0)
return 1;
}
ctrl = res;
- res = i2c_smbus_write_byte_data(i2c_bus_fd,
- MPL3115_REG_CTRL_REG1,
+ res = i2c_smbus_write_byte_data(i2c_bus_fd,
+ MPL3115_REG_CTRL_REG1,
ctrl | MPL3115_CTRL_REG1_SBYB);
if (res < 0)
{
sstrerror (errno, errbuf, sizeof (errbuf)));
return 1;
}
-
+
/* base sleep is 5ms x OST */
usleep(5000 * config_oversample);
-
+
/* check the flags/status if ready */
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
if (res < 0)
sstrerror (errno, errbuf, sizeof (errbuf)));
return 1;
}
-
+
while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
{
/* try some extra sleep... */
usleep(10000);
-
+
/* ... and repeat the check. The conversion has to finish sooner or later. */
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
if (res < 0)
return 1;
}
}
-
+
/* Now read all the data in one block. There is address autoincrement. */
- res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
- MPL3115_REG_OUT_P_MSB,
+ res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
+ MPL3115_REG_OUT_P_MSB,
MPL3115_NUM_CONV_VALS,
data);
if (res < 0)
sstrerror (errno, errbuf, sizeof (errbuf)));
return 1;
}
-
+
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)
{
data[3] = ~data[3] + 1;
{
*temperature = data[3];
}
-
+
*temperature += (double)(data[4]) / 256.0;
- DEBUG ("barometer: MPL3115_read, temperature = %lf C", *temperature);
-
+ DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
+
return 0;
}
-/**
+/**
* Initialize MPL3115 for barometeric measurements
- *
+ *
* @return 0 if successful
*/
static int MPL3115_init_sensor(void)
__s32 res;
__s8 offset;
char errbuf[1024];
-
+
/* Reset the sensor. It will reset immediately without ACKing */
/* the transaction, so no error handling here. */
- i2c_smbus_write_byte_data(i2c_bus_fd,
- MPL3115_REG_CTRL_REG1,
+ i2c_smbus_write_byte_data(i2c_bus_fd,
+ MPL3115_REG_CTRL_REG1,
MPL3115_CTRL_REG1_RST);
-
+
/* wait some time for the reset to finish */
usleep(100000);
/* now it should be in standby already so we can go and configure it */
-
+
/* Set temperature offset. */
/* result = ADCtemp + offset [C] */
offset = (__s8) (config_temp_offset * 16.0);
sstrerror (errno, errbuf, sizeof (errbuf)));
return -1;
}
-
+
/* Set pressure offset. */
/* result = ADCpress + offset [hPa] */
offset = (__s8) (config_press_offset * 100.0 / 4.0);
}
/* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
- res = i2c_smbus_write_byte_data(i2c_bus_fd,
+ res = i2c_smbus_write_byte_data(i2c_bus_fd,
MPL3115_REG_PT_DATA_CFG,
MPL3115_PT_DATA_DREM \
| MPL3115_PT_DATA_PDEF \
return -1;
}
- /* Set to barometer with an OSR */
- res = i2c_smbus_write_byte_data(i2c_bus_fd,
- MPL3115_REG_CTRL_REG1,
- oversample_MPL3115);
+ /* Set to barometer with an OSR */
+ res = i2c_smbus_write_byte_data(i2c_bus_fd,
+ MPL3115_REG_CTRL_REG1,
+ mpl3115_oversample);
if (res < 0)
{
ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
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
+ */
+static 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 ------------------------ */
* - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
* Requires #config_altitude
*
- * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
+ * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
* http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
* Requires both #config_altitude and temperature reference(s).
*
double temp = 0.0;
int result = 0;
- DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf, method = %d",
- abs_pressure,
- config_normalize);
-
if (config_normalize >= MSLP_DEU_WETT)
{
result = get_reference_temperature(&temp);
case MSLP_NONE:
mean = abs_pressure;
break;
-
+
case MSLP_INTERNATIONAL:
mean = abs_pressure / \
- pow(1.0 - 0.0065*config_altitude/288.15, 0.0065*0.0289644/(8.31447*0.0065));
+ pow(1.0 - 0.0065*config_altitude/288.15, 9.80665*0.0289644/(8.31447*0.0065));
break;
-
+
case MSLP_DEU_WETT:
{
double E; /* humidity */
break;
default:
- ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
+ ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
config_normalize);
mean = abs_pressure;
break;
}
- return mean;
+ DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, method = %d, meanPressure = %lf hPa",
+ abs_pressure,
+ config_normalize,
+ mean);
+
+ return mean;
}
/* ------------------------ main plugin callbacks ------------------------ */
-/**
+/**
* Main plugin configuration callback (using simple config)
- *
+ *
* @param key configuration key we should process
* @param value configuration value we should process
- *
+ *
* @return Zero when successful.
*/
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;
}
{
config_temp_offset = atof(value);
}
- else
+ else
{
return -1;
}
}
-/**
+/**
* Shutdown callback.
- *
+ *
* Close I2C and delete all the buffers.
- *
+ *
* @return Zero when successful (at the moment the only possible outcome)
*/
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);
}
-/**
+/**
* Plugin read callback for MPL115.
- *
+ *
* Dispatching will create values:
* - <hostname>/barometer-mpl115/pressure-normalized
* - <hostname>/barometer-mpl115/pressure-absolute
value_list_t vl = VALUE_LIST_INIT;
value_t values[1];
-
+
DEBUG("barometer: MPL115_collectd_barometer_read");
if (!configured)
}
-/**
+/**
* Plugin read callback for MPL3115.
- *
+ *
* Dispatching will create values:
* - <hostname>/barometer-mpl3115/pressure-normalized
* - <hostname>/barometer-mpl3115/pressure-absolute
static int MPL3115_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: MPL3115_collectd_barometer_read");
-
+
if (!configured)
{
return -1;
}
-
+
result = MPL3115_read(&pressure, &temperature);
if(result)
return result;
}
-/**
+/**
+ * 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
* ring buffers
- *
+ *
* @return Zero when successful.
*/
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();
plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
}
- else /* MPL115 */
+ break;
+
+/* MPL115 */
+ case Sensor_MPL115:
{
if (averaging_create (&pressure_averaging, config_oversample))
{
ERROR("barometer: collectd_barometer_init pressure averaging init failed");
return -1;
}
-
+
if (averaging_create (&temperature_averaging, config_oversample))
{
ERROR("barometer: collectd_barometer_init temperature averaging init failed");
return -1;
}
-
+
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;
/* ------------------------ plugin register / entry point ------------------------ */
-/**
+/**
* Plugin "entry" - register all callback.
- *
+ *
*/
void module_register (void)
{
- plugin_register_config ("barometer",
- collectd_barometer_config,
- config_keys,
+ plugin_register_config ("barometer",
+ collectd_barometer_config,
+ config_keys,
config_keys_num);
plugin_register_init ("barometer", collectd_barometer_init);
plugin_register_shutdown ("barometer", collectd_barometer_shutdown);