Code

dpdkstat: use portable format strings
[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  **/
22 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "utils_cache.h"
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>
35 /* ------------ MPL115 defines ------------ */
36 /* I2C address of the MPL115 sensor */
37 #define MPL115_I2C_ADDRESS 0x60
39 /* register addresses */
40 #define MPL115_ADDR_CONV 0x00
41 #define MPL115_ADDR_COEFFS 0x04
43 /* register sizes */
44 #define MPL115_NUM_CONV 4
45 #define MPL115_NUM_COEFFS 12
47 /* commands / addresses */
48 #define MPL115_CMD_CONVERT_PRESS 0x10
49 #define MPL115_CMD_CONVERT_TEMP 0x11
50 #define MPL115_CMD_CONVERT_BOTH 0x12
52 #define MPL115_CONVERSION_RETRIES 5
54 /* ------------ MPL3115 defines ------------ */
55 /* MPL3115 I2C address */
56 #define MPL3115_I2C_ADDRESS 0x60
58 /* register addresses (only the interesting ones) */
59 #define MPL3115_REG_STATUS 0x00
60 #define MPL3115_REG_OUT_P_MSB 0x01
61 #define MPL3115_REG_OUT_P_CSB 0x02
62 #define MPL3115_REG_OUT_P_LSB 0x03
63 #define MPL3115_REG_OUT_T_MSB 0x04
64 #define MPL3115_REG_OUT_T_LSB 0x05
65 #define MPL3115_REG_DR_STATUS 0x06
66 #define MPL3115_REG_WHO_AM_I 0x0C
67 #define MPL3115_REG_SYSMOD 0x11
68 #define MPL3115_REG_PT_DATA_CFG 0x13
69 #define MPL3115_REG_BAR_IN_MSB 0x14
70 #define MPL3115_REG_BAR_IN_LSB 0x15
71 #define MPL3115_REG_CTRL_REG1 0x26
72 #define MPL3115_REG_CTRL_REG2 0x27
73 #define MPL3115_REG_CTRL_REG3 0x28
74 #define MPL3115_REG_CTRL_REG4 0x29
75 #define MPL3115_REG_CTRL_REG5 0x2A
76 #define MPL3115_REG_OFF_P 0x2B
77 #define MPL3115_REG_OFF_T 0x2C
78 #define MPL3115_REG_OFF_H 0x2D
80 /* Register values, masks */
81 #define MPL3115_WHO_AM_I_RESP 0xC4
83 #define MPL3115_PT_DATA_DREM 0x04
84 #define MPL3115_PT_DATA_PDEF 0x02
85 #define MPL3115_PT_DATA_TDEF 0x01
87 #define MPL3115_DR_STATUS_TDR 0x02
88 #define MPL3115_DR_STATUS_PDR 0x04
89 #define MPL3115_DR_STATUS_PTDR 0x08
90 #define MPL3115_DR_STATUS_DR                                                   \
91   (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
93 #define MPL3115_DR_STATUS_TOW 0x20
94 #define MPL3115_DR_STATUS_POW 0x40
95 #define MPL3115_DR_STATUS_PTOW 0x80
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
113 #define MPL3115_NUM_CONV_VALS 5
115 /* ------------ BMP085 defines ------------ */
116 /* I2C address of the BMP085 sensor */
117 #define BMP085_I2C_ADDRESS 0x77
119 /* register addresses */
120 #define BMP085_ADDR_ID_REG 0xD0
121 #define BMP085_ADDR_VERSION 0xD1
123 #define BMP085_ADDR_CONV 0xF6
125 #define BMP085_ADDR_CTRL_REG 0xF4
126 #define BMP085_ADDR_COEFFS 0xAA
128 /* register sizes */
129 #define BMP085_NUM_COEFFS 22
131 /* commands, values */
132 #define BMP085_CHIP_ID 0x55
134 #define BMP085_CMD_CONVERT_TEMP 0x2E
136 #define BMP085_CMD_CONVERT_PRESS_0 0x34
137 #define BMP085_CMD_CONVERT_PRESS_1 0x74
138 #define BMP085_CMD_CONVERT_PRESS_2 0xB4
139 #define BMP085_CMD_CONVERT_PRESS_3 0xF4
141 /* in us */
142 #define BMP085_TIME_CNV_TEMP 4500
144 #define BMP085_TIME_CNV_PRESS_0 4500
145 #define BMP085_TIME_CNV_PRESS_1 7500
146 #define BMP085_TIME_CNV_PRESS_2 13500
147 #define BMP085_TIME_CNV_PRESS_3 25500
149 /* ------------ Normalization ------------ */
150 /* Mean sea level pressure normalization methods */
151 #define MSLP_NONE 0
152 #define MSLP_INTERNATIONAL 1
153 #define MSLP_DEU_WETT 2
155 /** Temperature reference history depth for averaging. See
156  * #get_reference_temperature */
157 #define REF_TEMP_AVG_NUM 5
159 /* ------------------------------------------ */
161 /** Supported sensor types */
162 enum Sensor_type {
163   Sensor_none = 0,
164   Sensor_MPL115,
165   Sensor_MPL3115,
166   Sensor_BMP085
167 };
169 static const char *config_keys[] = {
170     "Device",
171     "Oversampling",
172     "PressureOffset",    /**< only for MPL3115 */
173     "TemperatureOffset", /**< only for MPL3115 */
174     "Altitude",
175     "Normalization",
176     "TemperatureSensor"};
178 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
180 static char *config_device = NULL; /**< I2C bus device */
181 static int config_oversample = 1;  /**< averaging window */
183 static double config_press_offset = 0.0; /**< pressure offset */
184 static double config_temp_offset = 0.0;  /**< temperature offset */
186 static double config_altitude = NAN; /**< altitude */
187 static int config_normalize = 0;     /**< normalization method */
189 static _Bool configured = 0; /**< the whole plugin config status */
191 static int i2c_bus_fd = -1; /**< I2C bus device FD */
193 static enum Sensor_type sensor_type =
194     Sensor_none; /**< detected/used sensor type */
196 static __s32 mpl3115_oversample = 0; /**< MPL3115 CTRL1 oversample setting */
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 */
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;
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;
225 /* ------------------------ averaging ring buffer ------------------------ */
226 /*  Used only for MPL115. MPL3115 supports real oversampling in the device so */
227 /*  no need for any postprocessing. */
229 static _Bool avg_initialized = 0; /**< already initialized by real values */
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;
238 static averaging_t pressure_averaging = {NULL, 0, 0L, 0};
239 static averaging_t temperature_averaging = {NULL, 0, 0L, 0};
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   }
260   avg->ring_buffer_size = size;
261   avg->ring_buffer_sum = 0L;
262   avg->ring_buffer_head = 0;
264   return 0;
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;
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;
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);
302   DEBUG("barometer: averaging_add_sample - added %ld, result = %lf", sample,
303         result);
305   return result;
308 /* ------------------------ temperature refference ------------------------ */
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;
320 static temperature_list_t *temp_list = NULL;
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;
333   new_temp = malloc(sizeof(*new_temp));
334   if (new_temp == NULL)
335     return -1;
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   }
345   new_temp->next = temp_list;
346   temp_list = new_temp;
347   return 0;
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;
358   while (*list != NULL) {
359     tmp = (*list);
360     (*list) = (*list)->next;
361     free(tmp->sensor_name);
362     free(tmp);
363     tmp = NULL;
364   }
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;
387   gauge_t *values = NULL; /**< rate values */
388   size_t values_num = 0;  /**< number of rate values */
390   gauge_t values_history[REF_TEMP_AVG_NUM];
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 */
396   *result = NAN;
398   while (list != NULL) {
399     avg_sum = 0.0;
400     avg_num = 0;
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       }
415       DEBUG(
416           "barometer: get_reference_temperature - initialize \"%s\", %zu vals",
417           list->sensor_name, values_num);
419       list->initialized = 1;
420       list->num_values = values_num;
422       for (size_t i = 0; i < values_num; ++i) {
423         DEBUG("barometer: get_reference_temperature - rate %zu: %lf **", i,
424               values[i]);
425         if (!isnan(values[i])) {
426           avg_sum += values[i];
427           ++avg_num;
428         }
429       }
430       free(values);
431       values = NULL;
432     }
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     }
446     for (size_t i = 0; i < REF_TEMP_AVG_NUM * list->num_values; ++i) {
447       DEBUG("barometer: get_reference_temperature - history %zu: %lf", i,
448             values_history[i]);
449       if (!isnan(values_history[i])) {
450         avg_sum += values_history[i];
451         ++avg_num;
452       }
453     }
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       }
466       for (size_t i = 0; i < values_num; ++i) {
467         DEBUG("barometer: get_reference_temperature - rate last %zu: %lf **", i,
468               values[i]);
469         if (!isnan(values[i])) {
470           avg_sum += values[i];
471           ++avg_num;
472         }
473       }
474       free(values);
475       values = NULL;
476     }
478     if (avg_num == 0) {
479       ERROR("barometer: get_reference_temperature - could not read \"%s\"",
480             list->sensor_name);
481       list->initialized = 0;
482       list->num_values = 0;
483     } else {
484       average = avg_sum / (double)avg_num;
485       if (isnan(*result))
486         *result = average;
487       else if (*result > average)
488         *result = average;
489     }
490     list = list->next;
491   } /* while sensor list */
493   if (*result == NAN) {
494     ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
495     return -1;
496   }
497   DEBUG("barometer: get_reference_temperature - temp is %lf", *result);
498   return 0;
501 /* ------------------------ MPL115 access ------------------------ */
503 /**
504  * Detect presence of a MPL115 pressure sensor.
505  *
506  * Unfortunately there seems to be no ID register so we just try to read first
507  * conversion coefficient from device at MPL115 address and hope it is really
508  * MPL115. We should use this check as the last resort (which would be the
509  * typical
510  * case anyway since MPL115 is the least accurate sensor).
511  * As a sideeffect will leave set I2C slave address.
512  *
513  * @return 1 if MPL115, 0 otherwise
514  */
515 static int MPL115_detect(void) {
516   __s32 res;
517   char errbuf[1024];
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, sstrerror(errno, errbuf, sizeof(errbuf)));
523     return 0;
524   }
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   }
532   DEBUG("barometer: MPL115_detect - negative detection");
533   return 0;
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;
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;
551   char errbuf[1024];
553   res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL115_ADDR_COEFFS,
554                                       STATIC_ARRAY_SIZE(mpl115_coeffs),
555                                       mpl115_coeffs);
556   if (res < 0) {
557     ERROR("barometer: MPL115_read_coeffs - problem reading data: %s",
558           sstrerror(errno, errbuf, sizeof(errbuf)));
559     return -1;
560   }
562   /* Using perhaps less elegant/efficient code, but more readable. */
563   /* a0: 16total 1sign 12int 4fract 0pad */
564   sia0MSB = mpl115_coeffs[0];
565   sia0LSB = mpl115_coeffs[1];
566   sia0 = (int16_t)sia0MSB << 8;      /* s16 type, Shift to MSB */
567   sia0 += (int16_t)sia0LSB & 0x00FF; /* Add LSB to 16bit number */
568   mpl115_coeffA0 = (double)(sia0);
569   mpl115_coeffA0 /= 8.0; /* 3 fract bits */
571   /* b1: 16total 1sign 2int 13fract 0pad */
572   sib1MSB = mpl115_coeffs[2];
573   sib1LSB = mpl115_coeffs[3];
574   sib1 = sib1MSB << 8;      /* Shift to MSB */
575   sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
576   mpl115_coeffB1 = (double)(sib1);
577   mpl115_coeffB1 /= 8192.0; /* 13 fract */
579   /* b2: 16total 1sign 1int 14fract 0pad */
580   sib2MSB = mpl115_coeffs[4];
581   sib2LSB = mpl115_coeffs[5];
582   sib2 = sib2MSB << 8;      /* Shift to MSB */
583   sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
584   mpl115_coeffB2 = (double)(sib2);
585   mpl115_coeffB2 /= 16384.0; /* 14 fract */
587   /* c12: 14total 1sign 0int 13fract 9pad */
588   sic12MSB = mpl115_coeffs[6];
589   sic12LSB = mpl115_coeffs[7];
590   sic12 = sic12MSB << 8; /* Shift to MSB only by 8 for MSB */
591   sic12 += sic12LSB & 0x00FF;
592   mpl115_coeffC12 = (double)(sic12);
593   mpl115_coeffC12 /= 4.0;       /* 16-14=2 */
594   mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
596   /* c11: 11total 1sign 0int 11fract 11pad */
597   sic11MSB = mpl115_coeffs[8];
598   sic11LSB = mpl115_coeffs[9];
599   sic11 = sic11MSB << 8; /* Shift to MSB only by 8 for MSB */
600   sic11 += sic11LSB & 0x00FF;
601   mpl115_coeffC11 = (double)(sic11);
602   mpl115_coeffC11 /= 32.0;      /* 16-11=5 */
603   mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
605   /* c12: 11total 1sign 0int 10fract 15pad */
606   sic22MSB = mpl115_coeffs[10];
607   sic22LSB = mpl115_coeffs[11];
608   sic22 = sic22MSB << 8; /* Shift to MSB only by 8 for MSB */
609   sic22 += sic22LSB & 0x00FF;
610   mpl115_coeffC22 = (double)(sic22);
611   mpl115_coeffC22 /= 32.0;       // 16-11=5
612   mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
614   DEBUG("barometer: MPL115_read_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, "
615         "c11=%lf, c22=%lf",
616         mpl115_coeffA0, mpl115_coeffB1, mpl115_coeffB2, mpl115_coeffC12,
617         mpl115_coeffC11, mpl115_coeffC22);
618   return 0;
621 /**
622  * Convert raw adc values to real data using the sensor coefficients.
623  *
624  * @param adc_pressure adc pressure value to be converted
625  * @param adc_temp     adc temperature value to be converted
626  * @param pressure     computed real pressure
627  * @param temperature  computed real temperature
628  */
629 static void MPL115_convert_adc_to_real(double adc_pressure, double adc_temp,
630                                        double *pressure, double *temperature) {
631   double Pcomp;
632   Pcomp = mpl115_coeffA0 +
633           (mpl115_coeffB1 + mpl115_coeffC11 * adc_pressure +
634            mpl115_coeffC12 * adc_temp) *
635               adc_pressure +
636           (mpl115_coeffB2 + mpl115_coeffC22 * adc_temp) * adc_temp;
638   *pressure = ((1150.0 - 500.0) * Pcomp / 1023.0) + 500.0;
639   *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
640   DEBUG("barometer: MPL115_convert_adc_to_real - got %lf hPa, %lf C", *pressure,
641         *temperature);
644 /**
645  * Read sensor averegaed measurements
646  *
647  * @param pressure    averaged measured pressure
648  * @param temperature averaged measured temperature
649  *
650  * @return Zero when successful
651  */
652 static int MPL115_read_averaged(double *pressure, double *temperature) {
653   uint8_t mpl115_conv[MPL115_NUM_CONV] = {0};
654   int8_t res;
655   int retries;
656   int conv_pressure;
657   int conv_temperature;
658   double adc_pressure;
659   double adc_temperature;
660   char errbuf[1024];
662   *pressure = 0.0;
663   *temperature = 0.0;
665   /* start conversion of both temp and presure */
666   retries = MPL115_CONVERSION_RETRIES;
667   while (retries > 0) {
668     /* write 1 to start conversion */
669     res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL115_CMD_CONVERT_BOTH, 0x01);
670     if (res >= 0)
671       break;
673     --retries;
674     if (retries > 0) {
675       ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
676             "will retry at most %d more times",
677             sstrerror(errno, errbuf, sizeof(errbuf)), retries);
678     } else {
679       ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
680             "too many failed retries",
681             sstrerror(errno, errbuf, sizeof(errbuf)));
682       return -1;
683     }
684   }
686   usleep(10000); /* wait 10ms for the conversion */
688   retries = MPL115_CONVERSION_RETRIES;
689   while (retries > 0) {
690     res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL115_ADDR_CONV,
691                                         STATIC_ARRAY_SIZE(mpl115_conv),
692                                         mpl115_conv);
693     if (res >= 0)
694       break;
696     --retries;
697     if (retries > 0) {
698       ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
699             "will retry at most %d more times",
700             sstrerror(errno, errbuf, sizeof(errbuf)), retries);
701     } else {
702       ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
703             "too many failed retries",
704             sstrerror(errno, errbuf, sizeof(errbuf)));
705       return -1;
706     }
707   }
709   conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
710   conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
711   DEBUG("barometer: MPL115_read_averaged, raw pressure ADC value = %d, "
712         "raw temperature ADC value = %d",
713         conv_pressure, conv_temperature);
715   adc_pressure = averaging_add_sample(&pressure_averaging, conv_pressure);
716   adc_temperature =
717       averaging_add_sample(&temperature_averaging, conv_temperature);
719   MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure,
720                              temperature);
722   DEBUG("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / "
723         "temperature = %lf, "
724         "real pressure = %lf hPa / temperature = %lf C",
725         adc_pressure, adc_temperature, *pressure, *temperature);
727   return 0;
730 /* ------------------------ MPL3115 access ------------------------ */
732 /**
733  * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
734  *
735  * As a sideeffect will leave set I2C slave address.
736  *
737  * @return 1 if MPL3115, 0 otherwise
738  */
739 static int MPL3115_detect(void) {
740   __s32 res;
741   char errbuf[1024];
743   if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0) {
744     ERROR("barometer: MPL3115_detect problem setting i2c slave address to "
745           "0x%02X: %s",
746           MPL3115_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
747     return 0;
748   }
750   res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
751   if (res == MPL3115_WHO_AM_I_RESP) {
752     DEBUG("barometer: MPL3115_detect - positive detection");
753     return 1;
754   }
756   DEBUG("barometer: MPL3115_detect - negative detection");
757   return 0;
760 /**
761  * Adjusts oversampling to values supported by MPL3115
762  *
763  * MPL3115 supports only power of 2 in the range 1 to 128.
764  */
765 static void MPL3115_adjust_oversampling(void) {
766   int new_val = 0;
768   if (config_oversample > 100) {
769     new_val = 128;
770     mpl3115_oversample = MPL3115_CTRL_REG1_OST_128;
771   } else if (config_oversample > 48) {
772     new_val = 64;
773     mpl3115_oversample = MPL3115_CTRL_REG1_OST_64;
774   } else if (config_oversample > 24) {
775     new_val = 32;
776     mpl3115_oversample = MPL3115_CTRL_REG1_OST_32;
777   } else if (config_oversample > 12) {
778     new_val = 16;
779     mpl3115_oversample = MPL3115_CTRL_REG1_OST_16;
780   } else if (config_oversample > 6) {
781     new_val = 8;
782     mpl3115_oversample = MPL3115_CTRL_REG1_OST_8;
783   } else if (config_oversample > 3) {
784     new_val = 4;
785     mpl3115_oversample = MPL3115_CTRL_REG1_OST_4;
786   } else if (config_oversample > 1) {
787     new_val = 2;
788     mpl3115_oversample = MPL3115_CTRL_REG1_OST_2;
789   } else {
790     new_val = 1;
791     mpl3115_oversample = MPL3115_CTRL_REG1_OST_1;
792   }
794   DEBUG("barometer: MPL3115_adjust_oversampling - correcting oversampling from "
795         "%d to %d",
796         config_oversample, new_val);
797   config_oversample = new_val;
800 /**
801  * Read sensor averaged measurements
802  *
803  * @param pressure    averaged measured pressure
804  * @param temperature averaged measured temperature
805  *
806  * @return Zero when successful
807  */
808 static int MPL3115_read(double *pressure, double *temperature) {
809   __s32 res;
810   __s32 ctrl;
811   __u8 data[MPL3115_NUM_CONV_VALS];
812   long int tmp_value = 0;
813   char errbuf[1024];
815   /* Set Active - activate the device from standby */
816   res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
817   if (res < 0) {
818     ERROR("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
819           sstrerror(errno, errbuf, sizeof(errbuf)));
820     return 1;
821   }
822   ctrl = res;
823   res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
824                                   ctrl | MPL3115_CTRL_REG1_SBYB);
825   if (res < 0) {
826     ERROR("barometer: MPL3115_read - problem activating: %s",
827           sstrerror(errno, errbuf, sizeof(errbuf)));
828     return 1;
829   }
831   /* base sleep is 5ms x OST */
832   usleep(5000 * config_oversample);
834   /* check the flags/status if ready */
835   res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
836   if (res < 0) {
837     ERROR("barometer: MPL3115_read - cannot read status register: %s",
838           sstrerror(errno, errbuf, sizeof(errbuf)));
839     return 1;
840   }
842   while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR) {
843     /* try some extra sleep... */
844     usleep(10000);
846     /* ... and repeat the check. The conversion has to finish sooner or later.
847      */
848     res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
849     if (res < 0) {
850       ERROR("barometer: MPL3115_read - cannot read status register: %s",
851             sstrerror(errno, errbuf, sizeof(errbuf)));
852       return 1;
853     }
854   }
856   /* Now read all the data in one block. There is address autoincrement. */
857   res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL3115_REG_OUT_P_MSB,
858                                       MPL3115_NUM_CONV_VALS, data);
859   if (res < 0) {
860     ERROR("barometer: MPL3115_read - cannot read data registers: %s",
861           sstrerror(errno, errbuf, sizeof(errbuf)));
862     return 1;
863   }
865   tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
866   *pressure = ((double)tmp_value) / 4.0 / 16.0 / 100.0;
867   DEBUG("barometer: MPL3115_read - absolute pressure = %lf hPa", *pressure);
869   if (data[3] > 0x7F) {
870     data[3] = ~data[3] + 1;
871     *temperature = data[3];
872     *temperature = -*temperature;
873   } else {
874     *temperature = data[3];
875   }
877   *temperature += (double)(data[4]) / 256.0;
878   DEBUG("barometer: MPL3115_read - temperature = %lf C", *temperature);
880   return 0;
883 /**
884  * Initialize MPL3115 for barometeric measurements
885  *
886  * @return 0 if successful
887  */
888 static int MPL3115_init_sensor(void) {
889   __s32 res;
890   __s8 offset;
891   char errbuf[1024];
893   /* Reset the sensor. It will reset immediately without ACKing */
894   /* the transaction, so no error handling here. */
895   i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
896                             MPL3115_CTRL_REG1_RST);
898   /* wait some time for the reset to finish */
899   usleep(100000);
901   /* now it should be in standby already so we can go and configure it */
903   /*  Set temperature offset. */
904   /*  result = ADCtemp + offset [C] */
905   offset = (__s8)(config_temp_offset * 16.0);
906   res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
907   if (res < 0) {
908     ERROR("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
909           sstrerror(errno, errbuf, sizeof(errbuf)));
910     return -1;
911   }
913   /*  Set pressure offset. */
914   /*  result = ADCpress + offset [hPa] */
915   offset = (__s8)(config_press_offset * 100.0 / 4.0);
916   res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
917   if (res < 0) {
918     ERROR(
919         "barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
920         sstrerror(errno, errbuf, sizeof(errbuf)));
921     return -1;
922   }
924   /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
925   res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_PT_DATA_CFG,
926                                   MPL3115_PT_DATA_DREM | MPL3115_PT_DATA_PDEF |
927                                       MPL3115_PT_DATA_TDEF);
928   if (res < 0) {
929     ERROR("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
930           sstrerror(errno, errbuf, sizeof(errbuf)));
931     return -1;
932   }
934   /* Set to barometer with an OSR */
935   res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
936                                   mpl3115_oversample);
937   if (res < 0) {
938     ERROR("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
939           sstrerror(errno, errbuf, sizeof(errbuf)));
940     return -1;
941   }
943   return 0;
946 /* ------------------------ BMP085 access ------------------------ */
948 /**
949  * Detect presence of a BMP085 pressure sensor by checking its ID register
950  *
951  * As a sideeffect will leave set I2C slave address.
952  *
953  * @return 1 if BMP085, 0 otherwise
954  */
955 static int BMP085_detect(void) {
956   __s32 res;
957   char errbuf[1024];
959   if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0) {
960     ERROR("barometer: BMP085_detect - problem setting i2c slave address to "
961           "0x%02X: %s",
962           BMP085_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
963     return 0;
964   }
966   res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_ID_REG);
967   if (res == BMP085_CHIP_ID) {
968     DEBUG("barometer: BMP085_detect - positive detection");
970     /* get version */
971     res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION);
972     if (res < 0) {
973       ERROR("barometer: BMP085_detect - problem checking chip version: %s",
974             sstrerror(errno, errbuf, sizeof(errbuf)));
975       return 0;
976     }
977     DEBUG("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
978           res & 0x0f, (res & 0xf0) >> 4);
979     return 1;
980   }
982   DEBUG("barometer: BMP085_detect - negative detection");
983   return 0;
986 /**
987  * Adjusts oversampling settings to values supported by BMP085
988  *
989  * BMP085 supports only 1,2,4 or 8 samples.
990  */
991 static void BMP085_adjust_oversampling(void) {
992   int new_val = 0;
994   if (config_oversample > 6) /* 8 */
995   {
996     new_val = 8;
997     bmp085_oversampling = 3;
998     bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_3;
999     bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_3;
1000   } else if (config_oversample > 3) /* 4 */
1001   {
1002     new_val = 4;
1003     bmp085_oversampling = 2;
1004     bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_2;
1005     bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_2;
1006   } else if (config_oversample > 1) /* 2 */
1007   {
1008     new_val = 2;
1009     bmp085_oversampling = 1;
1010     bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_1;
1011     bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_1;
1012   } else /* 1 */
1013   {
1014     new_val = 1;
1015     bmp085_oversampling = 0;
1016     bmp085_cmdCnvPress = BMP085_CMD_CONVERT_PRESS_0;
1017     bmp085_timeCnvPress = BMP085_TIME_CNV_PRESS_0;
1018   }
1020   DEBUG("barometer: BMP085_adjust_oversampling - correcting oversampling from "
1021         "%d to %d",
1022         config_oversample, new_val);
1023   config_oversample = new_val;
1026 /**
1027  * Read the BMP085 sensor conversion coefficients.
1028  *
1029  * These are (device specific) constants so we can read them just once.
1030  *
1031  * @return Zero when successful
1032  */
1033 static int BMP085_read_coeffs(void) {
1034   __s32 res;
1035   __u8 coeffs[BMP085_NUM_COEFFS];
1036   char errbuf[1024];
1038   res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_COEFFS,
1039                                       BMP085_NUM_COEFFS, coeffs);
1040   if (res < 0) {
1041     ERROR("barometer: BMP085_read_coeffs - problem reading data: %s",
1042           sstrerror(errno, errbuf, sizeof(errbuf)));
1043     return -1;
1044   }
1046   bmp085_AC1 = ((int16_t)coeffs[0] << 8) | (int16_t)coeffs[1];
1047   bmp085_AC2 = ((int16_t)coeffs[2] << 8) | (int16_t)coeffs[3];
1048   bmp085_AC3 = ((int16_t)coeffs[4] << 8) | (int16_t)coeffs[5];
1049   bmp085_AC4 = ((uint16_t)coeffs[6] << 8) | (uint16_t)coeffs[7];
1050   bmp085_AC5 = ((uint16_t)coeffs[8] << 8) | (uint16_t)coeffs[9];
1051   bmp085_AC6 = ((uint16_t)coeffs[10] << 8) | (uint16_t)coeffs[11];
1052   bmp085_B1 = ((int16_t)coeffs[12] << 8) | (int16_t)coeffs[13];
1053   bmp085_B2 = ((int16_t)coeffs[14] << 8) | (int16_t)coeffs[15];
1054   bmp085_MB = ((int16_t)coeffs[16] << 8) | (int16_t)coeffs[17];
1055   bmp085_MC = ((int16_t)coeffs[18] << 8) | (int16_t)coeffs[19];
1056   bmp085_MD = ((int16_t)coeffs[20] << 8) | (int16_t)coeffs[21];
1058   DEBUG("barometer: BMP085_read_coeffs - AC1=%d, AC2=%d, AC3=%d, AC4=%u,"
1059         " AC5=%u, AC6=%u, B1=%d, B2=%d, MB=%d, MC=%d, MD=%d",
1060         bmp085_AC1, bmp085_AC2, bmp085_AC3, bmp085_AC4, bmp085_AC5, bmp085_AC6,
1061         bmp085_B1, bmp085_B2, bmp085_MB, bmp085_MC, bmp085_MD);
1063   return 0;
1066 /**
1067  * Convert raw BMP085 adc values to real data using the sensor coefficients.
1068  *
1069  * @param adc_pressure adc pressure value to be converted
1070  * @param adc_temp     adc temperature value to be converted
1071  * @param pressure     computed real pressure
1072  * @param temperature  computed real temperature
1073  */
1074 static void BMP085_convert_adc_to_real(long adc_pressure, long adc_temperature,
1075                                        double *pressure, double *temperature)
1078   long X1, X2, X3;
1079   long B3, B5, B6;
1080   unsigned long B4, B7;
1082   long T;
1083   long P;
1085   /* calculate real temperature */
1086   X1 = ((adc_temperature - bmp085_AC6) * bmp085_AC5) >> 15;
1087   X2 = (bmp085_MC << 11) / (X1 + bmp085_MD);
1089   /* B5, T */
1090   B5 = X1 + X2;
1091   T = (B5 + 8) >> 4;
1092   *temperature = (double)T * 0.1;
1094   /* calculate real pressure */
1095   /* in general X1, X2, X3 are recycled while values of B3, B4, B5, B6 are kept
1096    */
1098   /* B6, B3 */
1099   B6 = B5 - 4000;
1100   X1 = ((bmp085_B2 * ((B6 * B6) >> 12)) >> 11);
1101   X2 = (((long)bmp085_AC2 * B6) >> 11);
1102   X3 = X1 + X2;
1103   B3 = (((((long)bmp085_AC1 * 4) + X3) << bmp085_oversampling) + 2) >> 2;
1105   /* B4 */
1106   X1 = (((long)bmp085_AC3 * B6) >> 13);
1107   X2 = (bmp085_B1 * ((B6 * B6) >> 12)) >> 16;
1108   X3 = ((X1 + X2) + 2) >> 2;
1109   B4 = ((long)bmp085_AC4 * (unsigned long)(X3 + 32768)) >> 15;
1111   /* B7, P */
1112   B7 = (unsigned long)(adc_pressure - B3) * (50000 >> bmp085_oversampling);
1113   if (B7 < 0x80000000) {
1114     P = (B7 << 1) / B4;
1115   } else {
1116     P = (B7 / B4) << 1;
1117   }
1118   X1 = (P >> 8) * (P >> 8);
1119   X1 = (X1 * 3038) >> 16;
1120   X2 = ((-7357) * P) >> 16;
1121   P = P + ((X1 + X2 + 3791) >> 4);
1123   *pressure = P / 100.0; // in [hPa]
1124   DEBUG("barometer: BMP085_convert_adc_to_real - got %lf hPa, %lf C", *pressure,
1125         *temperature);
1128 /**
1129  * Read compensated sensor measurements
1130  *
1131  * @param pressure    averaged measured pressure
1132  * @param temperature averaged measured temperature
1133  *
1134  * @return Zero when successful
1135  */
1136 static int BMP085_read(double *pressure, double *temperature) {
1137   __s32 res;
1138   __u8 measBuff[3];
1140   long adc_pressure;
1141   long adc_temperature;
1143   char errbuf[1024];
1145   /* start conversion of temperature */
1146   res = i2c_smbus_write_byte_data(i2c_bus_fd, BMP085_ADDR_CTRL_REG,
1147                                   BMP085_CMD_CONVERT_TEMP);
1148   if (res < 0) {
1149     ERROR("barometer: BMP085_read - problem requesting temperature conversion: "
1150           "%s",
1151           sstrerror(errno, errbuf, sizeof(errbuf)));
1152     return 1;
1153   }
1155   usleep(BMP085_TIME_CNV_TEMP); /* wait for the conversion */
1157   res =
1158       i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 2, measBuff);
1159   if (res < 0) {
1160     ERROR("barometer: BMP085_read - problem reading temperature data: %s",
1161           sstrerror(errno, errbuf, sizeof(errbuf)));
1162     return 1;
1163   }
1165   adc_temperature = ((unsigned short)measBuff[0] << 8) + measBuff[1];
1167   /* get presure */
1168   res = i2c_smbus_write_byte_data(i2c_bus_fd, BMP085_ADDR_CTRL_REG,
1169                                   bmp085_cmdCnvPress);
1170   if (res < 0) {
1171     ERROR("barometer: BMP085_read - problem requesting pressure conversion: %s",
1172           sstrerror(errno, errbuf, sizeof(errbuf)));
1173     return 1;
1174   }
1176   usleep(bmp085_timeCnvPress); /* wait for the conversion */
1178   res =
1179       i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 3, measBuff);
1180   if (res < 0) {
1181     ERROR("barometer: BMP085_read - problem reading pressure data: %s",
1182           sstrerror(errno, errbuf, sizeof(errbuf)));
1183     return 1;
1184   }
1186   adc_pressure = (long)((((ulong)measBuff[0] << 16) |
1187                          ((ulong)measBuff[1] << 8) | (ulong)measBuff[2]) >>
1188                         (8 - bmp085_oversampling));
1190   DEBUG("barometer: BMP085_read - raw pressure ADC value = %ld, "
1191         "raw temperature ADC value = %ld",
1192         adc_pressure, adc_temperature);
1194   BMP085_convert_adc_to_real(adc_pressure, adc_temperature, pressure,
1195                              temperature);
1197   return 0;
1200 /* ------------------------ Sensor detection ------------------------ */
1201 /**
1202  * Detect presence of a supported sensor.
1203  *
1204  * As a sideeffect will leave set I2C slave address.
1205  * The detection is done in the order BMP085, MPL3115, MPL115 and stops after
1206  * first sensor beeing found.
1207  *
1208  * @return detected sensor type
1209  */
1210 static enum Sensor_type detect_sensor_type(void) {
1211   if (BMP085_detect())
1212     return Sensor_BMP085;
1214   else if (MPL3115_detect())
1215     return Sensor_MPL3115;
1217   else if (MPL115_detect())
1218     return Sensor_MPL115;
1220   return Sensor_none;
1223 /* ------------------------ Common functionality ------------------------ */
1225 /**
1226  * Convert absolute pressure (in hPa) to mean sea level pressure
1227  *
1228  * Implemented methods are:
1229  * - MSLP_NONE - no converions, returns absolute pressure
1230  *
1231  * - MSLP_INTERNATIONAL - see
1232  * http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
1233  *           Requires #config_altitude
1234  *
1235  * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
1236  *                http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
1237  *           Requires both #config_altitude and temperature reference(s).
1238  *
1239  * @param abs_pressure absloute pressure to be converted
1240  *
1241  * @return mean sea level pressure if successful, NAN otherwise
1242  */
1243 static double abs_to_mean_sea_level_pressure(double abs_pressure) {
1244   double mean = -1.0;
1245   double temp = 0.0;
1246   int result = 0;
1248   if (config_normalize >= MSLP_DEU_WETT) {
1249     result = get_reference_temperature(&temp);
1250     if (result) {
1251       return NAN;
1252     }
1253   }
1255   switch (config_normalize) {
1256   case MSLP_NONE:
1257     mean = abs_pressure;
1258     break;
1260   case MSLP_INTERNATIONAL:
1261     mean = abs_pressure / pow(1.0 - 0.0065 * config_altitude / 288.15,
1262                               9.80665 * 0.0289644 / (8.31447 * 0.0065));
1263     break;
1265   case MSLP_DEU_WETT: {
1266     double E; /* humidity */
1267     double x;
1268     if (temp < 9.1)
1269       E = 5.6402 * (-0.0916 + exp(0.06 * temp));
1270     else
1271       E = 18.2194 * (1.0463 - exp(-0.0666 * temp));
1272     x = 9.80665 /
1273         (287.05 * (temp + 273.15 + 0.12 * E + 0.0065 * config_altitude / 2)) *
1274         config_altitude;
1275     mean = abs_pressure * exp(x);
1276   } break;
1278   default:
1279     ERROR(
1280         "barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1281         config_normalize);
1282     mean = abs_pressure;
1283     break;
1284   }
1286   DEBUG("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf hPa, "
1287         "method = %d, meanPressure = %lf hPa",
1288         abs_pressure, config_normalize, mean);
1290   return mean;
1293 /* ------------------------ main plugin callbacks ------------------------ */
1295 /**
1296  * Main plugin configuration callback (using simple config)
1297  *
1298  * @param key   configuration key we should process
1299  * @param value configuration value we should process
1300  *
1301  * @return Zero when successful.
1302  */
1303 static int collectd_barometer_config(const char *key, const char *value) {
1304   DEBUG("barometer: collectd_barometer_config");
1306   if (strcasecmp(key, "Device") == 0) {
1307     sfree(config_device);
1308     config_device = strdup(value);
1309   } else if (strcasecmp(key, "Oversampling") == 0) {
1310     int oversampling_tmp = atoi(value);
1311     if (oversampling_tmp < 1 || oversampling_tmp > 1024) {
1312       WARNING("barometer: collectd_barometer_config: invalid oversampling: %d."
1313               " Allowed values are 1 to 1024 (for MPL115) or 1 to 128 (for "
1314               "MPL3115) or 1 to 8 (for BMP085).",
1315               oversampling_tmp);
1316       return 1;
1317     }
1318     config_oversample = oversampling_tmp;
1319   } else if (strcasecmp(key, "Altitude") == 0) {
1320     config_altitude = atof(value);
1321   } else if (strcasecmp(key, "Normalization") == 0) {
1322     int normalize_tmp = atoi(value);
1323     if (normalize_tmp < 0 || normalize_tmp > 2) {
1324       WARNING("barometer: collectd_barometer_config: invalid normalization: %d",
1325               normalize_tmp);
1326       return 1;
1327     }
1328     config_normalize = normalize_tmp;
1329   } else if (strcasecmp(key, "TemperatureSensor") == 0) {
1330     if (temp_list_add(temp_list, value)) {
1331       return -1;
1332     }
1333   } else if (strcasecmp(key, "PressureOffset") == 0) {
1334     config_press_offset = atof(value);
1335   } else if (strcasecmp(key, "TemperatureOffset") == 0) {
1336     config_temp_offset = atof(value);
1337   } else {
1338     return -1;
1339   }
1341   return 0;
1344 /**
1345  * Shutdown callback.
1346  *
1347  * Close I2C and delete all the buffers.
1348  *
1349  * @return Zero when successful (at the moment the only possible outcome)
1350  */
1351 static int collectd_barometer_shutdown(void) {
1352   DEBUG("barometer: collectd_barometer_shutdown");
1354   if (sensor_type == Sensor_MPL115) {
1355     averaging_delete(&pressure_averaging);
1356     averaging_delete(&temperature_averaging);
1358     temp_list_delete(&temp_list);
1359   }
1361   if (i2c_bus_fd > 0) {
1362     close(i2c_bus_fd);
1363     i2c_bus_fd = -1;
1364     sfree(config_device);
1365   }
1367   return 0;
1370 /**
1371  * Plugin read callback for MPL115.
1372  *
1373  *  Dispatching will create values:
1374  *  - <hostname>/barometer-mpl115/pressure-normalized
1375  *  - <hostname>/barometer-mpl115/pressure-absolute
1376  *  - <hostname>/barometer-mpl115/temperature
1377  *
1378  * @return Zero when successful.
1379  */
1380 static int MPL115_collectd_barometer_read(void) {
1381   int result = 0;
1383   double pressure = 0.0;
1384   double temperature = 0.0;
1385   double norm_pressure = 0.0;
1387   value_list_t vl = VALUE_LIST_INIT;
1388   value_t values[1];
1390   DEBUG("barometer: MPL115_collectd_barometer_read");
1392   if (!configured) {
1393     return -1;
1394   }
1396   /* Rather than delaying init, we will intitialize during first read. This
1397      way at least we have a better chance to have the reference temperature
1398      already available. */
1399   if (!avg_initialized) {
1400     for (int i = 0; i < config_oversample - 1; ++i) {
1401       result = MPL115_read_averaged(&pressure, &temperature);
1402       if (result) {
1403         ERROR("barometer: MPL115_collectd_barometer_read - mpl115 read, "
1404               "ignored during init");
1405       }
1406       DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i + 1,
1407             config_oversample - 1);
1408       usleep(20000);
1409     }
1410     avg_initialized = 1;
1411   }
1413   result = MPL115_read_averaged(&pressure, &temperature);
1414   if (result)
1415     return result;
1417   norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1419   sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1420   sstrncpy(vl.plugin_instance, "mpl115", sizeof(vl.plugin_instance));
1422   vl.values_len = 1;
1423   vl.values = values;
1425   /* dispatch normalized air pressure */
1426   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1427   sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1428   values[0].gauge = norm_pressure;
1429   plugin_dispatch_values(&vl);
1431   /* dispatch absolute air pressure */
1432   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1433   sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1434   values[0].gauge = pressure;
1435   plugin_dispatch_values(&vl);
1437   /* dispatch sensor temperature */
1438   sstrncpy(vl.type, "temperature", sizeof(vl.type));
1439   sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1440   values[0].gauge = temperature;
1441   plugin_dispatch_values(&vl);
1443   return 0;
1446 /**
1447  * Plugin read callback for MPL3115.
1448  *
1449  *  Dispatching will create values:
1450  *  - <hostname>/barometer-mpl3115/pressure-normalized
1451  *  - <hostname>/barometer-mpl3115/pressure-absolute
1452  *  - <hostname>/barometer-mpl3115/temperature
1453  *
1454  * @return Zero when successful.
1455  */
1456 static int MPL3115_collectd_barometer_read(void) {
1457   int result = 0;
1459   double pressure = 0.0;
1460   double temperature = 0.0;
1461   double norm_pressure = 0.0;
1463   value_list_t vl = VALUE_LIST_INIT;
1464   value_t values[1];
1466   DEBUG("barometer: MPL3115_collectd_barometer_read");
1468   if (!configured) {
1469     return -1;
1470   }
1472   result = MPL3115_read(&pressure, &temperature);
1473   if (result)
1474     return result;
1476   norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1478   sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1479   sstrncpy(vl.plugin_instance, "mpl3115", sizeof(vl.plugin_instance));
1481   vl.values_len = 1;
1482   vl.values = values;
1484   /* dispatch normalized air pressure */
1485   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1486   sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1487   values[0].gauge = norm_pressure;
1488   plugin_dispatch_values(&vl);
1490   /* dispatch absolute air pressure */
1491   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1492   sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1493   values[0].gauge = pressure;
1494   plugin_dispatch_values(&vl);
1496   /* dispatch sensor temperature */
1497   sstrncpy(vl.type, "temperature", sizeof(vl.type));
1498   sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1499   values[0].gauge = temperature;
1500   plugin_dispatch_values(&vl);
1502   return 0;
1505 /**
1506  * Plugin read callback for BMP085.
1507  *
1508  *  Dispatching will create values:
1509  *  - <hostname>/barometer-bmp085/pressure-normalized
1510  *  - <hostname>/barometer-bmp085/pressure-absolute
1511  *  - <hostname>/barometer-bmp085/temperature
1512  *
1513  * @return Zero when successful.
1514  */
1515 static int BMP085_collectd_barometer_read(void) {
1516   int result = 0;
1518   double pressure = 0.0;
1519   double temperature = 0.0;
1520   double norm_pressure = 0.0;
1522   value_list_t vl = VALUE_LIST_INIT;
1523   value_t values[1];
1525   DEBUG("barometer: BMP085_collectd_barometer_read");
1527   if (!configured) {
1528     return -1;
1529   }
1531   result = BMP085_read(&pressure, &temperature);
1532   if (result)
1533     return result;
1535   norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1537   sstrncpy(vl.plugin, "barometer", sizeof(vl.plugin));
1538   sstrncpy(vl.plugin_instance, "bmp085", sizeof(vl.plugin_instance));
1540   vl.values_len = 1;
1541   vl.values = values;
1543   /* dispatch normalized air pressure */
1544   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1545   sstrncpy(vl.type_instance, "normalized", sizeof(vl.type_instance));
1546   values[0].gauge = norm_pressure;
1547   plugin_dispatch_values(&vl);
1549   /* dispatch absolute air pressure */
1550   sstrncpy(vl.type, "pressure", sizeof(vl.type));
1551   sstrncpy(vl.type_instance, "absolute", sizeof(vl.type_instance));
1552   values[0].gauge = pressure;
1553   plugin_dispatch_values(&vl);
1555   /* dispatch sensor temperature */
1556   sstrncpy(vl.type, "temperature", sizeof(vl.type));
1557   sstrncpy(vl.type_instance, "", sizeof(vl.type_instance));
1558   values[0].gauge = temperature;
1559   plugin_dispatch_values(&vl);
1561   return 0;
1564 /**
1565  * Initialization callback
1566  *
1567  * Check config, initialize I2C bus access, conversion coefficients and
1568  * averaging
1569  * ring buffers
1570  *
1571  * @return Zero when successful.
1572  */
1573 static int collectd_barometer_init(void) {
1574   char errbuf[1024];
1576   DEBUG("barometer: collectd_barometer_init");
1578   if (config_device == NULL) {
1579     ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1580     return -1;
1581   }
1583   if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude)) {
1584     ERROR("barometer: collectd_barometer_init no altitude configured "
1585           "for mean sea level pressure normalization.");
1586     return -1;
1587   }
1589   if (config_normalize == MSLP_DEU_WETT && temp_list == NULL) {
1590     ERROR("barometer: collectd_barometer_init no temperature reference "
1591           "configured for mean sea level pressure normalization.");
1592     return -1;
1593   }
1595   i2c_bus_fd = open(config_device, O_RDWR);
1596   if (i2c_bus_fd < 0) {
1597     ERROR("barometer: collectd_barometer_init problem opening I2C bus device "
1598           "\"%s\": %s (is loaded mod i2c-dev?)",
1599           config_device, sstrerror(errno, errbuf, sizeof(errbuf)));
1600     return -1;
1601   }
1603   /* detect sensor type - this will also set slave address */
1604   sensor_type = detect_sensor_type();
1606   /* init correct sensor type */
1607   switch (sensor_type) {
1608   /* MPL3115 */
1609   case Sensor_MPL3115: {
1610     MPL3115_adjust_oversampling();
1612     if (MPL3115_init_sensor())
1613       return -1;
1615     plugin_register_read("barometer", MPL3115_collectd_barometer_read);
1616   } break;
1618   /* MPL115 */
1619   case Sensor_MPL115: {
1620     if (averaging_create(&pressure_averaging, config_oversample)) {
1621       ERROR(
1622           "barometer: collectd_barometer_init pressure averaging init failed");
1623       return -1;
1624     }
1626     if (averaging_create(&temperature_averaging, config_oversample)) {
1627       ERROR("barometer: collectd_barometer_init temperature averaging init "
1628             "failed");
1629       return -1;
1630     }
1632     if (MPL115_read_coeffs() < 0)
1633       return -1;
1635     plugin_register_read("barometer", MPL115_collectd_barometer_read);
1636   } break;
1638   /* BMP085 */
1639   case Sensor_BMP085: {
1640     BMP085_adjust_oversampling();
1642     if (BMP085_read_coeffs() < 0)
1643       return -1;
1645     plugin_register_read("barometer", BMP085_collectd_barometer_read);
1646   } break;
1648   /* anything else -> error */
1649   default:
1650     ERROR("barometer: collectd_barometer_init - no supported sensor found");
1651     return -1;
1652   }
1654   configured = 1;
1655   return 0;
1658 /* ------------------------ plugin register / entry point
1659  * ------------------------ */
1661 /**
1662  * Plugin "entry" - register all callback.
1663  *
1664  */
1665 void module_register(void) {
1666   plugin_register_config("barometer", collectd_barometer_config, config_keys,
1667                          config_keys_num);
1668   plugin_register_init("barometer", collectd_barometer_init);
1669   plugin_register_shutdown("barometer", collectd_barometer_shutdown);