meta-digi/meta-digi-dey/recipes-digi/dey-examples/files/gpio_sysfs_test/sysfsgpio.c

352 lines
5.7 KiB
C

/*
* sysfsgpio.c
*
* Copyright (C) 2011 by Digi International Inc.
* All rights reserved.
*
* 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.
*
* Description: GPIO SYSFS API library.
*
*/
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "sysfsgpio.h"
int sysfs_gpio_export(int gpio)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
if (fd < 0) {
perror("Error on GPIO export\n");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
int sysfs_gpio_unexport(int gpio)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
if (fd < 0) {
perror("Error on GPIO unexport");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
int sysfs_gpio_set_direction(int gpio, unsigned int out)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("Error setting GPIO direction\n");
return fd;
}
if (out)
write(fd, "out", 4);
else
write(fd, "in", 3);
close(fd);
return 0;
}
int sysfs_gpio_get_direction(int gpio, char * dir, int len)
{
int fd, length;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
length = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction",
gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("Error getting GPIO direction\n");
return fd;
}
memset(dir,0,len);
read(fd, dir, len);
dir[strlen(dir) - 1] = '\0';
if (strcmp(dir, "out") && strcmp(dir, "in")) {
perror("Error getting direction\n");
}
close(fd);
return 0;
}
int sysfs_gpio_set_active_low(int gpio, unsigned int low)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("Error setting GPIO value\n");
return fd;
}
snprintf(buf, sizeof(buf), "%s", low ? "1" : "0");
write(fd, buf, 2);
close(fd);
return 0;
}
int sysfs_gpio_get_active_low(int gpio, unsigned int *value)
{
int fd, len;
char buf[MAX_LEN];
char ch;
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("Error getting GPIO value\n");
return fd;
}
read(fd, &ch, 1);
if (ch != '0') {
*value = 1;
}
else {
*value = 0;
}
close(fd);
return 0;
}
int sysfs_gpio_set_value(int gpio, unsigned int value)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("Error setting GPIO value\n");
return fd;
}
snprintf(buf, sizeof(buf), "%s", value ? "1" : "0");
write(fd, buf, 2);
close(fd);
return 0;
}
int sysfs_gpio_get_value(int gpio, unsigned int *value)
{
int fd, len;
char buf[MAX_LEN];
char ch;
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("Error getting GPIO value\n");
return fd;
}
read(fd, &ch, 1);
if (ch != '0') {
*value = 1;
}
else {
*value = 0;
}
close(fd);
return 0;
}
static int sysfs_gpio_fset_value(int fd, unsigned int value)
{
char buf[MAX_LEN];
snprintf(buf, sizeof(buf), "%s", value ? "1" : "0");
write(fd, buf, 2);
return fd;
}
static int sysfs_gpio_fget_value(int fd, unsigned int *value)
{
char buf;
read(fd, &buf, sizeof(char));
if (buf != '0') {
*value = 1;
}
else {
*value = 0;
}
return fd;
}
int sysfs_gpio_set_edge(int gpio, char *edge)
{
int fd, len;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("Error setting GPIO edge\n");
return fd;
}
write(fd, edge, strlen(edge) + 1);
close(fd);
return 0;
}
int sysfs_gpio_get_edge(int gpio, char *edge, int len)
{
int fd, length;
char buf[MAX_LEN];
if( gpio < 0 )
return 0;
length = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("Error setting GPIO edge\n");
return fd;
}
memset(edge,0,len);
read(fd, edge, len);
//Remove trailing newline
edge[strlen(edge) - 1] = '\0';
close(fd);
return 0;
}
int sysfs_gpio_poll(int gpio, unsigned int timeout)
{
int fd, len;
char buf[MAX_LEN];
struct pollfd pfd;
int ret = 0;
unsigned int inval;
if( gpio < 0 )
return 0;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("Error on GPIO open\n");
ret = -1;
goto error;
}
/* Edge triggers are relative to the last read by the application
* and not to the start of poll. Read here to avoid poll returning
* immediately.*/
read(fd, &buf, sizeof(char));
memset((void*) &pfd, 0, sizeof(pfd));
pfd.fd = fd;
pfd.events = POLLPRI;
ret = poll(&pfd, 1, timeout);
if (ret > 0) {
if (pfd.revents & POLLNVAL) {
printf("Return error event %x\n", pfd.revents);
ret = -1;
}
else if ((pfd.revents & POLLPRI)) {
sysfs_gpio_fget_value(fd, &inval);
}
else {
printf("Unhandled event %x\n", pfd.revents);
ret = -1;
}
}
else if (ret == 0) {
printf("Timeout on poll\n");
}
else {
perror("Error on poll\n");
ret = -1;
;
}
close(fd);
error: return ret;
}