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