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