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