Merge pull request #413 from WiringPi/wiringPiISR

Release 2026
This commit is contained in:
mstroh
2026-01-17 11:11:53 +01:00
committed by GitHub
26 changed files with 940 additions and 98 deletions

View File

@@ -1 +1 @@
3.16 3.18

View File

@@ -473,7 +473,7 @@ static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) {
edgeType = "falling"; edgeType = "falling";
else else
edgeType = "none"; edgeType = "none";
printf("gpio BCM = %d, IRQ edge = %s, timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", wfiStatus.gpioPin, edgeType, wfiStatus.timeStamp_us, timenow, diff); printf("gpio BCM = %d, IRQ edge = %s, timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", wfiStatus.pinBCM, edgeType, wfiStatus.timeStamp_us, timenow, diff);
if (toggle == 0) { if (toggle == 0) {
digitalWrite (OUTpin, HIGH); digitalWrite (OUTpin, HIGH);
toggle = 1; toggle = 1;
@@ -500,19 +500,19 @@ int main (void)
printf("Testing waitForInterrupt on both edges IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT); printf("Testing waitForInterrupt on both edges IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT);
struct WPIWfiStatus wfiStatus = waitForInterrupt2(IRQpin, INT_EDGE_BOTH, TIMEOUT, BOUNCETIME_WFI); struct WPIWfiStatus wfiStatus = waitForInterrupt2(IRQpin, INT_EDGE_BOTH, TIMEOUT, BOUNCETIME_WFI);
if (wfiStatus.status < 0) { if (wfiStatus.statusOK < 0) {
printf("waitForInterrupt returned error\n"); printf("waitForInterrupt returned error\n");
pinMode(OUTpin, INPUT); pinMode(OUTpin, INPUT);
return 0; return 0;
} }
else if (wfiStatus.status == 0) { else if (wfiStatus.statusOK == 0) {
printf("waitForInterrupt timed out\n\n"); printf("waitForInterrupt timed out\n\n");
} }
else { else {
if (wfiStatus.edge == INT_EDGE_FALLING) if (wfiStatus.edge == INT_EDGE_FALLING)
printf("waitForInterrupt: GPIO pin %d falling edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, wfiStatus.timeStamp_us); printf("waitForInterrupt: GPIO pin %d falling edge fired at %lld microseconds\n\n", wfiStatus.pinBCM, wfiStatus.timeStamp_us);
else else
printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, wfiStatus.timeStamp_us); printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.pinBCM, wfiStatus.timeStamp_us);
} }
printf("Testing IRQ @ GPIO%d on both edges and bouncetime %d microseconds. Toggle LED @ GPIO%d on IRQ.\n\n", IRQpin, BOUNCETIME, OUTpin); printf("Testing IRQ @ GPIO%d on both edges and bouncetime %d microseconds. Toggle LED @ GPIO%d on IRQ.\n\n", IRQpin, BOUNCETIME, OUTpin);
@@ -809,8 +809,8 @@ int wiringPiSPISetupMode(int channel, int speed, int mode)
int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode) int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode)
``` ```
``number``: SPI Nummer (typisch 0, bei Compute Modul 0-7). ``number``: SPI Nummer (typisch 0, bei Compute Modul 0-6).
``channel``: SPI Kanal (typisch 0 oder 1, bei Compute Modul 0-3). ``channel``: SPI Kanal (typisch 0 oder 1, bei Compute Modul oder entsprechenden overlay 0-4).
``speed``: SPI Taktrate. ``speed``: SPI Taktrate.
``mode``: SPI Modus (https://www.kernel.org/doc/Documentation/spi/spidev). ``mode``: SPI Modus (https://www.kernel.org/doc/Documentation/spi/spidev).
``Rückgabewert``: Datei Handle zum SPI-Bus ``Rückgabewert``: Datei Handle zum SPI-Bus

View File

@@ -470,7 +470,7 @@ static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) {
edgeType = "falling"; edgeType = "falling";
else else
edgeType = "none"; edgeType = "none";
printf("gpio BCM = %d, IRQ edge = %s, timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", wfiStatus.gpioPin, edgeType, wfiStatus.timeStamp_us, timenow, diff); printf("gpio BCM = %d, IRQ edge = %s, timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", wfiStatus.pinBCM, edgeType, wfiStatus.timeStamp_us, timenow, diff);
if (toggle == 0) { if (toggle == 0) {
digitalWrite (OUTpin, HIGH); digitalWrite (OUTpin, HIGH);
toggle = 1; toggle = 1;
@@ -497,19 +497,19 @@ int main (void)
printf("Testing waitForInterrupt on both edges IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT); printf("Testing waitForInterrupt on both edges IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT);
struct WPIWfiStatus wfiStatus = waitForInterrupt2(IRQpin, INT_EDGE_BOTH, TIMEOUT, BOUNCETIME_WFI); struct WPIWfiStatus wfiStatus = waitForInterrupt2(IRQpin, INT_EDGE_BOTH, TIMEOUT, BOUNCETIME_WFI);
if (wfiStatus.status < 0) { if (wfiStatus.statusOK < 0) {
printf("waitForInterrupt returned error\n"); printf("waitForInterrupt returned error\n");
pinMode(OUTpin, INPUT); pinMode(OUTpin, INPUT);
return 0; return 0;
} }
else if (wfiStatus.status == 0) { else if (wfiStatus.statusOK == 0) {
printf("waitForInterrupt timed out\n\n"); printf("waitForInterrupt timed out\n\n");
} }
else { else {
if (wfiStatus.edge == INT_EDGE_FALLING) if (wfiStatus.edge == INT_EDGE_FALLING)
printf("waitForInterrupt: GPIO pin %d falling edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, wfiStatus.timeStamp_us); printf("waitForInterrupt: GPIO pin %d falling edge fired at %lld microseconds\n\n", wfiStatus.pinBCM, wfiStatus.timeStamp_us);
else else
printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, wfiStatus.timeStamp_us); printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.pinBCM, wfiStatus.timeStamp_us);
} }
printf("Testing IRQ @ GPIO%d on both edges and bouncetime %d microseconds. Toggle LED @ GPIO%d on IRQ.\n\n", IRQpin, BOUNCETIME, OUTpin); printf("Testing IRQ @ GPIO%d on both edges and bouncetime %d microseconds. Toggle LED @ GPIO%d on IRQ.\n\n", IRQpin, BOUNCETIME, OUTpin);
@@ -798,8 +798,8 @@ int wiringPiSPISetupMode(int channel, int speed, int mode);
int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode); int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode);
``` ```
``number``: SPI number (typically 0, on Compute Module 0-7). ``number``: SPI number (typically 0, on Compute Module 0-6).
``channel``: SPI channel (typically 0 or 1, on Compute Module 0-3). ``channel``: SPI channel (typically 0 or 1, on Compute Module or the corresponding overlay 0-4).
``speed``: SPI clock speed in Hz (500,000 to 32,000,000). ``speed``: SPI clock speed in Hz (500,000 to 32,000,000).
``mode``: SPI mode ([www.kernel.org/doc/Documentation/spi/spidev](https://www.kernel.org/doc/Documentation/spi/spidev)). ``mode``: SPI mode ([www.kernel.org/doc/Documentation/spi/spidev](https://www.kernel.org/doc/Documentation/spi/spidev)).
``Return Value``: File handle to the SPI bus, or -1 on error. ``Return Value``: File handle to the SPI bus, or -1 on error.

View File

@@ -282,7 +282,7 @@ Please report bugs to https://github.com/WiringPi/WiringPi/issues
.SH COPYRIGHT .SH COPYRIGHT
Copyright (c) 2012-2025 Gordon Henderson and contributors Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
.br .br
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

View File

@@ -2,7 +2,7 @@
* gpio.c: * gpio.c:
* Swiss-Army-Knife, Set-UID command-line interface to the Raspberry * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry
* Pi's GPIO. * Pi's GPIO.
* Copyright (c) 2012-2025 Gordon Henderson and contributors * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/
@@ -916,7 +916,7 @@ static void doVersion (char *argv [])
wiringPiVersion (&vMaj, &vMin) ; wiringPiVersion (&vMaj, &vMin) ;
printf ("gpio version: %d.%d\n", vMaj, vMin) ; printf ("gpio version: %d.%d\n", vMaj, vMin) ;
printf ("Copyright (c) 2012-2025 Gordon Henderson and contributors\n") ; printf ("Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors\n") ;
printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
printf ("For details type: %s -warranty\n", argv [0]) ; printf ("For details type: %s -warranty\n", argv [0]) ;
printf ("\n") ; printf ("\n") ;
@@ -1033,7 +1033,7 @@ int main (int argc, char *argv [])
if (strcasecmp (argv [1], "-warranty") == 0) if (strcasecmp (argv [1], "-warranty") == 0)
{ {
printf ("gpio version: %s\n", VERSION) ; printf ("gpio version: %s\n", VERSION) ;
printf ("Copyright (c) 2012-2025 Gordon Henderson and contributors\n") ; printf ("Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors\n") ;
printf ("\n") ; printf ("\n") ;
printf (" This program is free software; you can redistribute it and/or modify\n") ; printf (" This program is free software; you can redistribute it and/or modify\n") ;
printf (" it under the terms of the GNU Leser General Public License as published\n") ; printf (" it under the terms of the GNU Leser General Public License as published\n") ;

View File

@@ -1,7 +1,7 @@
/* /*
* readall.c: * readall.c:
* The readall functions - getting a bit big, so split them out. * The readall functions - getting a bit big, so split them out.
* Copyright (c) 2012-2024 Gordon Henderson and contributors * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/

90
gpio/test/gpio_test1_piface1.sh Executable file
View File

@@ -0,0 +1,90 @@
#!/bin/bash
echo -e "🔧 Starting relay unit test for MCP23S17@Piface unit test hw\n\n"
# set pin 200207 as output
for i in {200..207}; do
gpio -x mcp23s17:200:0:0 mode $i out
done
# set pin 208215 as input
for i in {208..215}; do
gpio -x mcp23s17:200:0:0 mode $i in
gpio -x mcp23s17:200:0:0 mode $i up
done
# Define relay output addresses and corresponding feedback input addresses
relay_addresses=(200 201 207 206)
feedback_addresses=(214 215 212 213)
for round in {1..3}; do
echo -e "🔄 Round $round / 3\n"
# Loop through each relay
for i in "${!relay_addresses[@]}"; do
out=${relay_addresses[$i]}
in=${feedback_addresses[$i]}
echo "➡️ Relay/IO write test $((i+1)): Address $out → Feedback at $in"
# Turn ON
gpio -x mcp23s17:200:0:0 write "$out" 1
sleep 0.5
feedback_on=$(gpio -x mcp23s17:200:0:0 read "$in")
if [ "$feedback_on" -eq 0 ]; then
echo "✅ ON Test passed: Feedback is LOW as expected."
else
echo "❌ ON Test failed: Feedback is HIGH."
fi
# Turn OFF
gpio -x mcp23s17:200:0:0 write "$out" 0
sleep 0.5
feedback_off=$(gpio -x mcp23s17:200:0:0 read "$in")
if [ "$feedback_off" -eq 1 ]; then
echo "✅ OFF Test passed: Feedback is HIGH as expected."
else
echo "❌ OFF Test failed: Feedback is LOW."
fi
echo -e "\n"
sleep 0.5
done
for addr in {208..211}; do
echo "🔃 Pullup resistor test address $addr: "
gpio -x mcp23s17:200:0:0 mode "$addr" up
sleep 0.5
feedback_on=$(gpio -x mcp23s17:200:0:0 read "$addr")
if [ "$feedback_on" -eq 1 ]; then
echo "✅ PULLUP Test passed: Feedback is HIGH as expected."
else
echo "❌ PULLUP Test failed: Feedback is LOW."
fi
sleep 0.5
gpio -x mcp23s17:200:0:0 mode "$addr" down
sleep 0.5
feedback_on=$(gpio -x mcp23s17:200:0:0 read "$addr")
if [ "$feedback_on" -eq 1 ]; then
echo "✅ PULLDOWN Test passed: Feedback is LOW as expected."
else
echo "❌ PULLDOW Test failed: Feedback is HIGH."
fi
echo -e "\n"
sleep 0.5
done
done
#echo "🧹 Cleanup complete. All relays turned OFF."

View File

@@ -1,3 +1,3 @@
#define VERSION "3.16" #define VERSION "3.18"
#define VERSION_MAJOR 3 #define VERSION_MAJOR 3
#define VERSION_MINOR 16 #define VERSION_MINOR 18

2
wiringPi/gtest/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
googletest-main

92
wiringPi/gtest/Makefile Normal file
View File

@@ -0,0 +1,92 @@
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -Werror -g \
-Igoogletest-main/googletest/include -Igoogletest-main/googlemock/include
LDFLAGS := -pthread
WIRING_PI_LIBS := -lwiringPi
# Where to download googletest
GTEST_URL := https://github.com/google/googletest/archive/refs/heads/main.zip
GTEST_ZIP := googletest.zip
GTEST_DIR := googletest-main
# Output directory
BIN_DIR := bin
# Helper program
RUN_ISR_SRC := run_isr.cpp
RUN_ISR_BIN := $(BIN_DIR)/run_isr
# Need BCM17 <-> BCM18 connection
TEST_SRCS := \
test_isr_both.cpp \
test_isr_conflict_between_processes.cpp \
test_isr_falling.cpp \
test_isr_restart.cpp \
test_isr_restart2.cpp \
test_isr_rising.cpp \
test_isr_rising2.cpp
# Derive test binaries (in bin/)
TEST_BINS := $(addprefix $(BIN_DIR)/, $(TEST_SRCS:.cpp=))
# gtest/gmock sources
GTEST_SRCS := $(GTEST_DIR)/googletest/src/gtest-all.cc
GMOCK_SRCS := $(GTEST_DIR)/googlemock/src/gmock-all.cc
GTEST_MAIN := $(GTEST_DIR)/googletest/src/gtest_main.cc
GTEST_INCLUDES := -I$(GTEST_DIR)/googletest/include -I$(GTEST_DIR)/googlemock/include
GTEST_OBJS := $(GTEST_SRCS:.cc=.o)
GMOCK_OBJS := $(GMOCK_SRCS:.cc=.o)
GTEST_MAIN_OBJ := $(GTEST_MAIN:.cc=.o)
# Default: build everything
all: $(GTEST_DIR) $(BIN_DIR) $(TEST_BINS) $(RUN_ISR_BIN)
# Rule: build normal test binaries
$(filter-out $(BIN_DIR)/test_conflict_between_processes,$(TEST_BINS)): $(BIN_DIR)/%: %.cpp $(GTEST_OBJS) $(GMOCK_OBJS) $(GTEST_MAIN_OBJ)
$(CXX) $(CXXFLAGS) $< $(GTEST_OBJS) $(GMOCK_OBJS) $(GTEST_MAIN_OBJ) -o $@ $(LDFLAGS) $(WIRING_PI_LIBS)
# Special case: test_conflict_between_processes depends on run_isr
$(BIN_DIR)/test_conflict_between_processes: test_conflict_between_processes.cpp $(GTEST_OBJS) $(GMOCK_OBJS) $(GTEST_MAIN_OBJ) $(RUN_ISR_BIN)
$(CXX) $(CXXFLAGS) $< $(GTEST_OBJS) $(GMOCK_OBJS) $(GTEST_MAIN_OBJ) -o $@ $(LDFLAGS) $(WIRING_PI_LIBS)
# Build run_isr
$(RUN_ISR_BIN): $(RUN_ISR_SRC) | $(BIN_DIR)
$(CXX) $(CXXFLAGS) $< -o $@ $(WIRING_PI_LIBS)
# Ensure bin directory exists
$(BIN_DIR):
mkdir -p $(BIN_DIR)
# Download googletest if not already present
$(GTEST_DIR):
@echo "Downloading GoogleTest..."
curl -L $(GTEST_URL) -o $(GTEST_ZIP)
unzip -q $(GTEST_ZIP)
rm -f $(GTEST_ZIP)
# Generic rules for compiling gtest/gmock sources
%.o: %.cc
$(CXX) $(CXXFLAGS) $(GTEST_INCLUDES) -I$(GTEST_DIR)/googletest -I$(GTEST_DIR)/googlemock -c $< -o $@
# Run all tests
test: all
@failed=0; \
for t in $(TEST_BINS); do \
echo "Running $$t..."; \
./$$t || failed=1; \
done; \
if [ $$failed -eq 0 ]; then \
echo "✅ All tests passed."; \
else \
echo "❌ Some tests failed."; \
exit 1; \
fi
clean:
rm -f $(TEST_BINS) $(RUN_ISR_BIN)
distclean: clean
rm -rf $(GTEST_DIR) $(BIN_DIR)
.PHONY: all clean distclean test

26
wiringPi/gtest/README.md Normal file
View File

@@ -0,0 +1,26 @@
## Quick Start
g++ is required to build the test cases.
Connect wPi pin 1 (BCM 18) and wPi pin 0 (BCM 17) to run ISR tests.
Also, wPi pin 6 (BCM 25) should be unconnected.
Run `make test` or do following to run the test:
```
make googletest-main
make -j 4
make test
```
To clean up the environment:
```
make clean
```
## Dependencies
Googletest is downloaded during
the build for the first time. The downloaded items are in directory `googletest-main`. `make clean` keeps this directory. Run `make distclean`
to erase all built images including googletest.

View File

@@ -0,0 +1,31 @@
/*
* Helper program of test_conflict_between_processes.
*
* The program configures ISR on pin 1 (BCM 18) and polls for a termination request.
*/
#include <stdint.h>
#include <stdio.h>
#include <wiringPi.h>
#define LISTENER_PIN 1 // BCM 18
static uint8_t ok_to_stop = 0;
static void noop() {
fprintf(stderr, "interrupted\n");
ok_to_stop = 1;
}
int main(int, char *[]) {
fprintf(stderr, "start\n");
wiringPiSetup();
if (wiringPiISR(LISTENER_PIN, INT_EDGE_RISING, noop)) {
fprintf(stderr, "failed to start listener\n");
return -1;
}
fprintf(stderr, "start listening\n");
while (!ok_to_stop) {
delay(1000);
}
fprintf(stderr, "bye\n");
}

View File

@@ -0,0 +1,51 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
/**
* Tests ISR for both edges.
*/
class ISRBoth : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, LOW);
wiringPiISR(LISTENER_PIN, INT_EDGE_BOTH, ISRBoth::TriggerCount);
delay(100);
}
static uint32_t count;
static void TriggerCount() { ++count; }
protected:
virtual void SetUp() { count = 0; }
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
uint32_t ISRBoth::count = 0;
TEST_F(ISRBoth, Fundamental) {
EXPECT_EQ(count, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 2u);
}
TEST_F(ISRBoth, ThreeTriggers) {
for (int i = 0; i < 5; ++i) {
digitalWrite(TRIGGER_PIN, (i + 1) % 2);
delay(10);
}
EXPECT_EQ(count, 5u);
}

View File

@@ -0,0 +1,68 @@
#include <gtest/gtest.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
#define ANOTHER_LISTENER_PIN 6 // BCM 25
static void *remote_isr(void *) {
std::system("./bin/run_isr");
return NULL;
}
/**
* Tests ISR setup conflict between two processes.
*
* Another program 'run_isr' starts first that occupies the pin 31 for an ISR.
* This program should fail to start ISR on the same pin.
*/
class ISRConflict : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
digitalWrite(TRIGGER_PIN, LOW);
pthread_t tid;
pthread_create(&tid, NULL, remote_isr, NULL);
delay(1000);
}
static void TearDownTestSuite() {
delay(1000);
}
static uint32_t count;
static void TriggerCount() { ++count; }
static void TriggerCount2(WPIWfiStatus, void *userdata) {
++*(uint32_t *)userdata;
}
protected:
virtual void SetUp() { count = 0; }
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
uint32_t ISRConflict::count = 0;
TEST_F(ISRConflict, TestConflictBetweenProcesses) {
// The ISRs should fail to start because run_isr is listening on the
// same port
EXPECT_EQ(
wiringPiISR(LISTENER_PIN, INT_EDGE_FALLING, ISRConflict::TriggerCount),
-1);
EXPECT_EQ(wiringPiISR2(LISTENER_PIN, INT_EDGE_FALLING,
ISRConflict::TriggerCount2, 0, &ISRConflict::count),
-1);
// to exit run_isr
digitalWrite(TRIGGER_PIN, HIGH);
}

View File

@@ -0,0 +1,57 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
/**
* Tests ISR for falling edges.
*/
class ISRFalling : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, HIGH);
wiringPiISR(LISTENER_PIN, INT_EDGE_FALLING, ISRFalling::TriggerCount);
delay(100);
}
static void TearDownTestSuite() { digitalWrite(TRIGGER_PIN, LOW); }
static uint32_t count;
static void TriggerCount() { ++count; }
protected:
virtual void SetUp() { count = 0; }
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
}
};
uint32_t ISRFalling::count = 0;
TEST_F(ISRFalling, Fundamental) {
EXPECT_EQ(count, 0u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
}
TEST_F(ISRFalling, ThreeTriggers) {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
count = 0;
for (int i = 0; i < 6; ++i) {
delay(10);
digitalWrite(TRIGGER_PIN, (i + 1) % 2);
}
delay(10);
EXPECT_EQ(count, 3u);
}

View File

@@ -0,0 +1,68 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
#define ANOTHER_LISTENER_PIN 6 // BCM 25
/**
* Tests restarting ISR.
*/
class ISRRestart : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, LOW);
wiringPiISR(LISTENER_PIN, INT_EDGE_RISING, ISRRestart::TriggerCount);
delay(100);
}
static uint32_t count;
static void TriggerCount() { ++count; }
static void TriggerCountDown() { --count; }
protected:
virtual void SetUp() { count = 0; }
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
uint32_t ISRRestart::count = 0;
TEST_F(ISRRestart, RestartISR) {
// fundamental ISR test
EXPECT_EQ(count, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 1u);
// stop the ISR
EXPECT_EQ(wiringPiISRStop(LISTENER_PIN), 0);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
// start another ISR on the same pin
EXPECT_EQ(
wiringPiISR(LISTENER_PIN, INT_EDGE_FALLING, ISRRestart::TriggerCountDown),
0);
count=1;
delay(100);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 0u);
}

