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