From e7db735a2f8ce14421a9159f658414ea43ae7733 Mon Sep 17 00:00:00 2001 From: Robert Wolterman Date: Wed, 13 Sep 2017 10:35:32 -0500 Subject: [PATCH] GPIO able to be controlled by pin sysfs number like RPi.GPIO, close #65 --- CHANGELOG.rst | 4 + Makefile | 7 +- debian/changelog | 10 ++- debian/files | 4 +- setup.py | 2 +- source/common.c | 33 ++++++- source/common.h | 1 + source/constants.c | 2 +- source/py_gpio.c | 208 ++++++++++++++++++++++++++++++++++++++------- 9 files changed, 231 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c006648..94ded19 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,7 @@ +0.7.0 +--- +* Added ability to specify GPIO only as a number, this doesn't work for PWM/SPWM/LRADC/SERVO + 0.6.2 --- * Implementation for #77 - ability to push up binary pypi diff --git a/Makefile b/Makefile index ec12481..d42bde1 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,13 @@ package: clean python setup.py sdist bdist_wheel python3 setup.py bdist_wheel +# PyPi Packaging +package3: package + @echo " ** PACKAGING FOR PYPI **" + python3 setup.py bdist_wheel + # PyPi Publishing -publish: package +publish: package package3 @echo " ** UPLOADING TO PYPI **" twine upload dist/* diff --git a/debian/changelog b/debian/changelog index 8863d2f..2e9a5f1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,13 @@ +chip-io (0.7.0-1) unstable; urgency=low + + * Added ability to specify GPIO only as a number, this doesn't work for PWM/SPWM/LRADC/SERVO + + -- Robert Wolterman Wed, 13 Sep 2017 09:51:00 -0600 + chip-io (0.6.2-1) unstable; urgency=low - * Implementation for #77 - ability to push up binary pypi - * Implementation for #75 - wait_for_edge timeout + * Implementation for number 77 ability to push up binary pypi + * Implementation for number 75 wait for edge timeout -- Robert Wolterman Sun, 03 Sep 2017 21:34:00 -0600 diff --git a/debian/files b/debian/files index 6b9ae85..432ccd0 100644 --- a/debian/files +++ b/debian/files @@ -1,2 +1,2 @@ -python-chip-io_0.6.1-1_armhf.deb python optional -python3-chip-io_0.6.1-1_armhf.deb python optional +python-chip-io_0.7.0-1_armhf.deb python optional +python3-chip-io_0.7.0-1_armhf.deb python optional diff --git a/setup.py b/setup.py index 185f93e..fbe1ebc 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ classifiers = ['Development Status :: 3 - Alpha', 'Topic :: System :: Hardware'] setup(name = 'CHIP_IO', - version = '0.6.2', + version = '0.7.0', author = 'Robert Wolterman', author_email = 'robert.wolterman@gmail.com', description = 'A module to control CHIP IO channels', diff --git a/source/common.c b/source/common.c index 60b922f..b6ff6f5 100644 --- a/source/common.c +++ b/source/common.c @@ -371,6 +371,28 @@ int gpio_pud_capable(pins_t *pin) return capable; } +int lookup_gpio_by_number(const char *num) { + // Convert the char to an int + char *ptr; + long ret; + int gpnum; + ret = strtol(num, &ptr, 10); + if (ret == 0) { + return -1; + } + // If we make it here, lets look for the data + pins_t *p; + for (p = pins_info; p->key != NULL; ++p) { + gpnum = gpio_number(p); + // If the number of the gpio pin matches the input + // we are + if (gpnum == (int)ret) { + return gpnum; + } + } + return -1; +} + int lookup_gpio_by_key(const char *key) { pins_t *p; @@ -541,10 +563,13 @@ int get_gpio_number(const char *key, int *gpio) if (*gpio <= 0) { *gpio = lookup_gpio_by_name(key); if (*gpio <= 0) { - *gpio = lookup_gpio_by_altname(key); - if (*gpio <=0) { - status = -1; /* error */ - } + *gpio = lookup_gpio_by_altname(key); + if (*gpio <=0) { + *gpio = lookup_gpio_by_number(key); + if (*gpio <= 0) { + status = -1; /* error */ + } + } } } return status; diff --git a/source/common.h b/source/common.h index 58fd9c7..cf8aa08 100644 --- a/source/common.h +++ b/source/common.h @@ -94,6 +94,7 @@ int get_xio_base(void); int is_this_chippro(void); int gpio_number(pins_t *pin); int gpio_pud_capable(pins_t *pin); +int lookup_gpio_by_number(const char *num); int lookup_gpio_by_key(const char *key); int lookup_gpio_by_name(const char *name); int lookup_gpio_by_altname(const char *altname); diff --git a/source/constants.c b/source/constants.c index e7a4ec4..7b8cdc6 100644 --- a/source/constants.c +++ b/source/constants.c @@ -85,6 +85,6 @@ void define_constants(PyObject *module) bcm = Py_BuildValue("i", BCM); PyModule_AddObject(module, "BCM", bcm); - version = Py_BuildValue("s", "0.6.2"); + version = Py_BuildValue("s", "0.7"); PyModule_AddObject(module, "VERSION", version); } diff --git a/source/py_gpio.c b/source/py_gpio.c index 7c0d1ba..ab11565 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -36,6 +36,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include "stdlib.h" #include "Python.h" #include "constants.h" @@ -129,13 +130,23 @@ static PyObject *py_cleanup(PyObject *self, PyObject *args, PyObject *kwargs) { int gpio; char *channel; + int inchan; static char *kwlist[] = {"channel", NULL}; clear_error_msg(); // Channel is optional - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &channel)) { - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); } // The !channel fixes issues #50 @@ -157,6 +168,7 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar int gpio; int allowed = -1; char *channel; + int inchan; int direction; int pud = PUD_OFF; int initial = 0; @@ -164,13 +176,30 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar clear_error_msg(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii", kwlist, &inchan, &direction, &pud, &initial); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (!module_setup) { init_module(); } - + + 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; + } + if (direction != INPUT && direction != OUTPUT) { PyErr_SetString(PyExc_ValueError, "An invalid direction was passed to setup()"); @@ -259,23 +288,33 @@ static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwar } 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) { int gpio; int value; char *channel; + int inchan; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "si", &channel, &value)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "si", &channel, &value); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "ii", &inchan, &value); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -322,14 +361,25 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args) { int gpio; char *channel; + int inchan; unsigned int value; PyObject *py_value; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -376,14 +426,25 @@ static PyObject *py_read_byte_gpio(PyObject *self, PyObject *args) { int gpio; char *channel; + int inchan; unsigned int value = 0; PyObject *py_value; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -430,14 +491,25 @@ static PyObject *py_read_word_gpio(PyObject *self, PyObject *args) { int gpio; char *channel; + int inchan; unsigned int value = 0; PyObject *py_value; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -557,6 +629,7 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject { int gpio; char *channel; + int inchan; int allowed = -1; unsigned int bouncetime = 0; PyObject *cb_func; @@ -564,8 +637,18 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject clear_error_msg(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &inchan, &cb_func, &bouncetime); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (!PyCallable_Check(cb_func)) { @@ -628,6 +711,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k { int gpio; char *channel; + int inchan; int edge, result; unsigned int bouncetime = 0; int allowed = -1; @@ -636,8 +720,18 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k clear_error_msg(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "ii|Oi", kwlist, &inchan, &edge, &cb_func, &bouncetime); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (cb_func != NULL && !PyCallable_Check(cb_func)) { @@ -714,6 +808,7 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) { int gpio; char *channel; + int inchan; struct py_callback *cb = py_callbacks; struct py_callback *temp; struct py_callback *prev = NULL; @@ -721,8 +816,18 @@ static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -784,12 +889,23 @@ static PyObject *py_event_detected(PyObject *self, PyObject *args) { int gpio; char *channel; + int inchan; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -823,14 +939,26 @@ static PyObject *py_wait_for_edge(PyObject *self, PyObject *args) int gpio; int edge, result, timeout; char *channel; + int inchan; char error[81]; int allowed = -1; clear_error_msg(); timeout = -1; - if (!PyArg_ParseTuple(args, "si|i", &channel, &edge, &timeout)) - return NULL; + + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "si|i", &channel, &edge, &timeout); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "ii|i", &inchan, &edge, &timeout); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -903,12 +1031,23 @@ static PyObject *py_gpio_function(PyObject *self, PyObject *args) unsigned int value; PyObject *func; char *channel; + int inchan; int allowed = -1; clear_error_msg(); - if (!PyArg_ParseTuple(args, "s", &channel)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTuple(args, "s", &channel); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTuple(args, "i", &inchan); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (get_gpio_number(channel, &gpio)) { PyErr_SetString(PyExc_ValueError, "Invalid channel"); @@ -1116,14 +1255,25 @@ static PyObject *py_set_direction(PyObject *self, PyObject *args, PyObject *kwar { int gpio; char *channel; + int inchan; int direction; int allowed = -1; static char *kwlist[] = { "channel", "direction", NULL }; clear_error_msg(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si", kwlist, &channel, &direction)) - return NULL; + // Try to parse the string + int rtn; + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "si", kwlist, &channel, &direction); + if (!rtn) { + // Fall into here are try to parse an int + rtn = PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &inchan, &direction); + if (!rtn) { + return NULL; + } + // We make it here, we can convert inchan to a string for us to ensure it's valid + asprintf(&channel, "%i", inchan); + } if (!module_setup) { init_module();