1 /**
2 * collectd - src/barometer.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; only version 2.1 of the License is
7 * applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Tomas Menzl
20 **/
22 #include "collectd.h"
24 #include "common.h"
25 #include "utils_cache.h"
26 #include "plugin.h"
28 #include <stdint.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <linux/i2c-dev.h>
32 #include <math.h>
34 /* ------------ MPL115 defines ------------ */
35 /* I2C address of the MPL115 sensor */
36 #define MPL115_I2C_ADDRESS 0x60
38 /* register addresses */
39 #define MPL115_ADDR_CONV 0x00
40 #define MPL115_ADDR_COEFFS 0x04
42 /* register sizes */
43 #define MPL115_NUM_CONV 4
44 #define MPL115_NUM_COEFFS 12
46 /* commands / addresses */
47 #define MPL115_CMD_CONVERT_PRESS 0x10
48 #define MPL115_CMD_CONVERT_TEMP 0x11
49 #define MPL115_CMD_CONVERT_BOTH 0x12
51 #define MPL115_CONVERSION_RETRIES 5
54 /* ------------ MPL3115 defines ------------ */
55 /* MPL3115 I2C address */
56 #define MPL3115_I2C_ADDRESS 0x60
58 /* register addresses (only the interesting ones) */
59 #define MPL3115_REG_STATUS 0x00
60 #define MPL3115_REG_OUT_P_MSB 0x01
61 #define MPL3115_REG_OUT_P_CSB 0x02
62 #define MPL3115_REG_OUT_P_LSB 0x03
63 #define MPL3115_REG_OUT_T_MSB 0x04
64 #define MPL3115_REG_OUT_T_LSB 0x05
65 #define MPL3115_REG_DR_STATUS 0x06
66 #define MPL3115_REG_WHO_AM_I 0x0C
67 #define MPL3115_REG_SYSMOD 0x11
68 #define MPL3115_REG_PT_DATA_CFG 0x13
69 #define MPL3115_REG_BAR_IN_MSB 0x14
70 #define MPL3115_REG_BAR_IN_LSB 0x15
71 #define MPL3115_REG_CTRL_REG1 0x26
72 #define MPL3115_REG_CTRL_REG2 0x27
73 #define MPL3115_REG_CTRL_REG3 0x28
74 #define MPL3115_REG_CTRL_REG4 0x29
75 #define MPL3115_REG_CTRL_REG5 0x2A
76 #define MPL3115_REG_OFF_P 0x2B
77 #define MPL3115_REG_OFF_T 0x2C
78 #define MPL3115_REG_OFF_H 0x2D
80 /* Register values, masks */
81 #define MPL3115_WHO_AM_I_RESP 0xC4
83 #define MPL3115_PT_DATA_DREM 0x04
84 #define MPL3115_PT_DATA_PDEF 0x02
85 #define MPL3115_PT_DATA_TDEF 0x01
87 #define MPL3115_DR_STATUS_TDR 0x02
88 #define MPL3115_DR_STATUS_PDR 0x04
89 #define MPL3115_DR_STATUS_PTDR 0x08
90 #define MPL3115_DR_STATUS_DR (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
92 #define MPL3115_DR_STATUS_TOW 0x20
93 #define MPL3115_DR_STATUS_POW 0x40
94 #define MPL3115_DR_STATUS_PTOW 0x80
96 #define MPL3115_CTRL_REG1_ALT 0x80
97 #define MPL3115_CTRL_REG1_RAW 0x40
98 #define MPL3115_CTRL_REG1_OST_MASK 0x38
99 #define MPL3115_CTRL_REG1_OST_1 0x00
100 #define MPL3115_CTRL_REG1_OST_2 0x08
101 #define MPL3115_CTRL_REG1_OST_4 0x10
102 #define MPL3115_CTRL_REG1_OST_8 0x18
103 #define MPL3115_CTRL_REG1_OST_16 0x20
104 #define MPL3115_CTRL_REG1_OST_32 0x28
105 #define MPL3115_CTRL_REG1_OST_64 0x30
106 #define MPL3115_CTRL_REG1_OST_128 0x38
107 #define MPL3115_CTRL_REG1_RST 0x04
108 #define MPL3115_CTRL_REG1_OST 0x02
109 #define MPL3115_CTRL_REG1_SBYB 0x01
110 #define MPL3115_CTRL_REG1_SBYB_MASK 0xFE
112 #define MPL3115_NUM_CONV_VALS 5
115 /* ------------ BMP085 defines ------------ */
116 /* I2C address of the BMP085 sensor */
117 #define BMP085_I2C_ADDRESS 0x77
119 /* register addresses */
120 #define BMP085_ADDR_ID_REG 0xD0
121 #define BMP085_ADDR_VERSION 0xD1
123 #define BMP085_ADDR_CONV 0xF6
125 #define BMP085_ADDR_CTRL_REG 0xF4
126 #define BMP085_ADDR_COEFFS 0xAA
128 /* register sizes */
129 #define BMP085_NUM_COEFFS 22
131 /* commands, values */
132 #define BMP085_CHIP_ID 0x55
134 #define BMP085_CMD_CONVERT_TEMP 0x2E
136 #define BMP085_CMD_CONVERT_PRESS_0 0x34
137 #define BMP085_CMD_CONVERT_PRESS_1 0x74
138 #define BMP085_CMD_CONVERT_PRESS_2 0xB4
139 #define BMP085_CMD_CONVERT_PRESS_3 0xF4
141 /* in us */
142 #define BMP085_TIME_CNV_TEMP 4500
144 #define BMP085_TIME_CNV_PRESS_0 4500
145 #define BMP085_TIME_CNV_PRESS_1 7500
146 #define BMP085_TIME_CNV_PRESS_2 13500
147 #define BMP085_TIME_CNV_PRESS_3 25500
150 /* ------------ Normalization ------------ */
151 /* Mean sea level pressure normalization methods */
152 #define MSLP_NONE 0
153 #define MSLP_INTERNATIONAL 1
154 #define MSLP_DEU_WETT 2
156 /** Temperature reference history depth for averaging. See #get_reference_temperature */
157 #define REF_TEMP_AVG_NUM 5
160 /* ------------------------------------------ */
162 /** Supported sensor types */
163 enum Sensor_type {
164 Sensor_none = 0,
165 Sensor_MPL115,
166 Sensor_MPL3115,
167 Sensor_BMP085
168 };
170 static const char *config_keys[] =
171 {
172 "Device",
173 "Oversampling",
174 "PressureOffset", /**< only for MPL3115 */
175 "TemperatureOffset", /**< only for MPL3115 */
176 "Altitude",
177 "Normalization",
178 "TemperatureSensor"
179 };
181 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
183 static char * config_device = NULL; /**< I2C bus device */
184 static int config_oversample = 1; /**< averaging window */
186 static double config_press_offset = 0.0; /**< pressure offset */
187 static double config_temp_offset = 0.0; /**< temperature offset */
189 static double config_altitude = NAN; /**< altitude */
190 static int config_normalize = 0; /**< normalization method */
192 static _Bool configured = 0; /**< the whole plugin config status */
194 static int i2c_bus_fd = -1; /**< I2C bus device FD */
196 static enum Sensor_type sensor_type = Sensor_none; /**< detected/used sensor type */
198 static __s32 mpl3115_oversample = 0; /**< MPL3115 CTRL1 oversample setting */
200 // BMP085 configuration
201 static unsigned bmp085_oversampling; /**< BMP085 oversampling (0-3) */
202 static unsigned long bmp085_timeCnvPress; /**< BMP085 conversion time for pressure in us */
203 static __u8 bmp085_cmdCnvPress; /**< BMP085 pressure conversion command */
206 /* MPL115 conversion coefficients */
207 static double mpl115_coeffA0;
208 static double mpl115_coeffB1;
209 static double mpl115_coeffB2;
210 static double mpl115_coeffC12;
211 static double mpl115_coeffC11;
212 static double mpl115_coeffC22;
214 /* BMP085 conversion coefficients */
215 static short bmp085_AC1;
216 static short bmp085_AC2;
217 static short bmp085_AC3;
218 static unsigned short bmp085_AC4;
219 static unsigned short bmp085_AC5;
220 static unsigned short bmp085_AC6;
221 static short bmp085_B1;
222 static short bmp085_B2;
223 static short bmp085_MB;
224 static short bmp085_MC;
225 static short bmp085_MD;
229 /* ------------------------ averaging ring buffer ------------------------ */
230 /* Used only for MPL115. MPL3115 supports real oversampling in the device so */
231 /* no need for any postprocessing. */
233 static _Bool avg_initialized = 0; /**< already initialized by real values */
235 typedef struct averaging_s {
236 long int * ring_buffer;
237 int ring_buffer_size;
238 long int ring_buffer_sum;
239 int ring_buffer_head;
240 } averaging_t;
243 static averaging_t pressure_averaging = { NULL, 0, 0L, 0 };
244 static averaging_t temperature_averaging = { NULL, 0, 0L, 0 };
247 /**
248 * Create / allocate averaging buffer
249 *
250 * The buffer is initialized with zeros.
251 *
252 * @param avg pointer to ring buffer to be allocated
253 * @param size requested buffer size
254 *
255 * @return Zero when successful
256 */
257 static int averaging_create(averaging_t *avg, int size)
258 {
259 avg->ring_buffer = calloc ((size_t) size, sizeof (*avg->ring_buffer));
260 if (avg->ring_buffer == NULL)
261 {
262 ERROR ("barometer: averaging_create - ring buffer allocation of size %d failed",
263 size);
264 return -1;
265 }
267 avg->ring_buffer_size = size;
268 avg->ring_buffer_sum = 0L;
269 avg->ring_buffer_head = 0;
271 return 0;
272 }
275 /**
276 * Delete / free existing averaging buffer
277 *
278 * @param avg pointer to the ring buffer to be deleted
279 */
280 static void averaging_delete(averaging_t * avg)
281 {
282 if (avg->ring_buffer != NULL)
283 {
284 free(avg->ring_buffer);
285 avg->ring_buffer = NULL;
286 }
287 avg->ring_buffer_size = 0;
288 avg->ring_buffer_sum = 0L;
289 avg->ring_buffer_head = 0;
290 }
293 /*
294 * Add new sample to the averaging buffer
295 *
296 * A new averaged value is returned. Note that till the buffer is full
297 * returned value is inaccurate as it is an average of real values and initial
298 * zeros.
299 *
300 * @param avg pointer to the ring buffer
301 * @param sample new sample value
302 *
303 * @return Averaged sample value
304 */
305 static double averaging_add_sample(averaging_t * avg, long int sample)
306 {
307 double result;
309 avg->ring_buffer_sum += sample - avg->ring_buffer[avg->ring_buffer_head];
310 avg->ring_buffer[avg->ring_buffer_head] = sample;
311 avg->ring_buffer_head = (avg->ring_buffer_head+1) % avg->ring_buffer_size;
312 result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
314 DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
315 sample,
316 result);
318 return result;
319 }
322 /* ------------------------ temperature refference ------------------------ */
324 /**
325 * Linked list type of temperature sensor references
326 */
327 typedef struct temperature_list_s {
328 char * sensor_name; /**< sensor name/reference */
329 size_t num_values; /**< number of values (usually one) */
330 _Bool initialized; /**< sensor already provides data */
331 struct temperature_list_s * next; /**< next in the list */
332 } temperature_list_t;
334 static temperature_list_t * temp_list = NULL;
337 /*
338 * Add new sensor to the temperature reference list
339 *
340 * @param list the list
341 * @param sensor reference name (as provided by the config file)
342 *
343 * @return Zero when successful
344 */
345 static int temp_list_add(temperature_list_t * list, const char * sensor)
346 {
347 temperature_list_t *new_temp;
349 new_temp = malloc(sizeof (*new_temp));
350 if(new_temp == NULL)
351 return -1;
353 new_temp->sensor_name = strdup(sensor);
354 new_temp->initialized = 0;
355 new_temp->num_values = 0;
356 if(new_temp->sensor_name == NULL)
357 {
358 free(new_temp);
359 return -1;
360 }
362 new_temp->next = temp_list;
363 temp_list = new_temp;
364 return 0;
365 }
368 /*
369 * Delete the whole temperature reference list
370 *
371 * @param list the list to be deleted
372 */
373 static void temp_list_delete(temperature_list_t ** list)
374 {
375 temperature_list_t * tmp;
377 while (*list != NULL)
378 {
379 tmp = (*list);
380 (*list) = (*list)->next;
381 free(tmp->sensor_name);
382 free(tmp);
383 tmp = NULL;
384 }
385 }
388 /*
389 * Get reference temperature value
390 *
391 * First initially uc_get_rate_by_name is tried. At the startup due to nondeterministic
392 * order the temperature may not be read yet (then it fails and first measurment gives
393 * only absolute air pressure reading which is acceptable). Once it succedes (should be
394 * second measurement at the latest) we use average of few last readings from
395 * uc_get_history_by_name. It may take few readings to start filling so again we use
396 * uc_get_rate_by_name as a fallback.
397 * The idea is to use basic "noise" filtering (history averaging) across all the values
398 * which given sensor provides (up to given depth). Then we get minimum among
399 * the sensors.
400 *
401 * @param result where the result is stored. When not available NAN is stored.
402 *
403 * @return Zero when successful
404 */
405 static int get_reference_temperature(double * result)
406 {
407 temperature_list_t * list = temp_list;
409 gauge_t * values = NULL; /**< rate values */
410 size_t values_num = 0; /**< number of rate values */
411 size_t i;
413 gauge_t values_history[REF_TEMP_AVG_NUM];
415 double avg_sum; /**< Value sum for computing average */
416 int avg_num; /**< Number of values for computing average */
417 double average; /**< Resulting value average */
419 *result = NAN;
421 while(list != NULL)
422 {
423 avg_sum = 0.0;
424 avg_num = 0;
426 /* First time need to read current rate to learn how many values are
427 there (typically for temperature it would be just one).
428 We do not expect dynamic changing of number of temperarure values
429 in runtime yet (are there any such cases?). */
430 if(!list->initialized)
431 {
432 if(uc_get_rate_by_name(list->sensor_name,
433 &values,
434 &values_num))
435 {
436 DEBUG ("barometer: get_reference_temperature - rate \"%s\" not found yet",
437 list->sensor_name);
438 list = list->next;
439 continue;
440 }
442 DEBUG ("barometer: get_reference_temperature - initialize \"%s\", %zu vals",
443 list->sensor_name,
444 values_num);
446 list->initialized = 1;
447 list->num_values = values_num;
449 for(i=0; i<values_num; ++i)
450 {
451 DEBUG ("barometer: get_reference_temperature - rate %zu: %lf **",
452 i, 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 %zu: %lf",
481 i, values_history[i]);
482 if(!isnan(values_history[i]))
483 {
484 avg_sum += values_history[i];
485 ++avg_num;
486 }
487 }
489 if(avg_num == 0) /* still no history? fallback to current */
490 {
491 if(uc_get_rate_by_name(list->sensor_name,
492 &values,
493 &values_num))
494 {
495 ERROR ("barometer: get_reference_temperature - rate \"%s\" lost",
496 list->sensor_name);
497 list->initialized = 0;
498 list->num_values = 0;
499 list = list->next;
500 continue;
501 }
503 for(i=0; i<values_num; ++i)
504 {
505 DEBUG ("barometer: get_reference_temperature - rate last %zu: %lf **",
506 i, values[i]);
507 if(!isnan(values[i]))
508 {
509 avg_sum += values[i];
510 ++avg_num;
511 }
512 }
513 free(values);
514 values = NULL;
515 }
517 if(avg_num == 0)
518 {
519 ERROR ("barometer: get_reference_temperature - could not read \"%s\"",
520 list->sensor_name);
521 list->initialized = 0;
522 list->num_values = 0;
523 }
524 else
525 {
526 average = avg_sum / (double) avg_num;
527 if(isnan(*result))
528 *result=average;
529 else if(*result>average)
530 *result=average;
531 }
532 list = list->next;
533 } /* while sensor list */
535 if(*result == NAN)
536 {
537 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
538 return -1;
539 }
540 DEBUG ("barometer: get_reference_temperature - temp is %lf", *result);
541 return 0;
542 }
545 /* ------------------------ MPL115 access ------------------------ */
547 /**
548 * Detect presence of a MPL115 pressure sensor.
549 *
550 * Unfortunately there seems to be no ID register so we just try to read first
551 * conversion coefficient from device at MPL115 address and hope it is really
552 * MPL115. We should use this check as the last resort (which would be the typical
553 * case anyway since MPL115 is the least accurate sensor).
554 * As a sideeffect will leave set I2C slave address.
555 *
556 * @return 1 if MPL115, 0 otherwise
557 */
558 static int MPL115_detect(void)
559 {
560 __s32 res;
561 char errbuf[1024];
563 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
564 {
565 ERROR("barometer: MPL115_detect problem setting i2c slave address to 0x%02X: %s",
566 MPL115_I2C_ADDRESS,
567 sstrerror (errno, errbuf, sizeof (errbuf)));
568 return 0 ;
569 }
571 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL115_ADDR_COEFFS);
572 if(res >= 0)
573 {
574 DEBUG ("barometer: MPL115_detect - positive detection");
575 return 1;
576 }
578 DEBUG ("barometer: MPL115_detect - negative detection");
579 return 0;
580 }
582 /**
583 * Read the MPL115 sensor conversion coefficients.
584 *
585 * These are (device specific) constants so we can read them just once.
586 *
587 * @return Zero when successful
588 */
589 static int MPL115_read_coeffs(void)
590 {
591 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS] = { 0 };
592 int32_t res;
594 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
595 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
596 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
598 char errbuf[1024];
600 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
601 MPL115_ADDR_COEFFS,
602 STATIC_ARRAY_SIZE (mpl115_coeffs),
603 mpl115_coeffs);
604 if (res < 0)
605 {
606 ERROR ("barometer: MPL115_read_coeffs - problem reading data: %s",
607 sstrerror (errno, errbuf, sizeof (errbuf)));
608 return -1;
609 }
611 /* Using perhaps less elegant/efficient code, but more readable. */
612 /* a0: 16total 1sign 12int 4fract 0pad */
613 sia0MSB = mpl115_coeffs[0];
614 sia0LSB = mpl115_coeffs[1];
615 sia0 = (int16_t) sia0MSB <<8; /* s16 type, Shift to MSB */
616 sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
617 mpl115_coeffA0 = (double) (sia0);
618 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
620 /* b1: 16total 1sign 2int 13fract 0pad */
621 sib1MSB= mpl115_coeffs[2];
622 sib1LSB= mpl115_coeffs[3];
623 sib1 = sib1MSB <<8; /* Shift to MSB */
624 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
625 mpl115_coeffB1 = (double) (sib1);
626 mpl115_coeffB1 /= 8192.0; /* 13 fract */
628 /* b2: 16total 1sign 1int 14fract 0pad */
629 sib2MSB= mpl115_coeffs[4];
630 sib2LSB= mpl115_coeffs[5];
631 sib2 = sib2MSB <<8; /* Shift to MSB */
632 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
633 mpl115_coeffB2 = (double) (sib2);
634 mpl115_coeffB2 /= 16384.0; /* 14 fract */
636 /* c12: 14total 1sign 0int 13fract 9pad */
637 sic12MSB= mpl115_coeffs[6];
638 sic12LSB= mpl115_coeffs[7];
639 sic12 = sic12MSB <<8; /* Shift to MSB only by 8 for MSB */
640 sic12 += sic12LSB & 0x00FF;
641 mpl115_coeffC12 = (double) (sic12);
642 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
643 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
645 /* c11: 11total 1sign 0int 11fract 11pad */
646 sic11MSB= mpl115_coeffs[8];
647 sic11LSB= mpl115_coeffs[9];
648 sic11 = sic11MSB <<8; /* Shift to MSB only by 8 for MSB */
649 sic11 += sic11LSB & 0x00FF;
650 mpl115_coeffC11 = (double) (sic11);
651 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
652 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
654 /* c12: 11total 1sign 0int 10fract 15pad */
655 sic22MSB= mpl115_coeffs[10];
656 sic22LSB= mpl115_coeffs[11];
657 sic22 = sic22MSB <<8; /* Shift to MSB only by 8 for MSB */
658 sic22 += sic22LSB & 0x00FF;
659 mpl115_coeffC22 = (double) (sic22);
660 mpl115_coeffC22 /= 32.0; //16-11=5
661 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
663 DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
664 mpl115_coeffA0,
665 mpl115_coeffB1,
666 mpl115_coeffB2,
667 mpl115_coeffC12,
668 mpl115_coeffC11,
669 mpl115_coeffC22);
670 return 0;
671 }
674 /**
675 * Convert raw adc values to real data using the sensor coefficients.
676 *
677 * @param adc_pressure adc pressure value to be converted
678 * @param adc_temp adc temperature value to be converted
679 * @param pressure computed real pressure
680 * @param temperature computed real temperature
681 */
682 static void MPL115_convert_adc_to_real(double adc_pressure,
683 double adc_temp,
684 double * pressure,
685 double * temperature)
686 {
687 double Pcomp;
688 Pcomp = mpl115_coeffA0 + \
689 (mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
690 (mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
692 *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
693 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
694 DEBUG ("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C",
695 *pressure,
696 *temperature);
697 }
700 /**
701 * Read sensor averegaed measurements
702 *
703 * @param pressure averaged measured pressure
704 * @param temperature averaged measured temperature
705 *
706 * @return Zero when successful
707 */
708 static int MPL115_read_averaged(double * pressure, double * temperature)
709 {
710 uint8_t mpl115_conv[MPL115_NUM_CONV] = { 0 };
711 int8_t res;
712 int retries;
713 int conv_pressure;
714 int conv_temperature;
715 double adc_pressure;
716 double adc_temperature;
717 char errbuf[1024];
719 *pressure = 0.0;
720 *temperature = 0.0;
722 /* start conversion of both temp and presure */
723 retries = MPL115_CONVERSION_RETRIES;
724 while (retries>0)
725 {
726 /* write 1 to start conversion */
727 res = i2c_smbus_write_byte_data (i2c_bus_fd,
728 MPL115_CMD_CONVERT_BOTH,
729 0x01);
730 if (res >= 0)
731 break;
733 --retries;
734 if(retries>0)
735 {
736 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, " \
737 "will retry at most %d more times",
738 sstrerror (errno, errbuf, sizeof (errbuf)),
739 retries);
740 }
741 else
742 {
743 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, "\
744 "too many failed retries",
745 sstrerror (errno, errbuf, sizeof (errbuf)));
746 return -1;
747 }
748 }
750 usleep (10000); /* wait 10ms for the conversion */
752 retries=MPL115_CONVERSION_RETRIES;
753 while (retries>0)
754 {
755 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
756 MPL115_ADDR_CONV,
757 STATIC_ARRAY_SIZE (mpl115_conv),
758 mpl115_conv);
759 if (res >= 0)
760 break;
762 --retries;
763 if (retries>0)
764 {
765 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
766 "will retry at most %d more times",
767 sstrerror (errno, errbuf, sizeof (errbuf)),
768 retries);
769 }
770 else
771 {
772 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
773 "too many failed retries",
774 sstrerror (errno, errbuf, sizeof (errbuf)));
775 return -1;
776 }
777 }
779 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
780 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
781 DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
782 "raw temperature ADC value = %d",
783 conv_pressure,
784 conv_temperature);
786 adc_pressure = averaging_add_sample (&pressure_averaging, conv_pressure);
787 adc_temperature = averaging_add_sample (&temperature_averaging, conv_temperature);
789 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
791 DEBUG ("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / temperature = %lf, " \
792 "real pressure = %lf hPa / temperature = %lf C",
793 adc_pressure,
794 adc_temperature,
795 *pressure,
796 *temperature);
798 return 0;
799 }
801 /* ------------------------ MPL3115 access ------------------------ */
803 /**
804 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
805 *
806 * As a sideeffect will leave set I2C slave address.
807 *
808 * @return 1 if MPL3115, 0 otherwise
809 */
810 static int MPL3115_detect(void)
811 {
812 __s32 res;
813 char errbuf[1024];
815 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0)
816 {
817 ERROR("barometer: MPL3115_detect problem setting i2c slave address to 0x%02X: %s",
818 MPL3115_I2C_ADDRESS,
819 sstrerror (errno, errbuf, sizeof (errbuf)));
820 return 0 ;
821 }
823 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
824 if(res == MPL3115_WHO_AM_I_RESP)
825 {
826 DEBUG ("barometer: MPL3115_detect - positive detection");
827 return 1;
828 }
830 DEBUG ("barometer: MPL3115_detect - negative detection");
831 return 0;
832 }
834 /**
835 * Adjusts oversampling to values supported by MPL3115
836 *
837 * MPL3115 supports only power of 2 in the range 1 to 128.
838 */
839 static void MPL3115_adjust_oversampling(void)
840 {
841 int new_val = 0;
843 if(config_oversample > 100)
844 {
845 new_val = 128;
846 mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
847 }
848 else if(config_oversample > 48)
849 {
850 new_val = 64;
851 mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
852 }
853 else if(config_oversample > 24)
854 {
855 new_val = 32;
856 mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
857 }
858 else if(config_oversample > 12)
859 {
860 new_val = 16;
861 mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
862 }
863 else if(config_oversample > 6)
864 {
865 new_val = 8;
866 mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
867 }
868 else if(config_oversample > 3)
869 {
870 new_val = 4;
871 mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
872 }
873 else if(config_oversample > 1)
874 {
875 new_val = 2;
876 mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
877 }
878 else
879 {
880 new_val = 1;
881 mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
882 }
884 DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from %d to %d",
885 config_oversample,
886 new_val);
887 config_oversample = new_val;
888 }
890 /**
891 * Read sensor averaged measurements
892 *
893 * @param pressure averaged measured pressure
894 * @param temperature averaged measured temperature
895 *
896 * @return Zero when successful
897 */
898 static int MPL3115_read(double * pressure, double * temperature)
899 {
900 __s32 res;
901 __s32 ctrl ;
902 __u8 data[MPL3115_NUM_CONV_VALS];
903 long int tmp_value = 0;
904 char errbuf[1024];
906 /* Set Active - activate the device from standby */
907 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
908 if (res < 0)
909 {
910 ERROR ("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
911 sstrerror (errno, errbuf, sizeof (errbuf)));
912 return 1;
913 }
914 ctrl = res;
915 res = i2c_smbus_write_byte_data(i2c_bus_fd,
916 MPL3115_REG_CTRL_REG1,
917 ctrl | MPL3115_CTRL_REG1_SBYB);
918 if (res < 0)
919 {
920 ERROR ("barometer: MPL3115_read - problem activating: %s",
921 sstrerror (errno, errbuf, sizeof (errbuf)));
922 return 1;
923 }
925 /* base sleep is 5ms x OST */
926 usleep(5000 * config_oversample);
928 /* check the flags/status if ready */
929 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
930 if (res < 0)
931 {
932 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
933 sstrerror (errno, errbuf, sizeof (errbuf)));
934 return 1;
935 }
937 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
938 {
939 /* try some extra sleep... */
940 usleep(10000);
942 /* ... and repeat the check. The conversion has to finish sooner or later. */
943 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
944 if (res < 0)
945 {
946 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
947 sstrerror (errno, errbuf, sizeof (errbuf)));
948 return 1;
949 }
950 }
952 /* Now read all the data in one block. There is address autoincrement. */
953 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
954 MPL3115_REG_OUT_P_MSB,
955 MPL3115_NUM_CONV_VALS,
956 data);
957 if (res < 0)
958 {
959 ERROR ("barometer: MPL3115_read - cannot read data registers: %s",
960 sstrerror (errno, errbuf, sizeof (errbuf)));
961 return 1;
962 }
964 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
965 *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
966 DEBUG ("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
968 if(data[3] > 0x7F)
969 {
970 data[3] = ~data[3] + 1;
971 *temperature = data[3];
972 *temperature = - *temperature;
973 }
974 else
975 {
976 *temperature = data[3];
977 }
979 *temperature += (double)(data[4]) / 256.0;
980 DEBUG ("barometer: MPL3115_read - temperature = %lf C", *temperature);
982 return 0;
983 }
985 /**
986 * Initialize MPL3115 for barometeric measurements
987 *
988 * @return 0 if successful
989 */
990 static int MPL3115_init_sensor(void)
991 {
992 __s32 res;
993 __s8 offset;
994 char errbuf[1024];
996 /* Reset the sensor. It will reset immediately without ACKing */
997 /* the transaction, so no error handling here. */
998 i2c_smbus_write_byte_data(i2c_bus_fd,
999 MPL3115_REG_CTRL_REG1,
1000 MPL3115_CTRL_REG1_RST);
1002 /* wait some time for the reset to finish */
1003 usleep(100000);
1005 /* now it should be in standby already so we can go and configure it */
1007 /* Set temperature offset. */
1008 /* result = ADCtemp + offset [C] */
1009 offset = (__s8) (config_temp_offset * 16.0);
1010 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
1011 if (res < 0)
1012 {
1013 ERROR ("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
1014 sstrerror (errno, errbuf, sizeof (errbuf)));
1015 return -1;
1016 }
1018 /* Set pressure offset. */
1019 /* result = ADCpress + offset [hPa] */
1020 offset = (__s8) (config_press_offset * 100.0 / 4.0);
1021 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
1022 if (res < 0)
1023 {
1024 ERROR ("barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
1025 sstrerror (errno, errbuf, sizeof (errbuf)));
1026 return -1;
1027 }
1029 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
1030 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1031 MPL3115_REG_PT_DATA_CFG,
1032 MPL3115_PT_DATA_DREM \
1033 | MPL3115_PT_DATA_PDEF \
1034 | MPL3115_PT_DATA_TDEF);
1035 if (res < 0)
1036 {
1037 ERROR ("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
1038 sstrerror (errno, errbuf, sizeof (errbuf)));
1039 return -1;
1040 }
1042 /* Set to barometer with an OSR */
1043 res = i2c_smbus_write_byte_data(i2c_bus_fd,
1044 MPL3115_REG_CTRL_REG1,
1045 mpl3115_oversample);
1046 if (res < 0)
1047 {
1048 ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
1049 sstrerror (errno, errbuf, sizeof (errbuf)));
1050 return -1;
1051 }
1053 return 0;
1054 }
1056 /* ------------------------ BMP085 access ------------------------ */
1058 /**
1059 * Detect presence of a BMP085 pressure sensor by checking its ID register
1060 *
1061 * As a sideeffect will leave set I2C slave address.
1062 *
1063 * @return 1 if BMP085, 0 otherwise
1064 */
1065 static int BMP085_detect(void)
1066 {
1067 __s32 res;
1068 char errbuf[1024];
1070 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0)
1071 {
1072 ERROR("barometer: BMP085_detect - problem setting i2c slave address to 0x%02X: %s",
1073 BMP085_I2C_ADDRESS,
1074 sstrerror (errno, errbuf, sizeof (errbuf)));
1075 return 0 ;
1076 }
1078 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
1079 if(res == BMP085_CHIP_ID)
1080 {
1081 DEBUG ("barometer: BMP085_detect - positive detection");
1083 /* get version */
1084 res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION );
1085 if (res < 0)
1086 {
1087 ERROR("barometer: BMP085_detect - problem checking chip version: %s",
1088 sstrerror (errno, errbuf, sizeof (errbuf)));
1089 return 0 ;
1090 }
1091 DEBUG ("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
1092 res & 0x0f,
1093 (res & 0xf0) >> 4);
1094 return 1;
1095 }
1097 DEBUG ("barometer: BMP085_detect - negative detection");
1098 return 0;
1099 }
1102 /**
1103 * Adjusts oversampling settings to values supported by BMP085
1104 *
1105 * BMP085 supports only 1,2,4 or 8 samples.
1106 */
1107 static void BMP085_adjust_oversampling(void)
1108 {
1109 int new_val = 0;
1111 if( config_oversample > 6 ) /* 8 */
1112 {
1113 new_val = 8;
1114 bmp085_oversampling = 3;
1115 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
1116 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1117 }
1118 else if( config_oversample > 3 ) /* 4 */
1119 {
1120 new_val = 4;
1121 bmp085_oversampling = 2;
1122 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1123 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1124 }
1125 else if( config_oversample > 1 ) /* 2 */
1126 {
1127 new_val = 2;
1128 bmp085_oversampling = 1;
1129 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1130 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1131 }
1132 else /* 1 */
1133 {
1134 new_val = 1;
1135 bmp085_oversampling = 0;
1136 bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1137 bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1138 }
1140 DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from %d to %d",
1141 config_oversample,
1142 new_val);
1143 config_oversample = new_val;
1144 }
1147 /**
1148 * Read the BMP085 sensor conversion coefficients.
1149 *
1150 * These are (device specific) constants so we can read them just once.
1151 *
1152 * @return Zero when successful
1153 */
1154 static int BMP085_read_coeffs(void)
1155 {
1156 __s32 res;
1157 __u8 coeffs[BMP085_NUM_COEFFS];
1158 char errbuf[1024];
1160 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
1161 BMP085_ADDR_COEFFS,
1162 BMP085_NUM_COEFFS,
1163 coeffs);
1164 if (res < 0)
1165 {
1166 ERROR ("barometer: BMP085_read_coeffs - problem reading data: %s",
1167 sstrerror (errno, errbuf, sizeof (errbuf)));
1168 return -1;
1169 }
1171 bmp085_AC1 = ((int16_t) coeffs[0] <<8) | (int16_t) coeffs[1];
1172 bmp085_AC2 = ((int16_t) coeffs[2] <<8) | (int16_t) coeffs[3];
1173 bmp085_AC3 = ((int16_t) coeffs[4] <<8) | (int16_t) coeffs[5];
1174 bmp085_AC4 = ((uint16_t) coeffs[6] <<8) | (uint16_t) coeffs[7];
1175 bmp085_AC5 = ((uint16_t) coeffs[8] <<8) | (uint16_t) coeffs[9];
1176 bmp085_AC6 = ((uint16_t) coeffs[10] <<8) | (uint16_t) coeffs[11];
1177 bmp085_B1 = ((int16_t) coeffs[12] <<8) | (int16_t) coeffs[13];
1178 bmp085_B2 = ((int16_t) coeffs[14] <<8) | (int16_t) coeffs[15];
1179 bmp085_MB = ((int16_t) coeffs[16] <<8) | (int16_t) coeffs[17];
1180 bmp085_MC = ((int16_t) coeffs[18] <<8) | (int16_t) coeffs[19];
1181 bmp085_MD = ((int16_t) coeffs[20] <<8) | (int16_t) coeffs[21];
1183 DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"\
1184 " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1185 bmp085_AC1,
1186 bmp085_AC2,
1187 bmp085_AC3,
1188 bmp085_AC4,
1189 bmp085_AC5,
1190 bmp085_AC6,
1191 bmp085_B1,
1192 bmp085_B2,
1193 bmp085_MB,
1194 bmp085_MC,
1195 bmp085_MD);
1197 return 0;
1198 }
1201 /**
1202 * Convert raw BMP085 adc values to real data using the sensor coefficients.
1203 *
1204 * @param adc_pressure adc pressure value to be converted
1205 * @param adc_temp adc temperature value to be converted
1206 * @param pressure computed real pressure
1207 * @param temperature computed real temperature
1208 */
1209 static void BMP085_convert_adc_to_real(long adc_pressure,
1210 long adc_temperature,
1211 double * pressure,
1212 double * temperature)
1214 {
1215 long X1, X2, X3;
1216 long B3, B5, B6;
1217 unsigned long B4, B7;
1219 long T;
1220 long P;
1223 /* calculate real temperature */
1224 X1 = ( (adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1225 X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1227 /* B5, T */
1228 B5 = X1 + X2;
1229 T = (B5 + 8) >> 4;
1230 *temperature = (double)T * 0.1;
1232 /* calculate real pressure */
1233 /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept */
1235 /* B6, B3 */
1236 B6 = B5 - 4000;
1237 X1 = ((bmp085_B2 * ((B6 * B6)>>12)) >> 11 );
1238 X2 = (((long)bmp085_AC2 * B6) >> 11);
1239 X3 = X1 + X2;
1240 B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1242 /* B4 */
1243 X1 = (((long)bmp085_AC3*B6) >> 13);
1244 X2 = (bmp085_B1*((B6*B6) >> 12) ) >> 16;
1245 X3 = ((X1 + X2) + 2 ) >> 2;
1246 B4 = ((long)bmp085_AC4* (unsigned long)(X3 + 32768)) >> 15;
1248 /* B7, P */
1249 B7 = (unsigned long)(adc_pressure - B3)*(50000>>bmp085_oversampling);
1250 if( B7 < 0x80000000 )
1251 {
1252 P = (B7 << 1) / B4;
1253 }
1254 else
1255 {
1256 P = (B7/B4) << 1;
1257 }
1258 X1 = (P >> 8) * (P >> 8);
1259 X1 = (X1 * 3038) >> 16;
1260 X2 = ((-7357) * P) >> 16;
1261 P = P + ( ( X1 + X2 + 3791 ) >> 4);
1263 *pressure = P / 100.0; // in [hPa]
1264 DEBUG ("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C",
1265 *pressure,
1266 *temperature);
1267 }
1270 /**
1271 * Read compensated sensor measurements
1272 *
1273 * @param pressure averaged measured pressure
1274 * @param temperature averaged measured temperature
1275 *
1276 * @return Zero when successful
1277 */
1278 static int BMP085_read(double * pressure, double * temperature)
1279 {
1280 __s32 res;
1281 __u8 measBuff[3];
1283 long adc_pressure;
1284 long adc_temperature;
1286 char errbuf[1024];
1288 /* start conversion of temperature */
1289 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1290 BMP085_ADDR_CTRL_REG,
1291 BMP085_CMD_CONVERT_TEMP );
1292 if (res < 0)
1293 {
1294 ERROR ("barometer: BMP085_read - problem requesting temperature conversion: %s",
1295 sstrerror (errno, errbuf, sizeof (errbuf)));
1296 return 1;
1297 }
1299 usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1301 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1302 BMP085_ADDR_CONV,
1303 2,
1304 measBuff);
1305 if (res < 0)
1306 {
1307 ERROR ("barometer: BMP085_read - problem reading temperature data: %s",
1308 sstrerror (errno, errbuf, sizeof (errbuf)));
1309 return 1;
1310 }
1312 adc_temperature = ( (unsigned short)measBuff[0] << 8 ) + measBuff[1];
1315 /* get presure */
1316 res = i2c_smbus_write_byte_data( i2c_bus_fd,
1317 BMP085_ADDR_CTRL_REG,
1318 bmp085_cmdCnvPress );
1319 if (res < 0)
1320 {
1321 ERROR ("barometer: BMP085_read - problem requesting pressure conversion: %s",
1322 sstrerror (errno, errbuf, sizeof (errbuf)));
1323 return 1;
1324 }
1326 usleep(bmp085_timeCnvPress); /* wait for the conversion */
1328 res = i2c_smbus_read_i2c_block_data( i2c_bus_fd,
1329 BMP085_ADDR_CONV,
1330 3,
1331 measBuff );
1332 if (res < 0)
1333 {
1334 ERROR ("barometer: BMP085_read - problem reading pressure data: %s",
1335 sstrerror (errno, errbuf, sizeof (errbuf)));
1336 return 1;
1337 }
1339 adc_pressure = (long)((((ulong)measBuff[0]<<16) | ((ulong)measBuff[1]<<8) | (ulong)measBuff[2] ) >> (8 - bmp085_oversampling));
1342 DEBUG ("barometer: BMP085_read - raw pressure ADC value = %ld, " \
1343 "raw temperature ADC value = %ld",
1344 adc_pressure,
1345 adc_temperature);
1347 BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
1349 return 0;
1350 }
1354 /* ------------------------ Sensor detection ------------------------ */
1355 /**
1356 * Detect presence of a supported sensor.
1357 *
1358 * As a sideeffect will leave set I2C slave address.
1359 * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1360 * first sensor beeing found.
1361 *
1362 * @return detected sensor type
1363 */
1364 static enum Sensor_type detect_sensor_type(void)
1365 {
1366 if(BMP085_detect())
1367 return Sensor_BMP085;
1369 else if(MPL3115_detect())
1370 return Sensor_MPL3115;
1372 else if(MPL115_detect())
1373 return Sensor_MPL115;
1375 return Sensor_none;
1376 }
1378 /* ------------------------ Common functionality ------------------------ */
1380 /**
1381 * Convert absolute pressure (in hPa) to mean sea level pressure
1382 *
1383 * Implemented methods are:
1384 * - MSLP_NONE - no converions, returns absolute pressure
1385 *
1386 * - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1387 * Requires #config_altitude
1388 *
1389 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1390 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1391 * Requires both #config_altitude and temperature reference(s).
1392 *
1393 * @param abs_pressure absloute pressure to be converted
1394 *
1395 * @return mean sea level pressure if successful, NAN otherwise
1396 */
1397 static double abs_to_mean_sea_level_pressure(double abs_pressure)
1398 {
1399 double mean = -1.0;
1400 double temp = 0.0;
1401 int result = 0;
1403 if (config_normalize >= MSLP_DEU_WETT)
1404 {
1405 result = get_reference_temperature(&temp);
1406 if(result)
1407 {
1408 return NAN;
1409 }
1410 }
1412 switch(config_normalize)
1413 {
1414 case MSLP_NONE:
1415 mean = abs_pressure;
1416 break;
1418 case MSLP_INTERNATIONAL:
1419 mean = abs_pressure / \
1420 pow(1.0 - 0.0065*config_altitude/288.15, 9.80665*0.0289644/(8.31447*0.0065));
1421 break;
1423 case MSLP_DEU_WETT:
1424 {
1425 double E; /* humidity */
1426 double x;
1427 if(temp<9.1)
1428 E = 5.6402 * (-0.0916 + exp(0.06*temp) );
1429 else
1430 E = 18.2194 * (1.0463 - exp(-0.0666*temp) );
1431 x = 9.80665 / (287.05 * (temp+273.15 + 0.12*E + 0.0065*config_altitude/2)) * config_altitude;
1432 mean = abs_pressure * exp(x);
1433 }
1434 break;
1436 default:
1437 ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1438 config_normalize);
1439 mean = abs_pressure;
1440 break;
1441 }
1443 DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, method = %d, meanPressure = %lf hPa",
1444 abs_pressure,
1445 config_normalize,
1446 mean);
1448 return mean;
1449 }
1451 /* ------------------------ main plugin callbacks ------------------------ */
1453 /**
1454 * Main plugin configuration callback (using simple config)
1455 *
1456 * @param key configuration key we should process
1457 * @param value configuration value we should process
1458 *
1459 * @return Zero when successful.
1460 */
1461 static int collectd_barometer_config (const char *key, const char *value)
1462 {
1463 DEBUG("barometer: collectd_barometer_config");
1465 if (strcasecmp (key, "Device") == 0)
1466 {
1467 sfree (config_device);
1468 config_device = strdup (value);
1469 }
1470 else if (strcasecmp (key, "Oversampling") == 0)
1471 {
1472 int oversampling_tmp = atoi (value);
1473 if (oversampling_tmp < 1 || oversampling_tmp > 1024)
1474 {
1475 WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
1476 " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for MPL3115) or 1 to 8 (for BMP085).",
1477 oversampling_tmp);
1478 return 1;
1479 }
1480 config_oversample = oversampling_tmp;
1481 }
1482 else if (strcasecmp (key, "Altitude") == 0)
1483 {
1484 config_altitude = atof (value);
1485 }
1486 else if (strcasecmp (key, "Normalization") == 0)
1487 {
1488 int normalize_tmp = atoi (value);
1489 if (normalize_tmp < 0 || normalize_tmp > 2)
1490 {
1491 WARNING ("barometer: collectd_barometer_config: invalid normalization: %d",
1492 normalize_tmp);
1493 return 1;
1494 }
1495 config_normalize = normalize_tmp;
1496 }
1497 else if (strcasecmp (key, "TemperatureSensor") == 0)
1498 {
1499 if(temp_list_add(temp_list, value))
1500 {
1501 return -1;
1502 }
1503 }
1504 else if (strcasecmp (key, "PressureOffset") == 0)
1505 {
1506 config_press_offset = atof(value);
1507 }
1508 else if (strcasecmp (key, "TemperatureOffset") == 0)
1509 {
1510 config_temp_offset = atof(value);
1511 }
1512 else
1513 {
1514 return -1;
1515 }
1517 return 0;
1518 }
1521 /**
1522 * Shutdown callback.
1523 *
1524 * Close I2C and delete all the buffers.
1525 *
1526 * @return Zero when successful (at the moment the only possible outcome)
1527 */
1528 static int collectd_barometer_shutdown(void)
1529 {
1530 DEBUG ("barometer: collectd_barometer_shutdown");
1532 if(sensor_type == Sensor_MPL115)
1533 {
1534 averaging_delete (&pressure_averaging);
1535 averaging_delete (&temperature_averaging);
1537 temp_list_delete(&temp_list);
1538 }
1540 if (i2c_bus_fd > 0)
1541 {
1542 close (i2c_bus_fd);
1543 i2c_bus_fd = -1;
1544 sfree (config_device);
1545 }
1547 return 0;
1548 }
1551 /**
1552 * Plugin read callback for MPL115.
1553 *
1554 * Dispatching will create values:
1555 * - <hostname>/barometer-mpl115/pressure-normalized
1556 * - <hostname>/barometer-mpl115/pressure-absolute
1557 * - <hostname>/barometer-mpl115/temperature
1558 *
1559 * @return Zero when successful.
1560 */
1561 static int MPL115_collectd_barometer_read (void)
1562 {
1563 int result = 0;
1565 double pressure = 0.0;
1566 double temperature = 0.0;
1567 double norm_pressure = 0.0;
1569 value_list_t vl = VALUE_LIST_INIT;
1570 value_t values[1];
1572 DEBUG("barometer: MPL115_collectd_barometer_read");
1574 if (!configured)
1575 {
1576 return -1;
1577 }
1579 /* Rather than delaying init, we will intitialize during first read. This
1580 way at least we have a better chance to have the reference temperature
1581 already available. */
1582 if(!avg_initialized)
1583 {
1584 int i;
1585 for(i=0; i<config_oversample-1; ++i)
1586 {
1587 result = MPL115_read_averaged(&pressure, &temperature);
1588 if(result)
1589 {
1590 ERROR ("barometer: MPL115_collectd_barometer_read - mpl115 read, ignored during init");
1591 }
1592 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i+1, config_oversample-1);
1593 usleep(20000);
1594 }
1595 avg_initialized = 1;
1596 }
1598 result = MPL115_read_averaged(&pressure, &temperature);
1599 if(result)
1600 return result;
1602 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1604 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1605 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1606 sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
1608 vl.values_len = 1;
1609 vl.values = values;
1611 /* dispatch normalized air pressure */
1612 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1613 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1614 values[0].gauge = norm_pressure;
1615 plugin_dispatch_values (&vl);
1617 /* dispatch absolute air pressure */
1618 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1619 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1620 values[0].gauge = pressure;
1621 plugin_dispatch_values (&vl);
1623 /* dispatch sensor temperature */
1624 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1625 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1626 values[0].gauge = temperature;
1627 plugin_dispatch_values (&vl);
1629 return 0;
1630 }
1633 /**
1634 * Plugin read callback for MPL3115.
1635 *
1636 * Dispatching will create values:
1637 * - <hostname>/barometer-mpl3115/pressure-normalized
1638 * - <hostname>/barometer-mpl3115/pressure-absolute
1639 * - <hostname>/barometer-mpl3115/temperature
1640 *
1641 * @return Zero when successful.
1642 */
1643 static int MPL3115_collectd_barometer_read (void)
1644 {
1645 int result = 0;
1647 double pressure = 0.0;
1648 double temperature = 0.0;
1649 double norm_pressure = 0.0;
1651 value_list_t vl = VALUE_LIST_INIT;
1652 value_t values[1];
1654 DEBUG("barometer: MPL3115_collectd_barometer_read");
1656 if (!configured)
1657 {
1658 return -1;
1659 }
1661 result = MPL3115_read(&pressure, &temperature);
1662 if(result)
1663 return result;
1665 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1667 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1668 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1669 sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
1671 vl.values_len = 1;
1672 vl.values = values;
1674 /* dispatch normalized air pressure */
1675 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1676 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1677 values[0].gauge = norm_pressure;
1678 plugin_dispatch_values (&vl);
1680 /* dispatch absolute air pressure */
1681 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1682 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1683 values[0].gauge = pressure;
1684 plugin_dispatch_values (&vl);
1686 /* dispatch sensor temperature */
1687 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1688 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1689 values[0].gauge = temperature;
1690 plugin_dispatch_values (&vl);
1692 return 0;
1693 }
1696 /**
1697 * Plugin read callback for BMP085.
1698 *
1699 * Dispatching will create values:
1700 * - <hostname>/barometer-bmp085/pressure-normalized
1701 * - <hostname>/barometer-bmp085/pressure-absolute
1702 * - <hostname>/barometer-bmp085/temperature
1703 *
1704 * @return Zero when successful.
1705 */
1706 static int BMP085_collectd_barometer_read (void)
1707 {
1708 int result = 0;
1710 double pressure = 0.0;
1711 double temperature = 0.0;
1712 double norm_pressure = 0.0;
1714 value_list_t vl = VALUE_LIST_INIT;
1715 value_t values[1];
1717 DEBUG("barometer: BMP085_collectd_barometer_read");
1719 if (!configured)
1720 {
1721 return -1;
1722 }
1724 result = BMP085_read(&pressure, &temperature);
1725 if(result)
1726 return result;
1728 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1730 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1731 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1732 sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
1734 vl.values_len = 1;
1735 vl.values = values;
1737 /* dispatch normalized air pressure */
1738 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1739 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1740 values[0].gauge = norm_pressure;
1741 plugin_dispatch_values (&vl);
1743 /* dispatch absolute air pressure */
1744 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1745 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1746 values[0].gauge = pressure;
1747 plugin_dispatch_values (&vl);
1749 /* dispatch sensor temperature */
1750 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1751 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1752 values[0].gauge = temperature;
1753 plugin_dispatch_values (&vl);
1755 return 0;
1756 }
1759 /**
1760 * Initialization callback
1761 *
1762 * Check config, initialize I2C bus access, conversion coefficients and averaging
1763 * ring buffers
1764 *
1765 * @return Zero when successful.
1766 */
1767 static int collectd_barometer_init (void)
1768 {
1769 char errbuf[1024];
1771 DEBUG ("barometer: collectd_barometer_init");
1773 if (config_device == NULL)
1774 {
1775 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1776 return -1;
1777 }
1779 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude))
1780 {
1781 ERROR("barometer: collectd_barometer_init no altitude configured " \
1782 "for mean sea level pressure normalization.");
1783 return -1;
1784 }
1786 if (config_normalize == MSLP_DEU_WETT
1787 &&
1788 temp_list == NULL)
1789 {
1790 ERROR("barometer: collectd_barometer_init no temperature reference "\
1791 "configured for mean sea level pressure normalization.");
1792 return -1;
1793 }
1796 i2c_bus_fd = open(config_device, O_RDWR);
1797 if (i2c_bus_fd < 0)
1798 {
1799 ERROR ("barometer: collectd_barometer_init problem opening I2C bus device \"%s\": %s (is loaded mod i2c-dev?)",
1800 config_device,
1801 sstrerror (errno, errbuf, sizeof (errbuf)));
1802 return -1;
1803 }
1805 /* detect sensor type - this will also set slave address */
1806 sensor_type = detect_sensor_type();
1808 /* init correct sensor type */
1809 switch(sensor_type)
1810 {
1811 /* MPL3115 */
1812 case Sensor_MPL3115:
1813 {
1814 MPL3115_adjust_oversampling();
1816 if(MPL3115_init_sensor())
1817 return -1;
1819 plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
1820 }
1821 break;
1823 /* MPL115 */
1824 case Sensor_MPL115:
1825 {
1826 if (averaging_create (&pressure_averaging, config_oversample))
1827 {
1828 ERROR("barometer: collectd_barometer_init pressure averaging init failed");
1829 return -1;
1830 }
1832 if (averaging_create (&temperature_averaging, config_oversample))
1833 {
1834 ERROR("barometer: collectd_barometer_init temperature averaging init failed");
1835 return -1;
1836 }
1838 if (MPL115_read_coeffs() < 0)
1839 return -1;
1841 plugin_register_read ("barometer", MPL115_collectd_barometer_read);
1842 }
1843 break;
1845 /* BMP085 */
1846 case Sensor_BMP085:
1847 {
1848 BMP085_adjust_oversampling();
1850 if (BMP085_read_coeffs() < 0)
1851 return -1;
1853 plugin_register_read ("barometer", BMP085_collectd_barometer_read);
1854 }
1855 break;
1857 /* anything else -> error */
1858 default:
1859 ERROR("barometer: collectd_barometer_init - no supported sensor found");
1860 return -1;
1861 }
1864 configured = 1;
1865 return 0;
1866 }
1868 /* ------------------------ plugin register / entry point ------------------------ */
1870 /**
1871 * Plugin "entry" - register all callback.
1872 *
1873 */
1874 void module_register (void)
1875 {
1876 plugin_register_config ("barometer",
1877 collectd_barometer_config,
1878 config_keys,
1879 config_keys_num);
1880 plugin_register_init ("barometer", collectd_barometer_init);
1881 plugin_register_shutdown ("barometer", collectd_barometer_shutdown);
1882 }