1
0
mirror of https://github.com/xtacocorex/CHIP_IO synced 2025-07-19 12:23:22 +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},
{ "GND", "U14_39", 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 */
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);
ASSRT(s == input_line && strlen(input_line) < sizeof(input_line)-1);
s = fgets(input_line, sizeof(input_line), base_fp); BUF2SMALL(input_line); ASSRT(s);
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 */
}
} /* 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);
if (dp != NULL) {
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);
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;
}
}
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
#define ASSRT(cond_expr) do { \
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); \
abort(); \
} } while (0)
@ -75,6 +75,7 @@ int setup_error;
int module_setup;
int get_xio_base(void);
int gpio_number(pins_t *pin);
int lookup_gpio_by_key(const char *key);
int lookup_gpio_by_name(const char *name);
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 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);

View File

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

View File

@ -45,7 +45,7 @@ SOFTWARE.
static int gpio_warnings = 1;
int max_gpio = -1;
int *gpio_direction = NULL;
void *gpio_direction = NULL;
struct py_callback
{
@ -60,26 +60,15 @@ static struct py_callback *py_callbacks = NULL;
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;
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? */
max_gpio = gpio + (gpio / 2);
gpio_direction = (int *)realloc(gpio_direction, max_gpio * sizeof(int));
}
gpio_direction[gpio] = direction;
dyn_int_array_set(&gpio_direction, gpio, direction, -1);
}
// python function cleanup()
@ -124,21 +113,23 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar
return NULL;
}
if (get_gpio_number(channel, &gpio))
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);
}
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_ValueError, "Invalid value for channel");
return NULL;
}
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;
}
@ -153,16 +144,22 @@ static PyObject *py_output_gpio(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "si", &channel, &value))
return NULL;
if (get_gpio_number(channel, &gpio))
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
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");
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;
}
@ -178,11 +175,13 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s", &channel))
return NULL;
if (get_gpio_number(channel, &gpio))
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// 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");
return NULL;
@ -282,8 +281,10 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
return NULL;
}
if (get_gpio_number(channel, &gpio))
return NULL;
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins
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
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");
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");
return NULL;
}
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
return NULL;
@ -331,8 +331,10 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
return NULL;
}
if (get_gpio_number(channel, &gpio))
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins
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
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");
return NULL;
@ -387,8 +389,10 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s", &channel))
return NULL;
if (get_gpio_number(channel, &gpio))
return NULL;
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins
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))
return NULL;
if (get_gpio_number(channel, &gpio))
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
if (event_detected(gpio))
Py_RETURN_TRUE;
@ -451,8 +457,10 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "si", &channel, &edge))
return NULL;
if (get_gpio_number(channel, &gpio))
return NULL;
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
// check to ensure gpio is one of the allowed pins
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
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");
return NULL;
@ -507,8 +515,10 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s", &channel))
return NULL;
if (get_gpio_number(channel, &gpio))
if (get_gpio_number(channel, &gpio)) {
PyErr_SetString(PyExc_RuntimeError, "Invalid channel");
return NULL;
}
if (setup_error)
{
@ -538,17 +548,105 @@ static PyObject *py_setwarnings(PyObject *self, PyObject *args)
// Internal unit tests
extern int num_get_xio_base;
extern pins_t pins_info[];
static PyObject *py_selftest(PyObject *self, PyObject *args)
{
int input;
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);
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;

View File

@ -32,13 +32,13 @@ SOFTWARE.
#include "Python.h"
#include "constants.h"
#include "common.h"
#include "c_softpwm.h"
#include "c_softpwm.h"
// python function cleanup()
static PyObject *py_cleanup(PyObject *self, PyObject *args)
{
// unexport the PWM
softpwm_cleanup();
softpwm_cleanup();
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)
{
char key[8];
char *channel;
char *channel = NULL;
float frequency = 2000.0;
float duty_cycle = 0.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)) {
return NULL;
}
ASSRT(channel != NULL);
if (!get_key(channel, key)) {
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;
}
if (!softpwm_start(key, duty_cycle, frequency, polarity))
if (!softpwm_start(key, duty_cycle, frequency, polarity))
return NULL;
Py_RETURN_NONE;
@ -94,12 +95,12 @@ static PyObject *py_stop_channel(PyObject *self, PyObject *args, PyObject *kwarg
if (!PyArg_ParseTuple(args, "s", &channel))
return NULL;
if (!get_key(channel, key)) {
if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
return NULL;
}
softpwm_disable(key);
softpwm_disable(key);
Py_RETURN_NONE;
}
@ -121,12 +122,12 @@ static PyObject *py_set_duty_cycle(PyObject *self, PyObject *args, PyObject *kwa
return NULL;
}
if (!get_key(channel, key)) {
if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
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");
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))
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;
}
if (!get_key(channel, key)) {
if (!get_key(channel, key)) {
PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name.");
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
import CHIP_IO.GPIO as GPIO
import time, os, threading
import time
import threading
num_callbacks = 0
def myfuncallback(channel):
global num_callbacks
num_callbacks += 1
print "CALLBACK LIKE DRAKE IN HOTLINE BLING"
loopfunction_exit = False
def loopfunction():
print "LOOP FUNCTION"
for i in xrange(20):
for i in xrange(4):
if loopfunction_exit:
break
if i % 2:
print "SETTING CSID0 LOW"
GPIO.output("CSID0",GPIO.LOW)
print "SETTING CSID0 LOW (i=", i, ")"
GPIO.output("CSID0", GPIO.LOW)
else:
print "SETTING CSID0 HIGH"
GPIO.output("CSID0",GPIO.HIGH)
print "SETTING CSID0 HIGH (i=", i, ")"
GPIO.output("CSID0", GPIO.HIGH)
print "SLEEPING"
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)
# VERIFY SIMPLE FUNCTIONALITY
@ -29,51 +51,57 @@ print "VERIFY SIMPLE FUNCTIONALITY"
print "READING XIO-PI"
GPIO.output("CSID0", GPIO.HIGH)
print "HIGH", GPIO.input("XIO-P0")
assert(GPIO.input("XIO-P0") == GPIO.HIGH)
GPIO.output("CSID0", GPIO.LOW)
print "LOW", GPIO.input("XIO-P0")
assert(GPIO.input("XIO-P0") == GPIO.LOW)
# ==============================================
# EDGE DETECTION - AP-EINT1
print "SETTING UP EDGE DETECTION ON AP-EINT1"
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"
f = open("/sys/class/gpio/gpio193/edge","r")
f = open("/sys/class/gpio/gpio193/edge", "r")
edge = f.read()
f.close()
print "EDGE: %s" % edge
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"
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"
f = open("/sys/class/gpio/gpio35/edge","r")
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"
GPIO.add_event_detect("XIO-P0",GPIO.FALLING,myfuncallback)
GPIO.add_event_detect("XIO-P0", GPIO.FALLING, myfuncallback)
print "VERIFYING EDGE DETECT"
f = open("/sys/class/gpio/gpio408/edge","r")
f = open("/sys/class/gpio/gpio408/edge", "r")
edge = f.read()
f.close()
print "EDGE: %s" % edge
assert(edge == "falling\n")
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
print "WAITING FOR CALLBACKS"
loopfunction()
print "num_callbacks=", num_callbacks
print "PRESS CONTROL-C TO EXIT IF SCRIPT GETS STUCK"
GPIO.remove_event_detect("XIO-P0")
@ -82,18 +110,30 @@ try:
t = threading.Thread(target=loopfunction)
t.start()
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 "ATTEMPTING TO CANCEL THE TIMER"
t.cancel()
except:
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"
GPIO.setup("CSID1",GPIO.IN)
GPIO.add_event_detect("CSID1",GPIO.FALLING,myfuncallback)
GPIO.setup("CSID1", GPIO.IN)
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"
GPIO.remove_event_detect("XIO-P0")
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