]> git.feebdaed.xyz Git - 0xmirror/WiringPi.git/commitdiff
Version 3.14: WiringPi functions upgrade to GPIO_V2 IOCTL
authorphylax2020 <severin.hoffmann@t-online.de>
Tue, 11 Feb 2025 15:02:33 +0000 (16:02 +0100)
committerphylax2020 <severin.hoffmann@t-online.de>
Tue, 11 Feb 2025 15:02:33 +0000 (16:02 +0100)
VERSION
documentation/deutsch/functions.md
version.h
wiringPi/wiringPi.c
wiringPi/wiringPi.h

diff --git a/VERSION b/VERSION
index 24ee5b1be9961e38a503c8e764b7385dbb6ba124..3767b4b17d1ee479abf8762cb628d10b00faa6d1 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.13
+3.14
\ No newline at end of file
index 2093650d856369a41e732e422fa22ff08137d99f..fbfc431436bef17b14b6c9846bea62e3eb230dea 100644 (file)
@@ -291,11 +291,11 @@ Registriert eine Interrupt Service Routine (ISR) bzw. Funktion die bei Flankenwe
 
 >>>
 ```C
-int wiringPiISR(int pin, int mode, void (*function)(unsigned int, long long int), int bouncetime);
+int wiringPiISR(int pin, int edgeMode, void (*function)(unsigned int, long long int), unsigned long bouncetime);
 ```
 
 ``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer).  
-``mode``: Auslösende Flankenmodus  
+``edgeMode``: Auslösende Flankenmodus  
  - INT_EDGE_RISING ... Steigende Flanke  
  - INT_EDGE_FALLING ... Fallende Flanke  
  - INT_EDGE_BOTH ... Steigende und fallende Flanke  
@@ -304,13 +304,13 @@ int wiringPiISR(int pin, int mode, void (*function)(unsigned int, long long int)
  > unsigned int: pin  
  > long long int: Zeitstempel  
  
-``bouncetime``: Entprellzeit in ms, 0 ms schaltet das Entprellen ab   
+``bouncetime``: Entprellzeit in Microsekunden, 0 ms schaltet das Entprellen ab   
 
 ``Rückgabewert``:   
  > 0 ... Erfolgreich  
 <!-- > <>0 ... Fehler, zur Zeit nicht implementiert -->
 
-Beispiel siehe waitForInterruptInit.
+Beispiel siehe waitForInterrupt.  
 
 
 ### wiringPiISRStop
@@ -330,42 +330,29 @@ int wiringPiISRStop (int pin)
 
 ### waitForInterrupt
 
-Wartet auf einen Aufruf der Interrupt Service Routine (ISR) mit Timeout und Entprellzeit in Millisekunden.
-
+Wartet auf einen Aufruf der Interrupt Service Routine (ISR) mit Timeout und Entprellzeit in Mikrosekunden.  
+Blockiert das Programm bis zum Eintreffen der auslösenden Flanke oder bis zum Ablauf des Timeouts.  
 >>>
 ```C
-long long int  waitForInterrupt (int pin, int mS, int bouncetime)
+long long int  waitForInterrupt (int pin, int edgeMode, int mS, unsigned long bouncetime)
 ```
 
 ``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer).  
+``edgeMode``: Auslösende Flankenmodus  
+ - INT_EDGE_RISING ... Steigende Flanke  
+ - INT_EDGE_FALLING ... Fallende Flanke  
+ - INT_EDGE_BOTH ... Steigende und fallende Flanke  
 ``mS``: Timeout in Milisekunden.  
  - \-1 warten ohne timeout  
  - 0 wartet nicht  
  - 1...n wartet maximal n mS Millisekunden  
-``bouncetime``: Entprellzeit in Millisekunden, 0 schaltet Entprellen ab  
+``bouncetime``: Entprellzeit in Microsekunden, 0 schaltet Entprellen ab.  
 
 ``Rückgabewert``:  
 > \>0 ... Zeitstempel des Interrupt Ereignisses in Mikrosekunden  
 > 0 ... Timeout  
 > \-1 ... GPIO Device Chip nicht erfolgreich geöffnet  
-> \-2 ... ISR wurde nicht registriert (waitForInterruptInit muss aufgerufen werden)  
-
-
-### waitForInterruptInit
-
-Initialisiert die Funktion waitForInterrupt, definiert, welche Flanke den Interrupt erzeugen soll
-
->>>
-```C
-int  waitForInterruptInit (int pin, int mode)
-```
-
-``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer)  
-``mode``: INT_EDGE_RISING, INT_EDGE_FALLING, INT_EDGE_BOTH   
-
-``Rückgabewert``:  
-> \-1 ... Fehler  
-> 0 ... erfolgreich  
+> \-2 ... ISR wurde nicht registriert  
 
 
 **Beispiel:**
