]> git.itanic.dy.fi Git - BME280_driver/blob - bmed.c
Makefile: Add install target for bmed
[BME280_driver] / bmed.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <linux/i2c-dev.h>
6 #include <fcntl.h>
7 #include <math.h>
8 #include <time.h>
9 #include <pthread.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <sys/ioctl.h>
15 #include <sys/epoll.h>
16
17 #include "bme280.h"
18
19 struct data_entry {
20         time_t time;
21         double temperature;
22         double humidity;
23         double pressure;
24         double dew_point;
25 };
26
27 struct bme280 {
28         struct bme280_dev *dev;
29         uint8_t dev_addr;
30         int8_t fd;
31         struct data_entry data[8192];
32         pthread_mutex_t lock;
33         int epollfd;
34 };
35
36 struct event_handler;
37
38 typedef int (handle_event_fn_t)(struct event_handler *);
39
40 struct event_handler {
41         struct epoll_event ev;
42         handle_event_fn_t *handle_event;
43         char *name;
44 };
45
46 int exit_all = 0;
47
48 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
49 #define min(a, b) ((a) < (b) ? (a) : (b))
50 #define max(a, b) ((a) > (b) ? (a) : (b))
51
52 int register_event_handler(struct bme280 *bme, struct event_handler *handler)
53 {
54         struct epoll_event ev;
55         int ret;
56
57         bzero(&ev, sizeof(ev));
58
59         if (handler->ev.data.fd <= 0) {
60                 printf("Invalid file descriptor of %d\n", handler->ev.data.fd);
61                 return -1;
62         }
63
64         if (!handler->handle_event) {
65                 printf("Handler callback missing\n");
66                 return -1;
67         }
68
69         printf("Registering handler for %s, fd %d\n",
70                 handler->name, handler->ev.data.fd);
71
72         ev.data.fd = handler->ev.data.fd;
73         ev.data.ptr = handler;
74         ev.events = handler->ev.events;
75         ret = epoll_ctl(bme->epollfd, EPOLL_CTL_ADD, handler->ev.data.fd, &ev);
76         if (ret) {
77                 printf("Failed to add epoll_fd: %m\n");
78                 return -1;
79         }
80
81         return 0;
82 }
83
84 int update_event_handler(struct bme280 *bme, struct event_handler *handler)
85 {
86         struct epoll_event ev;
87         int ret;
88
89         bzero(&ev, sizeof(ev));
90         ev.data.fd = handler->ev.data.fd;
91         ev.data.ptr = handler;
92         ev.events = handler->ev.events;
93         ret = epoll_ctl(bme->epollfd, EPOLL_CTL_MOD, handler->ev.data.fd, &ev);
94         if (ret) {
95                 printf("Failed to add epoll_fd: %m\n");
96                 return -1;
97         }
98
99         return 0;
100 }
101
102 struct connection_state {
103         struct event_handler ev;
104         char buf[128];
105         int len;
106         struct bme280 *bme;
107         int fd;
108         time_t min_timestamp;
109 };
110
111 static int handle_connection_state(struct event_handler *ptr)
112 {
113         struct connection_state *conn = (struct connection_state *)ptr;
114         struct bme280 *bme = conn->bme;
115         int len = 0;
116         int ret, i;
117
118         if (conn->min_timestamp == -1) {
119                 if (!conn->ev.ev.events & EPOLLIN) {
120                         printf("%s: No incoming data\n", __func__);
121                         return 0;
122                 }
123
124                 ret = read(conn->fd, conn->buf + conn->len, sizeof(conn->buf) - conn->len);
125                 if (ret < 0) {
126                         printf("%s: read: %m\n", __func__);
127                         return -1;
128                 }
129
130                 conn->buf[min((signed)sizeof(conn->buf) - 1, ret)] = '\0';
131
132                 if (ret == 0)
133                         goto out_free;
134
135                 for (i = 0; i < ret; i++)
136                         if (conn->buf[i] == '\n')
137                                 break;
138
139                 /* Did we get newline? */
140                 if (i == ret)
141                         return 0; /* Not yet */
142
143                 if (i == sizeof(conn->buf)) {
144                         printf("%s Data overflow\n", __func__);
145                         goto out_free;
146                 }
147
148                 printf("%s: Got %s", __func__, conn->buf);
149
150                 conn->min_timestamp = atoi(conn->buf);
151         }
152
153         /* Switch to sending data only mode only */
154         conn->ev.ev.events = EPOLLOUT;
155         conn->ev.ev.data.fd = conn->fd;
156         update_event_handler(bme, &conn->ev);
157
158         for (i = 0; i < (signed)ARRAY_SIZE(bme->data); i++) {
159                 pthread_mutex_lock(&bme->lock);
160
161                 /* Skip empty */
162                 if (!bme->data[i].time) {
163                         pthread_mutex_unlock(&bme->lock);
164                         continue;
165                 }
166
167                 /* Skip non-interesting or already sent items */
168                 if (bme->data[i].time <= conn->min_timestamp) {
169                         pthread_mutex_unlock(&bme->lock);
170                         continue;
171                 }
172
173                 len = snprintf(conn->buf, sizeof(conn->buf),
174                                 "%ld:%0.4lf:%0.4lf:%0.4lf:%.4lf\n",
175                                 bme->data[i].time,
176                                 bme->data[i].temperature,
177                                 bme->data[i].pressure,
178                                 bme->data[i].humidity,
179                                 bme->data[i].dew_point);
180
181                 ret = send(conn->fd, conn->buf, len, MSG_NOSIGNAL);
182                 if (ret < 0) {
183                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
184                                 pthread_mutex_unlock(&bme->lock);
185                                 return 0;
186                         }
187
188                         printf("%s: send(): %m\n", __func__);
189                         pthread_mutex_unlock(&bme->lock);
190                         goto out_free;
191                 }
192
193                 conn->min_timestamp = bme->data[i].time;
194                 pthread_mutex_unlock(&bme->lock);
195         }
196
197 out_free:
198         printf("%s: Closing socket %d\n", __func__, conn->fd);
199         close(conn->fd);
200         free(conn);
201
202         return 0;
203 }
204
205 struct listening_socket {
206         struct event_handler ev;
207         int fd;
208         struct bme280 *bme;
209 };
210
211 static int handle_incoming_connection(struct event_handler *ptr)
212 {
213         struct sockaddr_in peer;
214         socklen_t peerlen = 0;
215         struct listening_socket *listener = (struct listening_socket *)ptr;
216         struct connection_state *conn;
217         struct bme280 *bme = listener->bme;
218         int fd;
219
220         bzero(&peer, sizeof(peer));
221
222         fd = accept4(listener->fd, (struct sockaddr *)&peer, &peerlen, SOCK_NONBLOCK);
223         if (fd < 0) {
224                 printf("Error while accept(): %m\n");
225                 return -1;
226         }
227
228         conn = calloc(sizeof(*conn), 1);
229         conn->ev.ev.data.fd = fd;
230         conn->fd = fd;
231         conn->ev.ev.events = EPOLLIN;
232         conn->ev.handle_event = handle_connection_state;
233         conn->ev.name = "socket";
234         conn->bme = bme;
235         conn->min_timestamp = -1;
236         conn->len = 0;
237
238         register_event_handler(bme, &conn->ev);
239
240         return 0;
241 }
242
243 static void *event_handler(void *arg)
244 {
245         struct bme280 *bme = arg;
246         struct sockaddr_in addr;
247         struct listening_socket incoming;
248         int sockfd, ret;
249
250         bzero(&addr, sizeof(addr));
251         bzero(&incoming, sizeof(incoming));
252
253         sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
254         if (sockfd < 0) {
255                 printf("Failed to create socket: %m\n");
256                 goto out;
257         }
258
259         addr.sin_family = AF_INET;
260         addr.sin_port = htons(8347);
261         addr.sin_addr.s_addr = INADDR_ANY;
262
263         ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
264         if (ret < 0) {
265                 printf("Failed to bind: %m\n");
266                 goto close_socket;
267         }
268
269         ret = listen(sockfd, 5);
270         if (ret < 0) {
271                 printf("Failed to listen(): %m\n");
272                 goto close_socket;
273         }
274
275         bme->epollfd = epoll_create(1);
276         if (bme->epollfd == -1) {
277                 printf("Failed to epoll_create(): %m\n");
278                 goto close_socket;
279         }
280
281         incoming.bme = bme;
282         incoming.ev.ev.data.fd = sockfd;
283         incoming.ev.ev.events = EPOLLIN;
284         incoming.ev.handle_event = handle_incoming_connection;
285         incoming.ev.name = "listener";
286         incoming.fd = sockfd;
287
288         ret = register_event_handler(bme, &incoming.ev);
289
290         while(1) {
291                 struct epoll_event ev;
292                 struct event_handler *h;
293
294                 printf("%s: Waiting for events..\n", __func__);
295                 ret = epoll_wait(bme->epollfd, &ev, 1, -1);
296                 if (ret == -1) {
297                         if (errno != EINTR) {
298                                 printf("epoll_wait: %m\n");
299                                 goto close_socket;
300                         }
301
302                         continue;
303                 }
304
305                 if (ret == 0) {
306                         printf("Timed out\n");
307                         continue;
308                 }
309
310                 h = ev.data.ptr;
311
312                 printf("Handling %s %s event for %s\n",
313                         ev.events & EPOLLIN ? "incoming" : "",
314                         ev.events & EPOLLOUT ? "outgoing" : "",
315                         h->name);
316                 h->ev = ev;
317                 h->handle_event(h);
318         }
319
320 close_socket:
321         close(sockfd);
322 out:
323         exit_all = 1;
324
325         return NULL;
326 }
327
328 static int8_t i2c_read(uint8_t reg_addr, uint8_t *data, uint32_t len, void *intf_ptr)
329 {
330         struct bme280 id;
331         int ret;
332
333         id = *((struct bme280 *)intf_ptr);
334
335         ret = write(id.fd, &reg_addr, 1);
336         if (ret < 0)
337                 return ret;
338
339         ret = read(id.fd, data, len);
340         if (ret < 0)
341                 return ret;
342
343         return 0;
344 }
345
346 static void delay_us(uint32_t period, void *unused)
347 {
348         (void)unused;
349
350         usleep(period);
351 }
352
353 static int8_t i2c_write(uint8_t reg_addr, const uint8_t *data, uint32_t len, void *intf_ptr)
354 {
355         uint8_t *buf;
356         struct bme280 id;
357
358         id = *((struct bme280 *)intf_ptr);
359
360         buf = malloc(len + 1);
361         buf[0] = reg_addr;
362         memcpy(buf + 1, data, len);
363
364         if (write(id.fd, buf, len + 1) < (uint16_t)len) {
365                 return BME280_E_COMM_FAIL;
366         }
367
368         free(buf);
369
370         return BME280_OK;
371 }
372
373 static double dp(double RH, double T)
374 {
375         double gm, dp;
376         /*
377          * Constants and equation taken from:
378          * https://en.wikipedia.org/wiki/Dew_point#Calculating_the_dew_point
379          */
380 /*      double a = 6.112;*/
381         double b, c;
382         double d = 234.5;
383
384         if (T > 0) {
385                 b = 17.368;
386                 c = 238.88;
387         } else {
388                 b = 17.966;
389                 c = 247.15;
390         }
391
392         gm = log(RH / 100.0 * exp((b - T / d) * (T / (c + T))));
393         dp = c * gm / (b - gm);
394
395         return dp;
396 }
397
398 static int stream_sensor_data_forced_mode(struct bme280 *bme)
399 {
400         int ret;
401         uint8_t settings_sel = 0;
402         uint32_t req_delay;
403         struct bme280_data comp_data;
404         struct bme280_dev *dev = bme->dev;
405
406         double t_sum = 0, h_sum = 0, p_sum = 0;
407         int num = 0, first_run = 1, last_min;
408
409         /* Recommended mode of operation: Indoor navigation */
410         dev->settings.osr_h = BME280_OVERSAMPLING_1X;
411         dev->settings.osr_p = BME280_OVERSAMPLING_16X;
412         dev->settings.osr_t = BME280_OVERSAMPLING_2X;
413         dev->settings.filter = BME280_FILTER_COEFF_16;
414
415         settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL |
416                 BME280_OSR_HUM_SEL | BME280_FILTER_SEL;
417
418         ret = bme280_set_sensor_settings(settings_sel, dev);
419         if (ret) {
420                 fprintf(stderr, "Failed to set sensor settings (code %+d).", ret);
421
422                 return ret;
423         }
424
425         printf("Temperature, Pressure, Humidity\n");
426
427         /*
428          * Calculate the minimum delay required between consecutive
429          * measurement based upon the sensor enabled and the
430          * oversampling configuration.
431          */
432         req_delay = bme280_cal_meas_delay(&dev->settings);
433
434         while (1) {
435                 struct tm *now;
436                 time_t t;
437
438                 ret = 0;
439                 if (exit_all)
440                         break;
441
442                 ret = bme280_set_sensor_mode(BME280_FORCED_MODE, dev);
443                 if (ret) {
444                         fprintf(stderr, "Failed to set sensor mode (code %+d).", ret);
445                         break;
446                 }
447
448                 /* Wait for the measurement to complete and print data */
449                 dev->delay_us(req_delay * 1000, dev->intf_ptr);
450                 ret = bme280_get_sensor_data(BME280_ALL, &comp_data, dev);
451                 if (ret) {
452                         fprintf(stderr, "Failed to get sensor data (code %+d).", ret);
453                         break;
454                 }
455
456                 t_sum += comp_data.temperature;
457                 p_sum += comp_data.pressure;
458                 h_sum += comp_data.humidity;
459                 num++;
460
461                 t = time(NULL);
462                 now = localtime(&t);
463
464                 if (first_run || now->tm_min != last_min) {
465                         double temp, press, hum, dew;
466                         char s[64];
467                         long unsigned int i;
468
469                         first_run = 0;
470                         last_min = now->tm_min;
471
472                         temp = t_sum / (double)num;
473                         press = p_sum * 0.01 / (double)num;
474                         hum = h_sum / (double)num;
475
476                         strftime(s, sizeof(s), "%Y.%m.%d %H:%M:%S", now);
477                         dew = dp(hum, temp);
478
479                         printf("%s %0.4lf deg C, %0.4lf hPa, %0.4lf%%, dp: %.3f C\n",
480                                 s, temp, press, hum, dew);
481                         fflush(stdout);
482
483                         pthread_mutex_lock(&bme->lock);
484                         for (i = 0; i < ARRAY_SIZE(bme->data) - 1; i++)
485                                 bme->data[i] = bme->data[i + 1];
486
487                         bme->data[i].time = t;
488                         bme->data[i].temperature = temp;
489                         bme->data[i].pressure = press;
490                         bme->data[i].humidity = hum;
491                         bme->data[i].dew_point = dew;
492                         pthread_mutex_unlock(&bme->lock);
493
494                         num = 0;
495                         t_sum = p_sum = h_sum = 0;
496                 }
497         }
498
499         return ret;
500 }
501
502 int main(int argc, char *argv[])
503 {
504         pthread_t thread;
505         struct bme280_dev dev;
506         struct bme280 id;
507         int ret;
508
509         bzero(&id, sizeof(id));
510
511         if (argc < 3) {
512                 fprintf(stderr, "Missing argument for i2c bus and address.\n"
513                         "Usage: %s /dev/i2c-0 0x76\n", argv[0]);
514                 exit(1);
515         }
516
517         bzero(&id, sizeof(id));
518
519         if ((id.fd = open(argv[1], O_RDWR)) < 0) {
520                 fprintf(stderr, "Failed to open the i2c bus %s\n", argv[1]);
521                 exit(1);
522         }
523
524         id.dev_addr = strtol(argv[2], NULL, 0);
525         if (ioctl(id.fd, I2C_SLAVE, id.dev_addr) < 0) {
526                 fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\n");
527                 exit(1);
528         }
529
530         dev.intf = BME280_I2C_INTF;
531         dev.read = i2c_read;
532         dev.write = i2c_write;
533         dev.delay_us = delay_us;
534         dev.intf_ptr = &id;
535
536         id.dev = &dev;
537
538         ret = bme280_init(&dev);
539         if (ret) {
540                 fprintf(stderr, "Failed to initialize the device (code %+d).\n", ret);
541                 exit(1);
542         }
543
544         pthread_mutex_init(&id.lock, NULL);
545         pthread_create(&thread, NULL, event_handler, &id);
546
547         ret = stream_sensor_data_forced_mode(&id);
548         if (ret) {
549                 fprintf(stderr, "Failed to stream sensor data (code %+d).\n", ret);
550                 exit(1);
551         }
552 }