1
0
mirror of https://github.com/xtacocorex/CHIP_IO synced 2025-07-20 12:53:22 +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

@ -145,7 +145,7 @@ int softpwm_set_duty_cycle(const char *key, float duty) {;
void *softpwm_thread_toggle(void *key) void *softpwm_thread_toggle(void *key)
{ {
struct softpwm *pwm; struct softpwm *pwm;
unsigned int gpio; int gpio;
struct timespec tim_on; struct timespec tim_on;
struct timespec tim_off; struct timespec tim_off;
unsigned int sec; unsigned int sec;
@ -237,7 +237,7 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
struct softpwm *new_pwm, *pwm; struct softpwm *new_pwm, *pwm;
pthread_t new_thread; pthread_t new_thread;
pthread_mutex_t *new_params_lock; pthread_mutex_t *new_params_lock;
unsigned int gpio; int gpio;
int ret; int ret;
get_gpio_number(key, &gpio); get_gpio_number(key, &gpio);
@ -296,7 +296,7 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
int softpwm_disable(const char *key) int softpwm_disable(const char *key)
{ {
struct softpwm *pwm, *temp, *prev_pwm = NULL; struct softpwm *pwm, *temp, *prev_pwm = NULL;
unsigned int gpio = 0; int gpio = 0;
// remove from list // remove from list
pwm = exported_pwms; pwm = exported_pwms;

View File

@ -42,6 +42,7 @@ SOFTWARE.
#include "common.h" #include "common.h"
#include <stdio.h> #include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdlib.h> #include <stdlib.h>
@ -49,24 +50,25 @@ SOFTWARE.
int setup_error = 0; int setup_error = 0;
int module_setup = 0; int module_setup = 0;
// I have no idea if this table is correct, we shall see - Robert Wolterman // I have no idea if this table is correct, we shall see - Robert Wolterman
pins_t pins_info[] = { pins_t pins_info[] = {
{ "GND", "U13_1", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U13_1", -1, BASE_METHOD_AS_IS, -1, -1},
{ "CHG-IN", "U13_2", 0, BASE_METHOD_AS_IS, -1, -1}, { "CHG-IN", "U13_2", -1, BASE_METHOD_AS_IS, -1, -1},
{ "VCC-5V", "U13_3", 0, BASE_METHOD_AS_IS, -1, -1}, { "VCC-5V", "U13_3", -1, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U13_4", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U13_4", -1, BASE_METHOD_AS_IS, -1, -1},
{ "VCC-3V3", "U13_5", 0, BASE_METHOD_AS_IS, -1, -1}, { "VCC-3V3", "U13_5", -1, BASE_METHOD_AS_IS, -1, -1},
{ "TS", "U13_6", 0, BASE_METHOD_AS_IS, -1, -1}, { "TS", "U13_6", -1, BASE_METHOD_AS_IS, -1, -1},
{ "VCC-1V8", "U13_7", 0, BASE_METHOD_AS_IS, -1, -1}, { "VCC-1V8", "U13_7", -1, BASE_METHOD_AS_IS, -1, -1},
{ "BAT", "U13_8", 0, BASE_METHOD_AS_IS, -1, -1}, { "BAT", "U13_8", -1, BASE_METHOD_AS_IS, -1, -1},
{ "TWI1-SDA", "U13_9", 48, BASE_METHOD_AS_IS, -1, -1}, { "TWI1-SDA", "U13_9", 48, BASE_METHOD_AS_IS, -1, -1},
{ "PWRON", "U13_10", 0, BASE_METHOD_AS_IS, -1, -1}, { "PWRON", "U13_10", -1, BASE_METHOD_AS_IS, -1, -1},
{ "TWI1-SCK", "U13_11", 47, BASE_METHOD_AS_IS, -1, -1}, { "TWI1-SCK", "U13_11", 47, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U13_12", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U13_12", -1, BASE_METHOD_AS_IS, -1, -1},
{ "X1", "U13_13", 0, BASE_METHOD_AS_IS, -1, -1}, { "X1", "U13_13", -1, BASE_METHOD_AS_IS, -1, -1},
{ "X2", "U13_14", 0, BASE_METHOD_AS_IS, -1, -1}, { "X2", "U13_14", -1, BASE_METHOD_AS_IS, -1, -1},
{ "Y1", "U13_15", 0, BASE_METHOD_AS_IS, -1, -1}, { "Y1", "U13_15", -1, BASE_METHOD_AS_IS, -1, -1},
{ "Y2", "U13_16", 0, BASE_METHOD_AS_IS, -1, -1}, { "Y2", "U13_16", -1, BASE_METHOD_AS_IS, -1, -1},
{ "LCD-D2", "U13_17", 98, BASE_METHOD_AS_IS, -1, -1}, { "LCD-D2", "U13_17", 98, BASE_METHOD_AS_IS, -1, -1},
{ "PWM0", "U13_18", 34, BASE_METHOD_AS_IS, 0, -1}, { "PWM0", "U13_18", 34, BASE_METHOD_AS_IS, 0, -1},
{ "LCD-D4", "U13_19", 100, BASE_METHOD_AS_IS, -1, -1}, { "LCD-D4", "U13_19", 100, BASE_METHOD_AS_IS, -1, -1},
@ -89,20 +91,20 @@ pins_t pins_info[] = {
{ "LCD-D23", "U13_36", 119, BASE_METHOD_AS_IS, -1, -1}, { "LCD-D23", "U13_36", 119, BASE_METHOD_AS_IS, -1, -1},
{ "LCD-VSYNC", "U13_37", 123, BASE_METHOD_AS_IS, -1, -1}, { "LCD-VSYNC", "U13_37", 123, BASE_METHOD_AS_IS, -1, -1},
{ "LCD-HSYNC", "U13_38", 122, BASE_METHOD_AS_IS, -1, -1}, { "LCD-HSYNC", "U13_38", 122, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U13_39", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U13_39", -1, BASE_METHOD_AS_IS, -1, -1},
{ "LCD-DE", "U13_40", 121, BASE_METHOD_AS_IS, -1, -1}, { "LCD-DE", "U13_40", 121, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U14_1", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_1", -1, BASE_METHOD_AS_IS, -1, -1},
{ "VCC-5V", "U14_2", 0, BASE_METHOD_AS_IS, -1, -1}, { "VCC-5V", "U14_2", -1, BASE_METHOD_AS_IS, -1, -1},
{ "UART1-TX", "U14_3", 195, BASE_METHOD_AS_IS, -1, -1}, { "UART1-TX", "U14_3", 195, BASE_METHOD_AS_IS, -1, -1},
{ "HPL", "U14_4", 0, BASE_METHOD_AS_IS, -1, -1}, { "HPL", "U14_4", -1, BASE_METHOD_AS_IS, -1, -1},
{ "UART1-RX", "U14_5", 196, BASE_METHOD_AS_IS, -1, -1}, { "UART1-RX", "U14_5", 196, BASE_METHOD_AS_IS, -1, -1},
{ "HPCOM", "U14_6", 0, BASE_METHOD_AS_IS, -1, -1}, { "HPCOM", "U14_6", -1, BASE_METHOD_AS_IS, -1, -1},
{ "FEL", "U14_7", 0, BASE_METHOD_AS_IS, -1, -1}, { "FEL", "U14_7", -1, BASE_METHOD_AS_IS, -1, -1},
{ "HPR", "U14_8", 0, BASE_METHOD_AS_IS, -1, -1}, { "HPR", "U14_8", -1, BASE_METHOD_AS_IS, -1, -1},
{ "VCC-3V3", "U14_9", 0, BASE_METHOD_AS_IS, -1, -1}, { "VCC-3V3", "U14_9", -1, BASE_METHOD_AS_IS, -1, -1},
{ "MICM", "U14_10", 0, BASE_METHOD_AS_IS, -1, -1}, { "MICM", "U14_10", -1, BASE_METHOD_AS_IS, -1, -1},
{ "LRADC", "U14_11", 0, BASE_METHOD_AS_IS, -1, 0}, { "LRADC", "U14_11", -1, BASE_METHOD_AS_IS, -1, 0},
{ "MICIN1", "U14_12", 0, BASE_METHOD_AS_IS, -1, -1}, { "MICIN1", "U14_12", -1, BASE_METHOD_AS_IS, -1, -1},
{ "XIO-P0", "U14_13", 0, BASE_METHOD_XIO, -1, -1}, { "XIO-P0", "U14_13", 0, BASE_METHOD_XIO, -1, -1},
{ "XIO-P1", "U14_14", 1, BASE_METHOD_XIO, -1, -1}, { "XIO-P1", "U14_14", 1, BASE_METHOD_XIO, -1, -1},
{ "XIO-P2", "U14_15", 2, BASE_METHOD_XIO, -1, -1}, { "XIO-P2", "U14_15", 2, BASE_METHOD_XIO, -1, -1},
@ -111,8 +113,8 @@ pins_t pins_info[] = {
{ "XIO-P5", "U14_18", 5, BASE_METHOD_XIO, -1, -1}, { "XIO-P5", "U14_18", 5, BASE_METHOD_XIO, -1, -1},
{ "XIO-P6", "U14_19", 6, BASE_METHOD_XIO, -1, -1}, { "XIO-P6", "U14_19", 6, BASE_METHOD_XIO, -1, -1},
{ "XIO-P7", "U14_20", 7, BASE_METHOD_XIO, -1, -1}, { "XIO-P7", "U14_20", 7, BASE_METHOD_XIO, -1, -1},
{ "GND", "U14_21", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_21", -1, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U14_22", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_22", -1, BASE_METHOD_AS_IS, -1, -1},
{ "AP-EINT1", "U14_23", 193, BASE_METHOD_AS_IS, -1, -1}, { "AP-EINT1", "U14_23", 193, BASE_METHOD_AS_IS, -1, -1},
{ "AP-EINT3", "U14_24", 35, BASE_METHOD_AS_IS, -1, -1}, { "AP-EINT3", "U14_24", 35, BASE_METHOD_AS_IS, -1, -1},
{ "TWI2-SDA", "U14_25", 50, BASE_METHOD_AS_IS, -1, -1}, { "TWI2-SDA", "U14_25", 50, BASE_METHOD_AS_IS, -1, -1},
@ -129,9 +131,9 @@ pins_t pins_info[] = {
{ "CSID5", "U14_36", 137, BASE_METHOD_AS_IS, -1, -1}, { "CSID5", "U14_36", 137, BASE_METHOD_AS_IS, -1, -1},
{ "CSID6", "U14_37", 138, BASE_METHOD_AS_IS, -1, -1}, { "CSID6", "U14_37", 138, BASE_METHOD_AS_IS, -1, -1},
{ "CSID7", "U14_38", 139, BASE_METHOD_AS_IS, -1, -1}, { "CSID7", "U14_38", 139, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U14_39", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_39", -1, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U14_40", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_40", -1, BASE_METHOD_AS_IS, -1, -1},
{ NULL, NULL, 0, 0, -1, -1} { NULL, NULL, -1, 0, -1, -1}
}; };
@ -144,14 +146,14 @@ pins_t pins_info[] = {
// http://stackoverflow.com/questions/612097/how-can-i-get-the-list-of-files-in-a-directory-using-c-or-c // http://stackoverflow.com/questions/612097/how-can-i-get-the-list-of-files-in-a-directory-using-c-or-c
#define GPIO_PATH "/sys/class/gpio" #define GPIO_PATH "/sys/class/gpio"
#define EXPANDER "pcf8574a\n" #define EXPANDER "pcf8574a\n"
int num_get_xio_base = 0; /* for self-test purposes */
/* returns -1 for error */
int get_xio_base(void) int get_xio_base(void)
{ {
char label_file[FILENAME_BUFFER_SIZE]; char label_file[FILENAME_BUFFER_SIZE];
FILE *label_fp; FILE *label_fp;
char base_file[FILENAME_BUFFER_SIZE]; char base_file[FILENAME_BUFFER_SIZE];
FILE *base_fp; FILE *base_fp;
char input_line[80];
// Makes use of static variable xio_base_address to maintain state between // Makes use of static variable xio_base_address to maintain state between
// calls. First time this is called, xio_base_address is -1, so the actual // calls. First time this is called, xio_base_address is -1, so the actual
// base address is calculated and stored in xio_base_address. Subsequent // base address is calculated and stored in xio_base_address. Subsequent
@ -162,33 +164,55 @@ int get_xio_base(void)
struct dirent *ent; struct dirent *ent;
struct stat sbuf; struct stat sbuf;
if (xio_base_address == -1 && (dir = opendir (GPIO_PATH)) != NULL) { if (xio_base_address != -1)
return xio_base_address;
dir = opendir (GPIO_PATH);
if (dir == NULL) {
char err[256];
snprintf(err, sizeof(err), "get_xio_base: could not open '%s' (%s)", GPIO_PATH, strerror(errno));
add_error_msg(err);
return -1;
}
while (xio_base_address == -1 && (ent = readdir (dir)) != NULL) { while (xio_base_address == -1 && (ent = readdir (dir)) != NULL) {
lstat(ent->d_name,&sbuf); lstat(ent->d_name,&sbuf);
if (S_ISDIR(sbuf.st_mode)) { if (S_ISDIR(sbuf.st_mode)) {
if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) { if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) {
continue; /* skip "." and ".." entries */ continue; /* skip "." and ".." entries */
} }
snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file); snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file);
label_fp = fopen(label_file, "r"); label_fp = fopen(label_file, "r");
if (label_fp != NULL) { if (label_fp != NULL) {
char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line); ASSRT(s); char input_line[80]; input_line[0] = '\0';
char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line);
fclose(label_fp); fclose(label_fp);
if (strcmp(input_line, EXPANDER) == 0) { if (s != NULL && strcmp(input_line, EXPANDER) == 0) {
/* Found the expander, get the contents of base */ /* Found the expander, get the contents of base */
snprintf(base_file, sizeof(base_file), "%s/%s/base", GPIO_PATH, ent->d_name); BUF2SMALL(base_file); snprintf(base_file, sizeof(base_file), "%s/%s/base", GPIO_PATH, ent->d_name); BUF2SMALL(base_file);
base_fp = fopen(base_file, "r"); ASSRT(base_fp != NULL); base_fp = fopen(base_file, "r");
s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line); ASSRT(s); if (base_fp == NULL) {
char err[80];
snprintf(err, sizeof(err), "get_xio_base: could not open '%s' (%s)", base_file, strerror(errno));
add_error_msg(err);
break; /* error, exit loop */
}
s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line);
fclose(base_fp); fclose(base_fp);
if (s == NULL) {
char err[80];
snprintf(err, sizeof(err), "get_xio_base: could not read '%s' (%s)", base_file, strerror(errno));
add_error_msg(err);
break; /* error, exit loop */
}
/* Remember the value in the static local. */ /* Remember the value in the static local. */
xio_base_address = atoi(input_line); ASSRT(xio_base_address > 0); xio_base_address = atoi(input_line);
num_get_xio_base++; /* for self-test purposes */
} }
} /* if label file is open */ } /* if label file is open */
} /* if isdir */ } /* if isdir */
} /* while */ } /* while */
closedir (dir); closedir (dir);
}
return xio_base_address; return xio_base_address;
} /* get_xio_base */ } /* get_xio_base */
@ -197,6 +221,7 @@ int get_xio_base(void)
int gpio_number(pins_t *pin) int gpio_number(pins_t *pin)
{ {
int gpio_num = -1; int gpio_num = -1;
int xio_base;
switch (pin->base_method) { switch (pin->base_method) {
case BASE_METHOD_AS_IS: case BASE_METHOD_AS_IS:
@ -204,11 +229,16 @@ int gpio_number(pins_t *pin)
break; break;
case BASE_METHOD_XIO: case BASE_METHOD_XIO:
gpio_num = pin->gpio + get_xio_base(); xio_base = get_xio_base();
if (xio_base <= 0) {
char err[80]; snprintf(err, sizeof(err), "gpio_number: %d found for %s", xio_base, pin->name);
add_error_msg(err);
break; /* error, exit switch */
}
gpio_num = pin->gpio + xio_base;
break; break;
} }
ASSRT(gpio_num != -1);
return gpio_num; return gpio_num;
} /* gpio_number */ } /* gpio_number */
@ -221,7 +251,7 @@ int lookup_gpio_by_key(const char *key)
return gpio_number(p); return gpio_number(p);
} }
} }
return 0; return -1;
} }
int lookup_gpio_by_name(const char *name) int lookup_gpio_by_name(const char *name)
@ -232,7 +262,7 @@ int lookup_gpio_by_name(const char *name)
return gpio_number(p); return gpio_number(p);
} }
} }
return 0; return -1;
} }
int lookup_ain_by_key(const char *key) int lookup_ain_by_key(const char *key)
@ -325,15 +355,18 @@ int get_pwm_key_by_name(const char *name, char *key)
return 0; return 0;
} }
int get_gpio_number(const char *key, unsigned int *gpio) int get_gpio_number(const char *key, int *gpio)
{ {
int status = 0; /* assume success */
*gpio = lookup_gpio_by_key(key); *gpio = lookup_gpio_by_key(key);
if (!*gpio) { if (*gpio <= 0) {
*gpio = lookup_gpio_by_name(key); *gpio = lookup_gpio_by_name(key);
if (*gpio <= 0) {
status = -1; /* error */
} }
}
return 0; return status;
} }
int get_key(const char *input, char *key) int get_key(const char *input, char *key)
@ -421,73 +454,136 @@ int get_spi_bus_path_number(unsigned int spi)
} }
struct dyn_int_array { // We do not know at compile time how many GPIOs there are, so it is not safe
int num_elements; // to declare per-GPIO arrays with a static size. The "dyn_int_array_*"
int *array; // functions implement a dynamic integer array which grows as needed at run
}; // time. Users of a dynamic array do not access the array directly, but by
// access methods.
//
// To use, declare a dyn_int_array_t pointer initialized to NULL:
// dyn_int_array_t *my_per_gpio_array = NULL;
// If declared as a local to a function, consider making it "static":
// static dyn_int_array_t *my_per_gpio_array = NULL;
// The access methods must be passed a pointer to this pointer.
// Then when reading and writing to array elements, it is usually important
// to supply a "default value". This is so that as the array grows, the
// as-yet unused elements can be initialzied to a desired value.
// my_index = 100;
// dyn_int_array_set(&my_per_gpio_array, my_index, my_value, -1);
// This initializes elements 0-99 to -1, and element 100 to my_value. For
// efficiency purposes, it grows the array to half again larger than it needs
// to. Thus, elements 101-149 will be initialized to -1.
//
// If an element past the end of the array is read, the array is once again
// grown, with initialization:
// my_index = 500;
// int val = dyn_int_array_get(&my_per_gpio_array, my_index, -1);
// This grows the array to 749 (half again larger than 500) and initializes all
// the new elements to -1, including element 500, which is then returned.
void *dyn_int_array_create(int initial_num_elements, int initial_val) /* internal function; only called by access methods. */
dyn_int_array_t *dyn_int_array_create(int initial_num_elements, int initial_val)
{ {
struct dyn_int_array *new_array = (struct dyn_int_array *)malloc(sizeof(struct dyn_int_array)); dyn_int_array_t *new_array = (dyn_int_array_t *)malloc(sizeof(dyn_int_array_t));
ASSRT(new_array != NULL); ASSRT(new_array != NULL); /* out of memory */
new_array->num_elements = initial_num_elements; new_array->num_elements = initial_num_elements;
new_array->array = (int *)malloc(initial_num_elements * sizeof(int)); new_array->content = (int *)malloc(initial_num_elements * sizeof(int));
ASSRT(new_array->array != NULL); ASSRT(new_array->content != NULL); /* out of memory */
int i; int i;
for (i = 0; i < initial_num_elements; i++) for (i = 0; i < initial_num_elements; i++)
new_array->array[i] = initial_val; new_array->content[i] = initial_val;
return (void *)new_array; return new_array;
} /* dyn_int_array_create */ } /* dyn_int_array_create */
void dyn_int_array_set(void **in_array, int i, int val, int initial_val) void dyn_int_array_set(dyn_int_array_t **in_array, int i, int val, int initial_val)
{ {
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array); dyn_int_array_t *array = *in_array;
if (array == NULL) if (array == NULL) { /* if array hasn't been created yet */
array = dyn_int_array_create(i * 3 / 2, initial_val); array = dyn_int_array_create((i+1) * 3 / 2, initial_val);
*in_array = array;
}
if (i >= array->num_elements) { if (i >= array->num_elements) {
int new_num_elements = i * 3 / 2; /* half-again larger than current request */ int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */
array->array = realloc(array->array, new_num_elements * sizeof(int)); array->content = realloc(array->content, new_num_elements * sizeof(int));
ASSRT(array->array != NULL); ASSRT(array->content != NULL); /* out of memory */
// Zero out the newly allocated elements. // Zero out the newly allocated elements.
while (array->num_elements < new_num_elements) { while (array->num_elements < new_num_elements) {
array->array[array->num_elements] = initial_val; array->content[array->num_elements] = initial_val;
array->num_elements ++; array->num_elements ++;
} }
} }
array->array[i] = val; array->content[i] = val;
*in_array = (void *)array;
} /* dyn_int_array_set */ } /* dyn_int_array_set */
int dyn_int_array_get(void **in_array, int i, int initial_val) int dyn_int_array_get(dyn_int_array_t **in_array, int i, int initial_val)
{ {
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array); dyn_int_array_t *array = *in_array;
if (array == NULL) if (array == NULL) { /* if array hasn't been created yet */
array = dyn_int_array_create(i * 3 / 2, initial_val); array = dyn_int_array_create((i+1) * 3 / 2, initial_val);
*in_array = array;
}
if (i >= array->num_elements) { if (i >= array->num_elements) {
int new_num_elements = i * 3 / 2; /* half-again larger than current request */ int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */
array->array = realloc(array->array, new_num_elements * sizeof(int)); array->content = realloc(array->content, new_num_elements * sizeof(int));
ASSRT(array->array != NULL); ASSRT(array->content != NULL); /* out of memory */
// Zero out the newly allocated elements. // Zero out the newly allocated elements.
while (array->num_elements < new_num_elements) { while (array->num_elements < new_num_elements) {
array->array[array->num_elements] = initial_val; array->content[array->num_elements] = initial_val;
array->num_elements ++; array->num_elements ++;
} }
} }
return array->array[i]; return array->content[i];
*in_array = (void *)array;
} /* dyn_int_array_get */ } /* dyn_int_array_get */
void dyn_int_array_delete(void **in_array) void dyn_int_array_delete(dyn_int_array_t **in_array)
{ {
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array); dyn_int_array_t *array = *in_array;
free(array->array); free(array->content);
free(array); free(array);
} /* dyn_int_array_delete */ } /* dyn_int_array_delete */
char error_msg_buff[1024]; /* written to when an error must be returned */
void clear_error_msg(void)
{
error_msg_buff[0] = '\0';
}
char *get_error_msg(void)
{
return error_msg_buff;
}
void add_error_msg(char *msg)
{
int buff_len = strnlen(error_msg_buff, sizeof(error_msg_buff)); ASSRT(buff_len < sizeof(error_msg_buff));
int remaining = sizeof(error_msg_buff) - buff_len - 1; /* leave room for final null */
if (buff_len > 0 && remaining > 0) { /* include newline between messages */
error_msg_buff[buff_len] = '\n';
buff_len ++;
remaining --;
}
char *start = &error_msg_buff[buff_len]; /* points at null in the buffer */
int msg_len = strlen(msg);
if (msg_len >= remaining)
msg_len = remaining; /* don't overflow buffer; truncate message */
if (msg_len > 0)
memcpy(start, msg, msg_len);
start[msg_len] = '\0';
}

