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 int a;
260 avg->ring_buffer = (long int *) malloc(size * sizeof(*avg));
261 if (avg->ring_buffer == NULL)
262 {
263 ERROR ("barometer: averaging_create - ring buffer allocation of size %d failed",
264 size);
265 return -1;
266 }
268 for (a=0; a<size; ++a)
269 {
270 avg->ring_buffer[a] = 0L;
271 }
273 avg->ring_buffer_size = size;
274 avg->ring_buffer_sum = 0L;
275 avg->ring_buffer_head = 0;
277 return 0;
278 }
281 /**
282 * Delete / free existing averaging buffer
283 *
284 * @param avg pointer to the ring buffer to be deleted
285 */
286 static void averaging_delete(averaging_t * avg)
287 {
288 if (avg->ring_buffer != NULL)
289 {
290 free(avg->ring_buffer);
291 avg->ring_buffer = NULL;
292 }
293 avg->ring_buffer_size = 0;
294 avg->ring_buffer_sum = 0L;
295 avg->ring_buffer_head = 0;
296 }
299 /*
300 * Add new sample to the averaging buffer
301 *
302 * A new averaged value is returned. Note that till the buffer is full
303 * returned value is inaccurate as it is an average of real values and initial
304 * zeros.
305 *
306 * @param avg pointer to the ring buffer
307 * @param sample new sample value
308 *
309 * @return Averaged sample value
310 */
311 static double averaging_add_sample(averaging_t * avg, long int sample)
312 {
313 double result;
315 avg->ring_buffer_sum += sample - avg->ring_buffer[avg->ring_buffer_head];
316 avg->ring_buffer[avg->ring_buffer_head] = sample;
317 avg->ring_buffer_head = (avg->ring_buffer_head+1) % avg->ring_buffer_size;
318 result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
320 DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
321 sample,
322 result);
324 return result;
325 }
328 /* ------------------------ temperature refference ------------------------ */
330 /**
331 * Linked list type of temperature sensor references
332 */
333 typedef struct temperature_list_s {
334 char * sensor_name; /**< sensor name/reference */
335 size_t num_values; /**< number of values (usually one) */
336 _Bool initialized; /**< sensor already provides data */
337 struct temperature_list_s * next; /**< next in the list */
338 } temperature_list_t;
340 static temperature_list_t * temp_list = NULL;
343 /*
344 * Add new sensor to the temperature reference list
345 *
346 * @param list the list
347 * @param sensor reference name (as provided by the config file)
348 *
349 * @return Zero when successful
350 */
351 static int temp_list_add(temperature_list_t * list, const char * sensor)
352 {
353 temperature_list_t * new_temp;
355 new_temp = (temperature_list_t *) malloc(sizeof(*new_temp));
356 if(new_temp == NULL)
357 return -1;
359 new_temp->sensor_name = strdup(sensor);
360 new_temp->initialized = 0;
361 new_temp->num_values = 0;
362 if(new_temp->sensor_name == NULL)
363 {
364 free(new_temp);
365 return -1;
366 }
368 new_temp->next = temp_list;
369 temp_list = new_temp;
370 return 0;
371 }
374 /*
375 * Delete the whole temperature reference list
376 *
377 * @param list the list to be deleted
378 */
379 static void temp_list_delete(temperature_list_t ** list)
380 {
381 temperature_list_t * tmp;
383 while (*list != NULL)
384 {
385 tmp = (*list);
386 (*list) = (*list)->next;
387 free(tmp->sensor_name);
388 free(tmp);
389 tmp = NULL;
390 }
391 }
394 /*
395 * Get reference temperature value
396 *
397 * First initially uc_get_rate_by_name is tried. At the startup due to nondeterministic
398 * order the temperature may not be read yet (then it fails and first measurment gives
399 * only absolute air pressure reading which is acceptable). Once it succedes (should be
400 * second measurement at the latest) we use average of few last readings from
401 * uc_get_history_by_name. It may take few readings to start filling so again we use
402 * uc_get_rate_by_name as a fallback.
403 * The idea is to use basic "noise" filtering (history averaging) across all the values
404 * which given sensor provides (up to given depth). Then we get minimum among
405 * the sensors.
406 *
407 * @param result where the result is stored. When not available NAN is stored.
408 *
409 * @return Zero when successful
410 */
411 static int get_reference_temperature(double * result)
412 {
413 temperature_list_t * list = temp_list;
415 gauge_t * values = NULL; /**< rate values */
416 size_t values_num = 0; /**< number of rate values */
417 int i;
419 gauge_t values_history[REF_TEMP_AVG_NUM];
421 double avg_sum; /**< Value sum for computing average */
422 int avg_num; /**< Number of values for computing average */
423 double average; /**< Resulting value average */
425 *result = NAN;
427 while(list != NULL)
428 {
429 avg_sum = 0.0;
430 avg_num = 0;
432 /* First time need to read current rate to learn how many values are
433 there (typically for temperature it would be just one).
434 We do not expect dynamic changing of number of temperarure values
435 in runtime yet (are there any such cases?). */
436 if(!list->initialized)
437 {
438 if(uc_get_rate_by_name(list->sensor_name,
439 &values,
440 &values_num))
441 {
442 DEBUG ("barometer: get_reference_temperature - rate \"%s\" not found yet",
443 list->sensor_name);
444 list = list->next;
445 continue;
446 }
448 DEBUG ("barometer: get_reference_temperature - initialize \"%s\", %zu vals",
449 list->sensor_name,
450 values_num);
452 list->initialized = 1;
453 list->num_values = values_num;
455 for(i=0; i<values_num; ++i)
456 {
457 DEBUG ("barometer: get_reference_temperature - rate %d: %lf **",
458 i,
459 values[i]);
460 if(!isnan(values[i]))
461 {
462 avg_sum += values[i];
463 ++avg_num;
464 }
465 }
466 free(values);
467 values = NULL;
468 }
470 /* It is OK to get here the first time as well, in the worst case
471 the history will full of NANs. */
472 if(uc_get_history_by_name(list->sensor_name,
473 values_history,
474 REF_TEMP_AVG_NUM,
475 list->num_values))
476 {
477 ERROR ("barometer: get_reference_temperature - history \"%s\" lost",
478 list->sensor_name);
479 list->initialized = 0;
480 list->num_values = 0;
481 list = list->next;
482 continue;
483 }
485 for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
486 {
487 DEBUG ("barometer: get_reference_temperature - history %d: %lf",
488 i,
489 values_history[i]);
490 if(!isnan(values_history[i]))
491 {
492 avg_sum += values_history[i];
493 ++avg_num;
494 }
495 }
497 if(avg_num == 0) /* still no history? fallback to current */
498 {
499 if(uc_get_rate_by_name(list->sensor_name,
500 &values,
501 &values_num))
502 {
503 ERROR ("barometer: get_reference_temperature - rate \"%s\" lost",
504 list->sensor_name);
505 list->initialized = 0;
506 list->num_values = 0;
507 list = list->next;
508 continue;
509 }
511 for(i=0; i<values_num; ++i)
512 {
513 DEBUG ("barometer: get_reference_temperature - rate last %d: %lf **",
514 i,
515 values[i]);
516 if(!isnan(values[i]))
517 {
518 avg_sum += values[i];
519 ++avg_num;
520 }
521 }
522 free(values);
523 values = NULL;
524 }
526 if(avg_num == 0)
527 {
528 ERROR ("barometer: get_reference_temperature - could not read \"%s\"",
529 list->sensor_name);
530 list->initialized = 0;
531 list->num_values = 0;
532 }
533 else
534 {
535 average = avg_sum / (double) avg_num;
536 if(isnan(*result))
537 *result=average;
538 else if(*result>average)
539 *result=average;
540 }
541 list = list->next;
542 } /* while sensor list */
544 if(*result == NAN)
545 {
546 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
547 return -1;
548 }
549 DEBUG ("barometer: get_reference_temperature - temp is %lf", *result);
550 return 0;
551 }
554 /* ------------------------ MPL115 access ------------------------ */
556 /**
557 * Detect presence of a MPL115 pressure sensor.
558 *
559 * Unfortunately there seems to be no ID register so we just try to read first
560 * conversion coefficient from device at MPL115 address and hope it is really
561 * MPL115. We should use this check as the last resort (which would be the typical
562 * case anyway since MPL115 is the least accurate sensor).
563 * As a sideeffect will leave set I2C slave address.
564 *
565 * @return 1 if MPL115, 0 otherwise
566 */
567 static int MPL115_detect(void)
568 {
569 __s32 res;
570 char errbuf[1024];
572 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
573 {
574 ERROR("barometer: MPL115_detect problem setting i2c slave address to 0x%02X: %s",
575 MPL115_I2C_ADDRESS,
576 sstrerror (errno, errbuf, sizeof (errbuf)));
577 return 0 ;
578 }
580 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
581 if(res >= 0)
582 {
583 DEBUG ("barometer: MPL115_detect - positive detection");
584 return 1;
585 }
587 DEBUG ("barometer: MPL115_detect - negative detection");
588 return 0;
589 }
591 /**
592 * Read the MPL115 sensor conversion coefficients.
593 *
594 * These are (device specific) constants so we can read them just once.
595 *
596 * @return Zero when successful
597 */
598 static int MPL115_read_coeffs(void)
599 {
600 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS];
601 int32_t res;
603 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
604 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
605 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
607 char errbuf[1024];
609 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
610 MPL115_ADDR_COEFFS,
611 MPL115_NUM_COEFFS,
612 mpl115_coeffs);
613 if (res < 0)
614 {
615 ERROR ("barometer: MPL115_read_coeffs - problem reading data: %s",
616 sstrerror (errno, errbuf, sizeof (errbuf)));
617 return -1;
618 }
620 /* Using perhaps less elegant/efficient code, but more readable. */
621 /* a0: 16total 1sign 12int 4fract 0pad */
622 sia0MSB = mpl115_coeffs[0];
623 sia0LSB = mpl115_coeffs[1];
624 sia0 = (int16_t) sia0MSB <<8; /* s16 type, Shift to MSB */
625 sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
626 mpl115_coeffA0 = (double) (sia0);
627 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
629 /* b1: 16total 1sign 2int 13fract 0pad */
630 sib1MSB= mpl115_coeffs[2];
631 sib1LSB= mpl115_coeffs[3];
632 sib1 = sib1MSB <<8; /* Shift to MSB */
633 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
634 mpl115_coeffB1 = (double) (sib1);
635 mpl115_coeffB1 /= 8192.0; /* 13 fract */
637 /* b2: 16total 1sign 1int 14fract 0pad */
638 sib2MSB= mpl115_coeffs[4];
639 sib2LSB= mpl115_coeffs[5];
640 sib2 = sib2MSB <<8; /* Shift to MSB */
641 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
642 mpl115_coeffB2 = (double) (sib2);
643 mpl115_coeffB2 /= 16384.0; /* 14 fract */
645 /* c12: 14total 1sign 0int 13fract 9pad */
646 sic12MSB= mpl115_coeffs[6];
647 sic12LSB= mpl115_coeffs[7];
648 sic12 = sic12MSB <<8; /* Shift to MSB only by 8 for MSB */
649 sic12 += sic12LSB & 0x00FF;
650 mpl115_coeffC12 = (double) (sic12);
651 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
652 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
654 /* c11: 11total 1sign 0int 11fract 11pad */
655 sic11MSB= mpl115_coeffs[8];
656 sic11LSB= mpl115_coeffs[9];
657 sic11 = sic11MSB <<8; /* Shift to MSB only by 8 for MSB */
658 sic11 += sic11LSB & 0x00FF;
659 mpl115_coeffC11 = (double) (sic11);
660 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
661 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
663 /* c12: 11total 1sign 0int 10fract 15pad */
664 sic22MSB= mpl115_coeffs[10];
665 sic22LSB= mpl115_coeffs[11];
666 sic22 = sic22MSB <<8; /* Shift to MSB only by 8 for MSB */
667 sic22 += sic22LSB & 0x00FF;
668 mpl115_coeffC22 = (double) (sic22);
669 mpl115_coeffC22 /= 32.0; //16-11=5
670 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
672 DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
673 mpl115_coeffA0,
674 mpl115_coeffB1,
675 mpl115_coeffB2,
676 mpl115_coeffC12,
677 mpl115_coeffC11,
678 mpl115_coeffC22);
679 return 0;
680 }
683 /**
684 * Convert raw adc values to real data using the sensor coefficients.
685 *
686 * @param adc_pressure adc pressure value to be converted
687 * @param adc_temp adc temperature value to be converted
688 * @param pressure computed real pressure
689 * @param temperature computed real temperature
690 */
691 static void MPL115_convert_adc_to_real(double adc_pressure,
692 double adc_temp,
693 double * pressure,
694 double * temperature)
695 {
696 double Pcomp;
697 Pcomp = mpl115_coeffA0 + \
698 (mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
699 (mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
701 *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
702 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
703 DEBUG ("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C",
704 *pressure,
705 *temperature);
706 }
709 /**
710 * Read sensor averegaed measurements
711 *
712 * @param pressure averaged measured pressure
713 * @param temperature averaged measured temperature
714 *
715 * @return Zero when successful
716 */
717 static int MPL115_read_averaged(double * pressure, double * temperature)
718 {
719 uint8_t mpl115_conv[MPL115_NUM_CONV];
720 int8_t res;
721 int retries;
722 int conv_pressure;
723 int conv_temperature;
724 double adc_pressure;
725 double adc_temperature;
726 char errbuf[1024];
728 *pressure = 0.0;
729 *temperature = 0.0;
731 /* start conversion of both temp and presure */
732 retries = MPL115_CONVERSION_RETRIES;
733 while (retries>0)
734 {
735 /* write 1 to start conversion */
736 res = i2c_smbus_write_byte_data (i2c_bus_fd,
737 MPL115_CMD_CONVERT_BOTH,
738 0x01);
739 if (res >= 0)
740 break;
742 --retries;
743 if(retries>0)
744 {
745 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, " \
746 "will retry at most %d more times",
747 sstrerror (errno, errbuf, sizeof (errbuf)),
748 retries);
749 }
750 else
751 {
752 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, "\
753 "too many failed retries",
754 sstrerror (errno, errbuf, sizeof (errbuf)));
755 return -1;
756 }
757 }
759 usleep (10000); /* wait 10ms for the conversion */
761 retries=MPL115_CONVERSION_RETRIES;
762 while (retries>0)
763 {
764 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
765 MPL115_ADDR_CONV,
766 MPL115_NUM_CONV,
767 mpl115_conv);
768 if (res >= 0)
769 break;
771 --retries;
772 if (retries>0)
773 {
774 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
775 "will retry at most %d more times",
776 sstrerror (errno, errbuf, sizeof (errbuf)),
777 retries);
778 }
779 else
780 {
781 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
782 "too many failed retries",
783 sstrerror (errno, errbuf, sizeof (errbuf)));
784 return -1;
785 }
786 }
788 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
789 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
790 DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
791 "raw temperature ADC value = %d",
792 conv_pressure,
793 conv_temperature);
795 adc_pressure = averaging_add_sample (&pressure_averaging, conv_pressure);
796 adc_temperature = averaging_add_sample (&temperature_averaging, conv_temperature);
798 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
800 DEBUG ("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / temperature = %lf, " \
801 "real pressure = %lf hPa / temperature = %lf C",
802 adc_pressure,
803 adc_temperature,
804 *pressure,
805 *temperature);
807 return 0;
808 }
810 /* ------------------------ MPL3115 access ------------------------ */
812 /**
813 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
814 *
815 * As a sideeffect will leave set I2C slave address.
816 *
817 * @return 1 if MPL3115, 0 otherwise
818 */
819 static int MPL3115_detect(void)
820 {
821 __s32 res;
822 char errbuf[1024];
824 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0)
825 {
826 ERROR("barometer: MPL3115_detect problem setting i2c slave address to 0x%02X: %s",
827 MPL3115_I2C_ADDRESS,
828 sstrerror (errno, errbuf, sizeof (errbuf)));
829 return 0 ;
830 }
832 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
833 if(res == MPL3115_WHO_AM_I_RESP)
834 {
835 DEBUG ("barometer: MPL3115_detect - positive detection");
836 return 1;
837 }
839 DEBUG ("barometer: MPL3115_detect - negative detection");
840 return 0;
841 }
843 /**
844 * Adjusts oversampling to values supported by MPL3115
845 *
846 * MPL3115 supports only power of 2 in the range 1 to 128.
847 */
848 static void MPL3115_adjust_oversampling(void)
849 {
850 int new_val = 0;
852 if(config_oversample > 100)
853 {
854 new_val = 128;
855 mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
856 }
857 else if(config_oversample > 48)
858 {
859 new_val = 64;
860 mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
861 }
862 else if(config_oversample > 24)
863 {
864 new_val = 32;
865 mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
866 }
867 else if(config_oversample > 12)
868 {
869 new_val = 16;
870 mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
871 }
872 else if(config_oversample > 6)
873 {
874 new_val = 8;
875 mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
876 }
877 else if(config_oversample > 3)
878 {
879 new_val = 4;
880 mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
881 }
882 else if(config_oversample > 1)
883 {
884 new_val = 2;
885 mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
886 }
887 else
888 {
889 new_val = 1;
890 mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
891 }
893 DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
894 config_oversample,
895 new_val);
896 config_oversample = new_val;
897 }
899 /**
900 * Read sensor averegaed measurements
901 *
902 * @param pressure averaged measured pressure
903 * @param temperature averaged measured temperature
904 *
905 * @return Zero when successful
906 */
907 static int MPL3115_read(double * pressure, double * temperature)
908 {
909 __s32 res;
910 __s32 ctrl ;
911 __u8 data[MPL3115_NUM_CONV_VALS];
912 long int tmp_value = 0;
913 char errbuf[1024];
915 /* Set Active - activate the device from standby */
916 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
917 if (res < 0)
918 {
919 ERROR ("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
920 sstrerror (errno, errbuf, sizeof (errbuf)));
921 return 1;
922 }
923 ctrl = res;
924 res = i2c_smbus_write_byte_data(i2c_bus_fd,
925 MPL3115_REG_CTRL_REG1,
926 ctrl | MPL3115_CTRL_REG1_SBYB);
927 if (res < 0)
928 {
929 ERROR ("barometer: MPL3115_read - problem activating: %s",
930 sstrerror (errno, errbuf, sizeof (errbuf)));
931 return 1;
932 }
934 /* base sleep is 5ms x OST */
935 usleep(5000 * config_oversample);
937 /* check the flags/status if ready */
938 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
939 if (res < 0)
940 {
941 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
942 sstrerror (errno, errbuf, sizeof (errbuf)));
943 return 1;
944 }
946 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
947 {
948 /* try some extra sleep... */
949 usleep(10000);
951 /* ... and repeat the check. The conversion has to finish sooner or later. */
952 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
953 if (res < 0)
954 {
955 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
956 sstrerror (errno, errbuf, sizeof (errbuf)));
957 return 1;
958 }
959 }
961 /* Now read all the data in one block. There is address autoincrement. */
962 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
963 MPL3115_REG_OUT_P_MSB,
964 MPL3115_NUM_CONV_VALS,
965 data);
966 if (res < 0)
967 {
968 ERROR ("barometer: MPL3115_read - cannot read data registers: %s",
969 sstrerror (errno, errbuf, sizeof (errbuf)));
970 return 1;
971 }
973 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
974 *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
975 DEBUG ("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
977 if(data[3] > 0x7F)
978 {
979 data[3] = ~data[3] + 1;
980 *temperature = data[3];
981 *temperature = - *temperature;
982 }
983 else
984 {
985 *temperature = data[3];
986 }
988 *temperature += (double)(data[4]) / 256.0;
989 DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
991 return 0;
992 }
994 /**
995 * Initialize MPL3115 for barometeric measurements
996 *
997 * @return 0 if successful
998 */
999 static int MPL3115_init_sensor(void)
1000 {
1001 __s32 res;
1002 __s8 offset;
1003 char errbuf[1024];
1005 /* Reset the sensor. It will reset immediately without ACKing */
1006 /* the transaction, so no error handling here. */
1007 i2c_smbus_write_byte_data(i2c_bus_fd,
1008 MPL3115_REG_CTRL_REG1,
1009 MPL3115_CTRL_REG1_RST);
1011 /* wait some time for the reset to finish */
1012 usleep(100000);
1014 /* now it should be in standby already so we can go and configure it */
1016 /* Set temperature offset. */
1017 /* result = ADCtemp + offset [C] */
1018 offset = (__s8) (config_temp_offset * 16.0);
1019 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
1020 if (res < 0)
1021 {
1022 ERROR ("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
1023 sstrerror (errno, errbuf, sizeof (errbuf)));
1024 return -1;
1025 }
1027 /* Set pressure offset. */
1028 /* result = ADCpress + offset [hPa] */
1029 offset = (__s8) (config_press_offset * 100.0 / 4.0);
1030 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
1031 if (res < 0)
1032 {
1033 ERROR ("barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
1034 sstrerror (errno, errbuf, sizeof (errbuf)));
1035 return -1;
1036 }
1038 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
1039 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1040 MPL3115_REG_PT_DATA_CFG,
1041 MPL3115_PT_DATA_DREM \
1042 | MPL3115_PT_DATA_PDEF \
1043 | MPL3115_PT_DATA_TDEF);
1044 if (res < 0)
1045 {
1046 ERROR ("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
1047 sstrerror (errno, errbuf, sizeof (errbuf)));
1048 return -1;
1049 }
1051 /* Set to barometer with an OSR */
1052 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1053 MPL3115_REG_CTRL_REG1,
1054 mpl3115_oversample);
1055 if (res < 0)
1056 {
1057 ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
1058 sstrerror (errno, errbuf, sizeof (errbuf)));
1059 return -1;
1060 }
1062 return 0;
1063 }
1065 /* ------------------------ BMP085 access ------------------------ */
1067 /**
1068 * Detect presence of a BMP085 pressure sensor by checking its ID register
1069 *
1070 * As a sideeffect will leave set I2C slave address.
1071 *
1072 * @return 1 if BMP085, 0 otherwise
1073 */
1074 static int BMP085_detect(void)
1075 {
1076 __s32 res;
1077 char errbuf[1024];
1079 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0)
1080 {
1081 ERROR("barometer: BMP085_detect - problem setting i2c slave address to 0x%02X: %s",
1082 BMP085_I2C_ADDRESS,
1083 sstrerror (errno, errbuf, sizeof (errbuf)));
1084 return 0 ;
1085 }
1087 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
1088 if(res == BMP085_CHIP_ID)
1089 {
1090 DEBUG ("barometer: BMP085_detect - positive detection");
1092 /* get version */
1093 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION );
1094 if (res < 0)
1095 {
1096 ERROR("barometer: BMP085_detect - problem checking chip version: %s",
1097 sstrerror (errno, errbuf, sizeof (errbuf)));
1098 return 0 ;
1099 }
1100 DEBUG ("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
1101 res & 0x0f,
1102 (res & 0xf0) >> 4);
1103 return 1;
1104 }
1106 DEBUG ("barometer: BMP085_detect - negative detection");
1107 return 0;
1108 }
1111 /**
1112 * Adjusts oversampling settings to values supported by BMP085
1113 *
1114 * BMP085 supports only 1,2,4 or 8 samples.
1115 */
1116 static void BMP085_adjust_oversampling(void)
1117 {
1118 int new_val = 0;
1120 if( config_oversample > 6 ) /* 8 */
1121 {
1122 new_val = 8;
1123 bmp085_oversampling = 3;
1124 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
1125 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1126 }
1127 else if( config_oversample > 3 ) /* 4 */
1128 {
1129 new_val = 4;
1130 bmp085_oversampling = 2;
1131 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1132 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1133 }
1134 else if( config_oversample > 1 ) /* 2 */
1135 {
1136 new_val = 2;
1137 bmp085_oversampling = 1;
1138 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1139 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1140 }
1141 else /* 1 */
1142 {
1143 new_val = 1;
1144 bmp085_oversampling = 0;
1145 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1146 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1147 }
1149 DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from %d to %d",
1150 config_oversample,
1151 new_val);
1152 config_oversample = new_val;
1153 }
1156 /**
1157 * Read the BMP085 sensor conversion coefficients.
1158 *
1159 * These are (device specific) constants so we can read them just once.
1160 *
1161 * @return Zero when successful
1162 */
1163 static int BMP085_read_coeffs(void)
1164 {
1165 __s32 res;
1166 __u8 coeffs[BMP085_NUM_COEFFS];
1167 char errbuf[1024];
1169 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
1170 BMP085_ADDR_COEFFS,
1171 BMP085_NUM_COEFFS,
1172 coeffs);
1173 if (res < 0)
1174 {
1175 ERROR ("barometer: BMP085_read_coeffs - problem reading data: %s",
1176 sstrerror (errno, errbuf, sizeof (errbuf)));
1177 return -1;
1178 }
1180 bmp085_AC1 = ((int16_t) coeffs[0] <<8) | (int16_t) coeffs[1];
1181 bmp085_AC2 = ((int16_t) coeffs[2] <<8) | (int16_t) coeffs[3];
1182 bmp085_AC3 = ((int16_t) coeffs[4] <<8) | (int16_t) coeffs[5];
1183 bmp085_AC4 = ((uint16_t) coeffs[6] <<8) | (uint16_t) coeffs[7];
1184 bmp085_AC5 = ((uint16_t) coeffs[8] <<8) | (uint16_t) coeffs[9];
1185 bmp085_AC6 = ((uint16_t) coeffs[10] <<8) | (uint16_t) coeffs[11];
1186 bmp085_B1 = ((int16_t) coeffs[12] <<8) | (int16_t) coeffs[13];
1187 bmp085_B2 = ((int16_t) coeffs[14] <<8) | (int16_t) coeffs[15];
1188 bmp085_MB = ((int16_t) coeffs[16] <<8) | (int16_t) coeffs[17];
1189 bmp085_MC = ((int16_t) coeffs[18] <<8) | (int16_t) coeffs[19];
1190 bmp085_MD = ((int16_t) coeffs[20] <<8) | (int16_t) coeffs[21];
1192 DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"\
1193 " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1194 bmp085_AC1,
1195 bmp085_AC2,
1196 bmp085_AC3,
1197 bmp085_AC4,
1198 bmp085_AC5,
1199 bmp085_AC6,
1200 bmp085_B1,
1201 bmp085_B2,
1202 bmp085_MB,
1203 bmp085_MC,
1204 bmp085_MD);
1206 return 0;
1207 }
1210 /**
1211 * Convert raw BMP085 adc values to real data using the sensor coefficients.
1212 *
1213 * @param adc_pressure adc pressure value to be converted
1214 * @param adc_temp adc temperature value to be converted
1215 * @param pressure computed real pressure
1216 * @param temperature computed real temperature
1217 */
1218 static void BMP085_convert_adc_to_real(long adc_pressure,
1219 long adc_temperature,
1220 double * pressure,
1221 double * temperature)
1223 {
1224 long X1, X2, X3;
1225 long B3, B5, B6;
1226 unsigned long B4, B7;
1228 long T;
1229 long P;
1232 /* calculate real temperature */
1233 X1 = ( (adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1234 X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1236 /* B5, T */
1237 B5 = X1 + X2;
1238 T = (B5 + 8) >> 4;
1239 *temperature = (double)T * 0.1;
1241 /* calculate real pressure */
1242 /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept */
1244 /* B6, B3 */
1245 B6 = B5 - 4000;
1246 X1 = ((bmp085_B2 * ((B6 * B6)>>12)) >> 11 );
1247 X2 = (((long)bmp085_AC2 * B6) >> 11);
1248 X3 = X1 + X2;
1249 B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1251 /* B4 */
1252 X1 = (((long)bmp085_AC3*B6) >> 13);
1253 X2 = (bmp085_B1*((B6*B6) >> 12) ) >> 16;
1254 X3 = ((X1 + X2) + 2 ) >> 2;
1255 B4 = ((long)bmp085_AC4* (unsigned long)(X3 + 32768)) >> 15;
1257 /* B7, P */
1258 B7 = (unsigned long)(adc_pressure - B3)*(50000>>bmp085_oversampling);
1259 if( B7 < 0x80000000 )
1260 {
1261 P = (B7 << 1) / B4;
1262 }
1263 else
1264 {
1265 P = (B7/B4) << 1;
1266 }
1267 X1 = (P >> 8) * (P >> 8);
1268 X1 = (X1 * 3038) >> 16;
1269 X2 = ((-7357) * P) >> 16;
1270 P = P + ( ( X1 + X2 + 3791 ) >> 4);
1272 *pressure = P / 100.0; // in [hPa]
1273 DEBUG ("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C",
1274 *pressure,
1275 *temperature);
1276 }
1279 /**
1280 * Read compensated sensor measurements
1281 *
1282 * @param pressure averaged measured pressure
1283 * @param temperature averaged measured temperature
1284 *
1285 * @return Zero when successful
1286 */
1287 static int BMP085_read(double * pressure, double * temperature)
1288 {
1289 __s32 res;
1290 __u8 measBuff[3];
1292 long adc_pressure;
1293 long adc_temperature;
1295 char errbuf[1024];
1297 /* start conversion of temperature */
1298 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1299 BMP085_ADDR_CTRL_REG,
1300 BMP085_CMD_CONVERT_TEMP );
1301 if (res < 0)
1302 {
1303 ERROR ("barometer: BMP085_read - problem requesting temperature conversion: %s",
1304 sstrerror (errno, errbuf, sizeof (errbuf)));
1305 return 1;
1306 }
1308 usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1310 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1311 BMP085_ADDR_CONV,
1312 2,
1313 measBuff);
1314 if (res < 0)
1315 {
1316 ERROR ("barometer: BMP085_read - problem reading temperature data: %s",
1317 sstrerror (errno, errbuf, sizeof (errbuf)));
1318 return 1;
1319 }
1321 adc_temperature = ( (unsigned short)measBuff[0] << 8 ) + measBuff[1];
1324 /* get presure */
1325 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1326 BMP085_ADDR_CTRL_REG,
1327 bmp085_cmdCnvPress );
1328 if (res < 0)
1329 {
1330 ERROR ("barometer: BMP085_read - problem requesting pressure conversion: %s",
1331 sstrerror (errno, errbuf, sizeof (errbuf)));
1332 return 1;
1333 }
1335 usleep(bmp085_timeCnvPress); /* wait for the conversion */
1337 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1338 BMP085_ADDR_CONV,
1339 3,
1340 measBuff );
1341 if (res < 0)
1342 {
1343 ERROR ("barometer: BMP085_read - problem reading pressure data: %s",
1344 sstrerror (errno, errbuf, sizeof (errbuf)));
1345 return 1;
1346 }
1348 adc_pressure = (long)((((ulong)measBuff[0]<<16) | ((ulong)measBuff[1]<<8) | (ulong)measBuff[2] ) >> (8 - bmp085_oversampling));
1351 DEBUG ("barometer: BMP085_read - raw pressure ADC value = %ld, " \
1352 "raw temperature ADC value = %ld",
1353 adc_pressure,
1354 adc_temperature);
1356 BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
1358 return 0;
1359 }
1363 /* ------------------------ Sensor detection ------------------------ */
1364 /**
1365 * Detect presence of a supported sensor.
1366 *
1367 * As a sideeffect will leave set I2C slave address.
1368 * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1369 * first sensor beeing found.
1370 *
1371 * @return detected sensor type
1372 */
1373 enum Sensor_type Detect_sensor_type(void)
1374 {
1375 if(BMP085_detect())
1376 return Sensor_BMP085;
1378 else if(MPL3115_detect())
1379 return Sensor_MPL3115;
1381 else if(MPL115_detect())
1382 return Sensor_MPL115;
1384 return Sensor_none;
1385 }
1387 /* ------------------------ Common functionality ------------------------ */
1389 /**
1390 * Convert absolute pressure (in hPa) to mean sea level pressure
1391 *
1392 * Implemented methods are:
1393 * - MSLP_NONE - no converions, returns absolute pressure
1394 *
1395 * - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1396 * Requires #config_altitude
1397 *
1398 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1399 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1400 * Requires both #config_altitude and temperature reference(s).
1401 *
1402 * @param abs_pressure absloute pressure to be converted
1403 *
1404 * @return mean sea level pressure if successful, NAN otherwise
1405 */
1406 static double abs_to_mean_sea_level_pressure(double abs_pressure)
1407 {
1408 double mean = -1.0;
1409 double temp = 0.0;
1410 int result = 0;
1412 if (config_normalize >= MSLP_DEU_WETT)
1413 {
1414 result = get_reference_temperature(&temp);
1415 if(result)
1416 {
1417 return NAN;
1418 }
1419 }
1421 switch(config_normalize)
1422 {
1423 case MSLP_NONE:
1424 mean = abs_pressure;
1425 break;
1427 case MSLP_INTERNATIONAL:
1428 mean = abs_pressure / \
1429 pow(1.0 - 0.0065*config_altitude/288.15, 9.80665*0.0289644/(8.31447*0.0065));
1430 break;
1432 case MSLP_DEU_WETT:
1433 {
1434 double E; /* humidity */
1435 double x;
1436 if(temp<9.1)
1437 E = 5.6402 * (-0.0916 + exp(0.06*temp) );
1438 else
1439 E = 18.2194 * (1.0463 - exp(-0.0666*temp) );
1440 x = 9.80665 / (287.05 * (temp+273.15 + 0.12*E + 0.0065*config_altitude/2)) * config_altitude;
1441 mean = abs_pressure * exp(x);
1442 }
1443 break;
1445 default:
1446 ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1447 config_normalize);
1448 mean = abs_pressure;
1449 break;
1450 }
1452 DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, method = %d, meanPressure = %lf hPa",
1453 abs_pressure,
1454 config_normalize,
1455 mean);
1457 return mean;
1458 }
1460 /* ------------------------ main plugin callbacks ------------------------ */
1462 /**
1463 * Main plugin configuration callback (using simple config)
1464 *
1465 * @param key configuration key we should process
1466 * @param value configuration value we should process
1467 *
1468 * @return Zero when successful.
1469 */
1470 static int collectd_barometer_config (const char *key, const char *value)
1471 {
1472 DEBUG("barometer: collectd_barometer_config");
1474 if (strcasecmp (key, "Device") == 0)
1475 {
1476 sfree (config_device);
1477 config_device = strdup (value);
1478 }
1479 else if (strcasecmp (key, "Oversampling") == 0)
1480 {
1481 int oversampling_tmp = atoi (value);
1482 if (oversampling_tmp < 1 || oversampling_tmp > 1024)
1483 {
1484 WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
1485 " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for MPL3115) or 1 to 8 (for BMP085).",
1486 oversampling_tmp);
1487 return 1;
1488 }
1489 config_oversample = oversampling_tmp;
1490 }
1491 else if (strcasecmp (key, "Altitude") == 0)
1492 {
1493 config_altitude = atof (value);
1494 }
1495 else if (strcasecmp (key, "Normalization") == 0)
1496 {
1497 int normalize_tmp = atoi (value);
1498 if (normalize_tmp < 0 || normalize_tmp > 2)
1499 {
1500 WARNING ("barometer: collectd_barometer_config: invalid normalization: %d",
1501 normalize_tmp);
1502 return 1;
1503 }
1504 config_normalize = normalize_tmp;
1505 }
1506 else if (strcasecmp (key, "TemperatureSensor") == 0)
1507 {
1508 if(temp_list_add(temp_list, value))
1509 {
1510 return -1;
1511 }
1512 }
1513 else if (strcasecmp (key, "PressureOffset") == 0)
1514 {
1515 config_press_offset = atof(value);
1516 }
1517 else if (strcasecmp (key, "TemperatureOffset") == 0)
1518 {
1519 config_temp_offset = atof(value);
1520 }
1521 else
1522 {
1523 return -1;
1524 }
1526 return 0;
1527 }
1530 /**
1531 * Shutdown callback.
1532 *
1533 * Close I2C and delete all the buffers.
1534 *
1535 * @return Zero when successful (at the moment the only possible outcome)
1536 */
1537 static int collectd_barometer_shutdown(void)
1538 {
1539 DEBUG ("barometer: collectd_barometer_shutdown");
1541 if(sensor_type == Sensor_MPL115)
1542 {
1543 averaging_delete (&pressure_averaging);
1544 averaging_delete (&temperature_averaging);
1546 temp_list_delete(&temp_list);
1547 }
1549 if (i2c_bus_fd > 0)
1550 {
1551 close (i2c_bus_fd);
1552 i2c_bus_fd = -1;
1553 sfree (config_device);
1554 }
1556 return 0;
1557 }
1560 /**
1561 * Plugin read callback for MPL115.
1562 *
1563 * Dispatching will create values:
1564 * - <hostname>/barometer-mpl115/pressure-normalized
1565 * - <hostname>/barometer-mpl115/pressure-absolute
1566 * - <hostname>/barometer-mpl115/temperature
1567 *
1568 * @return Zero when successful.
1569 */
1570 static int MPL115_collectd_barometer_read (void)
1571 {
1572 int result = 0;
1574 double pressure = 0.0;
1575 double temperature = 0.0;
1576 double norm_pressure = 0.0;
1578 value_list_t vl = VALUE_LIST_INIT;
1579 value_t values[1];
1581 DEBUG("barometer: MPL115_collectd_barometer_read");
1583 if (!configured)
1584 {
1585 return -1;
1586 }
1588 /* Rather than delaying init, we will intitialize during first read. This
1589 way at least we have a better chance to have the reference temperature
1590 already available. */
1591 if(!avg_initialized)
1592 {
1593 int i;
1594 for(i=0; i<config_oversample-1; ++i)
1595 {
1596 result = MPL115_read_averaged(&pressure, &temperature);
1597 if(result)
1598 {
1599 ERROR ("barometer: MPL115_collectd_barometer_read - mpl115 read, ignored during init");
1600 }
1601 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i+1, config_oversample-1);
1602 usleep(20000);
1603 }
1604 avg_initialized = 1;
1605 }
1607 result = MPL115_read_averaged(&pressure, &temperature);
1608 if(result)
1609 return result;
1611 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1613 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1614 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1615 sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
1617 vl.values_len = 1;
1618 vl.values = values;
1620 /* dispatch normalized air pressure */
1621 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1622 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1623 values[0].gauge = norm_pressure;
1624 plugin_dispatch_values (&vl);
1626 /* dispatch absolute air pressure */
1627 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1628 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1629 values[0].gauge = pressure;
1630 plugin_dispatch_values (&vl);
1632 /* dispatch sensor temperature */
1633 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1634 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1635 values[0].gauge = temperature;
1636 plugin_dispatch_values (&vl);
1638 return 0;
1639 }
1642 /**
1643 * Plugin read callback for MPL3115.
1644 *
1645 * Dispatching will create values:
1646 * - <hostname>/barometer-mpl3115/pressure-normalized
1647 * - <hostname>/barometer-mpl3115/pressure-absolute
1648 * - <hostname>/barometer-mpl3115/temperature
1649 *
1650 * @return Zero when successful.
1651 */
1652 static int MPL3115_collectd_barometer_read (void)
1653 {
1654 int result = 0;
1656 double pressure = 0.0;
1657 double temperature = 0.0;
1658 double norm_pressure = 0.0;
1660 value_list_t vl = VALUE_LIST_INIT;
1661 value_t values[1];
1663 DEBUG("barometer: MPL3115_collectd_barometer_read");
1665 if (!configured)
1666 {
1667 return -1;
1668 }
1670 result = MPL3115_read(&pressure, &temperature);
1671 if(result)
1672 return result;
1674 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1676 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1677 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1678 sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
1680 vl.values_len = 1;
1681 vl.values = values;
1683 /* dispatch normalized air pressure */
1684 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1685 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1686 values[0].gauge = norm_pressure;
1687 plugin_dispatch_values (&vl);
1689 /* dispatch absolute air pressure */
1690 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1691 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1692 values[0].gauge = pressure;
1693 plugin_dispatch_values (&vl);
1695 /* dispatch sensor temperature */
1696 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1697 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1698 values[0].gauge = temperature;
1699 plugin_dispatch_values (&vl);
1701 return 0;
1702 }
1705 /**
1706 * Plugin read callback for BMP085.
1707 *
1708 * Dispatching will create values:
1709 * - <hostname>/barometer-bmp085/pressure-normalized
1710 * - <hostname>/barometer-bmp085/pressure-absolute
1711 * - <hostname>/barometer-bmp085/temperature
1712 *
1713 * @return Zero when successful.
1714 */
1715 static int BMP085_collectd_barometer_read (void)
1716 {
1717 int result = 0;
1719 double pressure = 0.0;
1720 double temperature = 0.0;
1721 double norm_pressure = 0.0;
1723 value_list_t vl = VALUE_LIST_INIT;
1724 value_t values[1];
1726 DEBUG("barometer: BMP085_collectd_barometer_read");
1728 if (!configured)
1729 {
1730 return -1;
1731 }
1733 result = BMP085_read(&pressure, &temperature);
1734 if(result)
1735 return result;
1737 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1739 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1740 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1741 sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
1743 vl.values_len = 1;
1744 vl.values = values;
1746 /* dispatch normalized air pressure */
1747 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1748 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1749 values[0].gauge = norm_pressure;
1750 plugin_dispatch_values (&vl);
1752 /* dispatch absolute air pressure */
1753 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1754 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1755 values[0].gauge = pressure;
1756 plugin_dispatch_values (&vl);
1758 /* dispatch sensor temperature */
1759 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1760 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1761 values[0].gauge = temperature;
1762 plugin_dispatch_values (&vl);
1764 return 0;
1765 }
1768 /**
1769 * Initialization callback
1770 *
1771 * Check config, initialize I2C bus access, conversion coefficients and averaging
1772 * ring buffers
1773 *
1774 * @return Zero when successful.
1775 */
1776 static int collectd_barometer_init (void)
1777 {
1778 char errbuf[1024];
1780 DEBUG ("barometer: collectd_barometer_init");
1782 if (config_device == NULL)
1783 {
1784 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1785 return -1;
1786 }
1788 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude))
1789 {
1790 ERROR("barometer: collectd_barometer_init no altitude configured " \
1791 "for mean sea level pressure normalization.");
1792 return -1;
1793 }
1795 if (config_normalize == MSLP_DEU_WETT
1796 &&
1797 temp_list == NULL)
1798 {
1799 ERROR("barometer: collectd_barometer_init no temperature reference "\
1800 "configured for mean sea level pressure normalization.");
1801 return -1;
1802 }
1805 i2c_bus_fd = open(config_device, O_RDWR);
1806 if (i2c_bus_fd < 0)
1807 {
1808 ERROR ("barometer: collectd_barometer_init problem opening I2C bus device \"%s\": %s (is loaded mod i2c-dev?)",
1809 config_device,
1810 sstrerror (errno, errbuf, sizeof (errbuf)));
1811 return -1;
1812 }
1814 /* detect sensor type - this will also set slave address */
1815 sensor_type = Detect_sensor_type();
1817 /* init correct sensor type */
1818 switch(sensor_type)
1819 {
1820 /* MPL3115 */
1821 case Sensor_MPL3115:
1822 {
1823 MPL3115_adjust_oversampling();
1825 if(MPL3115_init_sensor())
1826 return -1;
1828 plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
1829 }
1830 break;
1832 /* MPL115 */
1833 case Sensor_MPL115:
1834 {
1835 if (averaging_create (&pressure_averaging, config_oversample))
1836 {
1837 ERROR("barometer: collectd_barometer_init pressure averaging init failed");
1838 return -1;
1839 }
1841 if (averaging_create (&temperature_averaging, config_oversample))
1842 {
1843 ERROR("barometer: collectd_barometer_init temperature averaging init failed");
1844 return -1;
1845 }
1847 if (MPL115_read_coeffs() < 0)
1848 return -1;
1850 plugin_register_read ("barometer", MPL115_collectd_barometer_read);
1851 }
1852 break;
1854 /* BMP085 */
1855 case Sensor_BMP085:
1856 {
1857 BMP085_adjust_oversampling();
1859 if (BMP085_read_coeffs() < 0)
1860 return -1;
1862 plugin_register_read ("barometer", BMP085_collectd_barometer_read);
1863 }
1864 break;
1866 /* anything else -> error */
1867 default:
1868 ERROR("barometer: collectd_barometer_init - no supported sensor found");
1869 return -1;
1870 }
1873 configured = 1;
1874 return 0;
1875 }
1877 /* ------------------------ plugin register / entry point ------------------------ */
1879 /**
1880 * Plugin "entry" - register all callback.
1881 *
1882 */
1883 void module_register (void)
1884 {
1885 plugin_register_config ("barometer",
1886 collectd_barometer_config,
1887 config_keys,
1888 config_keys_num);
1889 plugin_register_init ("barometer", collectd_barometer_init);
1890 plugin_register_shutdown ("barometer", collectd_barometer_shutdown);
1891 }