1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#include "gpio.h"
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define GPIO_BASEDIR "/sys/class/gpio"
#define GPIO_EXPORT GPIO_BASEDIR "/export"
#define GPIO_IN "in"
#define GPIO_INIT_LOW "low"
#define GPIO_INIT_HIGH "high"
struct gpio_watcher {
int port;
void (*fn)(int);
char lastvalue;
};
static int gpio_open(int port, const char *field, int flags)
{
char path[256];
sprintf(path, "%s/gpio%d/%s", GPIO_BASEDIR, port, field);
return open(path, flags);
}
static void gpio_enable(int port, const char *state)
{
int export = open(GPIO_EXPORT, O_WRONLY);
dprintf(export, "%d", port);
close(export);
int direction = gpio_open(port, "direction", O_WRONLY);
write(direction, "direction", strlen(state));
close(direction);
}
static void *gpio_watch_thread(void *arg)
{
struct gpio_watcher *w = arg;
int fd = gpio_open(w->port, "value", O_RDONLY);
read(fd, &(w->lastvalue), 1);
for (;;) {
struct pollfd fds[] = { { fd, POLLPRI | POLLERR, 0 } };
if ((poll(fds, 1, -1) == 1) && (fds[0].revents & POLLPRI)) {
char value;
lseek(fd, 0, SEEK_SET);
read(fd, &value, 1);
if (value != w->lastvalue) {
w->fn(w->port);
w->lastvalue = value;
}
}
}
close(fd);
return NULL;
}
void gpio_watch(int port, void (*fn)(int))
{
printf("starting watcher for %d\n", port);
gpio_enable(port, "in");
int edge = gpio_open(port, "edge", O_WRONLY);
write(edge, "both", 4);
close(edge);
struct gpio_watcher *watcher = malloc(sizeof(*watcher));
watcher->port = port;
watcher->fn = fn;
pthread_t thread;
pthread_create(&thread, NULL, gpio_watch_thread, watcher);
}
|