diff --git a/api/gpio.h b/api/gpio.h index a2c6852..594a84c 100644 --- a/api/gpio.h +++ b/api/gpio.h @@ -34,6 +34,10 @@ extern "C" { #endif +#ifdef SWIG +#include +#endif + #include #include @@ -46,7 +50,11 @@ typedef struct { /*@{*/ int pin; /**< the pin number, as known to the os. */ int value_fp; /**< the file pointer to the value of the gpio */ +#ifdef SWIG + PyObject *isr; /**< the interupt service request */ +#else void (* isr)(); /**< the interupt service request */ +#endif pthread_t thread_id; /**< the isr handler thread id */ int isr_value_fp; /**< the isr file pointer on the value */ /*@}*/ diff --git a/examples/python/hello_isr.py b/examples/python/hello_isr.py new file mode 100644 index 0000000..64df878 --- /dev/null +++ b/examples/python/hello_isr.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import pymaa as maa + +def test(): + print("wooo") + +x = maa.Gpio(6) +x.dir(maa.MAA_GPIO_IN) +x.set_isr(test) diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index ed55bdd..e2fd9fd 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -124,7 +124,19 @@ maa_gpio_interrupt_handler(void* arg) for (;;) { ret = maa_gpio_wait_interrupt(dev->isr_value_fp); if (ret == MAA_SUCCESS) { +#ifdef SWIG + // In order to call a python object (all python functions are objects) we + // need to aquire the GIL (Global Interpreter Lock). This may not always be + // nessecary but especially if doing IO (like print()) python will segfault + // if we do not hold a lock on the GIL + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyEval_CallObject(dev->isr, NULL); + + PyGILState_Release (gilstate); +#else dev->isr(); +#endif } else { // we must have got an error code so die nicely close(dev->isr_value_fp); @@ -190,6 +202,11 @@ maa_gpio_isr_exit(maa_gpio_context *dev) { maa_result_t ret = MAA_SUCCESS; +#ifdef SWIG + // Dereference our Python call back function + Py_DECREF(dev->isr); +#endif + if (dev->thread_id == 0) { return ret; } diff --git a/src/maa.c b/src/maa.c index b02061c..37987c0 100644 --- a/src/maa.c +++ b/src/maa.c @@ -55,6 +55,12 @@ maa_init() if (plat != NULL) { return MAA_ERROR_PLATFORM_ALREADY_INITIALISED; } +#ifdef SWIG + // Initialise python threads, this allows use to grab the GIL when we are + // required to do so + Py_InitializeEx(0); + PyEval_InitThreads(); +#endif plat = maa_intel_galileo_rev_d(); return MAA_SUCCESS; } diff --git a/src/maa.i b/src/maa.i index 95cdb78..c3acccc 100644 --- a/src/maa.i +++ b/src/maa.i @@ -8,6 +8,7 @@ %} %init %{ + //Adding maa_init() to the module initialisation process maa_init(); %} @@ -45,9 +46,19 @@ typedef struct { /*@{*/ int pin; /**< the pin number, as known to the os. */ FILE *value_fp; /**< the file pointer to the value of the gpio */ +#if defined(SWIGPYTHON) + PyObject *isr; /**< the interupt service request */ +#endif + pthread_t thread_id; /**< the isr handler thread id */ + int isr_value_fp; /**< the isr file pointer on the value */ /*@}*/ } maa_gpio_context; +%typemap(check) PyObject *pyfunc { + if (!PyCallable_Check($1)) + SWIG_exception(SWIG_TypeError,"Expected function."); +} + %extend maa_gpio_context { maa_gpio_context(int pin, int raw=0) { @@ -95,6 +106,22 @@ typedef struct { { return maa_gpio_mode($self, mode); } +#if defined(SWIGPYTHON) + //set python method as the isr function + int set_isr(PyObject *pyfunc) + { + Py_INCREF(pyfunc); + // do a nasty cast to get away from the warnings + maa_gpio_isr(self, MAA_GPIO_EDGE_BOTH, pyfunc); + return 0; + } +#else + %ignore maa_gpio_isr; +#endif + int isr_exit() + { + maa_gpio_isr_exit(self); + } } #### i2c #### diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index f9eac11..ac43c5b 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -9,6 +9,8 @@ include_directories( swig_add_module (pymaa python pymaa.i ${maa_LIB_SRCS}) swig_link_libraries (pymaa ${PYTHON_LIBRARIES}) +set (CMAKE_C_FLAGS -DSWIG=${SWIG_FOUND}) + if (DOXYGEN_FOUND) foreach (_file ${DOCFILES}) add_dependencies (${SWIG_MODULE_pymaa_REAL_NAME} ${_file}doc_i)