text: /* Copyright (c) 2011, RidgeRun
   * Copyright (c) 2014, Bernd Porr
   * 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.
   * 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 "gpio-sysfs.h"
  
  /****************************************************************
   * Constants
   ****************************************************************/
   
  #define SYSFS_GPIO_DIR "/sys/class/gpio"
  
  
  const char* gpio_sysfs_version() {
    return "1.0.0\n";
  }
  
  /****************************************************************
   * 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;
    char buf[MAX_BUF];
   
    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;
    char buf[MAX_BUF];
   
    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;
    char buf[MAX_BUF];
    char ch;
  
    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, const char *edge)
  {
    int fd;
    char buf[MAX_BUF];
  
    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;
  }
  
  /****************************************************************
   * gpio_fd_open
   ****************************************************************/
  
  int gpio_fd_open(unsigned int gpio)
  {
    int fd;
    char buf[MAX_BUF];
  
    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);
  }
  
  
  /****************************************************************
   * gpio_poll
  ****************************************************************/
  
  int gpio_poll(int gpio_fd, int timeout)
  {
    struct pollfd fdset[1];
    int nfds = 1;
    int rc;
    char buf[MAX_BUF];
  
    memset((void*)fdset, 0, sizeof(fdset));
  
    fdset[0].fd = gpio_fd;
    fdset[0].events = POLLPRI;
  
    rc = poll(fdset, nfds, timeout);
  
    if (fdset[0].revents & POLLPRI) {
      // dummy read
      read(fdset[0].fd, buf, MAX_BUF);
    }
  
    return rc;
  }