-
-
Notifications
You must be signed in to change notification settings - Fork 896
Bug fix for GPIO under recent Linux kernel versions #1562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ | |
struct ThreadArgs { | ||
void (*func)(); | ||
int gpioPin; | ||
struct gpiod_line *line; | ||
}; | ||
|
||
volatile bool interruptsEnabled = true; | ||
|
@@ -87,10 +88,10 @@ int piHiPri(const int pri) | |
void *interruptHandler(void *args) | ||
{ | ||
int fd; | ||
struct pollfd polls; | ||
char c; | ||
struct ThreadArgs *arguments = (struct ThreadArgs *)args; | ||
int gpioPin = arguments->gpioPin; | ||
struct gpiod_line *line = arguments->line; | ||
void (*func)() = arguments->func; | ||
delete arguments; | ||
|
||
|
@@ -101,28 +102,26 @@ void *interruptHandler(void *args) | |
return NULL; | ||
} | ||
|
||
// Setup poll structure | ||
polls.fd = fd; | ||
polls.events = POLLPRI | POLLERR; | ||
|
||
while (1) { | ||
// Wait for it ... | ||
int ret = poll(&polls, 1, -1); | ||
// New version | ||
int ret = gpiod_line_event_wait(line, NULL); | ||
if (ret < 0) { | ||
logError("Error waiting for interrupt: %s\n", strerror(errno)); | ||
break; | ||
} | ||
// Do a dummy read to clear the interrupt | ||
// A one character read appars to be enough. | ||
if (lseek (fd, 0, SEEK_SET) < 0) { | ||
logError("Interrupt handler error: %s\n", strerror(errno)); | ||
break; | ||
} | ||
if (read (fd, &c, 1) < 0) { | ||
logError("Interrupt handler error: %s\n", strerror(errno)); | ||
break; | ||
struct gpiod_line_event event; | ||
if (gpiod_line_event_read(line, &event) == 0) { | ||
if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) { | ||
logInfo("RISING Edge\n"); | ||
} else { | ||
logInfo("FALLING Edge\n"); | ||
} | ||
} | ||
|
||
// Call user function. | ||
logError("Calling user function\n"); | ||
|
||
pthread_mutex_lock(&intMutex); | ||
if (interruptsEnabled) { | ||
pthread_mutex_unlock(&intMutex); | ||
|
@@ -131,6 +130,8 @@ void *interruptHandler(void *args) | |
pthread_mutex_unlock(&intMutex); | ||
} | ||
} | ||
// Adding gpiod closing instructions | ||
gpiod_line_release(line); | ||
|
||
close(fd); | ||
|
||
|
@@ -153,72 +154,53 @@ void attachInterrupt(uint8_t gpioPin, void (*func)(), uint8_t mode) | |
usleep(1000); | ||
} | ||
|
||
// Export pin for interrupt | ||
if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) { | ||
logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", gpioPin, strerror(errno)); | ||
exit(1); | ||
} | ||
fprintf(fd, "%d\n", gpioPin); | ||
fclose(fd); | ||
char *chipname = "gpiochip0"; | ||
unsigned int line_num = gpioPin; | ||
struct gpiod_line_event event; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is unused as well |
||
struct gpiod_chip *chip; | ||
struct gpiod_line *line; | ||
|
||
// Wait a bit the system to create /sys/class/gpio/gpio<GPIO number> | ||
usleep(1000); | ||
|
||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ; | ||
if ((fd = fopen (fName, "w")) == NULL) { | ||
logError("attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", | ||
gpioPin, strerror(errno)); | ||
exit(1) ; | ||
chip = gpiod_chip_open_by_name(chipname); | ||
if (!chip) { | ||
logError("Open chip failed\n"); | ||
exit(1); | ||
} | ||
fprintf(fd, "in\n") ; | ||
fclose(fd) ; | ||
|
||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ; | ||
if ((fd = fopen(fName, "w")) == NULL) { | ||
logError("attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", gpioPin, | ||
strerror(errno)); | ||
exit(1) ; | ||
line = gpiod_chip_get_line(chip, line_num); | ||
if (!line) { | ||
logError("Get line failed\n"); | ||
exit(1); | ||
} | ||
|
||
switch (mode) { | ||
case CHANGE: | ||
fprintf(fd, "both\n"); | ||
gpiod_line_request_both_edges_events(line, "gpiointerrupt"); | ||
break; | ||
case FALLING: | ||
fprintf(fd, "falling\n"); | ||
gpiod_line_request_falling_edge_events(line, "gpiointerrupt"); | ||
break; | ||
case RISING: | ||
fprintf(fd, "rising\n"); | ||
gpiod_line_request_rising_edge_events(line, "gpiointerrupt"); | ||
break; | ||
case NONE: | ||
fprintf(fd, "none\n"); | ||
break; | ||
default: | ||
logError("attachInterrupt: Invalid mode\n"); | ||
fclose(fd); | ||
return; | ||
} | ||
fclose(fd); | ||
|
||
if (sysFds[gpioPin] == -1) { | ||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/value", gpioPin); | ||
if ((sysFds[gpioPin] = open(fName, O_RDONLY)) < 0) { | ||
if ((sysFds[gpioPin] = gpiod_line_event_get_fd(line)) < 0) { | ||
logError("Error reading pin %d: %s\n", gpioPin, strerror(errno)); | ||
exit(1); | ||
} | ||
} | ||
|
||
// Clear any initial pending interrupt | ||
ioctl(sysFds[gpioPin], FIONREAD, &count); | ||
for (int i = 0; i < count; ++i) { | ||
if (read(sysFds[gpioPin], &c, 1) == -1) { | ||
logError("attachInterrupt: failed to read pin status: %s\n", strerror(errno)); | ||
} | ||
} | ||
|
||
struct ThreadArgs *threadArgs = new struct ThreadArgs; | ||
threadArgs->func = func; | ||
threadArgs->gpioPin = gpioPin; | ||
threadArgs->line = line; | ||
|
||
// Create a thread passing the pin and function | ||
pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs); | ||
|
@@ -238,14 +220,6 @@ void detachInterrupt(uint8_t gpioPin) | |
close(sysFds[gpioPin]); | ||
sysFds[gpioPin] = -1; | ||
} | ||
|
||
FILE *fp = fopen("/sys/class/gpio/unexport", "w"); | ||
if (fp == NULL) { | ||
logError("Unable to unexport pin %d for interrupt\n", gpioPin); | ||
exit(1); | ||
} | ||
fprintf(fp, "%d", gpioPin); | ||
fclose(fp); | ||
} | ||
|
||
void interrupts() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,8 @@ | |
|
||
#include <stdint.h> | ||
|
||
#include <gpiod.h> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know if this is installed by default on Raspberry Pi OS? If it is not, we should probably document how to install the dependency. |
||
|
||
#define CHANGE 1 | ||
#define FALLING 2 | ||
#define RISING 3 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
143-146 are now all unused vars from deleted code (fd, fName, c, count)