View File

@ -69,6 +69,14 @@ typedef struct pins_t {
int ain; int ain;
} pins_t; } pins_t;
struct dyn_int_array_s {
int num_elements;
int *content;
};
typedef struct dyn_int_array_s dyn_int_array_t;
#define FILENAME_BUFFER_SIZE 128 #define FILENAME_BUFFER_SIZE 128
int setup_error; int setup_error;
@ -84,12 +92,15 @@ int copy_key_by_key(const char *input_key, char *key);
int copy_pwm_key_by_key(const char *input_key, char *key); int copy_pwm_key_by_key(const char *input_key, char *key);
int get_key_by_name(const char *name, char *key); int get_key_by_name(const char *name, char *key);
int get_pwm_key_by_name(const char *name, char *key); int get_pwm_key_by_name(const char *name, char *key);
int get_gpio_number(const char *key, unsigned int *gpio); int get_gpio_number(const char *key, int *gpio);
int get_key(const char *input, char *key); int get_key(const char *input, char *key);
int get_pwm_key(const char *input, char *key); int get_pwm_key(const char *input, char *key);
int get_adc_ain(const char *key, unsigned int *ain); int get_adc_ain(const char *key, unsigned int *ain);
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len); int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len);
int get_spi_bus_path_number(unsigned int spi); int get_spi_bus_path_number(unsigned int spi);
void dyn_int_array_set(void **in_array, int i, int val, int initial_val); void dyn_int_array_set(dyn_int_array_t **in_array, int i, int val, int initial_val);
int dyn_int_array_get(void **in_array, int i, int initial_val); int dyn_int_array_get(dyn_int_array_t **in_array, int i, int initial_val);
void dyn_int_array_delete(void **in_array); void dyn_int_array_delete(dyn_int_array_t **in_array);
void clear_error_msg(void);
char *get_error_msg(void);
void add_error_msg(char *msg);

