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

Reworked a lot of error handling.

This commit is contained in:
fordsfords
2016-07-02 18:57:03 -05:00
parent 093922567a
commit 71b6829804
11 changed files with 442 additions and 104 deletions

View File

@ -131,7 +131,7 @@ pins_t pins_info[] = {
{ "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", 0, BASE_METHOD_AS_IS, -1, -1},
{ "GND", "U14_40", 0, BASE_METHOD_AS_IS, -1, -1}, { "GND", "U14_40", 0, BASE_METHOD_AS_IS, -1, -1},
{ NULL, NULL, 0 } { NULL, NULL, 0, 0, -1, -1}
}; };
@ -178,10 +178,10 @@ int get_xio_base(void)
/* 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"); ASSRT(base_fp != NULL);
s = fgets(input_line, sizeof(input_line), base_fp); s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line); ASSRT(s);
ASSRT(s == input_line && strlen(input_line) < sizeof(input_line)-1);
fclose(base_fp); fclose(base_fp);
xio_base_address = atoi(input_line); /* remember the result */ /* 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 */ num_get_xio_base++; /* for self-test purposes */
} }
} /* if label file is open */ } /* if label file is open */
@ -377,7 +377,7 @@ int build_path(const char *partial_path, const char *prefix, char *full_path, si
dp = opendir (partial_path); dp = opendir (partial_path);
if (dp != NULL) { if (dp != NULL) {
while ((ep = readdir (dp))) { while ((ep = readdir (dp))) {
// Enforce that the prefix must be the first part of the file // Enforce that the prefix must be the first part of the file name
char* found_string = strstr(ep->d_name, prefix); char* found_string = strstr(ep->d_name, prefix);
if (found_string != NULL && (ep->d_name - found_string) == 0) { if (found_string != NULL && (ep->d_name - found_string) == 0) {
@ -419,3 +419,75 @@ int get_spi_bus_path_number(unsigned int spi)
return -1; return -1;
} }
} }
struct dyn_int_array {
int num_elements;
int *array;
};
void *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);
new_array->num_elements = initial_num_elements;
new_array->array = (int *)malloc(initial_num_elements * sizeof(int));
ASSRT(new_array->array != NULL);
int i;
for (i = 0; i < initial_num_elements; i++)
new_array->array[i] = initial_val;
return (void *)new_array;
} /* dyn_int_array_create */
void dyn_int_array_set(void **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);
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);
// Zero out the newly allocated elements.
while (array->num_elements < new_num_elements) {
array->array[array->num_elements] = initial_val;
array->num_elements ++;
}
}
array->array[i] = val;
*in_array = (void *)array;
} /* dyn_int_array_set */
int dyn_int_array_get(void **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);
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);
// Zero out the newly allocated elements.
while (array->num_elements < new_num_elements) {
array->array[array->num_elements] = initial_val;
array->num_elements ++;
}
}
return array->array[i];
*in_array = (void *)array;
} /* dyn_int_array_get */
void dyn_int_array_delete(void **in_array)
{
struct dyn_int_array *array = (struct dyn_int_array *)(*in_array);
free(array->array);
free(array);
} /* dyn_int_array_delete */

View File

@ -41,7 +41,7 @@ SOFTWARE.
// See http://blog.geeky-boy.com/2016/06/of-compiler-warnings-and-asserts-in.html // See http://blog.geeky-boy.com/2016/06/of-compiler-warnings-and-asserts-in.html
#define ASSRT(cond_expr) do { \ #define ASSRT(cond_expr) do { \
if (!(cond_expr)) { \ if (!(cond_expr)) { \
fprintf(stderr, "ASSRT failed at %s:%d (%s)", __FILE__, __LINE__, #cond_expr); \ fprintf(stderr, "ASSRT failed at %s:%d (%s)\n", __FILE__, __LINE__, #cond_expr); \
fflush(stderr); \ fflush(stderr); \
abort(); \ abort(); \
} } while (0) } } while (0)
@ -75,6 +75,7 @@ int setup_error;
int module_setup; int module_setup;
int get_xio_base(void); int get_xio_base(void);
int gpio_number(pins_t *pin);
int lookup_gpio_by_key(const char *key); int lookup_gpio_by_key(const char *key);
int lookup_gpio_by_name(const char *name); int lookup_gpio_by_name(const char *name);
int lookup_ain_by_key(const char *key); int lookup_ain_by_key(const char *key);
@ -89,3 +90,6 @@ 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);
int dyn_int_array_get(void **in_array, int i, int initial_val);
void dyn_int_array_delete(void **in_array);

