From 7a21a7976980f2560844f4e4362777bf081d6dcd Mon Sep 17 00:00:00 2001 From: "Michael T. Mosier" Date: Thu, 21 Aug 2014 00:01:54 -0500 Subject: [PATCH 1/4] Applying Patch --- WiringPi/wiringPi/wiringPi.c | 125 +++++++++++++++++++++++++++++++++++ WiringPi/wiringPi/wiringPi.h | 1 + wiringpi_wrap.c | 48 ++++++++++++-- 3 files changed, 167 insertions(+), 7 deletions(-) diff --git a/WiringPi/wiringPi/wiringPi.c b/WiringPi/wiringPi/wiringPi.c index b54ad29..21d9ab5 100644 --- a/WiringPi/wiringPi/wiringPi.c +++ b/WiringPi/wiringPi/wiringPi.c @@ -223,6 +223,7 @@ static int sysFds [64] = // ISR Data static void (*isrFunctions [64])(void) ; +static void (*isrFunctionsWithArg [64])(void *) ; // Doing it the Arduino way with lookup tables... @@ -1405,6 +1406,130 @@ int wiringPiISR (int pin, int mode, void (*function)(void)) } +/* + * interruptHandlerWithArg: + * This is a thread and gets started to wait for the interrupt we're + * hoping to catch. It will call the user-function when the interrupt + * fires. + ********************************************************************************* + */ + +static void *interruptHandlerWithArg (void *arg) +{ + int myPin ; + + (void)piHiPri (55) ; // Only effective if we run as root + + myPin = pinPass ; + pinPass = -1 ; + + for (;;) + if (waitForInterrupt (myPin, -1) > 0) + isrFunctionsWithArg [myPin] (arg) ; + + return NULL ; +} + + +/* + * wiringPiISR: + * Pi Specific. + * Take the details and create an interrupt handler that will do a call- + * back to the user supplied function. + ********************************************************************************* + */ + +int wiringPiISRWithArg (int pin, int mode, void (*function)(void *), void *arg) +{ + pthread_t threadId ; + const char *modeS ; + char fName [64] ; + char pinS [8] ; + pid_t pid ; + int count, i ; + char c ; + int bcmGpioPin ; + + if ((pin < 0) || (pin > 63)) + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: pin must be 0-63 (%d)\n", pin) ; + + /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED) + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: wiringPi has not been initialised. Unable to continue.\n") ; + else if (wiringPiMode == WPI_MODE_PINS) + bcmGpioPin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + bcmGpioPin = physToGpio [pin] ; + else + bcmGpioPin = pin ; + +// Now export the pin and set the right edge +// We're going to use the gpio program to do this, so it assumes +// a full installation of wiringPi. It's a bit 'clunky', but it +// is a way that will work when we're running in "Sys" mode, as +// a non-root user. (without sudo) + + if (mode != INT_EDGE_SETUP) + { + /**/ if (mode == INT_EDGE_FALLING) + modeS = "falling" ; + else if (mode == INT_EDGE_RISING) + modeS = "rising" ; + else + modeS = "both" ; + + sprintf (pinS, "%d", bcmGpioPin) ; + + if ((pid = fork ()) < 0) // Fail + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: fork failed: %s\n", strerror (errno)) ; + + if (pid == 0) // Child, exec + { + /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0) + { + execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: execl failed: %s\n", strerror (errno)) ; + } + else if (access ("/usr/bin/gpio", X_OK) == 0) + { + execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: execl failed: %s\n", strerror (errno)) ; + } + else + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: Can't find gpio program\n") ; + } + else // Parent, wait + wait (NULL) ; + } + +// Now pre-open the /sys/class node - but it may already be open if +// we are in Sys mode... + + if (sysFds [bcmGpioPin] == -1) + { + sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ; + if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0) + return wiringPiFailure (WPI_FATAL, "wiringPiISRWithArg: unable to open %s: %s\n", fName, strerror (errno)) ; + } + +// Clear any initial pending interrupt + + ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ; + for (i = 0 ; i < count ; ++i) + read (sysFds [bcmGpioPin], &c, 1) ; + + isrFunctionsWithArg [pin] = function ; + + pthread_mutex_lock (&pinMutex) ; + pinPass = pin ; + pthread_create (&threadId, NULL, interruptHandlerWithArg, arg) ; + while (pinPass != -1) + delay (1) ; + pthread_mutex_unlock (&pinMutex) ; + + return 0 ; +} + + /* * initialiseEpoch: * Initialise our start-of-time variable to be the current unix diff --git a/WiringPi/wiringPi/wiringPi.h b/WiringPi/wiringPi/wiringPi.h index 7cfd2e5..9db3165 100644 --- a/WiringPi/wiringPi/wiringPi.h +++ b/WiringPi/wiringPi/wiringPi.h @@ -165,6 +165,7 @@ extern void gpioClockSet (int pin, int freq) ; extern int waitForInterrupt (int pin, int mS) ; extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; +extern int wiringPiISRWithArg (int pin, int mode, void (*function)(void *), void *arg) ; // Threads diff --git a/wiringpi_wrap.c b/wiringpi_wrap.c index 0eb71f3..8996b4c 100644 --- a/wiringpi_wrap.c +++ b/wiringpi_wrap.c @@ -3841,12 +3841,29 @@ SWIGINTERN PyObject *Swig_var_waitForInterrupt_get(void) { return pyobj; } +PyObject *event_callback[64]; +PyObject *event_callback_data[64]; + +void _wiringPiISR_callback(void *arg) { + PyObject *result; + int pinNumber = *((int *) arg); + + if (event_callback) { + PyGILState_STATE _swig_thread_block = PyGILState_Ensure(); + result = PyObject_CallFunction(event_callback[pinNumber], "O", event_callback_data[pinNumber]); + if (result == NULL && PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + Py_XDECREF(result); + PyGILState_Release(_swig_thread_block); + } +} SWIGINTERN PyObject *_wrap_wiringPiISR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; int arg1 ; int arg2 ; - void (*arg3)(void) = (void (*)(void)) 0 ; int val1 ; int ecode1 = 0 ; int val2 ; @@ -3854,9 +3871,12 @@ SWIGINTERN PyObject *_wrap_wiringPiISR(PyObject *SWIGUNUSEDPARM(self), PyObject PyObject * obj0 = 0 ; PyObject * obj1 = 0 ; PyObject * obj2 = 0 ; + PyObject * cb_func = NULL; + PyObject * cb_arg = NULL; int result; + int *pinNumber; - if (!PyArg_ParseTuple(args,(char *)"OOO:wiringPiISR",&obj0,&obj1,&obj2)) SWIG_fail; + if (!PyArg_ParseTuple(args,(char *)"OOO|O:wiringPiISR",&obj0,&obj1,&obj2,&cb_arg)) SWIG_fail; ecode1 = SWIG_AsVal_int(obj0, &val1); if (!SWIG_IsOK(ecode1)) { SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "wiringPiISR" "', argument " "1"" of type '" "int""'"); @@ -3868,12 +3888,26 @@ SWIGINTERN PyObject *_wrap_wiringPiISR(PyObject *SWIGUNUSEDPARM(self), PyObject } arg2 = (int)(val2); { - int res = SWIG_ConvertFunctionPtr(obj2, (void**)(&arg3), SWIGTYPE_p_f_void__void); - if (!SWIG_IsOK(res)) { - SWIG_exception_fail(SWIG_ArgError(res), "in method '" "wiringPiISR" "', argument " "3"" of type '" "void (*)(void)""'"); - } + if (!PyArg_ParseTuple(args, "iiO|O", &val1, &val2, &cb_func, &cb_arg)) { + SWIG_exception_fail(SWIG_ArgError(SWIG_TypeError), "in method '" "wiringPiISR" "', argument " "3"" of type '" "function""'"); + } + if (!PyCallable_Check(cb_func)) { + SWIG_exception_fail(SWIG_ArgError(SWIG_TypeError), "in method '" "wiringPiISR" "', argument " "3"" of type '" "function""'"); + } + if (event_callback[arg1]) { + Py_XDECREF(event_callback[arg1]); + } + if (event_callback_data[arg1]) { + Py_XDECREF(event_callback_data[arg1]); + } + event_callback[arg1] = cb_func; + event_callback_data[arg1] = cb_arg; + Py_XINCREF(cb_func); + Py_XINCREF(cb_arg); } - result = (int)wiringPiISR(arg1,arg2,arg3); + pinNumber = (int *)malloc(sizeof(*pinNumber)); + *pinNumber = arg1; + result = (int)wiringPiISRWithArg(arg1,arg2,&_wiringPiISR_callback,pinNumber); resultobj = SWIG_From_int((int)(result)); return resultobj; fail: From 4ccb493d2d7c2ef4bf2169c5543e557c2aec6f24 Mon Sep 17 00:00:00 2001 From: mtmosier Date: Thu, 21 Aug 2014 00:13:21 -0500 Subject: [PATCH 2/4] Update README.md --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f31410b..7c73749 100644 --- a/README.md +++ b/README.md @@ -15,67 +15,88 @@ If you manually rebuild the bindings with swig -python wiringpi.i YOU MUST FIRST INSTALL WIRINGPI2!! +``` git clone git://git.drogon.net/wiringPi cd wiringPi sudo ./build +``` **Get/setup repo:** +``` git clone https://github.com/Gadgetoid/WiringPi2-Python.git cd WiringPi2-Python +``` **Build & install with:** +``` sudo python setup.py install +``` Or Python 3 +``` sudo python3 setup.py install +``` **Class-based Usage:** Description incoming! **Usage:** - +``` import wiringpi2 wiringpi2.wiringPiSetup() # For sequential pin numbering, one of these MUST be called before using IO functions OR wiringpi2.wiringPiSetupSys() # For /sys/class/gpio with GPIO pin numbering OR wiringpi2.wiringPiSetupGpio() # For GPIO pin numbering +``` Setting up IO expanders (This example was tested on a quick2wire board with one digital IO expansion board connected via I2C): +``` wiringpi2.mcp23017Setup(65,0x20) wiringpi2.pinMode(65,1) wiringpi2.digitalWrite(65,1) +``` **General IO:** +``` wiringpi2.pinMode(1,1) # Set pin 1 to output wiringpi2.digitalWrite(1,1) # Write 1 HIGH to pin 1 wiringpi2.digitalRead(1) # Read pin 1 +``` **Setting up a peripheral:** WiringPi2 supports expanding your range of available "pins" by setting up a port expander. The implementation details of your port expander will be handled transparently, and you can write to the additional pins ( starting from PIN_OFFSET >= 64 ) as if they were normal pins on the Pi. +``` wiringpi2.mcp23017Setup(PIN_OFFSET,I2C_ADDR) +``` **Soft Tone** Hook a speaker up to your Pi and generate music with softTone. Also useful for generating frequencies for other uses such as modulating A/C. +``` wiringpi2.softToneCreate(PIN) wiringpi2.softToneWrite(PIN,FREQUENCY) +``` **Bit shifting:** +``` wiringpi2.shiftOut(1,2,0,123) # Shift out 123 (b1110110, byte 0-255) to data pin 1, clock pin 2 +``` **Serial:** +``` serial = wiringpi2.serialOpen('/dev/ttyAMA0',9600) # Requires device/baud and returns an ID wiringpi2.serialPuts(serial,"hello") wiringpi2.serialClose(serial) # Pass in ID +``` **Full details at:** http://www.wiringpi.com From 300e407e5d803da22c06922b0680107f2f04621c Mon Sep 17 00:00:00 2001 From: mtmosier Date: Thu, 21 Aug 2014 00:17:24 -0500 Subject: [PATCH 3/4] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 7c73749..7f0006d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ **WiringPi 2 for Python** +This is a fork of the projected located at https://github.com/Gadgetoid/WiringPi2-Python. + WiringPi: An implementation of most of the Arduino Wiring functions for the Raspberry Pi WiringPi2: WiringPi version 2 implements new functions for managing IO expanders. +**Changes** + +The only change made in this fork was to allow wiringPiISR to take a python function and argument for the callback. + **Testing:** Build with gcc version 4.6.3 (Debian 4.6.3-14+rpi1) Built against Python 2.7.2, Python 3.2.3 From a791b328bee4cb394404751b7b17b54345254c82 Mon Sep 17 00:00:00 2001 From: mtmosier Date: Thu, 21 Aug 2014 00:31:37 -0500 Subject: [PATCH 4/4] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f0006d..f0e1474 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,7 @@ WiringPi: An implementation of most of the Arduino Wiring WiringPi2: WiringPi version 2 implements new functions for managing IO expanders. -**Changes** - +**Changes:** The only change made in this fork was to allow wiringPiISR to take a python function and argument for the callback. **Testing:**