View File

@@ -0,0 +1,109 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
#define ANOTHER_LISTENER_PIN 26 // BCM 12
struct counters {
int32_t *primary;
int32_t *secondary;
};
/**
* Tests restarting ISR using function wiringPiISR2().
*/
class ISRRestart2 : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, LOW);
counters_a.primary = &count;
counters_a.secondary = &count2;
counters_b.primary = &count;
counters_b.secondary = &count3;
wiringPiISR2(LISTENER_PIN, INT_EDGE_RISING, ISRRestart2::TriggerCount, 1000,
&counters_a);
delay(100);
}
static int32_t count;
static int32_t count2;
static int32_t count3;
static counters counters_a;
static counters counters_b;
static void TriggerCount(WPIWfiStatus, void *userdata) {
struct counters *counters = (struct counters *)userdata;
++*counters->primary;
++*counters->secondary;
}
static void TriggerCountDown(WPIWfiStatus, void *userdata) {
struct counters *counters = (struct counters *)userdata;
++*counters->primary;
--*counters->secondary;
}
protected:
virtual void SetUp() {
count = 0;
count2 = 0;
count3 = 0;
}
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
int32_t ISRRestart2::count = 0;
int32_t ISRRestart2::count2 = 0;
int32_t ISRRestart2::count3 = 0;
struct counters ISRRestart2::counters_a;
struct counters ISRRestart2::counters_b;
TEST_F(ISRRestart2, RestartISR2) {
// fundamental ISR2 test
EXPECT_EQ(count, 0);
EXPECT_EQ(count2, 0);
digitalWrite(TRIGGER_PIN, HIGH);
delay(20);
EXPECT_EQ(count, 1);
EXPECT_EQ(count2, 1);
digitalWrite(TRIGGER_PIN, LOW);
delay(20);
EXPECT_EQ(count, 1);
EXPECT_EQ(count2, 1);
// stop the ISR
EXPECT_EQ(wiringPiISRStop(LISTENER_PIN), 0);
delay(100);
digitalWrite(TRIGGER_PIN, HIGH);
delay(20);
EXPECT_EQ(count, 1);
EXPECT_EQ(count2, 1);
EXPECT_EQ(count3, 0);
digitalWrite(TRIGGER_PIN, LOW);
// start another ISR2 on the same pin
EXPECT_EQ(wiringPiISR2(LISTENER_PIN, INT_EDGE_FALLING,
ISRRestart2::TriggerCountDown, 0, &counters_b),
0);
delay(100);
digitalWrite(TRIGGER_PIN, HIGH);
delay(20);
EXPECT_EQ(count, 1);
EXPECT_EQ(count2, 1);
EXPECT_EQ(count3, 0);
digitalWrite(TRIGGER_PIN, LOW);
delay(20);
EXPECT_EQ(count, 2);
EXPECT_EQ(count2, 1);
EXPECT_EQ(count3, -1);
}