View File

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

View File

@ -54,21 +54,21 @@ SOFTWARE.
#define PUD_DOWN 1 #define PUD_DOWN 1
#define PUD_UP 2 #define PUD_UP 2
int gpio_export(unsigned int gpio); int gpio_export(int gpio);
int gpio_unexport(unsigned int gpio); int gpio_unexport(int gpio);
void exports_cleanup(void); void exports_cleanup(void);
int gpio_set_direction(unsigned int gpio, unsigned int in_flag); int gpio_set_direction(int gpio, unsigned int in_flag);
int gpio_get_direction(unsigned int gpio, unsigned int *value); int gpio_get_direction(int gpio, unsigned int *value);
int gpio_set_value(unsigned int gpio, unsigned int value); int gpio_set_value(int gpio, unsigned int value);
int gpio_get_value(unsigned int gpio, unsigned int *value); int gpio_get_value(int gpio, unsigned int *value);
int add_edge_detect(unsigned int gpio, unsigned int edge); int add_edge_detect(int gpio, unsigned int edge);
void remove_edge_detect(unsigned int gpio); void remove_edge_detect(int gpio);
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)); int add_edge_callback(int gpio, void (*func)(int gpio));
int event_detected(unsigned int gpio); int event_detected(int gpio);
int gpio_event_add(unsigned int gpio); int gpio_event_add(int gpio);
int gpio_event_remove(unsigned int gpio); int gpio_event_remove(int gpio);
int gpio_is_evented(unsigned int gpio); int gpio_is_evented(int gpio);
int event_initialise(void); int event_initialise(void);
void event_cleanup(void); void event_cleanup(void);
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge); int blocking_wait_for_edge(int gpio, unsigned int edge);

