1 /**
2 * collectd - src/barometer.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; only version 2.1 of the License is
7 * applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Tomas Menzl
20 **/
22 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "utils_cache.h"
28 #include <fcntl.h>
29 #include <linux/i2c-dev.h>
30 #include <math.h>
31 #include <stdint.h>
32 #include <sys/ioctl.h>
33 #include <unistd.h>
35 /* ------------ MPL115 defines ------------ */
36 /* I2C address of the MPL115 sensor */
37 #define MPL115_I2C_ADDRESS 0x60
39 /* register addresses */
40 #define MPL115_ADDR_CONV 0x00
41 #define MPL115_ADDR_COEFFS 0x04
43 /* register sizes */
44 #define MPL115_NUM_CONV 4
45 #define MPL115_NUM_COEFFS 12
47 /* commands / addresses */
48 #define MPL115_CMD_CONVERT_PRESS 0x10
49 #define MPL115_CMD_CONVERT_TEMP 0x11
50 #define MPL115_CMD_CONVERT_BOTH 0x12
52 #define MPL115_CONVERSION_RETRIES 5
54 /* ------------ MPL3115 defines ------------ */
55 /* MPL3115 I2C address */
56 #define MPL3115_I2C_ADDRESS 0x60
58 /* register addresses (only the interesting ones) */
59 #define MPL3115_REG_STATUS 0x00
60 #define MPL3115_REG_OUT_P_MSB 0x01
61 #define MPL3115_REG_OUT_P_CSB 0x02
62 #define MPL3115_REG_OUT_P_LSB 0x03
63 #define MPL3115_REG_OUT_T_MSB 0x04
64 #define MPL3115_REG_OUT_T_LSB 0x05
65 #define MPL3115_REG_DR_STATUS 0x06
66 #define MPL3115_REG_WHO_AM_I 0x0C
67 #define MPL3115_REG_SYSMOD 0x11
68 #define MPL3115_REG_PT_DATA_CFG 0x13
69 #define MPL3115_REG_BAR_IN_MSB 0x14
70 #define MPL3115_REG_BAR_IN_LSB 0x15
71 #define MPL3115_REG_CTRL_REG1 0x26
72 #define MPL3115_REG_CTRL_REG2 0x27
73 #define MPL3115_REG_CTRL_REG3 0x28
74 #define MPL3115_REG_CTRL_REG4 0x29
75 #define MPL3115_REG_CTRL_REG5 0x2A
76 #define MPL3115_REG_OFF_P 0x2B
77 #define MPL3115_REG_OFF_T 0x2C
78 #define MPL3115_REG_OFF_H 0x2D
80 /* Register values, masks */
81 #define MPL3115_WHO_AM_I_RESP 0xC4
83 #define MPL3115_PT_DATA_DREM 0x04
84 #define MPL3115_PT_DATA_PDEF 0x02
85 #define MPL3115_PT_DATA_TDEF 0x01
87 #define MPL3115_DR_STATUS_TDR 0x02
88 #define MPL3115_DR_STATUS_PDR 0x04
89 #define MPL3115_DR_STATUS_PTDR 0x08
90 #define MPL3115_DR_STATUS_DR \
91 (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
93 #define MPL3115_DR_STATUS_TOW 0x20
94 #define MPL3115_DR_STATUS_POW 0x40
95 #define MPL3115_DR_STATUS_PTOW 0x80
97 #define MPL3115_CTRL_REG1_ALT 0x80
98 #define MPL3115_CTRL_REG1_RAW 0x40
99 #define MPL3115_CTRL_REG1_OST_MASK 0x38
100 #define MPL3115_CTRL_REG1_OST_1 0x00
101 #define MPL3115_CTRL_REG1_OST_2 0x08
102 #define MPL3115_CTRL_REG1_OST_4 0x10
103 #define MPL3115_CTRL_REG1_OST_8 0x18
104 #define MPL3115_CTRL_REG1_OST_16 0x20
105 #define MPL3115_CTRL_REG1_OST_32 0x28
106 #define MPL3115_CTRL_REG1_OST_64 0x30
107 #define MPL3115_CTRL_REG1_OST_128 0x38
108 #define MPL3115_CTRL_REG1_RST 0x04
109 #define MPL3115_CTRL_REG1_OST 0x02
110 #define MPL3115_CTRL_REG1_SBYB 0x01
111 #define MPL3115_CTRL_REG1_SBYB_MASK 0xFE
113 #define MPL3115_NUM_CONV_VALS 5
115 /* ------------ BMP085 defines ------------ */
116 /* I2C address of the BMP085 sensor */
117 #define BMP085_I2C_ADDRESS 0x77
119 /* register addresses */
120 #define BMP085_ADDR_ID_REG 0xD0
121 #define BMP085_ADDR_VERSION 0xD1
123 #define BMP085_ADDR_CONV 0xF6
125 #define BMP085_ADDR_CTRL_REG 0xF4
126 #define BMP085_ADDR_COEFFS 0xAA
128 /* register sizes */
129 #define BMP085_NUM_COEFFS 22
131 /* commands, values */
132 #define BMP085_CHIP_ID 0x55
134 #define BMP085_CMD_CONVERT_TEMP 0x2E
136 #define BMP085_CMD_CONVERT_PRESS_0 0x34
137 #define BMP085_CMD_CONVERT_PRESS_1 0x74
138 #define BMP085_CMD_CONVERT_PRESS_2 0xB4
139 #define BMP085_CMD_CONVERT_PRESS_3 0xF4
141 /* in us */
142 #define BMP085_TIME_CNV_TEMP 4500
144 #define BMP085_TIME_CNV_PRESS_0 4500
145 #define BMP085_TIME_CNV_PRESS_1 7500
146 #define BMP085_TIME_CNV_PRESS_2 13500
147 #define BMP085_TIME_CNV_PRESS_3 25500
149 /* ------------ Normalization ------------ */
150 /* Mean sea level pressure normalization methods */
151 #define MSLP_NONE 0
152 #define MSLP_INTERNATIONAL 1
153 #define MSLP_DEU_WETT 2
155 /** Temperature reference history depth for averaging. See
156 * #get_reference_temperature */
157 #define REF_TEMP_AVG_NUM 5
159 /* ------------------------------------------ */
161 /** Supported sensor types */
162 enum Sensor_type {
163 Sensor_none = 0,
164 Sensor_MPL115,
165 Sensor_MPL3115,
166 Sensor_BMP085
167 };
169 static const char *config_keys[] = {
170 "Device",
171 "Oversampling",
172 "PressureOffset", /**< only for MPL3115 */
173 "TemperatureOffset", /**< only for MPL3115 */
174 "Altitude",
175 "Normalization",
176 "TemperatureSensor"};
178 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
180 static char *config_device = NULL; /**< I2C bus device */
181 static int config_oversample = 1; /**< averaging window */
183 static double config_press_offset = 0.0; /**< pressure offset */
184 static double config_temp_offset = 0.0; /**< temperature offset */
186 static double config_altitude = NAN; /**< altitude */
187 static int config_normalize = 0; /**< normalization method */
189 static _Bool configured = 0; /**< the whole plugin config status */
191 static int i2c_bus_fd = -1; /**< I2C bus device FD */
193 static enum Sensor_type sensor_type =
194 Sensor_none; /**< detected/used sensor type */
196 static __s32 mpl3115_oversample = 0; /**< MPL3115 CTRL1 oversample setting */
198 // BMP085 configuration
199 static unsigned bmp085_oversampling; /**< BMP085 oversampling (0-3) */
200 static unsigned long
201 bmp085_timeCnvPress; /**< BMP085 conversion time for pressure in us */
202 static __u8 bmp085_cmdCnvPress; /**< BMP085 pressure conversion command */
204 /* MPL115 conversion coefficients */
205 static double mpl115_coeffA0;
206 static double mpl115_coeffB1;
207 static double mpl115_coeffB2;
208 static double mpl115_coeffC12;
209 static double mpl115_coeffC11;
210 static double mpl115_coeffC22;
212 /* BMP085 conversion coefficients */
213 static short bmp085_AC1;
214 static short bmp085_AC2;
215 static short bmp085_AC3;
216 static unsigned short bmp085_AC4;
217 static unsigned short bmp085_AC5;
218 static unsigned short bmp085_AC6;
219 static short bmp085_B1;
220 static short bmp085_B2;
221 static short bmp085_MB;
222 static short bmp085_MC;
223 static short bmp085_MD;
225 /* ------------------------ averaging ring buffer ------------------------ */
226 /* Used only for MPL115. MPL3115 supports real oversampling in the device so */
227 /* no need for any postprocessing. */
229 static _Bool avg_initialized = 0; /**< already initialized by real values */
231 typedef struct averaging_s {
232 long int *ring_buffer;
233 int ring_buffer_size;
234 long int ring_buffer_sum;
235 int ring_buffer_head;
236 } averaging_t;
238 static averaging_t pressure_averaging = {NULL, 0, 0L, 0};
239 static averaging_t temperature_averaging = {NULL, 0, 0L, 0};
241 /**
242 * Create / allocate averaging buffer
243 *
244 * The buffer is initialized with zeros.
245 *
246 * @param avg pointer to ring buffer to be allocated
247 * @param size requested buffer size
248 *
249 * @return Zero when successful
250 */
251 static int averaging_create(averaging_t *avg, int size) {
252 avg->ring_buffer = calloc((size_t)size, sizeof(*avg->ring_buffer));
253 if (avg->ring_buffer == NULL) {
254 ERROR("barometer: averaging_create - ring buffer allocation of size %d "
255 "failed",
256 size);
257 return -1;
258 }
260 avg->ring_buffer_size = size;
261 avg->ring_buffer_sum = 0L;
262 avg->ring_buffer_head = 0;
264 return 0;
265 }
267 /**
268 * Delete / free existing averaging buffer
269 *
270 * @param avg pointer to the ring buffer to be deleted
271 */
272 static void averaging_delete(averaging_t *avg) {
273 if (avg->ring_buffer != NULL) {
274 free(avg->ring_buffer);
275 avg->ring_buffer = NULL;
276 }
277 avg->ring_buffer_size = 0;
278 avg->ring_buffer_sum = 0L;
279 avg->ring_buffer_head = 0;
280 }
282 /*
283 * Add new sample to the averaging buffer
284 *
285 * A new averaged value is returned. Note that till the buffer is full
286 * returned value is inaccurate as it is an average of real values and initial
287 * zeros.
288 *
289 * @param avg pointer to the ring buffer
290 * @param sample new sample value
291 *
292 * @return Averaged sample value
293 */
294 static double averaging_add_sample(averaging_t *avg, long int sample) {
295 double result;
297 avg->ring_buffer_sum += sample - avg->ring_buffer[avg->ring_buffer_head];
298 avg->ring_buffer[avg->ring_buffer_head] = sample;
299 avg->ring_buffer_head = (avg->ring_buffer_head + 1) % avg->ring_buffer_size;
300 result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
302 DEBUG("barometer: averaging_add_sample - added %ld, result = %lf", sample,
303 result);
305 return result;
306 }
308 /* ------------------------ temperature refference ------------------------ */
310 /**
311 * Linked list type of temperature sensor references
312 */
313 typedef struct temperature_list_s {
314 char *sensor_name; /**< sensor name/reference */
315 size_t num_values; /**< number of values (usually one) */
316 _Bool initialized; /**< sensor already provides data */
317 struct temperature_list_s *next; /**< next in the list */
318 } temperature_list_t;
320 static temperature_list_t *temp_list = NULL;
322 /*
323 * Add new sensor to the temperature reference list
324 *
325 * @param list the list
326 * @param sensor reference name (as provided by the config file)
327 *
328 * @return Zero when successful
329 */
330 static int temp_list_add(temperature_list_t *list, const char *sensor) {
331 temperature_list_t *new_temp;
333 new_temp = malloc(sizeof(*new_temp));
334 if (new_temp == NULL)
335 return -1;
337 new_temp->sensor_name = strdup(sensor);
338 new_temp->initialized = 0;
339 new_temp->num_values = 0;
340 if (new_temp->sensor_name == NULL) {
341 free(new_temp);
342 return -1;
343 }
345 new_temp->next = temp_list;
346 temp_list = new_temp;
347 return 0;
348 }
350 /*
351 * Delete the whole temperature reference list
352 *
353 * @param list the list to be deleted
354 */
355 static void temp_list_delete(temperature_list_t **list) {
356 temperature_list_t *tmp;
358 while (*list != NULL) {
359 tmp = (*list);
360 (*list) = (*list)->next;
361 free(tmp->sensor_name);
362 free(tmp);
363 tmp = NULL;
364 }
365 }
367 /*
368 * Get reference temperature value
369 *
370 * First initially uc_get_rate_by_name is tried. At the startup due to
371 * nondeterministic order the temperature may not be read yet (then it fails and
372 * first measurment gives only absolute air pressure reading which is
373 * acceptable). Once it succedes (should be second measurement at the latest) we
374 * use average of few last readings from uc_get_history_by_name. It may take few
375 * readings to start filling so again we use uc_get_rate_by_name as a fallback.
376 * The idea is to use basic "noise" filtering (history averaging) across all the
377 * values which given sensor provides (up to given depth). Then we get minimum
378 * among the sensors.
379 *
380 * @param result where the result is stored. When not available NAN is stored.
381 *
382 * @return Zero when successful
383 */
384 static int get_reference_temperature(double *result) {
385 temperature_list_t *list = temp_list;
387 gauge_t *values = NULL; /**< rate values */
388 size_t values_num = 0; /**< number of rate values */
390 gauge_t values_history[REF_TEMP_AVG_NUM];
392 double avg_sum; /**< Value sum for computing average */
393 int avg_num; /**< Number of values for computing average */
394 double average; /**< Resulting value average */
396 *result = NAN;
398 while (list != NULL) {
399 avg_sum = 0.0;
400 avg_num = 0;
402 /* First time need to read current rate to learn how many values are
403 there (typically for temperature it would be just one). We do not expect
404 dynamic changing of number of temperarure values in runtime yet (are
405 there any such cases?). */
406 if (!list->initialized) {
407 if (uc_get_rate_by_name(list->sensor_name, &values, &values_num)) {
408 DEBUG(
409 "barometer: get_reference_temperature - rate \"%s\" not found yet",
410 list->sensor_name);
411 list = list->next;
412 continue;
413 }
415 DEBUG(
416 "barometer: get_reference_temperature - initialize \"%s\", %zu vals",
417 list->sensor_name, values_num);
419 list->initialized = 1;
420 list->num_values = values_num;
422 for (size_t i = 0; i < values_num; ++i) {
423 DEBUG("barometer: get_reference_temperature - rate %zu: %lf **", i,
424 values[i]);
425 if (!isnan(values[i])) {
426 avg_sum += values[i];
427 ++avg_num;
428 }
429 }
430 free(values);
431 values = NULL;
432 }
434 /* It is OK to get here the first time as well, in the worst case
435 the history will full of NANs. */
436 if (uc_get_history_by_name(list->sensor_name, values_history,
437 REF_TEMP_AVG_NUM, list->num_values)) {
438 ERROR("barometer: get_reference_temperature - history \"%s\" lost",
439 list->sensor_name);
440 list->initialized = 0;
441 list->num_values = 0;
442 list = list->next;
443 continue;
444 }
446 for (size_t i = 0; i < REF_TEMP_AVG_NUM * list->num_values; ++i) {
447 DEBUG("barometer: get_reference_temperature - history %zu: %lf", i,
448 values_history[i]);
449 if (!isnan(values_history[i])) {
450 avg_sum += values_history[i];
451 ++avg_num;
452 }
453 }
455 if (avg_num == 0) /* still no history? fallback to current */
456 {
457 if (uc_get_rate_by_name(list->sensor_name, &values, &values_num)) {
458 ERROR("barometer: get_reference_temperature - rate \"%s\" lost",
459 list->sensor_name);
460 list->initialized = 0;
461 list->num_values = 0;
462 list = list->next;
463 continue;
464 }
466 for (size_t i = 0; i < values_num; ++i) {
467 DEBUG("barometer: get_reference_temperature - rate last %zu: %lf **", i,
468 values[i]);
469 if (!isnan(values[i])) {
470 avg_sum += values[i];
471 ++avg_num;
472 }
473 }
474 free(values);
475 values = NULL;
476 }
478 if (avg_num == 0) {
479 ERROR("barometer: get_reference_temperature - could not read \"%s\"",
480 list->sensor_name);
481 list->initialized = 0;
482 list->num_values = 0;
483 } else {
484 average = avg_sum / (double)avg_num;
485 if (isnan(*result))
486 *result = average;
487 else if (*result > average)
488 *result = average;
489 }
490 list = list->next;
491 } /* while sensor list */
493 if (*result == NAN) {
494 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
495 return -1;
496 }
497 DEBUG("barometer: get_reference_temperature - temp is %lf", *result);
498 return 0;
499 }
501 /* ------------------------ MPL115 access ------------------------ */
503 /**
504 * Detect presence of a MPL115 pressure sensor.
505 *
506 * Unfortunately there seems to be no ID register so we just try to read first
507 * conversion coefficient from device at MPL115 address and hope it is really
508 * MPL115. We should use this check as the last resort (which would be the
509 * typical
510 * case anyway since MPL115 is the least accurate sensor).
511 * As a sideeffect will leave set I2C slave address.
512 *
513 * @return 1 if MPL115, 0 otherwise
514 */
515 static int MPL115_detect(void) {
516 __s32 res;
517 char errbuf[1024];
519 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0) {
520 ERROR("barometer: MPL115_detect problem setting i2c slave address to "
521 "0x%02X: %s",
522 MPL115_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
523 return 0;
524 }
526 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
527 if (res >= 0) {
528 DEBUG("barometer: MPL115_detect - positive detection");
529 return 1;
530 }
532 DEBUG("barometer: MPL115_detect - negative detection");
533 return 0;
534 }
536 /**
537 * Read the MPL115 sensor conversion coefficients.
538 *
539 * These are (device specific) constants so we can read them just once.
540 *
541 * @return Zero when successful
542 */
543 static int MPL115_read_coeffs(void) {
544 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS] = {0};
545 int32_t res;
547 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
548 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
549 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
551 char errbuf[1024];
553 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL115_ADDR_COEFFS,
554 STATIC_ARRAY_SIZE(mpl115_coeffs),
555 mpl115_coeffs);
556 if (res < 0) {
557 ERROR("barometer: MPL115_read_coeffs - problem reading data: %s",
558 sstrerror(errno, errbuf, sizeof(errbuf)));
559 return -1;
560 }
562 /* Using perhaps less elegant/efficient code, but more readable. */
563 /* a0: 16total 1sign 12int 4fract 0pad */
564 sia0MSB = mpl115_coeffs[0];
565 sia0LSB = mpl115_coeffs[1];
566 sia0 = (int16_t)sia0MSB << 8; /* s16 type, Shift to MSB */
567 sia0 += (int16_t)sia0LSB & 0x00FF; /* Add LSB to 16bit number */
568 mpl115_coeffA0 = (double)(sia0);
569 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
571 /* b1: 16total 1sign 2int 13fract 0pad */
572 sib1MSB = mpl115_coeffs[2];
573 sib1LSB = mpl115_coeffs[3];
574 sib1 = sib1MSB << 8; /* Shift to MSB */
575 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
576 mpl115_coeffB1 = (double)(sib1);
577 mpl115_coeffB1 /= 8192.0; /* 13 fract */
579 /* b2: 16total 1sign 1int 14fract 0pad */
580 sib2MSB = mpl115_coeffs[4];
581 sib2LSB = mpl115_coeffs[5];
582 sib2 = sib2MSB << 8; /* Shift to MSB */
583 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
584 mpl115_coeffB2 = (double)(sib2);
585 mpl115_coeffB2 /= 16384.0; /* 14 fract */
587 /* c12: 14total 1sign 0int 13fract 9pad */
588 sic12MSB = mpl115_coeffs[6];
589 sic12LSB = mpl115_coeffs[7];
590 sic12 = sic12MSB << 8; /* Shift to MSB only by 8 for MSB */
591 sic12 += sic12LSB & 0x00FF;
592 mpl115_coeffC12 = (double)(sic12);
593 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
594 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
596 /* c11: 11total 1sign 0int 11fract 11pad */
597 sic11MSB = mpl115_coeffs[8];
598 sic11LSB = mpl115_coeffs[9];
599 sic11 = sic11MSB << 8; /* Shift to MSB only by 8 for MSB */
600 sic11 += sic11LSB & 0x00FF;
601 mpl115_coeffC11 = (double)(sic11);
602 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
603 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
605 /* c12: 11total 1sign 0int 10fract 15pad */
606 sic22MSB = mpl115_coeffs[10];
607 sic22LSB = mpl115_coeffs[11];
608 sic22 = sic22MSB << 8; /* Shift to MSB only by 8 for MSB */
609 sic22 += sic22LSB & 0x00FF;
610 mpl115_coeffC22 = (double)(sic22);
611 mpl115_coeffC22 /= 32.0; // 16-11=5
612 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
614 DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, "
615 "c11=%lf, c22=%lf",
616 mpl115_coeffA0, mpl115_coeffB1, mpl115_coeffB2, mpl115_coeffC12,
617 mpl115_coeffC11, mpl115_coeffC22);
618 return 0;
619 }
621 /**
622 * Convert raw adc values to real data using the sensor coefficients.
623 *
624 * @param adc_pressure adc pressure value to be converted
625 * @param adc_temp adc temperature value to be converted
626 * @param pressure computed real pressure
627 * @param temperature computed real temperature
628 */
629 static void MPL115_convert_adc_to_real(double adc_pressure, double adc_temp,
630 double *pressure, double *temperature) {
631 double Pcomp;
632 Pcomp = mpl115_coeffA0 +
633 (mpl115_coeffB1 + mpl115_coeffC11 * adc_pressure +
634 mpl115_coeffC12 * adc_temp) *
635 adc_pressure +
636 (mpl115_coeffB2 + mpl115_coeffC22 * adc_temp) * adc_temp;
638 *pressure = ((1150.0 - 500.0) * Pcomp / 1023.0) + 500.0;
639 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
640 DEBUG("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C", *pressure,
641 *temperature);
642 }
644 /**
645 * Read sensor averegaed measurements
646 *
647 * @param pressure averaged measured pressure
648 * @param temperature averaged measured temperature
649 *
650 * @return Zero when successful
651 */
652 static int MPL115_read_averaged(double *pressure, double *temperature) {
653 uint8_t mpl115_conv[MPL115_NUM_CONV] = {0};
654 int8_t res;
655 int retries;
656 int conv_pressure;
657 int conv_temperature;
658 double adc_pressure;
659 double adc_temperature;
660 char errbuf[1024];
662 *pressure = 0.0;
663 *temperature = 0.0;
665 /* start conversion of both temp and presure */
666 retries = MPL115_CONVERSION_RETRIES;
667 while (retries > 0) {
668 /* write 1 to start conversion */
669 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL115_CMD_CONVERT_BOTH, 0x01);
670 if (res >= 0)
671 break;
673 --retries;
674 if (retries > 0) {
675 ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
676 "will retry at most %d more times",
677 sstrerror(errno, errbuf, sizeof(errbuf)), retries);
678 } else {
679 ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
680 "too many failed retries",
681 sstrerror(errno, errbuf, sizeof(errbuf)));
682 return -1;
683 }
684 }
686 usleep(10000); /* wait 10ms for the conversion */
688 retries = MPL115_CONVERSION_RETRIES;
689 while (retries > 0) {
690 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL115_ADDR_CONV,
691 STATIC_ARRAY_SIZE(mpl115_conv),
692 mpl115_conv);
693 if (res >= 0)
694 break;
696 --retries;
697 if (retries > 0) {
698 ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
699 "will retry at most %d more times",
700 sstrerror(errno, errbuf, sizeof(errbuf)), retries);
701 } else {
702 ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
703 "too many failed retries",
704 sstrerror(errno, errbuf, sizeof(errbuf)));
705 return -1;
706 }
707 }
709 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
710 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
711 DEBUG("barometer: MPL115_read_averaged, raw pressure ADC value = %d, "
712 "raw temperature ADC value = %d",
713 conv_pressure, conv_temperature);
715 adc_pressure = averaging_add_sample(&pressure_averaging, conv_pressure);
716 adc_temperature =
717 averaging_add_sample(&temperature_averaging, conv_temperature);
719 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure,
720 temperature);
722 DEBUG("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / "
723 "temperature = %lf, "
724 "real pressure = %lf hPa / temperature = %lf C",
725 adc_pressure, adc_temperature, *pressure, *temperature);
727 return 0;
728 }
730 /* ------------------------ MPL3115 access ------------------------ */
732 /**
733 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
734 *
735 * As a sideeffect will leave set I2C slave address.
736 *
737 * @return 1 if MPL3115, 0 otherwise
738 */
739 static int MPL3115_detect(void) {
740 __s32 res;
741 char errbuf[1024];
743 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0) {
744 ERROR("barometer: MPL3115_detect problem setting i2c slave address to "
745 "0x%02X: %s",
746 MPL3115_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
747 return 0;
748 }
750 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
751 if (res == MPL3115_WHO_AM_I_RESP) {
752 DEBUG("barometer: MPL3115_detect - positive detection");
753 return 1;
754 }
756 DEBUG("barometer: MPL3115_detect - negative detection");
757 return 0;
758 }
760 /**
761 * Adjusts oversampling to values supported by MPL3115
762 *
763 * MPL3115 supports only power of 2 in the range 1 to 128.
764 */
765 static void MPL3115_adjust_oversampling(void) {
766 int new_val = 0;
768 if (config_oversample > 100) {
769 new_val = 128;
770 mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
771 } else if (config_oversample > 48) {
772 new_val = 64;
773 mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
774 } else if (config_oversample > 24) {
775 new_val = 32;
776 mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
777 } else if (config_oversample > 12) {
778 new_val = 16;
779 mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
780 } else if (config_oversample > 6) {
781 new_val = 8;
782 mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
783 } else if (config_oversample > 3) {
784 new_val = 4;
785 mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
786 } else if (config_oversample > 1) {
787 new_val = 2;
788 mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
789 } else {
790 new_val = 1;
791 mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
792 }
794 DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from "
795 "%d to %d",
796 config_oversample, new_val);
797 config_oversample = new_val;
798 }
800 /**
801 * Read sensor averaged measurements
802 *
803 * @param pressure averaged measured pressure
804 * @param temperature averaged measured temperature
805 *
806 * @return Zero when successful
807 */
808 static int MPL3115_read(double *pressure, double *temperature) {
809 __s32 res;
810 __s32 ctrl;
811 __u8 data[MPL3115_NUM_CONV_VALS];
812 long int tmp_value = 0;
813 char errbuf[1024];
815 /* Set Active - activate the device from standby */
816 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
817 if (res < 0) {
818 ERROR("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
819 sstrerror(errno, errbuf, sizeof(errbuf)));
820 return 1;
821 }
822 ctrl = res;
823 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
824 ctrl | MPL3115_CTRL_REG1_SBYB);
825 if (res < 0) {
826 ERROR("barometer: MPL3115_read - problem activating: %s",
827 sstrerror(errno, errbuf, sizeof(errbuf)));
828 return 1;
829 }
831 /* base sleep is 5ms x OST */
832 usleep(5000 * config_oversample);
834 /* check the flags/status if ready */
835 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
836 if (res < 0) {
837 ERROR("barometer: MPL3115_read - cannot read status register: %s",
838 sstrerror(errno, errbuf, sizeof(errbuf)));
839 return 1;
840 }
842 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR) {
843 /* try some extra sleep... */
844 usleep(10000);
846 /* ... and repeat the check. The conversion has to finish sooner or later.
847 */
848 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
849 if (res < 0) {
850 ERROR("barometer: MPL3115_read - cannot read status register: %s",
851 sstrerror(errno, errbuf, sizeof(errbuf)));
852 return 1;
853 }
854 }
856 /* Now read all the data in one block. There is address autoincrement. */
857 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL3115_REG_OUT_P_MSB,
858 MPL3115_NUM_CONV_VALS, data);
859 if (res < 0) {
860 ERROR("barometer: MPL3115_read - cannot read data registers: %s",
861 sstrerror(errno, errbuf, sizeof(errbuf)));
862 return 1;
863 }
865 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
866 *pressure = ((double)tmp_value) / 4.0 / 16.0 / 100.0;
867 DEBUG("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
869 if (data[3] > 0x7F) {
870 data[3] = ~data[3] + 1;
871 *temperature = data[3];
872 *temperature = -*temperature;
873 } else {
874 *temperature = data[3];
875 }
877 *temperature += (double)(data[4]) / 256.0;
878 DEBUG("barometer: MPL3115_read - temperature = %lf C", *temperature);
880 return 0;
881 }
883 /**
884 * Initialize MPL3115 for barometeric measurements
885 *
886 * @return 0 if successful
887 */
888 static int MPL3115_init_sensor(void) {
889 __s32 res;
890 __s8 offset;
891 char errbuf[1024];
893 /* Reset the sensor. It will reset immediately without ACKing */
894 /* the transaction, so no error handling here. */
895 i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
896 MPL3115_CTRL_REG1_RST);
898 /* wait some time for the reset to finish */
899 usleep(100000);
901 /* now it should be in standby already so we can go and configure it */
903 /* Set temperature offset. */
904 /* result = ADCtemp + offset [C] */
905 offset = (__s8)(config_temp_offset * 16.0);
906 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
907 if (res < 0) {
908 ERROR("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
909 sstrerror(errno, errbuf, sizeof(errbuf)));
910 return -1;
911 }
913 /* Set pressure offset. */
914 /* result = ADCpress + offset [hPa] */
915 offset = (__s8)(config_press_offset * 100.0 / 4.0);
916 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
917 if (res < 0) {
918 ERROR(
919 "barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
920 sstrerror(errno, errbuf, sizeof(errbuf)));
921 return -1;
922 }
924 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
925 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_PT_DATA_CFG,
926 MPL3115_PT_DATA_DREM | MPL3115_PT_DATA_PDEF |
927 MPL3115_PT_DATA_TDEF);
928 if (res < 0) {
929 ERROR("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
930 sstrerror(errno, errbuf, sizeof(errbuf)));
931 return -1;
932 }
934 /* Set to barometer with an OSR */
935 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
936 mpl3115_oversample);
937 if (res < 0) {
938 ERROR("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
939 sstrerror(errno, errbuf, sizeof(errbuf)));
940 return -1;
941 }
943 return 0;
944 }
946 /* ------------------------ BMP085 access ------------------------ */
948 /**
949 * Detect presence of a BMP085 pressure sensor by checking its ID register
950 *
951 * As a sideeffect will leave set I2C slave address.
952 *
953 * @return 1 if BMP085, 0 otherwise
954 */
955 static int BMP085_detect(void) {
956 __s32 res;
957 char errbuf[1024];
959 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0) {
960 ERROR("barometer: BMP085_detect - problem setting i2c slave address to "
961 "0x%02X: %s",
962 BMP085_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
963 return 0;
964 }
966 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
967 if (res == BMP085_CHIP_ID) {
968 DEBUG("barometer: BMP085_detect - positive detection");
970 /* get version */
971 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION);
972 if (res < 0) {
973 ERROR("barometer: BMP085_detect - problem checking chip version: %s",
974 sstrerror(errno, errbuf, sizeof(errbuf)));
975 return 0;
976 }
977 DEBUG("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
978 res & 0x0f, (res & 0xf0) >> 4);
979 return 1;
980 }
982 DEBUG("barometer: BMP085_detect - negative detection");
983 return 0;
984 }
986 /**
987 * Adjusts oversampling settings to values supported by BMP085
988 *
989 * BMP085 supports only 1,2,4 or 8 samples.
990 */
991 static void BMP085_adjust_oversampling(void) {
992 int new_val = 0;
994 if (config_oversample > 6) /* 8 */
995 {
996 new_val = 8;
997 bmp085_oversampling = 3;
998 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
999 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1000 } else if (config_oversample > 3) /* 4 */
1001 {
1002 new_val = 4;
1003 bmp085_oversampling = 2;
1004 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1005 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1006 } else if (config_oversample > 1) /* 2 */
1007 {
1008 new_val = 2;
1009 bmp085_oversampling = 1;
1010 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1011 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1012 } else /* 1 */
1013 {
1014 new_val = 1;
1015 bmp085_oversampling = 0;
1016 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1017 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1018 }
1020 DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from "
1021 "%d to %d",
1022 config_oversample, new_val);
1023 config_oversample = new_val;
1024 }
1026 /**
1027 * Read the BMP085 sensor conversion coefficients.
1028 *
1029 * These are (device specific) constants so we can read them just once.
1030 *
1031 * @return Zero when successful
1032 */
1033 static int BMP085_read_coeffs(void) {
1034 __s32 res;
1035 __u8 coeffs[BMP085_NUM_COEFFS];
1036 char errbuf[1024];
1038 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_COEFFS,
1039 BMP085_NUM_COEFFS, coeffs);
1040 if (res < 0) {
1041 ERROR("barometer: BMP085_read_coeffs - problem reading data: %s",
1042 sstrerror(errno, errbuf, sizeof(errbuf)));
1043 return -1;
1044 }
1046 bmp085_AC1 = ((int16_t)coeffs[0] << 8) | (int16_t)coeffs[1];
1047 bmp085_AC2 = ((int16_t)coeffs[2] << 8) | (int16_t)coeffs[3];
1048 bmp085_AC3 = ((int16_t)coeffs[4] << 8) | (int16_t)coeffs[5];
1049 bmp085_AC4 = ((uint16_t)coeffs[6] << 8) | (uint16_t)coeffs[7];
1050 bmp085_AC5 = ((uint16_t)coeffs[8] << 8) | (uint16_t)coeffs[9];
1051 bmp085_AC6 = ((uint16_t)coeffs[10] << 8) | (uint16_t)coeffs[11];
1052 bmp085_B1 = ((int16_t)coeffs[12] << 8) | (int16_t)coeffs[13];
1053 bmp085_B2 = ((int16_t)coeffs[14] << 8) | (int16_t)coeffs[15];
1054 bmp085_MB = ((int16_t)coeffs[16] << 8) | (int16_t)coeffs[17];
1055 bmp085_MC = ((int16_t)coeffs[18] << 8) | (int16_t)coeffs[19];
1056 bmp085_MD = ((int16_t)coeffs[20] << 8) | (int16_t)coeffs[21];
1058 DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"
1059 " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1060 bmp085_AC1, bmp085_AC2, bmp085_AC3, bmp085_AC4, bmp085_AC5, bmp085_AC6,
1061 bmp085_B1, bmp085_B2, bmp085_MB, bmp085_MC, bmp085_MD);
1063 return 0;
1064 }
1066 /**
1067 * Convert raw BMP085 adc values to real data using the sensor coefficients.
1068 *
1069 * @param adc_pressure adc pressure value to be converted
1070 * @param adc_temp adc temperature value to be converted
1071 * @param pressure computed real pressure
1072 * @param temperature computed real temperature
1073 */
1074 static void BMP085_convert_adc_to_real(long adc_pressure, long adc_temperature,
1075 double *pressure, double *temperature)
1077 {
1078 long X1, X2, X3;
1079 long B3, B5, B6;
1080 unsigned long B4, B7;
1082 long T;
1083 long P;
1085 /* calculate real temperature */
1086 X1 = ((adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1087 X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1089 /* B5, T */
1090 B5 = X1 + X2;
1091 T = (B5 + 8) >> 4;
1092 *temperature = (double)T * 0.1;
1094 /* calculate real pressure */
1095 /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept
1096 */
1098 /* B6, B3 */
1099 B6 = B5 - 4000;
1100 X1 = ((bmp085_B2 * ((B6 * B6) >> 12)) >> 11);
1101 X2 = (((long)bmp085_AC2 * B6) >> 11);
1102 X3 = X1 + X2;
1103 B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1105 /* B4 */
1106 X1 = (((long)bmp085_AC3 * B6) >> 13);
1107 X2 = (bmp085_B1 * ((B6 * B6) >> 12)) >> 16;
1108 X3 = ((X1 + X2) + 2) >> 2;
1109 B4 = ((long)bmp085_AC4 * (unsigned long)(X3 + 32768)) >> 15;
1111 /* B7, P */
1112 B7 = (unsigned long)(adc_pressure - B3) * (50000 >> bmp085_oversampling);
1113 if (B7 < 0x80000000) {
1114 P = (B7 << 1) / B4;
1115 } else {
1116 P = (B7 / B4) << 1;
1117 }
1118 X1 = (P >> 8) * (P >> 8);
1119 X1 = (X1 * 3038) >> 16;
1120 X2 = ((-7357) * P) >> 16;
1121 P = P + ((X1 + X2 + 3791) >> 4);
1123 *pressure = P / 100.0; // in [hPa]
1124 DEBUG("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C", *pressure,
1125 *temperature);
1126 }
1128 /**
1129 * Read compensated sensor measurements
1130 *
1131 * @param pressure averaged measured pressure
1132 * @param temperature averaged measured temperature
1133 *
1134 * @return Zero when successful
1135 */
1136 static int BMP085_read(double *pressure, double *temperature) {
1137 __s32 res;
1138 __u8 measBuff[3];
1140 long adc_pressure;
1141 long adc_temperature;
1143 char errbuf[1024];
1145 /* start conversion of temperature */
1146 res = i2c_smbus_write_byte_data(i2c_bus_fd, BMP085_ADDR_CTRL_REG,
1147 BMP085_CMD_CONVERT_TEMP);
1148 if (res < 0) {
1149 ERROR("barometer: BMP085_read - problem requesting temperature conversion: "
1150 "%s",
1151 sstrerror(errno, errbuf, sizeof(errbuf)));
1152 return 1;
1153 }
1155 usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1157 res =
1158 i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 2, measBuff);
1159 if (res < 0) {
1160 ERROR("barometer: BMP085_read - problem reading temperature data: %s",
1161 sstrerror(errno, errbuf, sizeof(errbuf)));
1162 return 1;
1163 }
1165 adc_temperature = ((unsigned short)measBuff[0] << 8) + measBuff[1];
1167 /* get presure */
1168 res = i2c_smbus_write_byte_data(i2c_bus_fd, BMP085_ADDR_CTRL_REG,
1169 bmp085_cmdCnvPress);
1170 if (res < 0) {
1171 ERROR("barometer: BMP085_read - problem requesting pressure conversion: %s",
1172 sstrerror(errno, errbuf, sizeof(errbuf)));
1173 return 1;
1174 }
1176 usleep(bmp085_timeCnvPress); /* wait for the conversion */
1178 res =
1179 i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 3, measBuff);
1180 if (res < 0) {
1181 ERROR("barometer: BMP085_read - problem reading pressure data: %s",
1182 sstrerror(errno, errbuf, sizeof(errbuf)));
1183 return 1;
1184 }
1186 adc_pressure = (long)((((ulong)measBuff[0] << 16) |
1187 ((ulong)measBuff[1] << 8) | (ulong)measBuff[2]) >>
1188 (8 - bmp085_oversampling));
1190 DEBUG("barometer: BMP085_read - raw pressure ADC value = %ld, "
1191 "raw temperature ADC value = %ld",
1192 adc_pressure, adc_temperature);
1194 BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure,
1195 temperature);
1197 return 0;
1198 }
1200 /* ------------------------ Sensor detection ------------------------ */
1201 /**
1202 * Detect presence of a supported sensor.
1203 *
1204 * As a sideeffect will leave set I2C slave address.
1205 * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1206 * first sensor beeing found.
1207 *
1208 * @return detected sensor type
1209 */
1210 static enum Sensor_type detect_sensor_type(void) {
1211 if (BMP085_detect())
1212 return Sensor_BMP085;
1214 else if (MPL3115_detect())
1215 return Sensor_MPL3115;
1217 else if (MPL115_detect())
1218 return Sensor_MPL115;
1220 return Sensor_none;
1221 }
1223 /* ------------------------ Common functionality ------------------------ */
1225 /**
1226 * Convert absolute pressure (in hPa) to mean sea level pressure
1227 *
1228 * Implemented methods are:
1229 * - MSLP_NONE - no converions, returns absolute pressure
1230 *
1231 * - MSLP_INTERNATIONAL - see
1232 * http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1233 * Requires #config_altitude
1234 *
1235 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1236 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1237 * Requires both #config_altitude and temperature reference(s).
1238 *
1239 * @param abs_pressure absloute pressure to be converted
1240 *
1241 * @return mean sea level pressure if successful, NAN otherwise
1242 */
1243 static double abs_to_mean_sea_level_pressure(double abs_pressure) {
1244 double mean = -1.0;
1245 double temp = 0.0;
1246 int result = 0;
1248 if (config_normalize >= MSLP_DEU_WETT) {
1249 result = get_reference_temperature(&temp);
1250 if (result) {
1251 return NAN;
1252 }
1253 }
1255 switch (config_normalize) {
1256 case MSLP_NONE:
1257 mean = abs_pressure;
1258 break;
1260 case MSLP_INTERNATIONAL:
1261 mean = abs_pressure / pow(1.0 - 0.0065 * config_altitude / 288.15,
1262 9.80665 * 0.0289644 / (8.31447 * 0.0065));
1263 break;
1265 case MSLP_DEU_WETT: {
1266 double E; /* humidity */
1267 double x;
1268 if (temp < 9.1)
1269 E = 5.6402 * (-0.0916 + exp(0.06 * temp));
1270 else
1271 E = 18.2194 * (1.0463 - exp(-0.0666 * temp));
1272 x = 9.80665 /
1273 (287.05 * (temp + 273.15 + 0.12 * E + 0.0065 * config_altitude / 2)) *
1274 config_altitude;
1275 mean = abs_pressure * exp(x);
1276 } break;
1278 default:
1279 ERROR(
1280 "barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1281 config_normalize);
1282 mean = abs_pressure;
1283 break;
1284 }
1286 DEBUG("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, "
1287 "method = %d, meanPressure = %lf hPa",
1288 abs_pressure, config_normalize, mean);
1290 return mean;
1291 }
1293 /* ------------------------ main plugin callbacks ------------------------ */
1295 /**
1296 * Main plugin configuration callback (using simple config)
1297 *
1298 * @param key configuration key we should process
1299 * @param value configuration value we should process
1300 *
1301 * @return Zero when successful.
1302 */
1303 static int collectd_barometer_config(const char *key, const char *value) {
1304 DEBUG("barometer: collectd_barometer_config");
1306 if (strcasecmp(key, "Device") == 0) {
1307 sfree(config_device);
1308 config_device = strdup(value);
1309 } else if (strcasecmp(key, "Oversampling") == 0) {
1310 int oversampling_tmp = atoi(value);
1311 if (oversampling_tmp < 1 || oversampling_tmp > 1024) {
1312 WARNING("barometer: collectd_barometer_config: invalid oversampling: %d."
1313 " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for "
1314 "MPL3115) or 1 to 8 (for BMP085).",
1315 oversampling_tmp);
1316 return 1;
1317 }
1318 config_oversample = oversampling_tmp;
1319 } else if (strcasecmp(key, "Altitude") == 0) {
1320 config_altitude = atof(value);
1321 } else if (strcasecmp(key, "Normalization") == 0) {
1322 int normalize_tmp = atoi(value);
1323 if (normalize_tmp < 0 || normalize_tmp > 2) {
1324 WARNING("barometer: collectd_barometer_config: invalid normalization: %d",
1325 normalize_tmp);
1326 return 1;
1327 }
1328 config_normalize = normalize_tmp;
1329 } else if (strcasecmp(key, "TemperatureSensor") == 0) {
1330 if (temp_list_add(temp_list, value)) {
1331 return -1;
1332 }
1333 } else if (strcasecmp(key, "PressureOffset") == 0) {
1334 config_press_offset = atof(value);
1335 } else if (strcasecmp(key, "TemperatureOffset") == 0) {
1336 config_temp_offset = atof(value);
1337 } else {
1338 return -1;
1339 }
1341 return 0;
1342 }
1344 /**
1345 * Shutdown callback.
1346 *
1347 * Close I2C and delete all the buffers.
1348 *
1349 * @return Zero when successful (at the moment the only possible outcome)
1350 */
1351 static int collectd_barometer_shutdown(void) {
1352 DEBUG("barometer: collectd_barometer_shutdown");
1354 if (sensor_type == Sensor_MPL115) {
1355 averaging_delete(&pressure_averaging);
1356 averaging_delete(&temperature_averaging);
1358 temp_list_delete(&temp_list);
1359 }
1361 if (i2c_bus_fd > 0) {
1362 close(i2c_bus_fd);
1363 i2c_bus_fd = -1;
1364 sfree(config_device);
1365 }
1367 return 0;
1368 }
1370 /**
1371 * Plugin read callback for MPL115.
1372 *
1373 * Dispatching will create values:
1374 * - <hostname>/barometer-mpl115/pressure-normalized
1375 * - <hostname>/barometer-mpl115/pressure-absolute
1376 * - <hostname>/barometer-mpl115/temperature
1377 *
1378 * @return Zero when successful.
1379 */
1380 static int MPL115_collectd_barometer_read(void) {
1381 int result = 0;
1383 double pressure = 0.0;
1384 double temperature = 0.0;
1385 double norm_pressure = 0.0;
1387 value_list_t vl = VALUE_LIST_INIT;
1388 value_t values[1];
1390 DEBUG("barometer: MPL115_collectd_barometer_read");
1392 if (!configured) {
1393 return -1;
1394 }
1396 /* Rather than delaying init, we will intitialize during first read. This
1397 way at least we have a better chance to have the reference temperature
1398 already available. */
1399 if (!avg_initialized) {
1400 for (int i = 0; i < config_oversample - 1; ++i) {
1401 result = MPL115_read_averaged(&pressure, &temperature);
1402 if (result) {
1403 ERROR("barometer: MPL115_collectd_barometer_read - mpl115 read, "
1404 "ignored during init");
1405 }
1406 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i + 1,
1407 config_oversample - 1);
1408 usleep(20000);
1409 }
1410 avg_initialized = 1;
1411 }
1413 result = MPL115_read_averaged(&pressure, &temperature);
1414 if (result)
1415 return result;
1417 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1419 sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1420 sstrncpy(vl.plugin_instance, "mpl115", sizeof(vl.plugin_instance));
1422 vl.values_len = 1;
1423 vl.values = values;
1425 /* dispatch normalized air pressure */
1426 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1427 sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1428 values[0].gauge = norm_pressure;
1429 plugin_dispatch_values(&vl);
1431 /* dispatch absolute air pressure */
1432 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1433 sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1434 values[0].gauge = pressure;
1435 plugin_dispatch_values(&vl);
1437 /* dispatch sensor temperature */
1438 sstrncpy(vl.type, "temperature", sizeof(vl.type));
1439 sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1440 values[0].gauge = temperature;
1441 plugin_dispatch_values(&vl);
1443 return 0;
1444 }
1446 /**
1447 * Plugin read callback for MPL3115.
1448 *
1449 * Dispatching will create values:
1450 * - <hostname>/barometer-mpl3115/pressure-normalized
1451 * - <hostname>/barometer-mpl3115/pressure-absolute
1452 * - <hostname>/barometer-mpl3115/temperature
1453 *
1454 * @return Zero when successful.
1455 */
1456 static int MPL3115_collectd_barometer_read(void) {
1457 int result = 0;
1459 double pressure = 0.0;
1460 double temperature = 0.0;
1461 double norm_pressure = 0.0;
1463 value_list_t vl = VALUE_LIST_INIT;
1464 value_t values[1];
1466 DEBUG("barometer: MPL3115_collectd_barometer_read");
1468 if (!configured) {
1469 return -1;
1470 }
1472 result = MPL3115_read(&pressure, &temperature);
1473 if (result)
1474 return result;
1476 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1478 sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1479 sstrncpy(vl.plugin_instance, "mpl3115", sizeof(vl.plugin_instance));
1481 vl.values_len = 1;
1482 vl.values = values;
1484 /* dispatch normalized air pressure */
1485 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1486 sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1487 values[0].gauge = norm_pressure;
1488 plugin_dispatch_values(&vl);
1490 /* dispatch absolute air pressure */
1491 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1492 sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1493 values[0].gauge = pressure;
1494 plugin_dispatch_values(&vl);
1496 /* dispatch sensor temperature */
1497 sstrncpy(vl.type, "temperature", sizeof(vl.type));
1498 sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1499 values[0].gauge = temperature;
1500 plugin_dispatch_values(&vl);
1502 return 0;
1503 }
1505 /**
1506 * Plugin read callback for BMP085.
1507 *
1508 * Dispatching will create values:
1509 * - <hostname>/barometer-bmp085/pressure-normalized
1510 * - <hostname>/barometer-bmp085/pressure-absolute
1511 * - <hostname>/barometer-bmp085/temperature
1512 *
1513 * @return Zero when successful.
1514 */
1515 static int BMP085_collectd_barometer_read(void) {
1516 int result = 0;
1518 double pressure = 0.0;
1519 double temperature = 0.0;
1520 double norm_pressure = 0.0;
1522 value_list_t vl = VALUE_LIST_INIT;
1523 value_t values[1];
1525 DEBUG("barometer: BMP085_collectd_barometer_read");
1527 if (!configured) {
1528 return -1;
1529 }
1531 result = BMP085_read(&pressure, &temperature);
1532 if (result)
1533 return result;
1535 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1537 sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1538 sstrncpy(vl.plugin_instance, "bmp085", sizeof(vl.plugin_instance));
1540 vl.values_len = 1;
1541 vl.values = values;
1543 /* dispatch normalized air pressure */
1544 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1545 sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1546 values[0].gauge = norm_pressure;
1547 plugin_dispatch_values(&vl);
1549 /* dispatch absolute air pressure */
1550 sstrncpy(vl.type, "pressure", sizeof(vl.type));
1551 sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1552 values[0].gauge = pressure;
1553 plugin_dispatch_values(&vl);
1555 /* dispatch sensor temperature */
1556 sstrncpy(vl.type, "temperature", sizeof(vl.type));
1557 sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1558 values[0].gauge = temperature;
1559 plugin_dispatch_values(&vl);
1561 return 0;
1562 }
1564 /**
1565 * Initialization callback
1566 *
1567 * Check config, initialize I2C bus access, conversion coefficients and
1568 * averaging
1569 * ring buffers
1570 *
1571 * @return Zero when successful.
1572 */
1573 static int collectd_barometer_init(void) {
1574 char errbuf[1024];
1576 DEBUG("barometer: collectd_barometer_init");
1578 if (config_device == NULL) {
1579 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1580 return -1;
1581 }
1583 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude)) {
1584 ERROR("barometer: collectd_barometer_init no altitude configured "
1585 "for mean sea level pressure normalization.");
1586 return -1;
1587 }
1589 if (config_normalize == MSLP_DEU_WETT && temp_list == NULL) {
1590 ERROR("barometer: collectd_barometer_init no temperature reference "
1591 "configured for mean sea level pressure normalization.");
1592 return -1;
1593 }
1595 i2c_bus_fd = open(config_device, O_RDWR);
1596 if (i2c_bus_fd < 0) {
1597 ERROR("barometer: collectd_barometer_init problem opening I2C bus device "
1598 "\"%s\": %s (is loaded mod i2c-dev?)",
1599 config_device, sstrerror(errno, errbuf, sizeof(errbuf)));
1600 return -1;
1601 }
1603 /* detect sensor type - this will also set slave address */
1604 sensor_type = detect_sensor_type();
1606 /* init correct sensor type */
1607 switch (sensor_type) {
1608 /* MPL3115 */
1609 case Sensor_MPL3115: {
1610 MPL3115_adjust_oversampling();
1612 if (MPL3115_init_sensor())
1613 return -1;
1615 plugin_register_read("barometer", MPL3115_collectd_barometer_read);
1616 } break;
1618 /* MPL115 */
1619 case Sensor_MPL115: {
1620 if (averaging_create(&pressure_averaging, config_oversample)) {
1621 ERROR(
1622 "barometer: collectd_barometer_init pressure averaging init failed");
1623 return -1;
1624 }
1626 if (averaging_create(&temperature_averaging, config_oversample)) {
1627 ERROR("barometer: collectd_barometer_init temperature averaging init "
1628 "failed");
1629 return -1;
1630 }
1632 if (MPL115_read_coeffs() < 0)
1633 return -1;
1635 plugin_register_read("barometer", MPL115_collectd_barometer_read);
1636 } break;
1638 /* BMP085 */
1639 case Sensor_BMP085: {
1640 BMP085_adjust_oversampling();
1642 if (BMP085_read_coeffs() < 0)
1643 return -1;
1645 plugin_register_read("barometer", BMP085_collectd_barometer_read);
1646 } break;
1648 /* anything else -> error */
1649 default:
1650 ERROR("barometer: collectd_barometer_init - no supported sensor found");
1651 return -1;
1652 }
1654 configured = 1;
1655 return 0;
1656 }
1658 /* ------------------------ plugin register / entry point
1659 * ------------------------ */
1661 /**
1662 * Plugin "entry" - register all callback.
1663 *
1664 */
1665 void module_register(void) {
1666 plugin_register_config("barometer", collectd_barometer_config, config_keys,
1667 config_keys_num);
1668 plugin_register_init("barometer", collectd_barometer_init);
1669 plugin_register_shutdown("barometer", collectd_barometer_shutdown);
1670 }