View File

@@ -0,0 +1,80 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
#define ANOTHER_LISTENER_PIN 26 // BCM 12
/**
* Tests ISR for rising edges.
*/
class ISRRising : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, LOW);
wiringPiISR(LISTENER_PIN, INT_EDGE_RISING, ISRRising::TriggerCount);
delay(100);
}
static uint32_t count;
static void TriggerCount() { ++count; }
static void TriggerCountDown() { --count; }
protected:
virtual void SetUp() { count = 0; }
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
uint32_t ISRRising::count = 0;
TEST_F(ISRRising, Fundamental) {
EXPECT_EQ(count, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 1u);
}
TEST_F(ISRRising, ThreeTriggers) {
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
count = 0;
for (int i = 0; i < 6; ++i) {
delay(10);
digitalWrite(TRIGGER_PIN, i % 2);
}
delay(10);
EXPECT_EQ(count, 3u);
}
TEST_F(ISRRising, ISRInitConflict) {
// this initialization should fail for ISR conflict
EXPECT_EQ(
wiringPiISR(LISTENER_PIN, INT_EDGE_FALLING, ISRRising::TriggerCountDown),
-1);
// ensure the initialization above has released the mutex lock
EXPECT_EQ(wiringPiISR(ANOTHER_LISTENER_PIN, INT_EDGE_RISING,
ISRRising::TriggerCountDown),
0);
delay(100);
// ensure the existing ISR has not broken
EXPECT_EQ(count, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
EXPECT_EQ(count, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
EXPECT_EQ(count, 1u);
}

View File

@@ -0,0 +1,136 @@
#include <gtest/gtest.h>
#include <time.h>
#include <wiringPi.h>
#define TRIGGER_PIN 0 // BCM 17
#define LISTENER_PIN 1 // BCM 18
#define ANOTHER_LISTENER_PIN 6 // BCM 25
struct counters {
uint32_t *primary;
uint32_t *secondary;
};
/**
* Tests ISR for rising edges.
* Function wiringPiISR2 is used for the configuraiton.
*/
class ISRRising2 : public ::testing::Test {
public:
static void SetUpTestSuite() {
wiringPiSetup();
pinMode(TRIGGER_PIN, OUTPUT);
digitalWrite(TRIGGER_PIN, LOW);
counters_a.primary = &count;
counters_a.secondary = &count2;
counters_b.primary = &count;
counters_b.secondary = &count3;
wiringPiISR2(LISTENER_PIN, INT_EDGE_RISING, ISRRising2::TriggerCount, 1000,
&counters_a);
delay(100);
}
static uint32_t count;
static uint32_t count2;
static uint32_t count3;
static counters counters_a;
static counters counters_b;
static void TriggerCount(WPIWfiStatus, void *userdata) {
struct counters *counters = (struct counters *)userdata;
++*counters->primary;
++*counters->secondary;
}
static void TriggerCountDown(WPIWfiStatus, void *userdata) {
struct counters *counters = (struct counters *)userdata;
++*counters->primary;
--*counters->secondary;
}
protected:
virtual void SetUp() {
count = 0;
count2 = 0;
count3 = 0;
}
virtual void TearDown() {
digitalWrite(TRIGGER_PIN, LOW);
delay(10);
}
};
uint32_t ISRRising2::count = 0;
uint32_t ISRRising2::count2 = 0;
uint32_t ISRRising2::count3 = 0;
struct counters ISRRising2::counters_a;
struct counters ISRRising2::counters_b;
TEST_F(ISRRising2, Fundamental) {
EXPECT_EQ(count, 0u);
EXPECT_EQ(count2, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(20);
EXPECT_EQ(count, 1u);
EXPECT_EQ(count2, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(20);
EXPECT_EQ(count, 1u);
EXPECT_EQ(count2, 1u);
}
TEST_F(ISRRising2, ThreeTriggers) {
digitalWrite(TRIGGER_PIN, HIGH);
delay(10);
count = 0;
for (int i = 0; i < 6; ++i) {
delay(20);
digitalWrite(TRIGGER_PIN, i % 2);
}
delay(20);
EXPECT_EQ(count, 3u);
}
TEST_F(ISRRising2, Debounce) {
delay(20);
for (int i = 0; i < 7; ++i) {
digitalWrite(TRIGGER_PIN, (i + 1) % 2);
}
delay(20);
EXPECT_EQ(count, 1u);
}
TEST_F(ISRRising2, ISRInitConflict) {
// this initialization should fail for ISR conflict
EXPECT_EQ(wiringPiISR2(LISTENER_PIN, INT_EDGE_FALLING,
ISRRising2::TriggerCountDown, 0, &counters_b),
-1);
// ensure the initialization above has released the mutex lock
EXPECT_EQ(wiringPiISR2(ANOTHER_LISTENER_PIN, INT_EDGE_BOTH,
ISRRising2::TriggerCountDown, 0, &counters_b),
0);
delay(100);
// ensure the existing ISR has not broken
EXPECT_EQ(count, 0u);
EXPECT_EQ(count2, 0u);
digitalWrite(TRIGGER_PIN, HIGH);
delay(20);
EXPECT_EQ(count, 1u);
EXPECT_EQ(count2, 1u);
digitalWrite(TRIGGER_PIN, LOW);
delay(20);
EXPECT_EQ(count, 1u);
EXPECT_EQ(count2, 1u);
delay(20);
count = 0;
for (int i = 0; i < 7; ++i) {
delay(1);
digitalWrite(TRIGGER_PIN, (i + 1) % 2);
}
delay(20);
EXPECT_EQ(count, 1u);
}

View File

@@ -83,7 +83,8 @@ int main (void) {
case PI_MODEL_400: case PI_MODEL_400:
case PI_MODEL_CM4: case PI_MODEL_CM4:
case PI_MODEL_CM4S: case PI_MODEL_CM4S:
fExpectTimedigitalWrite = 0.020; //us //fExpectTimedigitalWrite = 0.020; //us - with kernel <6.12.47
fExpectTimedigitalWrite = 0.016; //us
fExpectTimedigitalRead = 0.038; //us fExpectTimedigitalRead = 0.038; //us
fExpectTimepinMode = 0.121; //us fExpectTimepinMode = 0.121; //us
fWriteReadDelayFactor = 1.86; fWriteReadDelayFactor = 1.86;

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPi: * wiringPi:
* Arduino look-a-like Wiring library for the Raspberry Pi * Arduino look-a-like Wiring library for the Raspberry Pi
* Copyright (c) 2012-2025 Gordon Henderson and contributors * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
* Additional code for pwmSetClock by Chris Hall <chris@kchall.plus.com> * Additional code for pwmSetClock by Chris Hall <chris@kchall.plus.com>
* *
* Thanks to code samples from Gert Jan van Loo and the * Thanks to code samples from Gert Jan van Loo and the
@@ -2868,42 +2868,32 @@ int waitForInterruptClose(int pin) {
} }
/* /*
* interruptHandlerV2: * interruptHandlerInit:
* This is a thread and gets started to wait for the interrupt we're * Initializes an interrupt handler before starting the listener loop in a
* hoping to catch. It will call the user-function when the interrupt * separate thread.
* fires. * Returns: >0 on successful initialization, 0 if the listener loop does not
* have to start, -1 on error.
********************************************************************************* *********************************************************************************
*/ */
void *interruptHandlerV2(void *arg) static int interruptHandlerInit(int pin, int EdgeMode, unsigned long debounce_period_us)
{ {
const char* strmode = ""; const char* strmode = "";
int pin, EdgeMode, ret, fd, attr, i; int ret, attr;
unsigned int readret;
unsigned long debounce_period_us;
struct pollfd polls ;
struct gpio_v2_line_config config; struct gpio_v2_line_config config;
struct gpio_v2_line_request req; struct gpio_v2_line_request req;
struct gpio_v2_line_event evdat[64];
struct WPIWfiStatus wfiStatus;
struct timespec tspec = {0, 5e5}; /* 0.5 ms timeout {0, 1e6} */
pin = *(int *)arg;
if (wiringPiGpioDeviceGetFd()<0) { if (wiringPiGpioDeviceGetFd() < 0) {
return NULL; return -1;
} }
EdgeMode = isrEdgeMode[pin];
debounce_period_us = isrDebouncePeriodUs[pin];
if (wiringPiDebug) { if (wiringPiDebug) {
printf ("interruptHandlerV2: GPIO line %d, edge mode %d, debounce_period_us %lu \n", pin, EdgeMode, debounce_period_us) ; printf ("interruptHandlerV2: GPIO line %d, edge mode %d, debounce_period_us %lu \n", pin, EdgeMode, debounce_period_us) ;
} }
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
memset(&config, 0, sizeof(config)); memset(&config, 0, sizeof(config));
/* setup config */ /* setup config */
config.flags = GPIO_V2_LINE_FLAG_INPUT; config.flags = GPIO_V2_LINE_FLAG_INPUT;
switch(EdgeMode) { switch(EdgeMode) {
@@ -2912,7 +2902,7 @@ void *interruptHandlerV2(void *arg)
if (wiringPiDebug) { if (wiringPiDebug) {
printf ("interruptHandlerV2: waitForInterruptMode edge mode INT_EDGE_SETUP - exiting\n") ; printf ("interruptHandlerV2: waitForInterruptMode edge mode INT_EDGE_SETUP - exiting\n") ;
} }
return NULL; return 0;
case INT_EDGE_FALLING: case INT_EDGE_FALLING:
config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
strmode = "falling"; strmode = "falling";
@@ -2927,7 +2917,7 @@ void *interruptHandlerV2(void *arg)
break; break;
} }
strcpy(req.consumer, "wiringpi_gpio_irq"); strcpy(req.consumer, "wiringpi_gpio_irq");
if (debounce_period_us) { if (debounce_period_us) {
attr = config.num_attrs; attr = config.num_attrs;
config.num_attrs++; config.num_attrs++;
@@ -2935,7 +2925,7 @@ void *interruptHandlerV2(void *arg)
config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
config.attrs[attr].attr.debounce_period_us = debounce_period_us; config.attrs[attr].attr.debounce_period_us = debounce_period_us;
} }
req.num_lines = 1; req.num_lines = 1;
req.event_buffer_size = 45; req.event_buffer_size = 45;
req.offsets[0] = pin; req.offsets[0] = pin;
@@ -2944,16 +2934,46 @@ void *interruptHandlerV2(void *arg)
ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req); ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req);
if (ret == -1) { if (ret == -1) {
ReportDeviceError("interruptHandlerV2: get line event", pin , strmode, ret); ReportDeviceError("interruptHandlerV2: get line event", pin , strmode, ret);
return NULL; return -1;
} }
if (wiringPiDebug) if (wiringPiDebug) {
printf ("interruptHandlerV2: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; printf ("interruptHandlerV2: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd);
}
return req.fd;
}
struct interrupt_handler_params {
int pin;
int fd;
};
/*
* interruptHandlerV2:
* This is a thread and gets started to wait for the interrupt we're
* hoping to catch. It will call the user-function when the interrupt
* fires.
*********************************************************************************
*/
static void *interruptHandlerV2(void *arg)
{
struct interrupt_handler_params *params;
int pin, ret, fd, i;
unsigned int readret;
struct pollfd polls ;
struct gpio_v2_line_event evdat[64];
struct WPIWfiStatus wfiStatus;
struct timespec tspec = {0, 5e5}; /* 0.5 ms timeout {0, 1e6} */
params = (struct interrupt_handler_params *)arg;
pin = params->pin;
fd = params->fd;
/* set event fd */ /* set event fd */
fd = req.fd;
isrFds [pin] = fd; isrFds [pin] = fd;
(void)piHiPri (55) ; // Only effective if we run as root (void)piHiPri (55) ; // Only effective if we run as root
for (;;) { // check if event data is available, check if interruptHandlerV2 thread must be canceled for (;;) { // check if event data is available, check if interruptHandlerV2 thread must be canceled
@@ -2962,24 +2982,24 @@ void *interruptHandlerV2(void *arg)
polls.fd = fd; polls.fd = fd;
polls.events = POLLIN | POLLPRI; polls.events = POLLIN | POLLPRI;
polls.revents = 0; polls.revents = 0;
// get event data, this is also a cancelation point, when pthread_cancel is called // get event data, this is also a cancelation point, when pthread_cancel is called
ret = ppoll(&polls, 1, &tspec, NULL); // returns -1 on error, 0 on timeout, >0 number of elements ret = ppoll(&polls, 1, &tspec, NULL); // returns -1 on error, 0 on timeout, >0 number of elements
if (ret < 0) { // we do not reach this point if canceled, ppoll does not return, is Cancellation Point if (ret < 0) { // we do not reach this point if canceled, ppoll does not return, is Cancellation Point
if (wiringPiDebug) if (wiringPiDebug)
printf("interruptHandlerV2: ERROR: poll returned=%d\n", ret); printf("interruptHandlerV2: ERROR: poll returned=%d\n", ret);
pthread_exit(NULL); pthread_exit(NULL);
return NULL; // never landing here return NULL; // never landing here
} else if (ret == 0) { } else if (ret == 0) {
// if (wiringPiDebug) // if (wiringPiDebug)
// printf("interruptHandlerV2: timeout: poll returned=%d\n", ret); // printf("interruptHandlerV2: timeout: poll returned=%d\n", ret);
continue; continue;
} }
else { else {
if (wiringPiDebug) if (wiringPiDebug)
printf ("interruptHandlerV2: IRQ line %d received %d events, fd=%d\n", pin, ret, isrFds[pin]) ; printf ("interruptHandlerV2: IRQ line %d received %d events, fd=%d\n", pin, ret, isrFds[pin]) ;
if (polls.revents & POLLIN) { if (polls.revents & POLLIN) {
/* read event data */ /* read event data */
readret = read(fd, &evdat, sizeof(evdat)); readret = read(fd, &evdat, sizeof(evdat));
if (readret >= sizeof(evdat[0])) { if (readret >= sizeof(evdat[0])) {
@@ -2989,7 +3009,7 @@ void *interruptHandlerV2(void *arg)
ret = readret/sizeof(evdat[0]); // number of events read from fd ret = readret/sizeof(evdat[0]); // number of events read from fd
for (i = 0; i < ret; ++i) { for (i = 0; i < ret; ++i) {
if (isrFunctionsV2[pin]) { if (isrFunctionsV2[pin]) {
if (wiringPiDebug) if (wiringPiDebug)
printf( "interruptHandlerV2: GPIO EVENT at %llu on line %u (%u|%u) \n", evdat[i].timestamp_ns, evdat[i].offset, evdat[i].line_seqno, evdat[i].seqno); printf( "interruptHandlerV2: GPIO EVENT at %llu on line %u (%u|%u) \n", evdat[i].timestamp_ns, evdat[i].offset, evdat[i].line_seqno, evdat[i].seqno);
wfiStatus.statusOK = 1; wfiStatus.statusOK = 1;
wfiStatus.pinBCM = pin; wfiStatus.pinBCM = pin;
@@ -3006,10 +3026,10 @@ void *interruptHandlerV2(void *arg)
break; break;
default: default:
wfiStatus.edge = INT_EDGE_SETUP; // edge = 0 wfiStatus.edge = INT_EDGE_SETUP; // edge = 0
if (wiringPiDebug) if (wiringPiDebug)
printf("waitForInterrupt2: unknown event\n"); printf("waitForInterrupt2: unknown event\n");
break; break;
} }
wfiStatus.timeStamp_us = evdat[i].timestamp_ns/1000LL; wfiStatus.timeStamp_us = evdat[i].timestamp_ns/1000LL;
if (wiringPiDebug) { if (wiringPiDebug) {
printf( "interruptHandlerV2: call isr function\n"); printf( "interruptHandlerV2: call isr function\n");
@@ -3033,7 +3053,7 @@ void *interruptHandlerV2(void *arg)
else { // if thread canceled we do not reach this point, read(...) does not return, is Cancellation Point else { // if thread canceled we do not reach this point, read(...) does not return, is Cancellation Point
if (wiringPiDebug) if (wiringPiDebug)
printf ("interruptHandlerV2: reading events from fd received signal, exit thread\n"); printf ("interruptHandlerV2: reading events from fd received signal, exit thread\n");
pthread_exit(NULL); pthread_exit(NULL);
return NULL; // never landing here return NULL; // never landing here
} }
} }
@@ -3041,9 +3061,8 @@ void *interruptHandlerV2(void *arg)
} }
} }
/* /*
* wiringPiISR: * wiringPiISRInternal:
* Pi Specific. * Pi Specific.
* Take the details and create an interrupt handler that will do a call- * Take the details and create an interrupt handler that will do a call-
* back to the user supplied function. * back to the user supplied function.
@@ -3064,38 +3083,48 @@ int wiringPiISRInternal(int pin, int edgeMode, void (*function)(struct WPIWfiSta
printf("wiringPi: wiringPiISR pin %d, edgeMode %d\n", pin, edgeMode); printf("wiringPi: wiringPiISR pin %d, edgeMode %d\n", pin, edgeMode);
} }
if (isrFunctions[pin] || isrFunctionsV2[pin]) { if (isrFunctions[pin] || isrFunctionsV2[pin]) {
fprintf(stderr, "wiringPi: ISR function already active, ignoring \n"); fprintf(stderr, "wiringPi: ISR function already active\n");
} }
isrFunctionsV2[pin] = function;
isrUserdata[pin] = userdata;
isrFunctions[pin] = functionClassic;
isrEdgeMode[pin] = edgeMode;
isrDebouncePeriodUs[pin] = debounce_period_us;
if (wiringPiDebug) { if (wiringPiDebug) {
printf("wiringPi: mutex in\n"); printf("wiringPi: mutex in\n");
} }
pthread_mutex_lock (&pinMutex) ; pthread_mutex_lock (&pinMutex) ;
pinPass = pin ; struct interrupt_handler_params params = {
if (wiringPiDebug) { .pin = pin,
printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]); };
params.fd = interruptHandlerInit(pin, edgeMode, debounce_period_us);
if (params.fd < 0) {
pthread_mutex_unlock (&pinMutex) ;
return -1;
} }
if (pthread_create (&isrThreads[pin], NULL, interruptHandlerV2, &pin)==0) {
// OK to start the new ISR. Update the table.
isrFunctionsV2[pin] = function;
isrUserdata[pin] = userdata;
isrFunctions[pin] = functionClassic;
isrEdgeMode[pin] = edgeMode;
isrDebouncePeriodUs[pin] = debounce_period_us;
pinPass = pin ;
if (params.fd > 0) {
if (wiringPiDebug) { if (wiringPiDebug) {
printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]); printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]);
} }
/* while (pinPass != -1) if (pthread_create (&isrThreads[pin], NULL, interruptHandlerV2, &params)==0) {
delay (1) ; */ if (wiringPiDebug) {
// wait so that interruptHandler is up und running. printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]);
// when interruptHandler is running, the calling function wiringPiISR }
// must be still alive, otherwise the thread argument &pin points into nirwana, } else {
// when it is picked up from interruptHandler. if (wiringPiDebug) {
delay (10); printf("wiringPi: pthread_create failed\n");
} else { }
if (wiringPiDebug) {
printf("wiringPi: pthread_create failed\n");
} }
// wait so that interruptHandler is up und running.
// when interruptHandler is running, the calling function wiringPiISRInternal
// must be still alive, otherwise the thread argument &param points into nirwana,
// when it is picked up from interruptHandlerV2.
delay(10);
} }
if (wiringPiDebug) { if (wiringPiDebug) {

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPi.h: * wiringPi.h:
* Arduino like Wiring library for the Raspberry Pi. * Arduino like Wiring library for the Raspberry Pi.
* Copyright (c) 2012-2025 Gordon Henderson * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPiI2C.c: * wiringPiI2C.c:
* Simplified I2C access routines * Simplified I2C access routines
* Copyright (c) 2013-2024 Gordon Henderson and contributors * Copyright (c) 20132019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPiI2C.h: * wiringPiI2C.h:
* Simplified I2C access routines * Simplified I2C access routines
* Copyright (c) 2013-2024 Gordon Henderson and contributors * Copyright (c) 20132019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPiSPI.c: * wiringPiSPI.c:
* Simplified SPI access routines * Simplified SPI access routines
* Copyright (c) 2012-2025 Gordon Henderson and contributors * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/
@@ -44,9 +44,11 @@
//static const char *spiDev1 = "/dev/spidev0.1" ; //static const char *spiDev1 = "/dev/spidev0.1" ;
static const uint8_t spiBPW = 8 ; static const uint8_t spiBPW = 8 ;
static const uint16_t spiDelay = 0 ; static const uint16_t spiDelay = 0 ;
//https://datasheets.raspberrypi.com/cm4/cm4-datasheet.pdf //https://datasheets.raspberrypi.com/cm4/cm4-datasheet.pdf SPI0-6, CS0-2
//cm5-datasheet.pdf SPI0-5, CS depend on SPInumber, can be up to 4
//spi0-4cs.dts extention for supporting CS0-4
const uint8_t WPI_MaxSPINumbers = 7 ; const uint8_t WPI_MaxSPINumbers = 7 ;
const uint8_t WPI_MaxSPIChannels = 3 ; const uint8_t WPI_MaxSPIChannels = 5 ;
static uint32_t spiSpeeds [7][3] = static uint32_t spiSpeeds [7][3] =

View File

@@ -1,7 +1,7 @@
/* /*
* wiringPiSPI.h: * wiringPiSPI.h:
* Simplified SPI access routines * Simplified SPI access routines
* Copyright (c) 2012-2025 Gordon Henderson and contributors * Copyright (c) 20122019 Gordon Henderson; 20192026 Contributors
*********************************************************************** ***********************************************************************
* This file is part of wiringPi: * This file is part of wiringPi:
* https://github.com/WiringPi/WiringPi/ * https://github.com/WiringPi/WiringPi/