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