View File

@ -45,12 +45,12 @@ SOFTWARE.
static int gpio_warnings = 1; static int gpio_warnings = 1;
int max_gpio = -1; int max_gpio = -1;
void *gpio_direction = NULL; dyn_int_array_t *gpio_direction = NULL;
struct py_callback struct py_callback
{ {
char channel[32]; char channel[32];
unsigned int gpio; int gpio;
PyObject *py_cb; PyObject *py_cb;
unsigned long long lastcall; unsigned long long lastcall;
unsigned int bouncetime; unsigned int bouncetime;
@ -74,6 +74,8 @@ static void remember_gpio_direction(int gpio, int direction)
// python function cleanup() // python function cleanup()
static PyObject *py_cleanup(PyObject *self, PyObject *args) static PyObject *py_cleanup(PyObject *self, PyObject *args)
{ {
clear_error_msg();
// clean up any exports // clean up any exports
event_cleanup(); event_cleanup();
@ -83,13 +85,15 @@ static PyObject *py_cleanup(PyObject *self, PyObject *args)
// python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None) // python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None)
static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs) static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
int direction; int direction;
int pud = PUD_OFF; int pud = PUD_OFF;
int initial = 0; int initial = 0;
static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL}; static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL};
clear_error_msg();
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial)) if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial))
return NULL; return NULL;
@ -113,39 +117,54 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar
return NULL; return NULL;
} }
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio) < 0) {
PyErr_SetString(PyExc_ValueError, "Invalid value for channel"); char err[2000];
snprintf(err, sizeof(err), "Invalid channel %s. (%s)", channel, get_error_msg());
PyErr_SetString(PyExc_ValueError, err);
return NULL; return NULL;
} }
int result = gpio_export(gpio); if (gpio_export(gpio) < 0) {
if (result < 0) { char err[2000];
PyErr_SetString(PyExc_ValueError, "Channel in use (already exported)"); snprintf(err, sizeof(err), "Error setting up channel %s, maybe already exported? (%s)", channel, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
if (gpio_set_direction(gpio, direction) < 0) {
char err[2000];
snprintf(err, sizeof(err), "Error setting direction %d on channel %s. (%s)", direction, channel, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL; return NULL;
} }
gpio_set_direction(gpio, direction);
// For some reason, the following code doesn't work for XIOs. Skip.
if (direction == OUTPUT) { if (direction == OUTPUT) {
gpio_set_value(gpio, initial); if (gpio_set_value(gpio, initial) < 0) {
char err[2000];
snprintf(err, sizeof(err), "Error setting initial value %d on channel %s. (%s)", initial, channel, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
} }
remember_gpio_direction(gpio, direction); remember_gpio_direction(gpio, direction);
Py_RETURN_NONE; Py_RETURN_NONE;
} } /* py_setup_channel */
// python function output(channel, value) // python function output(channel, value)
static PyObject *py_output_gpio(PyObject *self, PyObject *args) static PyObject *py_output_gpio(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
int value; int value;
char *channel; char *channel;
clear_error_msg();
if (!PyArg_ParseTuple(args, "si", &channel, &value)) if (!PyArg_ParseTuple(args, "si", &channel, &value))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -157,26 +176,31 @@ static PyObject *py_output_gpio(PyObject *self, PyObject *args)
int result = gpio_set_value(gpio, value); int result = gpio_set_value(gpio, value);
if (result < 0) { if (result < 0) {
PyErr_SetString(PyExc_RuntimeError, "Could not write to channel"); char err[2000];
snprintf(err, sizeof(err), "Could no write %d on channel %s. (%s)", value, channel, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL; return NULL;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
} } /* py_output_gpio */
// python function value = input(channel) // python function value = input(channel)
static PyObject *py_input_gpio(PyObject *self, PyObject *args) static PyObject *py_input_gpio(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
unsigned int value; unsigned int value;
PyObject *py_value; PyObject *py_value;
clear_error_msg();
if (!PyArg_ParseTuple(args, "s", &channel)) if (!PyArg_ParseTuple(args, "s", &channel))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -194,7 +218,7 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args)
return py_value; return py_value;
} }
static void run_py_callbacks(unsigned int gpio) static void run_py_callbacks(int gpio)
{ {
PyObject *result; PyObject *result;
PyGILState_STATE gstate; PyGILState_STATE gstate;
@ -202,6 +226,8 @@ static void run_py_callbacks(unsigned int gpio)
struct timeval tv_timenow; struct timeval tv_timenow;
unsigned long long timenow; unsigned long long timenow;
clear_error_msg();
while (cb != NULL) while (cb != NULL)
{ {
if (cb->gpio == gpio) if (cb->gpio == gpio)
@ -231,11 +257,13 @@ static void run_py_callbacks(unsigned int gpio)
} }
} }
static int add_py_callback(char *channel, unsigned int gpio, unsigned int bouncetime, PyObject *cb_func) static int add_py_callback(char *channel, int gpio, unsigned int bouncetime, PyObject *cb_func)
{ {
struct py_callback *new_py_cb; struct py_callback *new_py_cb;
struct py_callback *cb = py_callbacks; struct py_callback *cb = py_callbacks;
clear_error_msg();
// add callback to py_callbacks list // add callback to py_callbacks list
new_py_cb = malloc(sizeof(struct py_callback)); new_py_cb = malloc(sizeof(struct py_callback));
if (new_py_cb == 0) if (new_py_cb == 0)
@ -266,12 +294,14 @@ static int add_py_callback(char *channel, unsigned int gpio, unsigned int bounce
// python function add_event_callback(gpio, callback, bouncetime=0) // python function add_event_callback(gpio, callback, bouncetime=0)
static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
unsigned int bouncetime = 0; unsigned int bouncetime = 0;
PyObject *cb_func; PyObject *cb_func;
char *kwlist[] = {"gpio", "callback", "bouncetime", NULL}; char *kwlist[] = {"gpio", "callback", "bouncetime", NULL};
clear_error_msg();
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime)) if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime))
return NULL; return NULL;
@ -282,7 +312,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
} }
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -290,7 +320,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
&& gpio != lookup_gpio_by_name("AP-EINT1") && gpio != lookup_gpio_by_name("AP-EINT1")
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) { && !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
PyErr_SetString(PyExc_RuntimeError, "Callbacks currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only"); PyErr_SetString(PyExc_ValueError, "Callbacks currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
return NULL; return NULL;
} }
@ -315,13 +345,15 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
// python function add_event_detect(gpio, edge, callback=None, bouncetime=0 // python function add_event_detect(gpio, edge, callback=None, bouncetime=0
static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs) static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
int edge, result; int edge, result;
unsigned int bouncetime = 0; unsigned int bouncetime = 0;
PyObject *cb_func = NULL; PyObject *cb_func = NULL;
char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL}; char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL};
clear_error_msg();
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime))
return NULL; return NULL;
@ -332,7 +364,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
} }
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -340,14 +372,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
&& gpio != lookup_gpio_by_name("AP-EINT1") && gpio != lookup_gpio_by_name("AP-EINT1")
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) { && !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only"); PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
return NULL;
}
// check channel is set up as an input
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
{
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL; return NULL;
} }
@ -358,6 +383,13 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
return NULL; return NULL;
} }
// check channel is set up as an input
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
{
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL;
}
if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread
{ {
if (result == 1) if (result == 1)
@ -380,17 +412,19 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
// python function remove_event_detect(gpio) // python function remove_event_detect(gpio)
static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
struct py_callback *cb = py_callbacks; struct py_callback *cb = py_callbacks;
struct py_callback *temp; struct py_callback *temp;
struct py_callback *prev = NULL; struct py_callback *prev = NULL;
clear_error_msg();
if (!PyArg_ParseTuple(args, "s", &channel)) if (!PyArg_ParseTuple(args, "s", &channel))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -398,7 +432,7 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
&& gpio != lookup_gpio_by_name("AP-EINT1") && gpio != lookup_gpio_by_name("AP-EINT1")
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) { && !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only"); PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
return NULL; return NULL;
} }
@ -429,14 +463,16 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
// python function value = event_detected(channel) // python function value = event_detected(channel)
static PyObject *py_event_detected(PyObject *self, PyObject *args) static PyObject *py_event_detected(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
char *channel; char *channel;
clear_error_msg();
if (!PyArg_ParseTuple(args, "s", &channel)) if (!PyArg_ParseTuple(args, "s", &channel))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -449,16 +485,18 @@ static PyObject *py_event_detected(PyObject *self, PyObject *args)
// python function py_wait_for_edge(gpio, edge) // python function py_wait_for_edge(gpio, edge)
static PyObject *py_wait_for_edge(PyObject *self, PyObject *args) static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
int edge, result; int edge, result;
char *channel; char *channel;
char error[81]; char error[81];
clear_error_msg();
if (!PyArg_ParseTuple(args, "si", &channel, &edge)) if (!PyArg_ParseTuple(args, "si", &channel, &edge))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -466,14 +504,7 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
&& gpio != lookup_gpio_by_name("AP-EINT1") && gpio != lookup_gpio_by_name("AP-EINT1")
&& !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) { && !(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
PyErr_SetString(PyExc_RuntimeError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only"); PyErr_SetString(PyExc_ValueError, "Edge Detection currently available on AP-EINT1, AP-EINT3, and XIO-P0 to XIO-P7 only");
return NULL;
}
// check channel is setup as an input
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
{
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL; return NULL;
} }
@ -484,6 +515,13 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
// check channel is setup as an input
if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != INPUT)
{
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL;
}
Py_BEGIN_ALLOW_THREADS // disable GIL Py_BEGIN_ALLOW_THREADS // disable GIL
result = blocking_wait_for_edge(gpio, edge); result = blocking_wait_for_edge(gpio, edge);
Py_END_ALLOW_THREADS // enable GIL Py_END_ALLOW_THREADS // enable GIL
@ -506,17 +544,18 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
// python function value = gpio_function(gpio) // python function value = gpio_function(gpio)
static PyObject *py_gpio_function(PyObject *self, PyObject *args) static PyObject *py_gpio_function(PyObject *self, PyObject *args)
{ {
unsigned int gpio; int gpio;
unsigned int value; unsigned int value;
PyObject *func; PyObject *func;
char *channel; char *channel;
clear_error_msg();
if (!PyArg_ParseTuple(args, "s", &channel)) if (!PyArg_ParseTuple(args, "s", &channel))
return NULL; return NULL;
if (get_gpio_number(channel, &gpio)) { if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); PyErr_SetString(PyExc_ValueError, "Invalid channel");
return NULL; return NULL;
} }
@ -534,6 +573,8 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args)
// python function setwarnings(state) // python function setwarnings(state)
static PyObject *py_setwarnings(PyObject *self, PyObject *args) static PyObject *py_setwarnings(PyObject *self, PyObject *args)
{ {
clear_error_msg();
if (!PyArg_ParseTuple(args, "i", &gpio_warnings)) if (!PyArg_ParseTuple(args, "i", &gpio_warnings))
return NULL; return NULL;
@ -552,56 +593,62 @@ static PyObject *py_gpio_base(PyObject *self, PyObject *args)
unsigned int value; unsigned int value;
PyObject *py_value; PyObject *py_value;
value = get_xio_base(); clear_error_msg();
value = get_xio_base();
if (value <= 0) {
char err[1024];
snprintf(err, sizeof(err), "Could not get XIO base ('%s')", get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
py_value = Py_BuildValue("i", value); py_value = Py_BuildValue("i", value);
return py_value; return py_value;
} }
// Internal unit tests // Internal unit tests
extern int num_get_xio_base;
extern pins_t pins_info[]; extern pins_t pins_info[];
static PyObject *py_selftest(PyObject *self, PyObject *args) static PyObject *py_selftest(PyObject *self, PyObject *args)
{ {
int input; int input;
clear_error_msg();
if (!PyArg_ParseTuple(args, "i", &input)) if (!PyArg_ParseTuple(args, "i", &input))
return NULL; return NULL;
printf("Testing get_xio_base\n"); printf("Testing get_xio_base\n");
ASSRT(num_get_xio_base == 0); int first_base = get_xio_base(); ASSRT(first_base > 0);
int base = get_xio_base(); ASSRT(base > 0 && base < 1024); int second_base = get_xio_base(); ASSRT(second_base == first_base);
ASSRT(num_get_xio_base == 1); printf("base=%d\n", first_base);
int second_base = get_xio_base(); ASSRT(second_base == base);
ASSRT(num_get_xio_base == 1); /* make sure it didn't do the full calc a second time. */
printf("base=%d\n", base);
printf("Testing lookup_gpio_by_key\n"); printf("Testing lookup_gpio_by_key\n");
ASSRT(0 == lookup_gpio_by_key("U13_1")); ASSRT(-1 == lookup_gpio_by_key("U13_1"));
ASSRT(48 == lookup_gpio_by_key("U13_9")); ASSRT(48 == lookup_gpio_by_key("U13_9"));
ASSRT(47 == lookup_gpio_by_key("U13_11")); ASSRT(47 == lookup_gpio_by_key("U13_11"));
ASSRT(base == lookup_gpio_by_key("U14_13")); ASSRT(first_base == lookup_gpio_by_key("U14_13"));
ASSRT((base+1) == lookup_gpio_by_key("U14_14")); ASSRT((first_base+1) == lookup_gpio_by_key("U14_14"));
ASSRT((base+6) == lookup_gpio_by_key("U14_19")); ASSRT((first_base+6) == lookup_gpio_by_key("U14_19"));
ASSRT((base+7) == lookup_gpio_by_key("U14_20")); ASSRT((first_base+7) == lookup_gpio_by_key("U14_20"));
ASSRT(193 == lookup_gpio_by_key("U14_23")); ASSRT(193 == lookup_gpio_by_key("U14_23"));
ASSRT(139 == lookup_gpio_by_key("U14_38")); ASSRT(139 == lookup_gpio_by_key("U14_38"));
ASSRT(0 == lookup_gpio_by_key("U14_40")); ASSRT(-1 == lookup_gpio_by_key("U14_40"));
ASSRT(0 == lookup_gpio_by_key("NOTFOUND")); ASSRT(-1 == lookup_gpio_by_key("NOTFOUND"));
ASSRT(0 == lookup_gpio_by_key("U14_")); ASSRT(-1 == lookup_gpio_by_key("U14_"));
ASSRT(0 == lookup_gpio_by_key("U14_4000")); ASSRT(-1 == lookup_gpio_by_key("U14_4000"));
printf("Testing lookup_gpio_by_name\n"); printf("Testing lookup_gpio_by_name\n");
ASSRT(0 == lookup_gpio_by_name("GND")); ASSRT(-1 == lookup_gpio_by_name("GND"));
ASSRT(48 == lookup_gpio_by_name("TWI1-SDA")); ASSRT(48 == lookup_gpio_by_name("TWI1-SDA"));
ASSRT(47 == lookup_gpio_by_name("TWI1-SCK")); ASSRT(47 == lookup_gpio_by_name("TWI1-SCK"));
ASSRT(base == lookup_gpio_by_name("XIO-P0")); ASSRT(first_base == lookup_gpio_by_name("XIO-P0"));
ASSRT((base+6) == lookup_gpio_by_name("XIO-P6")); ASSRT((first_base+6) == lookup_gpio_by_name("XIO-P6"));
ASSRT((base+7) == lookup_gpio_by_name("XIO-P7")); ASSRT((first_base+7) == lookup_gpio_by_name("XIO-P7"));
ASSRT(139 == lookup_gpio_by_name("CSID7")); ASSRT(139 == lookup_gpio_by_name("CSID7"));
ASSRT(0 == lookup_gpio_by_name("NOTFOUND")); ASSRT(-1 == lookup_gpio_by_name("NOTFOUND"));
ASSRT(0 == lookup_gpio_by_name("CSID")); ASSRT(-1 == lookup_gpio_by_name("CSID"));
ASSRT(0 == lookup_gpio_by_name("CSID777")); ASSRT(-1 == lookup_gpio_by_name("CSID777"));
printf("Testing lookup_ain_by_key\n"); printf("Testing lookup_ain_by_key\n");
ASSRT(-1 == lookup_ain_by_key("U14_1")); ASSRT(-1 == lookup_ain_by_key("U14_1"));
@ -661,6 +708,26 @@ static PyObject *py_selftest(PyObject *self, PyObject *args)
ASSRT(2 == get_spi_bus_path_number(0)); /* doesn't really work on CHIP */ ASSRT(2 == get_spi_bus_path_number(0)); /* doesn't really work on CHIP */
ASSRT(2 == get_spi_bus_path_number(1)); /* doesn't really work on CHIP */ ASSRT(2 == get_spi_bus_path_number(1)); /* doesn't really work on CHIP */
printf("Testing error message buffer\n");
clear_error_msg();
ASSRT(0 == strlen(get_error_msg()));
char *s100 = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
add_error_msg(s100); ASSRT(100 == strlen(get_error_msg()));
// Subsequent messages added include a newline separator.
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(403 == strlen(get_error_msg()));
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(706 == strlen(get_error_msg()));
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(1009 == strlen(get_error_msg()));
add_error_msg(s100); add_error_msg(s100); add_error_msg(s100); ASSRT(1023 == strlen(get_error_msg()));
printf("Testing dynamic integer array\n");
dyn_int_array_t *my_array = NULL;
ASSRT(-2 == dyn_int_array_get(&my_array, 29, -2)); ASSRT(my_array->num_elements == 45);
dyn_int_array_set(&my_array, 44, 3, -2); ASSRT(my_array->num_elements == 45);
ASSRT(3 == dyn_int_array_get(&my_array, 44, -2)); ASSRT(my_array->num_elements == 45);
dyn_int_array_set(&my_array, 45, 6, -2); ASSRT(my_array->num_elements == 69);
ASSRT(6 == dyn_int_array_get(&my_array, 45, -2)); ASSRT(my_array->num_elements == 69);
dyn_int_array_delete(&my_array);
int value = input; int value = input;
PyObject *py_value = Py_BuildValue("i", value); PyObject *py_value = Py_BuildValue("i", value);
@ -704,6 +771,8 @@ PyMODINIT_FUNC initGPIO(void)
{ {
PyObject *module = NULL; PyObject *module = NULL;
clear_error_msg();
#if PY_MAJOR_VERSION > 2 #if PY_MAJOR_VERSION > 2
if ((module = PyModule_Create(&rpigpiomodule)) == NULL) if ((module = PyModule_Create(&rpigpiomodule)) == NULL)
return NULL; return NULL;

View File

@ -0,0 +1,96 @@
# The default ``config.py``
def set_prefs(prefs):
"""This function is called before opening the project"""
# Specify which files and folders to ignore in the project.
# Changes to ignored resources are not added to the history and
# VCSs. Also they are not returned in `Project.get_files()`.
# Note that ``?`` and ``*`` match all characters but slashes.
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
# '.svn': matches 'pkg/.svn' and all of its children
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
prefs['ignored_resources'] = [
'*.pyc', '*~', '.ropeproject', '.hg', '.svn', '_svn', '.git',
'.tox', '.env', 'node_modules', 'bower_components']
# Specifies which files should be considered python files. It is
# useful when you have scripts inside your project. Only files
# ending with ``.py`` are considered to be python files by
# default.
#prefs['python_files'] = ['*.py']
# Custom source folders: By default rope searches the project
# for finding source folders (folders that should be searched
# for finding modules). You can add paths to that list. Note
# that rope guesses project source folders correctly most of the
# time; use this if you have any problems.
# The folders should be relative to project root and use '/' for
# separating folders regardless of the platform rope is running on.
# 'src/my_source_folder' for instance.
#prefs.add('source_folders', 'src')
# You can extend python path for looking up modules
#prefs.add('python_path', '~/python/')
# Should rope save object information or not.
prefs['save_objectdb'] = True
prefs['compress_objectdb'] = False
# If `True`, rope analyzes each module when it is being saved.
prefs['automatic_soa'] = True
# The depth of calls to follow in static object analysis
prefs['soa_followed_calls'] = 0
# If `False` when running modules or unit tests "dynamic object
# analysis" is turned off. This makes them much faster.
prefs['perform_doa'] = True
# Rope can check the validity of its object DB when running.
prefs['validate_objectdb'] = True
# How many undos to hold?
prefs['max_history_items'] = 32
# Shows whether to save history across sessions.
prefs['save_history'] = True
prefs['compress_history'] = False
# Set the number spaces used for indenting. According to
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
# unit-tests use 4 spaces it is more reliable, too.
prefs['indent_size'] = 4
# Builtin and c-extension modules that are allowed to be imported
# and inspected by rope.
prefs['extension_modules'] = []
# Add all standard c-extensions to extension_modules list.
prefs['import_dynload_stdmods'] = True
# If `True` modules with syntax errors are considered to be empty.
# The default value is `False`; When `False` syntax errors raise
# `rope.base.exceptions.ModuleSyntaxError` exception.
prefs['ignore_syntax_errors'] = False
# If `True`, rope ignores unresolvable imports. Otherwise, they
# appear in the importing namespace.
prefs['ignore_bad_imports'] = False
# If `True`, rope will transform a comma list of imports into
# multiple separate import statements when organizing
# imports.
prefs['split_imports'] = False
# If `True`, rope will sort imports alphabetically by module name
# instead of alphabetically by import statement, with from imports
# after normal imports.
prefs['sort_imports_alphabetically'] = False
def project_opened(project):
"""This function is called after opening the project"""
# Do whatever you like here!

View File

@ -0,0 +1,2 @@
<EFBFBD>}q(Utest_softpwm_setup]q(Uteardown_moduleqUTestSoftpwmSetupqeUtest_gpio_output]q(hUTestGPIOOutputqeUtest_pwm_setup]q(hU TestPwmSetupqeUtest_gpio_setup]q (hU TestSetupq
eUtest_gpio_input]q (hU

View File

@ -0,0 +1 @@
<EFBFBD>]q(]q]qe.

View File

@ -0,0 +1 @@
<EFBFBD>}q.

View File

@ -42,7 +42,7 @@ if (GPIO.input("XIO-P0") != GPIO.HIGH):
num_errs += 1 num_errs += 1
GPIO.cleanup() GPIO.cleanup()
GPIO.setup("XIO-P0", GPIO.IN) GPIO.setup("U14_13", GPIO.IN) # XIO-P0
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW) GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW)
if (GPIO.input("XIO-P0") != GPIO.LOW): if (GPIO.input("XIO-P0") != GPIO.LOW):
print "A low output on CSI0 does not lead to a low input on XIO-P0." print "A low output on CSI0 does not lead to a low input on XIO-P0."
@ -51,7 +51,7 @@ if (GPIO.input("XIO-P0") != GPIO.LOW):
GPIO.cleanup() GPIO.cleanup()
GPIO.setup("XIO-P0", GPIO.IN) GPIO.setup("XIO-P0", GPIO.IN)
GPIO.setup("CSID0", GPIO.OUT) GPIO.setup("U14_31", GPIO.OUT) # CSID0
# VERIFY SIMPLE FUNCTIONALITY # VERIFY SIMPLE FUNCTIONALITY
print "VERIFY SIMPLE FUNCTIONALITY" print "VERIFY SIMPLE FUNCTIONALITY"
@ -66,7 +66,7 @@ assert(GPIO.input("XIO-P0") == GPIO.LOW)
# ============================================== # ==============================================
# EDGE DETECTION - AP-EINT1 # EDGE DETECTION - AP-EINT1
print "SETTING UP EDGE DETECTION ON AP-EINT1" print "SETTING UP RISING EDGE DETECTION ON AP-EINT1"
GPIO.setup("AP-EINT1", GPIO.IN) GPIO.setup("AP-EINT1", GPIO.IN)
print "adding event detect" print "adding event detect"
GPIO.add_event_detect("AP-EINT1", GPIO.RISING) GPIO.add_event_detect("AP-EINT1", GPIO.RISING)
@ -75,13 +75,12 @@ print "VERIFYING EDGE DETECT"
f = open("/sys/class/gpio/gpio193/edge", "r") f = open("/sys/class/gpio/gpio193/edge", "r")
edge = f.read() edge = f.read()
f.close() f.close()
print "edge='", edge, "'"
assert(edge == "rising\n") assert(edge == "rising\n")
GPIO.remove_event_detect("AP-EINT1") GPIO.remove_event_detect("AP-EINT1")
# ============================================== # ==============================================
# EDGE DETECTION - AP-EINT3 # EDGE DETECTION - AP-EINT3
print "SETTING UP EDGE DETECTION ON AP-EINT3" print "SETTING UP BOTH EDGE DETECTION ON AP-EINT3"
GPIO.setup("AP-EINT3", GPIO.IN) GPIO.setup("AP-EINT3", GPIO.IN)
GPIO.add_event_detect("AP-EINT3", GPIO.BOTH) GPIO.add_event_detect("AP-EINT3", GPIO.BOTH)
@ -89,13 +88,12 @@ print "VERIFYING EDGE DETECT"
f = open("/sys/class/gpio/gpio35/edge", "r") f = open("/sys/class/gpio/gpio35/edge", "r")
edge = f.read() edge = f.read()
f.close() f.close()
print "EDGE: %s" % edge
assert(edge == "both\n") assert(edge == "both\n")
GPIO.remove_event_detect("AP-EINT3") GPIO.remove_event_detect("AP-EINT3")
# ============================================== # ==============================================
# EDGE DETECTION - EXPANDED GPIO # EDGE DETECTION - EXPANDED GPIO
print "SETTING UP EDGE DETECTION ON XIO-P0" print "SETTING UP FALLING EDGE DETECTION ON XIO-P0"
GPIO.add_event_detect("XIO-P0", GPIO.FALLING, myfuncallback) GPIO.add_event_detect("XIO-P0", GPIO.FALLING, myfuncallback)
print "VERIFYING EDGE DETECT" print "VERIFYING EDGE DETECT"
@ -104,7 +102,6 @@ gfile = "/sys/class/gpio/gpio%d/edge" % base
f = open(gfile, "r") f = open(gfile, "r")
edge = f.read() edge = f.read()
f.close() f.close()
print "EDGE: %s" % edge
assert(edge == "falling\n") assert(edge == "falling\n")
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK # LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
@ -134,14 +131,60 @@ GPIO.setup("CSID1", GPIO.IN)
try: try:
GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback) GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback)
print "Oops, it did not throw an exception! BUG!!!" print "Oops, it did not throw an exception! BUG!!!"
except: num_errors += 1
except ValueError, ex:
print "error msg=", ex.args[0]
pass
except RuntimeError, ex:
print "error msg=", ex.args[0]
pass
print "TESTING ERRORS THROWN WHEN SETTING UP AN ALREADY EXPORTED GPIO"
try:
GPIO.output("XIO-P0", GPIO.LOW)
print "Oops, it did not throw an exception! BUG!!!"
num_errors += 1
except ValueError, ex:
print "error msg=", ex.args[0]
pass
except RuntimeError, ex:
print "error msg=", ex.args[0]
pass pass
print "TESTING ERRORS THROWN WHEN WRITING TO A GPIO WITH NO DIRECTION" print "TESTING ERRORS THROWN WHEN WRITING TO A GPIO WITH NO DIRECTION"
try: try:
GPIO.output("CSID1", GPIO.LOW) GPIO.output("CSID1", GPIO.LOW)
print "Oops, it did not throw an exception! BUG!!!" print "Oops, it did not throw an exception! BUG!!!"
except: num_errors += 1
except ValueError, ex:
print "error msg=", ex.args[0]
pass
except RuntimeError, ex:
print "error msg=", ex.args[0]
pass
print "TESTING ERRORS THROWN FOR ILLEGAL GPIO"
try:
GPIO.setup("NOTUSED", GPIO.IN)
print "Oops, it did not throw an exception! BUG!!!"
num_errors += 1
except ValueError, ex:
print "error msg=", ex.args[0]
pass
except RuntimeError, ex:
print "error msg=", ex.args[0]
pass
print "TESTING ERRORS THROWN FOR NON-GPIO"
try:
GPIO.setup("FEL", GPIO.IN)
print "Oops, it did not throw an exception! BUG!!!"
num_errors += 1
except ValueError, ex:
print "error msg=", ex.args[0]
pass
except RuntimeError, ex:
print "error msg=", ex.args[0]
pass pass
print "CLEANUP" print "CLEANUP"