rpi_gpio 0.1.5 → 0.2.0

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