diff --git a/VERSION b/VERSION index 8c50098..a3ec5a4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.1 +3.2 diff --git a/gpio/gpio.c b/gpio/gpio.c index 680305a..5989fbf 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -556,16 +556,30 @@ void doExport (int argc, char *argv []) ********************************************************************************* */ -static void wfi (void) - { exit (0) ; } +static volatile int iterations ; +static volatile int globalCounter ; + +static void wfi (void) { + globalCounter++; + //printf("irq count %d/%d\n", globalCounter , iterations); + if(globalCounter>=iterations) { + printf("finished\n"); + exit (0) ; + } else { + printf("I"); fflush(stdout); + } +} void doWfi (int argc, char *argv []) { - int pin, mode ; + int pin, mode; + int timeoutSec = 2147483647; - if (argc != 4) + iterations = 1; + globalCounter = 0; + if (argc != 4 && argc != 5 && argc != 6) { - fprintf (stderr, "Usage: %s wfi pin mode\n", argv [0]) ; + fprintf (stderr, "Usage: %s wfi pin mode [interations] [timeout sec.]\n", argv [0]) ; exit (1) ; } @@ -579,6 +593,12 @@ void doWfi (int argc, char *argv []) fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", argv [1], argv [3]) ; exit (1) ; } + if (argc>=5) { + iterations = atoi(argv [4]); + } + if (argc>=6) { + timeoutSec = atoi(argv [5]); + } if (wiringPiISR (pin, mode, &wfi) < 0) { @@ -586,8 +606,13 @@ void doWfi (int argc, char *argv []) exit (1) ; } - for (;;) - delay (9999) ; + printf("wait for interrupt function call \n"); + for (int Sec=0; Sec #include #include +#include #include "softPwm.h" #include "softTone.h" @@ -406,9 +407,10 @@ static int sysFds [64] = } ; // ISR Data - +static int chipFd = -1; static void (*isrFunctions [64])(void) ; - +static pthread_t isrThreads[64]; +static int isrMode[64]; // Doing it the Arduino way with lookup tables... // Yes, it's probably more innefficient than all the bit-twidling, but it @@ -2112,7 +2114,7 @@ unsigned int digitalReadByte2 (void) * waitForInterrupt: * Pi Specific. * Wait for Interrupt on a GPIO pin. - * This is actually done via the /sys/class/gpio interface regardless of + * This is actually done via the /dev/gpiochip interface regardless of * the wiringPi access mode in-use. Maybe sometime it might get a better * way for a bit more efficiency. ********************************************************************************* @@ -2120,11 +2122,12 @@ unsigned int digitalReadByte2 (void) int waitForInterrupt (int pin, int mS) { - int fd, x ; - uint8_t c ; + int fd, ret; struct pollfd polls ; + struct gpioevent_data evdata; + //struct gpio_v2_line_request req2; - /**/ if (wiringPiMode == WPI_MODE_PINS) + if (wiringPiMode == WPI_MODE_PINS) pin = pinToGpio [pin] ; else if (wiringPiMode == WPI_MODE_PHYS) pin = physToGpio [pin] ; @@ -2132,27 +2135,145 @@ int waitForInterrupt (int pin, int mS) if ((fd = sysFds [pin]) == -1) return -2 ; -// Setup poll structure + // Setup poll structure + polls.fd = fd; + polls.events = POLLIN | POLLERR ; + polls.revents = 0; - polls.fd = fd ; - polls.events = POLLPRI | POLLERR ; - -// Wait for it ... - - x = poll (&polls, 1, mS) ; - -// If no error, do a dummy read to clear the interrupt -// A one character read appars to be enough. - - if (x > 0) - { - lseek (fd, 0, SEEK_SET) ; // Rewind - (void)read (fd, &c, 1) ; // Read & clear + // Wait for it ... + ret = poll(&polls, 1, mS); + if (ret <= 0) { + fprintf(stderr, "wiringPi: ERROR: poll returned=%d\n", ret); + } else { + //if (polls.revents & POLLIN) + if (wiringPiDebug) { + printf ("wiringPi: IRQ line %d received %d, fd=%d\n", pin, ret, sysFds [pin]) ; + } + /* read event data */ + int readret = read(sysFds [pin], &evdata, sizeof(evdata)); + if (readret == sizeof(evdata)) { + if (wiringPiDebug) { + printf ("wiringPi: IRQ data id: %d, timestamp: %lld\n", evdata.id, evdata.timestamp) ; + } + ret = evdata.id; + } else { + ret = 0; + } } - - return x ; + return ret; } +const char DEV_GPIO_PI[] ="/dev/gpiochip0"; +const char DEV_GPIO_PI5[]="/dev/gpiochip4"; + +int waitForInterruptInit (int pin, int mode) +{ + const char* strmode = ""; + + if (wiringPiMode == WPI_MODE_PINS) { + pin = pinToGpio [pin] ; + } else if (wiringPiMode == WPI_MODE_PHYS) { + pin = physToGpio [pin] ; + } + + /* open gpio */ + sleep(1); + const char* gpiochip = PI_MODEL_5 == RaspberryPiModel ? DEV_GPIO_PI5 : DEV_GPIO_PI; + if (chipFd < 0) { + chipFd = open(gpiochip, O_RDWR); + if (chipFd < 0) { + fprintf(stderr, "wiringPi: ERROR: %s open ret=%d\n", gpiochip, chipFd); + return -1; + } + } + if (wiringPiDebug) { + printf ("wiringPi: Open chip %s succeded, fd=%d\n", gpiochip, chipFd) ; + } + + struct gpioevent_request req; + req.lineoffset = pin; + req.handleflags = GPIOHANDLE_REQUEST_INPUT; + switch(mode) { + default: + case INT_EDGE_SETUP: + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptMode mode INT_EDGE_SETUP - exiting\n") ; + } + return -1; + case INT_EDGE_FALLING: + req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; + strmode = "falling"; + break; + case INT_EDGE_RISING: + req.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; + strmode = "rising"; + break; + case INT_EDGE_BOTH: + req.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; + strmode = "both"; + break; + } + strncpy(req.consumer_label, "wiringpi_gpio_irq", sizeof(req.consumer_label) - 1); + + //later implement GPIO_V2_GET_LINE_IOCTL req2 + int ret = ioctl(chipFd, GPIO_GET_LINEEVENT_IOCTL, &req); + if (ret) { + fprintf(stderr, "wiringPi: ERROR: %s ioctl get line %d %s returned %d\n", gpiochip, pin, strmode, ret); + return -1; + } + if (wiringPiDebug) { + printf ("wiringPi: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; + } + + /* set event fd nonbloack read */ + int fd_line = req.fd; + sysFds [pin] = fd_line; + int flags = fcntl(fd_line, F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl(fd_line, F_SETFL, flags); + if (ret) { + fprintf(stderr, "wiringPi: ERROR: %s fcntl set nonblock read=%d\n", gpiochip, chipFd); + return -1; + } + + return 0; +} + + +int waitForInterruptClose (int pin) { + if (sysFds[pin]>0) { + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose close thread 0x%lX\n", (unsigned long)isrThreads[pin]) ; + } + if (pthread_cancel(isrThreads[pin]) == 0) { + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose thread canceled successfuly\n") ; + } + } else { + if (wiringPiDebug) { + fprintf (stderr, "wiringPi: waitForInterruptClose could not cancel thread\n"); + } + } + close(sysFds [pin]); + } + sysFds [pin] = -1; + + /* -not closing so far - other isr may be using it - only close if no other is using - will code later + if (chipFd>0) { + close(chipFd); + } + chipFd = -1; + */ + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose finished\n") ; + } + return 0; +} + + +int wiringPiISRStop (int pin) { + return waitForInterruptClose (pin); +} /* * interruptHandler: @@ -2164,17 +2285,30 @@ int waitForInterrupt (int pin, int mS) static void *interruptHandler (UNU void *arg) { - int myPin ; + int pin ; (void)piHiPri (55) ; // Only effective if we run as root - myPin = pinPass ; + pin = pinPass ; pinPass = -1 ; - for (;;) - if (waitForInterrupt (myPin, -1) > 0) - isrFunctions [myPin] () ; + for (;;) { + int ret = waitForInterrupt(pin, -1); + if ( ret> 0) { + if (wiringPiDebug) { + printf ("wiringPi: call function\n") ; + } + isrFunctions [pin] () ; + // wait again - in the past forever - now can be stopped by waitForInterruptClose + } else if( ret< 0) { + break; // stop thread! + } + } + waitForInterruptClose (pin); + if (wiringPiDebug) { + printf ("wiringPi: interruptHandler finished\n") ; + } return NULL ; } @@ -2189,93 +2323,55 @@ static void *interruptHandler (UNU void *arg) int wiringPiISR (int pin, int mode, void (*function)(void)) { - pthread_t threadId ; - const char *modeS ; - char fName [64] ; - char pinS [8] ; - pid_t pid ; - int count, i ; - char c ; - int bcmGpioPin ; const int maxpin = GetMaxPin(); if (pin < 0 || pin > maxpin) return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-%d (%d)\n", maxpin, pin) ; - - /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED) + if (wiringPiMode == WPI_MODE_UNINITIALISED) return wiringPiFailure (WPI_FATAL, "wiringPiISR: 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, "wiringPiISR: 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, "wiringPiISR: 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, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; - } - else - return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ; - } - else // Parent, wait - waitpid (pid, NULL, 0) ; + if (wiringPiDebug) { + printf ("wiringPi: wiringPiISR pin %d, mode %d\n", pin, mode) ; } - -// Now pre-open the /sys/class node - but it may already be open if -// we are in Sys mode... - - if (sysFds [bcmGpioPin] == -1) - { - int pinFS = GPIOToSysFS(bcmGpioPin); - sprintf (fName, "/sys/class/gpio/gpio%d/value", pinFS) ; - if (pinFS>=0 && (sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ; + if (isrFunctions [pin]) { + printf ("wiringPi: ISR function alread active, ignoring \n") ; } -// Clear any initial pending interrupt - - ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ; - for (i = 0 ; i < count ; ++i) - read (sysFds [bcmGpioPin], &c, 1) ; - isrFunctions [pin] = function ; + isrMode[pin] = mode; + if(waitForInterruptInit (pin, mode)<0) { + if (wiringPiDebug) { + fprintf (stderr, "wiringPi: waitForInterruptInit failed\n") ; + } + }; + if (wiringPiDebug) { + printf ("wiringPi: mutex in\n") ; + } pthread_mutex_lock (&pinMutex) ; pinPass = pin ; - pthread_create (&threadId, NULL, interruptHandler, NULL) ; - while (pinPass != -1) - delay (1) ; + if (wiringPiDebug) { + printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]); + } + if (pthread_create (&isrThreads[pin], NULL, interruptHandler, NULL)==0) { + if (wiringPiDebug) { + printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]); + } + while (pinPass != -1) + delay (1) ; + } else { + if (wiringPiDebug) { + printf("wiringPi: pthread_create failed\n"); + } + } + + if (wiringPiDebug) { + printf ("wiringPi: mutex out\n") ; + } pthread_mutex_unlock (&pinMutex) ; + if (wiringPiDebug) { + printf ("wiringPi: wiringPiISR finished\n") ; + } return 0 ; } diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index 0212016..d6ee11a 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -239,7 +239,7 @@ extern void piBoardId (int *model, int *rev, int *mem, int *m extern int wpiPinToGpio (int wpiPin) ; extern int physPinToGpio (int physPin) ; extern void setPadDrive (int group, int value) ; -extern void setPadDrivePin (int pin, int value); // Interface V2 +extern void setPadDrivePin (int pin, int value); // Interface V3.0 extern int getAlt (int pin) ; extern void pwmToneWrite (int pin, int freq) ; extern void pwmSetMode (int mode) ; @@ -256,6 +256,8 @@ extern void digitalWriteByte2 (int value) ; extern int waitForInterrupt (int pin, int mS) ; extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; +extern int wiringPiISRStop (int pin) ; //V3.2 +extern int waitForInterruptClose(int pin) ; //V3.2 // Threads