rpi_gpio 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2015 Nick Lowery
5
+
6
+ Copyright (c) 2013-2014 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
+ #define PY_PUD_CONST_OFFSET 20
28
+ #define PY_EVENT_CONST_OFFSET 30
29
+
30
+ VALUE pwm;
31
+ VALUE serial;
32
+ VALUE i2c;
33
+ VALUE spi;
34
+ VALUE unknown;
35
+ VALUE rising_edge;
36
+ VALUE falling_edge;
37
+ VALUE both_edge;
38
+ VALUE version;
39
+
40
+ void define_constants(VALUE module);
@@ -0,0 +1,88 @@
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2015 Nick Lowery
5
+
6
+ Copyright (c) 2013-2014 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 <stdio.h>
28
+ #include <string.h>
29
+ #include "cpuinfo.h"
30
+
31
+ char *get_cpuinfo_revision(char *revision)
32
+ {
33
+ FILE *fp;
34
+ char buffer[1024];
35
+ char hardware[1024];
36
+ int rpi_found = 0;
37
+
38
+ if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
39
+ return 0;
40
+
41
+ while(!feof(fp)) {
42
+ fgets(buffer, sizeof(buffer) , fp);
43
+ sscanf(buffer, "Hardware : %s", hardware);
44
+ if (strcmp(hardware, "BCM2708") == 0)
45
+ rpi_found = 1;
46
+ sscanf(buffer, "Revision : %s", revision);
47
+ }
48
+ fclose(fp);
49
+
50
+ if (!rpi_found)
51
+ revision = NULL;
52
+ return revision;
53
+ }
54
+
55
+ int get_rpi_revision(void)
56
+ {
57
+ char raw_revision[1024] = {'\0'};
58
+ int len;
59
+ char *revision;
60
+
61
+ if (get_cpuinfo_revision(raw_revision) == NULL)
62
+ return -1;
63
+
64
+ // get last four characters (ignore preceeding 1000 for overvolt)
65
+ len = strlen(raw_revision);
66
+ if (len > 4)
67
+ revision = (char *)&raw_revision+len-4;
68
+ else
69
+ revision = raw_revision;
70
+
71
+ if ((strcmp(revision, "0002") == 0) ||
72
+ (strcmp(revision, "0003") == 0))
73
+ return 1;
74
+ else if ((strcmp(revision, "0004") == 0) ||
75
+ (strcmp(revision, "0005") == 0) ||
76
+ (strcmp(revision, "0006") == 0) ||
77
+ (strcmp(revision, "0007") == 0) ||
78
+ (strcmp(revision, "0008") == 0) ||
79
+ (strcmp(revision, "0009") == 0) ||
80
+ (strcmp(revision, "000d") == 0) ||
81
+ (strcmp(revision, "000e") == 0) ||
82
+ (strcmp(revision, "000f") == 0))
83
+ return 2; // revision 2
84
+ else if (strcmp(revision, "0011") == 0)
85
+ return 0; // compute module
86
+ else // assume B+ (0010) or A+ (0012)
87
+ return 3;
88
+ }
@@ -0,0 +1,27 @@
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2015 Nick Lowery
5
+
6
+ Copyright (c) 2013-2014 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
+ int get_rpi_revision(void);
@@ -0,0 +1,556 @@
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2015 Nick Lowery
5
+
6
+ Copyright (c) 2013-2014 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 fd;
103
+ char filename[33];
104
+
105
+ snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
106
+ if ((fd = open(filename, O_WRONLY)) < 0)
107
+ return -1;
108
+
109
+ if (in_flag)
110
+ write(fd, "in", 3);
111
+ else
112
+ write(fd, "out", 4);
113
+
114
+ close(fd);
115
+ return 0;
116
+ }
117
+
118
+ int gpio_set_edge(unsigned int gpio, unsigned int edge)
119
+ {
120
+ int fd;
121
+ char filename[28];
122
+
123
+ snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio);
124
+
125
+ if ((fd = open(filename, O_WRONLY)) < 0)
126
+ return -1;
127
+
128
+ write(fd, stredge[edge], strlen(stredge[edge]) + 1);
129
+ close(fd);
130
+ return 0;
131
+ }
132
+
133
+ int open_value_file(unsigned int gpio)
134
+ {
135
+ int fd;
136
+ char filename[29];
137
+
138
+ // create file descriptor of value file
139
+ snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
140
+ if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
141
+ return -1;
142
+ return fd;
143
+ }
144
+
145
+ /********* gpio list functions **********/
146
+ struct gpios *get_gpio(unsigned int gpio)
147
+ {
148
+ struct gpios *g = gpio_list;
149
+ while (g != NULL) {
150
+ if (g->gpio == gpio)
151
+ return g;
152
+ g = g->next;
153
+ }
154
+ return NULL;
155
+ }
156
+
157
+ struct gpios *get_gpio_from_value_fd(int fd)
158
+ {
159
+ struct gpios *g = gpio_list;
160
+ while (g != NULL) {
161
+ if (g->value_fd == fd)
162
+ return g;
163
+ g = g->next;
164
+ }
165
+ return NULL;
166
+ }
167
+
168
+ struct gpios *new_gpio(unsigned int gpio)
169
+ {
170
+ struct gpios *new_gpio;
171
+
172
+ new_gpio = malloc(sizeof(struct gpios));
173
+ if (new_gpio == 0)
174
+ return NULL; // out of memory
175
+
176
+ new_gpio->gpio = gpio;
177
+ if (gpio_export(gpio) != 0) {
178
+ free(new_gpio);
179
+ return NULL;
180
+ }
181
+ new_gpio->exported = 1;
182
+
183
+ if (gpio_set_direction(gpio,1) != 0) { // 1==input
184
+ free(new_gpio);
185
+ return NULL;
186
+ }
187
+
188
+ if ((new_gpio->value_fd = open_value_file(gpio)) == -1) {
189
+ gpio_unexport(gpio);
190
+ free(new_gpio);
191
+ return NULL;
192
+ }
193
+
194
+ new_gpio->initial_thread = 1;
195
+ new_gpio->initial_wait = 1;
196
+ new_gpio->bouncetime = -666;
197
+ new_gpio->lastcall = 0;
198
+ new_gpio->thread_added = 0;
199
+
200
+ if (gpio_list == NULL) {
201
+ new_gpio->next = NULL;
202
+ } else {
203
+ new_gpio->next = gpio_list;
204
+ }
205
+ gpio_list = new_gpio;
206
+ return new_gpio;
207
+ }
208
+
209
+ void delete_gpio(unsigned int gpio)
210
+ {
211
+ struct gpios *g = gpio_list;
212
+ struct gpios *temp;
213
+ struct gpios *prev = NULL;
214
+
215
+ while (g != NULL) {
216
+ if (g->gpio == gpio) {
217
+ if (prev == NULL)
218
+ gpio_list = g->next;
219
+ else
220
+ prev->next = g->next;
221
+ temp = g;
222
+ g = g->next;
223
+ free(temp);
224
+ return;
225
+ } else {
226
+ prev = g;
227
+ g = g->next;
228
+ }
229
+ }
230
+ }
231
+
232
+ int gpio_event_added(unsigned int gpio)
233
+ {
234
+ struct gpios *g = gpio_list;
235
+ while (g != NULL) {
236
+ if (g->gpio == gpio)
237
+ return g->edge;
238
+ g = g->next;
239
+ }
240
+ return 0;
241
+ }
242
+
243
+ /******* callback list functions ********/
244
+ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
245
+ {
246
+ struct callback *cb = callbacks;
247
+ struct callback *new_cb;
248
+
249
+ new_cb = malloc(sizeof(struct callback));
250
+ if (new_cb == 0)
251
+ return -1; // out of memory
252
+
253
+ new_cb->gpio = gpio;
254
+ new_cb->func = func;
255
+ new_cb->next = NULL;
256
+
257
+ if (callbacks == NULL) {
258
+ // start new list
259
+ callbacks = new_cb;
260
+ } else {
261
+ // add to end of list
262
+ while (cb->next != NULL)
263
+ cb = cb->next;
264
+ cb->next = new_cb;
265
+ }
266
+ return 0;
267
+ }
268
+
269
+ int callback_exists(unsigned int gpio)
270
+ {
271
+ struct callback *cb = callbacks;
272
+ while (cb != NULL) {
273
+ if (cb->gpio == gpio)
274
+ return 1;
275
+ cb = cb->next;
276
+ }
277
+ return 0;
278
+ }
279
+
280
+ void run_callbacks(unsigned int gpio)
281
+ {
282
+ struct callback *cb = callbacks;
283
+ while (cb != NULL)
284
+ {
285
+ if (cb->gpio == gpio)
286
+ cb->func(cb->gpio);
287
+ cb = cb->next;
288
+ }
289
+ }
290
+
291
+ void remove_callbacks(unsigned int gpio)
292
+ {
293
+ struct callback *cb = callbacks;
294
+ struct callback *temp;
295
+ struct callback *prev = NULL;
296
+
297
+ while (cb != NULL)
298
+ {
299
+ if (cb->gpio == gpio)
300
+ {
301
+ if (prev == NULL)
302
+ callbacks = cb->next;
303
+ else
304
+ prev->next = cb->next;
305
+ temp = cb;
306
+ cb = cb->next;
307
+ free(temp);
308
+ } else {
309
+ prev = cb;
310
+ cb = cb->next;
311
+ }
312
+ }
313
+ }
314
+
315
+ void *poll_thread(void *threadarg)
316
+ {
317
+ struct epoll_event events;
318
+ char buf;
319
+ struct timeval tv_timenow;
320
+ unsigned long long timenow;
321
+ struct gpios *g;
322
+ int n;
323
+
324
+ thread_running = 1;
325
+ while (thread_running) {
326
+ if ((n = epoll_wait(epfd_thread, &events, 1, -1)) == -1) {
327
+ thread_running = 0;
328
+ pthread_exit(NULL);
329
+ }
330
+ if (n > 0) {
331
+ lseek(events.data.fd, 0, SEEK_SET);
332
+ if (read(events.data.fd, &buf, 1) != 1) {
333
+ thread_running = 0;
334
+ pthread_exit(NULL);
335
+ }
336
+ g = get_gpio_from_value_fd(events.data.fd);
337
+ if (g->initial_thread) { // ignore first epoll trigger
338
+ g->initial_thread = 0;
339
+ } else {
340
+ gettimeofday(&tv_timenow, NULL);
341
+ timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
342
+ if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) {
343
+ g->lastcall = timenow;
344
+ event_occurred[g->gpio] = 1;
345
+ run_callbacks(g->gpio);
346
+ }
347
+ }
348
+ }
349
+ }
350
+ thread_running = 0;
351
+ pthread_exit(NULL);
352
+ }
353
+
354
+ void remove_edge_detect(unsigned int gpio)
355
+ {
356
+ struct epoll_event ev;
357
+ struct gpios *g = get_gpio(gpio);
358
+
359
+ if (g == NULL)
360
+ return;
361
+
362
+ // delete epoll of fd
363
+
364
+ ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
365
+ ev.data.fd = g->value_fd;
366
+ epoll_ctl(epfd_thread, EPOLL_CTL_DEL, g->value_fd, &ev);
367
+
368
+ // delete callbacks for gpio
369
+ remove_callbacks(gpio);
370
+
371
+ // btc fixme - check return result??
372
+ gpio_set_edge(gpio, NO_EDGE);
373
+ g->edge = NO_EDGE;
374
+
375
+ if (g->value_fd != -1)
376
+ close(g->value_fd);
377
+
378
+ // btc fixme - check return result??
379
+ gpio_unexport(gpio);
380
+ event_occurred[gpio] = 0;
381
+
382
+ delete_gpio(gpio);
383
+ }
384
+
385
+ int event_detected(unsigned int gpio)
386
+ {
387
+ if (event_occurred[gpio]) {
388
+ event_occurred[gpio] = 0;
389
+ return 1;
390
+ } else {
391
+ return 0;
392
+ }
393
+ }
394
+
395
+ void event_cleanup(unsigned int gpio)
396
+ // gpio of -666 means clean every channel used
397
+ {
398
+ struct gpios *g = gpio_list;
399
+ struct gpios *temp = NULL;
400
+
401
+ while (g != NULL) {
402
+ if ((gpio == -666) || (g->gpio == gpio))
403
+ temp = g->next;
404
+ remove_edge_detect(g->gpio);
405
+ g = temp;
406
+ }
407
+ if (gpio_list == NULL)
408
+ if (epfd_blocking != -1)
409
+ close(epfd_blocking);
410
+ epfd_blocking = -1;
411
+ if (epfd_thread != -1)
412
+ close(epfd_thread);
413
+ epfd_thread = -1;
414
+ thread_running = 0;
415
+ }
416
+
417
+ void event_cleanup_all(void)
418
+ {
419
+ event_cleanup(-666);
420
+ }
421
+
422
+ int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime)
423
+ // return values:
424
+ // 0 - Success
425
+ // 1 - Edge detection already added
426
+ // 2 - Other error
427
+ {
428
+ pthread_t threads;
429
+ struct epoll_event ev;
430
+ long t = 0;
431
+ struct gpios *g;
432
+ int i = -1;
433
+
434
+ i = gpio_event_added(gpio);
435
+ if (i == 0) { // event not already added
436
+ if ((g = new_gpio(gpio)) == NULL)
437
+ return 2;
438
+
439
+ gpio_set_edge(gpio, edge);
440
+ g->edge = edge;
441
+ g->bouncetime = bouncetime;
442
+ } else if (i == edge) { // get existing event
443
+ g = get_gpio(gpio);
444
+ if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used
445
+ (g->thread_added)) // event already added
446
+ return 1;
447
+ } else {
448
+ return 1;
449
+ }
450
+
451
+ // create epfd_thread if not already open
452
+ if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1))
453
+ return 2;
454
+
455
+ // add to epoll fd
456
+ ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
457
+ ev.data.fd = g->value_fd;
458
+ if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) {
459
+ remove_edge_detect(gpio);
460
+ return 2;
461
+ }
462
+ g->thread_added = 1;
463
+
464
+ // start poll thread if it is not already running
465
+ if (!thread_running) {
466
+ if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) {
467
+ remove_edge_detect(gpio);
468
+ return 2;
469
+ }
470
+ }
471
+ return 0;
472
+ }
473
+
474
+ int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime)
475
+ // return values:
476
+ // 0 - Success
477
+ // 1 - Edge detection already added
478
+ // 2 - Other error
479
+ {
480
+ int n, ed;
481
+ struct epoll_event events, ev;
482
+ char buf;
483
+ struct gpios *g = NULL;
484
+ struct timeval tv_timenow;
485
+ unsigned long long timenow;
486
+ int finished = 0;
487
+
488
+ if (callback_exists(gpio))
489
+ return 1;
490
+
491
+ // add gpio if it has not been added already
492
+ ed = gpio_event_added(gpio);
493
+ if (ed == edge) { // get existing record
494
+ g = get_gpio(gpio);
495
+ if (g->bouncetime != -666 && g->bouncetime != bouncetime) {
496
+ return 1;
497
+ }
498
+ } else if (ed == NO_EDGE) { // not found so add event
499
+ if ((g = new_gpio(gpio)) == NULL)
500
+ return 2;
501
+ gpio_set_edge(gpio, edge);
502
+ g->edge = edge;
503
+ g->bouncetime = bouncetime;
504
+ } else { // ed != edge - event for a different edge
505
+ g = get_gpio(gpio);
506
+ gpio_set_edge(gpio, edge);
507
+ g->edge = edge;
508
+ g->bouncetime = bouncetime;
509
+ g->initial_wait = 1;
510
+ }
511
+
512
+ // create epfd_blocking if not already open
513
+ if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) {
514
+ return 2;
515
+ }
516
+
517
+ // add to epoll fd
518
+ ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
519
+ ev.data.fd = g->value_fd;
520
+ if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) {
521
+ return 2;
522
+ }
523
+
524
+ // wait for edge
525
+ while (!finished) {
526
+ if ((n = epoll_wait(epfd_blocking, &events, 1, -1)) == -1) {
527
+ epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
528
+ return 2;
529
+ }
530
+ if (g->initial_wait) { // first time triggers with current state, so ignore
531
+ g->initial_wait = 0;
532
+ } else {
533
+ gettimeofday(&tv_timenow, NULL);
534
+ timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
535
+ if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) {
536
+ g->lastcall = timenow;
537
+ finished = 1;
538
+ }
539
+ }
540
+ }
541
+
542
+ if (n > 0) {
543
+ lseek(events.data.fd, 0, SEEK_SET);
544
+ if (read(events.data.fd, &buf, 1) != 1) {
545
+ epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
546
+ return 2;
547
+ }
548
+ if (events.data.fd != g->value_fd) {
549
+ epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
550
+ return 2;
551
+ }
552
+ }
553
+
554
+ epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev);
555
+ return 0;
556
+ }