|
@@ -71,6 +71,8 @@ |
|
|
#include <sys/ioctl.h> |
|
|
#include <sys/ioctl.h> |
|
|
#include <asm/ioctl.h> |
|
|
#include <asm/ioctl.h> |
|
|
#include <byteswap.h> |
|
|
#include <byteswap.h> |
|
|
|
|
|
#include <sys/utsname.h> |
|
|
|
|
|
#include <linux/gpio.h> |
|
|
|
|
|
|
|
|
#include "softPwm.h" |
|
|
#include "softPwm.h" |
|
|
#include "softTone.h" |
|
|
#include "softTone.h" |
|
@@ -405,9 +407,10 @@ static int sysFds [64] = |
|
|
} ; |
|
|
} ; |
|
|
|
|
|
|
|
|
// ISR Data |
|
|
// ISR Data |
|
|
|
|
|
|
|
|
|
|
|
static int chipFd = -1; |
|
|
static void (*isrFunctions [64])(void) ; |
|
|
static void (*isrFunctions [64])(void) ; |
|
|
|
|
|
|
|
|
|
|
|
static pthread_t isrThreads[64]; |
|
|
|
|
|
static int isrMode[64]; |
|
|
|
|
|
|
|
|
// Doing it the Arduino way with lookup tables... |
|
|
// Doing it the Arduino way with lookup tables... |
|
|
// Yes, it's probably more innefficient than all the bit-twidling, but it |
|
|
// Yes, it's probably more innefficient than all the bit-twidling, but it |
|
@@ -851,6 +854,36 @@ static void usingGpioMemCheck (const char *what) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrintSystemStdErr () { |
|
|
|
|
|
struct utsname sys_info; |
|
|
|
|
|
if (uname(&sys_info) == 0) { |
|
|
|
|
|
fprintf (stderr, " wiringpi = %d.%d\n", VERSION_MAJOR, VERSION_MINOR); |
|
|
|
|
|
fprintf (stderr, " system name = %s\n", sys_info.sysname); |
|
|
|
|
|
//fprintf (stderr, " node name = %s\n", sys_info.nodename); |
|
|
|
|
|
fprintf (stderr, " release = %s\n", sys_info.release); |
|
|
|
|
|
fprintf (stderr, " version = %s\n", sys_info.version); |
|
|
|
|
|
fprintf (stderr, " machine = %s\n", sys_info.machine); |
|
|
|
|
|
if (strstr(sys_info.machine, "arm") == NULL && strstr(sys_info.machine, "aarch")==NULL) { |
|
|
|
|
|
fprintf (stderr, " -> This is not an ARM architecture; it cannot be a Raspberry Pi.\n") ; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void piFunctionOops (const char *function, const char* suggestion, const char* url) |
|
|
|
|
|
{ |
|
|
|
|
|
fprintf (stderr, "Oops: Function %s is not supported\n", function) ; |
|
|
|
|
|
PrintSystemStdErr(); |
|
|
|
|
|
if (suggestion) { |
|
|
|
|
|
fprintf (stderr, " -> Please %s\n", suggestion) ; |
|
|
|
|
|
} |
|
|
|
|
|
if (url) { |
|
|
|
|
|
fprintf (stderr, " -> See info at %s\n", url) ; |
|
|
|
|
|
} |
|
|
|
|
|
fprintf (stderr, " -> Check at https://github.com/wiringpi/wiringpi/issues.\n\n") ; |
|
|
|
|
|
exit (EXIT_FAILURE) ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* piGpioLayout: |
|
|
* piGpioLayout: |
|
@@ -876,12 +909,15 @@ static void usingGpioMemCheck (const char *what) |
|
|
* |
|
|
* |
|
|
********************************************************************************* |
|
|
********************************************************************************* |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
const char* revfile = "/proc/device-tree/system/linux,revision"; |
|
|
|
|
|
|
|
|
void piGpioLayoutOops (const char *why) |
|
|
void piGpioLayoutOops (const char *why) |
|
|
{ |
|
|
{ |
|
|
fprintf (stderr, "Oops: Unable to determine board revision from /proc/cpuinfo\n") ; |
|
|
|
|
|
|
|
|
fprintf (stderr, "Oops: Unable to determine Raspberry Pi board revision from %s and from /proc/cpuinfo\n", revfile) ; |
|
|
|
|
|
PrintSystemStdErr(); |
|
|
fprintf (stderr, " -> %s\n", why) ; |
|
|
fprintf (stderr, " -> %s\n", why) ; |
|
|
fprintf (stderr, " -> Check at https://github.com/wiringpi/wiringpi/issues.\n") ; |
|
|
|
|
|
|
|
|
fprintf (stderr, " -> WiringPi is designed for Raspberry Pi and can only be used with a Raspberry Pi.\n\n") ; |
|
|
|
|
|
fprintf (stderr, " -> Check at https://github.com/wiringpi/wiringpi/issues.\n\n") ; |
|
|
exit (EXIT_FAILURE) ; |
|
|
exit (EXIT_FAILURE) ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -905,10 +941,6 @@ int piBoardRev (void) |
|
|
return piGpioLayout () ; |
|
|
return piGpioLayout () ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* revfile = "/proc/device-tree/system/linux,revision"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* GetPiRevision(char* line, int linelength, unsigned int* revision) { |
|
|
const char* GetPiRevision(char* line, int linelength, unsigned int* revision) { |
|
|
|
|
|
|
|
|
const char* c = NULL; |
|
|
const char* c = NULL; |
|
@@ -1012,6 +1044,8 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) |
|
|
unsigned int revision = 0x00 ; |
|
|
unsigned int revision = 0x00 ; |
|
|
int bRev, bType, bProc, bMfg, bMem, bWarranty ; |
|
|
int bRev, bType, bProc, bMfg, bMem, bWarranty ; |
|
|
|
|
|
|
|
|
|
|
|
//piGpioLayoutOops ("this is only a test case"); |
|
|
|
|
|
|
|
|
c = GetPiRevision(line, maxlength, &revision); // device tree |
|
|
c = GetPiRevision(line, maxlength, &revision); // device tree |
|
|
if (NULL==c) { |
|
|
if (NULL==c) { |
|
|
c = GetPiRevisionLegacy(line, maxlength, &revision); // proc/cpuinfo |
|
|
c = GetPiRevisionLegacy(line, maxlength, &revision); // proc/cpuinfo |
|
@@ -1729,19 +1763,12 @@ void pullUpDnControl (int pin, int pud) |
|
|
|
|
|
|
|
|
int digitalRead (int pin) |
|
|
int digitalRead (int pin) |
|
|
{ |
|
|
{ |
|
|
char c ; |
|
|
|
|
|
struct wiringPiNodeStruct *node = wiringPiNodes ; |
|
|
struct wiringPiNodeStruct *node = wiringPiNodes ; |
|
|
|
|
|
|
|
|
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin |
|
|
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin |
|
|
{ |
|
|
{ |
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode |
|
|
|
|
|
{ |
|
|
|
|
|
if (sysFds [pin] == -1) |
|
|
|
|
|
return LOW ; |
|
|
|
|
|
|
|
|
|
|
|
lseek (sysFds [pin], 0L, SEEK_SET) ; |
|
|
|
|
|
read (sysFds [pin], &c, 1) ; |
|
|
|
|
|
return (c == '0') ? LOW : HIGH ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
|
|
|
return LOW ; |
|
|
else if (wiringPiMode == WPI_MODE_PINS) |
|
|
else if (wiringPiMode == WPI_MODE_PINS) |
|
|
pin = pinToGpio [pin] ; |
|
|
pin = pinToGpio [pin] ; |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
@@ -1804,17 +1831,8 @@ void digitalWrite (int pin, int value) |
|
|
|
|
|
|
|
|
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin |
|
|
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin |
|
|
{ |
|
|
{ |
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode |
|
|
|
|
|
{ |
|
|
|
|
|
if (sysFds [pin] != -1) |
|
|
|
|
|
{ |
|
|
|
|
|
if (value == LOW) |
|
|
|
|
|
write (sysFds [pin], "0\n", 2) ; |
|
|
|
|
|
else |
|
|
|
|
|
write (sysFds [pin], "1\n", 2) ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode |
|
|
return ; |
|
|
return ; |
|
|
} |
|
|
|
|
|
else if (wiringPiMode == WPI_MODE_PINS) |
|
|
else if (wiringPiMode == WPI_MODE_PINS) |
|
|
pin = pinToGpio [pin] ; |
|
|
pin = pinToGpio [pin] ; |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
@@ -1985,13 +2003,8 @@ void digitalWriteByte (const int value) |
|
|
|
|
|
|
|
|
FailOnModel5(); |
|
|
FailOnModel5(); |
|
|
|
|
|
|
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
{ |
|
|
{ |
|
|
for (pin = 0 ; pin < 8 ; ++pin) |
|
|
|
|
|
{ |
|
|
|
|
|
digitalWrite (pinToGpio [pin], value & mask) ; |
|
|
|
|
|
mask <<= 1 ; |
|
|
|
|
|
} |
|
|
|
|
|
return ; |
|
|
return ; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
@@ -2019,13 +2032,9 @@ unsigned int digitalReadByte (void) |
|
|
|
|
|
|
|
|
FailOnModel5(); |
|
|
FailOnModel5(); |
|
|
|
|
|
|
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
{ |
|
|
{ |
|
|
for (pin = 0 ; pin < 8 ; ++pin) |
|
|
|
|
|
{ |
|
|
|
|
|
x = digitalRead (pinToGpio [pin]) ; |
|
|
|
|
|
data = (data << 1) | x ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return 0; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
@@ -2052,19 +2061,10 @@ unsigned int digitalReadByte (void) |
|
|
|
|
|
|
|
|
void digitalWriteByte2 (const int value) |
|
|
void digitalWriteByte2 (const int value) |
|
|
{ |
|
|
{ |
|
|
register int mask = 1 ; |
|
|
|
|
|
register int pin ; |
|
|
|
|
|
|
|
|
|
|
|
FailOnModel5(); |
|
|
FailOnModel5(); |
|
|
|
|
|
|
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
{ |
|
|
{ |
|
|
for (pin = 20 ; pin < 28 ; ++pin) |
|
|
|
|
|
{ |
|
|
|
|
|
digitalWrite (pin, value & mask) ; |
|
|
|
|
|
mask <<= 1 ; |
|
|
|
|
|
} |
|
|
|
|
|
return ; |
|
|
|
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
@@ -2075,18 +2075,12 @@ void digitalWriteByte2 (const int value) |
|
|
|
|
|
|
|
|
unsigned int digitalReadByte2 (void) |
|
|
unsigned int digitalReadByte2 (void) |
|
|
{ |
|
|
{ |
|
|
int pin, x ; |
|
|
|
|
|
uint32_t data = 0 ; |
|
|
uint32_t data = 0 ; |
|
|
|
|
|
|
|
|
FailOnModel5(); |
|
|
FailOnModel5(); |
|
|
|
|
|
|
|
|
/**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_GPIO_SYS) |
|
|
{ |
|
|
{ |
|
|
for (pin = 20 ; pin < 28 ; ++pin) |
|
|
|
|
|
{ |
|
|
|
|
|
x = digitalRead (pin) ; |
|
|
|
|
|
data = (data << 1) | x ; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins |
|
|
data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins |
|
@@ -2099,7 +2093,7 @@ unsigned int digitalReadByte2 (void) |
|
|
* waitForInterrupt: |
|
|
* waitForInterrupt: |
|
|
* Pi Specific. |
|
|
* Pi Specific. |
|
|
* Wait for Interrupt on a GPIO pin. |
|
|
* 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 |
|
|
* the wiringPi access mode in-use. Maybe sometime it might get a better |
|
|
* way for a bit more efficiency. |
|
|
* way for a bit more efficiency. |
|
|
********************************************************************************* |
|
|
********************************************************************************* |
|
@@ -2107,11 +2101,12 @@ unsigned int digitalReadByte2 (void) |
|
|
|
|
|
|
|
|
int waitForInterrupt (int pin, int mS) |
|
|
int waitForInterrupt (int pin, int mS) |
|
|
{ |
|
|
{ |
|
|
int fd, x ; |
|
|
|
|
|
uint8_t c ; |
|
|
|
|
|
|
|
|
int fd, ret; |
|
|
struct pollfd polls ; |
|
|
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] ; |
|
|
pin = pinToGpio [pin] ; |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
|
else if (wiringPiMode == WPI_MODE_PHYS) |
|
|
pin = physToGpio [pin] ; |
|
|
pin = physToGpio [pin] ; |
|
@@ -2119,28 +2114,147 @@ int waitForInterrupt (int pin, int mS) |
|
|
if ((fd = sysFds [pin]) == -1) |
|
|
if ((fd = sysFds [pin]) == -1) |
|
|
return -2 ; |
|
|
return -2 ; |
|
|
|
|
|
|
|
|
// Setup poll structure |
|
|
|
|
|
|
|
|
// 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, 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 ret; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
polls.fd = fd ; |
|
|
|
|
|
polls.events = POLLPRI | POLLERR ; |
|
|
|
|
|
|
|
|
const char DEV_GPIO_PI[] ="/dev/gpiochip0"; |
|
|
|
|
|
const char DEV_GPIO_PI5[]="/dev/gpiochip4"; |
|
|
|
|
|
|
|
|
// Wait for it ... |
|
|
|
|
|
|
|
|
int waitForInterruptInit (int pin, int mode) |
|
|
|
|
|
{ |
|
|
|
|
|
const char* strmode = ""; |
|
|
|
|
|
|
|
|
x = poll (&polls, 1, mS) ; |
|
|
|
|
|
|
|
|
if (wiringPiMode == WPI_MODE_PINS) { |
|
|
|
|
|
pin = pinToGpio [pin] ; |
|
|
|
|
|
} else if (wiringPiMode == WPI_MODE_PHYS) { |
|
|
|
|
|
pin = physToGpio [pin] ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// If no error, do a dummy read to clear the interrupt |
|
|
|
|
|
// A one character read appars to be enough. |
|
|
|
|
|
|
|
|
/* 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) ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (x > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
lseek (fd, 0, SEEK_SET) ; // Rewind |
|
|
|
|
|
(void)read (fd, &c, 1) ; // Read & clear |
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
return x ; |
|
|
|
|
|
|
|
|
//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; |
|
|
|
|
|
isrFunctions [pin] = NULL; |
|
|
|
|
|
|
|
|
|
|
|
/* -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: |
|
|
* interruptHandler: |
|
|
* This is a thread and gets started to wait for the interrupt we're |
|
|
* This is a thread and gets started to wait for the interrupt we're |
|
@@ -2151,17 +2265,32 @@ int waitForInterrupt (int pin, int mS) |
|
|
|
|
|
|
|
|
static void *interruptHandler (UNU void *arg) |
|
|
static void *interruptHandler (UNU void *arg) |
|
|
{ |
|
|
{ |
|
|
int myPin ; |
|
|
|
|
|
|
|
|
int pin ; |
|
|
|
|
|
|
|
|
(void)piHiPri (55) ; // Only effective if we run as root |
|
|
(void)piHiPri (55) ; // Only effective if we run as root |
|
|
|
|
|
|
|
|
myPin = pinPass ; |
|
|
|
|
|
|
|
|
pin = pinPass ; |
|
|
pinPass = -1 ; |
|
|
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") ; |
|
|
|
|
|
} |
|
|
|
|
|
if(isrFunctions [pin]) { |
|
|
|
|
|
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 ; |
|
|
return NULL ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -2176,93 +2305,55 @@ static void *interruptHandler (UNU void *arg) |
|
|
|
|
|
|
|
|
int wiringPiISR (int pin, int mode, void (*function)(void)) |
|
|
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(); |
|
|
const int maxpin = GetMaxPin(); |
|
|
|
|
|
|
|
|
if (pin < 0 || pin > maxpin) |
|
|
if (pin < 0 || pin > maxpin) |
|
|
return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-%d (%d)\n", maxpin, pin) ; |
|
|
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") ; |
|
|
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 ; |
|
|
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) ; |
|
|
pthread_mutex_lock (&pinMutex) ; |
|
|
pinPass = pin ; |
|
|
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) ; |
|
|
pthread_mutex_unlock (&pinMutex) ; |
|
|
|
|
|
|
|
|
|
|
|
if (wiringPiDebug) { |
|
|
|
|
|
printf ("wiringPi: wiringPiISR finished\n") ; |
|
|
|
|
|
} |
|
|
return 0 ; |
|
|
return 0 ; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -2712,60 +2803,18 @@ int wiringPiSetupPhys (void) |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* wiringPiSetupSys: |
|
|
* wiringPiSetupSys: |
|
|
* Must be called once at the start of your program execution. |
|
|
|
|
|
* |
|
|
|
|
|
* Initialisation (again), however this time we are using the /sys/class/gpio |
|
|
|
|
|
* interface to the GPIO systems - slightly slower, but always usable as |
|
|
|
|
|
* a non-root user, assuming the devices are already exported and setup correctly. |
|
|
|
|
|
|
|
|
* GPIO Sysfs Interface for Userspace is deprecated |
|
|
|
|
|
* https://www.kernel.org/doc/html/v5.5/admin-guide/gpio/sysfs.html |
|
|
|
|
|
* The last Raspberry Pi Kernel with Sysfs was 6.1. |
|
|
|
|
|
* If needed, please use WiringPi 3.1. |
|
|
|
|
|
* |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
int wiringPiSetupSys (void) |
|
|
int wiringPiSetupSys (void) |
|
|
{ |
|
|
{ |
|
|
char fName [128] ; |
|
|
|
|
|
|
|
|
|
|
|
if (wiringPiSetuped) |
|
|
|
|
|
return 0 ; |
|
|
|
|
|
|
|
|
|
|
|
wiringPiSetuped = TRUE ; |
|
|
|
|
|
|
|
|
|
|
|
if (getenv (ENV_DEBUG) != NULL) |
|
|
|
|
|
wiringPiDebug = TRUE ; |
|
|
|
|
|
|
|
|
|
|
|
if (getenv (ENV_CODES) != NULL) |
|
|
|
|
|
wiringPiReturnCodes = TRUE ; |
|
|
|
|
|
|
|
|
|
|
|
if (wiringPiDebug) |
|
|
|
|
|
printf ("wiringPi: wiringPiSetupSys called\n") ; |
|
|
|
|
|
|
|
|
|
|
|
int model, rev, mem, maker, overVolted ; |
|
|
|
|
|
piBoardId (&model, &rev, &mem, &maker, &overVolted) ; |
|
|
|
|
|
|
|
|
|
|
|
if (piGpioLayout () == GPIO_LAYOUT_PI1_REV1) |
|
|
|
|
|
{ |
|
|
|
|
|
pinToGpio = pinToGpioR1 ; |
|
|
|
|
|
physToGpio = physToGpioR1 ; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
pinToGpio = pinToGpioR2 ; |
|
|
|
|
|
physToGpio = physToGpioR2 ; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Open and scan the directory, looking for exported GPIOs, and pre-open |
|
|
|
|
|
// the 'value' interface to speed things up for later |
|
|
|
|
|
|
|
|
|
|
|
for (int pin = 0, maxpin=GetMaxPin() ; pin <= maxpin ; ++pin) |
|
|
|
|
|
{ |
|
|
|
|
|
int pinFS = GPIOToSysFS(pin); |
|
|
|
|
|
if (pinFS>=0) { |
|
|
|
|
|
sprintf (fName, "/sys/class/gpio/gpio%d/value", pinFS) ; |
|
|
|
|
|
sysFds [pin] = open (fName, O_RDWR) ; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
initialiseEpoch () ; |
|
|
|
|
|
|
|
|
|
|
|
wiringPiMode = WPI_MODE_GPIO_SYS ; |
|
|
|
|
|
|
|
|
piFunctionOops("wiringPiSetupSys", |
|
|
|
|
|
"use wringpi 3.1 (last version with GPIO Sysfs interface)", |
|
|
|
|
|
"https://www.kernel.org/doc/html/v5.5/admin-guide/gpio/sysfs.html"); |
|
|
|
|
|
|
|
|
return 0 ; |
|
|
return 0 ; |
|
|
} |
|
|
} |