]> git.itanic.dy.fi Git - BME280_driver/blob - examples/linux_userspace.c
c360eb07f2ad9350812e5f99ac6abb49a24da810
[BME280_driver] / examples / linux_userspace.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 linux_userspace.c\r
34 * @date 10/01/2020\r
35 * @version\r
36 *\r
37 */\r
38 \r
39 /*!\r
40  * @ingroup bme280GroupExample\r
41  * @defgroup bme280GroupExample linux_userspace\r
42  * @brief Linux userspace test code, simple and mose code directly from the doco.\r
43  * compile like this: gcc linux_userspace.c ../bme280.c -I ../ -o bme280\r
44  * tested: Raspberry Pi.\r
45  * Use like: ./bme280 /dev/i2c-0\r
46  * \include linux_userspace.c\r
47  */\r
48 \r
49 #ifdef __KERNEL__\r
50 #include <linux/i2c-dev.h>\r
51 #include <sys/ioctl.h>\r
52 #endif\r
53 \r
54 /******************************************************************************/\r
55 /*!                         System header files                               */\r
56 #include <string.h>\r
57 #include <stdio.h>\r
58 #include <stdlib.h>\r
59 #include <unistd.h>\r
60 #include <sys/types.h>\r
61 #include <fcntl.h>\r
62 \r
63 /******************************************************************************/\r
64 /*!                         Own header files                                  */\r
65 #include "bme280.h"\r
66 \r
67 /*****************************************************************************/\r
68 /*!                         Global variables                                 */\r
69 int fd;\r
70 \r
71 /****************************************************************************/\r
72 /*!                         Functions                                       */\r
73 \r
74 /*!\r
75  *  @brief Function that creates a mandatory delay required in some of the APIs.\r
76  *\r
77  *  @param[in] period  : The required wait time in microseconds.\r
78  *  @return void.\r
79  *\r
80  */\r
81 void user_delay_ms(uint32_t period);\r
82 \r
83 /*!\r
84  * @brief Function for print the temperature, humidity and pressure data.\r
85  *\r
86  * @param[out] comp_data    :   Structure instance of bme280_data\r
87  *\r
88  * @note Sensor data whose can be read\r
89  *\r
90  * sens_list\r
91  * --------------\r
92  * Pressure\r
93  * Temperature\r
94  * Humidity\r
95  *\r
96  */\r
97 void print_sensor_data(struct bme280_data *comp_data);\r
98 \r
99 /*!\r
100  *  @brief Function for reading the sensor's registers through I2C bus.\r
101  *\r
102  *  @param[in] id       : Sensor I2C address.\r
103  *  @param[in] reg_addr : Register address.\r
104  *  @param[out] data    : Pointer to the data buffer to store the read data.\r
105  *  @param[in] len      : No of bytes to read.\r
106  *\r
107  *  @return Status of execution\r
108  *\r
109  *  @retval 0 -> Success\r
110  *  @retval > 0 -> Failure Info\r
111  *\r
112  */\r
113 int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);\r
114 \r
115 /*!\r
116  *  @brief Function for writing the sensor's registers through I2C bus.\r
117  *\r
118  *  @param[in] id       : Sensor I2C address.\r
119  *  @param[in] reg_addr : Register address.\r
120  *  @param[in] data     : Pointer to the data buffer whose value is to be written.\r
121  *  @param[in] len      : No of bytes to write.\r
122  *\r
123  *  @return Status of execution\r
124  *\r
125  *  @retval BME280_OK -> Success\r
126  *  @retval BME280_E_COMM_FAIL -> Communication failure.\r
127  *\r
128  */\r
129 int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len);\r
130 \r
131 /*!\r
132  * @brief Function reads temperature, humidity and pressure data in forced mode.\r
133  *\r
134  * @param[in] dev   :   Structure instance of bme280_dev.\r
135  *\r
136  * @return Result of API execution status\r
137  *\r
138  * @retval BME280_OK - Success.\r
139  * @retval BME280_E_NULL_PTR - Error: Null pointer error\r
140  * @retval BME280_E_COMM_FAIL - Error: Communication fail error\r
141  * @retval BME280_E_NVM_COPY_FAILED - Error: NVM copy failed\r
142  *\r
143  */\r
144 int8_t stream_sensor_data_forced_mode(struct bme280_dev *dev);\r
145 \r
146 /*!\r
147  * @brief This function starts execution of the program.\r
148  */\r
149 int main(int argc, char* argv[])\r
150 {\r
151     struct bme280_dev dev;\r
152 \r
153     /* Variable to define the result */\r
154     int8_t rslt = BME280_OK;\r
155 \r
156     if (argc < 2)\r
157     {\r
158         fprintf(stderr, "Missing argument for i2c bus.\n");\r
159         exit(1);\r
160     }\r
161 \r
162     /* Make sure to select BME280_I2C_ADDR_PRIM or BME280_I2C_ADDR_SEC as needed */\r
163     dev.dev_id = BME280_I2C_ADDR_PRIM;\r
164 \r
165     /* dev.dev_id = BME280_I2C_ADDR_SEC; */\r
166     dev.intf = BME280_I2C_INTF;\r
167     dev.read = user_i2c_read;\r
168     dev.write = user_i2c_write;\r
169     dev.delay_ms = user_delay_ms;\r
170 \r
171     if ((fd = open(argv[1], O_RDWR)) < 0)\r
172     {\r
173         fprintf(stderr, "Failed to open the i2c bus %s\n", argv[1]);\r
174         exit(1);\r
175     }\r
176 \r
177 #ifdef __KERNEL__\r
178     if (ioctl(fd, I2C_SLAVE, dev.dev_id) < 0)\r
179     {\r
180         fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\n");\r
181         exit(1);\r
182     }\r
183 #endif\r
184 \r
185     /* Initialize the bme280 */\r
186     rslt = bme280_init(&dev);\r
187     if (rslt != BME280_OK)\r
188     {\r
189         fprintf(stderr, "Failed to initialize the device (code %+d).\n", rslt);\r
190         exit(1);\r
191     }\r
192 \r
193     rslt = stream_sensor_data_forced_mode(&dev);\r
194     if (rslt != BME280_OK)\r
195     {\r
196         fprintf(stderr, "Failed to stream sensor data (code %+d).\n", rslt);\r
197         exit(1);\r
198     }\r
199 \r
200     return 0;\r
201 }\r
202 \r
203 /*!\r
204  * @brief This function reading the sensor's registers through I2C bus.\r
205  */\r
206 int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len)\r
207 {\r
208     write(fd, &reg_addr, 1);\r
209     read(fd, data, len);\r
210 \r
211     return 0;\r
212 }\r
213 \r
214 /*!\r
215  * @brief This function provides the delay for required time (Microseconds) as per the input provided in some of the\r
216  * APIs\r
217  */\r
218 void user_delay_ms(uint32_t period)\r
219 {\r
220     /* Milliseconds convert to microseconds */\r
221     usleep(period * 1000);\r
222 }\r
223 \r
224 /*!\r
225  * @brief This function for writing the sensor's registers through I2C bus.\r
226  */\r
227 int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len)\r
228 {\r
229     int8_t *buf;\r
230 \r
231     buf = malloc(len + 1);\r
232     buf[0] = reg_addr;\r
233     memcpy(buf + 1, data, len);\r
234     if (write(fd, buf, len + 1) < len)\r
235     {\r
236         return BME280_E_COMM_FAIL;\r
237     }\r
238 \r
239     free(buf);\r
240 \r
241     return BME280_OK;\r
242 }\r
243 \r
244 /*!\r
245  * @brief This API used to print the sensor temperature, pressure and humidity data.\r
246  */\r
247 void print_sensor_data(struct bme280_data *comp_data)\r
248 {\r
249     float temp, press, hum;\r
250 \r
251 #ifdef BME280_FLOAT_ENABLE\r
252     temp = comp_data->temperature;\r
253     press = 0.01 * comp_data->pressure;\r
254     hum = comp_data->humidity;\r
255 #else\r
256 #ifdef BME280_64BIT_ENABLE\r
257     temp = 0.01f * comp_data->temperature;\r
258     press = 0.0001f * comp_data->pressure;\r
259     hum = 1.0f / 1024.0f * comp_data->humidity;\r
260 #else\r
261     temp = 0.01f * comp_data->temperature;\r
262     press = 0.01f * comp_data->pressure;\r
263     hum = 1.0f / 1024.0f * comp_data->humidity;\r
264 #endif\r
265 #endif\r
266     printf("%0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", temp, press, hum);\r
267 }\r
268 \r
269 /*!\r
270  * @brief This API reads the sensor temperature, pressure and humidity data in forced mode.\r
271  */\r
272 int8_t stream_sensor_data_forced_mode(struct bme280_dev *dev)\r
273 {\r
274     /* Variable to define the result */\r
275     int8_t rslt = BME280_OK;\r
276 \r
277     /* Variable to define the selecting sensors */\r
278     uint8_t settings_sel = 0;\r
279 \r
280     /* Variable to store minimum wait time between consecutive measurement in force mode */\r
281     uint32_t req_delay;\r
282 \r
283     /* Structure to get the pressure, temperature and humidity values */\r
284     struct bme280_data comp_data;\r
285 \r
286     /* Recommended mode of operation: Indoor navigation */\r
287     dev->settings.osr_h = BME280_OVERSAMPLING_1X;\r
288     dev->settings.osr_p = BME280_OVERSAMPLING_16X;\r
289     dev->settings.osr_t = BME280_OVERSAMPLING_2X;\r
290     dev->settings.filter = BME280_FILTER_COEFF_16;\r
291 \r
292     settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL;\r
293 \r
294     /* Set the sensor settings */\r
295     rslt = bme280_set_sensor_settings(settings_sel, dev);\r
296     if (rslt != BME280_OK)\r
297     {\r
298         fprintf(stderr, "Failed to set sensor settings (code %+d).", rslt);\r
299 \r
300         return rslt;\r
301     }\r
302 \r
303     printf("Temperature, Pressure, Humidity\n");\r
304 \r
305     /*Calculate the minimum delay required between consecutive measurement based upon the sensor enabled\r
306      *  and the oversampling configuration. */\r
307     req_delay = bme280_cal_meas_delay(&dev->settings);\r
308 \r
309     /* Continuously stream sensor data */\r
310     while (1)\r
311     {\r
312         /* Set the sensor to forced mode */\r
313         rslt = bme280_set_sensor_mode(BME280_FORCED_MODE, dev);\r
314         if (rslt != BME280_OK)\r
315         {\r
316             fprintf(stderr, "Failed to set sensor mode (code %+d).", rslt);\r
317             break;\r
318         }\r
319 \r
320         /* Wait for the measurement to complete and print data */\r
321         dev->delay_ms(req_delay);\r
322         rslt = bme280_get_sensor_data(BME280_ALL, &comp_data, dev);\r
323         if (rslt != BME280_OK)\r
324         {\r
325             fprintf(stderr, "Failed to get sensor data (code %+d).", rslt);\r
326             break;\r
327         }\r
328 \r
329         print_sensor_data(&comp_data);\r
330     }\r
331 \r
332     return rslt;\r
333 }\r