/* * Copyright (c) 2015 Sulev-Madis Silber * Copyright (c) 2015 Luiz Otavio O Souza * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Example program to read GPIO IRQ events. * * Build with: * cc -Wall -o gpio-irq-event gpio-irq-event.c -lgpio */ #include #include #include #include #include #include #include #include #include #include #include #define MAXIRQS 32 static gpio_handle_t handle; static int irq[MAXIRQS], nirqs; static struct pollfd fds[MAXIRQS]; static void usage(void) { printf("usage:\n"); printf("gpio-irq-event [-f /dev/gpioN] [-n] pin_number [pin] [..] [pin]\n"); exit(1); } static void sig_die(int sig) { int i; for (i = 0; i < nirqs; i++) { if (fds[i].fd != -1) { gpio_close(fds[i].fd); } if (gpio_irq_unregister(handle, irq[i]) < 0) { perror("gpio_irq_unregister"); } } gpio_close(handle); printf("\n"); exit(1); } static int read_ev(int fd, char *buf, ssize_t buflen, ssize_t *offset) { ssize_t len; struct gpio_irq_event *ev; len = read(fd, buf + *offset, buflen - *offset); if (len == -1) { perror("read"); return len; } else if (len == 0) { printf("nothing to read: %d\n", len); return len; } ev = (struct gpio_irq_event *)buf; *offset = len; while (*offset >= sizeof(*ev)) { printf("gpiointerrupt ts=%lld.%06ld ts_last=%lld.%06ld pin=%d level=%d\n", ev->ev_ts.tv_sec, ev->ev_ts.tv_usec, ev->ev_ts_last.tv_sec, ev->ev_ts_last.tv_usec, ev->ev_pin, ev->ev_level); ev++; *offset -= sizeof(*ev); } if (offset > 0) { bcopy(buf + len - *offset, buf, *offset); } return 1; } static void poll_irq_ev(struct pollfd *fds, int nfds) { char *buf; int i, rv; ssize_t buflen, offset; offset = 0; buflen = sizeof(struct gpio_irq_event) * 128; buf = malloc(buflen); for (;;) { rv = poll(fds, nfds, -1); if (rv == -1) { perror("poll"); break; } else if (rv == 0) { printf("invalid poll return\n"); break; } for (i = 0; i < nfds; i++) { if (fds[i].revents & POLLIN) { if (read_ev(fds[i].fd, buf, buflen, &offset) <= 0) { break; } } } } free(buf); } static void read_irq_ev(int fd) { char *buf; ssize_t buflen, offset; offset = 0; buflen = sizeof(struct gpio_irq_event) * 128; buf = malloc(buflen); for (;;) { if (read_ev(fd, buf, buflen, &offset) <= 0) { break; } } free(buf); } int main(int argc, char **argv) { char *ctlfile; int ch, flags, i; unsigned int unit; flags = 0; ctlfile = NULL; while ((ch = getopt(argc, argv, "f:n")) != -1) { switch (ch) { case 'f': ctlfile = optarg; break; case 'n': flags |= O_NONBLOCK; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1) { usage(); } nirqs = 0; while (argc > 0 && nirqs < MAXIRQS) { irq[nirqs] = atoi(argv[0]); argc--; argv++; nirqs++; } if (argc > 0 || nirqs > MAXIRQS) { printf("too many pins at once, try increase MAXIRQS.\n"); exit(1); } if (nirqs > 1 && (flags & O_NONBLOCK) == 0) { printf("multiple pins implies the use of nonblock mode.\n"); flags |= O_NONBLOCK; } if (flags & O_NONBLOCK) { printf("using nonblock mode.\n"); } if (ctlfile == NULL) { handle = gpio_open(0); } else { handle = gpio_open_device(ctlfile); } if (handle == GPIO_INVALID_HANDLE) { perror("gpio_open"); exit(1); } for (i = 0; i < MAXIRQS; i++) { fds[i].fd = -1; } signal(SIGINT, sig_die); signal(SIGHUP, sig_die); signal(SIGTERM, sig_die); for (i = 0; i < nirqs; i++) { if (gpio_irq_register(handle, irq[i], &unit) < 0) { perror("gpio_irq_register"); goto out; } /* Open irq event device. */ fds[i].fd = gpio_irq_open(unit, flags); if (fds[i].fd == GPIO_INVALID_HANDLE) { perror("gpio_irq_open"); goto out; } fds[i].events = POLLIN; } fprintf(stderr, "READY\n"); if (flags & O_NONBLOCK) { poll_irq_ev(fds, nirqs); } else { read_irq_ev(fds[0].fd); } out: for (i = 0; i < nirqs; i++) { if (fds[i].fd != -1) { gpio_close(fds[i].fd); } if (gpio_irq_unregister(handle, irq[i]) < 0) { perror("gpio_irq_unregister"); } } gpio_close(handle); exit(0); }