+/* Copyright (c) 2011, RidgeRun
+ * All rights reserved.
+ *
+ * Contributors include:
+ * Todd Fischer
+ * Brad Lu
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the RidgeRun.
+ * 4. Neither the name of the RidgeRun nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''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 RIDGERUN 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <getopt.h>
+#include <time.h>
+
+ /****************************************************************
+ * Constants
+ ****************************************************************/
+
+#define SYSFS_GPIO_DIR "/sys/class/gpio"
+#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
+#define MAX_BUF 64
+
+/****************************************************************
+ * gpio_export
+ ****************************************************************/
+int gpio_export(unsigned int gpio)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/export");
+ return fd;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%d", gpio);
+ write(fd, buf, len);
+ close(fd);
+
+ return 0;
+}
+
+/****************************************************************
+ * gpio_unexport
+ ****************************************************************/
+int gpio_unexport(unsigned int gpio)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/export");
+ return fd;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%d", gpio);
+ write(fd, buf, len);
+ close(fd);
+ return 0;
+}
+
+/****************************************************************
+ * gpio_set_dir
+ ****************************************************************/
+int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
+
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/direction");
+ return fd;
+ }
+
+ if (out_flag)
+ write(fd, "out", 4);
+ else
+ write(fd, "in", 3);
+
+ close(fd);
+ return 0;
+}
+
+/****************************************************************
+ * gpio_set_value
+ ****************************************************************/
+int gpio_set_value(unsigned int gpio, unsigned int value)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/set-value");
+ return fd;
+ }
+
+ if (value)
+ write(fd, "1", 2);
+ else
+ write(fd, "0", 2);
+
+ close(fd);
+ return 0;
+}
+
+/****************************************************************
+ * gpio_get_value
+ ****************************************************************/
+int gpio_get_value(unsigned int gpio, unsigned int *value)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+ char ch;
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ perror("gpio/get-value");
+ return fd;
+ }
+
+ read(fd, &ch, 1);
+
+ if (ch != '0') {
+ *value = 1;
+ } else {
+ *value = 0;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/****************************************************************
+ * gpio_set_edge
+ ****************************************************************/
+
+int gpio_set_edge(unsigned int gpio, char *edge)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
+
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/set-edge");
+ return fd;
+ }
+
+ write(fd, edge, strlen(edge) + 1);
+ close(fd);
+ return 0;
+}
+
+int gpio_set_level(unsigned int gpio, int level)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
+
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) {
+ perror("gpio/set-level");
+ return fd;
+ }
+
+ write(fd, level?"1":"0", 2);
+
+ close(fd);
+ return 0;
+}
+
+/****************************************************************
+ * gpio_fd_open
+ ****************************************************************/
+
+int gpio_fd_open(unsigned int gpio)
+{
+ int fd, len;
+ char buf[MAX_BUF];
+
+ len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+ fd = open(buf, O_RDONLY | O_NONBLOCK );
+ if (fd < 0) {
+ perror("gpio/fd_open");
+ }
+ return fd;
+}
+
+/****************************************************************
+ * gpio_fd_close
+ ****************************************************************/
+
+int gpio_fd_close(int fd)
+{
+ return close(fd);
+}
+
+/****************************************************************
+ * Main
+ ****************************************************************/
+
+#define OPTSTRING "e:l:"
+
+int main(int argc, char **argv, char **envp)
+{
+ struct pollfd *fdset;
+ int timeout, rc;
+ char *buf[MAX_BUF];
+ unsigned int gpio;
+ unsigned int count;
+ unsigned int *gpios;
+ int len;
+ int i,j;
+ char valbuf;
+ int default_level=1;
+ char *default_edge="both";
+ struct timespec spec;
+ int s,ms;
+
+ int ch;
+
+ while (-1 != (ch = getopt(argc, argv, OPTSTRING))) {
+ switch (ch) {
+ case 'e':
+ default_edge=strdup(optarg);
+ if ( ! ((0 == strncmp(default_edge,"rising",8)) ||
+ (0 == strncmp(default_edge,"falling",8)) ||
+ (0 == strncmp(default_edge,"both",8)))
+ )
+ {
+ fprintf(stderr, "error: invalid edge value: %s\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'l':
+ if ( 0 == strncmp(optarg,"low",8) ) {
+ default_level=1;
+ } else if ( 0 == strncmp(optarg,"high",8) ) {
+ default_level=0;
+ } else {
+ fprintf(stderr, "error: invalid level value: %s\n", optarg);
+ exit(1);
+ }
+ break;
+ case '?':
+ printf("Usage: gpio-int [-l level] [-e edge ] <gpio-pin...>\n\n");
+ printf("Waits for a change in the GPIO pins voltage level\n");
+ exit(2);
+ }
+ }
+
+ count=argc-optind;
+
+ gpios = malloc(count*sizeof(unsigned int));
+ fdset = malloc(count*sizeof(fdset[0]));
+
+ j=0;
+ for (i=optind;i<argc;i++) {
+ gpio = atoi(argv[i]);
+ gpio_unexport(gpio);
+ gpio_export(gpio);
+ gpio_set_dir(gpio, 0);
+ gpio_set_edge(gpio, default_edge);
+ gpio_set_level(gpio, default_level);
+ fdset[j].fd = gpio_fd_open(gpio);
+ fdset[j].events = POLLPRI;
+ gpios[j] = gpio;
+ j++;
+ }
+
+ timeout = POLL_TIMEOUT;
+
+ while (1) {
+
+ rc = poll(fdset, count, timeout);
+
+ if (rc < 0) {
+ printf("\npoll() failed!\n");
+ break;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &spec);
+ for (i=0;i<count;i++) {
+ if (fdset[i].revents & POLLPRI) {
+ lseek(fdset[i].fd, 0, SEEK_SET);
+ len = read(fdset[i].fd, buf, MAX_BUF);
+ valbuf = buf[0];
+ s=spec.tv_sec;
+ ms = spec.tv_nsec / 1.0e6;
+ printf("%d %c %d.%03d\n", gpios[i], valbuf, s, ms);
+ }
+ }
+
+ fflush(stdout);
+ }
+
+ for (i=0;i<count;i++) {
+ gpio_fd_close(fdset[i].fd);
+ }
+ return 0;