diff --git a/source/c_softpwm.c b/source/c_softpwm.c index 6bc073e..aed22fe 100644 --- a/source/c_softpwm.c +++ b/source/c_softpwm.c @@ -145,7 +145,7 @@ int softpwm_set_duty_cycle(const char *key, float duty) {; void *softpwm_thread_toggle(void *key) { struct softpwm *pwm; - unsigned int gpio; + int gpio; struct timespec tim_on; struct timespec tim_off; unsigned int sec; @@ -237,7 +237,7 @@ int softpwm_start(const char *key, float duty, float freq, int polarity) struct softpwm *new_pwm, *pwm; pthread_t new_thread; pthread_mutex_t *new_params_lock; - unsigned int gpio; + int gpio; int ret; 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) { struct softpwm *pwm, *temp, *prev_pwm = NULL; - unsigned int gpio = 0; + int gpio = 0; // remove from list pwm = exported_pwms; diff --git a/source/common.c b/source/common.c index 4bd2463..93d698c 100644 --- a/source/common.c +++ b/source/common.c @@ -42,6 +42,7 @@ SOFTWARE. #include "common.h" #include #include +#include #include #include #include @@ -49,24 +50,25 @@ SOFTWARE. int setup_error = 0; int module_setup = 0; + // I have no idea if this table is correct, we shall see - Robert Wolterman pins_t pins_info[] = { - { "GND", "U13_1", 0, BASE_METHOD_AS_IS, -1, -1}, - { "CHG-IN", "U13_2", 0, BASE_METHOD_AS_IS, -1, -1}, - { "VCC-5V", "U13_3", 0, BASE_METHOD_AS_IS, -1, -1}, - { "GND", "U13_4", 0, BASE_METHOD_AS_IS, -1, -1}, - { "VCC-3V3", "U13_5", 0, BASE_METHOD_AS_IS, -1, -1}, - { "TS", "U13_6", 0, BASE_METHOD_AS_IS, -1, -1}, - { "VCC-1V8", "U13_7", 0, BASE_METHOD_AS_IS, -1, -1}, - { "BAT", "U13_8", 0, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U13_1", -1, BASE_METHOD_AS_IS, -1, -1}, + { "CHG-IN", "U13_2", -1, BASE_METHOD_AS_IS, -1, -1}, + { "VCC-5V", "U13_3", -1, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U13_4", -1, BASE_METHOD_AS_IS, -1, -1}, + { "VCC-3V3", "U13_5", -1, BASE_METHOD_AS_IS, -1, -1}, + { "TS", "U13_6", -1, BASE_METHOD_AS_IS, -1, -1}, + { "VCC-1V8", "U13_7", -1, 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}, - { "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}, - { "GND", "U13_12", 0, BASE_METHOD_AS_IS, -1, -1}, - { "X1", "U13_13", 0, BASE_METHOD_AS_IS, -1, -1}, - { "X2", "U13_14", 0, BASE_METHOD_AS_IS, -1, -1}, - { "Y1", "U13_15", 0, BASE_METHOD_AS_IS, -1, -1}, - { "Y2", "U13_16", 0, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U13_12", -1, BASE_METHOD_AS_IS, -1, -1}, + { "X1", "U13_13", -1, BASE_METHOD_AS_IS, -1, -1}, + { "X2", "U13_14", -1, BASE_METHOD_AS_IS, -1, -1}, + { "Y1", "U13_15", -1, 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}, { "PWM0", "U13_18", 34, BASE_METHOD_AS_IS, 0, -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-VSYNC", "U13_37", 123, 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}, - { "GND", "U14_1", 0, BASE_METHOD_AS_IS, -1, -1}, - { "VCC-5V", "U14_2", 0, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U14_1", -1, 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}, - { "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}, - { "HPCOM", "U14_6", 0, BASE_METHOD_AS_IS, -1, -1}, - { "FEL", "U14_7", 0, BASE_METHOD_AS_IS, -1, -1}, - { "HPR", "U14_8", 0, BASE_METHOD_AS_IS, -1, -1}, - { "VCC-3V3", "U14_9", 0, BASE_METHOD_AS_IS, -1, -1}, - { "MICM", "U14_10", 0, BASE_METHOD_AS_IS, -1, -1}, - { "LRADC", "U14_11", 0, BASE_METHOD_AS_IS, -1, 0}, - { "MICIN1", "U14_12", 0, BASE_METHOD_AS_IS, -1, -1}, + { "HPCOM", "U14_6", -1, BASE_METHOD_AS_IS, -1, -1}, + { "FEL", "U14_7", -1, BASE_METHOD_AS_IS, -1, -1}, + { "HPR", "U14_8", -1, BASE_METHOD_AS_IS, -1, -1}, + { "VCC-3V3", "U14_9", -1, BASE_METHOD_AS_IS, -1, -1}, + { "MICM", "U14_10", -1, BASE_METHOD_AS_IS, -1, -1}, + { "LRADC", "U14_11", -1, BASE_METHOD_AS_IS, -1, 0}, + { "MICIN1", "U14_12", -1, BASE_METHOD_AS_IS, -1, -1}, { "XIO-P0", "U14_13", 0, 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}, @@ -111,8 +113,8 @@ pins_t pins_info[] = { { "XIO-P5", "U14_18", 5, 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}, - { "GND", "U14_21", 0, BASE_METHOD_AS_IS, -1, -1}, - { "GND", "U14_22", 0, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U14_21", -1, 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-EINT3", "U14_24", 35, 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}, { "CSID6", "U14_37", 138, 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_40", 0, BASE_METHOD_AS_IS, -1, -1}, - { NULL, NULL, 0, 0, -1, -1} + { "GND", "U14_39", -1, BASE_METHOD_AS_IS, -1, -1}, + { "GND", "U14_40", -1, BASE_METHOD_AS_IS, -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 #define GPIO_PATH "/sys/class/gpio" #define EXPANDER "pcf8574a\n" -int num_get_xio_base = 0; /* for self-test purposes */ + +/* returns -1 for error */ int get_xio_base(void) { char label_file[FILENAME_BUFFER_SIZE]; FILE *label_fp; char base_file[FILENAME_BUFFER_SIZE]; FILE *base_fp; - char input_line[80]; // 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 // base address is calculated and stored in xio_base_address. Subsequent @@ -162,34 +164,56 @@ int get_xio_base(void) struct dirent *ent; struct stat sbuf; - if (xio_base_address == -1 && (dir = opendir (GPIO_PATH)) != NULL) { - while (xio_base_address == -1 && (ent = readdir (dir)) != NULL) { - lstat(ent->d_name,&sbuf); - if (S_ISDIR(sbuf.st_mode)) { - if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) { - continue; /* skip "." and ".." entries */ - } - snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file); - label_fp = fopen(label_file, "r"); - if (label_fp != NULL) { - char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line); ASSRT(s); - fclose(label_fp); - if (strcmp(input_line, EXPANDER) == 0) { - /* 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); - base_fp = fopen(base_file, "r"); ASSRT(base_fp != NULL); - s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line); ASSRT(s); - fclose(base_fp); - /* Remember the value in the static local. */ - xio_base_address = atoi(input_line); ASSRT(xio_base_address > 0); - num_get_xio_base++; /* for self-test purposes */ - } - } /* if label file is open */ - } /* if isdir */ - } /* while */ - closedir (dir); + 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) { + lstat(ent->d_name,&sbuf); + if (S_ISDIR(sbuf.st_mode)) { + if (strcmp(".",ent->d_name) == 0 || strcmp("..",ent->d_name) == 0) { + continue; /* skip "." and ".." entries */ + } + + snprintf(label_file, sizeof(label_file), "%s/%s/label", GPIO_PATH, ent->d_name); BUF2SMALL(label_file); + label_fp = fopen(label_file, "r"); + if (label_fp != NULL) { + char input_line[80]; input_line[0] = '\0'; + char *s = fgets(input_line, sizeof(input_line), label_fp); BUF2SMALL(input_line); + fclose(label_fp); + if (s != NULL && strcmp(input_line, EXPANDER) == 0) { + /* 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); + base_fp = fopen(base_file, "r"); + 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); + 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. */ + xio_base_address = atoi(input_line); + } + } /* if label file is open */ + } /* if isdir */ + } /* while */ + closedir (dir); + return xio_base_address; } /* get_xio_base */ @@ -197,6 +221,7 @@ int get_xio_base(void) int gpio_number(pins_t *pin) { int gpio_num = -1; + int xio_base; switch (pin->base_method) { case BASE_METHOD_AS_IS: @@ -204,11 +229,16 @@ int gpio_number(pins_t *pin) break; 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; } - ASSRT(gpio_num != -1); return gpio_num; } /* gpio_number */ @@ -221,7 +251,7 @@ int lookup_gpio_by_key(const char *key) return gpio_number(p); } } - return 0; + return -1; } 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 0; + return -1; } 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; } -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); - if (!*gpio) { + if (*gpio <= 0) { *gpio = lookup_gpio_by_name(key); + if (*gpio <= 0) { + status = -1; /* error */ + } } - - return 0; + return status; } 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 { - int num_elements; - int *array; -}; +// We do not know at compile time how many GPIOs there are, so it is not safe +// to declare per-GPIO arrays with a static size. The "dyn_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)); - ASSRT(new_array != NULL); + dyn_int_array_t *new_array = (dyn_int_array_t *)malloc(sizeof(dyn_int_array_t)); + ASSRT(new_array != NULL); /* out of memory */ + new_array->num_elements = initial_num_elements; - new_array->array = (int *)malloc(initial_num_elements * sizeof(int)); - ASSRT(new_array->array != NULL); + new_array->content = (int *)malloc(initial_num_elements * sizeof(int)); + ASSRT(new_array->content != NULL); /* out of memory */ + int 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 */ -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); - if (array == NULL) - array = dyn_int_array_create(i * 3 / 2, initial_val); + dyn_int_array_t *array = *in_array; + if (array == NULL) { /* if array hasn't been created yet */ + array = dyn_int_array_create((i+1) * 3 / 2, initial_val); + *in_array = array; + } if (i >= array->num_elements) { - int new_num_elements = i * 3 / 2; /* half-again larger than current request */ - array->array = realloc(array->array, new_num_elements * sizeof(int)); - ASSRT(array->array != NULL); + int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */ + array->content = realloc(array->content, new_num_elements * sizeof(int)); + ASSRT(array->content != NULL); /* out of memory */ // Zero out the newly allocated 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->array[i] = val; - *in_array = (void *)array; + array->content[i] = val; } /* 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); - if (array == NULL) - array = dyn_int_array_create(i * 3 / 2, initial_val); + dyn_int_array_t *array = *in_array; + if (array == NULL) { /* if array hasn't been created yet */ + array = dyn_int_array_create((i+1) * 3 / 2, initial_val); + *in_array = array; + } if (i >= array->num_elements) { - int new_num_elements = i * 3 / 2; /* half-again larger than current request */ - array->array = realloc(array->array, new_num_elements * sizeof(int)); - ASSRT(array->array != NULL); + int new_num_elements = (i+1) * 3 / 2; /* half-again larger than current request */ + array->content = realloc(array->content, new_num_elements * sizeof(int)); + ASSRT(array->content != NULL); /* out of memory */ // Zero out the newly allocated 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 ++; } } - return array->array[i]; - *in_array = (void *)array; + return array->content[i]; } /* 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); - free(array->array); + dyn_int_array_t *array = *in_array; + free(array->content); free(array); } /* 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'; +} diff --git a/source/common.h b/source/common.h index 7fafeb3..63cf77b 100644 --- a/source/common.h +++ b/source/common.h @@ -69,6 +69,14 @@ typedef struct pins_t { int ain; } 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 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 get_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_pwm_key(const char *input, char *key); 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 get_spi_bus_path_number(unsigned int spi); -void dyn_int_array_set(void **in_array, int i, int val, int initial_val); -int dyn_int_array_get(void **in_array, int i, int initial_val); -void dyn_int_array_delete(void **in_array); +void dyn_int_array_set(dyn_int_array_t **in_array, int i, int val, int initial_val); +int dyn_int_array_get(dyn_int_array_t **in_array, int i, int initial_val); +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); diff --git a/source/event_gpio.c b/source/event_gpio.c index 6f28f81..45f4996 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -42,6 +42,7 @@ SOFTWARE. #include #include #include +#include #include #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; } diff --git a/source/event_gpio.h b/source/event_gpio.h index b58d102..603677d 100644 --- a/source/event_gpio.h +++ b/source/event_gpio.h @@ -54,21 +54,21 @@ SOFTWARE. #define PUD_DOWN 1 #define PUD_UP 2 -int gpio_export(unsigned int gpio); -int gpio_unexport(unsigned int gpio); +int gpio_export(int gpio); +int gpio_unexport(int gpio); void exports_cleanup(void); -int gpio_set_direction(unsigned int gpio, unsigned int in_flag); -int gpio_get_direction(unsigned int gpio, unsigned int *value); -int gpio_set_value(unsigned int gpio, unsigned int value); -int gpio_get_value(unsigned int gpio, unsigned int *value); +int gpio_set_direction(int gpio, unsigned int in_flag); +int gpio_get_direction(int gpio, unsigned int *value); +int gpio_set_value(int gpio, unsigned int value); +int gpio_get_value(int gpio, unsigned int *value); -int add_edge_detect(unsigned int gpio, unsigned int edge); -void remove_edge_detect(unsigned int gpio); -int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)); -int event_detected(unsigned int gpio); -int gpio_event_add(unsigned int gpio); -int gpio_event_remove(unsigned int gpio); -int gpio_is_evented(unsigned int gpio); +int add_edge_detect(int gpio, unsigned int edge); +void remove_edge_detect(int gpio); +int add_edge_callback(int gpio, void (*func)(int gpio)); +int event_detected(int gpio); +int gpio_event_add(int gpio); +int gpio_event_remove(int gpio); +int gpio_is_evented(int gpio); int event_initialise(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); diff --git a/source/py_gpio.c b/source/py_gpio.c index f417459..5e90683 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -45,12 +45,12 @@ SOFTWARE. static int gpio_warnings = 1; int max_gpio = -1; -void *gpio_direction = NULL; +dyn_int_array_t *gpio_direction = NULL; struct py_callback { char channel[32]; - unsigned int gpio; + int gpio; PyObject *py_cb; unsigned long long lastcall; unsigned int bouncetime; @@ -68,12 +68,14 @@ static int init_module(void) static void remember_gpio_direction(int gpio, int direction) { - dyn_int_array_set(&gpio_direction, gpio, direction, -1); + dyn_int_array_set(&gpio_direction, gpio, direction, -1); } // python function cleanup() static PyObject *py_cleanup(PyObject *self, PyObject *args) { + clear_error_msg(); + // clean up any exports 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) static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs) { - unsigned int gpio; + int gpio; char *channel; int direction; int pud = PUD_OFF; int initial = 0; 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)) return NULL; @@ -113,39 +117,54 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar return NULL; } - if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_ValueError, "Invalid value for channel"); + if (get_gpio_number(channel, &gpio) < 0) { + char err[2000]; + snprintf(err, sizeof(err), "Invalid channel %s. (%s)", channel, get_error_msg()); + PyErr_SetString(PyExc_ValueError, err); return NULL; } - int result = gpio_export(gpio); - if (result < 0) { - PyErr_SetString(PyExc_ValueError, "Channel in use (already exported)"); + if (gpio_export(gpio) < 0) { + char err[2000]; + 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; } - gpio_set_direction(gpio, direction); - // For some reason, the following code doesn't work for XIOs. Skip. 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); Py_RETURN_NONE; -} +} /* py_setup_channel */ + // python function output(channel, value) static PyObject *py_output_gpio(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; int value; char *channel; + clear_error_msg(); + if (!PyArg_ParseTuple(args, "si", &channel, &value)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -157,26 +176,31 @@ static PyObject *py_output_gpio(PyObject *self, PyObject *args) int result = gpio_set_value(gpio, value); 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; } Py_RETURN_NONE; -} +} /* py_output_gpio */ + // python function value = input(channel) static PyObject *py_input_gpio(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; char *channel; unsigned int value; PyObject *py_value; + clear_error_msg(); + if (!PyArg_ParseTuple(args, "s", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -194,7 +218,7 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args) return py_value; } -static void run_py_callbacks(unsigned int gpio) +static void run_py_callbacks(int gpio) { PyObject *result; PyGILState_STATE gstate; @@ -202,6 +226,8 @@ static void run_py_callbacks(unsigned int gpio) struct timeval tv_timenow; unsigned long long timenow; + clear_error_msg(); + while (cb != NULL) { 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 *cb = py_callbacks; + clear_error_msg(); + // add callback to py_callbacks list new_py_cb = malloc(sizeof(struct py_callback)); 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) static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) { - unsigned int gpio; + int gpio; char *channel; unsigned int bouncetime = 0; PyObject *cb_func; char *kwlist[] = {"gpio", "callback", "bouncetime", NULL}; + clear_error_msg(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime)) return NULL; @@ -282,7 +312,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject } if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); 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") && gpio != lookup_gpio_by_name("AP-EINT1") && !(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; } @@ -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 static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs) { - unsigned int gpio; + int gpio; char *channel; int edge, result; unsigned int bouncetime = 0; PyObject *cb_func = NULL; char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL}; + clear_error_msg(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) return NULL; @@ -332,7 +364,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k } if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -340,17 +372,10 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k if (gpio != lookup_gpio_by_name("AP-EINT3") && gpio != lookup_gpio_by_name("AP-EINT1") && !(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; - } - // is edge valid value if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) { @@ -358,6 +383,13 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k 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 == 1) @@ -380,17 +412,19 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k // python function remove_event_detect(gpio) static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; char *channel; struct py_callback *cb = py_callbacks; struct py_callback *temp; struct py_callback *prev = NULL; + clear_error_msg(); + if (!PyArg_ParseTuple(args, "s", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -398,7 +432,7 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) if (gpio != lookup_gpio_by_name("AP-EINT3") && gpio != lookup_gpio_by_name("AP-EINT1") && !(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; } @@ -429,14 +463,16 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) // python function value = event_detected(channel) static PyObject *py_event_detected(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; char *channel; + clear_error_msg(); + if (!PyArg_ParseTuple(args, "s", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -449,16 +485,18 @@ static PyObject *py_event_detected(PyObject *self, PyObject *args) // python function py_wait_for_edge(gpio, edge) static PyObject *py_wait_for_edge(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; int edge, result; char *channel; char error[81]; + clear_error_msg(); + if (!PyArg_ParseTuple(args, "si", &channel, &edge)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -466,17 +504,10 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args) if (gpio != lookup_gpio_by_name("AP-EINT3") && gpio != lookup_gpio_by_name("AP-EINT1") && !(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; - } - // is edge a valid value? if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) { @@ -484,6 +515,13 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args) 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 result = blocking_wait_for_edge(gpio, edge); 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) static PyObject *py_gpio_function(PyObject *self, PyObject *args) { - unsigned int gpio; + int gpio; unsigned int value; PyObject *func; char *channel; + clear_error_msg(); if (!PyArg_ParseTuple(args, "s", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) { - PyErr_SetString(PyExc_RuntimeError, "Invalid channel"); + PyErr_SetString(PyExc_ValueError, "Invalid channel"); return NULL; } @@ -534,6 +573,8 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args) // python function setwarnings(state) static PyObject *py_setwarnings(PyObject *self, PyObject *args) { + clear_error_msg(); + if (!PyArg_ParseTuple(args, "i", &gpio_warnings)) return NULL; @@ -552,56 +593,62 @@ static PyObject *py_gpio_base(PyObject *self, PyObject *args) unsigned int 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); return py_value; } // Internal unit tests -extern int num_get_xio_base; extern pins_t pins_info[]; static PyObject *py_selftest(PyObject *self, PyObject *args) { int input; + + clear_error_msg(); + if (!PyArg_ParseTuple(args, "i", &input)) return NULL; printf("Testing get_xio_base\n"); - ASSRT(num_get_xio_base == 0); - int base = get_xio_base(); ASSRT(base > 0 && base < 1024); - ASSRT(num_get_xio_base == 1); - 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); + int first_base = get_xio_base(); ASSRT(first_base > 0); + int second_base = get_xio_base(); ASSRT(second_base == first_base); + printf("base=%d\n", first_base); 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(47 == lookup_gpio_by_key("U13_11")); - ASSRT(base == lookup_gpio_by_key("U14_13")); - ASSRT((base+1) == lookup_gpio_by_key("U14_14")); - ASSRT((base+6) == lookup_gpio_by_key("U14_19")); - ASSRT((base+7) == lookup_gpio_by_key("U14_20")); + ASSRT(first_base == lookup_gpio_by_key("U14_13")); + ASSRT((first_base+1) == lookup_gpio_by_key("U14_14")); + ASSRT((first_base+6) == lookup_gpio_by_key("U14_19")); + ASSRT((first_base+7) == lookup_gpio_by_key("U14_20")); ASSRT(193 == lookup_gpio_by_key("U14_23")); ASSRT(139 == lookup_gpio_by_key("U14_38")); - ASSRT(0 == lookup_gpio_by_key("U14_40")); - ASSRT(0 == lookup_gpio_by_key("NOTFOUND")); - ASSRT(0 == lookup_gpio_by_key("U14_")); - ASSRT(0 == lookup_gpio_by_key("U14_4000")); + ASSRT(-1 == lookup_gpio_by_key("U14_40")); + ASSRT(-1 == lookup_gpio_by_key("NOTFOUND")); + ASSRT(-1 == lookup_gpio_by_key("U14_")); + ASSRT(-1 == lookup_gpio_by_key("U14_4000")); 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(47 == lookup_gpio_by_name("TWI1-SCK")); - ASSRT(base == lookup_gpio_by_name("XIO-P0")); - ASSRT((base+6) == lookup_gpio_by_name("XIO-P6")); - ASSRT((base+7) == lookup_gpio_by_name("XIO-P7")); + ASSRT(first_base == lookup_gpio_by_name("XIO-P0")); + ASSRT((first_base+6) == lookup_gpio_by_name("XIO-P6")); + ASSRT((first_base+7) == lookup_gpio_by_name("XIO-P7")); ASSRT(139 == lookup_gpio_by_name("CSID7")); - ASSRT(0 == lookup_gpio_by_name("NOTFOUND")); - ASSRT(0 == lookup_gpio_by_name("CSID")); - ASSRT(0 == lookup_gpio_by_name("CSID777")); + ASSRT(-1 == lookup_gpio_by_name("NOTFOUND")); + ASSRT(-1 == lookup_gpio_by_name("CSID")); + ASSRT(-1 == lookup_gpio_by_name("CSID777")); printf("Testing lookup_ain_by_key\n"); 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(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; PyObject *py_value = Py_BuildValue("i", value); @@ -704,6 +771,8 @@ PyMODINIT_FUNC initGPIO(void) { PyObject *module = NULL; + clear_error_msg(); + #if PY_MAJOR_VERSION > 2 if ((module = PyModule_Create(&rpigpiomodule)) == NULL) return NULL; diff --git a/test/.ropeproject/config.py b/test/.ropeproject/config.py new file mode 100644 index 0000000..3745e30 --- /dev/null +++ b/test/.ropeproject/config.py @@ -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! diff --git a/test/.ropeproject/globalnames b/test/.ropeproject/globalnames new file mode 100644 index 0000000..370cd7a --- /dev/null +++ b/test/.ropeproject/globalnames @@ -0,0 +1,2 @@ +€}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 TestGPIOInputq eUgptest]q (UfU loopfunctionqU num_callbacksqUedgeqUgfileqUtUbaseqUexqUloopfunction_exitqU myfuncallbackqUnum_errsqeu. \ No newline at end of file diff --git a/test/.ropeproject/history b/test/.ropeproject/history new file mode 100644 index 0000000..fcd9c96 --- /dev/null +++ b/test/.ropeproject/history @@ -0,0 +1 @@ +€]q(]q]qe. \ No newline at end of file diff --git a/test/.ropeproject/objectdb b/test/.ropeproject/objectdb new file mode 100644 index 0000000..29c40cd --- /dev/null +++ b/test/.ropeproject/objectdb @@ -0,0 +1 @@ +€}q. \ No newline at end of file diff --git a/test/gptest.py b/test/gptest.py index 886bbef..1bc6b50 100755 --- a/test/gptest.py +++ b/test/gptest.py @@ -42,7 +42,7 @@ if (GPIO.input("XIO-P0") != GPIO.HIGH): num_errs += 1 GPIO.cleanup() -GPIO.setup("XIO-P0", GPIO.IN) +GPIO.setup("U14_13", GPIO.IN) # XIO-P0 GPIO.setup("CSID0", GPIO.OUT, initial=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." @@ -51,7 +51,7 @@ if (GPIO.input("XIO-P0") != GPIO.LOW): GPIO.cleanup() GPIO.setup("XIO-P0", GPIO.IN) -GPIO.setup("CSID0", GPIO.OUT) +GPIO.setup("U14_31", GPIO.OUT) # CSID0 # VERIFY SIMPLE FUNCTIONALITY print "VERIFY SIMPLE FUNCTIONALITY" @@ -66,7 +66,7 @@ assert(GPIO.input("XIO-P0") == GPIO.LOW) # ============================================== # 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) print "adding event detect" GPIO.add_event_detect("AP-EINT1", GPIO.RISING) @@ -75,13 +75,12 @@ print "VERIFYING EDGE DETECT" f = open("/sys/class/gpio/gpio193/edge", "r") edge = f.read() f.close() -print "edge='", edge, "'" assert(edge == "rising\n") GPIO.remove_event_detect("AP-EINT1") # ============================================== # 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.add_event_detect("AP-EINT3", GPIO.BOTH) @@ -89,13 +88,12 @@ print "VERIFYING EDGE DETECT" f = open("/sys/class/gpio/gpio35/edge", "r") edge = f.read() f.close() -print "EDGE: %s" % edge assert(edge == "both\n") GPIO.remove_event_detect("AP-EINT3") # ============================================== # 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) print "VERIFYING EDGE DETECT" @@ -104,7 +102,6 @@ gfile = "/sys/class/gpio/gpio%d/edge" % base f = open(gfile, "r") edge = f.read() f.close() -print "EDGE: %s" % edge assert(edge == "falling\n") # LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK @@ -134,14 +131,60 @@ GPIO.setup("CSID1", GPIO.IN) try: GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback) 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 print "TESTING ERRORS THROWN WHEN WRITING TO A GPIO WITH NO DIRECTION" try: GPIO.output("CSID1", GPIO.LOW) 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 print "CLEANUP"