Skip to content

Commit 97f6974

Browse files
author
Linus Walleij
committed
tools/gpio: add the gpio-event-mon tool
The gpio-event-mon is used from userspace as an example of how to monitor GPIO line events. It will latch on to a certain GPIO line on a certain gpiochip and print timestamped events as they arrive. Example output: $ gpio-event-mon -n gpiochip2 -o 0 -r -f Monitoring line 0 on gpiochip2 Initial line value: 1 GPIO EVENT 946685798487609863: falling edge GPIO EVENT 946685798732482910: rising edge GPIO EVENT 946685799115997314: falling edge GPIO EVENT 946685799381469726: rising edge Signed-off-by: Linus Walleij <[email protected]>
1 parent 61f922d commit 97f6974

File tree

2 files changed

+195
-2
lines changed

2 files changed

+195
-2
lines changed

tools/gpio/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
CC = $(CROSS_COMPILE)gcc
22
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE
33

4-
all: lsgpio gpio-hammer
4+
all: lsgpio gpio-hammer gpio-event-mon
55

66
lsgpio: lsgpio.o gpio-utils.o
77
gpio-hammer: gpio-hammer.o gpio-utils.o
8+
gpio-event-mon: gpio-event-mon.o gpio-utils.o
89

910
%.o: %.c gpio-utils.h
1011

1112
.PHONY: clean
1213
clean:
13-
rm -f *.o lsgpio gpio-hammer
14+
rm -f *.o lsgpio gpio-hammer gpio-event-mon

tools/gpio/gpio-event-mon.c

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* gpio-hammer - example swiss army knife to shake GPIO lines on a system
3+
*
4+
* Copyright (C) 2016 Linus Walleij
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 as published by
8+
* the Free Software Foundation.
9+
*
10+
* Usage:
11+
* gpio-event-mon -n <device-name> -o <offset>
12+
*/
13+
14+
#include <unistd.h>
15+
#include <stdlib.h>
16+
#include <stdbool.h>
17+
#include <stdio.h>
18+
#include <dirent.h>
19+
#include <errno.h>
20+
#include <string.h>
21+
#include <poll.h>
22+
#include <fcntl.h>
23+
#include <getopt.h>
24+
#include <inttypes.h>
25+
#include <sys/ioctl.h>
26+
#include <linux/gpio.h>
27+
28+
int monitor_device(const char *device_name,
29+
unsigned int line,
30+
u_int32_t handleflags,
31+
u_int32_t eventflags,
32+
unsigned int loops)
33+
{
34+
struct gpioevent_request req;
35+
struct gpiohandle_data data;
36+
char *chrdev_name;
37+
int fd;
38+
int ret;
39+
int i = 0;
40+
41+
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
42+
if (ret < 0)
43+
return -ENOMEM;
44+
45+
fd = open(chrdev_name, 0);
46+
if (fd == -1) {
47+
ret = -errno;
48+
fprintf(stderr, "Failed to open %s\n", chrdev_name);
49+
goto exit_close_error;
50+
}
51+
52+
req.lineoffset = line;
53+
req.handleflags = handleflags;
54+
req.eventflags = eventflags;
55+
strcpy(req.consumer_label, "gpio-event-mon");
56+
57+
ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
58+
if (ret == -1) {
59+
ret = -errno;
60+
fprintf(stderr, "Failed to issue GET EVENT "
61+
"IOCTL (%d)\n",
62+
ret);
63+
goto exit_close_error;
64+
}
65+
66+
/* Read initial states */
67+
ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
68+
if (ret == -1) {
69+
ret = -errno;
70+
fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
71+
"VALUES IOCTL (%d)\n",
72+
ret);
73+
goto exit_close_error;
74+
}
75+
76+
fprintf(stdout, "Monitoring line %d on %s\n", line, device_name);
77+
fprintf(stdout, "Initial line value: %d\n", data.values[0]);
78+
79+
while (1) {
80+
struct gpioevent_data event;
81+
82+
ret = read(req.fd, &event, sizeof(event));
83+
if (ret == -1) {
84+
if (errno == -EAGAIN) {
85+
fprintf(stderr, "nothing available\n");
86+
continue;
87+
} else {
88+
ret = -errno;
89+
fprintf(stderr, "Failed to read event (%d)\n",
90+
ret);
91+
break;
92+
}
93+
}
94+
95+
if (ret != sizeof(event)) {
96+
fprintf(stderr, "Reading event failed\n");
97+
ret = -EIO;
98+
break;
99+
}
100+
fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
101+
switch (event.id) {
102+
case GPIOEVENT_EVENT_RISING_EDGE:
103+
fprintf(stdout, "rising edge");
104+
break;
105+
case GPIOEVENT_EVENT_FALLING_EDGE:
106+
fprintf(stdout, "falling edge");
107+
break;
108+
default:
109+
fprintf(stdout, "unknown event");
110+
}
111+
fprintf(stdout, "\n");
112+
113+
i++;
114+
if (i == loops)
115+
break;
116+
}
117+
118+
exit_close_error:
119+
if (close(fd) == -1)
120+
perror("Failed to close GPIO character device file");
121+
free(chrdev_name);
122+
return ret;
123+
}
124+
125+
void print_usage(void)
126+
{
127+
fprintf(stderr, "Usage: gpio-event-mon [options]...\n"
128+
"Listen to events on GPIO lines, 0->1 1->0\n"
129+
" -n <name> Listen on GPIOs on a named device (must be stated)\n"
130+
" -o <n> Offset to monitor\n"
131+
" -d Set line as open drain\n"
132+
" -s Set line as open source\n"
133+
" -r Listen for rising edges\n"
134+
" -f Listen for falling edges\n"
135+
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
136+
" -? This helptext\n"
137+
"\n"
138+
"Example:\n"
139+
"gpio-event-mon -n gpiochip0 -o 4 -r -f\n"
140+
);
141+
}
142+
143+
int main(int argc, char **argv)
144+
{
145+
const char *device_name = NULL;
146+
unsigned int line = -1;
147+
unsigned int loops = 0;
148+
u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT;
149+
u_int32_t eventflags = 0;
150+
int c;
151+
152+
while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) {
153+
switch (c) {
154+
case 'c':
155+
loops = strtoul(optarg, NULL, 10);
156+
break;
157+
case 'n':
158+
device_name = optarg;
159+
break;
160+
case 'o':
161+
line = strtoul(optarg, NULL, 10);
162+
break;
163+
case 'd':
164+
handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
165+
break;
166+
case 's':
167+
handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
168+
break;
169+
case 'r':
170+
eventflags |= GPIOEVENT_REQUEST_RISING_EDGE;
171+
break;
172+
case 'f':
173+
eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE;
174+
break;
175+
case '?':
176+
print_usage();
177+
return -1;
178+
}
179+
}
180+
181+
if (!device_name || line == -1) {
182+
print_usage();
183+
return -1;
184+
}
185+
if (!eventflags) {
186+
printf("No flags specified, listening on both rising and "
187+
"falling edges\n");
188+
eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
189+
}
190+
return monitor_device(device_name, line, handleflags,
191+
eventflags, loops);
192+
}

0 commit comments

Comments
 (0)