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