View File

@ -77,7 +77,7 @@ struct gpio_exp
struct gpio_exp *exported_gpios = NULL; struct gpio_exp *exported_gpios = NULL;
pthread_t threads; pthread_t threads;
int event_occurred[430] = { 0 }; void *event_occurred = NULL;
int thread_running = 0; int thread_running = 0;
int epfd = -1; int epfd = -1;
@ -92,8 +92,12 @@ int gpio_export(unsigned int gpio)
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);
close(fd); close(fd);
if (s != len)
{
return -1;
}
// add to list // add to list
new_gpio = malloc(sizeof(struct gpio_exp)); new_gpio = malloc(sizeof(struct gpio_exp));
@ -183,8 +187,9 @@ int open_value_file(unsigned int gpio)
// create file descriptor of value file // create file descriptor of value file
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) {
return -1; return -1;
}
add_fd_list(gpio, fd); add_fd_list(gpio, fd);
return fd; return fd;
} }
@ -240,7 +245,6 @@ int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
} 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)); ASSRT(s == strlen(direction));
close(fd); close(fd);
return 0; return 0;
@ -285,8 +289,11 @@ 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)); ASSRT(s == strlen(vstr)); ssize_t s = write(fd, vstr, strlen(vstr));
close(fd); close(fd);
if (s != strlen(vstr))
return -2;
return 0; return 0;
} }
@ -454,11 +461,12 @@ void *poll_thread(void *threadarg)
thread_running = 0; thread_running = 0;
pthread_exit(NULL); pthread_exit(NULL);
} }
// The return value represents the ending level after the edge.
gpio = gpio_lookup(events.data.fd); gpio = gpio_lookup(events.data.fd);
if (gpio_initial(gpio)) { // ignore first epoll trigger if (gpio_initial(gpio)) { // ignore first epoll trigger
set_initial_false(gpio); set_initial_false(gpio);
} else { } else {
event_occurred[gpio] = 1; dyn_int_array_set(&event_occurred, gpio, 1, 0);
run_callbacks(gpio); run_callbacks(gpio);
} }
} }
@ -512,6 +520,7 @@ int gpio_event_remove(unsigned int gpio)
return 0; return 0;
} }
// 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(unsigned int gpio, unsigned int edge)
// return values: // return values:
// 0 - Success // 0 - Success
@ -528,31 +537,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_export(gpio);
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) {
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)) {
return 2; return 2;
}
// 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) {
return 2; return 2;
}
// start poll thread if it is not already running // start poll thread if it is not already running
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) {
return 2; return 2;
}
} }
return 0; return 0;
@ -576,13 +588,13 @@ void remove_edge_detect(unsigned int gpio)
gpio_event_remove(gpio); gpio_event_remove(gpio);
// clear detected flag // clear detected flag
event_occurred[gpio] = 0; dyn_int_array_set(&event_occurred, gpio, 0, 0);
} }
int event_detected(unsigned int gpio) int event_detected(unsigned int gpio)
{ {
if (event_occurred[gpio]) { if (dyn_int_array_get(&event_occurred, gpio, 0)) {
event_occurred[gpio] = 0; dyn_int_array_set(&event_occurred, gpio, 0, 0);
return 1; return 1;
} else { } else {
return 0; return 0;
@ -612,7 +624,7 @@ int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
return 2; return 2;
// export /sys/class/gpio interface // export /sys/class/gpio interface
gpio_export(gpio); 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);

View File

@ -45,7 +45,7 @@ SOFTWARE.
static int gpio_warnings = 1; static int gpio_warnings = 1;
int max_gpio = -1; int max_gpio = -1;
int *gpio_direction = NULL; void *gpio_direction = NULL;
struct py_callback struct py_callback
{ {
@ -60,26 +60,15 @@ static struct py_callback *py_callbacks = NULL;
static int init_module(void) static int init_module(void)
{ {
int i;
max_gpio = 1024;
gpio_direction = (int *)malloc(max_gpio * sizeof(int));
for (i=0; i<max_gpio; i++)
gpio_direction[i] = -1;
module_setup = 1; module_setup = 1;
return 0; return 0;
} }
static void set_gpio_direction(int gpio, int direction) static void remember_gpio_direction(int gpio, int direction)
{ {
if (gpio >= max_gpio) { /* Does gpio_direction need to be expanded? */ dyn_int_array_set(&gpio_direction, gpio, direction, -1);
max_gpio = gpio + (gpio / 2);
gpio_direction = (int *)realloc(gpio_direction, max_gpio * sizeof(int));
}
gpio_direction[gpio] = direction;
} }
// python function cleanup() // python function cleanup()
@ -124,21 +113,23 @@ 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)) {
return NULL; PyErr_SetString(PyExc_ValueError, "Invalid value for channel");
return NULL;
gpio_export(gpio);
gpio_set_direction(gpio, direction);
// For some reason, the following code doesn't work for XIOs. Skip.
if (!(gpio >= lookup_gpio_by_name("XIO-P0") && gpio <= lookup_gpio_by_name("XIO-P7"))) {
if (direction == OUTPUT) {
gpio_set_value(gpio, initial);
} else {
gpio_set_value(gpio, pud);
}
} }
set_gpio_direction(gpio, direction); int result = gpio_export(gpio);
if (result < 0) {
PyErr_SetString(PyExc_ValueError, "Channel in use (already exported)");
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);
}
remember_gpio_direction(gpio, direction);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -153,16 +144,22 @@ static PyObject *py_output_gpio(PyObject *self, PyObject *args)
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");
return NULL; return NULL;
}
if (!module_setup || gpio_direction[gpio] != OUTPUT) if (!module_setup || dyn_int_array_get(&gpio_direction, gpio, -1) != OUTPUT)
{ {
PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been setup() as an OUTPUT"); PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been setup() as an OUTPUT");
return NULL; return NULL;
} }
gpio_set_value(gpio, value); int result = gpio_set_value(gpio, value);
if (result < 0) {
PyErr_SetString(PyExc_RuntimeError, "Could not write to channel");
return NULL;
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -178,11 +175,13 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args)
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");
return NULL; return NULL;
}
// check channel is set up as an input or output // check channel is set up as an input or output
if (!module_setup || (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT)) if (!module_setup || (dyn_int_array_get(&gpio_direction, gpio, -1) == -1))
{ {
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first"); PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first");
return NULL; return NULL;
@ -282,8 +281,10 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
return NULL; return NULL;
} }
if (get_gpio_number(channel, &gpio)) if (get_gpio_number(channel, &gpio)) {
return NULL; PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins // check to ensure gpio is one of the allowed pins
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
@ -294,7 +295,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
} }
// check channel is set up as an input // check channel is set up as an input
if (!module_setup || gpio_direction[gpio] != 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"); PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL; return NULL;
@ -305,7 +306,6 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback"); PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback");
return NULL; return NULL;
} }
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0) if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
return NULL; return NULL;
@ -331,8 +331,10 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
return NULL; return NULL;
} }
if (get_gpio_number(channel, &gpio)) if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL; return NULL;
}
// check to ensure gpio is one of the allowed pins // check to ensure gpio is one of the allowed pins
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
@ -343,7 +345,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
} }
// check channel is set up as an input // check channel is set up as an input
if (!module_setup || gpio_direction[gpio] != 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"); PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL; return NULL;
@ -387,8 +389,10 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
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)) {
return NULL; PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins // check to ensure gpio is one of the allowed pins
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
@ -431,8 +435,10 @@ static PyObject *py_event_detected(PyObject *self, PyObject *args)
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");
return NULL; return NULL;
}
if (event_detected(gpio)) if (event_detected(gpio))
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -451,8 +457,10 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
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)) {
return NULL; PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins // check to ensure gpio is one of the allowed pins
if (gpio != lookup_gpio_by_name("AP-EINT3") if (gpio != lookup_gpio_by_name("AP-EINT3")
@ -463,7 +471,7 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
} }
// check channel is setup as an input // check channel is setup as an input
if (!module_setup || gpio_direction[gpio] != 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"); PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
return NULL; return NULL;
@ -507,8 +515,10 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args)
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");
return NULL; return NULL;
}
if (setup_error) if (setup_error)
{ {
@ -538,17 +548,105 @@ static PyObject *py_setwarnings(PyObject *self, PyObject *args)
// Internal unit tests // Internal unit tests
extern int num_get_xio_base; extern int num_get_xio_base;
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;
if (!PyArg_ParseTuple(args, "i", &input)) if (!PyArg_ParseTuple(args, "i", &input))
return NULL; return NULL;
printf("Testing get_xio_base\n");
ASSRT(num_get_xio_base == 0); ASSRT(num_get_xio_base == 0);
int base = get_xio_base(); ASSRT(base > 0 && base < 1024); int base = get_xio_base(); ASSRT(base > 0 && base < 1024);
ASSRT(num_get_xio_base == 1); ASSRT(num_get_xio_base == 1);
int second_base = get_xio_base(); ASSRT(second_base == 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. */ 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");
ASSRT(0 == 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(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"));
printf("Testing lookup_gpio_by_name\n");
ASSRT(0 == 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(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"));
printf("Testing lookup_ain_by_key\n");
ASSRT(-1 == lookup_ain_by_key("U14_1"));
ASSRT(0 == lookup_ain_by_key("U14_11"));
ASSRT(-1 == lookup_ain_by_key("NOTFOUND"));
ASSRT(-1 == lookup_ain_by_key("U14_"));
ASSRT(-1 == lookup_ain_by_key("U14_1111"));
printf("Testing lookup_ain_by_name\n");
ASSRT(-1 == lookup_ain_by_name("GND"));
ASSRT(0 == lookup_ain_by_name("LRADC"));
ASSRT(-1 == lookup_ain_by_name("NOTFOUND"));
ASSRT(-1 == lookup_ain_by_name("LR"));
ASSRT(-1 == lookup_ain_by_name("LRADCCC"));
char k[9];
printf("Testing copy_key_by_key\n");
ASSRT(1 == copy_key_by_key("U13_1", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U13_1", k));
ASSRT(1 == copy_key_by_key("U14_40", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U14_40", k));
ASSRT(0 == copy_key_by_key("NOTFOUND", k));
ASSRT(0 == copy_key_by_key("U14_", k));
ASSRT(0 == copy_key_by_key("U14_4000", k));
printf("Testing copy_pwm_key_by_key\n");
ASSRT(1 == copy_pwm_key_by_key("U13_18", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U13_18", k));
ASSRT(0 == copy_pwm_key_by_key("U13_1", k));
ASSRT(0 == copy_pwm_key_by_key("U14_40", k));
ASSRT(0 == copy_pwm_key_by_key("NOTFOUND", k));
ASSRT(0 == copy_pwm_key_by_key("U13_", k));
ASSRT(0 == copy_pwm_key_by_key("U13_1888", k));
printf("Testing get_key_by_name\n");
ASSRT(1 == get_key_by_name("GND", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U13_1", k));
ASSRT(1 == get_key_by_name("CSID7", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U14_38", k));
ASSRT(0 == get_key_by_name("NOTFOUND", k));
ASSRT(0 == get_key_by_name("CSID", k));
ASSRT(0 == get_key_by_name("CSID777", k));
printf("Testing get_pwm_key_by_name\n");
ASSRT(1 == get_pwm_key_by_name("PWM0", k)); BUF2SMALL(k); ASSRT(0 == strcmp("U13_18", k));
ASSRT(0 == get_pwm_key_by_name("NOTFOUND", k));
ASSRT(0 == get_pwm_key_by_name("PWM", k));
ASSRT(0 == get_pwm_key_by_name("PWM000", k));
char fp[80];
printf("Testing build_path\n");
ASSRT(1 == build_path("/home", "ch", fp, sizeof(fp))); ASSRT(0 == strcmp("/home/chip", fp));
ASSRT(1 == build_path("/home", "chip", fp, sizeof(fp))); ASSRT(0 == strcmp("/home/chip", fp));
ASSRT(0 == build_path("/home", "NOTFOUND", fp, sizeof(fp)));
ASSRT(0 == build_path("/home", "chipp", fp, sizeof(fp)));
ASSRT(0 == build_path("/home", "ip", fp, sizeof(fp)));
ASSRT(0 == build_path("/NOTFOUND", "ch", fp, sizeof(fp)));
printf("Testing get_spi_bus_path_number\n");
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 */
int value = input; int value = input;

View File

@ -32,13 +32,13 @@ SOFTWARE.
#include "Python.h" #include "Python.h"
#include "constants.h" #include "constants.h"
#include "common.h" #include "common.h"
#include "c_softpwm.h" #include "c_softpwm.h"
// python function cleanup() // python function cleanup()
static PyObject *py_cleanup(PyObject *self, PyObject *args) static PyObject *py_cleanup(PyObject *self, PyObject *args)
{ {
// unexport the PWM // unexport the PWM
softpwm_cleanup(); softpwm_cleanup();
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -47,7 +47,7 @@ static PyObject *py_cleanup(PyObject *self, PyObject *args)
static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwargs) static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
char key[8]; char key[8];
char *channel; char *channel = NULL;
float frequency = 2000.0; float frequency = 2000.0;
float duty_cycle = 0.0; float duty_cycle = 0.0;
int polarity = 0; int polarity = 0;
@ -56,6 +56,7 @@ static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwar
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ffi", kwlist, &channel, &duty_cycle, &frequency, &polarity)) { if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ffi", kwlist, &channel, &duty_cycle, &frequency, &polarity)) {
return NULL; return NULL;
} }
ASSRT(channel != NULL);
if (!get_key(channel, key)) { if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid SOFTPWM key or name."); PyErr_SetString(PyExc_ValueError, "Invalid SOFTPWM key or name.");
@ -79,7 +80,7 @@ static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwar
return NULL; return NULL;
} }
if (!softpwm_start(key, duty_cycle, frequency, polarity)) if (!softpwm_start(key, duty_cycle, frequency, polarity))
return NULL; return NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
@ -94,12 +95,12 @@ static PyObject *py_stop_channel(PyObject *self, PyObject *args, PyObject *kwarg
if (!PyArg_ParseTuple(args, "s", &channel)) if (!PyArg_ParseTuple(args, "s", &channel))
return NULL; return NULL;
if (!get_key(channel, key)) { if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name."); PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
return NULL; return NULL;
} }
softpwm_disable(key); softpwm_disable(key);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -121,12 +122,12 @@ static PyObject *py_set_duty_cycle(PyObject *self, PyObject *args, PyObject *kwa
return NULL; return NULL;
} }
if (!get_key(channel, key)) { if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name."); PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
return NULL; return NULL;
} }
if (softpwm_set_duty_cycle(key, duty_cycle) == -1) { if (softpwm_set_duty_cycle(key, duty_cycle) == -1) {
PyErr_SetString(PyExc_RuntimeError, "You must start() the PWM channel first"); PyErr_SetString(PyExc_RuntimeError, "You must start() the PWM channel first");
return NULL; return NULL;
} }
@ -145,13 +146,13 @@ static PyObject *py_set_frequency(PyObject *self, PyObject *args, PyObject *kwar
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|f", kwlist, &channel, &frequency)) if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|f", kwlist, &channel, &frequency))
return NULL; return NULL;
if ((frequency <= 0.0) || (frequency > 10000.0)) if ((frequency <= 0.0) || (frequency > 10000.0))
{ {
PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0 and less than 10000.0"); PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0 and less than 10000.0");
return NULL; return NULL;
} }
if (!get_key(channel, key)) { if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name."); PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
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,5 @@
<EFBFBD>}qUS/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py}q(U
Thread._blockcrope.base.oi.memorydb
ScopeInfo
q)<29>q}qUinstanceqUdefinedqUS/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyUThreadq<08><><EFBFBD>hhUS/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyU
_Conditionq <09><>s}q

View File

@ -1,27 +1,49 @@
#!/usr/bin/python #!/usr/bin/python
import CHIP_IO.GPIO as GPIO import CHIP_IO.GPIO as GPIO
import time, os, threading import time
import threading
num_callbacks = 0
def myfuncallback(channel): def myfuncallback(channel):
global num_callbacks
num_callbacks += 1
print "CALLBACK LIKE DRAKE IN HOTLINE BLING" print "CALLBACK LIKE DRAKE IN HOTLINE BLING"
loopfunction_exit = False
def loopfunction(): def loopfunction():
print "LOOP FUNCTION" print "LOOP FUNCTION"
for i in xrange(20): for i in xrange(4):
if loopfunction_exit:
break
if i % 2: if i % 2:
print "SETTING CSID0 LOW" print "SETTING CSID0 LOW (i=", i, ")"
GPIO.output("CSID0",GPIO.LOW) GPIO.output("CSID0", GPIO.LOW)
else: else:
print "SETTING CSID0 HIGH" print "SETTING CSID0 HIGH (i=", i, ")"
GPIO.output("CSID0",GPIO.HIGH) GPIO.output("CSID0", GPIO.HIGH)
print "SLEEPING" print "SLEEPING"
time.sleep(1) time.sleep(1)
print "SETUP XIO-P0"
GPIO.setup("XIO-P0", GPIO.IN)
print "SETUP CSID0"
GPIO.selftest(0)
GPIO.setup("XIO-P0", GPIO.IN)
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.HIGH)
assert(GPIO.input("XIO-P0") == GPIO.HIGH)
GPIO.cleanup()
GPIO.setup("XIO-P0", GPIO.IN)
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW)
assert(GPIO.input("XIO-P0") == GPIO.LOW)
GPIO.cleanup()
GPIO.setup("XIO-P0", GPIO.IN)
GPIO.setup("CSID0", GPIO.OUT) GPIO.setup("CSID0", GPIO.OUT)
# VERIFY SIMPLE FUNCTIONALITY # VERIFY SIMPLE FUNCTIONALITY
@ -29,51 +51,57 @@ print "VERIFY SIMPLE FUNCTIONALITY"
print "READING XIO-PI" print "READING XIO-PI"
GPIO.output("CSID0", GPIO.HIGH) GPIO.output("CSID0", GPIO.HIGH)
print "HIGH", GPIO.input("XIO-P0") assert(GPIO.input("XIO-P0") == GPIO.HIGH)
GPIO.output("CSID0", GPIO.LOW) GPIO.output("CSID0", GPIO.LOW)
print "LOW", GPIO.input("XIO-P0") print "LOW", GPIO.input("XIO-P0")
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 EDGE DETECTION ON AP-EINT1"
GPIO.setup("AP-EINT1", GPIO.IN) GPIO.setup("AP-EINT1", GPIO.IN)
GPIO.add_event_detect("AP-EINT1",GPIO.FALLING) print "adding event detect"
GPIO.add_event_detect("AP-EINT1", GPIO.RISING)
print "VERIFYING EDGE DETECT" 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: %s" % edge print "edge='", edge, "'"
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 EDGE DETECTION ON AP-EINT3"
GPIO.setup("AP-EINT3", GPIO.IN) GPIO.setup("AP-EINT3", GPIO.IN)
GPIO.add_event_detect("AP-EINT3",GPIO.FALLING) GPIO.add_event_detect("AP-EINT3", GPIO.BOTH)
print "VERIFYING EDGE DETECT" 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 print "EDGE: %s" % edge
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 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"
f = open("/sys/class/gpio/gpio408/edge","r") f = open("/sys/class/gpio/gpio408/edge", "r")
edge = f.read() edge = f.read()
f.close() f.close()
print "EDGE: %s" % edge print "EDGE: %s" % edge
assert(edge == "falling\n")
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK # LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
print "WAITING FOR CALLBACKS" print "WAITING FOR CALLBACKS"
loopfunction() loopfunction()
print "num_callbacks=", num_callbacks
print "PRESS CONTROL-C TO EXIT IF SCRIPT GETS STUCK" print "PRESS CONTROL-C TO EXIT IF SCRIPT GETS STUCK"
GPIO.remove_event_detect("XIO-P0") GPIO.remove_event_detect("XIO-P0")
@ -82,18 +110,30 @@ try:
t = threading.Thread(target=loopfunction) t = threading.Thread(target=loopfunction)
t.start() t.start()
print "WAITING FOR EDGE" print "WAITING FOR EDGE"
GPIO.wait_for_edge("XIO-P0",GPIO.FALLING) GPIO.wait_for_edge("XIO-P0", GPIO.FALLING)
print "WE'VE FALLEN LIKE COOLIO'S CAREER" print "WE'VE FALLEN LIKE COOLIO'S CAREER"
print "ATTEMPTING TO CANCEL THE TIMER"
t.cancel()
except: except:
pass pass
print "Exit thread"
loopfunction_exit = True
t.join() # Wait till the thread exits.
GPIO.remove_event_detect("XIO-P0")
print "TESTING ERRORS THROWN WHEN SPECIFYING EDGE DETECTION ON UNAUTHORIZED GPIO" print "TESTING ERRORS THROWN WHEN SPECIFYING EDGE DETECTION ON UNAUTHORIZED GPIO"
GPIO.setup("CSID1",GPIO.IN) GPIO.setup("CSID1", GPIO.IN)
GPIO.add_event_detect("CSID1",GPIO.FALLING,myfuncallback) try:
GPIO.add_event_detect("CSID1", GPIO.FALLING, myfuncallback)
print "Oops, it did not throw an exception! BUG!!!"
except:
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:
pass
print "CLEANUP" print "CLEANUP"
GPIO.remove_event_detect("XIO-P0")
GPIO.cleanup() GPIO.cleanup()

7
unexport_all.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
for F in /sys/class/gpio/gpio[0-9]*; do :
GPIO=`echo $F | sed 's/^[^0-9]*//'`
echo $F $GPIO
echo $GPIO >/sys/class/gpio/unexport
done