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

Fixed a bunch of error handling

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

View File

@ -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;