@@ -373,7 +360,7 @@ int  waitForInterruptInit (int pin, int mode)
 ```C  
 /*
  * isr_debounce.c:
- *     Wait for Interrupt test program  WiringPi >=3.13 - ISR method
+ *     Wait for Interrupt test program  WiringPi >=3.14 - ISR method
  *
  *
  */
@@ -382,11 +369,13 @@ int  waitForInterruptInit (int pin, int mode)
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <wiringPi.h>
 
 #include <time.h>
 
-#define BOUNCETIME 300
+#define BOUNCETIME 3000 // microseconds
+#define BOUNCETIME_WFI  300
 #define TIMEOUT    10000
 //*************************************
 // BCM pins
@@ -447,18 +436,9 @@ int main (void)
 
   pinMode(OUTpin, OUTPUT);
   digitalWrite (OUTpin, LOW) ;
-  
-  // test waitForInterrupt
 
-  ret = waitForInterruptInit (IRQpin, INT_EDGE_FALLING);
-  if (ret < 0) {
-    printf("waitForInterruptInit returned error %d\n", ret);
-    pinMode(OUTpin, INPUT);
-    return 0;
-  }
-  
   printf("Testing waitForInterrupt IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT);  
-  ret = waitForInterrupt(IRQpin, TIMEOUT, 0);
+  ret = waitForInterrupt(IRQpin, INT_EDGE_FALLING, TIMEOUT, BOUNCETIME_WFI );
   if (ret < 0) {
     printf("waitForInterrupt returned error %lld\n", ret);
     wiringPiISRStop (IRQpin) ;  
@@ -470,11 +450,11 @@ int main (void)
     wiringPiISRStop (IRQpin) ;  
   }   
   else {
-    printf("waitForInterrupt: falling edge fired at %lld microseconds\n\n", ret);     
+    printf("waitForInterrupt: falling edge fired at %lld microseconds\n\n", ret);    
     wiringPiISRStop (IRQpin) ;  
   }
   
-  printf("Testing IRQ @ GPIO%d with trigger @ GPIO%d falling edge and bouncetime %d ms. Toggle LED @ OUTpin on IRQ.\n\n", IRQpin, IRQpin, BOUNCETIME, OUTpin);
+  printf("Testing IRQ @ GPIO%d with trigger @ GPIO%d falling edge and bouncetime %d microseconds. Toggle LED @ OUTpin on IRQ.\n\n", IRQpin, IRQpin, BOUNCETIME, OUTpin);
   printf("To stop program hit return key\n\n");
   
   wiringPiISR (IRQpin, INT_EDGE_FALLING, &wfi, BOUNCETIME) ; 
index 35a30486dcad5df59a8ac19a378014572a3cb52e..c2da28279c00ae874ecafd8e7a928e41e4def849 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1,3 +1,3 @@
-#define VERSION "3.13"
+#define VERSION "3.14"
 #define VERSION_MAJOR 3
-#define VERSION_MINOR 13
+#define VERSION_MINOR 14
index e3d6a25ed46552dba9103e3d0308a27343f0e0c0..1dafed592d8e4e364cef1f5ff101e25a0d25045e 100644 (file)
@@ -56,6 +56,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <ctype.h>
 #include <poll.h>
 #include <unistd.h>
@@ -471,12 +472,14 @@ static int isrFds [64] =
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 } ;
 
+
+
 // ISR Data
 static int chipFd = -1;
 static void (*isrFunctions [64])(unsigned int, long long int) ;
 static pthread_t isrThreads[64];
-static int isrMode[64];
-static unsigned long long lastcall[64];
+static int isrMode[64];             // irq on rising/falling edge
+static unsigned long isrDebouncePeriodUs [64];      // 0: debounce is off
 
 // Doing it the Arduino way with lookup tables...
 //     Yes, it's probably more innefficient than all the bit-twidling, but it
@@ -1734,11 +1737,14 @@ void releaseLine(int pin) {
   lineFlags[pin] = 0;
   close(lineFds[pin]);
   lineFds[pin] = -1;
+  isrDebouncePeriodUs[pin] = 0;
 }
 
 int requestLine(int pin, unsigned int lineRequestFlags) {
-  struct gpiohandle_request rq;
-
+   struct gpio_v2_line_request req;
+   struct gpio_v2_line_config config;
+   int ret;
+   
    if (lineFds[pin]>=0) {
     if (lineRequestFlags == lineFlags[pin]) {
       //already requested
@@ -1753,17 +1759,25 @@ int requestLine(int pin, unsigned int lineRequestFlags) {
   if (wiringPiGpioDeviceGetFd()<0) {
     return -1;  // error
   }
-  rq.lineoffsets[0] = pin;
-  rq.lines = 1;
-  rq.flags = lineRequestFlags;
-  int ret = ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &rq);
-  if (ret || rq.fd<0) {
+  
+  memset(&req, 0, sizeof(req));
+  memset(&config, 0, sizeof(config));
+  config.flags = lineRequestFlags;
+  strcpy(req.consumer, "wiringpi_gpio_req");
+  
+  req.offsets[0] = pin;
+  req.num_lines = 1;
+  req.config = config;
+  
+  ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req);
+  
+  if (ret || req.fd<0) {
     ReportDeviceError("get line handle", pin, "RequestLine", ret);
     return -1;  // error
   }
 
   lineFlags[pin] = lineRequestFlags;
-  lineFds[pin] = rq.fd;
+  lineFds[pin] = req.fd;
   if (wiringPiDebug)
     printf ("requestLine succeeded: pin:%d, flags: %u, fd :%d\n", pin, lineRequestFlags, lineFds[pin]) ;
   return lineFds[pin];
@@ -1863,16 +1877,16 @@ void pinModeFlagsDevice (int pin, int mode, unsigned int flags) {
   if (wiringPiDebug)
       printf ("pinModeFlagsDevice: pin:%d mode:%d, flags: %u\n", pin, mode, flags) ;
 
-  lflag &= ~(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_OUTPUT);
+  lflag &= ~(GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_OUTPUT);
   switch(mode) {
     default:
       fprintf(stderr, "pinMode: invalid mode request (only input und output supported)\n");
       return;
     case INPUT:
-      lflag |= GPIOHANDLE_REQUEST_INPUT;
+      lflag |= GPIO_V2_LINE_FLAG_INPUT;
       break;
     case OUTPUT:
-      lflag |= GPIOHANDLE_REQUEST_OUTPUT;
+      lflag |= GPIO_V2_LINE_FLAG_OUTPUT;
       break;
     case PM_OFF:
       pinModeFlagsDevice(pin, INPUT, 0);
@@ -2038,20 +2052,20 @@ void pinMode (int pin, int mode)
  */
 void pullUpDnControlDevice (int pin, int pud) {
   unsigned int flag = lineFlags[pin];
-  unsigned int biasflags = GPIOHANDLE_REQUEST_BIAS_DISABLE | GPIOHANDLE_REQUEST_BIAS_PULL_UP | GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
+  unsigned int biasflags = GPIO_V2_LINE_FLAG_BIAS_DISABLED | GPIO_V2_LINE_FLAG_BIAS_PULL_UP | GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN;
 
   flag &= ~biasflags;
   switch (pud){
-    case PUD_OFF:  flag |= GPIOHANDLE_REQUEST_BIAS_DISABLE;   break;
-    case PUD_UP:   flag |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;   break;
-    case PUD_DOWN: flag |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; break;
+    case PUD_OFF:  flag |= GPIO_V2_LINE_FLAG_BIAS_DISABLED;   break;
+    case PUD_UP:   flag |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP;   break;
+    case PUD_DOWN: flag |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN; break;
     default: return ; /* An illegal value */
   }
 
   // reset input/output
-  if (lineFlags[pin] & GPIOHANDLE_REQUEST_OUTPUT) {
+  if (lineFlags[pin] & GPIO_V2_LINE_FLAG_OUTPUT) {
     pinModeFlagsDevice (pin, OUTPUT, flag);
-  } else if(lineFlags[pin] & GPIOHANDLE_REQUEST_INPUT) {
+  } else if(lineFlags[pin] & GPIO_V2_LINE_FLAG_INPUT) {
     pinModeFlagsDevice (pin, INPUT, flag);
   } else {
     lineFlags[pin] = flag; // only store for later
@@ -2135,7 +2149,33 @@ void pullUpDnControl (int pin, int pud)
   }
 }
 
+/*
+ helper functions for gpio_v2_line_values bits 
+*/
+static inline void gpiotools_set_bit(__u64 *b, int n)
+{
+       *b |= _BITULL(n);
+}
+
+static inline void gpiotools_clear_bit(__u64 *b, int n)
+{
+       *b &= ~_BITULL(n);
+}
+
+static inline void gpiotools_assign_bit(__u64 *b, int n, bool value)
+{
+       if (value)
+               gpiotools_set_bit(b, n);
+       else
+               gpiotools_clear_bit(b, n);
+}
 
+static inline int gpiotools_test_bit(__u64 b, int n)
+{
+       return !!(b & _BITULL(n));
+}
+
+//*********************************************
 
 
 /*
@@ -2145,19 +2185,23 @@ void pullUpDnControl (int pin, int pud)
  */
 
 int digitalReadDevice (int pin) {   // INPUT and OUTPUT should work
-
-   if (lineFds[pin]<0) {
+  struct gpio_v2_line_values lv;
+  int ret;
+  
+  if (lineFds[pin]<0) {
     // line not requested - auto request on first read as input
-    pinModeDevice(pin, INPUT);
+     pinModeDevice(pin, INPUT);
   }
+  lv.mask = 0;
+  lv.bits = 0;
   if (lineFds[pin]>=0) {
-    struct gpiohandle_data data;
-    int ret = ioctl(lineFds[pin], GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
+    gpiotools_set_bit(&lv.mask, 0); 
+    ret = ioctl(lineFds[pin], GPIO_V2_LINE_GET_VALUES_IOCTL, &lv);
     if (ret) {
       ReportDeviceError("get line values", pin, "digitalRead", ret);
       return LOW;  // error
     }
-    return data.values[0];
+    return gpiotools_test_bit(lv.bits, 0);
   }
   return LOW;  // error , need to request line before
 }
@@ -2239,7 +2283,9 @@ unsigned int digitalRead8 (int pin)
  */
 
 void digitalWriteDevice (int pin, int value) {
-
+  int ret;
+  struct gpio_v2_line_values values;
+  
   if (wiringPiDebug)
     printf ("digitalWriteDevice: ioctl pin:%d value: %d\n", pin, value) ;
 
@@ -2247,22 +2293,25 @@ void digitalWriteDevice (int pin, int value) {
     // line not requested - auto request on first write as output
     pinModeDevice(pin, OUTPUT);
   }
-  if (lineFds[pin]>=0 && (lineFlags[pin] & GPIOHANDLE_REQUEST_OUTPUT)>0) {
-    struct gpiohandle_data data;
-    data.values[0] = value;
-    if (wiringPiDebug)
-      printf ("digitalWriteDevice: ioctl pin:%d cmd: GPIOHANDLE_SET_LINE_VALUES_IOCTL, value: %d\n", pin, value) ;
-    int ret = ioctl(lineFds[pin], GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
-    if (ret) {
-      ReportDeviceError("set line values", pin, "digitalWrite", ret);
-      return;  // error
-    }
+  
+  if (lineFds[pin]>=0 && (lineFlags[pin] & GPIO_V2_LINE_FLAG_OUTPUT)>0) {
+    values.mask = 0;
+    values.bits = 0;    
+    gpiotools_set_bit(&values.mask, 0);
+    gpiotools_assign_bit(&values.bits, 0, !!value);
+
+       ret = ioctl(lineFds[pin], GPIO_V2_LINE_SET_VALUES_IOCTL, &values);
+       if (ret == -1) {
+      ReportDeviceError("digitalWriteDevice", pin, "GPIO_V2_LINE_SET_VALUES_IOCTL", ret);
+      return; // error
+       }
   } else {
     fprintf(stderr, "digitalWrite: no output (%d)\n", lineFlags[pin]);
   }
   return; // error
 }
 
+
 void digitalWrite (int pin, int value)
 {
   struct wiringPiNodeStruct *node = wiringPiNodes ;
@@ -2560,96 +2609,23 @@ unsigned int digitalReadByte2 (void)
 }
 
 
-/*
- * waitForInterrupt:
- *     Pi Specific.
- *     Wait for Interrupt on a GPIO pin.
- *     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.
- *  Returns timestamp in microseconds, when interrupt happened
- *********************************************************************************
- */
-
-long long int waitForInterrupt (int pin, int mS, int bouncetime)  // bounctime in milliseconds
-{
-  long long int ret;
-  int fd;
-  struct pollfd polls ;
-  struct gpioevent_data evdata;
-  //struct gpio_v2_line_request req2;
-  struct timeval tv_timenow;
-  unsigned long long timenow;
-  int finished = 0;
-  int initial_edge = 1;
-
-  if (wiringPiDebug) {
-    printf ("waitForInterrupt: mS = %d,  bouncetime = %d\n", mS, bouncetime) ;
-  }
-  
-  if (wiringPiMode == WPI_MODE_PINS)
-    pin = pinToGpio [pin] ;
-  else if (wiringPiMode == WPI_MODE_PHYS)
-    pin = physToGpio [pin] ;
-
-  if ((fd = isrFds [pin]) == -1)
-    return -2 ;
 
-  // Setup poll structure
-  polls.fd      = fd;
-  polls.events  = POLLIN | POLLERR ;
-  polls.revents = 0;
 
-  // Wait for it ...
-  while (!finished) {
-    ret = (long long int)poll(&polls, 1, mS);
-    if (ret < 0) {
-      if (wiringPiDebug) {  
-        fprintf(stderr, "wiringPi: ERROR: poll returned=%lld\n", ret);
-      }
-      break;
-    } else if (ret == 0) { 
-      if (wiringPiDebug) {  
-        fprintf(stderr, "wiringPi: timeout: poll returned=%lld\n", ret);
-      }
-      break;    
-    }
-    else {
-      //if (polls.revents & POLLIN)
-      if (wiringPiDebug) {
-        printf ("wiringPi: IRQ line %d received %lld, fd=%d\n", pin, ret, isrFds[pin]) ;
-      }
-      if (initial_edge) {    // first time triggers with current state, so ignore
-        initial_edge = 0;
-      } else {
-      /* read event data */
-        int readret = read(isrFds [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;
-          gettimeofday(&tv_timenow, NULL);
-          timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
-          if (bouncetime == 0 || timenow - lastcall[pin] > (unsigned int)bouncetime*1000 || lastcall[pin] == 0 || lastcall[pin] > timenow) {
-             lastcall[pin] = timenow;
-             finished = 1;
-             ret = evdata.timestamp / 1000LL;    // nanoseconds u64 to microseconds
-          }
-        } else {
-          ret = -1;
-          break;
-        }
-      }
-    }
-  }
-  return ret;
-}
+//--------------------------------------------------------------------
+// waitForInteruptInit
+// Prepares waitForInterrupt for edgeMode, and debounce_period_us
+// 
+// returns -1 on error
+// returns 0 on success
+//--------------------------------------------------------------------
 
-int waitForInterruptInit (int pin, int mode)
+int waitForInterruptInit (int pin, int edgeMode, unsigned long debounce_period_us)
 {
   const char* strmode = "";
-
+  struct gpio_v2_line_config config;
+  struct gpio_v2_line_request req;
+  int attr, ret;
+  
   if (wiringPiMode == WPI_MODE_PINS) {
     pin = pinToGpio [pin] ;
   } else if (wiringPiMode == WPI_MODE_PHYS) {
@@ -2657,15 +2633,17 @@ int waitForInterruptInit (int pin, int mode)
   }
 
   /* open gpio */
-  sleep(1);
+//  sleep(1);
   if (wiringPiGpioDeviceGetFd()<0) {
     return -1;
   }
-
-  struct gpioevent_request req;
-  req.lineoffset = pin;
-  req.handleflags = GPIOHANDLE_REQUEST_INPUT;
-  switch(mode) {
+  
+  memset(&req, 0, sizeof(req));
+  memset(&config, 0, sizeof(config));
+  
+  /* setup config */
+  config.flags = GPIO_V2_LINE_FLAG_INPUT;
+  switch(edgeMode) {
     default:
     case INT_EDGE_SETUP:
       if (wiringPiDebug) {
@@ -2673,33 +2651,49 @@ int waitForInterruptInit (int pin, int mode)
       }
       return -1;
     case INT_EDGE_FALLING:
-      req.eventflags  = GPIOEVENT_REQUEST_FALLING_EDGE;
+      config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
       strmode = "falling";
       break;
     case INT_EDGE_RISING:
-      req.eventflags  = GPIOEVENT_REQUEST_RISING_EDGE;
+      config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING;
       strmode = "rising";
       break;
     case INT_EDGE_BOTH:
-      req.eventflags  = GPIOEVENT_REQUEST_BOTH_EDGES;
+      config.flags |= (GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING);
       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) {
-    ReportDeviceError("get line event", pin , strmode, ret);
+  strcpy(req.consumer, "wiringpi_gpio_irq");
+  
+  if (debounce_period_us) {
+               attr = config.num_attrs;
+               config.num_attrs++;
+        gpiotools_set_bit(&config.attrs[attr].mask, 0);
+               config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
+               config.attrs[attr].attr.debounce_period_us = debounce_period_us;
+  }
+  
+  req.num_lines = 1;
+  req.offsets[0] = pin;
+  req.event_buffer_size = 32;
+  req.config = config;
+
+  ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req);
+  if (ret == -1) {
+    ReportDeviceError("GPIO_V2_GET_LINE_IOCTL", 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;
   isrFds [pin] = fd_line;
+  isrDebouncePeriodUs[pin] = debounce_period_us; 
+  
+/* set event fd nonbloack read */ 
+  /*
   int flags = fcntl(fd_line, F_GETFL);
   flags |= O_NONBLOCK;
   ret = fcntl(fd_line, F_SETFL, flags);
@@ -2707,30 +2701,109 @@ int waitForInterruptInit (int pin, int mode)
     fprintf(stderr, "wiringPi: ERROR: fcntl set nonblock return=%d\n", ret);
     return -1;
   }
-
+*/
   return 0;
 }
 
 
+/*
+ * waitForInterrupt:
+ *     Pi Specific.
+ *     Wait for Interrupt on a GPIO pin.
+ *     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.
+ *  Returns timestamp in microseconds on interrupt
+ *********************************************************************************
+ */
+
+long long int waitForInterrupt (int pin, int edgeMode, int mS, unsigned long debounce_period_us)    // ms < 0 wait infinite, = 0 return immediately, > 0 wait timeout
+{
+  long long int ret;
+  int fd;
+  struct pollfd polls ;
+  struct gpio_v2_line_event evdata;
+  
+  if (wiringPiMode == WPI_MODE_PINS)
+    pin = pinToGpio [pin] ;
+  else if (wiringPiMode == WPI_MODE_PHYS)
+    pin = physToGpio [pin] ;
+
+  if (waitForInterruptInit (pin, edgeMode, debounce_period_us ) != 0)
+    return -1 ;
+
+  fd = isrFds[pin];
+  // Setup poll structure
+  polls.fd      = fd;
+  polls.events  = POLLIN | POLLERR ;
+  polls.revents = 0;
+
+  ret = (long long int)poll(&polls, 1, mS);
+  
+  if (ret < 0) {
+    if (wiringPiDebug)  
+      fprintf(stderr, "wiringPi: ERROR: poll returned=%lld\n", ret);
+  } else if (ret == 0) { 
+    if (wiringPiDebug)  
+      fprintf(stderr, "wiringPi: timeout: poll returned=%lld\n", ret);
+  }
+  else {
+    if (wiringPiDebug)
+      printf ("wiringPi: IRQ line %d received %lld, fd=%d\n", pin, ret, isrFds[pin]) ;
+    if (polls.revents & POLLIN) {  
+    /* read event data */
+      int readret = read(isrFds [pin], &evdata, sizeof(evdata));
+      if (readret == sizeof(evdata)) {
+        if (wiringPiDebug)
+          printf ("wiringPi: IRQ at PIN: %d, timestamp: %lld\n", evdata.offset, evdata.timestamp_ns) ;
+
+        switch (evdata.id) {
+                 case GPIO_V2_LINE_EVENT_RISING_EDGE:
+            if (wiringPiDebug)
+                     printf("wiringPi: rising edge\n");
+                       break;
+                 case GPIO_V2_LINE_EVENT_FALLING_EDGE:
+            if (wiringPiDebug)
+                         printf("wiringPi: falling edge\n");
+                       break;
+                 default:
+            if (wiringPiDebug) 
+                     printf("wiringPi: unknown event\n");
+            break;
+               }        
+        ret = evdata.timestamp_ns / 1000LL;    // nanoseconds u64 to microseconds
+      }
+      else {
+        ret = -1;
+      }
+    }
+  }
+  return ret;
+}
+
+
 int waitForInterruptClose (int pin) {
   if (isrFds[pin]>0) {
     if (wiringPiDebug) {
       printf ("wiringPi: waitForInterruptClose close thread 0x%lX\n", (unsigned long)isrThreads[pin]) ;
     }
-    if (isrThreads[pin] && 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");
+    if (isrThreads[pin] != 0) {
+      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(isrFds [pin]);
   }
   isrFds [pin] = -1;
   isrFunctions [pin] = NULL;
-  lastcall[pin] = 0;
+  isrDebouncePeriodUs[pin] = 0;
+  
   /* -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);
@@ -2744,6 +2817,77 @@ int waitForInterruptClose (int pin) {
 }
 
 
+/*
+ * wfi:
+ *     Pi Specific.
+ *     Wait for Interrupt on a GPIO pin, called from interruptHandler
+ *  Returns timestamp in microseconds on interrupt
+ *********************************************************************************
+ */
+
+long long int wfi(int pin) 
+{
+  long long int ret;
+  int fd;
+  struct pollfd polls ;
+  struct gpio_v2_line_event evdata;
+  
+  if (wiringPiMode == WPI_MODE_PINS)
+    pin = pinToGpio [pin] ;
+  else if (wiringPiMode == WPI_MODE_PHYS)
+    pin = physToGpio [pin] ;
+
+  if ((fd = isrFds [pin]) == -1)
+    return -2 ;
+
+  // Setup poll structure
+  polls.fd      = fd;
+  polls.events  = POLLIN | POLLERR ;
+  polls.revents = 0;
+
+  ret = (long long int)poll(&polls, 1, -1);     // no timeout, wait forevver
+  
+  if (ret < 0) {
+    if (wiringPiDebug)  
+      fprintf(stderr, "wiringPi: ERROR: poll returned=%lld\n", ret);
+  } else if (ret == 0) { 
+    if (wiringPiDebug)  
+      fprintf(stderr, "wiringPi: timeout: poll returned=%lld\n", ret);
+  }
+  else {
+    if (wiringPiDebug)
+      printf ("wiringPi: IRQ line %d received %lld, fd=%d\n", pin, ret, isrFds[pin]) ;
+    if (polls.revents & POLLIN) {  
+    /* read event data */
+      int readret = read(isrFds [pin], &evdata, sizeof(evdata));
+      if (readret == sizeof(evdata)) {
+        if (wiringPiDebug)
+          printf ("wiringPi: IRQ at PIN: %d, timestamp: %lld\n", evdata.offset, evdata.timestamp_ns) ;
+
+        switch (evdata.id) {
+                 case GPIO_V2_LINE_EVENT_RISING_EDGE:
+            if (wiringPiDebug)
+                     printf("wiringPi: rising edge\n");
+                       break;
+                 case GPIO_V2_LINE_EVENT_FALLING_EDGE:
+            if (wiringPiDebug)
+                         printf("wiringPi: falling edge\n");
+                       break;
+                 default:
+            if (wiringPiDebug) 
+                     printf("wiringPi: unknown event\n");
+            break;
+               }        
+        ret = evdata.timestamp_ns / 1000LL;    // nanoseconds u64 to microseconds
+      }
+      else {
+        ret = -1;
+      }
+    }
+  }
+  return ret;
+}
+
 int wiringPiISRStop (int pin) {
   return waitForInterruptClose (pin);
 }
@@ -2756,20 +2900,89 @@ int wiringPiISRStop (int pin) {
  *********************************************************************************
  */
 
-static void *interruptHandler (void *arg)
+void *interruptHandler (void *arg)
 {
-  int pin ;
-  int bouncetime;
+  const char* strmode = ""; 
+  int pin, mode ;
+  unsigned long debounce_period_us;
+  struct gpio_v2_line_config config;
+  struct gpio_v2_line_request req;
+  int attr, ret;
   
-  (void)piHiPri (55) ; // Only effective if we run as root
-
-  pin   = pinPass ;
-  bouncetime = *(int *)arg;
+  pin = *(int *)arg;
+  
+/*  pin   = pinPass ; 
   pinPass = -1 ;
+*/  
+  if (wiringPiGpioDeviceGetFd()<0) {
+    return NULL;
+  }
+    
+  mode = isrMode[pin];
+  debounce_period_us = isrDebouncePeriodUs[pin];
+  if (wiringPiDebug) {
+    printf ("interruptHandler: GPIO line %d, mode %d, debounce_period_us %lu \n", pin, mode, debounce_period_us) ;
+  } 
+  
+  memset(&req, 0, sizeof(req));
+  memset(&config, 0, sizeof(config));
+  
+  /* setup config */
+  config.flags = GPIO_V2_LINE_FLAG_INPUT;
+  switch(mode) {
+    default:
+    case INT_EDGE_SETUP:
+      if (wiringPiDebug) {
+        printf ("wiringPi: waitForInterruptMode mode INT_EDGE_SETUP - exiting\n") ;
+      }
+      return NULL;
+    case INT_EDGE_FALLING:
+      config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
+      strmode = "falling";
+      break;
+    case INT_EDGE_RISING:
+      config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING;
+      strmode = "rising";
+      break;
+    case INT_EDGE_BOTH:
+      config.flags |= (GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING);
+      strmode = "both";
+      break;
+  }
+  strcpy(req.consumer, "wiringpi_gpio_irq");
+  
+  if (debounce_period_us) {
+               attr = config.num_attrs;
+               config.num_attrs++;
+        gpiotools_set_bit(&config.attrs[attr].mask, 0);
+               config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
+               config.attrs[attr].attr.debounce_period_us = debounce_period_us;
+  }
+  
+  req.num_lines = 1;
+  req.offsets[0] = pin;
+  req.config = config;
+
+  ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req);
+  if (ret == -1) {
+    ReportDeviceError("get line event", pin , strmode, ret);
+    return NULL;
+  }
+/*
+  if (wiringPiDebug) {
+    printf ("wiringPi: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ;
+  }
+*/
+  /* set event fd  */
+  int fd_line = req.fd;
+  isrFds [pin] = fd_line;
   
+  (void)piHiPri (55) ; // Only effective if we run as root
+
   for (;;) {
-    long long int ret = waitForInterrupt(pin, -1, bouncetime);
-    if ( ret> 0) {      // return timestamp in microseconds
+    long long int ret = wfi(pin);       // poll for event and return timestamp
+    if ( ret> 0) {                      // return timestamp in microseconds
       if (wiringPiDebug) {
         printf ("wiringPi: call function\n") ;
       }
@@ -2795,10 +3008,11 @@ static void *interruptHandler (void *arg)
  *     Pi Specific.
  *     Take the details and create an interrupt handler that will do a call-
  *     back to the user supplied function.
+ *  debounce_period_us in microseconds
  *********************************************************************************
  */
 
-int wiringPiISR (int pin, int mode, void (*function)(unsigned int, long long int), int bouncetime)
+int wiringPiISR (int pin, int edgeMode, void (*function)(unsigned int, long long int), unsigned long debounce_period_us)
 {
   const int maxpin = GetMaxPin();
 
@@ -2806,22 +3020,24 @@ int wiringPiISR (int pin, int mode, void (*function)(unsigned int, long long int
     return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-%d (%d)\n", maxpin, pin) ;
   if (wiringPiMode == WPI_MODE_UNINITIALISED)
     return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ;
+     
+  if (wiringPiMode == WPI_MODE_PINS) {
+    pin = pinToGpio [pin] ;
+  } else if (wiringPiMode == WPI_MODE_PHYS) {
+    pin = physToGpio [pin] ;
+  }
+  
   if (wiringPiDebug) {
-    printf ("wiringPi: wiringPiISR pin %d, mode %d\n", pin, mode) ;
+    printf ("wiringPi: wiringPiISR pin %d, edgeMode %d\n", pin, edgeMode) ;
   }
   if (isrFunctions [pin]) {
-    printf ("wiringPi: ISR function alread active, ignoring \n") ;
+    printf ("wiringPi: ISR function already active, ignoring \n") ;
   }
 
   isrFunctions [pin] = function ;
-  isrMode[pin] = mode;
-  lastcall[pin] = 0;
-  if(waitForInterruptInit (pin, mode)<0) {
-    if (wiringPiDebug) {
-      fprintf (stderr, "wiringPi: waitForInterruptInit failed\n") ;
-    }
-  }
-
+  isrMode[pin] = edgeMode;
+  isrDebouncePeriodUs[pin] = debounce_period_us;
+  
   if (wiringPiDebug) {
     printf ("wiringPi: mutex in\n") ;
   }
@@ -2830,12 +3046,17 @@ int wiringPiISR (int pin, int mode, void (*function)(unsigned int, long long int
     if (wiringPiDebug) {
       printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]);
     }
-    if (pthread_create (&isrThreads[pin], NULL, interruptHandler, &bouncetime)==0) {
+    if (pthread_create (&isrThreads[pin], NULL, interruptHandler, &pin)==0) {
       if (wiringPiDebug) {
         printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]);
       }
-      while (pinPass != -1)
-        delay (1) ;
+/*      while (pinPass != -1)
+        delay (1) ; */
+    // wait so that interruptHandler is up und running. 
+    // when interruptHandler is running, the calling function wiringPiISR
+    // must be still alive, otherwise the thread argument &pin points into nirwana,
+    // when it is picked up from interruptHandler.
+      delay (10);
     } else {
       if (wiringPiDebug) {
         printf("wiringPi: pthread_create failed\n");
@@ -3187,12 +3408,12 @@ int wiringPiSetup (void)
 
   /**/ if (piGpioLayout () == GPIO_LAYOUT_PI1_REV1)    // A, B, Rev 1, 1.1
   {
-     pinToGpio =  pinToGpioR1 ;
+    pinToGpio =  pinToGpioR1 ;
     physToGpio = physToGpioR1 ;
   }
   else                                         // A2, B2, A+, B+, CM, Pi2, Pi3, Zero, Zero W, Zero 2 W
   {
-     pinToGpio =  pinToGpioR2 ;
+    pinToGpio =  pinToGpioR2 ;
     physToGpio = physToGpioR2 ;
   }
 
@@ -3201,7 +3422,7 @@ int wiringPiSetup (void)
 //     Try /dev/mem. If that fails, then
 //     try /dev/gpiomem. If that fails then game over.
 
-       const char* gpiomemGlobal = gpiomem_global;
+  const char* gpiomemGlobal = gpiomem_global;
   const char* gpiomemModule = gpiomem_BCM;
 
   if (PI_MODEL_5 == model) {
@@ -3242,7 +3463,7 @@ int wiringPiSetup (void)
     printf ("wiringPi: access to %s succeded %d\n", usingGpioMem ? gpiomemModule : gpiomemGlobal, fd) ;
   }
 //     GPIO:
- if (PI_MODEL_5 != model) {
 if (PI_MODEL_5 != model) {
    //Set the offsets into the memory interface.
 
     GPIO_PADS  = piGpioBase + 0x00100000 ;
index 7659d84c4130d25a26ea923f7ea4bf4b50901dcc..e7cbfb6abf954d284bd7ec50f8e6932af15a2948 100644 (file)
@@ -289,11 +289,11 @@ extern          void digitalWriteByte2   (int value) ;
 // Interrupts
 //     (Also Pi hardware specific)
 
-extern long long int  waitForInterrupt    (int pin, int mS, int bouncetime) ;
-extern int  wiringPiISR         (int pin, int mode, void (*function)(unsigned int, long long int), int bouncetime) ;
+extern long long int  waitForInterrupt    (int pin, int edgeMode, int mS, unsigned long debounce_period_us) ;
+extern int  wiringPiISR         (int pin, int mode, void (*function)(unsigned int, long long int), unsigned long debounce_period_us) ;
 extern int  wiringPiISRStop     (int pin) ;  //V3.2
 extern int  waitForInterruptClose(int pin) ; //V3.2
-extern int  waitForInterruptInit (int pin, int mode); //v3.2
+//  extern int  waitForInterruptInit (int pin, int mode); //v3.2
 
 // Threads