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