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"
23 #include "common.h"
24 #include "utils_cache.h"
25 #include "plugin.h"
27 #include <stdint.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <linux/i2c-dev.h>
31 #include <math.h>
33 /* ------------ MPL115 defines ------------ */
34 /* I2C address of the MPL115 sensor */
35 #define MPL115_I2C_ADDRESS 0x60
37 /* register addresses */
38 #define MPL115_ADDR_CONV 0x00
39 #define MPL115_ADDR_COEFFS 0x04
41 /* register sizes */
42 #define MPL115_NUM_CONV 4
43 #define MPL115_NUM_COEFFS 12
45 /* commands / addresses */
46 #define MPL115_CMD_CONVERT_PRESS 0x10
47 #define MPL115_CMD_CONVERT_TEMP 0x11
48 #define MPL115_CMD_CONVERT_BOTH 0x12
50 #define MPL115_CONVERSION_RETRIES 5
53 /* ------------ MPL3115 defines ------------ */
54 /* MPL3115 I2C address */
55 #define MPL3115_I2C_ADDRESS 0x60
57 /* register addresses (only the interesting ones) */
58 #define MPL3115_REG_STATUS 0x00
59 #define MPL3115_REG_OUT_P_MSB 0x01
60 #define MPL3115_REG_OUT_P_CSB 0x02
61 #define MPL3115_REG_OUT_P_LSB 0x03
62 #define MPL3115_REG_OUT_T_MSB 0x04
63 #define MPL3115_REG_OUT_T_LSB 0x05
64 #define MPL3115_REG_DR_STATUS 0x06
65 #define MPL3115_REG_WHO_AM_I 0x0C
66 #define MPL3115_REG_SYSMOD 0x11
67 #define MPL3115_REG_PT_DATA_CFG 0x13
68 #define MPL3115_REG_BAR_IN_MSB 0x14
69 #define MPL3115_REG_BAR_IN_LSB 0x15
70 #define MPL3115_REG_CTRL_REG1 0x26
71 #define MPL3115_REG_CTRL_REG2 0x27
72 #define MPL3115_REG_CTRL_REG3 0x28
73 #define MPL3115_REG_CTRL_REG4 0x29
74 #define MPL3115_REG_CTRL_REG5 0x2A
75 #define MPL3115_REG_OFF_P 0x2B
76 #define MPL3115_REG_OFF_T 0x2C
77 #define MPL3115_REG_OFF_H 0x2D
79 /* Register values, masks */
80 #define MPL3115_WHO_AM_I_RESP 0xC4
82 #define MPL3115_PT_DATA_DREM 0x04
83 #define MPL3115_PT_DATA_PDEF 0x02
84 #define MPL3115_PT_DATA_TDEF 0x01
86 #define MPL3115_DR_STATUS_TDR 0x02
87 #define MPL3115_DR_STATUS_PDR 0x04
88 #define MPL3115_DR_STATUS_PTDR 0x08
89 #define MPL3115_DR_STATUS_DR (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
91 #define MPL3115_DR_STATUS_TOW 0x20
92 #define MPL3115_DR_STATUS_POW 0x40
93 #define MPL3115_DR_STATUS_PTOW 0x80
95 #define MPL3115_CTRL_REG1_ALT 0x80
96 #define MPL3115_CTRL_REG1_RAW 0x40
97 #define MPL3115_CTRL_REG1_OST_MASK 0x38
98 #define MPL3115_CTRL_REG1_OST_1 0x00
99 #define MPL3115_CTRL_REG1_OST_2 0x08
100 #define MPL3115_CTRL_REG1_OST_4 0x10
101 #define MPL3115_CTRL_REG1_OST_8 0x18
102 #define MPL3115_CTRL_REG1_OST_16 0x20
103 #define MPL3115_CTRL_REG1_OST_32 0x28
104 #define MPL3115_CTRL_REG1_OST_64 0x30
105 #define MPL3115_CTRL_REG1_OST_128 0x38
106 #define MPL3115_CTRL_REG1_RST 0x04
107 #define MPL3115_CTRL_REG1_OST 0x02
108 #define MPL3115_CTRL_REG1_SBYB 0x01
109 #define MPL3115_CTRL_REG1_SBYB_MASK 0xFE
111 #define MPL3115_NUM_CONV_VALS 5
114 /* ------------ BMP085 defines ------------ */
115 /* I2C address of the BMP085 sensor */
116 #define BMP085_I2C_ADDRESS 0x77
118 /* register addresses */
119 #define BMP085_ADDR_ID_REG 0xD0
120 #define BMP085_ADDR_VERSION 0xD1
122 #define BMP085_ADDR_CONV 0xF6
124 #define BMP085_ADDR_CTRL_REG 0xF4
125 #define BMP085_ADDR_COEFFS 0xAA
127 /* register sizes */
128 #define BMP085_NUM_COEFFS 22
130 /* commands, values */
131 #define BMP085_CHIP_ID 0x55
133 #define BMP085_CMD_CONVERT_TEMP 0x2E
135 #define BMP085_CMD_CONVERT_PRESS_0 0x34
136 #define BMP085_CMD_CONVERT_PRESS_1 0x74
137 #define BMP085_CMD_CONVERT_PRESS_2 0xB4
138 #define BMP085_CMD_CONVERT_PRESS_3 0xF4
140 /* in us */
141 #define BMP085_TIME_CNV_TEMP 4500
143 #define BMP085_TIME_CNV_PRESS_0 4500
144 #define BMP085_TIME_CNV_PRESS_1 7500
145 #define BMP085_TIME_CNV_PRESS_2 13500
146 #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 #get_reference_temperature */
156 #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 {
171 "Device",
172 "Oversampling",
173 "PressureOffset", /**< only for MPL3115 */
174 "TemperatureOffset", /**< only for MPL3115 */
175 "Altitude",
176 "Normalization",
177 "TemperatureSensor"
178 };
180 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
182 static char * config_device = NULL; /**< I2C bus device */
183 static int config_oversample = 1; /**< averaging window */
185 static double config_press_offset = 0.0; /**< pressure offset */
186 static double config_temp_offset = 0.0; /**< temperature offset */
188 static double config_altitude = NAN; /**< altitude */
189 static int config_normalize = 0; /**< normalization method */
191 static _Bool configured = 0; /**< the whole plugin config status */
193 static int i2c_bus_fd = -1; /**< I2C bus device FD */
195 static enum Sensor_type sensor_type = Sensor_none; /**< detected/used sensor type */
197 static __s32 mpl3115_oversample = 0; /**< MPL3115 CTRL1 oversample setting */
199 // BMP085 configuration
200 static unsigned bmp085_oversampling; /**< BMP085 oversampling (0-3) */
201 static unsigned long bmp085_timeCnvPress; /**< BMP085 conversion time for pressure in us */
202 static __u8 bmp085_cmdCnvPress; /**< BMP085 pressure conversion command */
205 /* MPL115 conversion coefficients */
206 static double mpl115_coeffA0;
207 static double mpl115_coeffB1;
208 static double mpl115_coeffB2;
209 static double mpl115_coeffC12;
210 static double mpl115_coeffC11;
211 static double mpl115_coeffC22;
213 /* BMP085 conversion coefficients */
214 static short bmp085_AC1;
215 static short bmp085_AC2;
216 static short bmp085_AC3;
217 static unsigned short bmp085_AC4;
218 static unsigned short bmp085_AC5;
219 static unsigned short bmp085_AC6;
220 static short bmp085_B1;
221 static short bmp085_B2;
222 static short bmp085_MB;
223 static short bmp085_MC;
224 static short bmp085_MD;
228 /* ------------------------ averaging ring buffer ------------------------ */
229 /* Used only for MPL115. MPL3115 supports real oversampling in the device so */
230 /* no need for any postprocessing. */
232 static _Bool avg_initialized = 0; /**< already initialized by real values */
234 typedef struct averaging_s {
235 long int * ring_buffer;
236 int ring_buffer_size;
237 long int ring_buffer_sum;
238 int ring_buffer_head;
239 } averaging_t;
242 static averaging_t pressure_averaging = { NULL, 0, 0L, 0 };
243 static averaging_t temperature_averaging = { NULL, 0, 0L, 0 };
246 /**
247 * Create / allocate averaging buffer
248 *
249 * The buffer is initialized with zeros.
250 *
251 * @param avg pointer to ring buffer to be allocated
252 * @param size requested buffer size
253 *
254 * @return Zero when successful
255 */
256 static int averaging_create(averaging_t *avg, int size)
257 {
258 avg->ring_buffer = calloc ((size_t) size, sizeof (*avg->ring_buffer));
259 if (avg->ring_buffer == NULL)
260 {
261 ERROR ("barometer: averaging_create - ring buffer allocation of size %d failed",
262 size);
263 return -1;
264 }
266 avg->ring_buffer_size = size;
267 avg->ring_buffer_sum = 0L;
268 avg->ring_buffer_head = 0;
270 return 0;
271 }
274 /**
275 * Delete / free existing averaging buffer
276 *
277 * @param avg pointer to the ring buffer to be deleted
278 */
279 static void averaging_delete(averaging_t * avg)
280 {
281 if (avg->ring_buffer != NULL)
282 {
283 free(avg->ring_buffer);
284 avg->ring_buffer = NULL;
285 }
286 avg->ring_buffer_size = 0;
287 avg->ring_buffer_sum = 0L;
288 avg->ring_buffer_head = 0;
289 }
292 /*
293 * Add new sample to the averaging buffer
294 *
295 * A new averaged value is returned. Note that till the buffer is full
296 * returned value is inaccurate as it is an average of real values and initial
297 * zeros.
298 *
299 * @param avg pointer to the ring buffer
300 * @param sample new sample value
301 *
302 * @return Averaged sample value
303 */
304 static double averaging_add_sample(averaging_t * avg, long int sample)
305 {
306 double result;
308 avg->ring_buffer_sum += sample - avg->ring_buffer[avg->ring_buffer_head];
309 avg->ring_buffer[avg->ring_buffer_head] = sample;
310 avg->ring_buffer_head = (avg->ring_buffer_head+1) % avg->ring_buffer_size;
311 result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
313 DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
314 sample,
315 result);
317 return result;
318 }
321 /* ------------------------ temperature refference ------------------------ */
323 /**
324 * Linked list type of temperature sensor references
325 */
326 typedef struct temperature_list_s {
327 char * sensor_name; /**< sensor name/reference */
328 size_t num_values; /**< number of values (usually one) */
329 _Bool initialized; /**< sensor already provides data */
330 struct temperature_list_s * next; /**< next in the list */
331 } temperature_list_t;
333 static temperature_list_t * temp_list = NULL;
336 /*
337 * Add new sensor to the temperature reference list
338 *
339 * @param list the list
340 * @param sensor reference name (as provided by the config file)
341 *
342 * @return Zero when successful
343 */
344 static int temp_list_add(temperature_list_t * list, const char * sensor)
345 {
346 temperature_list_t *new_temp;
348 new_temp = malloc(sizeof (*new_temp));
349 if(new_temp == NULL)
350 return -1;
352 new_temp->sensor_name = strdup(sensor);
353 new_temp->initialized = 0;
354 new_temp->num_values = 0;
355 if(new_temp->sensor_name == NULL)
356 {
357 free(new_temp);
358 return -1;
359 }
361 new_temp->next = temp_list;
362 temp_list = new_temp;
363 return 0;
364 }
367 /*
368 * Delete the whole temperature reference list
369 *
370 * @param list the list to be deleted
371 */
372 static void temp_list_delete(temperature_list_t ** list)
373 {
374 temperature_list_t * tmp;
376 while (*list != NULL)
377 {
378 tmp = (*list);
379 (*list) = (*list)->next;
380 free(tmp->sensor_name);
381 free(tmp);
382 tmp = NULL;
383 }
384 }
387 /*
388 * Get reference temperature value
389 *
390 * First initially uc_get_rate_by_name is tried. At the startup due to nondeterministic
391 * order the temperature may not be read yet (then it fails and first measurment gives
392 * only absolute air pressure reading which is acceptable). Once it succedes (should be
393 * second measurement at the latest) we use average of few last readings from
394 * uc_get_history_by_name. It may take few readings to start filling so again we use
395 * uc_get_rate_by_name as a fallback.
396 * The idea is to use basic "noise" filtering (history averaging) across all the values
397 * which given sensor provides (up to given depth). Then we get minimum among
398 * the sensors.
399 *
400 * @param result where the result is stored. When not available NAN is stored.
401 *
402 * @return Zero when successful
403 */
404 static int get_reference_temperature(double * result)
405 {
406 temperature_list_t * list = temp_list;
408 gauge_t * values = NULL; /**< rate values */
409 size_t values_num = 0; /**< number of rate values */
410 size_t i;
412 gauge_t values_history[REF_TEMP_AVG_NUM];
414 double avg_sum; /**< Value sum for computing average */
415 int avg_num; /**< Number of values for computing average */
416 double average; /**< Resulting value average */
418 *result = NAN;
420 while(list != NULL)
421 {
422 avg_sum = 0.0;
423 avg_num = 0;
425 /* First time need to read current rate to learn how many values are
426 there (typically for temperature it would be just one).
427 We do not expect dynamic changing of number of temperarure values
428 in runtime yet (are there any such cases?). */
429 if(!list->initialized)
430 {
431 if(uc_get_rate_by_name(list->sensor_name,
432 &values,
433 &values_num))
434 {
435 DEBUG ("barometer: get_reference_temperature - rate \"%s\" not found yet",
436 list->sensor_name);
437 list = list->next;
438 continue;
439 }
441 DEBUG ("barometer: get_reference_temperature - initialize \"%s\", %zu vals",
442 list->sensor_name,
443 values_num);
445 list->initialized = 1;
446 list->num_values = values_num;
448 for(i=0; i<values_num; ++i)
449 {
450 DEBUG ("barometer: get_reference_temperature - rate %zu: %lf **",
451 i, values[i]);
452 if(!isnan(values[i]))
453 {
454 avg_sum += values[i];
455 ++avg_num;
456 }
457 }
458 free(values);
459 values = NULL;
460 }
462 /* It is OK to get here the first time as well, in the worst case
463 the history will full of NANs. */
464 if(uc_get_history_by_name(list->sensor_name,
465 values_history,
466 REF_TEMP_AVG_NUM,
467 list->num_values))
468 {
469 ERROR ("barometer: get_reference_temperature - history \"%s\" lost",
470 list->sensor_name);
471 list->initialized = 0;
472 list->num_values = 0;
473 list = list->next;
474 continue;
475 }
477 for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
478 {
479 DEBUG ("barometer: get_reference_temperature - history %zu: %lf",
480 i, values_history[i]);
481 if(!isnan(values_history[i]))
482 {
483 avg_sum += values_history[i];
484 ++avg_num;
485 }
486 }
488 if(avg_num == 0) /* still no history? fallback to current */
489 {
490 if(uc_get_rate_by_name(list->sensor_name,
491 &values,
492 &values_num))
493 {
494 ERROR ("barometer: get_reference_temperature - rate \"%s\" lost",
495 list->sensor_name);
496 list->initialized = 0;
497 list->num_values = 0;
498 list = list->next;
499 continue;
500 }
502 for(i=0; i<values_num; ++i)
503 {
504 DEBUG ("barometer: get_reference_temperature - rate last %zu: %lf **",
505 i, values[i]);
506 if(!isnan(values[i]))
507 {
508 avg_sum += values[i];
509 ++avg_num;
510 }
511 }
512 free(values);
513 values = NULL;
514 }
516 if(avg_num == 0)
517 {
518 ERROR ("barometer: get_reference_temperature - could not read \"%s\"",
519 list->sensor_name);
520 list->initialized = 0;
521 list->num_values = 0;
522 }
523 else
524 {
525 average = avg_sum / (double) avg_num;
526 if(isnan(*result))
527 *result=average;
528 else if(*result>average)
529 *result=average;
530 }
531 list = list->next;
532 } /* while sensor list */
534 if(*result == NAN)
535 {
536 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
537 return -1;
538 }
539 DEBUG ("barometer: get_reference_temperature - temp is %lf", *result);
540 return 0;
541 }
544 /* ------------------------ MPL115 access ------------------------ */
546 /**
547 * Detect presence of a MPL115 pressure sensor.
548 *
549 * Unfortunately there seems to be no ID register so we just try to read first
550 * conversion coefficient from device at MPL115 address and hope it is really
551 * MPL115. We should use this check as the last resort (which would be the typical
552 * case anyway since MPL115 is the least accurate sensor).
553 * As a sideeffect will leave set I2C slave address.
554 *
555 * @return 1 if MPL115, 0 otherwise
556 */
557 static int MPL115_detect(void)
558 {
559 __s32 res;
560 char errbuf[1024];
562 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
563 {
564 ERROR("barometer: MPL115_detect problem setting i2c slave address to 0x%02X: %s",
565 MPL115_I2C_ADDRESS,
566 sstrerror (errno, errbuf, sizeof (errbuf)));
567 return 0 ;
568 }
570 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
571 if(res >= 0)
572 {
573 DEBUG ("barometer: MPL115_detect - positive detection");
574 return 1;
575 }
577 DEBUG ("barometer: MPL115_detect - negative detection");
578 return 0;
579 }
581 /**
582 * Read the MPL115 sensor conversion coefficients.
583 *
584 * These are (device specific) constants so we can read them just once.
585 *
586 * @return Zero when successful
587 */
588 static int MPL115_read_coeffs(void)
589 {
590 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS] = { 0 };
591 int32_t res;
593 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
594 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
595 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
597 char errbuf[1024];
599 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
600 MPL115_ADDR_COEFFS,
601 STATIC_ARRAY_SIZE (mpl115_coeffs),
602 mpl115_coeffs);
603 if (res < 0)
604 {
605 ERROR ("barometer: MPL115_read_coeffs - problem reading data: %s",
606 sstrerror (errno, errbuf, sizeof (errbuf)));
607 return -1;
608 }
610 /* Using perhaps less elegant/efficient code, but more readable. */
611 /* a0: 16total 1sign 12int 4fract 0pad */
612 sia0MSB = mpl115_coeffs[0];
613 sia0LSB = mpl115_coeffs[1];
614 sia0 = (int16_t) sia0MSB <<8; /* s16 type, Shift to MSB */
615 sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
616 mpl115_coeffA0 = (double) (sia0);
617 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
619 /* b1: 16total 1sign 2int 13fract 0pad */
620 sib1MSB= mpl115_coeffs[2];
621 sib1LSB= mpl115_coeffs[3];
622 sib1 = sib1MSB <<8; /* Shift to MSB */
623 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
624 mpl115_coeffB1 = (double) (sib1);
625 mpl115_coeffB1 /= 8192.0; /* 13 fract */
627 /* b2: 16total 1sign 1int 14fract 0pad */
628 sib2MSB= mpl115_coeffs[4];
629 sib2LSB= mpl115_coeffs[5];
630 sib2 = sib2MSB <<8; /* Shift to MSB */
631 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
632 mpl115_coeffB2 = (double) (sib2);
633 mpl115_coeffB2 /= 16384.0; /* 14 fract */
635 /* c12: 14total 1sign 0int 13fract 9pad */
636 sic12MSB= mpl115_coeffs[6];
637 sic12LSB= mpl115_coeffs[7];
638 sic12 = sic12MSB <<8; /* Shift to MSB only by 8 for MSB */
639 sic12 += sic12LSB & 0x00FF;
640 mpl115_coeffC12 = (double) (sic12);
641 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
642 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
644 /* c11: 11total 1sign 0int 11fract 11pad */
645 sic11MSB= mpl115_coeffs[8];
646 sic11LSB= mpl115_coeffs[9];
647 sic11 = sic11MSB <<8; /* Shift to MSB only by 8 for MSB */
648 sic11 += sic11LSB & 0x00FF;
649 mpl115_coeffC11 = (double) (sic11);
650 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
651 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
653 /* c12: 11total 1sign 0int 10fract 15pad */
654 sic22MSB= mpl115_coeffs[10];
655 sic22LSB= mpl115_coeffs[11];
656 sic22 = sic22MSB <<8; /* Shift to MSB only by 8 for MSB */
657 sic22 += sic22LSB & 0x00FF;
658 mpl115_coeffC22 = (double) (sic22);
659 mpl115_coeffC22 /= 32.0; //16-11=5
660 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
662 DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
663 mpl115_coeffA0,
664 mpl115_coeffB1,
665 mpl115_coeffB2,
666 mpl115_coeffC12,
667 mpl115_coeffC11,
668 mpl115_coeffC22);
669 return 0;
670 }
673 /**
674 * Convert raw adc values to real data using the sensor coefficients.
675 *
676 * @param adc_pressure adc pressure value to be converted
677 * @param adc_temp adc temperature value to be converted
678 * @param pressure computed real pressure
679 * @param temperature computed real temperature
680 */
681 static void MPL115_convert_adc_to_real(double adc_pressure,
682 double adc_temp,
683 double * pressure,
684 double * temperature)
685 {
686 double Pcomp;
687 Pcomp = mpl115_coeffA0 + \
688 (mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
689 (mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
691 *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
692 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
693 DEBUG ("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C",
694 *pressure,
695 *temperature);
696 }
699 /**
700 * Read sensor averegaed measurements
701 *
702 * @param pressure averaged measured pressure
703 * @param temperature averaged measured temperature
704 *
705 * @return Zero when successful
706 */
707 static int MPL115_read_averaged(double * pressure, double * temperature)
708 {
709 uint8_t mpl115_conv[MPL115_NUM_CONV] = { 0 };
710 int8_t res;
711 int retries;
712 int conv_pressure;
713 int conv_temperature;
714 double adc_pressure;
715 double adc_temperature;
716 char errbuf[1024];
718 *pressure = 0.0;
719 *temperature = 0.0;
721 /* start conversion of both temp and presure */
722 retries = MPL115_CONVERSION_RETRIES;
723 while (retries>0)
724 {
725 /* write 1 to start conversion */
726 res = i2c_smbus_write_byte_data (i2c_bus_fd,
727 MPL115_CMD_CONVERT_BOTH,
728 0x01);
729 if (res >= 0)
730 break;
732 --retries;
733 if(retries>0)
734 {
735 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, " \
736 "will retry at most %d more times",
737 sstrerror (errno, errbuf, sizeof (errbuf)),
738 retries);
739 }
740 else
741 {
742 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, "\
743 "too many failed retries",
744 sstrerror (errno, errbuf, sizeof (errbuf)));
745 return -1;
746 }
747 }
749 usleep (10000); /* wait 10ms for the conversion */
751 retries=MPL115_CONVERSION_RETRIES;
752 while (retries>0)
753 {
754 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
755 MPL115_ADDR_CONV,
756 STATIC_ARRAY_SIZE (mpl115_conv),
757 mpl115_conv);
758 if (res >= 0)
759 break;
761 --retries;
762 if (retries>0)
763 {
764 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
765 "will retry at most %d more times",
766 sstrerror (errno, errbuf, sizeof (errbuf)),
767 retries);
768 }
769 else
770 {
771 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
772 "too many failed retries",
773 sstrerror (errno, errbuf, sizeof (errbuf)));
774 return -1;
775 }
776 }
778 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
779 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
780 DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
781 "raw temperature ADC value = %d",
782 conv_pressure,
783 conv_temperature);
785 adc_pressure = averaging_add_sample (&pressure_averaging, conv_pressure);
786 adc_temperature = averaging_add_sample (&temperature_averaging, conv_temperature);
788 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
790 DEBUG ("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / temperature = %lf, " \
791 "real pressure = %lf hPa / temperature = %lf C",
792 adc_pressure,
793 adc_temperature,
794 *pressure,
795 *temperature);
797 return 0;
798 }
800 /* ------------------------ MPL3115 access ------------------------ */
802 /**
803 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
804 *
805 * As a sideeffect will leave set I2C slave address.
806 *
807 * @return 1 if MPL3115, 0 otherwise
808 */
809 static int MPL3115_detect(void)
810 {
811 __s32 res;
812 char errbuf[1024];
814 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0)
815 {
816 ERROR("barometer: MPL3115_detect problem setting i2c slave address to 0x%02X: %s",
817 MPL3115_I2C_ADDRESS,
818 sstrerror (errno, errbuf, sizeof (errbuf)));
819 return 0 ;
820 }
822 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
823 if(res == MPL3115_WHO_AM_I_RESP)
824 {
825 DEBUG ("barometer: MPL3115_detect - positive detection");
826 return 1;
827 }
829 DEBUG ("barometer: MPL3115_detect - negative detection");
830 return 0;
831 }
833 /**
834 * Adjusts oversampling to values supported by MPL3115
835 *
836 * MPL3115 supports only power of 2 in the range 1 to 128.
837 */
838 static void MPL3115_adjust_oversampling(void)
839 {
840 int new_val = 0;
842 if(config_oversample > 100)
843 {
844 new_val = 128;
845 mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
846 }
847 else if(config_oversample > 48)
848 {
849 new_val = 64;
850 mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
851 }
852 else if(config_oversample > 24)
853 {
854 new_val = 32;
855 mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
856 }
857 else if(config_oversample > 12)
858 {
859 new_val = 16;
860 mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
861 }
862 else if(config_oversample > 6)
863 {
864 new_val = 8;
865 mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
866 }
867 else if(config_oversample > 3)
868 {
869 new_val = 4;
870 mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
871 }
872 else if(config_oversample > 1)
873 {
874 new_val = 2;
875 mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
876 }
877 else
878 {
879 new_val = 1;
880 mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
881 }
883 DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
884 config_oversample,
885 new_val);
886 config_oversample = new_val;
887 }
889 /**
890 * Read sensor averaged measurements
891 *
892 * @param pressure averaged measured pressure
893 * @param temperature averaged measured temperature
894 *
895 * @return Zero when successful
896 */
897 static int MPL3115_read(double * pressure, double * temperature)
898 {
899 __s32 res;
900 __s32 ctrl ;
901 __u8 data[MPL3115_NUM_CONV_VALS];
902 long int tmp_value = 0;
903 char errbuf[1024];
905 /* Set Active - activate the device from standby */
906 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
907 if (res < 0)
908 {
909 ERROR ("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
910 sstrerror (errno, errbuf, sizeof (errbuf)));
911 return 1;
912 }
913 ctrl = res;
914 res = i2c_smbus_write_byte_data(i2c_bus_fd,
915 MPL3115_REG_CTRL_REG1,
916 ctrl | MPL3115_CTRL_REG1_SBYB);
917 if (res < 0)
918 {
919 ERROR ("barometer: MPL3115_read - problem activating: %s",
920 sstrerror (errno, errbuf, sizeof (errbuf)));
921 return 1;
922 }
924 /* base sleep is 5ms x OST */
925 usleep(5000 * config_oversample);
927 /* check the flags/status if ready */
928 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
929 if (res < 0)
930 {
931 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
932 sstrerror (errno, errbuf, sizeof (errbuf)));
933 return 1;
934 }
936 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
937 {
938 /* try some extra sleep... */
939 usleep(10000);
941 /* ... and repeat the check. The conversion has to finish sooner or later. */
942 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
943 if (res < 0)
944 {
945 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
946 sstrerror (errno, errbuf, sizeof (errbuf)));
947 return 1;
948 }
949 }
951 /* Now read all the data in one block. There is address autoincrement. */
952 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
953 MPL3115_REG_OUT_P_MSB,
954 MPL3115_NUM_CONV_VALS,
955 data);
956 if (res < 0)
957 {
958 ERROR ("barometer: MPL3115_read - cannot read data registers: %s",
959 sstrerror (errno, errbuf, sizeof (errbuf)));
960 return 1;
961 }
963 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
964 *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
965 DEBUG ("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
967 if(data[3] > 0x7F)
968 {
969 data[3] = ~data[3] + 1;
970 *temperature = data[3];
971 *temperature = - *temperature;
972 }
973 else
974 {
975 *temperature = data[3];
976 }
978 *temperature += (double)(data[4]) / 256.0;
979 DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
981 return 0;
982 }
984 /**
985 * Initialize MPL3115 for barometeric measurements
986 *
987 * @return 0 if successful
988 */
989 static int MPL3115_init_sensor(void)
990 {
991 __s32 res;
992 __s8 offset;
993 char errbuf[1024];
995 /* Reset the sensor. It will reset immediately without ACKing */
996 /* the transaction, so no error handling here. */
997 i2c_smbus_write_byte_data(i2c_bus_fd,
998 MPL3115_REG_CTRL_REG1,
999 MPL3115_CTRL_REG1_RST);
1001 /* wait some time for the reset to finish */
1002 usleep(100000);
1004 /* now it should be in standby already so we can go and configure it */
1006 /* Set temperature offset. */
1007 /* result = ADCtemp + offset [C] */
1008 offset = (__s8) (config_temp_offset * 16.0);
1009 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
1010 if (res < 0)
1011 {
1012 ERROR ("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
1013 sstrerror (errno, errbuf, sizeof (errbuf)));
1014 return -1;
1015 }
1017 /* Set pressure offset. */
1018 /* result = ADCpress + offset [hPa] */
1019 offset = (__s8) (config_press_offset * 100.0 / 4.0);
1020 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
1021 if (res < 0)
1022 {
1023 ERROR ("barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
1024 sstrerror (errno, errbuf, sizeof (errbuf)));
1025 return -1;
1026 }
1028 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
1029 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1030 MPL3115_REG_PT_DATA_CFG,
1031 MPL3115_PT_DATA_DREM \
1032 | MPL3115_PT_DATA_PDEF \
1033 | MPL3115_PT_DATA_TDEF);
1034 if (res < 0)
1035 {
1036 ERROR ("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
1037 sstrerror (errno, errbuf, sizeof (errbuf)));
1038 return -1;
1039 }
1041 /* Set to barometer with an OSR */
1042 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1043 MPL3115_REG_CTRL_REG1,
1044 mpl3115_oversample);
1045 if (res < 0)
1046 {
1047 ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
1048 sstrerror (errno, errbuf, sizeof (errbuf)));
1049 return -1;
1050 }
1052 return 0;
1053 }
1055 /* ------------------------ BMP085 access ------------------------ */
1057 /**
1058 * Detect presence of a BMP085 pressure sensor by checking its ID register
1059 *
1060 * As a sideeffect will leave set I2C slave address.
1061 *
1062 * @return 1 if BMP085, 0 otherwise
1063 */
1064 static int BMP085_detect(void)
1065 {
1066 __s32 res;
1067 char errbuf[1024];
1069 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0)
1070 {
1071 ERROR("barometer: BMP085_detect - problem setting i2c slave address to 0x%02X: %s",
1072 BMP085_I2C_ADDRESS,
1073 sstrerror (errno, errbuf, sizeof (errbuf)));
1074 return 0 ;
1075 }
1077 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
1078 if(res == BMP085_CHIP_ID)
1079 {
1080 DEBUG ("barometer: BMP085_detect - positive detection");
1082 /* get version */
1083 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION );
1084 if (res < 0)
1085 {
1086 ERROR("barometer: BMP085_detect - problem checking chip version: %s",
1087 sstrerror (errno, errbuf, sizeof (errbuf)));
1088 return 0 ;
1089 }
1090 DEBUG ("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
1091 res & 0x0f,
1092 (res & 0xf0) >> 4);
1093 return 1;
1094 }
1096 DEBUG ("barometer: BMP085_detect - negative detection");
1097 return 0;
1098 }
1101 /**
1102 * Adjusts oversampling settings to values supported by BMP085
1103 *
1104 * BMP085 supports only 1,2,4 or 8 samples.
1105 */
1106 static void BMP085_adjust_oversampling(void)
1107 {
1108 int new_val = 0;
1110 if( config_oversample > 6 ) /* 8 */
1111 {
1112 new_val = 8;
1113 bmp085_oversampling = 3;
1114 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
1115 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1116 }
1117 else if( config_oversample > 3 ) /* 4 */
1118 {
1119 new_val = 4;
1120 bmp085_oversampling = 2;
1121 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1122 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1123 }
1124 else if( config_oversample > 1 ) /* 2 */
1125 {
1126 new_val = 2;
1127 bmp085_oversampling = 1;
1128 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1129 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1130 }
1131 else /* 1 */
1132 {
1133 new_val = 1;
1134 bmp085_oversampling = 0;
1135 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1136 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1137 }
1139 DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from %d to %d",
1140 config_oversample,
1141 new_val);
1142 config_oversample = new_val;
1143 }
1146 /**
1147 * Read the BMP085 sensor conversion coefficients.
1148 *
1149 * These are (device specific) constants so we can read them just once.
1150 *
1151 * @return Zero when successful
1152 */
1153 static int BMP085_read_coeffs(void)
1154 {
1155 __s32 res;
1156 __u8 coeffs[BMP085_NUM_COEFFS];
1157 char errbuf[1024];
1159 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
1160 BMP085_ADDR_COEFFS,
1161 BMP085_NUM_COEFFS,
1162 coeffs);
1163 if (res < 0)
1164 {
1165 ERROR ("barometer: BMP085_read_coeffs - problem reading data: %s",
1166 sstrerror (errno, errbuf, sizeof (errbuf)));
1167 return -1;
1168 }
1170 bmp085_AC1 = ((int16_t) coeffs[0] <<8) | (int16_t) coeffs[1];
1171 bmp085_AC2 = ((int16_t) coeffs[2] <<8) | (int16_t) coeffs[3];
1172 bmp085_AC3 = ((int16_t) coeffs[4] <<8) | (int16_t) coeffs[5];
1173 bmp085_AC4 = ((uint16_t) coeffs[6] <<8) | (uint16_t) coeffs[7];
1174 bmp085_AC5 = ((uint16_t) coeffs[8] <<8) | (uint16_t) coeffs[9];
1175 bmp085_AC6 = ((uint16_t) coeffs[10] <<8) | (uint16_t) coeffs[11];
1176 bmp085_B1 = ((int16_t) coeffs[12] <<8) | (int16_t) coeffs[13];
1177 bmp085_B2 = ((int16_t) coeffs[14] <<8) | (int16_t) coeffs[15];
1178 bmp085_MB = ((int16_t) coeffs[16] <<8) | (int16_t) coeffs[17];
1179 bmp085_MC = ((int16_t) coeffs[18] <<8) | (int16_t) coeffs[19];
1180 bmp085_MD = ((int16_t) coeffs[20] <<8) | (int16_t) coeffs[21];
1182 DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"\
1183 " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1184 bmp085_AC1,
1185 bmp085_AC2,
1186 bmp085_AC3,
1187 bmp085_AC4,
1188 bmp085_AC5,
1189 bmp085_AC6,
1190 bmp085_B1,
1191 bmp085_B2,
1192 bmp085_MB,
1193 bmp085_MC,
1194 bmp085_MD);
1196 return 0;
1197 }
1200 /**
1201 * Convert raw BMP085 adc values to real data using the sensor coefficients.
1202 *
1203 * @param adc_pressure adc pressure value to be converted
1204 * @param adc_temp adc temperature value to be converted
1205 * @param pressure computed real pressure
1206 * @param temperature computed real temperature
1207 */
1208 static void BMP085_convert_adc_to_real(long adc_pressure,
1209 long adc_temperature,
1210 double * pressure,
1211 double * temperature)
1213 {
1214 long X1, X2, X3;
1215 long B3, B5, B6;
1216 unsigned long B4, B7;
1218 long T;
1219 long P;
1222 /* calculate real temperature */
1223 X1 = ( (adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1224 X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1226 /* B5, T */
1227 B5 = X1 + X2;
1228 T = (B5 + 8) >> 4;
1229 *temperature = (double)T * 0.1;
1231 /* calculate real pressure */
1232 /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept */
1234 /* B6, B3 */
1235 B6 = B5 - 4000;
1236 X1 = ((bmp085_B2 * ((B6 * B6)>>12)) >> 11 );
1237 X2 = (((long)bmp085_AC2 * B6) >> 11);
1238 X3 = X1 + X2;
1239 B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1241 /* B4 */
1242 X1 = (((long)bmp085_AC3*B6) >> 13);
1243 X2 = (bmp085_B1*((B6*B6) >> 12) ) >> 16;
1244 X3 = ((X1 + X2) + 2 ) >> 2;
1245 B4 = ((long)bmp085_AC4* (unsigned long)(X3 + 32768)) >> 15;
1247 /* B7, P */
1248 B7 = (unsigned long)(adc_pressure - B3)*(50000>>bmp085_oversampling);
1249 if( B7 < 0x80000000 )
1250 {
1251 P = (B7 << 1) / B4;
1252 }
1253 else
1254 {
1255 P = (B7/B4) << 1;
1256 }
1257 X1 = (P >> 8) * (P >> 8);
1258 X1 = (X1 * 3038) >> 16;
1259 X2 = ((-7357) * P) >> 16;
1260 P = P + ( ( X1 + X2 + 3791 ) >> 4);
1262 *pressure = P / 100.0; // in [hPa]
1263 DEBUG ("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C",
1264 *pressure,
1265 *temperature);
1266 }
1269 /**
1270 * Read compensated sensor measurements
1271 *
1272 * @param pressure averaged measured pressure
1273 * @param temperature averaged measured temperature
1274 *
1275 * @return Zero when successful
1276 */
1277 static int BMP085_read(double * pressure, double * temperature)
1278 {
1279 __s32 res;
1280 __u8 measBuff[3];
1282 long adc_pressure;
1283 long adc_temperature;
1285 char errbuf[1024];
1287 /* start conversion of temperature */
1288 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1289 BMP085_ADDR_CTRL_REG,
1290 BMP085_CMD_CONVERT_TEMP );
1291 if (res < 0)
1292 {
1293 ERROR ("barometer: BMP085_read - problem requesting temperature conversion: %s",
1294 sstrerror (errno, errbuf, sizeof (errbuf)));
1295 return 1;
1296 }
1298 usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1300 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1301 BMP085_ADDR_CONV,
1302 2,
1303 measBuff);
1304 if (res < 0)
1305 {
1306 ERROR ("barometer: BMP085_read - problem reading temperature data: %s",
1307 sstrerror (errno, errbuf, sizeof (errbuf)));
1308 return 1;
1309 }
1311 adc_temperature = ( (unsigned short)measBuff[0] << 8 ) + measBuff[1];
1314 /* get presure */
1315 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1316 BMP085_ADDR_CTRL_REG,
1317 bmp085_cmdCnvPress );
1318 if (res < 0)
1319 {
1320 ERROR ("barometer: BMP085_read - problem requesting pressure conversion: %s",
1321 sstrerror (errno, errbuf, sizeof (errbuf)));
1322 return 1;
1323 }
1325 usleep(bmp085_timeCnvPress); /* wait for the conversion */
1327 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1328 BMP085_ADDR_CONV,
1329 3,
1330 measBuff );
1331 if (res < 0)
1332 {
1333 ERROR ("barometer: BMP085_read - problem reading pressure data: %s",
1334 sstrerror (errno, errbuf, sizeof (errbuf)));
1335 return 1;
1336 }
1338 adc_pressure = (long)((((ulong)measBuff[0]<<16) | ((ulong)measBuff[1]<<8) | (ulong)measBuff[2] ) >> (8 - bmp085_oversampling));
1341 DEBUG ("barometer: BMP085_read - raw pressure ADC value = %ld, " \
1342 "raw temperature ADC value = %ld",
1343 adc_pressure,
1344 adc_temperature);
1346 BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
1348 return 0;
1349 }
1353 /* ------------------------ Sensor detection ------------------------ */
1354 /**
1355 * Detect presence of a supported sensor.
1356 *
1357 * As a sideeffect will leave set I2C slave address.
1358 * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1359 * first sensor beeing found.
1360 *
1361 * @return detected sensor type
1362 */
1363 static enum Sensor_type detect_sensor_type(void)
1364 {
1365 if(BMP085_detect())
1366 return Sensor_BMP085;
1368 else if(MPL3115_detect())
1369 return Sensor_MPL3115;
1371 else if(MPL115_detect())
1372 return Sensor_MPL115;
1374 return Sensor_none;
1375 }
1377 /* ------------------------ Common functionality ------------------------ */
1379 /**
1380 * Convert absolute pressure (in hPa) to mean sea level pressure
1381 *
1382 * Implemented methods are:
1383 * - MSLP_NONE - no converions, returns absolute pressure
1384 *
1385 * - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1386 * Requires #config_altitude
1387 *
1388 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1389 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1390 * Requires both #config_altitude and temperature reference(s).
1391 *
1392 * @param abs_pressure absloute pressure to be converted
1393 *
1394 * @return mean sea level pressure if successful, NAN otherwise
1395 */
1396 static double abs_to_mean_sea_level_pressure(double abs_pressure)
1397 {
1398 double mean = -1.0;
1399 double temp = 0.0;
1400 int result = 0;
1402 if (config_normalize >= MSLP_DEU_WETT)
1403 {
1404 result = get_reference_temperature(&temp);
1405 if(result)
1406 {
1407 return NAN;
1408 }
1409 }
1411 switch(config_normalize)
1412 {
1413 case MSLP_NONE:
1414 mean = abs_pressure;
1415 break;
1417 case MSLP_INTERNATIONAL:
1418 mean = abs_pressure / \
1419 pow(1.0 - 0.0065*config_altitude/288.15, 9.80665*0.0289644/(8.31447*0.0065));
1420 break;
1422 case MSLP_DEU_WETT:
1423 {
1424 double E; /* humidity */
1425 double x;
1426 if(temp<9.1)
1427 E = 5.6402 * (-0.0916 + exp(0.06*temp) );
1428 else
1429 E = 18.2194 * (1.0463 - exp(-0.0666*temp) );
1430 x = 9.80665 / (287.05 * (temp+273.15 + 0.12*E + 0.0065*config_altitude/2)) * config_altitude;
1431 mean = abs_pressure * exp(x);
1432 }
1433 break;
1435 default:
1436 ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1437 config_normalize);
1438 mean = abs_pressure;
1439 break;
1440 }
1442 DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, method = %d, meanPressure = %lf hPa",
1443 abs_pressure,
1444 config_normalize,
1445 mean);
1447 return mean;
1448 }
1450 /* ------------------------ main plugin callbacks ------------------------ */
1452 /**
1453 * Main plugin configuration callback (using simple config)
1454 *
1455 * @param key configuration key we should process
1456 * @param value configuration value we should process
1457 *
1458 * @return Zero when successful.
1459 */
1460 static int collectd_barometer_config (const char *key, const char *value)
1461 {
1462 DEBUG("barometer: collectd_barometer_config");
1464 if (strcasecmp (key, "Device") == 0)
1465 {
1466 sfree (config_device);
1467 config_device = strdup (value);
1468 }
1469 else if (strcasecmp (key, "Oversampling") == 0)
1470 {
1471 int oversampling_tmp = atoi (value);
1472 if (oversampling_tmp < 1 || oversampling_tmp > 1024)
1473 {
1474 WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
1475 " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for MPL3115) or 1 to 8 (for BMP085).",
1476 oversampling_tmp);
1477 return 1;
1478 }
1479 config_oversample = oversampling_tmp;
1480 }
1481 else if (strcasecmp (key, "Altitude") == 0)
1482 {
1483 config_altitude = atof (value);
1484 }
1485 else if (strcasecmp (key, "Normalization") == 0)
1486 {
1487 int normalize_tmp = atoi (value);
1488 if (normalize_tmp < 0 || normalize_tmp > 2)
1489 {
1490 WARNING ("barometer: collectd_barometer_config: invalid normalization: %d",
1491 normalize_tmp);
1492 return 1;
1493 }
1494 config_normalize = normalize_tmp;
1495 }
1496 else if (strcasecmp (key, "TemperatureSensor") == 0)
1497 {
1498 if(temp_list_add(temp_list, value))
1499 {
1500 return -1;
1501 }
1502 }
1503 else if (strcasecmp (key, "PressureOffset") == 0)
1504 {
1505 config_press_offset = atof(value);
1506 }
1507 else if (strcasecmp (key, "TemperatureOffset") == 0)
1508 {
1509 config_temp_offset = atof(value);
1510 }
1511 else
1512 {
1513 return -1;
1514 }
1516 return 0;
1517 }
1520 /**
1521 * Shutdown callback.
1522 *
1523 * Close I2C and delete all the buffers.
1524 *
1525 * @return Zero when successful (at the moment the only possible outcome)
1526 */
1527 static int collectd_barometer_shutdown(void)
1528 {
1529 DEBUG ("barometer: collectd_barometer_shutdown");
1531 if(sensor_type == Sensor_MPL115)
1532 {
1533 averaging_delete (&pressure_averaging);
1534 averaging_delete (&temperature_averaging);
1536 temp_list_delete(&temp_list);
1537 }
1539 if (i2c_bus_fd > 0)
1540 {
1541 close (i2c_bus_fd);
1542 i2c_bus_fd = -1;
1543 sfree (config_device);
1544 }
1546 return 0;
1547 }
1550 /**
1551 * Plugin read callback for MPL115.
1552 *
1553 * Dispatching will create values:
1554 * - <hostname>/barometer-mpl115/pressure-normalized
1555 * - <hostname>/barometer-mpl115/pressure-absolute
1556 * - <hostname>/barometer-mpl115/temperature
1557 *
1558 * @return Zero when successful.
1559 */
1560 static int MPL115_collectd_barometer_read (void)
1561 {
1562 int result = 0;
1564 double pressure = 0.0;
1565 double temperature = 0.0;
1566 double norm_pressure = 0.0;
1568 value_list_t vl = VALUE_LIST_INIT;
1569 value_t values[1];
1571 DEBUG("barometer: MPL115_collectd_barometer_read");
1573 if (!configured)
1574 {
1575 return -1;
1576 }
1578 /* Rather than delaying init, we will intitialize during first read. This
1579 way at least we have a better chance to have the reference temperature
1580 already available. */
1581 if(!avg_initialized)
1582 {
1583 int i;
1584 for(i=0; i<config_oversample-1; ++i)
1585 {
1586 result = MPL115_read_averaged(&pressure, &temperature);
1587 if(result)
1588 {
1589 ERROR ("barometer: MPL115_collectd_barometer_read - mpl115 read, ignored during init");
1590 }
1591 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i+1, config_oversample-1);
1592 usleep(20000);
1593 }
1594 avg_initialized = 1;
1595 }
1597 result = MPL115_read_averaged(&pressure, &temperature);
1598 if(result)
1599 return result;
1601 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1603 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1604 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1605 sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
1607 vl.values_len = 1;
1608 vl.values = values;
1610 /* dispatch normalized air pressure */
1611 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1612 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1613 values[0].gauge = norm_pressure;
1614 plugin_dispatch_values (&vl);
1616 /* dispatch absolute air pressure */
1617 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1618 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1619 values[0].gauge = pressure;
1620 plugin_dispatch_values (&vl);
1622 /* dispatch sensor temperature */
1623 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1624 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1625 values[0].gauge = temperature;
1626 plugin_dispatch_values (&vl);
1628 return 0;
1629 }
1632 /**
1633 * Plugin read callback for MPL3115.
1634 *
1635 * Dispatching will create values:
1636 * - <hostname>/barometer-mpl3115/pressure-normalized
1637 * - <hostname>/barometer-mpl3115/pressure-absolute
1638 * - <hostname>/barometer-mpl3115/temperature
1639 *
1640 * @return Zero when successful.
1641 */
1642 static int MPL3115_collectd_barometer_read (void)
1643 {
1644 int result = 0;
1646 double pressure = 0.0;
1647 double temperature = 0.0;
1648 double norm_pressure = 0.0;
1650 value_list_t vl = VALUE_LIST_INIT;
1651 value_t values[1];
1653 DEBUG("barometer: MPL3115_collectd_barometer_read");
1655 if (!configured)
1656 {
1657 return -1;
1658 }
1660 result = MPL3115_read(&pressure, &temperature);
1661 if(result)
1662 return result;
1664 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1666 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1667 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1668 sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
1670 vl.values_len = 1;
1671 vl.values = values;
1673 /* dispatch normalized air pressure */
1674 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1675 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1676 values[0].gauge = norm_pressure;
1677 plugin_dispatch_values (&vl);
1679 /* dispatch absolute air pressure */
1680 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1681 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1682 values[0].gauge = pressure;
1683 plugin_dispatch_values (&vl);
1685 /* dispatch sensor temperature */
1686 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1687 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1688 values[0].gauge = temperature;
1689 plugin_dispatch_values (&vl);
1691 return 0;
1692 }
1695 /**
1696 * Plugin read callback for BMP085.
1697 *
1698 * Dispatching will create values:
1699 * - <hostname>/barometer-bmp085/pressure-normalized
1700 * - <hostname>/barometer-bmp085/pressure-absolute
1701 * - <hostname>/barometer-bmp085/temperature
1702 *
1703 * @return Zero when successful.
1704 */
1705 static int BMP085_collectd_barometer_read (void)
1706 {
1707 int result = 0;
1709 double pressure = 0.0;
1710 double temperature = 0.0;
1711 double norm_pressure = 0.0;
1713 value_list_t vl = VALUE_LIST_INIT;
1714 value_t values[1];
1716 DEBUG("barometer: BMP085_collectd_barometer_read");
1718 if (!configured)
1719 {
1720 return -1;
1721 }
1723 result = BMP085_read(&pressure, &temperature);
1724 if(result)
1725 return result;
1727 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1729 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1730 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1731 sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
1733 vl.values_len = 1;
1734 vl.values = values;
1736 /* dispatch normalized air pressure */
1737 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1738 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1739 values[0].gauge = norm_pressure;
1740 plugin_dispatch_values (&vl);
1742 /* dispatch absolute air pressure */
1743 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1744 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1745 values[0].gauge = pressure;
1746 plugin_dispatch_values (&vl);
1748 /* dispatch sensor temperature */
1749 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1750 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1751 values[0].gauge = temperature;
1752 plugin_dispatch_values (&vl);
1754 return 0;
1755 }
1758 /**
1759 * Initialization callback
1760 *
1761 * Check config, initialize I2C bus access, conversion coefficients and averaging
1762 * ring buffers
1763 *
1764 * @return Zero when successful.
1765 */
1766 static int collectd_barometer_init (void)
1767 {
1768 char errbuf[1024];
1770 DEBUG ("barometer: collectd_barometer_init");
1772 if (config_device == NULL)
1773 {
1774 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1775 return -1;
1776 }
1778 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude))
1779 {
1780 ERROR("barometer: collectd_barometer_init no altitude configured " \
1781 "for mean sea level pressure normalization.");
1782 return -1;
1783 }
1785 if (config_normalize == MSLP_DEU_WETT
1786 &&
1787 temp_list == NULL)
1788 {
1789 ERROR("barometer: collectd_barometer_init no temperature reference "\
1790 "configured for mean sea level pressure normalization.");
1791 return -1;
1792 }
1795 i2c_bus_fd = open(config_device, O_RDWR);
1796 if (i2c_bus_fd < 0)
1797 {
1798 ERROR ("barometer: collectd_barometer_init problem opening I2C bus device \"%s\": %s (is loaded mod i2c-dev?)",
1799 config_device,
1800 sstrerror (errno, errbuf, sizeof (errbuf)));
1801 return -1;
1802 }
1804 /* detect sensor type - this will also set slave address */
1805 sensor_type = detect_sensor_type();
1807 /* init correct sensor type */
1808 switch(sensor_type)
1809 {
1810 /* MPL3115 */
1811 case Sensor_MPL3115:
1812 {
1813 MPL3115_adjust_oversampling();
1815 if(MPL3115_init_sensor())
1816 return -1;
1818 plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
1819 }
1820 break;
1822 /* MPL115 */
1823 case Sensor_MPL115:
1824 {
1825 if (averaging_create (&pressure_averaging, config_oversample))
1826 {
1827 ERROR("barometer: collectd_barometer_init pressure averaging init failed");
1828 return -1;
1829 }
1831 if (averaging_create (&temperature_averaging, config_oversample))
1832 {
1833 ERROR("barometer: collectd_barometer_init temperature averaging init failed");
1834 return -1;
1835 }
1837 if (MPL115_read_coeffs() < 0)
1838 return -1;
1840 plugin_register_read ("barometer", MPL115_collectd_barometer_read);
1841 }
1842 break;
1844 /* BMP085 */
1845 case Sensor_BMP085:
1846 {
1847 BMP085_adjust_oversampling();
1849 if (BMP085_read_coeffs() < 0)
1850 return -1;
1852 plugin_register_read ("barometer", BMP085_collectd_barometer_read);
1853 }
1854 break;
1856 /* anything else -> error */
1857 default:
1858 ERROR("barometer: collectd_barometer_init - no supported sensor found");
1859 return -1;
1860 }
1863 configured = 1;
1864 return 0;
1865 }
1867 /* ------------------------ plugin register / entry point ------------------------ */
1869 /**
1870 * Plugin "entry" - register all callback.
1871 *
1872 */
1873 void module_register (void)
1874 {
1875 plugin_register_config ("barometer",
1876 collectd_barometer_config,
1877 config_keys,
1878 config_keys_num);
1879 plugin_register_init ("barometer", collectd_barometer_init);
1880 plugin_register_shutdown ("barometer", collectd_barometer_shutdown);
1881 }