rpi_gpio 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,575 +0,0 @@
1
- /*
2
- Original code by Ben Croston modified for Ruby by Nick Lowery
3
- (github.com/clockvapor)
4
- Copyright (c) 2014-2016 Nick Lowery
5
-
6
- Copyright (c) 2013-2016 Ben Croston
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of
9
- this software and associated documentation files (the "Software"), to deal in
10
- the Software without restriction, including without limitation the rights to
11
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
- of the Software, and to permit persons to whom the Software is furnished to do
13
- so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
- */
26
-
27
- #include <pthread.h>
28
- #include <sys/epoll.h>
29
- #include <stdio.h>
30
- #include <stdlib.h>
31
- #include <fcntl.h>
32
- #include <unistd.h>
33
- #include <string.h>
34
- #include <sys/time.h>
35
- #include "event_gpio.h"
36
-
37
- const char *stredge[4] = {"none", "rising", "falling", "both"};
38
-
39
- struct gpios
40
- {
41
- unsigned int gpio;
42
- int value_fd;
43
- int exported;
44
- int edge;
45
- int initial_thread;
46
- int initial_wait;
47
- int thread_added;
48
- int bouncetime;
49
- unsigned long long lastcall;
50
- struct gpios *next;
51
- };
52
- struct gpios *gpio_list = NULL;
53
-
54
- // event callbacks
55
- struct callback
56
- {
57
- unsigned int gpio;
58
- void (*func)(unsigned int gpio);
59
- struct callback *next;
60
- };
61
- struct callback *callbacks = NULL;
62
-
63
- pthread_t threads;
64
- int event_occurred[54] = { 0 };
65
- int thread_running = 0;
66
- int epfd_thread = -1;
67
- int epfd_blocking = -1;
68
-
69
- /************* /sys/class/gpio functions ************/
70
- int gpio_export(unsigned int gpio)
71
- {
72
- int fd, len;
73
- char str_gpio[3];
74
-
75
- if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
76
- return -1;
77
-
78
- len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
79
- write(fd, str_gpio, len);
80
- close(fd);
81
-
82
- return 0;
83
- }
84
-
85
- int gpio_unexport(unsigned int gpio)
86
- {
87
- int fd, len;
88
- char str_gpio[3];
89
-
90
- if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
91
- return -1;
92
-
93
- len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
94
- write(fd, str_gpio, len);
95
- close(fd);
96
-
97
- return 0;
98
- }
99
-
100
- int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
101
- {
102
- int retry;
103
- struct timespec delay;
104
- int fd;
105
- char filename[33];
106
-
107
- snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
108
-
109
- // retry waiting for udev to set correct file permissions
110
- delay.tv_sec = 0;
111
- delay.tv_nsec = 10000000L; // 10ms
112
- for (retry=0; retry<100; retry++) {
113
- if ((fd = open(filename, O_WRONLY)) >= 0)
114
- break;
115
- nanosleep(&delay, NULL);
116
- }
117
- if (retry >= 100) {
118
- return -1;
119
- }
120
-
121
- if (in_flag) {
122
- write(fd, "in", 3);
123
- } else {
124
- write(fd, "out", 4);
125
- }
126
-
127
- close(fd);
128
- return 0;
129
- }
130
-
131
- int gpio_set_edge(unsigned int gpio, unsigned int edge)
132
- {
133
- int fd;
134
- char filename[28];
135
-
136
- snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio);
137
-
138
- if ((fd = open(filename, O_WRONLY)) < 0)
139
- return -1;
140
-
141
- write(fd, stredge[edge], strlen(stredge[edge]) + 1);
142
- close(fd);
143
- return 0;
144
- }
145
-
146
- int open_value_file(unsigned int gpio)
147
- {
148
- int fd;
149
- char filename[29];
150
-
151
- // create file descriptor of value file
152
- snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
153
- if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
154
- return -1;
155
- return fd;
156
- }
157
-
158
- /********* gpio list functions **********/
159
- struct gpios *get_gpio(unsigned int gpio)
160
- {
161
- struct gpios *g = gpio_list;
162
- while (g != NULL) {
163
- if (g->gpio == gpio)
164
- return g;
165
- g = g->next;
166
- }
167
- return NULL;
168
- }
169
-
170
- struct gpios *get_gpio_from_value_fd(int fd)
171
- {
172
- struct gpios *g = gpio_list;
173
- while (g != NULL) {
174
- if (g->value_fd == fd)
175
- return g;
176
- g = g->next;
177
- }
178
- return NULL;
179
- }
180
-
181
- struct gpios *new_gpio(unsigned int gpio)
182
- {
183
- struct gpios *new_gpio;
184
-
185
- new_gpio = malloc(sizeof(struct gpios));
186
- if (new_gpio == 0) {
187
- return NULL; // out of memory
188
- }
189
-
190
- new_gpio->gpio = gpio;
191
- if (gpio_export(gpio) != 0) {
192
- free(new_gpio);
193
- return NULL;
194
- }
195
- new_gpio->exported = 1;
196
-
197
- if (gpio_set_direction(gpio,1) != 0) { // 1==input
198
- free(new_gpio);
199
- return NULL;
200
- }
201
-
202
- if ((new_gpio->value_fd = open_value_file(gpio)) == -1) {
203
- gpio_unexport(gpio);
204
- free(new_gpio);
205
- return NULL;
206
- }
207
-
208
- new_gpio->initial_thread = 1;
209
- new_gpio->initial_wait = 1;
210
- new_gpio->bouncetime = -666;
211
- new_gpio->lastcall = 0;
212
- new_gpio->thread_added = 0;
213
-
214
- if (gpio_list == NULL) {
215
- new_gpio->next = NULL;
216
- } else {
217
- new_gpio->next = gpio_list;
218
- }
219
- gpio_list = new_gpio;
220
- return new_gpio;
221
- }
222
-
223
- void delete_gpio(unsigned int gpio)
224
- {
225
- struct gpios *g = gpio_list;
226
- struct gpios *temp;
227
- struct gpios *prev = NULL;
228
-
229
- while (g != NULL) {
230
- if (g->gpio == gpio) {
231
- if (prev == NULL)
232
- gpio_list = g->next;
233
- else
234
- prev->next = g->next;
235
- temp = g;
236
- g = g->next;
237
- free(temp);
238
- return;
239
- } else {
240
- prev = g;
241
- g = g->next;
242
- }
243
- }
244
- }
245
-
246
- int gpio_event_added(unsigned int gpio)
247
- {
248
- struct gpios *g = gpio_list;
249
- while (g != NULL) {
250
- if (g->gpio == gpio)
251
- return g->edge;
252
- g = g->next;
253
- }
254
- return 0;
255
- }
256
-
257
- /******* callback list functions ********/
258
- int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
259
- {
260
- struct callback *cb = callbacks;
261
- struct callback *new_cb;
262
-
263
- new_cb = malloc(sizeof(struct callback));
264
- if (new_cb == 0)
265
- return -1; // out of memory
266
-
267
- new_cb->gpio = gpio;
268
- new_cb->func = func;
269
- new_cb->next = NULL;
270
-
271
- if (callbacks == NULL) {
272
- // start new list
273
- callbacks = new_cb;
274
- } else {
275
- // add to end of list
276
- while (cb->next != NULL)
277
- cb = cb->next;
278
- cb->next = new_cb;
279
- }
280
- return 0;
281
- }
282
-
283
- int callback_exists(unsigned int gpio)
284
- {
285
- struct callback *cb = callbacks;
286
- while (cb != NULL) {
287
- if (cb->gpio == gpio)
288
- return 1;
289
- cb = cb->next;
290
- }
291
- return 0;
292
- }
293
-
294
- void run_callbacks(unsigned int gpio)
295
- {
296
- struct callback *cb = callbacks;
297
- while (cb != NULL)
298
- {
299
- if (cb->gpio == gpio)
300
- cb->func(cb->gpio);
301
- cb = cb->next;
302
- }
303
- }
304
-
305
- void remove_callbacks(unsigned int gpio)
306
- {
307
- struct callback *cb = callbacks;
308
- struct callback *temp;
309
- struct callback *prev = NULL;
310
-
311
- while (cb != NULL)
312
- {
313
- if (cb->gpio == gpio)
314
- {
315
- if (prev == NULL)
316
- callbacks = cb->next;
317
- else
318
- prev->next = cb->next;
319
- temp = cb;
320
- cb = cb->next;
321
- free(temp);
322
- } else {
323
- prev = cb;
324
- cb = cb->next;
325
- }
326
- }
327
- }
328
-
329
- void *poll_thread(void *threadarg)
330
- {
331
- struct epoll_event events;
332
- char buf;
333
- struct timeval tv_timenow;
334
- unsigned long long timenow;
335
- struct gpios *g;
336
- int n;
337
-
338
- thread_running = 1;
339
- while (thread_running) {
340
- if ((n = epoll_wait(epfd_thread, &events, 1, -1)) == -1) {
341
- thread_running = 0;
342
- pthread_exit(NULL);
343
- }
344
- if (n > 0) {
345
- lseek(events.data.fd, 0, SEEK_SET);
346
- if (read(events.data.fd, &buf, 1) != 1) {
347
- thread_running = 0;
348
- pthread_exit(NULL);
349
- }
350
- g = get_gpio_from_value_fd(events.data.fd);
351
- if (g->initial_thread) { // ignore first epoll trigger
352
- g->initial_thread = 0;
353
- } else {
354
- gettimeofday(&tv_timenow, NULL);
355
- timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
356
- if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) {
357
- g->lastcall = timenow;
358
- event_occurred[g->gpio] = 1;
359
- run_callbacks(g->gpio);
360
- }
361
- }
362
- }
363
- }
364
- thread_running = 0;
365
- pthread_exit(NULL);
366
- }
367
-
368
- void remove_edge_detect(unsigned int gpio)
369
- {
370
- struct epoll_event ev;
371
- struct gpios *g = get_gpio(gpio);
372
-
373
- if (g == NULL)
374
- return;
375
-
376
- // delete epoll of fd
377
-
378
- ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
379
- ev.data.fd = g->value_fd;
380
- epoll_ctl(epfd_thread, EPOLL_CTL_DEL, g->value_fd, &ev);
381
-
382
- // delete callbacks for gpio
383
- remove_callbacks(gpio);
384
-
385
- // btc fixme - check return result??
386
- gpio_set_edge(gpio, NO_EDGE);
387
- g->edge = NO_EDGE;
388
-
389
- if (g->value_fd != -1)
390
- close(g->value_fd);
391
-
392
- // btc fixme - check return result??
393
- gpio_unexport(gpio);
394
- event_occurred[gpio] = 0;
395
-
396
- delete_gpio(gpio);
397
- }
398
-
399
- int event_detected(unsigned int gpio)
400
- {
401
- if (event_occurred[gpio]) {
402
- event_occurred[gpio] = 0;
403
- return 1;
404
- } else {
405
- return 0;
406
- }
407
- }
408
-
409
- void event_cleanup(unsigned int gpio)
410
- // gpio of -666 means clean every channel used
411
- {
412
- struct gpios *g = gpio_list;
413
- struct gpios *temp = NULL;
414
-
415
- while (g != NULL) {
416
- if ((gpio == -666) || (g->gpio == gpio))
417
- temp = g->next;
418
- remove_edge_detect(g->gpio);
419
- g = temp;
420
- }
421
- if (gpio_list == NULL)
422
- if (epfd_blocking != -1)
423
- close(epfd_blocking);
424
- epfd_blocking = -1;
425
- if (epfd_thread != -1)
426
- close(epfd_thread);
427
- epfd_thread = -1;
428
- thread_running = 0;
429
- }
430
-
431
- void event_cleanup_all(void)
432
- {
433
- event_cleanup(-666);
434
- }
435
-
436
- int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime)
437
- // return values:
438
- // 0 - Success
439
- // 1 - Edge detection already added
440
- // 2 - Other error
441
- {
442
- pthread_t threads;
443
- struct epoll_event ev;
444
- long t = 0;
445
- struct gpios *g;
446
- int i = -1;
447
-
448
- i = gpio_event_added(gpio);
449
- if (i == 0) { // event not already added
450
- if ((g = new_gpio(gpio)) == NULL)
451
- return 2;
452
-
453
- gpio_set_edge(gpio, edge);
454
- g->edge = edge;
455
- g->bouncetime = bouncetime;
456
- } else if (i == edge) { // get existing event
457
- g = get_gpio(gpio);
458
- if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used
459
- (g->thread_added)) // event already added
460
- return 1;
461
- } else {
462
- return 1;
463
- }
464
-
465
- // create epfd_thread if not already open
466
- if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1))
467
- return 2;
468
-
469
- // add to epoll fd
470
- ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
471
- ev.data.fd = g->value_fd;
472
- if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) {
473
- remove_edge_detect(gpio);
474
- return 2;
475
- }
476
- g->thread_added = 1;
477
-
478
- // start poll thread if it is not already running
479
- if (!thread_running) {
480
- if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) {
481
- remove_edge_detect(gpio);
482
- return 2;
483
- }
484
- }
485
- return 0;
486
- }
487
-
488
- int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout)
489
- // return values:
490
- // 1 - Success (edge detected)
491
- // 0 - Timeout
492
- // -1 - Edge detection already added
493
- // -2 - Other error
494
- {
495
- int n, ed;
496
- struct epoll_event events, ev;
497
- char buf;
498
- struct gpios *g = NULL;
499
- struct timeval tv_timenow;
500
- unsigned long long timenow;
501
- int finished = 0;
502
- int initial_edge = 1;
503
-
504
- if (callback_exists(gpio)) {
505
- return -1;
506
- }
507
-
508
- // add gpio if it has not been added already
509
- ed = gpio_event_added(gpio);
510
- if (ed == edge) { // get existing record
511
- g = get_gpio(gpio);
512
- if (g->bouncetime != -666 && g->bouncetime != bouncetime) {
513
- return -1;
514
- }
515
- } else if (ed == NO_EDGE) { // not found so add event
516
- if ((g = new_gpio(gpio)) == NULL) {
517
- return -2;
518
- }
519
- gpio_set_edge(gpio, edge);
520
- g->edge = edge;
521
- g->bouncetime = bouncetime;
522
- } else { // ed != edge - event for a different edge
523
- g = get_gpio(gpio);
524
- gpio_set_edge(gpio, edge);
525
- g->edge = edge;
526
- g->bouncetime = bouncetime;
527
- g->initial_wait = 1;
528
- }
529
-
530
- // create epfd_blocking if not already open
531
- if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) {
532
- return -2;
533
- }
534
-
535
- // add to epoll fd
536
- ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
537
- ev.data.fd = g->value_fd;
538
- if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) {
539
- return -2;
540
- }
541
-
542
- // wait for edge
543
- while (!finished) {
544
- if ((n = epoll_wait(epfd_blocking, &events, 1, timeout)) == -1) {
545
- epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
546
- return -2;
547
- }
548
- if (initial_edge) { // first time triggers with current state, so ignore
549
- initial_edge = 0;
550
- } else {
551
- gettimeofday(&tv_timenow, NULL);
552
- timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
553
- if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) {
554
- g->lastcall = timenow;
555
- finished = 1;
556
- }
557
- }
558
- }
559
-
560
- // check event was valid
561
- if (n > 0) {
562
- lseek(events.data.fd, 0, SEEK_SET);
563
- if ((read(events.data.fd, &buf, 1) != 1) || (events.data.fd != g->value_fd)) {
564
- epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
565
- return -2;
566
- }
567
- }
568
-
569
- epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
570
- if (n == 0) {
571
- return 0; // timeout
572
- } else {
573
- return 1; // edge found
574
- }
575
- }