Merge pull request #318 from phylax2020/development

Upgrade to GPIO_V2 IOCTL with debounce option
This commit is contained in:
Manfred Wallner
2025-02-13 21:39:39 +01:00
committed by GitHub
6 changed files with 666 additions and 180 deletions

View File

@@ -1 +1 @@
3.14
3.14

View File

@@ -20,13 +20,13 @@ sudo apt install git
git clone https://github.com/WiringPi/WiringPi.git
cd WiringPi
./build debian
mv debian-template/wiringpi-3.0-1.deb .
mv debian-template/wiringpi-3.13.deb .
```
**Debian-Paket installieren:**
```bash
sudo apt install ./wiringpi-3.0-1.deb
sudo apt install ./wiringpi-3.13.deb
```
**Debian-Paket deinstallieren:**
@@ -291,21 +291,27 @@ Registriert eine Interrupt Service Routine (ISR) bzw. Funktion die bei Flankenwe
>>>
```C
int wiringPiISR(int pin, int mode, void (*function)(void));
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
``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
``*function``: Funktionspointer für ISR
``*function``: Funktionspointer für ISR mit Rückgabeparameter pin und Zeitstempel:
> unsigned int: pin
> long long int: Zeitstempel
``bouncetime``: Entprellzeit in Microsekunden, 0 ms schaltet das Entprellen ab
``Rückgabewert``:
> 0 ... Erfolgreich
<!-- > <>0 ... Fehler, zur Zeit nicht implementiert -->
Beispiel siehe wiringPiISRStop.
Beispiel siehe waitForInterrupt.
### wiringPiISRStop
@@ -323,42 +329,148 @@ int wiringPiISRStop (int pin)
<!-- > <>0 ... Fehler, zur Zeit nicht implementiert -->
**Beispiel:**
```C
static volatile int edgeCounter;
static void isr(void) {
edgeCounter++;
}
int main (void) {
wiringPiSetupPinType(WPI_PIN_BCM);
edgeCounter = 0;
wiringPiISR (17, INT_EDGE_RISING, &isr);
Sleep(1000);
printf("%d rinsing edges\n", )
wiringPiISRStop(17) ;
}
```
### waitForInterrupt
Wartet auf einen Aufruf der Interrupt Service Routine (ISR) mit Timeout.
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
int waitForInterrupt (int pin, int mS)
long long int waitForInterrupt (int pin, int edgeMode, int mS, unsigned long bouncetime)
```
``pin``: Der gewünschte Pin (BCM-, WiringPi- oder Pin-Nummer).
``mS``: Timeout in Milisekunden.
``Rückgabewert``: Fehler
> 0 ... Erfolgreich
> -1 ... GPIO Device Chip nicht erfolgreich geöffnet
> -2 ... ISR wurde nicht registriert (wiringPiISR muss aufgerufen werden)
``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 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
**Beispiel:**
```C
/*
* isr_debounce.c:
* Wait for Interrupt test program WiringPi >=3.14 - ISR method
*
*
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
#include <time.h>
#define BOUNCETIME 3000 // microseconds
#define BOUNCETIME_WFI 300
#define TIMEOUT 10000
//*************************************
// BCM pins
// IRQpin : setup as input with internal pullup. Connected with push button to GND with 1K resistor in series.
// OUTpin : connected to a LED with 470 Ohm resistor in series to GND. Toggles LED with every push button pressed.
//*************************************
#define IRQpin 16
#define OUTpin 12
int toggle = 0;
/*
* myInterrupt:
*********************************************************************************
*/
static void wfi (unsigned int gpio, long long int timestamp) {
// struct timeval now;
long long int timenow, diff;
struct timespec curr;
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) {
printf("clock_gettime error");
return;
}
timenow = curr.tv_sec * 1000000LL + curr.tv_nsec/1000L; // convert to microseconds
diff = timenow - timestamp;
printf("gpio BCM = %d, IRQ timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", gpio, timestamp, timenow, diff);
if (toggle == 0) {
digitalWrite (OUTpin, HIGH) ;
toggle = 1;
}
else {
digitalWrite (OUTpin, LOW) ;
toggle = 0;
}
}
int main (void)
{
int major, minor;
long long int ret;
wiringPiVersion(&major, &minor);
printf("\nISR debounce test (WiringPi %d.%d)\n\n", major, minor);
wiringPiSetupGpio() ;
pinMode(IRQpin, INPUT);
// pull up/down mode (PUD_OFF, PUD_UP, PUD_DOWN) => down
pullUpDnControl(IRQpin, PUD_UP);
pinMode(OUTpin, OUTPUT);
digitalWrite (OUTpin, LOW) ;
printf("Testing waitForInterrupt IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT);
ret = waitForInterrupt(IRQpin, INT_EDGE_FALLING, TIMEOUT, BOUNCETIME_WFI );
if (ret < 0) {
printf("waitForInterrupt returned error %lld\n", ret);
wiringPiISRStop (IRQpin) ;
pinMode(OUTpin, INPUT);
return 0;
}
else if (ret == 0) {
printf("waitForInterrupt timed out %lld\n\n", ret);
wiringPiISRStop (IRQpin) ;
}
else {
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 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) ;
getc(stdin);
wiringPiISRStop (IRQpin) ;
pinMode(OUTpin, INPUT);
return 0 ;
}
```
## Hardware PWM (Pulsweitenmodulation)
@@ -564,4 +676,4 @@ if (fd>0) {
## SPI - Bus
...
...

116
examples/isr_debounce.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* isr_debounce.c:
* Wait for Interrupt test program WiringPi >=3.13 - ISR method
*
*
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <time.h>
#define BOUNCETIME 300
#define TIMEOUT 10000
//*************************************
// BCM pins
// IRQpin : setup as input with internal pullup. Connected with push button to GND with 1K resistor in series.
// OUTpin : connected to a LED with 470 Ohm resistor in series to GND. Toggles LED with every push button pressed.
//*************************************
#define IRQpin 16
#define OUTpin 12
int toggle = 0;
/*
* myInterrupt:
*********************************************************************************
*/
static void wfi (unsigned int gpio, long long int timestamp) {
// struct timeval now;
long long int timenow, diff;
struct timespec curr;
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) {
printf("clock_gettime error");
return;
}
timenow = curr.tv_sec * 1000000LL + curr.tv_nsec/1000L; // convert to microseconds
diff = timenow - timestamp;
printf("gpio BCM = %d, IRQ timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", gpio, timestamp, timenow, diff);
if (toggle == 0) {
digitalWrite (OUTpin, HIGH) ;
toggle = 1;
}
else {
digitalWrite (OUTpin, LOW) ;
toggle = 0;
}
}
int main (void)
{
int major, minor;
long long int ret;
wiringPiVersion(&major, &minor);
printf("\nISR debounce test (WiringPi %d.%d)\n\n", major, minor);
wiringPiSetupGpio() ;
pinMode(IRQpin, INPUT);
// pull up/down mode (PUD_OFF, PUD_UP, PUD_DOWN) => down
pullUpDnControl(IRQpin, PUD_UP);
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);
if (ret < 0) {
printf("waitForInterrupt returned error %lld\n", ret);
wiringPiISRStop (IRQpin) ;
pinMode(OUTpin, INPUT);
return 0;
}
else if (ret == 0) {
printf("waitForInterrupt timed out %lld\n\n", ret);
wiringPiISRStop (IRQpin) ;
}
else {
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("To stop program hit return key\n\n");
wiringPiISR (IRQpin, INT_EDGE_FALLING, &wfi, BOUNCETIME) ;
// sleep(30);
getc(stdin);
wiringPiISRStop (IRQpin) ;
pinMode(OUTpin, INPUT);
return 0 ;
}

View File

@@ -177,7 +177,7 @@ void printgpio(const char* text) {
}
}
static void wfi (void) {
static void wfi (unsigned int pin, long long int timestamp) {
globalCounter++;
if(globalCounter>=iterations) {
printgpio("finished\n");
@@ -217,7 +217,7 @@ void doWfi (int argc, char *argv [])
timeoutSec = atoi(argv [5]);
}
if (wiringPiISR (pin, mode, &wfi) < 0)
if (wiringPiISR (pin, mode, &wfi, 0) < 0)
{
fprintf (stderr, "%s: wfi: Unable to setup ISR: %s\n", argv [1], strerror (errno)) ;
exit (1) ;

View 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>
@@ -477,11 +478,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])(void) ;
static void (*isrFunctions [64])(unsigned int, long long int) ;
static pthread_t isrThreads[64];
static int isrMode[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
@@ -1753,11 +1757,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
@@ -1772,17 +1779,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];
@@ -1882,16 +1897,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);
@@ -2057,20 +2072,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
@@ -2154,7 +2169,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));
}
//*********************************************
/*
@@ -2164,19 +2205,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
}
@@ -2258,7 +2303,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) ;
@@ -2266,22 +2313,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 ;
@@ -2579,63 +2629,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.
*********************************************************************************
*/
int waitForInterrupt (int pin, int mS)
{
int fd, ret;
struct pollfd polls ;
struct gpioevent_data evdata;
//struct gpio_v2_line_request req2;
if (wiringPiMode == WPI_MODE_PINS)
pin = pinToGpio [pin] ;
else if (wiringPiMode == WPI_MODE_PHYS)
pin = physToGpio [pin] ;
//--------------------------------------------------------------------
// waitForInteruptInit
// Prepares waitForInterrupt for edgeMode, and debounce_period_us
//
// returns -1 on error
// returns 0 on success
//--------------------------------------------------------------------
if ((fd = isrFds [pin]) == -1)
return -2 ;
// Setup poll structure
polls.fd = fd;
polls.events = POLLIN | POLLERR ;
polls.revents = 0;
// 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, isrFds[pin]) ;
}
/* 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;
} else {
ret = 0;
}
}
return ret;
}
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) {
@@ -2643,15 +2653,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) {
@@ -2659,33 +2671,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);
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;
//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);
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);
@@ -2693,30 +2721,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 (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;
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);
@@ -2730,6 +2837,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);
}
@@ -2742,23 +2920,94 @@ int wiringPiISRStop (int pin) {
*********************************************************************************
*/
static void *interruptHandler (UNU void *arg)
void *interruptHandler (void *arg)
{
int pin ;
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;
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
pin = pinPass ;
pinPass = -1 ;
for (;;) {
int ret = waitForInterrupt(pin, -1);
if ( ret> 0) {
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") ;
}
if(isrFunctions [pin]) {
isrFunctions [pin] () ;
isrFunctions [pin] ((unsigned int)pin, ret) ;
}
// wait again - in the past forever - now can be stopped by waitForInterruptClose
} else if( ret< 0) {
@@ -2779,10 +3028,11 @@ static void *interruptHandler (UNU 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)(void))
int wiringPiISR (int pin, int edgeMode, void (*function)(unsigned int, long long int), unsigned long debounce_period_us)
{
const int maxpin = GetMaxPin();
@@ -2790,21 +3040,24 @@ int wiringPiISR (int pin, int mode, void (*function)(void))
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;
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") ;
}
@@ -2813,12 +3066,17 @@ int wiringPiISR (int pin, int mode, void (*function)(void))
if (wiringPiDebug) {
printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]);
}
if (pthread_create (&isrThreads[pin], NULL, interruptHandler, NULL)==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");
@@ -3170,12 +3428,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 ;
}
@@ -3184,7 +3442,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 (piRP1Model()) {
@@ -3225,7 +3483,7 @@ int wiringPiSetup (void)
printf ("wiringPi: access to %s succeded %d\n", usingGpioMem ? gpiomemModule : gpiomemGlobal, fd) ;
}
// GPIO:
if (!piRP1Model()) {
if (!piRP1Model()) {
//Set the offsets into the memory interface.
GPIO_PADS = piGpioBase + 0x00100000 ;

View File

@@ -298,8 +298,8 @@ extern void digitalWriteByte2 (int value) ;
// Interrupts
// (Also Pi hardware specific)
extern int waitForInterrupt (int pin, int mS) ;
extern int wiringPiISR (int pin, int mode, void (*function)(void)) ;
extern long long int waitForInterrupt (int pin, int edgeMode, int mS, unsigned long debounce_period_us) ; // V3.14 phylax
extern int wiringPiISR (int pin, int mode, void (*function)(unsigned int, long long int), unsigned long debounce_period_us) ; // v3.14 phylax
extern int wiringPiISRStop (int pin) ; //V3.2
extern int waitForInterruptClose(int pin) ; //V3.2