2 * collectd - src/barometer.c
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
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.
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
24 #include "utils_cache.h"
30 #include <linux/i2c-dev.h>
33 /* ------------ MPL115 defines ------------ */
34 /* I2C address of the MPL115 sensor */
35 #define MPL115_I2C_ADDRESS 0x60
37 /* register addresses */
38 #define MPL115_ADDR_CONV 0x00
39 #define MPL115_ADDR_COEFFS 0x04
42 #define MPL115_NUM_CONV 4
43 #define MPL115_NUM_COEFFS 12
45 /* commands / addresses */
46 #define MPL115_CMD_CONVERT_PRESS 0x10
47 #define MPL115_CMD_CONVERT_TEMP 0x11
48 #define MPL115_CMD_CONVERT_BOTH 0x12
50 #define MPL115_CONVERSION_RETRIES 5
53 /* ------------ MPL3115 defines ------------ */
54 /* MPL3115 I2C address */
55 #define MPL3115_I2C_ADDRESS 0x60
57 /* register addresses (only the interesting ones) */
58 #define MPL3115_REG_STATUS 0x00
59 #define MPL3115_REG_OUT_P_MSB 0x01
60 #define MPL3115_REG_OUT_P_CSB 0x02
61 #define MPL3115_REG_OUT_P_LSB 0x03
62 #define MPL3115_REG_OUT_T_MSB 0x04
63 #define MPL3115_REG_OUT_T_LSB 0x05
64 #define MPL3115_REG_DR_STATUS 0x06
65 #define MPL3115_REG_WHO_AM_I 0x0C
66 #define MPL3115_REG_SYSMOD 0x11
67 #define MPL3115_REG_PT_DATA_CFG 0x13
68 #define MPL3115_REG_BAR_IN_MSB 0x14
69 #define MPL3115_REG_BAR_IN_LSB 0x15
70 #define MPL3115_REG_CTRL_REG1 0x26
71 #define MPL3115_REG_CTRL_REG2 0x27
72 #define MPL3115_REG_CTRL_REG3 0x28
73 #define MPL3115_REG_CTRL_REG4 0x29
74 #define MPL3115_REG_CTRL_REG5 0x2A
75 #define MPL3115_REG_OFF_P 0x2B
76 #define MPL3115_REG_OFF_T 0x2C
77 #define MPL3115_REG_OFF_H 0x2D
79 /* Register values, masks */
80 #define MPL3115_WHO_AM_I_RESP 0xC4
82 #define MPL3115_PT_DATA_DREM 0x04
83 #define MPL3115_PT_DATA_PDEF 0x02
84 #define MPL3115_PT_DATA_TDEF 0x01
86 #define MPL3115_DR_STATUS_TDR 0x02
87 #define MPL3115_DR_STATUS_PDR 0x04
88 #define MPL3115_DR_STATUS_PTDR 0x08
89 #define MPL3115_DR_STATUS_DR (MPL3115_DR_STATUS_TDR | MPL3115_DR_STATUS_PDR | MPL3115_DR_STATUS_PTDR)
91 #define MPL3115_DR_STATUS_TOW 0x20
92 #define MPL3115_DR_STATUS_POW 0x40
93 #define MPL3115_DR_STATUS_PTOW 0x80
95 #define MPL3115_CTRL_REG1_ALT 0x80
96 #define MPL3115_CTRL_REG1_RAW 0x40
97 #define MPL3115_CTRL_REG1_OST_MASK 0x38
98 #define MPL3115_CTRL_REG1_OST_1 0x00
99 #define MPL3115_CTRL_REG1_OST_2 0x08
100 #define MPL3115_CTRL_REG1_OST_4 0x10
101 #define MPL3115_CTRL_REG1_OST_8 0x18
102 #define MPL3115_CTRL_REG1_OST_16 0x20
103 #define MPL3115_CTRL_REG1_OST_32 0x28
104 #define MPL3115_CTRL_REG1_OST_64 0x30
105 #define MPL3115_CTRL_REG1_OST_128 0x38
106 #define MPL3115_CTRL_REG1_RST 0x04
107 #define MPL3115_CTRL_REG1_OST 0x02
108 #define MPL3115_CTRL_REG1_SBYB 0x01
109 #define MPL3115_CTRL_REG1_SBYB_MASK 0xFE
111 #define MPL3115_NUM_CONV_VALS 5
114 /* ------------ Normalization ------------ */
115 /* Mean sea level pressure normalization methods */
117 #define MSLP_INTERNATIONAL 1
118 #define MSLP_DEU_WETT 2
120 /** Temperature reference history depth for averaging. See #get_reference_temperature */
121 #define REF_TEMP_AVG_NUM 5
123 /* ------------------------------------------ */
124 static const char *config_keys[] =
128 "PressureOffset", /**< only for MPL3115 */
129 "TemperatureOffset", /**< only for MPL3115 */
135 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
137 static char * config_device = NULL; /**< I2C bus device */
138 static int config_oversample = 1; /**< averaging window */
140 static double config_press_offset = 0.0; /**< pressure offset */
141 static double config_temp_offset = 0.0; /**< temperature offset */
143 static double config_altitude = NAN; /**< altitude */
144 static int config_normalize = 0; /**< normalization method */
146 static _Bool configured = 0; /**< the whole plugin config status */
148 static int i2c_bus_fd = -1; /**< I2C bus device FD */
150 static _Bool is_MPL3115 = 0; /**< is this MPL3115? */
151 static __s32 oversample_MPL3115 = 0; /**< MPL3115 CTRL1 oversample setting */
154 /* MPL115 conversion coefficients */
155 static double mpl115_coeffA0;
156 static double mpl115_coeffB1;
157 static double mpl115_coeffB2;
158 static double mpl115_coeffC12;
159 static double mpl115_coeffC11;
160 static double mpl115_coeffC22;
162 /* ------------------------ averaging ring buffer ------------------------ */
163 /* Used only for MPL115. MPL3115 supports real oversampling in the device so */
164 /* no need for any postprocessing. */
166 static _Bool avg_initialized = 0; /**< already initialized by real values */
168 typedef struct averaging_s {
169 long int * ring_buffer;
170 int ring_buffer_size;
171 long int ring_buffer_sum;
172 int ring_buffer_head;
176 static averaging_t pressure_averaging = { NULL, 0, 0L, 0 };
177 static averaging_t temperature_averaging = { NULL, 0, 0L, 0 };
181 * Create / allocate averaging buffer
183 * The buffer is initialized with zeros.
185 * @param avg pointer to ring buffer to be allocated
186 * @param size requested buffer size
188 * @return Zero when successful
190 static int averaging_create(averaging_t * avg, int size)
194 avg->ring_buffer = (long int *) malloc(size * sizeof(*avg));
195 if (avg->ring_buffer == NULL)
197 ERROR ("barometer: averaging_create - ring buffer allocation of size %d failed",
202 for (a=0; a<size; ++a)
204 avg->ring_buffer[a] = 0L;
207 avg->ring_buffer_size = size;
208 avg->ring_buffer_sum = 0L;
209 avg->ring_buffer_head = 0;
216 * Delete / free existing averaging buffer
218 * @param avg pointer to the ring buffer to be deleted
220 static void averaging_delete(averaging_t * avg)
222 if (avg->ring_buffer != NULL)
224 free(avg->ring_buffer);
225 avg->ring_buffer = NULL;
227 avg->ring_buffer_size = 0;
228 avg->ring_buffer_sum = 0L;
229 avg->ring_buffer_head = 0;
234 * Add new sample to the averaging buffer
236 * A new averaged value is returned. Note that till the buffer is full
237 * returned value is inaccurate as it is an average of real values and initial
240 * @param avg pointer to the ring buffer
241 * @param sample new sample value
243 * @return Averaged sample value
245 static double averaging_add_sample(averaging_t * avg, long int sample)
249 avg->ring_buffer_sum += sample - avg->ring_buffer[avg->ring_buffer_head];
250 avg->ring_buffer[avg->ring_buffer_head] = sample;
251 avg->ring_buffer_head = (avg->ring_buffer_head+1) % avg->ring_buffer_size;
252 result = (double)(avg->ring_buffer_sum) / (double)(avg->ring_buffer_size);
254 DEBUG ("barometer: averaging_add_sample - added %ld, result = %lf",
262 /* ------------------------ temperature refference ------------------------ */
265 * Linked list type of temperature sensor references
267 typedef struct temperature_list_s {
268 char * sensor_name; /**< sensor name/reference */
269 size_t num_values; /**< number of values (usually one) */
270 _Bool initialized; /**< sensor already provides data */
271 struct temperature_list_s * next; /**< next in the list */
272 } temperature_list_t;
274 static temperature_list_t * temp_list = NULL;
278 * Add new sensor to the temperature reference list
280 * @param list the list
281 * @param sensor reference name (as provided by the config file)
283 * @return Zero when successful
285 static int temp_list_add(temperature_list_t * list, const char * sensor)
287 temperature_list_t * new_temp;
289 new_temp = (temperature_list_t *) malloc(sizeof(*new_temp));
293 new_temp->sensor_name = strdup(sensor);
294 new_temp->initialized = 0;
295 new_temp->num_values = 0;
296 if(new_temp->sensor_name == NULL)
302 new_temp->next = temp_list;
303 temp_list = new_temp;
309 * Delete the whole temperature reference list
311 * @param list the list to be deleted
313 static void temp_list_delete(temperature_list_t ** list)
315 temperature_list_t * tmp;
317 while (*list != NULL)
320 (*list) = (*list)->next;
321 free(tmp->sensor_name);
329 * Get reference temperature value
331 * First initially uc_get_rate_by_name is tried. At the startup due to nondeterministic
332 * order the temperature may not be read yet (then it fails and first measurment gives
333 * only absolute air pressure reading which is acceptable). Once it succedes (should be
334 * second measurement at the latest) we use average of few last readings from
335 * uc_get_history_by_name. It may take few readings to start filling so again we use
336 * uc_get_rate_by_name as a fallback.
337 * The idea is to use basic "noise" filtering (history averaging) across all the values
338 * which given sensor provides (up to given depth). Then we get minimum among
341 * @param result where the result is stored. When not available NAN is stored.
343 * @return Zero when successful
345 static int get_reference_temperature(double * result)
347 temperature_list_t * list = temp_list;
349 gauge_t * values = NULL; /**< rate values */
350 size_t values_num = 0; /**< number of rate values */
353 gauge_t values_history[REF_TEMP_AVG_NUM];
355 double avg_sum; /**< Value sum for computing average */
356 int avg_num; /**< Number of values for computing average */
357 double average; /**< Resulting value average */
366 /* First time need to read current rate to learn how many values are
367 there (typically for temperature it would be just one).
368 We do not expect dynamic changing of number of temperarure values
369 in runtime yet (are there any such cases?). */
370 if(!list->initialized)
372 if(uc_get_rate_by_name(list->sensor_name,
376 DEBUG ("barometer: get_reference_temperature - rate \"%s\" not found yet",
382 DEBUG ("barometer: get_reference_temperature - initialize \"%s\", %zu vals",
386 list->initialized = 1;
387 list->num_values = values_num;
389 for(i=0; i<values_num; ++i)
391 DEBUG ("barometer: get_reference_temperature - rate %d: %lf **",
394 if(!isnan(values[i]))
396 avg_sum += values[i];
404 /* It is OK to get here the first time as well, in the worst case
405 the history will full of NANs. */
406 if(uc_get_history_by_name(list->sensor_name,
411 ERROR ("barometer: get_reference_temperature - history \"%s\" lost",
413 list->initialized = 0;
414 list->num_values = 0;
419 for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
421 DEBUG ("barometer: get_reference_temperature - history %d: %lf",
424 if(!isnan(values_history[i]))
426 avg_sum += values_history[i];
431 if(avg_num == 0) /* still no history? fallback to current */
433 if(uc_get_rate_by_name(list->sensor_name,
437 ERROR ("barometer: get_reference_temperature - rate \"%s\" lost",
439 list->initialized = 0;
440 list->num_values = 0;
445 for(i=0; i<values_num; ++i)
447 DEBUG ("barometer: get_reference_temperature - rate last %d: %lf **",
450 if(!isnan(values[i]))
452 avg_sum += values[i];
462 ERROR ("barometer: get_reference_temperature - could not read \"%s\"",
464 list->initialized = 0;
465 list->num_values = 0;
469 average = avg_sum / (double) avg_num;
472 else if(*result>average)
476 } /* while sensor list */
480 ERROR("barometer: get_reference_temperature - no sensor available (yet?)");
483 DEBUG ("barometer: get_reference_temperature - temp is %lf", *result);
487 /* ------------------------ MPL115 access ------------------------ */
490 * Read the MPL115 sensor conversion coefficients.
492 * These are (device specific) constants so we can read them just once.
494 * @return Zero when successful
496 static int MPL115_read_coeffs(void)
498 uint8_t mpl115_coeffs[MPL115_NUM_COEFFS];
501 int8_t sia0MSB, sia0LSB, sib1MSB, sib1LSB, sib2MSB, sib2LSB;
502 int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
503 int16_t sia0, sib1, sib2, sic12, sic11, sic22;
507 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
513 ERROR ("barometer: read_mpl115_coeffs - problem reading data: %s",
514 sstrerror (errno, errbuf, sizeof (errbuf)));
518 /* Using perhaps less elegant/efficient code, but more readable. */
519 /* a0: 16total 1sign 12int 4fract 0pad */
520 sia0MSB = mpl115_coeffs[0];
521 sia0LSB = mpl115_coeffs[1];
522 sia0 = (int16_t) sia0MSB <<8; /* s16 type, Shift to MSB */
523 sia0 += (int16_t) sia0LSB & 0x00FF; /* Add LSB to 16bit number */
524 mpl115_coeffA0 = (double) (sia0);
525 mpl115_coeffA0 /= 8.0; /* 3 fract bits */
527 /* b1: 16total 1sign 2int 13fract 0pad */
528 sib1MSB= mpl115_coeffs[2];
529 sib1LSB= mpl115_coeffs[3];
530 sib1 = sib1MSB <<8; /* Shift to MSB */
531 sib1 += sib1LSB & 0x00FF; /* Add LSB to 16bit number */
532 mpl115_coeffB1 = (double) (sib1);
533 mpl115_coeffB1 /= 8192.0; /* 13 fract */
535 /* b2: 16total 1sign 1int 14fract 0pad */
536 sib2MSB= mpl115_coeffs[4];
537 sib2LSB= mpl115_coeffs[5];
538 sib2 = sib2MSB <<8; /* Shift to MSB */
539 sib2 += sib2LSB & 0x00FF; /* Add LSB to 16bit number */
540 mpl115_coeffB2 = (double) (sib2);
541 mpl115_coeffB2 /= 16384.0; /* 14 fract */
543 /* c12: 14total 1sign 0int 13fract 9pad */
544 sic12MSB= mpl115_coeffs[6];
545 sic12LSB= mpl115_coeffs[7];
546 sic12 = sic12MSB <<8; /* Shift to MSB only by 8 for MSB */
547 sic12 += sic12LSB & 0x00FF;
548 mpl115_coeffC12 = (double) (sic12);
549 mpl115_coeffC12 /= 4.0; /* 16-14=2 */
550 mpl115_coeffC12 /= 4194304.0; /* 13+9=22 fract */
552 /* c11: 11total 1sign 0int 11fract 11pad */
553 sic11MSB= mpl115_coeffs[8];
554 sic11LSB= mpl115_coeffs[9];
555 sic11 = sic11MSB <<8; /* Shift to MSB only by 8 for MSB */
556 sic11 += sic11LSB & 0x00FF;
557 mpl115_coeffC11 = (double) (sic11);
558 mpl115_coeffC11 /= 32.0; /* 16-11=5 */
559 mpl115_coeffC11 /= 4194304.0; /* 11+11=22 fract */
561 /* c12: 11total 1sign 0int 10fract 15pad */
562 sic22MSB= mpl115_coeffs[10];
563 sic22LSB= mpl115_coeffs[11];
564 sic22 = sic22MSB <<8; /* Shift to MSB only by 8 for MSB */
565 sic22 += sic22LSB & 0x00FF;
566 mpl115_coeffC22 = (double) (sic22);
567 mpl115_coeffC22 /= 32.0; //16-11=5
568 mpl115_coeffC22 /= 33554432.0; /* 10+15=25 fract */
570 DEBUG("barometer: read_mpl115_coeffs: a0=%lf, b1=%lf, b2=%lf, c12=%lf, c11=%lf, c22=%lf",
582 * Convert raw adc values to real data using the sensor coefficients.
584 * @param adc_pressure adc pressure value to be converted
585 * @param adc_temp adc temperature value to be converted
586 * @param pressure computed real pressure
587 * @param temperature computed real temperature
589 static void MPL115_convert_adc_to_real(double adc_pressure,
592 double * temperature)
595 Pcomp = mpl115_coeffA0 + \
596 (mpl115_coeffB1 + mpl115_coeffC11*adc_pressure + mpl115_coeffC12*adc_temp) * adc_pressure + \
597 (mpl115_coeffB2 + mpl115_coeffC22*adc_temp) * adc_temp;
599 *pressure = ((1150.0-500.0) * Pcomp / 1023.0) + 500.0;
600 *temperature = (472.0 - adc_temp) / 5.35 + 25.0;
601 DEBUG ("barometer: convert_adc_to_real - got %lf hPa, %lf C",
608 * Read sensor averegaed measurements
610 * @param pressure averaged measured pressure
611 * @param temperature averaged measured temperature
613 * @return Zero when successful
615 static int MPL115_read_averaged(double * pressure, double * temperature)
617 uint8_t mpl115_conv[MPL115_NUM_CONV];
621 int conv_temperature;
623 double adc_temperature;
629 /* start conversion of both temp and presure */
630 retries = MPL115_CONVERSION_RETRIES;
633 /* write 1 to start conversion */
634 res = i2c_smbus_write_byte_data (i2c_bus_fd,
635 MPL115_CMD_CONVERT_BOTH,
643 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, " \
644 "will retry at most %d more times",
645 sstrerror (errno, errbuf, sizeof (errbuf)),
650 ERROR ("barometer: MPL115_read_averaged - requesting conversion: %s, "\
651 "too many failed retries",
652 sstrerror (errno, errbuf, sizeof (errbuf)));
657 usleep (10000); /* wait 10ms for the conversion */
659 retries=MPL115_CONVERSION_RETRIES;
662 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
672 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
673 "will retry at most %d more times",
674 sstrerror (errno, errbuf, sizeof (errbuf)),
679 ERROR ("barometer: MPL115_read_averaged - reading conversion: %s, " \
680 "too many failed retries",
681 sstrerror (errno, errbuf, sizeof (errbuf)));
686 conv_pressure = ((mpl115_conv[0] << 8) | mpl115_conv[1]) >> 6;
687 conv_temperature = ((mpl115_conv[2] << 8) | mpl115_conv[3]) >> 6;
688 DEBUG ("barometer: MPL115_read_averaged, raw pressure ADC value = %d, " \
689 "raw temperature ADC value = %d",
693 adc_pressure = averaging_add_sample (&pressure_averaging, conv_pressure);
694 adc_temperature = averaging_add_sample (&temperature_averaging, conv_temperature);
696 MPL115_convert_adc_to_real(adc_pressure, adc_temperature, pressure, temperature);
698 DEBUG ("barometer: MPL115_read_averaged - averaged ADC pressure = %lf / temperature = %lf, " \
699 "real pressure = %lf hPa / temperature = %lf C",
708 /* ------------------------ MPL3115 access ------------------------ */
711 * Detect presence of a MPL3115 pressure sensor by checking register "WHO AM I"
713 * @return 1 if MPL3115, 0 otherwise
715 static int MPL3115_detect(void)
719 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_WHO_AM_I);
720 if(res == MPL3115_WHO_AM_I_RESP)
722 DEBUG ("barometer: MPL3115_detect - positive detection");
726 DEBUG ("barometer: MPL3115_detect - negative detection");
731 * Adjusts oversampling to values supported by MPL3115
733 * MPL3115 supports only power of 2 in the range 1 to 128.
735 static void MPL3115_adjust_oversampling(void)
739 if(config_oversample > 100)
742 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_128;
744 else if(config_oversample > 48)
747 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_64;
749 else if(config_oversample > 24)
752 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_32;
754 else if(config_oversample > 12)
757 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_16;
759 else if(config_oversample > 6)
762 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_8;
764 else if(config_oversample > 3)
767 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_4;
769 else if(config_oversample > 1)
772 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_2;
777 oversample_MPL3115 = MPL3115_CTRL_REG1_OST_1;
780 DEBUG("barometer: correcting oversampling for MPL3115 from %d to %d",
783 config_oversample = new_val;
787 * Read sensor averegaed measurements
789 * @param pressure averaged measured pressure
790 * @param temperature averaged measured temperature
792 * @return Zero when successful
794 static int MPL3115_read(double * pressure, double * temperature)
798 __u8 data[MPL3115_NUM_CONV_VALS];
799 long int tmp_value = 0;
802 /* Set Active - activate the device from standby */
803 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
806 ERROR ("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
807 sstrerror (errno, errbuf, sizeof (errbuf)));
811 res = i2c_smbus_write_byte_data(i2c_bus_fd,
812 MPL3115_REG_CTRL_REG1,
813 ctrl | MPL3115_CTRL_REG1_SBYB);
816 ERROR ("barometer: MPL3115_read - problem activating: %s",
817 sstrerror (errno, errbuf, sizeof (errbuf)));
821 /* base sleep is 5ms x OST */
822 usleep(5000 * config_oversample);
824 /* check the flags/status if ready */
825 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
828 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
829 sstrerror (errno, errbuf, sizeof (errbuf)));
833 while ((res & MPL3115_DR_STATUS_DR) != MPL3115_DR_STATUS_DR)
835 /* try some extra sleep... */
838 /* ... and repeat the check. The conversion has to finish sooner or later. */
839 res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
842 ERROR ("barometer: MPL3115_read - cannot read status register: %s",
843 sstrerror (errno, errbuf, sizeof (errbuf)));
848 /* Now read all the data in one block. There is address autoincrement. */
849 res = i2c_smbus_read_i2c_block_data(i2c_bus_fd,
850 MPL3115_REG_OUT_P_MSB,
851 MPL3115_NUM_CONV_VALS,
855 ERROR ("barometer: MPL3115_read - cannot read data registers: %s",
856 sstrerror (errno, errbuf, sizeof (errbuf)));
860 tmp_value = (data[0] << 16) | (data[1] << 8) | data[2];
861 *pressure = ((double) tmp_value) / 4.0 / 16.0 / 100.0;
862 DEBUG ("barometer: MPL3115_read, absolute pressure = %lf hPa", *pressure);
866 data[3] = ~data[3] + 1;
867 *temperature = data[3];
868 *temperature = - *temperature;
872 *temperature = data[3];
875 *temperature += (double)(data[4]) / 256.0;
876 DEBUG ("barometer: MPL3115_read, temperature = %lf C", *temperature);
882 * Initialize MPL3115 for barometeric measurements
884 * @return 0 if successful
886 static int MPL3115_init_sensor(void)
892 /* Reset the sensor. It will reset immediately without ACKing */
893 /* the transaction, so no error handling here. */
894 i2c_smbus_write_byte_data(i2c_bus_fd,
895 MPL3115_REG_CTRL_REG1,
896 MPL3115_CTRL_REG1_RST);
898 /* wait some time for the reset to finish */
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);
909 ERROR ("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
910 sstrerror (errno, errbuf, sizeof (errbuf)));
914 /* Set pressure offset. */
915 /* result = ADCpress + offset [hPa] */
916 offset = (__s8) (config_press_offset * 100.0 / 4.0);
917 res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_P, offset);
920 ERROR ("barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
921 sstrerror (errno, errbuf, sizeof (errbuf)));
925 /* Enable Data Flags in PT_DATA_CFG - flags on both pressure and temp */
926 res = i2c_smbus_write_byte_data(i2c_bus_fd,
927 MPL3115_REG_PT_DATA_CFG,
928 MPL3115_PT_DATA_DREM \
929 | MPL3115_PT_DATA_PDEF \
930 | MPL3115_PT_DATA_TDEF);
933 ERROR ("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
934 sstrerror (errno, errbuf, sizeof (errbuf)));
938 /* Set to barometer with an OSR */
939 res = i2c_smbus_write_byte_data(i2c_bus_fd,
940 MPL3115_REG_CTRL_REG1,
944 ERROR ("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
945 sstrerror (errno, errbuf, sizeof (errbuf)));
953 /* ------------------------ Common functionality ------------------------ */
956 * Convert absolute pressure (in hPa) to mean sea level pressure
958 * Implemented methods are:
959 * - MSLP_NONE - no converions, returns absolute pressure
961 * - MSLP_INTERNATIONAL - see http://en.wikipedia.org/wiki/Atmospheric_pressure#Altitude_atmospheric_pressure_variation
962 * Requires #config_altitude
964 * - MSLP_DEU_WETT - formula as recommended by the Deutsche Wetterdienst. See
965 * http://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel#Theorie
966 * Requires both #config_altitude and temperature reference(s).
968 * @param abs_pressure absloute pressure to be converted
970 * @return mean sea level pressure if successful, NAN otherwise
972 static double abs_to_mean_sea_level_pressure(double abs_pressure)
978 DEBUG ("barometer: abs_to_mean_sea_level_pressure: absPressure = %lf, method = %d",
982 if (config_normalize >= MSLP_DEU_WETT)
984 result = get_reference_temperature(&temp);
991 switch(config_normalize)
997 case MSLP_INTERNATIONAL:
998 mean = abs_pressure / \
999 pow(1.0 - 0.0065*config_altitude/288.15, 0.0065*0.0289644/(8.31447*0.0065));
1004 double E; /* humidity */
1007 E = 5.6402 * (-0.0916 + exp(0.06*temp) );
1009 E = 18.2194 * (1.0463 - exp(-0.0666*temp) );
1010 x = 9.80665 / (287.05 * (temp+273.15 + 0.12*E + 0.0065*config_altitude/2)) * config_altitude;
1011 mean = abs_pressure * exp(x);
1016 ERROR ("barometer: abs_to_mean_sea_level_pressure: wrong conversion method %d",
1018 mean = abs_pressure;
1025 /* ------------------------ main plugin callbacks ------------------------ */
1028 * Main plugin configuration callback (using simple config)
1030 * @param key configuration key we should process
1031 * @param value configuration value we should process
1033 * @return Zero when successful.
1035 static int collectd_barometer_config (const char *key, const char *value)
1037 DEBUG("barometer: collectd_barometer_config");
1039 if (strcasecmp (key, "Device") == 0)
1041 sfree (config_device);
1042 config_device = strdup (value);
1044 else if (strcasecmp (key, "Oversampling") == 0)
1046 int oversampling_tmp = atoi (value);
1047 if (oversampling_tmp < 1 || oversampling_tmp > 1024)
1049 WARNING ("barometer: collectd_barometer_config: invalid oversampling: %d." \
1050 " Allowed values are 1 to 1024 (for MPL115) or 128 (for MPL3115).",
1054 config_oversample = oversampling_tmp;
1056 else if (strcasecmp (key, "Altitude") == 0)
1058 config_altitude = atof (value);
1060 else if (strcasecmp (key, "Normalization") == 0)
1062 int normalize_tmp = atoi (value);
1063 if (normalize_tmp < 0 || normalize_tmp > 2)
1065 WARNING ("barometer: collectd_barometer_config: invalid normalization: %d",
1069 config_normalize = normalize_tmp;
1071 else if (strcasecmp (key, "TemperatureSensor") == 0)
1073 if(temp_list_add(temp_list, value))
1078 else if (strcasecmp (key, "PressureOffset") == 0)
1080 config_press_offset = atof(value);
1082 else if (strcasecmp (key, "TemperatureOffset") == 0)
1084 config_temp_offset = atof(value);
1096 * Shutdown callback.
1098 * Close I2C and delete all the buffers.
1100 * @return Zero when successful (at the moment the only possible outcome)
1102 static int collectd_barometer_shutdown(void)
1104 DEBUG ("barometer: collectd_barometer_shutdown");
1108 averaging_delete (&pressure_averaging);
1109 averaging_delete (&temperature_averaging);
1111 temp_list_delete(&temp_list);
1118 sfree (config_device);
1126 * Plugin read callback for MPL115.
1128 * Dispatching will create values:
1129 * - <hostname>/barometer-mpl115/pressure-normalized
1130 * - <hostname>/barometer-mpl115/pressure-absolute
1131 * - <hostname>/barometer-mpl115/temperature
1133 * @return Zero when successful.
1135 static int MPL115_collectd_barometer_read (void)
1139 double pressure = 0.0;
1140 double temperature = 0.0;
1141 double norm_pressure = 0.0;
1143 value_list_t vl = VALUE_LIST_INIT;
1146 DEBUG("barometer: MPL115_collectd_barometer_read");
1153 /* Rather than delaying init, we will intitialize during first read. This
1154 way at least we have a better chance to have the reference temperature
1155 already available. */
1156 if(!avg_initialized)
1159 for(i=0; i<config_oversample-1; ++i)
1161 result = MPL115_read_averaged(&pressure, &temperature);
1164 ERROR ("barometer: MPL115_collectd_barometer_read - mpl115 read, ignored during init");
1166 DEBUG("barometer: MPL115_collectd_barometer_read - init %d / %d", i+1, config_oversample-1);
1169 avg_initialized = 1;
1172 result = MPL115_read_averaged(&pressure, &temperature);
1176 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1178 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1179 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1180 sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
1185 /* dispatch normalized air pressure */
1186 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1187 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1188 values[0].gauge = norm_pressure;
1189 plugin_dispatch_values (&vl);
1191 /* dispatch absolute air pressure */
1192 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1193 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1194 values[0].gauge = pressure;
1195 plugin_dispatch_values (&vl);
1197 /* dispatch sensor temperature */
1198 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1199 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1200 values[0].gauge = temperature;
1201 plugin_dispatch_values (&vl);
1208 * Plugin read callback for MPL3115.
1210 * Dispatching will create values:
1211 * - <hostname>/barometer-mpl3115/pressure-normalized
1212 * - <hostname>/barometer-mpl3115/pressure-absolute
1213 * - <hostname>/barometer-mpl3115/temperature
1215 * @return Zero when successful.
1217 static int MPL3115_collectd_barometer_read (void)
1221 double pressure = 0.0;
1222 double temperature = 0.0;
1223 double norm_pressure = 0.0;
1225 value_list_t vl = VALUE_LIST_INIT;
1228 DEBUG("barometer: MPL3115_collectd_barometer_read");
1235 result = MPL3115_read(&pressure, &temperature);
1239 norm_pressure = abs_to_mean_sea_level_pressure(pressure);
1241 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
1242 sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
1243 sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
1248 /* dispatch normalized air pressure */
1249 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1250 sstrncpy (vl.type_instance, "normalized", sizeof (vl.type_instance));
1251 values[0].gauge = norm_pressure;
1252 plugin_dispatch_values (&vl);
1254 /* dispatch absolute air pressure */
1255 sstrncpy (vl.type, "pressure", sizeof (vl.type));
1256 sstrncpy (vl.type_instance, "absolute", sizeof (vl.type_instance));
1257 values[0].gauge = pressure;
1258 plugin_dispatch_values (&vl);
1260 /* dispatch sensor temperature */
1261 sstrncpy (vl.type, "temperature", sizeof (vl.type));
1262 sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
1263 values[0].gauge = temperature;
1264 plugin_dispatch_values (&vl);
1271 * Initialization callback
1273 * Check config, initialize I2C bus access, conversion coefficients and averaging
1276 * @return Zero when successful.
1278 static int collectd_barometer_init (void)
1282 DEBUG ("barometer: collectd_barometer_init");
1284 if (config_device == NULL)
1286 ERROR("barometer: collectd_barometer_init I2C bus device not configured");
1290 if (config_normalize >= MSLP_INTERNATIONAL && isnan(config_altitude))
1292 ERROR("barometer: collectd_barometer_init no altitude configured " \
1293 "for mean sea level pressure normalization.");
1297 if (config_normalize == MSLP_DEU_WETT
1301 ERROR("barometer: collectd_barometer_init no temperature reference "\
1302 "configured for mean sea level pressure normalization.");
1307 i2c_bus_fd = open(config_device, O_RDWR);
1310 ERROR ("barometer: collectd_barometer_init problem opening I2C bus device \"%s\": %s (is loaded mod i2c-dev?)",
1312 sstrerror (errno, errbuf, sizeof (errbuf)));
1316 if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0)
1318 ERROR("barometer: collectd_barometer_init problem setting i2c slave address to 0x%02X: %s",
1320 sstrerror (errno, errbuf, sizeof (errbuf)));
1324 /* detect sensor type - MPL115 or MPL3115 */
1325 is_MPL3115 = MPL3115_detect();
1327 /* init correct sensor type */
1328 if(is_MPL3115) /* MPL3115 */
1330 MPL3115_adjust_oversampling();
1332 if(MPL3115_init_sensor())
1335 plugin_register_read ("barometer", MPL3115_collectd_barometer_read);
1339 if (averaging_create (&pressure_averaging, config_oversample))
1341 ERROR("barometer: collectd_barometer_init pressure averaging init failed");
1345 if (averaging_create (&temperature_averaging, config_oversample))
1347 ERROR("barometer: collectd_barometer_init temperature averaging init failed");
1351 if (MPL115_read_coeffs() < 0)
1354 plugin_register_read ("barometer", MPL115_collectd_barometer_read);
1361 /* ------------------------ plugin register / entry point ------------------------ */
1364 * Plugin "entry" - register all callback.
1367 void module_register (void)
1369 plugin_register_config ("barometer",
1370 collectd_barometer_config,
1373 plugin_register_init ("barometer", collectd_barometer_init);
1374 plugin_register_shutdown ("barometer", collectd_barometer_shutdown);