This repository has been archived by the owner on Jul 7, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgpio.h
132 lines (112 loc) · 3.56 KB
/
gpio.h
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// gpio - v1 - simple wrapper around the sysfs gpio interface - public domain - by Patrick Gaskin
#ifndef GPIO_H
#define GPIO_H
#define HIGH 1
#define LOW 0
#define INPUT "in"
#define OUTPUT "out"
#define EDGE_RISING "rising"
#define EDGE_FALLING "falling"
#define EDGE_BOTH "both"
#define EDGE_NONE "none"
// See https://www.kernel.org/doc/Documentation/gpio/sysfs.txt for documentation.
int gpio_export(int pin);
int gpio_unexport(int pin);
int gpio_read(int pin);
int gpio_write(int pin, int val);
int gpio_edge(int pin, char* edge);
int gpio_direction(int pin, char* dir);
int gpio_active_low(int pin, int val);
// gpio_interrupt waits indefinitely for an interrupt on the specified pin.
int gpio_interrupt(int pin);
// gpio_wait_debounced_until uses the algorithm described in
// https://www.embedded.com/electronics-blogs/break-points/4024981/My-favorite-software-debouncers
// to wait for a button to be pressed on the specified pin. It does not require
// interrupts. The pin must already be exported and set to input.
// Example: pullup on pin 2: gpio_wait_debounced_until(2, LOW, 3);
int gpio_wait_debounced_until(int pin, int pressed_val, int tick_millis);
#endif
#ifdef GPIO_IMPLEMENTATION
#include <stdint.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#include <fcntl.h>
#include <unistd.h>
// Note: these macros depend on GCC compiler extensions.
#define GPIO_PATH_R(F) ({char p[255]; snprintf(p, 255, "/sys/class/gpio/%s", F); p;})
#define GPIO_PATH(N, F) ({char p[255]; snprintf(p, 255, "/sys/class/gpio/gpio%d/%s", N, F); p;})
// DO_READ reads N bytes of F into O, and returns -1 on error (errno will be set).
#define DO_READ(F, O, N) ({ \
int tmp = 0, fd = open(F, O_RDONLY); \
if (fd < 0) tmp = -1; \
if (!tmp && read(fd, O, N) != N) tmp = -1; \
if (!tmp) close(fd); \
tmp; \
})
// DO_WRITE does dprintf on a file.
#define DO_WRITE(F, ...) ({ \
int tmp = 0, fd = open(F, O_WRONLY); \
if (fd < 0) tmp = -1; \
if (!tmp && dprintf(fd, __VA_ARGS__) < 0) tmp = -1; \
if (!tmp) close(fd); \
tmp; \
})
int gpio_export(int pin) {
return DO_WRITE(GPIO_PATH_R("export"), "%d", pin);
}
int gpio_unexport(int pin) {
return DO_WRITE(GPIO_PATH_R("unexport"), "%d", pin);
}
int gpio_read(int pin) {
char v;
if (DO_READ(GPIO_PATH(pin, "value"), &v, 1))
return -1;
if (v != '0' && v != '1') {
errno = EINVAL;
return -1;
}
return v == '1' ? HIGH : LOW;
}
int gpio_wait(int pin) {
struct pollfd p;
p.events = POLLPRI | POLLERR;
p.fd = open(GPIO_PATH(pin, "value"), O_RDONLY);
if (p.fd < 0)
return -1;
if (poll(&p, 1, -1) < 0)
return -1;
if (!(p.revents & POLLIN)) {
errno = -1;
return -1;
}
return 0;
}
int gpio_write(int pin, int val) {
return DO_WRITE(GPIO_PATH(pin, "value"), "%d", val);
}
int gpio_edge(int pin, char* edge) {
return DO_WRITE(GPIO_PATH(pin, "edge"), "%s", edge);
}
int gpio_direction(int pin, char* dir) {
return DO_WRITE(GPIO_PATH(pin, "direction"), "%s", dir);
}
int gpio_active_low(int pin, int val) {
return DO_WRITE(GPIO_PATH(pin, "active_low"), "%d", val);
}
int gpio_read_debounced_until(int pin, int pressed_val, int tick_millis) {
int v;
uint16_t state = 0;
while (state != 0xF000) {
nanosleep((const struct timespec[]){{0, tick_millis * 1000000}}, NULL);
if ((v = gpio_read(pin)) < 0)
return -1;
state = (state << 1) | (v != pressed_val ? 0 : 1) | 0xE000;
}
return 0;
}
#undef GPIO_PATH_R
#undef GPIO_PATH
#undef DO_READ
#undef DO_WRITE
#endif