]> git.itanic.dy.fi Git - BME280_driver/blob - bme280.c
Merge pull request #77 from kni/master
[BME280_driver] / bme280.c
1 /**\mainpage\r
2  * Copyright (C) 2018 - 2019 Bosch Sensortec GmbH\r
3  *\r
4  * Redistribution and use in source and binary forms, with or without\r
5  * modification, are permitted provided that the following conditions are met:\r
6  *\r
7  * Redistributions of source code must retain the above copyright\r
8  * notice, this list of conditions and the following disclaimer.\r
9  *\r
10  * Redistributions in binary form must reproduce the above copyright\r
11  * notice, this list of conditions and the following disclaimer in the\r
12  * documentation and/or other materials provided with the distribution.\r
13  *\r
14  * Neither the name of the copyright holder nor the names of the\r
15  * contributors may be used to endorse or promote products derived from\r
16  * this software without specific prior written permission.\r
17  *\r
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
19  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR\r
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
22  * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER\r
23  * OR CONTRIBUTORS BE LIABLE FOR ANY\r
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\r
25  * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,\r
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
31  * ANY WAY OUT OF THE USE OF THIS\r
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE\r
33  *\r
34  * The information provided is believed to be accurate and reliable.\r
35  * The copyright holder assumes no responsibility\r
36  * for the consequences of use\r
37  * of such information nor for any infringement of patents or\r
38  * other rights of third parties which may result from its use.\r
39  * No license is granted by implication or otherwise under any patent or\r
40  * patent rights of the copyright holder.\r
41  *\r
42  * File     bme280.c\r
43  * Date     26 Aug 2019\r
44  * Version  3.3.7\r
45  *\r
46  */\r
47 \r
48 /*! @file bme280.c\r
49  * @brief Sensor driver for BME280 sensor\r
50  */\r
51 #include "bme280.h"\r
52 \r
53 /**\name Internal macros */\r
54 /* To identify osr settings selected by user */\r
55 #define OVERSAMPLING_SETTINGS   UINT8_C(0x07)\r
56 \r
57 /* To identify filter and standby settings selected by user */\r
58 #define FILTER_STANDBY_SETTINGS UINT8_C(0x18)\r
59 \r
60 /*!\r
61  * @brief This internal API puts the device to sleep mode.\r
62  *\r
63  * @param[in] dev : Structure instance of bme280_dev.\r
64  *\r
65  * @return Result of API execution status.\r
66  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
67  */\r
68 static int8_t put_device_to_sleep(const struct bme280_dev *dev);\r
69 \r
70 /*!\r
71  * @brief This internal API writes the power mode in the sensor.\r
72  *\r
73  * @param[in] dev : Structure instance of bme280_dev.\r
74  * @param[in] sensor_mode : Variable which contains the power mode to be set.\r
75  *\r
76  * @return Result of API execution status.\r
77  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
78  */\r
79 static int8_t write_power_mode(uint8_t sensor_mode, const struct bme280_dev *dev);\r
80 \r
81 /*!\r
82  * @brief This internal API is used to validate the device pointer for\r
83  * null conditions.\r
84  *\r
85  * @param[in] dev : Structure instance of bme280_dev.\r
86  *\r
87  * @return Result of API execution status\r
88  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
89  */\r
90 static int8_t null_ptr_check(const struct bme280_dev *dev);\r
91 \r
92 /*!\r
93  * @brief This internal API interleaves the register address between the\r
94  * register data buffer for burst write operation.\r
95  *\r
96  * @param[in] reg_addr : Contains the register address array.\r
97  * @param[out] temp_buff : Contains the temporary buffer to store the\r
98  * register data and register address.\r
99  * @param[in] reg_data : Contains the register data to be written in the\r
100  * temporary buffer.\r
101  * @param[in] len : No of bytes of data to be written for burst write.\r
102  */\r
103 static void interleave_reg_addr(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint8_t len);\r
104 \r
105 /*!\r
106  * @brief This internal API reads the calibration data from the sensor, parse\r
107  * it and store in the device structure.\r
108  *\r
109  * @param[in] dev : Structure instance of bme280_dev.\r
110  *\r
111  * @return Result of API execution status\r
112  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
113  */\r
114 static int8_t get_calib_data(struct bme280_dev *dev);\r
115 \r
116 /*!\r
117  *  @brief This internal API is used to parse the temperature and\r
118  *  pressure calibration data and store it in the device structure.\r
119  *\r
120  *  @param[out] dev : Structure instance of bme280_dev to store the calib data.\r
121  *  @param[in] reg_data : Contains the calibration data to be parsed.\r
122  */\r
123 static void parse_temp_press_calib_data(const uint8_t *reg_data, struct bme280_dev *dev);\r
124 \r
125 /*!\r
126  *  @brief This internal API is used to parse the humidity calibration data\r
127  *  and store it in device structure.\r
128  *\r
129  *  @param[out] dev : Structure instance of bme280_dev to store the calib data.\r
130  *  @param[in] reg_data : Contains calibration data to be parsed.\r
131  */\r
132 static void parse_humidity_calib_data(const uint8_t *reg_data, struct bme280_dev *dev);\r
133 \r
134 #ifdef BME280_FLOAT_ENABLE\r
135 \r
136 /*!\r
137  * @brief This internal API is used to compensate the raw pressure data and\r
138  * return the compensated pressure data in double data type.\r
139  *\r
140  * @param[in] uncomp_data : Contains the uncompensated pressure data.\r
141  * @param[in] calib_data : Pointer to the calibration data structure.\r
142  *\r
143  * @return Compensated pressure data.\r
144  * @retval Compensated pressure data in double.\r
145  */\r
146 static double compensate_pressure(const struct bme280_uncomp_data *uncomp_data,\r
147                                   const struct bme280_calib_data *calib_data);\r
148 \r
149 /*!\r
150  * @brief This internal API is used to compensate the raw humidity data and\r
151  * return the compensated humidity data in double data type.\r
152  *\r
153  * @param[in] uncomp_data : Contains the uncompensated humidity data.\r
154  * @param[in] calib_data : Pointer to the calibration data structure.\r
155  *\r
156  * @return Compensated humidity data.\r
157  * @retval Compensated humidity data in double.\r
158  */\r
159 static double compensate_humidity(const struct bme280_uncomp_data *uncomp_data,\r
160                                   const struct bme280_calib_data *calib_data);\r
161 \r
162 /*!\r
163  * @brief This internal API is used to compensate the raw temperature data and\r
164  * return the compensated temperature data in double data type.\r
165  *\r
166  * @param[in] uncomp_data : Contains the uncompensated temperature data.\r
167  * @param[in] calib_data : Pointer to calibration data structure.\r
168  *\r
169  * @return Compensated temperature data.\r
170  * @retval Compensated temperature data in double.\r
171  */\r
172 static double compensate_temperature(const struct bme280_uncomp_data *uncomp_data,\r
173                                      struct bme280_calib_data *calib_data);\r
174 \r
175 #else\r
176 \r
177 /*!\r
178  * @brief This internal API is used to compensate the raw temperature data and\r
179  * return the compensated temperature data in integer data type.\r
180  *\r
181  * @param[in] uncomp_data : Contains the uncompensated temperature data.\r
182  * @param[in] calib_data : Pointer to calibration data structure.\r
183  *\r
184  * @return Compensated temperature data.\r
185  * @retval Compensated temperature data in integer.\r
186  */\r
187 static int32_t compensate_temperature(const struct bme280_uncomp_data *uncomp_data,\r
188                                       struct bme280_calib_data *calib_data);\r
189 \r
190 /*!\r
191  * @brief This internal API is used to compensate the raw pressure data and\r
192  * return the compensated pressure data in integer data type.\r
193  *\r
194  * @param[in] uncomp_data : Contains the uncompensated pressure data.\r
195  * @param[in] calib_data : Pointer to the calibration data structure.\r
196  *\r
197  * @return Compensated pressure data.\r
198  * @retval Compensated pressure data in integer.\r
199  */\r
200 static uint32_t compensate_pressure(const struct bme280_uncomp_data *uncomp_data,\r
201                                     const struct bme280_calib_data *calib_data);\r
202 \r
203 /*!\r
204  * @brief This internal API is used to compensate the raw humidity data and\r
205  * return the compensated humidity data in integer data type.\r
206  *\r
207  * @param[in] uncomp_data : Contains the uncompensated humidity data.\r
208  * @param[in] calib_data : Pointer to the calibration data structure.\r
209  *\r
210  * @return Compensated humidity data.\r
211  * @retval Compensated humidity data in integer.\r
212  */\r
213 static uint32_t compensate_humidity(const struct bme280_uncomp_data *uncomp_data,\r
214                                     const struct bme280_calib_data *calib_data);\r
215 \r
216 #endif\r
217 \r
218 /*!\r
219  * @brief This internal API is used to identify the settings which the user\r
220  * wants to modify in the sensor.\r
221  *\r
222  * @param[in] sub_settings : Contains the settings subset to identify particular\r
223  * group of settings which the user is interested to change.\r
224  * @param[in] desired_settings : Contains the user specified settings.\r
225  *\r
226  * @return Indicates whether user is interested to modify the settings which\r
227  * are related to sub_settings.\r
228  * @retval True -> User wants to modify this group of settings\r
229  * @retval False -> User does not want to modify this group of settings\r
230  */\r
231 static uint8_t are_settings_changed(uint8_t sub_settings, uint8_t desired_settings);\r
232 \r
233 /*!\r
234  * @brief This API sets the humidity oversampling settings of the sensor.\r
235  *\r
236  * @param[in] dev : Structure instance of bme280_dev.\r
237  *\r
238  * @return Result of API execution status\r
239  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
240  */\r
241 static int8_t set_osr_humidity_settings(const struct bme280_settings *settings, const struct bme280_dev *dev);\r
242 \r
243 /*!\r
244  * @brief This internal API sets the oversampling settings for pressure,\r
245  * temperature and humidity in the sensor.\r
246  *\r
247  * @param[in] desired_settings : Variable used to select the settings which\r
248  * are to be set.\r
249  * @param[in] dev : Structure instance of bme280_dev.\r
250  *\r
251  * @return Result of API execution status\r
252  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
253  */\r
254 static int8_t set_osr_settings(uint8_t desired_settings,\r
255                                const struct bme280_settings *settings,\r
256                                const struct bme280_dev *dev);\r
257 \r
258 /*!\r
259  * @brief This API sets the pressure and/or temperature oversampling settings\r
260  * in the sensor according to the settings selected by the user.\r
261  *\r
262  * @param[in] dev : Structure instance of bme280_dev.\r
263  * @param[in] desired_settings: variable to select the pressure and/or\r
264  * temperature oversampling settings.\r
265  *\r
266  * @return Result of API execution status\r
267  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
268  */\r
269 static int8_t set_osr_press_temp_settings(uint8_t desired_settings,\r
270                                           const struct bme280_settings *settings,\r
271                                           const struct bme280_dev *dev);\r
272 \r
273 /*!\r
274  * @brief This internal API fills the pressure oversampling settings provided by\r
275  * the user in the data buffer so as to write in the sensor.\r
276  *\r
277  * @param[in] dev : Structure instance of bme280_dev.\r
278  * @param[out] reg_data : Variable which is filled according to the pressure\r
279  * oversampling data provided by the user.\r
280  */\r
281 static void fill_osr_press_settings(uint8_t *reg_data, const struct bme280_settings *settings);\r
282 \r
283 /*!\r
284  * @brief This internal API fills the temperature oversampling settings provided\r
285  * by the user in the data buffer so as to write in the sensor.\r
286  *\r
287  * @param[in] dev : Structure instance of bme280_dev.\r
288  * @param[out] reg_data : Variable which is filled according to the temperature\r
289  * oversampling data provided by the user.\r
290  */\r
291 static void fill_osr_temp_settings(uint8_t *reg_data, const struct bme280_settings *settings);\r
292 \r
293 /*!\r
294  * @brief This internal API sets the filter and/or standby duration settings\r
295  * in the sensor according to the settings selected by the user.\r
296  *\r
297  * @param[in] dev : Structure instance of bme280_dev.\r
298  * @param[in] desired_settings : variable to select the filter and/or\r
299  * standby duration settings.\r
300  *\r
301  * @return Result of API execution status\r
302  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
303  */\r
304 static int8_t set_filter_standby_settings(uint8_t desired_settings,\r
305                                           const struct bme280_settings *settings,\r
306                                           const struct bme280_dev *dev);\r
307 \r
308 /*!\r
309  * @brief This internal API fills the filter settings provided by the user\r
310  * in the data buffer so as to write in the sensor.\r
311  *\r
312  * @param[in] dev : Structure instance of bme280_dev.\r
313  * @param[out] reg_data : Variable which is filled according to the filter\r
314  * settings data provided by the user.\r
315  */\r
316 static void fill_filter_settings(uint8_t *reg_data, const struct bme280_settings *settings);\r
317 \r
318 /*!\r
319  * @brief This internal API fills the standby duration settings provided by the\r
320  * user in the data buffer so as to write in the sensor.\r
321  *\r
322  * @param[in] dev : Structure instance of bme280_dev.\r
323  * @param[out] reg_data : Variable which is filled according to the standby\r
324  * settings data provided by the user.\r
325  */\r
326 static void fill_standby_settings(uint8_t *reg_data, const struct bme280_settings *settings);\r
327 \r
328 /*!\r
329  * @brief This internal API parse the oversampling(pressure, temperature\r
330  * and humidity), filter and standby duration settings and store in the\r
331  * device structure.\r
332  *\r
333  * @param[out] dev : Structure instance of bme280_dev.\r
334  * @param[in] reg_data : Register data to be parsed.\r
335  */\r
336 static void parse_device_settings(const uint8_t *reg_data, struct bme280_settings *settings);\r
337 \r
338 /*!\r
339  * @brief This internal API reloads the already existing device settings in the\r
340  * sensor after soft reset.\r
341  *\r
342  * @param[in] dev : Structure instance of bme280_dev.\r
343  * @param[in] settings : Pointer variable which contains the settings to\r
344  * be set in the sensor.\r
345  *\r
346  * @return Result of API execution status\r
347  * @retval zero -> Success / +ve value -> Warning / -ve value -> Error\r
348  */\r
349 static int8_t reload_device_settings(const struct bme280_settings *settings, const struct bme280_dev *dev);\r
350 \r
351 /****************** Global Function Definitions *******************************/\r
352 \r
353 /*!\r
354  *  @brief This API is the entry point.\r
355  *  It reads the chip-id and calibration data from the sensor.\r
356  */\r
357 int8_t bme280_init(struct bme280_dev *dev)\r
358 {\r
359     int8_t rslt;\r
360 \r
361     /* chip id read try count */\r
362     uint8_t try_count = 5;\r
363     uint8_t chip_id = 0;\r
364 \r
365     /* Check for null pointer in the device structure*/\r
366     rslt = null_ptr_check(dev);\r
367 \r
368     /* Proceed if null check is fine */\r
369     if (rslt == BME280_OK)\r
370     {\r
371         while (try_count)\r
372         {\r
373             /* Read the chip-id of bme280 sensor */\r
374             rslt = bme280_get_regs(BME280_CHIP_ID_ADDR, &chip_id, 1, dev);\r
375 \r
376             /* Check for chip id validity */\r
377             if ((rslt == BME280_OK) && (chip_id == BME280_CHIP_ID))\r
378             {\r
379                 dev->chip_id = chip_id;\r
380 \r
381                 /* Reset the sensor */\r
382                 rslt = bme280_soft_reset(dev);\r
383                 if (rslt == BME280_OK)\r
384                 {\r
385                     /* Read the calibration data */\r
386                     rslt = get_calib_data(dev);\r
387                 }\r
388                 break;\r
389             }\r
390 \r
391             /* Wait for 1 ms */\r
392             dev->delay_ms(1);\r
393             --try_count;\r
394         }\r
395 \r
396         /* Chip id check failed */\r
397         if (!try_count)\r
398         {\r
399             rslt = BME280_E_DEV_NOT_FOUND;\r
400         }\r
401     }\r
402 \r
403     return rslt;\r
404 }\r
405 \r
406 /*!\r
407  * @brief This API reads the data from the given register address of the sensor.\r
408  */\r
409 int8_t bme280_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, const struct bme280_dev *dev)\r
410 {\r
411     int8_t rslt;\r
412 \r
413     /* Check for null pointer in the device structure*/\r
414     rslt = null_ptr_check(dev);\r
415 \r
416     /* Proceed if null check is fine */\r
417     if (rslt == BME280_OK)\r
418     {\r
419         /* If interface selected is SPI */\r
420         if (dev->intf != BME280_I2C_INTF)\r
421         {\r
422             reg_addr = reg_addr | 0x80;\r
423         }\r
424 \r
425         /* Read the data  */\r
426         rslt = dev->read(dev->dev_id, reg_addr, reg_data, len);\r
427 \r
428         /* Check for communication error */\r
429         if (rslt != BME280_OK)\r
430         {\r
431             rslt = BME280_E_COMM_FAIL;\r
432         }\r
433     }\r
434 \r
435     return rslt;\r
436 }\r
437 \r
438 /*!\r
439  * @brief This API writes the given data to the register address\r
440  * of the sensor.\r
441  */\r
442 int8_t bme280_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, const struct bme280_dev *dev)\r
443 {\r
444     int8_t rslt;\r
445     uint8_t temp_buff[20]; /* Typically not to write more than 10 registers */\r
446 \r
447     if (len > 10)\r
448     {\r
449         len = 10;\r
450     }\r
451     uint16_t temp_len;\r
452     uint8_t reg_addr_cnt;\r
453 \r
454     /* Check for null pointer in the device structure*/\r
455     rslt = null_ptr_check(dev);\r
456 \r
457     /* Check for arguments validity */\r
458     if ((rslt == BME280_OK) && (reg_addr != NULL) && (reg_data != NULL))\r
459     {\r
460         if (len != 0)\r
461         {\r
462             temp_buff[0] = reg_data[0];\r
463 \r
464             /* If interface selected is SPI */\r
465             if (dev->intf != BME280_I2C_INTF)\r
466             {\r
467                 for (reg_addr_cnt = 0; reg_addr_cnt < len; reg_addr_cnt++)\r
468                 {\r
469                     reg_addr[reg_addr_cnt] = reg_addr[reg_addr_cnt] & 0x7F;\r
470                 }\r
471             }\r
472 \r
473             /* Burst write mode */\r
474             if (len > 1)\r
475             {\r
476                 /* Interleave register address w.r.t data for\r
477                  * burst write\r
478                  */\r
479                 interleave_reg_addr(reg_addr, temp_buff, reg_data, len);\r
480                 temp_len = ((len * 2) - 1);\r
481             }\r
482             else\r
483             {\r
484                 temp_len = len;\r
485             }\r
486             rslt = dev->write(dev->dev_id, reg_addr[0], temp_buff, temp_len);\r
487 \r
488             /* Check for communication error */\r
489             if (rslt != BME280_OK)\r
490             {\r
491                 rslt = BME280_E_COMM_FAIL;\r
492             }\r
493         }\r
494         else\r
495         {\r
496             rslt = BME280_E_INVALID_LEN;\r
497         }\r
498     }\r
499     else\r
500     {\r
501         rslt = BME280_E_NULL_PTR;\r
502     }\r
503 \r
504     return rslt;\r
505 }\r
506 \r
507 /*!\r
508  * @brief This API sets the oversampling, filter and standby duration\r
509  * (normal mode) settings in the sensor.\r
510  */\r
511 int8_t bme280_set_sensor_settings(uint8_t desired_settings, const struct bme280_dev *dev)\r
512 {\r
513     int8_t rslt;\r
514     uint8_t sensor_mode;\r
515 \r
516     /* Check for null pointer in the device structure*/\r
517     rslt = null_ptr_check(dev);\r
518 \r
519     /* Proceed if null check is fine */\r
520     if (rslt == BME280_OK)\r
521     {\r
522         rslt = bme280_get_sensor_mode(&sensor_mode, dev);\r
523         if ((rslt == BME280_OK) && (sensor_mode != BME280_SLEEP_MODE))\r
524         {\r
525             rslt = put_device_to_sleep(dev);\r
526         }\r
527         if (rslt == BME280_OK)\r
528         {\r
529             /* Check if user wants to change oversampling\r
530              * settings\r
531              */\r
532             if (are_settings_changed(OVERSAMPLING_SETTINGS, desired_settings))\r
533             {\r
534                 rslt = set_osr_settings(desired_settings, &dev->settings, dev);\r
535             }\r
536 \r
537             /* Check if user wants to change filter and/or\r
538              * standby settings\r
539              */\r
540             if ((rslt == BME280_OK) && are_settings_changed(FILTER_STANDBY_SETTINGS, desired_settings))\r
541             {\r
542                 rslt = set_filter_standby_settings(desired_settings, &dev->settings, dev);\r
543             }\r
544         }\r
545     }\r
546 \r
547     return rslt;\r
548 }\r
549 \r
550 /*!\r
551  * @brief This API gets the oversampling, filter and standby duration\r
552  * (normal mode) settings from the sensor.\r
553  */\r
554 int8_t bme280_get_sensor_settings(struct bme280_dev *dev)\r
555 {\r
556     int8_t rslt;\r
557     uint8_t reg_data[4];\r
558 \r
559     /* Check for null pointer in the device structure*/\r
560     rslt = null_ptr_check(dev);\r
561 \r
562     /* Proceed if null check is fine */\r
563     if (rslt == BME280_OK)\r
564     {\r
565         rslt = bme280_get_regs(BME280_CTRL_HUM_ADDR, reg_data, 4, dev);\r
566         if (rslt == BME280_OK)\r
567         {\r
568             parse_device_settings(reg_data, &dev->settings);\r
569         }\r
570     }\r
571 \r
572     return rslt;\r
573 }\r
574 \r
575 /*!\r
576  * @brief This API sets the power mode of the sensor.\r
577  */\r
578 int8_t bme280_set_sensor_mode(uint8_t sensor_mode, const struct bme280_dev *dev)\r
579 {\r
580     int8_t rslt;\r
581     uint8_t last_set_mode;\r
582 \r
583     /* Check for null pointer in the device structure*/\r
584     rslt = null_ptr_check(dev);\r
585     if (rslt == BME280_OK)\r
586     {\r
587         rslt = bme280_get_sensor_mode(&last_set_mode, dev);\r
588 \r
589         /* If the sensor is not in sleep mode put the device to sleep\r
590          * mode\r
591          */\r
592         if ((rslt == BME280_OK) && (last_set_mode != BME280_SLEEP_MODE))\r
593         {\r
594             rslt = put_device_to_sleep(dev);\r
595         }\r
596 \r
597         /* Set the power mode */\r
598         if (rslt == BME280_OK)\r
599         {\r
600             rslt = write_power_mode(sensor_mode, dev);\r
601         }\r
602     }\r
603 \r
604     return rslt;\r
605 }\r
606 \r
607 /*!\r
608  * @brief This API gets the power mode of the sensor.\r
609  */\r
610 int8_t bme280_get_sensor_mode(uint8_t *sensor_mode, const struct bme280_dev *dev)\r
611 {\r
612     int8_t rslt;\r
613 \r
614     /* Check for null pointer in the device structure*/\r
615     rslt = null_ptr_check(dev);\r
616     if (rslt == BME280_OK)\r
617     {\r
618         /* Read the power mode register */\r
619         rslt = bme280_get_regs(BME280_PWR_CTRL_ADDR, sensor_mode, 1, dev);\r
620 \r
621         /* Assign the power mode in the device structure */\r
622         *sensor_mode = BME280_GET_BITS_POS_0(*sensor_mode, BME280_SENSOR_MODE);\r
623     }\r
624 \r
625     return rslt;\r
626 }\r
627 \r
628 /*!\r
629  * @brief This API performs the soft reset of the sensor.\r
630  */\r
631 int8_t bme280_soft_reset(const struct bme280_dev *dev)\r
632 {\r
633     int8_t rslt;\r
634     uint8_t reg_addr = BME280_RESET_ADDR;\r
635     uint8_t status_reg = 0;\r
636     uint8_t try_run = 5;\r
637 \r
638     /* 0xB6 is the soft reset command */\r
639     uint8_t soft_rst_cmd = BME280_SOFT_RESET_COMMAND;\r
640 \r
641     /* Check for null pointer in the device structure*/\r
642     rslt = null_ptr_check(dev);\r
643 \r
644     /* Proceed if null check is fine */\r
645     if (rslt == BME280_OK)\r
646     {\r
647         /* Write the soft reset command in the sensor */\r
648         rslt = bme280_set_regs(&reg_addr, &soft_rst_cmd, 1, dev);\r
649 \r
650         if (rslt == BME280_OK)\r
651         {\r
652             /* If NVM not copied yet, Wait for NVM to copy */\r
653             do\r
654             {\r
655                 /* As per data sheet - Table 1, startup time is 2 ms. */\r
656                 dev->delay_ms(2);\r
657                 rslt = bme280_get_regs(BME280_STATUS_REG_ADDR, &status_reg, 1, dev);\r
658             } while ((rslt == BME280_OK) && (try_run--) && (status_reg & BME280_STATUS_IM_UPDATE));\r
659 \r
660             if (status_reg & BME280_STATUS_IM_UPDATE)\r
661             {\r
662                 rslt = BME280_E_NVM_COPY_FAILED;\r
663             }\r
664 \r
665         }\r
666     }\r
667 \r
668     return rslt;\r
669 }\r
670 \r
671 /*!\r
672  * @brief This API reads the pressure, temperature and humidity data from the\r
673  * sensor, compensates the data and store it in the bme280_data structure\r
674  * instance passed by the user.\r
675  */\r
676 int8_t bme280_get_sensor_data(uint8_t sensor_comp, struct bme280_data *comp_data, struct bme280_dev *dev)\r
677 {\r
678     int8_t rslt;\r
679 \r
680     /* Array to store the pressure, temperature and humidity data read from\r
681      * the sensor\r
682      */\r
683     uint8_t reg_data[BME280_P_T_H_DATA_LEN] = { 0 };\r
684     struct bme280_uncomp_data uncomp_data = { 0 };\r
685 \r
686     /* Check for null pointer in the device structure*/\r
687     rslt = null_ptr_check(dev);\r
688     if ((rslt == BME280_OK) && (comp_data != NULL))\r
689     {\r
690         /* Read the pressure and temperature data from the sensor */\r
691         rslt = bme280_get_regs(BME280_DATA_ADDR, reg_data, BME280_P_T_H_DATA_LEN, dev);\r
692         if (rslt == BME280_OK)\r
693         {\r
694             /* Parse the read data from the sensor */\r
695             bme280_parse_sensor_data(reg_data, &uncomp_data);\r
696 \r
697             /* Compensate the pressure and/or temperature and/or\r
698              * humidity data from the sensor\r
699              */\r
700             rslt = bme280_compensate_data(sensor_comp, &uncomp_data, comp_data, &dev->calib_data);\r
701         }\r
702     }\r
703     else\r
704     {\r
705         rslt = BME280_E_NULL_PTR;\r
706     }\r
707 \r
708     return rslt;\r
709 }\r
710 \r
711 /*!\r
712  *  @brief This API is used to parse the pressure, temperature and\r
713  *  humidity data and store it in the bme280_uncomp_data structure instance.\r
714  */\r
715 void bme280_parse_sensor_data(const uint8_t *reg_data, struct bme280_uncomp_data *uncomp_data)\r
716 {\r
717     /* Variables to store the sensor data */\r
718     uint32_t data_xlsb;\r
719     uint32_t data_lsb;\r
720     uint32_t data_msb;\r
721 \r
722     /* Store the parsed register values for pressure data */\r
723     data_msb = (uint32_t)reg_data[0] << 12;\r
724     data_lsb = (uint32_t)reg_data[1] << 4;\r
725     data_xlsb = (uint32_t)reg_data[2] >> 4;\r
726     uncomp_data->pressure = data_msb | data_lsb | data_xlsb;\r
727 \r
728     /* Store the parsed register values for temperature data */\r
729     data_msb = (uint32_t)reg_data[3] << 12;\r
730     data_lsb = (uint32_t)reg_data[4] << 4;\r
731     data_xlsb = (uint32_t)reg_data[5] >> 4;\r
732     uncomp_data->temperature = data_msb | data_lsb | data_xlsb;\r
733 \r
734     /* Store the parsed register values for temperature data */\r
735     data_lsb = (uint32_t)reg_data[6] << 8;\r
736     data_msb = (uint32_t)reg_data[7];\r
737     uncomp_data->humidity = data_msb | data_lsb;\r
738 }\r
739 \r
740 /*!\r
741  * @brief This API is used to compensate the pressure and/or\r
742  * temperature and/or humidity data according to the component selected\r
743  * by the user.\r
744  */\r
745 int8_t bme280_compensate_data(uint8_t sensor_comp,\r
746                               const struct bme280_uncomp_data *uncomp_data,\r
747                               struct bme280_data *comp_data,\r
748                               struct bme280_calib_data *calib_data)\r
749 {\r
750     int8_t rslt = BME280_OK;\r
751 \r
752     if ((uncomp_data != NULL) && (comp_data != NULL) && (calib_data != NULL))\r
753     {\r
754         /* Initialize to zero */\r
755         comp_data->temperature = 0;\r
756         comp_data->pressure = 0;\r
757         comp_data->humidity = 0;\r
758 \r
759         /* If pressure or temperature component is selected */\r
760         if (sensor_comp & (BME280_PRESS | BME280_TEMP | BME280_HUM))\r
761         {\r
762             /* Compensate the temperature data */\r
763             comp_data->temperature = compensate_temperature(uncomp_data, calib_data);\r
764         }\r
765         if (sensor_comp & BME280_PRESS)\r
766         {\r
767             /* Compensate the pressure data */\r
768             comp_data->pressure = compensate_pressure(uncomp_data, calib_data);\r
769         }\r
770         if (sensor_comp & BME280_HUM)\r
771         {\r
772             /* Compensate the humidity data */\r
773             comp_data->humidity = compensate_humidity(uncomp_data, calib_data);\r
774         }\r
775     }\r
776     else\r
777     {\r
778         rslt = BME280_E_NULL_PTR;\r
779     }\r
780 \r
781     return rslt;\r
782 }\r
783 \r
784 /*!\r
785  * @brief This internal API sets the oversampling settings for pressure,\r
786  * temperature and humidity in the sensor.\r
787  */\r
788 static int8_t set_osr_settings(uint8_t desired_settings,\r
789                                const struct bme280_settings *settings,\r
790                                const struct bme280_dev *dev)\r
791 {\r
792     int8_t rslt = BME280_W_INVALID_OSR_MACRO;\r
793 \r
794     if (desired_settings & BME280_OSR_HUM_SEL)\r
795     {\r
796         rslt = set_osr_humidity_settings(settings, dev);\r
797     }\r
798     if (desired_settings & (BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL))\r
799     {\r
800         rslt = set_osr_press_temp_settings(desired_settings, settings, dev);\r
801     }\r
802 \r
803     return rslt;\r
804 }\r
805 \r
806 /*!\r
807  * @brief This API sets the humidity oversampling settings of the sensor.\r
808  */\r
809 static int8_t set_osr_humidity_settings(const struct bme280_settings *settings, const struct bme280_dev *dev)\r
810 {\r
811     int8_t rslt;\r
812     uint8_t ctrl_hum;\r
813     uint8_t ctrl_meas;\r
814     uint8_t reg_addr = BME280_CTRL_HUM_ADDR;\r
815 \r
816     ctrl_hum = settings->osr_h & BME280_CTRL_HUM_MSK;\r
817 \r
818     /* Write the humidity control value in the register */\r
819     rslt = bme280_set_regs(&reg_addr, &ctrl_hum, 1, dev);\r
820 \r
821     /* Humidity related changes will be only effective after a\r
822      * write operation to ctrl_meas register\r
823      */\r
824     if (rslt == BME280_OK)\r
825     {\r
826         reg_addr = BME280_CTRL_MEAS_ADDR;\r
827         rslt = bme280_get_regs(reg_addr, &ctrl_meas, 1, dev);\r
828         if (rslt == BME280_OK)\r
829         {\r
830             rslt = bme280_set_regs(&reg_addr, &ctrl_meas, 1, dev);\r
831         }\r
832     }\r
833 \r
834     return rslt;\r
835 }\r
836 \r
837 /*!\r
838  * @brief This API sets the pressure and/or temperature oversampling settings\r
839  * in the sensor according to the settings selected by the user.\r
840  */\r
841 static int8_t set_osr_press_temp_settings(uint8_t desired_settings,\r
842                                           const struct bme280_settings *settings,\r
843                                           const struct bme280_dev *dev)\r
844 {\r
845     int8_t rslt;\r
846     uint8_t reg_addr = BME280_CTRL_MEAS_ADDR;\r
847     uint8_t reg_data;\r
848 \r
849     rslt = bme280_get_regs(reg_addr, &reg_data, 1, dev);\r
850     if (rslt == BME280_OK)\r
851     {\r
852         if (desired_settings & BME280_OSR_PRESS_SEL)\r
853         {\r
854             fill_osr_press_settings(&reg_data, settings);\r
855         }\r
856         if (desired_settings & BME280_OSR_TEMP_SEL)\r
857         {\r
858             fill_osr_temp_settings(&reg_data, settings);\r
859         }\r
860 \r
861         /* Write the oversampling settings in the register */\r
862         rslt = bme280_set_regs(&reg_addr, &reg_data, 1, dev);\r
863     }\r
864 \r
865     return rslt;\r
866 }\r
867 \r
868 /*!\r
869  * @brief This internal API sets the filter and/or standby duration settings\r
870  * in the sensor according to the settings selected by the user.\r
871  */\r
872 static int8_t set_filter_standby_settings(uint8_t desired_settings,\r
873                                           const struct bme280_settings *settings,\r
874                                           const struct bme280_dev *dev)\r
875 {\r
876     int8_t rslt;\r
877     uint8_t reg_addr = BME280_CONFIG_ADDR;\r
878     uint8_t reg_data;\r
879 \r
880     rslt = bme280_get_regs(reg_addr, &reg_data, 1, dev);\r
881     if (rslt == BME280_OK)\r
882     {\r
883         if (desired_settings & BME280_FILTER_SEL)\r
884         {\r
885             fill_filter_settings(&reg_data, settings);\r
886         }\r
887         if (desired_settings & BME280_STANDBY_SEL)\r
888         {\r
889             fill_standby_settings(&reg_data, settings);\r
890         }\r
891 \r
892         /* Write the oversampling settings in the register */\r
893         rslt = bme280_set_regs(&reg_addr, &reg_data, 1, dev);\r
894     }\r
895 \r
896     return rslt;\r
897 }\r
898 \r
899 /*!\r
900  * @brief This internal API fills the filter settings provided by the user\r
901  * in the data buffer so as to write in the sensor.\r
902  */\r
903 static void fill_filter_settings(uint8_t *reg_data, const struct bme280_settings *settings)\r
904 {\r
905     *reg_data = BME280_SET_BITS(*reg_data, BME280_FILTER, settings->filter);\r
906 }\r
907 \r
908 /*!\r
909  * @brief This internal API fills the standby duration settings provided by\r
910  * the user in the data buffer so as to write in the sensor.\r
911  */\r
912 static void fill_standby_settings(uint8_t *reg_data, const struct bme280_settings *settings)\r
913 {\r
914     *reg_data = BME280_SET_BITS(*reg_data, BME280_STANDBY, settings->standby_time);\r
915 }\r
916 \r
917 /*!\r
918  * @brief This internal API fills the pressure oversampling settings provided by\r
919  * the user in the data buffer so as to write in the sensor.\r
920  */\r
921 static void fill_osr_press_settings(uint8_t *reg_data, const struct bme280_settings *settings)\r
922 {\r
923     *reg_data = BME280_SET_BITS(*reg_data, BME280_CTRL_PRESS, settings->osr_p);\r
924 }\r
925 \r
926 /*!\r
927  * @brief This internal API fills the temperature oversampling settings\r
928  * provided by the user in the data buffer so as to write in the sensor.\r
929  */\r
930 static void fill_osr_temp_settings(uint8_t *reg_data, const struct bme280_settings *settings)\r
931 {\r
932     *reg_data = BME280_SET_BITS(*reg_data, BME280_CTRL_TEMP, settings->osr_t);\r
933 }\r
934 \r
935 /*!\r
936  * @brief This internal API parse the oversampling(pressure, temperature\r
937  * and humidity), filter and standby duration settings and store in the\r
938  * device structure.\r
939  */\r
940 static void parse_device_settings(const uint8_t *reg_data, struct bme280_settings *settings)\r
941 {\r
942     settings->osr_h = BME280_GET_BITS_POS_0(reg_data[0], BME280_CTRL_HUM);\r
943     settings->osr_p = BME280_GET_BITS(reg_data[2], BME280_CTRL_PRESS);\r
944     settings->osr_t = BME280_GET_BITS(reg_data[2], BME280_CTRL_TEMP);\r
945     settings->filter = BME280_GET_BITS(reg_data[3], BME280_FILTER);\r
946     settings->standby_time = BME280_GET_BITS(reg_data[3], BME280_STANDBY);\r
947 }\r
948 \r
949 /*!\r
950  * @brief This internal API writes the power mode in the sensor.\r
951  */\r
952 static int8_t write_power_mode(uint8_t sensor_mode, const struct bme280_dev *dev)\r
953 {\r
954     int8_t rslt;\r
955     uint8_t reg_addr = BME280_PWR_CTRL_ADDR;\r
956 \r
957     /* Variable to store the value read from power mode register */\r
958     uint8_t sensor_mode_reg_val;\r
959 \r
960     /* Read the power mode register */\r
961     rslt = bme280_get_regs(reg_addr, &sensor_mode_reg_val, 1, dev);\r
962 \r
963     /* Set the power mode */\r
964     if (rslt == BME280_OK)\r
965     {\r
966         sensor_mode_reg_val = BME280_SET_BITS_POS_0(sensor_mode_reg_val, BME280_SENSOR_MODE, sensor_mode);\r
967 \r
968         /* Write the power mode in the register */\r
969         rslt = bme280_set_regs(&reg_addr, &sensor_mode_reg_val, 1, dev);\r
970     }\r
971 \r
972     return rslt;\r
973 }\r
974 \r
975 /*!\r
976  * @brief This internal API puts the device to sleep mode.\r
977  */\r
978 static int8_t put_device_to_sleep(const struct bme280_dev *dev)\r
979 {\r
980     int8_t rslt;\r
981     uint8_t reg_data[4];\r
982     struct bme280_settings settings;\r
983 \r
984     rslt = bme280_get_regs(BME280_CTRL_HUM_ADDR, reg_data, 4, dev);\r
985     if (rslt == BME280_OK)\r
986     {\r
987         parse_device_settings(reg_data, &settings);\r
988         rslt = bme280_soft_reset(dev);\r
989         if (rslt == BME280_OK)\r
990         {\r
991             rslt = reload_device_settings(&settings, dev);\r
992         }\r
993     }\r
994 \r
995     return rslt;\r
996 }\r
997 \r
998 /*!\r
999  * @brief This internal API reloads the already existing device settings in\r
1000  * the sensor after soft reset.\r
1001  */\r
1002 static int8_t reload_device_settings(const struct bme280_settings *settings, const struct bme280_dev *dev)\r
1003 {\r
1004     int8_t rslt;\r
1005 \r
1006     rslt = set_osr_settings(BME280_ALL_SETTINGS_SEL, settings, dev);\r
1007     if (rslt == BME280_OK)\r
1008     {\r
1009         rslt = set_filter_standby_settings(BME280_ALL_SETTINGS_SEL, settings, dev);\r
1010     }\r
1011 \r
1012     return rslt;\r
1013 }\r
1014 \r
1015 #ifdef BME280_FLOAT_ENABLE\r
1016 \r
1017 /*!\r
1018  * @brief This internal API is used to compensate the raw temperature data and\r
1019  * return the compensated temperature data in double data type.\r
1020  */\r
1021 static double compensate_temperature(const struct bme280_uncomp_data *uncomp_data, struct bme280_calib_data *calib_data)\r
1022 {\r
1023     double var1;\r
1024     double var2;\r
1025     double temperature;\r
1026     double temperature_min = -40;\r
1027     double temperature_max = 85;\r
1028 \r
1029     var1 = ((double)uncomp_data->temperature) / 16384.0 - ((double)calib_data->dig_T1) / 1024.0;\r
1030     var1 = var1 * ((double)calib_data->dig_T2);\r
1031     var2 = (((double)uncomp_data->temperature) / 131072.0 - ((double)calib_data->dig_T1) / 8192.0);\r
1032     var2 = (var2 * var2) * ((double)calib_data->dig_T3);\r
1033     calib_data->t_fine = (int32_t)(var1 + var2);\r
1034     temperature = (var1 + var2) / 5120.0;\r
1035     if (temperature < temperature_min)\r
1036     {\r
1037         temperature = temperature_min;\r
1038     }\r
1039     else if (temperature > temperature_max)\r
1040     {\r
1041         temperature = temperature_max;\r
1042     }\r
1043 \r
1044     return temperature;\r
1045 }\r
1046 \r
1047 /*!\r
1048  * @brief This internal API is used to compensate the raw pressure data and\r
1049  * return the compensated pressure data in double data type.\r
1050  */\r
1051 static double compensate_pressure(const struct bme280_uncomp_data *uncomp_data,\r
1052                                   const struct bme280_calib_data *calib_data)\r
1053 {\r
1054     double var1;\r
1055     double var2;\r
1056     double var3;\r
1057     double pressure;\r
1058     double pressure_min = 30000.0;\r
1059     double pressure_max = 110000.0;\r
1060 \r
1061     var1 = ((double)calib_data->t_fine / 2.0) - 64000.0;\r
1062     var2 = var1 * var1 * ((double)calib_data->dig_P6) / 32768.0;\r
1063     var2 = var2 + var1 * ((double)calib_data->dig_P5) * 2.0;\r
1064     var2 = (var2 / 4.0) + (((double)calib_data->dig_P4) * 65536.0);\r
1065     var3 = ((double)calib_data->dig_P3) * var1 * var1 / 524288.0;\r
1066     var1 = (var3 + ((double)calib_data->dig_P2) * var1) / 524288.0;\r
1067     var1 = (1.0 + var1 / 32768.0) * ((double)calib_data->dig_P1);\r
1068 \r
1069     /* avoid exception caused by division by zero */\r
1070     if (var1)\r
1071     {\r
1072         pressure = 1048576.0 - (double) uncomp_data->pressure;\r
1073         pressure = (pressure - (var2 / 4096.0)) * 6250.0 / var1;\r
1074         var1 = ((double)calib_data->dig_P9) * pressure * pressure / 2147483648.0;\r
1075         var2 = pressure * ((double)calib_data->dig_P8) / 32768.0;\r
1076         pressure = pressure + (var1 + var2 + ((double)calib_data->dig_P7)) / 16.0;\r
1077         if (pressure < pressure_min)\r
1078         {\r
1079             pressure = pressure_min;\r
1080         }\r
1081         else if (pressure > pressure_max)\r
1082         {\r
1083             pressure = pressure_max;\r
1084         }\r
1085     }\r
1086     else /* Invalid case */\r
1087     {\r
1088         pressure = pressure_min;\r
1089     }\r
1090 \r
1091     return pressure;\r
1092 }\r
1093 \r
1094 /*!\r
1095  * @brief This internal API is used to compensate the raw humidity data and\r
1096  * return the compensated humidity data in double data type.\r
1097  */\r
1098 static double compensate_humidity(const struct bme280_uncomp_data *uncomp_data,\r
1099                                   const struct bme280_calib_data *calib_data)\r
1100 {\r
1101     double humidity;\r
1102     double humidity_min = 0.0;\r
1103     double humidity_max = 100.0;\r
1104     double var1;\r
1105     double var2;\r
1106     double var3;\r
1107     double var4;\r
1108     double var5;\r
1109     double var6;\r
1110 \r
1111     var1 = ((double)calib_data->t_fine) - 76800.0;\r
1112     var2 = (((double)calib_data->dig_H4) * 64.0 + (((double)calib_data->dig_H5) / 16384.0) * var1);\r
1113     var3 = uncomp_data->humidity - var2;\r
1114     var4 = ((double)calib_data->dig_H2) / 65536.0;\r
1115     var5 = (1.0 + (((double)calib_data->dig_H3) / 67108864.0) * var1);\r
1116     var6 = 1.0 + (((double)calib_data->dig_H6) / 67108864.0) * var1 * var5;\r
1117     var6 = var3 * var4 * (var5 * var6);\r
1118     humidity = var6 * (1.0 - ((double)calib_data->dig_H1) * var6 / 524288.0);\r
1119     if (humidity > humidity_max)\r
1120     {\r
1121         humidity = humidity_max;\r
1122     }\r
1123     else if (humidity < humidity_min)\r
1124     {\r
1125         humidity = humidity_min;\r
1126     }\r
1127 \r
1128     return humidity;\r
1129 }\r
1130 \r
1131 #else\r
1132 \r
1133 /*!\r
1134  * @brief This internal API is used to compensate the raw temperature data and\r
1135  * return the compensated temperature data in integer data type.\r
1136  */\r
1137 static int32_t compensate_temperature(const struct bme280_uncomp_data *uncomp_data,\r
1138                                       struct bme280_calib_data *calib_data)\r
1139 {\r
1140     int32_t var1;\r
1141     int32_t var2;\r
1142     int32_t temperature;\r
1143     int32_t temperature_min = -4000;\r
1144     int32_t temperature_max = 8500;\r
1145 \r
1146     var1 = (int32_t)((uncomp_data->temperature / 8) - ((int32_t)calib_data->dig_T1 * 2));\r
1147     var1 = (var1 * ((int32_t)calib_data->dig_T2)) / 2048;\r
1148     var2 = (int32_t)((uncomp_data->temperature / 16) - ((int32_t)calib_data->dig_T1));\r
1149     var2 = (((var2 * var2) / 4096) * ((int32_t)calib_data->dig_T3)) / 16384;\r
1150     calib_data->t_fine = var1 + var2;\r
1151     temperature = (calib_data->t_fine * 5 + 128) / 256;\r
1152     if (temperature < temperature_min)\r
1153     {\r
1154         temperature = temperature_min;\r
1155     }\r
1156     else if (temperature > temperature_max)\r
1157     {\r
1158         temperature = temperature_max;\r
1159     }\r
1160 \r
1161     return temperature;\r
1162 }\r
1163 #ifdef BME280_64BIT_ENABLE\r
1164 \r
1165 /*!\r
1166  * @brief This internal API is used to compensate the raw pressure data and\r
1167  * return the compensated pressure data in integer data type with higher\r
1168  * accuracy.\r
1169  */\r
1170 static uint32_t compensate_pressure(const struct bme280_uncomp_data *uncomp_data,\r
1171                                     const struct bme280_calib_data *calib_data)\r
1172 {\r
1173     int64_t var1;\r
1174     int64_t var2;\r
1175     int64_t var3;\r
1176     int64_t var4;\r
1177     uint32_t pressure;\r
1178     uint32_t pressure_min = 3000000;\r
1179     uint32_t pressure_max = 11000000;\r
1180 \r
1181     var1 = ((int64_t)calib_data->t_fine) - 128000;\r
1182     var2 = var1 * var1 * (int64_t)calib_data->dig_P6;\r
1183     var2 = var2 + ((var1 * (int64_t)calib_data->dig_P5) * 131072);\r
1184     var2 = var2 + (((int64_t)calib_data->dig_P4) * 34359738368);\r
1185     var1 = ((var1 * var1 * (int64_t)calib_data->dig_P3) / 256) + ((var1 * ((int64_t)calib_data->dig_P2) * 4096));\r
1186     var3 = ((int64_t)1) * 140737488355328;\r
1187     var1 = (var3 + var1) * ((int64_t)calib_data->dig_P1) / 8589934592;\r
1188 \r
1189     /* To avoid divide by zero exception */\r
1190     if (var1 != 0)\r
1191     {\r
1192         var4 = 1048576 - uncomp_data->pressure;\r
1193         var4 = (((var4 * INT64_C(2147483648)) - var2) * 3125) / var1;\r
1194         var1 = (((int64_t)calib_data->dig_P9) * (var4 / 8192) * (var4 / 8192)) / 33554432;\r
1195         var2 = (((int64_t)calib_data->dig_P8) * var4) / 524288;\r
1196         var4 = ((var4 + var1 + var2) / 256) + (((int64_t)calib_data->dig_P7) * 16);\r
1197         pressure = (uint32_t)(((var4 / 2) * 100) / 128);\r
1198         if (pressure < pressure_min)\r
1199         {\r
1200             pressure = pressure_min;\r
1201         }\r
1202         else if (pressure > pressure_max)\r
1203         {\r
1204             pressure = pressure_max;\r
1205         }\r
1206     }\r
1207     else\r
1208     {\r
1209         pressure = pressure_min;\r
1210     }\r
1211 \r
1212     return pressure;\r
1213 }\r
1214 #else\r
1215 \r
1216 /*!\r
1217  * @brief This internal API is used to compensate the raw pressure data and\r
1218  * return the compensated pressure data in integer data type.\r
1219  */\r
1220 static uint32_t compensate_pressure(const struct bme280_uncomp_data *uncomp_data,\r
1221                                     const struct bme280_calib_data *calib_data)\r
1222 {\r
1223     int32_t var1;\r
1224     int32_t var2;\r
1225     int32_t var3;\r
1226     int32_t var4;\r
1227     uint32_t var5;\r
1228     uint32_t pressure;\r
1229     uint32_t pressure_min = 30000;\r
1230     uint32_t pressure_max = 110000;\r
1231 \r
1232     var1 = (((int32_t)calib_data->t_fine) / 2) - (int32_t)64000;\r
1233     var2 = (((var1 / 4) * (var1 / 4)) / 2048) * ((int32_t)calib_data->dig_P6);\r
1234     var2 = var2 + ((var1 * ((int32_t)calib_data->dig_P5)) * 2);\r
1235     var2 = (var2 / 4) + (((int32_t)calib_data->dig_P4) * 65536);\r
1236     var3 = (calib_data->dig_P3 * (((var1 / 4) * (var1 / 4)) / 8192)) / 8;\r
1237     var4 = (((int32_t)calib_data->dig_P2) * var1) / 2;\r
1238     var1 = (var3 + var4) / 262144;\r
1239     var1 = (((32768 + var1)) * ((int32_t)calib_data->dig_P1)) / 32768;\r
1240 \r
1241     /* avoid exception caused by division by zero */\r
1242     if (var1)\r
1243     {\r
1244         var5 = (uint32_t)((uint32_t)1048576) - uncomp_data->pressure;\r
1245         pressure = ((uint32_t)(var5 - (uint32_t)(var2 / 4096))) * 3125;\r
1246         if (pressure < 0x80000000)\r
1247         {\r
1248             pressure = (pressure << 1) / ((uint32_t)var1);\r
1249         }\r
1250         else\r
1251         {\r
1252             pressure = (pressure / (uint32_t)var1) * 2;\r
1253         }\r
1254         var1 = (((int32_t)calib_data->dig_P9) * ((int32_t)(((pressure / 8) * (pressure / 8)) / 8192))) / 4096;\r
1255         var2 = (((int32_t)(pressure / 4)) * ((int32_t)calib_data->dig_P8)) / 8192;\r
1256         pressure = (uint32_t)((int32_t)pressure + ((var1 + var2 + calib_data->dig_P7) / 16));\r
1257         if (pressure < pressure_min)\r
1258         {\r
1259             pressure = pressure_min;\r
1260         }\r
1261         else if (pressure > pressure_max)\r
1262         {\r
1263             pressure = pressure_max;\r
1264         }\r
1265     }\r
1266     else\r
1267     {\r
1268         pressure = pressure_min;\r
1269     }\r
1270 \r
1271     return pressure;\r
1272 }\r
1273 #endif\r
1274 \r
1275 /*!\r
1276  * @brief This internal API is used to compensate the raw humidity data and\r
1277  * return the compensated humidity data in integer data type.\r
1278  */\r
1279 static uint32_t compensate_humidity(const struct bme280_uncomp_data *uncomp_data,\r
1280                                     const struct bme280_calib_data *calib_data)\r
1281 {\r
1282     int32_t var1;\r
1283     int32_t var2;\r
1284     int32_t var3;\r
1285     int32_t var4;\r
1286     int32_t var5;\r
1287     uint32_t humidity;\r
1288     uint32_t humidity_max = 102400;\r
1289 \r
1290     var1 = calib_data->t_fine - ((int32_t)76800);\r
1291     var2 = (int32_t)(uncomp_data->humidity * 16384);\r
1292     var3 = (int32_t)(((int32_t)calib_data->dig_H4) * 1048576);\r
1293     var4 = ((int32_t)calib_data->dig_H5) * var1;\r
1294     var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768;\r
1295     var2 = (var1 * ((int32_t)calib_data->dig_H6)) / 1024;\r
1296     var3 = (var1 * ((int32_t)calib_data->dig_H3)) / 2048;\r
1297     var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152;\r
1298     var2 = ((var4 * ((int32_t)calib_data->dig_H2)) + 8192) / 16384;\r
1299     var3 = var5 * var2;\r
1300     var4 = ((var3 / 32768) * (var3 / 32768)) / 128;\r
1301     var5 = var3 - ((var4 * ((int32_t)calib_data->dig_H1)) / 16);\r
1302     var5 = (var5 < 0 ? 0 : var5);\r
1303     var5 = (var5 > 419430400 ? 419430400 : var5);\r
1304     humidity = (uint32_t)(var5 / 4096);\r
1305     if (humidity > humidity_max)\r
1306     {\r
1307         humidity = humidity_max;\r
1308     }\r
1309 \r
1310     return humidity;\r
1311 }\r
1312 #endif\r
1313 \r
1314 /*!\r
1315  * @brief This internal API reads the calibration data from the sensor, parse\r
1316  * it and store in the device structure.\r
1317  */\r
1318 static int8_t get_calib_data(struct bme280_dev *dev)\r
1319 {\r
1320     int8_t rslt;\r
1321     uint8_t reg_addr = BME280_TEMP_PRESS_CALIB_DATA_ADDR;\r
1322 \r
1323     /* Array to store calibration data */\r
1324     uint8_t calib_data[BME280_TEMP_PRESS_CALIB_DATA_LEN] = { 0 };\r
1325 \r
1326     /* Read the calibration data from the sensor */\r
1327     rslt = bme280_get_regs(reg_addr, calib_data, BME280_TEMP_PRESS_CALIB_DATA_LEN, dev);\r
1328     if (rslt == BME280_OK)\r
1329     {\r
1330         /* Parse temperature and pressure calibration data and store\r
1331          * it in device structure\r
1332          */\r
1333         parse_temp_press_calib_data(calib_data, dev);\r
1334         reg_addr = BME280_HUMIDITY_CALIB_DATA_ADDR;\r
1335 \r
1336         /* Read the humidity calibration data from the sensor */\r
1337         rslt = bme280_get_regs(reg_addr, calib_data, BME280_HUMIDITY_CALIB_DATA_LEN, dev);\r
1338         if (rslt == BME280_OK)\r
1339         {\r
1340             /* Parse humidity calibration data and store it in\r
1341              * device structure\r
1342              */\r
1343             parse_humidity_calib_data(calib_data, dev);\r
1344         }\r
1345     }\r
1346 \r
1347     return rslt;\r
1348 }\r
1349 \r
1350 /*!\r
1351  * @brief This internal API interleaves the register address between the\r
1352  * register data buffer for burst write operation.\r
1353  */\r
1354 static void interleave_reg_addr(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint8_t len)\r
1355 {\r
1356     uint8_t index;\r
1357 \r
1358     for (index = 1; index < len; index++)\r
1359     {\r
1360         temp_buff[(index * 2) - 1] = reg_addr[index];\r
1361         temp_buff[index * 2] = reg_data[index];\r
1362     }\r
1363 }\r
1364 \r
1365 /*!\r
1366  *  @brief This internal API is used to parse the temperature and\r
1367  *  pressure calibration data and store it in device structure.\r
1368  */\r
1369 static void parse_temp_press_calib_data(const uint8_t *reg_data, struct bme280_dev *dev)\r
1370 {\r
1371     struct bme280_calib_data *calib_data = &dev->calib_data;\r
1372 \r
1373     calib_data->dig_T1 = BME280_CONCAT_BYTES(reg_data[1], reg_data[0]);\r
1374     calib_data->dig_T2 = (int16_t)BME280_CONCAT_BYTES(reg_data[3], reg_data[2]);\r
1375     calib_data->dig_T3 = (int16_t)BME280_CONCAT_BYTES(reg_data[5], reg_data[4]);\r
1376     calib_data->dig_P1 = BME280_CONCAT_BYTES(reg_data[7], reg_data[6]);\r
1377     calib_data->dig_P2 = (int16_t)BME280_CONCAT_BYTES(reg_data[9], reg_data[8]);\r
1378     calib_data->dig_P3 = (int16_t)BME280_CONCAT_BYTES(reg_data[11], reg_data[10]);\r
1379     calib_data->dig_P4 = (int16_t)BME280_CONCAT_BYTES(reg_data[13], reg_data[12]);\r
1380     calib_data->dig_P5 = (int16_t)BME280_CONCAT_BYTES(reg_data[15], reg_data[14]);\r
1381     calib_data->dig_P6 = (int16_t)BME280_CONCAT_BYTES(reg_data[17], reg_data[16]);\r
1382     calib_data->dig_P7 = (int16_t)BME280_CONCAT_BYTES(reg_data[19], reg_data[18]);\r
1383     calib_data->dig_P8 = (int16_t)BME280_CONCAT_BYTES(reg_data[21], reg_data[20]);\r
1384     calib_data->dig_P9 = (int16_t)BME280_CONCAT_BYTES(reg_data[23], reg_data[22]);\r
1385     calib_data->dig_H1 = reg_data[25];\r
1386 }\r
1387 \r
1388 /*!\r
1389  *  @brief This internal API is used to parse the humidity calibration data\r
1390  *  and store it in device structure.\r
1391  */\r
1392 static void parse_humidity_calib_data(const uint8_t *reg_data, struct bme280_dev *dev)\r
1393 {\r
1394     struct bme280_calib_data *calib_data = &dev->calib_data;\r
1395     int16_t dig_H4_lsb;\r
1396     int16_t dig_H4_msb;\r
1397     int16_t dig_H5_lsb;\r
1398     int16_t dig_H5_msb;\r
1399 \r
1400     calib_data->dig_H2 = (int16_t)BME280_CONCAT_BYTES(reg_data[1], reg_data[0]);\r
1401     calib_data->dig_H3 = reg_data[2];\r
1402     dig_H4_msb = (int16_t)(int8_t)reg_data[3] * 16;\r
1403     dig_H4_lsb = (int16_t)(reg_data[4] & 0x0F);\r
1404     calib_data->dig_H4 = dig_H4_msb | dig_H4_lsb;\r
1405     dig_H5_msb = (int16_t)(int8_t)reg_data[5] * 16;\r
1406     dig_H5_lsb = (int16_t)(reg_data[4] >> 4);\r
1407     calib_data->dig_H5 = dig_H5_msb | dig_H5_lsb;\r
1408     calib_data->dig_H6 = (int8_t)reg_data[6];\r
1409 }\r
1410 \r
1411 /*!\r
1412  * @brief This internal API is used to identify the settings which the user\r
1413  * wants to modify in the sensor.\r
1414  */\r
1415 static uint8_t are_settings_changed(uint8_t sub_settings, uint8_t desired_settings)\r
1416 {\r
1417     uint8_t settings_changed = FALSE;\r
1418 \r
1419     if (sub_settings & desired_settings)\r
1420     {\r
1421         /* User wants to modify this particular settings */\r
1422         settings_changed = TRUE;\r
1423     }\r
1424     else\r
1425     {\r
1426         /* User don't want to modify this particular settings */\r
1427         settings_changed = FALSE;\r
1428     }\r
1429 \r
1430     return settings_changed;\r
1431 }\r
1432 \r
1433 /*!\r
1434  * @brief This internal API is used to validate the device structure pointer for\r
1435  * null conditions.\r
1436  */\r
1437 static int8_t null_ptr_check(const struct bme280_dev *dev)\r
1438 {\r
1439     int8_t rslt;\r
1440 \r
1441     if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL))\r
1442     {\r
1443         /* Device structure pointer is not valid */\r
1444         rslt = BME280_E_NULL_PTR;\r
1445     }\r
1446     else\r
1447     {\r
1448         /* Device structure is fine */\r
1449         rslt = BME280_OK;\r
1450     }\r
1451 \r
1452     return rslt;\r
1453 }\r