forked from skristiansson/linux
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <linus.walleij@linaro.org>
- Loading branch information
Showing
2 changed files
with
195 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
CC = $(CROSS_COMPILE)gcc | ||
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE | ||
|
||
all: lsgpio gpio-hammer | ||
all: lsgpio gpio-hammer gpio-event-mon | ||
|
||
lsgpio: lsgpio.o gpio-utils.o | ||
gpio-hammer: gpio-hammer.o gpio-utils.o | ||
gpio-event-mon: gpio-event-mon.o gpio-utils.o | ||
|
||
%.o: %.c gpio-utils.h | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f *.o lsgpio gpio-hammer | ||
rm -f *.o lsgpio gpio-hammer gpio-event-mon |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* gpio-hammer - example swiss army knife to shake GPIO lines on a system | ||
* | ||
* Copyright (C) 2016 Linus Walleij | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 as published by | ||
* the Free Software Foundation. | ||
* | ||
* Usage: | ||
* gpio-event-mon -n <device-name> -o <offset> | ||
*/ | ||
|
||
#include <unistd.h> | ||
#include <stdlib.h> | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
#include <poll.h> | ||
#include <fcntl.h> | ||
#include <getopt.h> | ||
#include <inttypes.h> | ||
#include <sys/ioctl.h> | ||
#include <linux/gpio.h> | ||
|
||
int monitor_device(const char *device_name, | ||
unsigned int line, | ||
u_int32_t handleflags, | ||
u_int32_t eventflags, | ||
unsigned int loops) | ||
{ | ||
struct gpioevent_request req; | ||
struct gpiohandle_data data; | ||
char *chrdev_name; | ||
int fd; | ||
int ret; | ||
int i = 0; | ||
|
||
ret = asprintf(&chrdev_name, "/dev/%s", device_name); | ||
if (ret < 0) | ||
return -ENOMEM; | ||
|
||
fd = open(chrdev_name, 0); | ||
if (fd == -1) { | ||
ret = -errno; | ||
fprintf(stderr, "Failed to open %s\n", chrdev_name); | ||
goto exit_close_error; | ||
} | ||
|
||
req.lineoffset = line; | ||
req.handleflags = handleflags; | ||
req.eventflags = eventflags; | ||
strcpy(req.consumer_label, "gpio-event-mon"); | ||
|
||
ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req); | ||
if (ret == -1) { | ||
ret = -errno; | ||
fprintf(stderr, "Failed to issue GET EVENT " | ||
"IOCTL (%d)\n", | ||
ret); | ||
goto exit_close_error; | ||
} | ||
|
||
/* Read initial states */ | ||
ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); | ||
if (ret == -1) { | ||
ret = -errno; | ||
fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " | ||
"VALUES IOCTL (%d)\n", | ||
ret); | ||
goto exit_close_error; | ||
} | ||
|
||
fprintf(stdout, "Monitoring line %d on %s\n", line, device_name); | ||
fprintf(stdout, "Initial line value: %d\n", data.values[0]); | ||
|
||
while (1) { | ||
struct gpioevent_data event; | ||
|
||
ret = read(req.fd, &event, sizeof(event)); | ||
if (ret == -1) { | ||
if (errno == -EAGAIN) { | ||
fprintf(stderr, "nothing available\n"); | ||
continue; | ||
} else { | ||
ret = -errno; | ||
fprintf(stderr, "Failed to read event (%d)\n", | ||
ret); | ||
break; | ||
} | ||
} | ||
|
||
if (ret != sizeof(event)) { | ||
fprintf(stderr, "Reading event failed\n"); | ||
ret = -EIO; | ||
break; | ||
} | ||
fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp); | ||
switch (event.id) { | ||
case GPIOEVENT_EVENT_RISING_EDGE: | ||
fprintf(stdout, "rising edge"); | ||
break; | ||
case GPIOEVENT_EVENT_FALLING_EDGE: | ||
fprintf(stdout, "falling edge"); | ||
break; | ||
default: | ||
fprintf(stdout, "unknown event"); | ||
} | ||
fprintf(stdout, "\n"); | ||
|
||
i++; | ||
if (i == loops) | ||
break; | ||
} | ||
|
||
exit_close_error: | ||
if (close(fd) == -1) | ||
perror("Failed to close GPIO character device file"); | ||
free(chrdev_name); | ||
return ret; | ||
} | ||
|
||
void print_usage(void) | ||
{ | ||
fprintf(stderr, "Usage: gpio-event-mon [options]...\n" | ||
"Listen to events on GPIO lines, 0->1 1->0\n" | ||
" -n <name> Listen on GPIOs on a named device (must be stated)\n" | ||
" -o <n> Offset to monitor\n" | ||
" -d Set line as open drain\n" | ||
" -s Set line as open source\n" | ||
" -r Listen for rising edges\n" | ||
" -f Listen for falling edges\n" | ||
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n" | ||
" -? This helptext\n" | ||
"\n" | ||
"Example:\n" | ||
"gpio-event-mon -n gpiochip0 -o 4 -r -f\n" | ||
); | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
const char *device_name = NULL; | ||
unsigned int line = -1; | ||
unsigned int loops = 0; | ||
u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT; | ||
u_int32_t eventflags = 0; | ||
int c; | ||
|
||
while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) { | ||
switch (c) { | ||
case 'c': | ||
loops = strtoul(optarg, NULL, 10); | ||
break; | ||
case 'n': | ||
device_name = optarg; | ||
break; | ||
case 'o': | ||
line = strtoul(optarg, NULL, 10); | ||
break; | ||
case 'd': | ||
handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN; | ||
break; | ||
case 's': | ||
handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE; | ||
break; | ||
case 'r': | ||
eventflags |= GPIOEVENT_REQUEST_RISING_EDGE; | ||
break; | ||
case 'f': | ||
eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE; | ||
break; | ||
case '?': | ||
print_usage(); | ||
return -1; | ||
} | ||
} | ||
|
||
if (!device_name || line == -1) { | ||
print_usage(); | ||
return -1; | ||
} | ||
if (!eventflags) { | ||
printf("No flags specified, listening on both rising and " | ||
"falling edges\n"); | ||
eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; | ||
} | ||
return monitor_device(device_name, line, handleflags, | ||
eventflags, loops); | ||
} |