1
0
mirror of https://github.com/xtacocorex/CHIP_IO synced 2025-07-20 04:43:21 +00:00

Fixed a bunch of error handling

This commit is contained in:
fordsfords
2016-07-04 13:56:11 -05:00
parent fd29b17796
commit 0e7d03c472
11 changed files with 787 additions and 309 deletions

View File

@ -42,6 +42,7 @@ SOFTWARE.
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "event_gpio.h"
#include "common.h"
@ -52,7 +53,7 @@ const char *stredge[4] = {"none", "rising", "falling", "both"};
struct fdx
{
int fd;
unsigned int gpio;
int gpio;
int initial;
unsigned int is_evented;
struct fdx *next;
@ -62,8 +63,8 @@ struct fdx *fd_list = NULL;
// event callbacks
struct callback
{
unsigned int gpio;
void (*func)(unsigned int gpio);
int gpio;
void (*func)(int gpio);
struct callback *next;
};
struct callback *callbacks = NULL;
@ -71,38 +72,47 @@ struct callback *callbacks = NULL;
// gpio exports
struct gpio_exp
{
unsigned int gpio;
int gpio;
struct gpio_exp *next;
};
struct gpio_exp *exported_gpios = NULL;
pthread_t threads;
void *event_occurred = NULL;
dyn_int_array_t *event_occurred = NULL;
int thread_running = 0;
int epfd = -1;
int gpio_export(unsigned int gpio)
int gpio_export(int gpio)
{
int fd, len;
char str_gpio[16];
int fd, len, e_no;
char filename[MAX_FILENAME];
char str_gpio[80];
struct gpio_exp *new_gpio, *g;
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
snprintf(filename, sizeof(filename), "/sys/class/gpio/export"); BUF2SMALL(filename);
if ((fd = open(filename, O_WRONLY)) < 0)
{
char err[80];
snprintf(err, sizeof(err), "gpio_export: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
ssize_t s = write(fd, str_gpio, len);
ssize_t s = write(fd, str_gpio, len); e_no = errno;
close(fd);
if (s != len)
{
char err[80];
snprintf(err, sizeof(err), "gpio_export: could not write '%s' to %s (%s)", str_gpio, filename, strerror(e_no));
add_error_msg(err);
return -1;
}
// add to list
new_gpio = malloc(sizeof(struct gpio_exp));
if (new_gpio == 0)
return -1; // out of memory
new_gpio = malloc(sizeof(struct gpio_exp)); ASSRT(new_gpio != NULL);
new_gpio->gpio = gpio;
new_gpio->next = NULL;
@ -118,10 +128,12 @@ int gpio_export(unsigned int gpio)
g = g->next;
g->next = new_gpio;
}
return 0;
}
void close_value_fd(unsigned int gpio)
return 0;
} /* gpio_export */
void close_value_fd(int gpio)
{
struct fdx *f = fd_list;
struct fdx *temp;
@ -144,9 +156,10 @@ void close_value_fd(unsigned int gpio)
f = f->next;
}
}
}
} /* close_value_fd */
int fd_lookup(unsigned int gpio)
int fd_lookup(int gpio)
{
struct fdx *f = fd_list;
while (f != NULL)
@ -155,16 +168,16 @@ int fd_lookup(unsigned int gpio)
return f->fd;
f = f->next;
}
return 0;
}
int add_fd_list(unsigned int gpio, int fd)
int add_fd_list(int gpio, int fd)
{
struct fdx *new_fd;
new_fd = malloc(sizeof(struct fdx));
if (new_fd == 0)
return -1; // out of memory
new_fd = malloc(sizeof(struct fdx)); ASSRT(new_fd != NULL);
new_fd->fd = fd;
new_fd->gpio = gpio;
@ -176,10 +189,11 @@ int add_fd_list(unsigned int gpio, int fd)
new_fd->next = fd_list;
}
fd_list = new_fd;
return 0;
}
int open_value_file(unsigned int gpio)
int open_value_file(int gpio)
{
int fd;
char filename[MAX_FILENAME];
@ -188,26 +202,44 @@ int open_value_file(unsigned int gpio)
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
char err[80];
snprintf(err, sizeof(err), "open_value_file: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
add_fd_list(gpio, fd);
return fd;
}
int gpio_unexport(unsigned int gpio)
return fd;
} /* open_value_file */
int gpio_unexport(int gpio)
{
int fd, len;
int fd, len, e_no;
char filename[MAX_FILENAME];
char str_gpio[16];
struct gpio_exp *g, *temp, *prev_g = NULL;
close_value_fd(gpio);
if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
snprintf(filename, sizeof(filename), "/sys/class/gpio/unexport"); BUF2SMALL(filename);
if ((fd = open(filename, O_WRONLY)) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_unexport: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
ssize_t s = write(fd, str_gpio, len); ASSRT(s == len);
ssize_t s = write(fd, str_gpio, len); e_no = errno;
close(fd);
if (s != len) {
char err[80];
snprintf(err, sizeof(err), "gpio_unexport: could not write '%s' (%s)", filename, strerror(e_no));
add_error_msg(err);
return -1;
}
// remove from list
g = exported_gpios;
@ -227,61 +259,100 @@ int gpio_unexport(unsigned int gpio)
g = g->next;
}
}
return 0;
return 0;
}
int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
int gpio_set_direction(int gpio, unsigned int in_flag)
{
int fd;
char filename[MAX_FILENAME];
char direction[16] = { 0 };
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_WRONLY)) < 0)
return -1;
if (in_flag) {
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
} else {
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
}
ssize_t s = write(fd, direction, strlen(direction)); ASSRT(s == strlen(direction));
close(fd);
return 0;
}
int gpio_get_direction(unsigned int gpio, unsigned int *value)
{
int fd;
char direction[4] = { 0 };
char filename[MAX_FILENAME];
int fd, e_no;
char filename[MAX_FILENAME]; filename[0] = '\0';
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
if ((fd = open(filename, O_WRONLY)) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_direction: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
lseek(fd, 0, SEEK_SET);
ssize_t s = read(fd, &direction, sizeof(direction) - 1); ASSRT(s > 0);
if (strcmp(direction, "out") == 0) {
*value = OUTPUT;
char direction[16];
if (in_flag) {
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
} else {
*value = INPUT;
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
}
ssize_t s = write(fd, direction, strlen(direction)); e_no = errno;
close(fd);
if (s != strlen(direction)) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_direction: could not write '%s' (%s)", filename, strerror(e_no));
add_error_msg(err);
return -1;
}
return 0;
}
int gpio_set_value(unsigned int gpio, unsigned int value)
int gpio_get_direction(int gpio, unsigned int *value)
{
int fd;
int fd, e_no;
char filename[MAX_FILENAME];
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_get_direction: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
if (lseek(fd, 0, SEEK_SET) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_get_direction: could not seek GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return -1;
}
char direction[4] = { 0 }; /* make sure read is null-terminated */
ssize_t s = read(fd, &direction, sizeof(direction) - 1); e_no = errno;
close(fd);
if (s < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_direction: could not read '%s' (%s)", filename, strerror(e_no));
add_error_msg(err);
return -1;
}
if (strcmp(direction, "out") == 0)
*value = OUTPUT;
else if (strcmp(direction, "in") == 0)
*value = INPUT;
else {
char err[80];
snprintf(err, sizeof(err), "gpio_set_direction: unexpected '%s' found in %s", direction, filename);
add_error_msg(err);
return -1;
}
return 0;
} /* gpio_set_direction */
int gpio_set_value(int gpio, unsigned int value)
{
int fd, e_no;
char filename[MAX_FILENAME];
char vstr[16];
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_WRONLY)) < 0)
if ((fd = open(filename, O_WRONLY)) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_value: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
if (value) {
strncpy(vstr, "1", ARRAY_SIZE(vstr) - 1);
@ -289,53 +360,89 @@ int gpio_set_value(unsigned int gpio, unsigned int value)
strncpy(vstr, "0", ARRAY_SIZE(vstr) - 1);
}
ssize_t s = write(fd, vstr, strlen(vstr));
ssize_t s = write(fd, vstr, strlen(vstr)); e_no = errno;
close(fd);
if (s != strlen(vstr))
if (s != strlen(vstr)) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_value: could not write '%s' to %s (%s)", vstr, filename, strerror(e_no));
add_error_msg(err);
return -2;
}
return 0;
}
int gpio_get_value(unsigned int gpio, unsigned int *value)
int gpio_get_value(int gpio, unsigned int *value)
{
int fd = fd_lookup(gpio);
char ch;
if (!fd)
{
if ((fd = open_value_file(gpio)) == -1)
if ((fd = open_value_file(gpio)) == -1) {
char err[80];
snprintf(err, sizeof(err), "gpio_get_value: could not open GPIO %d value file", gpio);
add_error_msg(err);
return -1;
}
}
lseek(fd, 0, SEEK_SET);
ssize_t s = read(fd, &ch, sizeof(ch)); ASSRT(s > 0);
if (lseek(fd, 0, SEEK_SET) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_get_value: could not seek GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return -1;
}
ssize_t s = read(fd, &ch, sizeof(ch));
if (s < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_get_value: could not read GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return -1;
}
if (ch != '0') {
if (ch == '1') {
*value = 1;
} else {
} else if (ch == '0') {
*value = 0;
} else {
char err[80];
snprintf(err, sizeof(err), "gpio_get_value: unrecognized read GPIO %d (%c)", gpio, ch);
add_error_msg(err);
return -1;
}
return 0;
}
int gpio_set_edge(unsigned int gpio, unsigned int edge)
int gpio_set_edge(int gpio, unsigned int edge)
{
int fd;
char filename[MAX_FILENAME];
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_WRONLY)) < 0)
return -1;
if ((fd = open(filename, O_WRONLY)) < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_edge: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
ssize_t s = write(fd, stredge[edge], strlen(stredge[edge]) + 1); ASSRT(s == strlen(stredge[edge]) + 1);
ssize_t s = write(fd, stredge[edge], strlen(stredge[edge]) + 1);
if (s < 0) {
char err[80];
snprintf(err, sizeof(err), "gpio_set_edge: could not write '%s' to %s (%s)", stredge[edge], filename, strerror(errno));
add_error_msg(err);
return -1;
}
close(fd);
return 0;
}
unsigned int gpio_lookup(int fd)
int gpio_lookup(int fd)
{
struct fdx *f = fd_list;
while (f != NULL)
@ -344,7 +451,8 @@ unsigned int gpio_lookup(int fd)
return f->gpio;
f = f->next;
}
return 0;
return -1;
}
void exports_cleanup(void)
@ -354,14 +462,12 @@ void exports_cleanup(void)
gpio_unexport(exported_gpios->gpio);
}
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
int add_edge_callback(int gpio, void (*func)(int gpio))
{
struct callback *cb = callbacks;
struct callback *new_cb;
new_cb = malloc(sizeof(struct callback));
if (new_cb == 0)
return -1; // out of memory
new_cb = malloc(sizeof(struct callback)); ASSRT(new_cb != NULL);
new_cb->gpio = gpio;
new_cb->func = func;
@ -379,7 +485,7 @@ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
return 0;
}
void run_callbacks(unsigned int gpio)
void run_callbacks(int gpio)
{
struct callback *cb = callbacks;
while (cb != NULL)
@ -390,7 +496,7 @@ void run_callbacks(unsigned int gpio)
}
}
void remove_callbacks(unsigned int gpio)
void remove_callbacks(int gpio)
{
struct callback *cb = callbacks;
struct callback *temp;
@ -414,7 +520,7 @@ void remove_callbacks(unsigned int gpio)
}
}
void set_initial_false(unsigned int gpio)
void set_initial_false(int gpio)
{
struct fdx *f = fd_list;
@ -426,7 +532,7 @@ void set_initial_false(unsigned int gpio)
}
}
int gpio_initial(unsigned int gpio)
int gpio_initial(int gpio)
{
struct fdx *f = fd_list;
@ -443,7 +549,7 @@ void *poll_thread(void *threadarg)
{
struct epoll_event events;
char buf;
unsigned int gpio;
int gpio;
int n;
thread_running = 1;
@ -475,7 +581,7 @@ void *poll_thread(void *threadarg)
pthread_exit(NULL);
}
int gpio_is_evented(unsigned int gpio)
int gpio_is_evented(int gpio)
{
struct fdx *f = fd_list;
while (f != NULL)
@ -487,7 +593,7 @@ int gpio_is_evented(unsigned int gpio)
return 0;
}
int gpio_event_add(unsigned int gpio)
int gpio_event_add(int gpio)
{
struct fdx *f = fd_list;
while (f != NULL)
@ -505,7 +611,7 @@ int gpio_event_add(unsigned int gpio)
return 0;
}
int gpio_event_remove(unsigned int gpio)
int gpio_event_remove(int gpio)
{
struct fdx *f = fd_list;
while (f != NULL)
@ -521,7 +627,7 @@ int gpio_event_remove(unsigned int gpio)
}
// add_edge_detect assumes the caller has ensured the GPIO is already exported.
int add_edge_detect(unsigned int gpio, unsigned int edge)
int add_edge_detect(int gpio, unsigned int edge)
// return values:
// 0 - Success
// 1 - Edge detection already added
@ -537,18 +643,34 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
return 1;
// export /sys/class/gpio interface
gpio_set_direction(gpio, 0); // 0=input
gpio_set_edge(gpio, edge);
if (gpio_set_direction(gpio, 0) < 0) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not set direction for GPIO %d", gpio);
add_error_msg(err);
return 2;
}
if (gpio_set_edge(gpio, edge) < 0) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not set edge for GPIO %d", gpio);
add_error_msg(err);
return 2;
}
if (!fd)
{
if ((fd = open_value_file(gpio)) == -1) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not open GPIO %d value file", gpio);
add_error_msg(err);
return 2;
}
}
// create epfd if not already open
if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not epoll_create GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return 2;
}
@ -556,6 +678,9 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
ev.data.fd = fd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not epoll_ctl GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return 2;
}
@ -563,14 +688,18 @@ int add_edge_detect(unsigned int gpio, unsigned int edge)
if (!thread_running)
{
if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) {
char err[80];
snprintf(err, sizeof(err), "add_edge_detect: could not pthread_create GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return 2;
}
}
return 0;
}
} /* add_edge_detect */
void remove_edge_detect(unsigned int gpio)
void remove_edge_detect(int gpio)
{
struct epoll_event ev;
int fd = fd_lookup(gpio);
@ -591,7 +720,8 @@ void remove_edge_detect(unsigned int gpio)
dyn_int_array_set(&event_occurred, gpio, 0, 0);
}
int event_detected(unsigned int gpio)
int event_detected(int gpio)
{
if (dyn_int_array_get(&event_occurred, gpio, 0)) {
dyn_int_array_set(&event_occurred, gpio, 0, 0);
@ -608,7 +738,8 @@ void event_cleanup(void)
exports_cleanup();
}
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
// blocking_wait_for_edge assumes the caller has ensured the GPIO is already exported.
int blocking_wait_for_edge(int gpio, unsigned int edge)
// standalone from all the event functions above
{
int fd = fd_lookup(gpio);
@ -616,22 +747,33 @@ int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
struct epoll_event events, ev;
char buf;
if ((epfd = epoll_create(1)) == -1)
if ((epfd = epoll_create(1)) == -1) {
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not epoll_create GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return 1;
}
// check to see if this gpio has been added already, if not, mark as added
if (gpio_event_add(gpio) != 0)
if (gpio_event_add(gpio) != 0) {
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not add event for GPIO %d", gpio);
add_error_msg(err);
return 2;
}
// export /sys/class/gpio interface
gpio_export(gpio); // ignore errors
gpio_set_direction(gpio, 0); // 0=input
gpio_set_edge(gpio, edge);
if (!fd)
{
if ((fd = open_value_file(gpio)) == -1)
if ((fd = open_value_file(gpio)) == -1) {
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not open GPIO %d value file", gpio);
add_error_msg(err);
return 3;
}
}
// add to epoll fd
@ -639,28 +781,45 @@ int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
ev.data.fd = fd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
{
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not epoll_ctl GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
gpio_event_remove(gpio);
return 4;
}
// epoll for event
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
{
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
{
gpio_event_remove(gpio);
return 5;
}
}
if (n > 0)
{
lseek(events.data.fd, 0, SEEK_SET);
if (lseek(events.data.fd, 0, SEEK_SET) < 0)
{
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not seek GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return 6;
}
if (read(events.data.fd, &buf, sizeof(buf)) != 1)
{
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: could not read GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
gpio_event_remove(gpio);
return 6;
}
if (events.data.fd != fd)
{
char err[80];
snprintf(err, sizeof(err), "blocking_wait_for_edge: events.data.fd (%d) not equal to fd (%d) for GPIO %d", events.data.fd, fd, gpio);
add_error_msg(err);
gpio_event_remove(gpio);
return 7;
}