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));
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 = (temperature_list_t *) 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 int 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 %d: %lf **",
451 i,
452 values[i]);
453 if(!isnan(values[i]))
454 {
455 avg_sum += values[i];
456 ++avg_num;
457 }
458 }
459 free(values);
460 values = NULL;
461 }
463 /* It is OK to get here the first time as well, in the worst case
464 the history will full of NANs. */
465 if(uc_get_history_by_name(list->sensor_name,
466 values_history,
467 REF_TEMP_AVG_NUM,
468 list->num_values))
469 {
470 ERROR ("barometer: get_reference_temperature - history \"%s\" lost",
471 list->sensor_name);
472 list->initialized = 0;
473 list->num_values = 0;
474 list = list->next;
475 continue;
476 }
478 for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
479 {
480 DEBUG ("barometer: get_reference_temperature - history %d: %lf",
481 i,
482 values_history[i]);
483 if(!isnan(values_history[i]))
484 {
485 avg_sum += values_history[i];
486 ++avg_num;
487 }
488 }
490 if(avg_num == 0) /* still no history? fallback to current */
491 {
492 if(uc_get_rate_by_name(list->sensor_name,
493 &values,
494 &values_num))
495 {
496 ERROR ("barometer: get_reference_temperature - rate \"%s\" lost",
497 list->sensor_name);
498 list->initialized = 0;
499 list->num_values = 0;
500 list = list->next;
501 continue;
502 }
504 for(i=0; i<values_num; ++i)
505 {
506 DEBUG ("barometer: get_reference_temperature - rate last %d: %lf **",
507 i,
508 values[i]);
509 if(!isnan(values[i]))
510 {
511 avg_sum += values[i];
512 ++avg_num;
513 }
514 }
515 free(values);
516 values = NULL;
517 }
519 if(avg_num == 0)
520 {
521 ERROR ("barometer: get_reference_temperature - could not read \"%s\"",
522 list->sensor_name);
523 list->initialized = 0;
524 list->num_values = 0;
525 }
526 else
527 {
528 average = avg_sum / (double) avg_num;
529 if(isnan(*result))
530 *result=average;
531 else if(*result>average)
532 *result=average;
533 }
534 list = list->next;
535 } /* while sensor list */
537 if(*result == NAN)
538 {
539 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
540 return -1;
541 }
542 DEBUG ("barometer: get_reference_temperature - temp is %lf", *result);
543 return 0;
544 }
547 /* ------------------------ MPL115 access ------------------------ */
549 /**
550 * Detect presence of a MPL115 pressure sensor.
551 *
552 * Unfortunately there seems to be no ID register so we just try to read first
553 * conversion coefficient from device at MPL115 address and hope it is really
554 * MPL115. We should use this check as the last resort (which would be the typical
555 * case anyway since MPL115 is the least accurate sensor).
556 * As a sideeffect will leave set I2C slave address.
557 *
558 * @return 1 if MPL115, 0 otherwise
559 */
560 static int MPL115_detect(void)
561 {
562 __s32 res;
563 char errbuf[1024];
565 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
566 {
567 ERROR("barometer: MPL115_detect problem setting i2c slave address to 0x%02X: %s",
568 MPL115_I2C_ADDRESS,
569 sstrerror (errno, errbuf, sizeof (errbuf)));
570 return 0 ;
571 }
573 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
574 if(res >= 0)
575 {
576 DEBUG ("barometer: MPL115_detect - positive detection");
577 return 1;
578 }
580 DEBUG ("barometer: MPL115_detect - negative detection");
581 return 0;
582 }
584 /**
585 * Read the MPL115 sensor conversion coefficients.
586 *
587 * These are (device specific) constants so we can read them just once.
588 *
589 * @return Zero when successful
590 */
591 static int MPL115_read_coeffs(void)
592 {
593 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS];
594 int32_t res;
596 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
597 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
598 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
600 char errbuf[1024];
602 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
603 MPL115_ADDR_COEFFS,
604 MPL115_NUM_COEFFS,
605 mpl115_coeffs);
606 if (res < 0)
607 {
608 ERROR ("barometer: MPL115_read_coeffs - problem reading data: %s",
609 sstrerror (errno, errbuf, sizeof (errbuf)));
610 return -1;
611 }
613 /* Using perhaps less elegant/efficient code, but more readable. */
614 /* a0: 16total 1sign 12int 4fract 0pad */
615 sia0MSB = mpl115_coeffs[0];
616 sia0LSB = mpl115_coeffs[1];
617 sia0 = (int16_t) sia0MSB <<8; /* s16 type, Shift to MSB */
618 sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
619 mpl115_coeffA0 = (double) (sia0);
620 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
622 /* b1: 16total 1sign 2int 13fract 0pad */
623 sib1MSB= mpl115_coeffs[2];
624 sib1LSB= mpl115_coeffs[3];
625 sib1 = sib1MSB <<8; /* Shift to MSB */
626 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
627 mpl115_coeffB1 = (double) (sib1);
628 mpl115_coeffB1 /= 8192.0; /* 13 fract */
630 /* b2: 16total 1sign 1int 14fract 0pad */
631 sib2MSB= mpl115_coeffs[4];
632 sib2LSB= mpl115_coeffs[5];
633 sib2 = sib2MSB <<8; /* Shift to MSB */
634 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
635 mpl115_coeffB2 = (double) (sib2);
636 mpl115_coeffB2 /= 16384.0; /* 14 fract */
638 /* c12: 14total 1sign 0int 13fract 9pad */
639 sic12MSB= mpl115_coeffs[6];
640 sic12LSB= mpl115_coeffs[7];
641 sic12 = sic12MSB <<8; /* Shift to MSB only by 8 for MSB */
642 sic12 += sic12LSB & 0x00FF;
643 mpl115_coeffC12 = (double) (sic12);
644 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
645 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
647 /* c11: 11total 1sign 0int 11fract 11pad */
648 sic11MSB= mpl115_coeffs[8];
649 sic11LSB= mpl115_coeffs[9];
650 sic11 = sic11MSB <<8; /* Shift to MSB only by 8 for MSB */
651 sic11 += sic11LSB & 0x00FF;
652 mpl115_coeffC11 = (double) (sic11);
653 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
654 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
656 /* c12: 11total 1sign 0int 10fract 15pad */
657 sic22MSB= mpl115_coeffs[10];
658 sic22LSB= mpl115_coeffs[11];
659 sic22 = sic22MSB <<8; /* Shift to MSB only by 8 for MSB */
660 sic22 += sic22LSB & 0x00FF;
661 mpl115_coeffC22 = (double) (sic22);
662 mpl115_coeffC22 /= 32.0; //16-11=5
663 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
665 DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
666 mpl115_coeffA0,
667 mpl115_coeffB1,
668 mpl115_coeffB2,
669 mpl115_coeffC12,
670 mpl115_coeffC11,
671 mpl115_coeffC22);
672 return 0;
673 }
676 /**
677 * Convert raw adc values to real data using the sensor coefficients.
678 *
679 * @param adc_pressure adc pressure value to be converted
680 * @param adc_temp adc temperature value to be converted
681 * @param pressure computed real pressure
682 * @param temperature computed real temperature
683 */
684 static void MPL115_convert_adc_to_real(double adc_pressure,
685 double adc_temp,
686 double * pressure,
687 double * temperature)
688 {
689 double Pcomp;
690 Pcomp = mpl115_coeffA0 + \
691 (mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
692 (mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
694 *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
695 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
696 DEBUG ("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C",
697 *pressure,
698 *temperature);
699 }
702 /**
703 * Read sensor averegaed measurements
704 *
705 * @param pressure averaged measured pressure
706 * @param temperature averaged measured temperature
707 *
708 * @return Zero when successful
709 */
710 static int MPL115_read_averaged(double * pressure, double * temperature)
711 {
712 uint8_t mpl115_conv[MPL115_NUM_CONV];
713 int8_t res;
714 int retries;
715 int conv_pressure;
716 int conv_temperature;
717 double adc_pressure;
718 double adc_temperature;
719 char errbuf[1024];
721 *pressure = 0.0;
722 *temperature = 0.0;
724 /* start conversion of both temp and presure */
725 retries = MPL115_CONVERSION_RETRIES;
726 while (retries>0)
727 {
728 /* write 1 to start conversion */
729 res = i2c_smbus_write_byte_data (i2c_bus_fd,
730 MPL115_CMD_CONVERT_BOTH,
731 0x01);
732 if (res >= 0)
733 break;
735 --retries;
736 if(retries>0)
737 {
738 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, " \
739 "will retry at most %d more times",
740 sstrerror (errno, errbuf, sizeof (errbuf)),
741 retries);
742 }
743 else
744 {
745 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, "\
746 "too many failed retries",
747 sstrerror (errno, errbuf, sizeof (errbuf)));
748 return -1;
749 }
750 }
752 usleep (10000); /* wait 10ms for the conversion */
754 retries=MPL115_CONVERSION_RETRIES;
755 while (retries>0)
756 {
757 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
758 MPL115_ADDR_CONV,
759 MPL115_NUM_CONV,
760 mpl115_conv);
761 if (res >= 0)
762 break;
764 --retries;
765 if (retries>0)
766 {
767 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
768 "will retry at most %d more times",
769 sstrerror (errno, errbuf, sizeof (errbuf)),
770 retries);
771 }
772 else
773 {
774 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
775 "too many failed retries",
776 sstrerror (errno, errbuf, sizeof (errbuf)));
777 return -1;
778 }
779 }
781 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
782 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
783 DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
784 "raw temperature ADC value = %d",
785 conv_pressure,
786 conv_temperature);
788 adc_pressure = averaging_add_sample (&pressure_averaging, conv_pressure);
789 adc_temperature = averaging_add_sample (&temperature_averaging, conv_temperature);
791 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
793 DEBUG ("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / temperature = %lf, " \
794 "real pressure = %lf hPa / temperature = %lf C",
795 adc_pressure,
796 adc_temperature,
797 *pressure,
798 *temperature);
800 return 0;
801 }
803 /* ------------------------ MPL3115 access ------------------------ */
805 /**
806 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
807 *
808 * As a sideeffect will leave set I2C slave address.
809 *
810 * @return 1 if MPL3115, 0 otherwise
811 */
812 static int MPL3115_detect(void)
813 {
814 __s32 res;
815 char errbuf[1024];
817 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0)
818 {
819 ERROR("barometer: MPL3115_detect problem setting i2c slave address to 0x%02X: %s",
820 MPL3115_I2C_ADDRESS,
821 sstrerror (errno, errbuf, sizeof (errbuf)));
822 return 0 ;
823 }
825 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
826 if(res == MPL3115_WHO_AM_I_RESP)
827 {
828 DEBUG ("barometer: MPL3115_detect - positive detection");
829 return 1;
830 }
832 DEBUG ("barometer: MPL3115_detect - negative detection");
833 return 0;
834 }
836 /**
837 * Adjusts oversampling to values supported by MPL3115
838 *
839 * MPL3115 supports only power of 2 in the range 1 to 128.
840 */
841 static void MPL3115_adjust_oversampling(void)
842 {
843 int new_val = 0;
845 if(config_oversample > 100)
846 {
847 new_val = 128;
848 mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
849 }
850 else if(config_oversample > 48)
851 {
852 new_val = 64;
853 mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
854 }
855 else if(config_oversample > 24)
856 {
857 new_val = 32;
858 mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
859 }
860 else if(config_oversample > 12)
861 {
862 new_val = 16;
863 mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
864 }
865 else if(config_oversample > 6)
866 {
867 new_val = 8;
868 mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
869 }
870 else if(config_oversample > 3)
871 {
872 new_val = 4;
873 mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
874 }
875 else if(config_oversample > 1)
876 {
877 new_val = 2;
878 mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
879 }
880 else
881 {
882 new_val = 1;
883 mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
884 }
886 DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
887 config_oversample,
888 new_val);
889 config_oversample = new_val;
890 }
892 /**
893 * Read sensor averegaed measurements
894 *
895 * @param pressure averaged measured pressure
896 * @param temperature averaged measured temperature
897 *
898 * @return Zero when successful
899 */
900 static int MPL3115_read(double * pressure, double * temperature)
901 {
902 __s32 res;
903 __s32 ctrl ;
904 __u8 data[MPL3115_NUM_CONV_VALS];
905 long int tmp_value = 0;
906 char errbuf[1024];
908 /* Set Active - activate the device from standby */
909 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
910 if (res < 0)
911 {
912 ERROR ("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
913 sstrerror (errno, errbuf, sizeof (errbuf)));
914 return 1;
915 }
916 ctrl = res;
917 res = i2c_smbus_write_byte_data(i2c_bus_fd,
918 MPL3115_REG_CTRL_REG1,
919 ctrl | MPL3115_CTRL_REG1_SBYB);
920 if (res < 0)
921 {
922 ERROR ("barometer: MPL3115_read - problem activating: %s",
923 sstrerror (errno, errbuf, sizeof (errbuf)));
924 return 1;
925 }
927 /* base sleep is 5ms x OST */
928 usleep(5000 * config_oversample);
930 /* check the flags/status if ready */
931 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
932 if (res < 0)
933 {
934 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
935 sstrerror (errno, errbuf, sizeof (errbuf)));
936 return 1;
937 }
939 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
940 {
941 /* try some extra sleep... */
942 usleep(10000);
944 /* ... and repeat the check. The conversion has to finish sooner or later. */
945 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
946 if (res < 0)
947 {
948 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
949 sstrerror (errno, errbuf, sizeof (errbuf)));
950 return 1;
951 }
952 }
954 /* Now read all the data in one block. There is address autoincrement. */
955 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
956 MPL3115_REG_OUT_P_MSB,
957 MPL3115_NUM_CONV_VALS,
958 data);
959 if (res < 0)
960 {
961 ERROR ("barometer: MPL3115_read - cannot read data registers: %s",
962 sstrerror (errno, errbuf, sizeof (errbuf)));
963 return 1;
964 }
966 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
967 *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
968 DEBUG ("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
970 if(data[3] > 0x7F)
971 {
972 data[3] = ~data[3] + 1;
973 *temperature = data[3];
974 *temperature = - *temperature;
975 }
976 else
977 {
978 *temperature = data[3];
979 }
981 *temperature += (double)(data[4]) / 256.0;
982 DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
984 return 0;
985 }
987 /**
988 * Initialize MPL3115 for barometeric measurements
989 *
990 * @return 0 if successful
991 */
992 static int MPL3115_init_sensor(void)
993 {
994 __s32 res;
995 __s8 offset;
996 char errbuf[1024];
998 /* Reset the sensor. It will reset immediately without ACKing */
999 /* the transaction, so no error handling here. */
1000 i2c_smbus_write_byte_data(i2c_bus_fd,
1001 MPL3115_REG_CTRL_REG1,
1002 MPL3115_CTRL_REG1_RST);
1004 /* wait some time for the reset to finish */
1005 usleep(100000);
1007 /* now it should be in standby already so we can go and configure it */
1009 /* Set temperature offset. */
1010 /* result = ADCtemp + offset [C] */
1011 offset = (__s8) (config_temp_offset * 16.0);
1012 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
1013 if (res < 0)
1014 {
1015 ERROR ("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
1016 sstrerror (errno, errbuf, sizeof (errbuf)));
1017 return -1;
1018 }
1020 /* Set pressure offset. */
1021 /* result = ADCpress + offset [hPa] */
1022 offset = (__s8) (config_press_offset * 100.0 / 4.0);
1023 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
1024 if (res < 0)
1025 {
1026 ERROR ("barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
1027 sstrerror (errno, errbuf, sizeof (errbuf)));
1028 return -1;
1029 }
1031 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
1032 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1033 MPL3115_REG_PT_DATA_CFG,
1034 MPL3115_PT_DATA_DREM \
1035 | MPL3115_PT_DATA_PDEF \
1036 | MPL3115_PT_DATA_TDEF);
1037 if (res < 0)
1038 {
1039 ERROR ("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
1040 sstrerror (errno, errbuf, sizeof (errbuf)));
1041 return -1;
1042 }
1044 /* Set to barometer with an OSR */
1045 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1046 MPL3115_REG_CTRL_REG1,
1047 mpl3115_oversample);
1048 if (res < 0)
1049 {
1050 ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
1051 sstrerror (errno, errbuf, sizeof (errbuf)));
1052 return -1;
1053 }
1055 return 0;
1056 }
1058 /* ------------------------ BMP085 access ------------------------ */
1060 /**
1061 * Detect presence of a BMP085 pressure sensor by checking its ID register
1062 *
1063 * As a sideeffect will leave set I2C slave address.
1064 *
1065 * @return 1 if BMP085, 0 otherwise
1066 */
1067 static int BMP085_detect(void)
1068 {
1069 __s32 res;
1070 char errbuf[1024];
1072 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0)
1073 {
1074 ERROR("barometer: BMP085_detect - problem setting i2c slave address to 0x%02X: %s",
1075 BMP085_I2C_ADDRESS,
1076 sstrerror (errno, errbuf, sizeof (errbuf)));
1077 return 0 ;
1078 }
1080 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
1081 if(res == BMP085_CHIP_ID)
1082 {
1083 DEBUG ("barometer: BMP085_detect - positive detection");
1085 /* get version */
1086 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION );
1087 if (res < 0)
1088 {
1089 ERROR("barometer: BMP085_detect - problem checking chip version: %s",
1090 sstrerror (errno, errbuf, sizeof (errbuf)));
1091 return 0 ;
1092 }
1093 DEBUG ("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
1094 res & 0x0f,
1095 (res & 0xf0) >> 4);
1096 return 1;
1097 }
1099 DEBUG ("barometer: BMP085_detect - negative detection");
1100 return 0;
1101 }
1104 /**
1105 * Adjusts oversampling settings to values supported by BMP085
1106 *
1107 * BMP085 supports only 1,2,4 or 8 samples.
1108 */
1109 static void BMP085_adjust_oversampling(void)
1110 {
1111 int new_val = 0;
1113 if( config_oversample > 6 ) /* 8 */
1114 {
1115 new_val = 8;
1116 bmp085_oversampling = 3;
1117 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
1118 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1119 }
1120 else if( config_oversample > 3 ) /* 4 */
1121 {
1122 new_val = 4;
1123 bmp085_oversampling = 2;
1124 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1125 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1126 }
1127 else if( config_oversample > 1 ) /* 2 */
1128 {
1129 new_val = 2;
1130 bmp085_oversampling = 1;
1131 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1132 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1133 }
1134 else /* 1 */
1135 {
1136 new_val = 1;
1137 bmp085_oversampling = 0;
1138 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1139 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1140 }
1142 DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from %d to %d",
1143 config_oversample,
1144 new_val);
1145 config_oversample = new_val;
1146 }
1149 /**
1150 * Read the BMP085 sensor conversion coefficients.
1151 *
1152 * These are (device specific) constants so we can read them just once.
1153 *
1154 * @return Zero when successful
1155 */
1156 static int BMP085_read_coeffs(void)
1157 {
1158 __s32 res;
1159 __u8 coeffs[BMP085_NUM_COEFFS];
1160 char errbuf[1024];
1162 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
1163 BMP085_ADDR_COEFFS,
1164 BMP085_NUM_COEFFS,
1165 coeffs);
1166 if (res < 0)
1167 {
1168 ERROR ("barometer: BMP085_read_coeffs - problem reading data: %s",
1169 sstrerror (errno, errbuf, sizeof (errbuf)));
1170 return -1;
1171 }
1173 bmp085_AC1 = ((int16_t) coeffs[0] <<8) | (int16_t) coeffs[1];
1174 bmp085_AC2 = ((int16_t) coeffs[2] <<8) | (int16_t) coeffs[3];
1175 bmp085_AC3 = ((int16_t) coeffs[4] <<8) | (int16_t) coeffs[5];
1176 bmp085_AC4 = ((uint16_t) coeffs[6] <<8) | (uint16_t) coeffs[7];
1177 bmp085_AC5 = ((uint16_t) coeffs[8] <<8) | (uint16_t) coeffs[9];
1178 bmp085_AC6 = ((uint16_t) coeffs[10] <<8) | (uint16_t) coeffs[11];
1179 bmp085_B1 = ((int16_t) coeffs[12] <<8) | (int16_t) coeffs[13];
1180 bmp085_B2 = ((int16_t) coeffs[14] <<8) | (int16_t) coeffs[15];
1181 bmp085_MB = ((int16_t) coeffs[16] <<8) | (int16_t) coeffs[17];
1182 bmp085_MC = ((int16_t) coeffs[18] <<8) | (int16_t) coeffs[19];
1183 bmp085_MD = ((int16_t) coeffs[20] <<8) | (int16_t) coeffs[21];
1185 DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"\
1186 " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1187 bmp085_AC1,
1188 bmp085_AC2,
1189 bmp085_AC3,
1190 bmp085_AC4,
1191 bmp085_AC5,
1192 bmp085_AC6,
1193 bmp085_B1,
1194 bmp085_B2,
1195 bmp085_MB,
1196 bmp085_MC,
1197 bmp085_MD);
1199 return 0;
1200 }
1203 /**
1204 * Convert raw BMP085 adc values to real data using the sensor coefficients.
1205 *
1206 * @param adc_pressure adc pressure value to be converted
1207 * @param adc_temp adc temperature value to be converted
1208 * @param pressure computed real pressure
1209 * @param temperature computed real temperature
1210 */
1211 static void BMP085_convert_adc_to_real(long adc_pressure,
1212 long adc_temperature,
1213 double * pressure,
1214 double * temperature)
1216 {
1217 long X1, X2, X3;
1218 long B3, B5, B6;
1219 unsigned long B4, B7;
1221 long T;
1222 long P;
1225 /* calculate real temperature */
1226 X1 = ( (adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1227 X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1229 /* B5, T */
1230 B5 = X1 + X2;
1231 T = (B5 + 8) >> 4;
1232 *temperature = (double)T * 0.1;
1234 /* calculate real pressure */
1235 /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept */
1237 /* B6, B3 */
1238 B6 = B5 - 4000;
1239 X1 = ((bmp085_B2 * ((B6 * B6)>>12)) >> 11 );
1240 X2 = (((long)bmp085_AC2 * B6) >> 11);
1241 X3 = X1 + X2;
1242 B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1244 /* B4 */
1245 X1 = (((long)bmp085_AC3*B6) >> 13);
1246 X2 = (bmp085_B1*((B6*B6) >> 12) ) >> 16;
1247 X3 = ((X1 + X2) + 2 ) >> 2;
1248 B4 = ((long)bmp085_AC4* (unsigned long)(X3 + 32768)) >> 15;
1250 /* B7, P */
1251 B7 = (unsigned long)(adc_pressure - B3)*(50000>>bmp085_oversampling);
1252 if( B7 < 0x80000000 )
1253 {
1254 P = (B7 << 1) / B4;
1255 }
1256 else
1257 {
1258 P = (B7/B4) << 1;
1259 }
1260 X1 = (P >> 8) * (P >> 8);
1261 X1 = (X1 * 3038) >> 16;
1262 X2 = ((-7357) * P) >> 16;
1263 P = P + ( ( X1 + X2 + 3791 ) >> 4);
1265 *pressure = P / 100.0; // in [hPa]
1266 DEBUG ("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C",
1267 *pressure,
1268 *temperature);
1269 }
1272 /**
1273 * Read compensated sensor measurements
1274 *
1275 * @param pressure averaged measured pressure
1276 * @param temperature averaged measured temperature
1277 *
1278 * @return Zero when successful
1279 */
1280 static int BMP085_read(double * pressure, double * temperature)
1281 {
1282 __s32 res;
1283 __u8 measBuff[3];
1285 long adc_pressure;
1286 long adc_temperature;
1288 char errbuf[1024];
1290 /* start conversion of temperature */
1291 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1292 BMP085_ADDR_CTRL_REG,
1293 BMP085_CMD_CONVERT_TEMP );
1294 if (res < 0)
1295 {
1296 ERROR ("barometer: BMP085_read - problem requesting temperature conversion: %s",
1297 sstrerror (errno, errbuf, sizeof (errbuf)));
1298 return 1;
1299 }
1301 usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1303 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1304 BMP085_ADDR_CONV,
1305 2,
1306 measBuff);
1307 if (res < 0)
1308 {
1309 ERROR ("barometer: BMP085_read - problem reading temperature data: %s",
1310 sstrerror (errno, errbuf, sizeof (errbuf)));
1311 return 1;
1312 }
1314 adc_temperature = ( (unsigned short)measBuff[0] << 8 ) + measBuff[1];
1317 /* get presure */
1318 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1319 BMP085_ADDR_CTRL_REG,
1320 bmp085_cmdCnvPress );
1321 if (res < 0)
1322 {
1323 ERROR ("barometer: BMP085_read - problem requesting pressure conversion: %s",
1324 sstrerror (errno, errbuf, sizeof (errbuf)));
1325 return 1;
1326 }
1328 usleep(bmp085_timeCnvPress); /* wait for the conversion */
1330 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1331 BMP085_ADDR_CONV,
1332 3,
1333 measBuff );
1334 if (res < 0)
1335 {
1336 ERROR ("barometer: BMP085_read - problem reading pressure data: %s",
1337 sstrerror (errno, errbuf, sizeof (errbuf)));
1338 return 1;
1339 }
1341 adc_pressure = (long)((((ulong)measBuff[0]<<16) | ((ulong)measBuff[1]<<8) | (ulong)measBuff[2] ) >> (8 - bmp085_oversampling));
1344 DEBUG ("barometer: BMP085_read - raw pressure ADC value = %ld, " \
1345 "raw temperature ADC value = %ld",
1346 adc_pressure,
1347 adc_temperature);
1349 BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
1351 return 0;
1352 }
1356 /* ------------------------ Sensor detection ------------------------ */
1357 /**
1358 * Detect presence of a supported sensor.
1359 *
1360 * As a sideeffect will leave set I2C slave address.
1361 * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1362 * first sensor beeing found.
1363 *
1364 * @return detected sensor type
1365 */
1366 enum Sensor_type Detect_sensor_type(void)
1367 {
1368 if(BMP085_detect())
1369 return Sensor_BMP085;
1371 else if(MPL3115_detect())
1372 return Sensor_MPL3115;
1374 else if(MPL115_detect())
1375 return Sensor_MPL115;
1377 return Sensor_none;
1378 }
1380 /* ------------------------ Common functionality ------------------------ */
1382 /**
1383 * Convert absolute pressure (in hPa) to mean sea level pressure
1384 *
1385 * Implemented methods are:
1386 * - MSLP_NONE - no converions, returns absolute pressure
1387 *
1388 * - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1389 * Requires #config_altitude
1390 *
1391 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1392 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1393 * Requires both #config_altitude and temperature reference(s).
1394 *
1395 * @param abs_pressure absloute pressure to be converted
1396 *
1397 * @return mean sea level pressure if successful, NAN otherwise
1398 */
1399 static double abs_to_mean_sea_level_pressure(double abs_pressure)
1400 {
1401 double mean = -1.0;
1402 double temp = 0.0;
1403 int result = 0;
1405 if (config_normalize >= MSLP_DEU_WETT)
1406 {
1407 result = get_reference_temperature(&temp);
1408 if(result)
1409 {
1410 return NAN;
1411 }
1412 }
1414 switch(config_normalize)
1415 {
1416 case MSLP_NONE:
1417 mean = abs_pressure;
1418 break;
1420 case MSLP_INTERNATIONAL:
1421 mean = abs_pressure / \
1422 pow(1.0 - 0.0065*config_altitude/288.15, 9.80665*0.0289644/(8.31447*0.0065));
1423 break;
1425 case MSLP_DEU_WETT:
1426 {
1427 double E; /* humidity */
1428 double x;
1429 if(temp<9.1)
1430 E = 5.6402 * (-0.0916 + exp(0.06*temp) );
1431 else
1432 E = 18.2194 * (1.0463 - exp(-0.0666*temp) );
1433 x = 9.80665 / (287.05 * (temp+273.15 + 0.12*E + 0.0065*config_altitude/2)) * config_altitude;
1434 mean = abs_pressure * exp(x);
1435 }
1436 break;
1438 default:
1439 ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1440 config_normalize);
1441 mean = abs_pressure;
1442 break;
1443 }
1445 DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, method = %d, meanPressure = %lf hPa",
1446 abs_pressure,
1447 config_normalize,
1448 mean);
1450 return mean;
1451 }
1453 /* ------------------------ main plugin callbacks ------------------------ */
1455 /**
1456 * Main plugin configuration callback (using simple config)
1457 *
1458 * @param key configuration key we should process
1459 * @param value configuration value we should process
1460 *
1461 * @return Zero when successful.
1462 */
1463 static int collectd_barometer_config (const char *key, const char *value)
1464 {
1465 DEBUG("barometer: collectd_barometer_config");
1467 if (strcasecmp (key, "Device") == 0)
1468 {
1469 sfree (config_device);
1470 config_device = strdup (value);
1471 }
1472 else if (strcasecmp (key, "Oversampling") == 0)
1473 {
1474 int oversampling_tmp = atoi (value);
1475 if (oversampling_tmp < 1 || oversampling_tmp > 1024)
1476 {
1477 WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
1478 " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for MPL3115) or 1 to 8 (for BMP085).",
1479 oversampling_tmp);
1480 return 1;
1481 }
1482 config_oversample = oversampling_tmp;
1483 }
1484 else if (strcasecmp (key, "Altitude") == 0)
1485 {
1486 config_altitude = atof (value);
1487 }
1488 else if (strcasecmp (key, "Normalization") == 0)
1489 {
1490 int normalize_tmp = atoi (value);
1491 if (normalize_tmp < 0 || normalize_tmp > 2)
1492 {
1493 WARNING ("barometer: collectd_barometer_config: invalid normalization: %d",
1494 normalize_tmp);
1495 return 1;
1496 }
1497 config_normalize = normalize_tmp;
1498 }
1499 else if (strcasecmp (key, "TemperatureSensor") == 0)
1500 {
1501 if(temp_list_add(temp_list, value))
1502 {
1503 return -1;
1504 }
1505 }
1506 else if (strcasecmp (key, "PressureOffset") == 0)
1507 {
1508 config_press_offset = atof(value);
1509 }
1510 else if (strcasecmp (key, "TemperatureOffset") == 0)
1511 {
1512 config_temp_offset = atof(value);
1513 }
1514 else
1515 {
1516 return -1;
1517 }
1519 return 0;
1520 }
1523 /**
1524 * Shutdown callback.
1525 *
1526 * Close I2C and delete all the buffers.
1527 *
1528 * @return Zero when successful (at the moment the only possible outcome)
1529 */
1530 static int collectd_barometer_shutdown(void)
1531 {
1532 DEBUG ("barometer: collectd_barometer_shutdown");
1534 if(sensor_type == Sensor_MPL115)
1535 {
1536 averaging_delete (&pressure_averaging);
1537 averaging_delete (&temperature_averaging);
1539 temp_list_delete(&temp_list);
1540 }
1542 if (i2c_bus_fd > 0)
1543 {
1544 close (i2c_bus_fd);
1545 i2c_bus_fd = -1;
1546 sfree (config_device);
1547 }
1549 return 0;
1550 }
1553 /**
1554 * Plugin read callback for MPL115.
1555 *
1556 * Dispatching will create values:
1557 * - <hostname>/barometer-mpl115/pressure-normalized
1558 * - <hostname>/barometer-mpl115/pressure-absolute
1559 * - <hostname>/barometer-mpl115/temperature
1560 *
1561 * @return Zero when successful.
1562 */
1563 static int MPL115_collectd_barometer_read (void)
1564 {
1565 int result = 0;
1567 double pressure = 0.0;
1568 double temperature = 0.0;
1569 double norm_pressure = 0.0;
1571 value_list_t vl = VALUE_LIST_INIT;
1572 value_t values[1];
1574 DEBUG("barometer: MPL115_collectd_barometer_read");
1576 if (!configured)
1577 {
1578 return -1;
1579 }
1581 /* Rather than delaying init, we will intitialize during first read. This
1582 way at least we have a better chance to have the reference temperature
1583 already available. */
1584 if(!avg_initialized)
1585 {
1586 int i;
1587 for(i=0; i<config_oversample-1; ++i)
1588 {
1589 result = MPL115_read_averaged(&pressure, &temperature);
1590 if(result)
1591 {
1592 ERROR ("barometer: MPL115_collectd_barometer_read - mpl115 read, ignored during init");
1593 }
1594 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i+1, config_oversample-1);
1595 usleep(20000);
1596 }
1597 avg_initialized = 1;
1598 }
1600 result = MPL115_read_averaged(&pressure, &temperature);
1601 if(result)
1602 return result;
1604 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1606 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1607 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1608 sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
1610 vl.values_len = 1;
1611 vl.values = values;
1613 /* dispatch normalized air pressure */
1614 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1615 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1616 values[0].gauge = norm_pressure;
1617 plugin_dispatch_values (&vl);
1619 /* dispatch absolute air pressure */
1620 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1621 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1622 values[0].gauge = pressure;
1623 plugin_dispatch_values (&vl);
1625 /* dispatch sensor temperature */
1626 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1627 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1628 values[0].gauge = temperature;
1629 plugin_dispatch_values (&vl);
1631 return 0;
1632 }
1635 /**
1636 * Plugin read callback for MPL3115.
1637 *
1638 * Dispatching will create values:
1639 * - <hostname>/barometer-mpl3115/pressure-normalized
1640 * - <hostname>/barometer-mpl3115/pressure-absolute
1641 * - <hostname>/barometer-mpl3115/temperature
1642 *
1643 * @return Zero when successful.
1644 */
1645 static int MPL3115_collectd_barometer_read (void)
1646 {
1647 int result = 0;
1649 double pressure = 0.0;
1650 double temperature = 0.0;
1651 double norm_pressure = 0.0;
1653 value_list_t vl = VALUE_LIST_INIT;
1654 value_t values[1];
1656 DEBUG("barometer: MPL3115_collectd_barometer_read");
1658 if (!configured)
1659 {
1660 return -1;
1661 }
1663 result = MPL3115_read(&pressure, &temperature);
1664 if(result)
1665 return result;
1667 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1669 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1670 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1671 sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
1673 vl.values_len = 1;
1674 vl.values = values;
1676 /* dispatch normalized air pressure */
1677 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1678 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1679 values[0].gauge = norm_pressure;
1680 plugin_dispatch_values (&vl);
1682 /* dispatch absolute air pressure */
1683 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1684 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1685 values[0].gauge = pressure;
1686 plugin_dispatch_values (&vl);
1688 /* dispatch sensor temperature */
1689 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1690 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1691 values[0].gauge = temperature;
1692 plugin_dispatch_values (&vl);
1694 return 0;
1695 }
1698 /**
1699 * Plugin read callback for BMP085.
1700 *
1701 * Dispatching will create values:
1702 * - <hostname>/barometer-bmp085/pressure-normalized
1703 * - <hostname>/barometer-bmp085/pressure-absolute
1704 * - <hostname>/barometer-bmp085/temperature
1705 *
1706 * @return Zero when successful.
1707 */
1708 static int BMP085_collectd_barometer_read (void)
1709 {
1710 int result = 0;
1712 double pressure = 0.0;
1713 double temperature = 0.0;
1714 double norm_pressure = 0.0;
1716 value_list_t vl = VALUE_LIST_INIT;
1717 value_t values[1];
1719 DEBUG("barometer: BMP085_collectd_barometer_read");
1721 if (!configured)
1722 {
1723 return -1;
1724 }
1726 result = BMP085_read(&pressure, &temperature);
1727 if(result)
1728 return result;
1730 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1732 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1733 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1734 sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
1736 vl.values_len = 1;
1737 vl.values = values;
1739 /* dispatch normalized air pressure */
1740 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1741 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1742 values[0].gauge = norm_pressure;
1743 plugin_dispatch_values (&vl);
1745 /* dispatch absolute air pressure */
1746 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1747 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1748 values[0].gauge = pressure;
1749 plugin_dispatch_values (&vl);
1751 /* dispatch sensor temperature */
1752 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1753 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1754 values[0].gauge = temperature;
1755 plugin_dispatch_values (&vl);
1757 return 0;
1758 }
1761 /**
1762 * Initialization callback
1763 *
1764 * Check config, initialize I2C bus access, conversion coefficients and averaging
1765 * ring buffers
1766 *
1767 * @return Zero when successful.
1768 */
1769 static int collectd_barometer_init (void)
1770 {
1771 char errbuf[1024];
1773 DEBUG ("barometer: collectd_barometer_init");
1775 if (config_device == NULL)
1776 {
1777 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1778 return -1;
1779 }
1781 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude))
1782 {
1783 ERROR("barometer: collectd_barometer_init no altitude configured " \
1784 "for mean sea level pressure normalization.");
1785 return -1;
1786 }
1788 if (config_normalize == MSLP_DEU_WETT
1789 &&
1790 temp_list == NULL)
1791 {
1792 ERROR("barometer: collectd_barometer_init no temperature reference "\
1793 "configured for mean sea level pressure normalization.");
1794 return -1;
1795 }
1798 i2c_bus_fd = open(config_device, O_RDWR);
1799 if (i2c_bus_fd < 0)
1800 {
1801 ERROR ("barometer: collectd_barometer_init problem opening I2C bus device \"%s\": %s (is loaded mod i2c-dev?)",
1802 config_device,
1803 sstrerror (errno, errbuf, sizeof (errbuf)));
1804 return -1;
1805 }
1807 /* detect sensor type - this will also set slave address */
1808 sensor_type = Detect_sensor_type();
1810 /* init correct sensor type */
1811 switch(sensor_type)
1812 {
1813 /* MPL3115 */
1814 case Sensor_MPL3115:
1815 {
1816 MPL3115_adjust_oversampling();
1818 if(MPL3115_init_sensor())
1819 return -1;
1821 plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
1822 }
1823 break;
1825 /* MPL115 */
1826 case Sensor_MPL115:
1827 {
1828 if (averaging_create (&pressure_averaging, config_oversample))
1829 {
1830 ERROR("barometer: collectd_barometer_init pressure averaging init failed");
1831 return -1;
1832 }
1834 if (averaging_create (&temperature_averaging, config_oversample))
1835 {
1836 ERROR("barometer: collectd_barometer_init temperature averaging init failed");
1837 return -1;
1838 }
1840 if (MPL115_read_coeffs() < 0)
1841 return -1;
1843 plugin_register_read ("barometer", MPL115_collectd_barometer_read);
1844 }
1845 break;
1847 /* BMP085 */
1848 case Sensor_BMP085:
1849 {
1850 BMP085_adjust_oversampling();
1852 if (BMP085_read_coeffs() < 0)
1853 return -1;
1855 plugin_register_read ("barometer", BMP085_collectd_barometer_read);
1856 }
1857 break;
1859 /* anything else -> error */
1860 default:
1861 ERROR("barometer: collectd_barometer_init - no supported sensor found");
1862 return -1;
1863 }
1866 configured = 1;
1867 return 0;
1868 }
1870 /* ------------------------ plugin register / entry point ------------------------ */
1872 /**
1873 * Plugin "entry" - register all callback.
1874 *
1875 */
1876 void module_register (void)
1877 {
1878 plugin_register_config ("barometer",
1879 collectd_barometer_config,
1880 config_keys,
1881 config_keys_num);
1882 plugin_register_init ("barometer", collectd_barometer_init);
1883 plugin_register_shutdown ("barometer", collectd_barometer_shutdown);
1884 }