diff --git a/VERSION b/VERSION index 5174c53..b2fb78a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.16 +3.18 diff --git a/documentation/deutsch/functions.md b/documentation/deutsch/functions.md index 0c86b55..f0c87b3 100644 --- a/documentation/deutsch/functions.md +++ b/documentation/deutsch/functions.md @@ -473,7 +473,7 @@ static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) { edgeType = "falling"; else 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) { digitalWrite (OUTpin, HIGH); toggle = 1; @@ -500,19 +500,19 @@ int main (void) 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); - if (wfiStatus.status < 0) { + if (wfiStatus.statusOK < 0) { printf("waitForInterrupt returned error\n"); pinMode(OUTpin, INPUT); return 0; } - else if (wfiStatus.status == 0) { + else if (wfiStatus.statusOK == 0) { printf("waitForInterrupt timed out\n\n"); } else { 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 - 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); @@ -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) ``` -``number``: SPI Nummer (typisch 0, bei Compute Modul 0-7). -``channel``: SPI Kanal (typisch 0 oder 1, bei Compute Modul 0-3). +``number``: SPI Nummer (typisch 0, bei Compute Modul 0-6). +``channel``: SPI Kanal (typisch 0 oder 1, bei Compute Modul oder entsprechenden overlay 0-4). ``speed``: SPI Taktrate. ``mode``: SPI Modus (https://www.kernel.org/doc/Documentation/spi/spidev). ``Rückgabewert``: Datei Handle zum SPI-Bus diff --git a/documentation/english/functions.md b/documentation/english/functions.md index f13874a..f1ec746 100644 --- a/documentation/english/functions.md +++ b/documentation/english/functions.md @@ -470,7 +470,7 @@ static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) { edgeType = "falling"; else 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) { digitalWrite (OUTpin, HIGH); toggle = 1; @@ -497,19 +497,19 @@ int main (void) 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); - if (wfiStatus.status < 0) { + if (wfiStatus.statusOK < 0) { printf("waitForInterrupt returned error\n"); pinMode(OUTpin, INPUT); return 0; } - else if (wfiStatus.status == 0) { + else if (wfiStatus.statusOK == 0) { printf("waitForInterrupt timed out\n\n"); } else { 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 - 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); @@ -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); ``` -``number``: SPI number (typically 0, on Compute Module 0-7). -``channel``: SPI channel (typically 0 or 1, on Compute Module 0-3). +``number``: SPI number (typically 0, on Compute Module 0-6). +``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). ``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. diff --git a/gpio/gpio.1 b/gpio/gpio.1 index 4d76671..e99b66a 100644 --- a/gpio/gpio.1 +++ b/gpio/gpio.1 @@ -282,7 +282,7 @@ Please report bugs to https://github.com/WiringPi/WiringPi/issues .SH COPYRIGHT -Copyright (c) 2012-2025 Gordon Henderson and contributors +Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/gpio/gpio.c b/gpio/gpio.c index 8eae4d1..bf7d23d 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -2,7 +2,7 @@ * gpio.c: * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry * Pi's GPIO. - * Copyright (c) 2012-2025 Gordon Henderson and contributors + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ @@ -916,7 +916,7 @@ static void doVersion (char *argv []) wiringPiVersion (&vMaj, &vMin) ; printf ("gpio version: %d.%d\n", vMaj, vMin) ; - printf ("Copyright (c) 2012-2025 Gordon Henderson and contributors\n") ; + printf ("Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors\n") ; printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; printf ("For details type: %s -warranty\n", argv [0]) ; printf ("\n") ; @@ -1033,7 +1033,7 @@ int main (int argc, char *argv []) if (strcasecmp (argv [1], "-warranty") == 0) { printf ("gpio version: %s\n", VERSION) ; - printf ("Copyright (c) 2012-2025 Gordon Henderson and contributors\n") ; + printf ("Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors\n") ; printf ("\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") ; diff --git a/gpio/readall.c b/gpio/readall.c index 3812e53..d75c414 100644 --- a/gpio/readall.c +++ b/gpio/readall.c @@ -1,7 +1,7 @@ /* * readall.c: * The readall functions - getting a bit big, so split them out. - * Copyright (c) 2012-2024 Gordon Henderson and contributors + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/gpio/test/gpio_test1_piface1.sh b/gpio/test/gpio_test1_piface1.sh new file mode 100755 index 0000000..5840830 --- /dev/null +++ b/gpio/test/gpio_test1_piface1.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +echo -e "🔧 Starting relay unit test for MCP23S17@Piface unit test hw\n\n" + +# set pin 200–207 as output +for i in {200..207}; do + gpio -x mcp23s17:200:0:0 mode $i out +done + +# set pin 208–215 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." + diff --git a/version.h b/version.h index 5ea1e8c..5d9ebc5 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ -#define VERSION "3.16" +#define VERSION "3.18" #define VERSION_MAJOR 3 -#define VERSION_MINOR 16 +#define VERSION_MINOR 18 diff --git a/wiringPi/gtest/.gitignore b/wiringPi/gtest/.gitignore new file mode 100644 index 0000000..b868581 --- /dev/null +++ b/wiringPi/gtest/.gitignore @@ -0,0 +1,2 @@ +bin +googletest-main diff --git a/wiringPi/gtest/Makefile b/wiringPi/gtest/Makefile new file mode 100644 index 0000000..16ce2f8 --- /dev/null +++ b/wiringPi/gtest/Makefile @@ -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 \ No newline at end of file diff --git a/wiringPi/gtest/README.md b/wiringPi/gtest/README.md new file mode 100644 index 0000000..b061c05 --- /dev/null +++ b/wiringPi/gtest/README.md @@ -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. diff --git a/wiringPi/gtest/run_isr.cpp b/wiringPi/gtest/run_isr.cpp new file mode 100644 index 0000000..9937946 --- /dev/null +++ b/wiringPi/gtest/run_isr.cpp @@ -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 +#include +#include + +#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"); +} \ No newline at end of file diff --git a/wiringPi/gtest/test_isr_both.cpp b/wiringPi/gtest/test_isr_both.cpp new file mode 100644 index 0000000..a404e73 --- /dev/null +++ b/wiringPi/gtest/test_isr_both.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/wiringPi/gtest/test_isr_conflict_between_processes.cpp b/wiringPi/gtest/test_isr_conflict_between_processes.cpp new file mode 100644 index 0000000..2ac955c --- /dev/null +++ b/wiringPi/gtest/test_isr_conflict_between_processes.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/wiringPi/gtest/test_isr_falling.cpp b/wiringPi/gtest/test_isr_falling.cpp new file mode 100644 index 0000000..ee52e6a --- /dev/null +++ b/wiringPi/gtest/test_isr_falling.cpp @@ -0,0 +1,57 @@ +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/wiringPi/gtest/test_isr_restart.cpp b/wiringPi/gtest/test_isr_restart.cpp new file mode 100644 index 0000000..29c2f79 --- /dev/null +++ b/wiringPi/gtest/test_isr_restart.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +#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); +} diff --git a/wiringPi/gtest/test_isr_restart2.cpp b/wiringPi/gtest/test_isr_restart2.cpp new file mode 100644 index 0000000..df2ca5e --- /dev/null +++ b/wiringPi/gtest/test_isr_restart2.cpp @@ -0,0 +1,109 @@ +#include +#include +#include + +#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); +} diff --git a/wiringPi/gtest/test_isr_rising.cpp b/wiringPi/gtest/test_isr_rising.cpp new file mode 100644 index 0000000..ea5473c --- /dev/null +++ b/wiringPi/gtest/test_isr_rising.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#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); +} diff --git a/wiringPi/gtest/test_isr_rising2.cpp b/wiringPi/gtest/test_isr_rising2.cpp new file mode 100644 index 0000000..d23b5dd --- /dev/null +++ b/wiringPi/gtest/test_isr_rising2.cpp @@ -0,0 +1,136 @@ +#include +#include +#include + +#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); +} diff --git a/wiringPi/test/wiringpi_test7_bench.c b/wiringPi/test/wiringpi_test7_bench.c index 9c0f221..ffdf367 100644 --- a/wiringPi/test/wiringpi_test7_bench.c +++ b/wiringPi/test/wiringpi_test7_bench.c @@ -83,7 +83,8 @@ int main (void) { case PI_MODEL_400: case PI_MODEL_CM4: 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 fExpectTimepinMode = 0.121; //us fWriteReadDelayFactor = 1.86; diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index 4537192..d387d1a 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -1,7 +1,7 @@ /* * wiringPi: * Arduino look-a-like Wiring library for the Raspberry Pi - * Copyright (c) 2012-2025 Gordon Henderson and contributors + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors * Additional code for pwmSetClock by Chris Hall * * Thanks to code samples from Gert Jan van Loo and the @@ -2868,42 +2868,32 @@ int waitForInterruptClose(int pin) { } /* - * 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. + * interruptHandlerInit: + * Initializes an interrupt handler before starting the listener loop in a + * separate thread. + * 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 = ""; - int pin, EdgeMode, ret, fd, attr, i; - unsigned int readret; - unsigned long debounce_period_us; - struct pollfd polls ; + const char* strmode = ""; + int ret, attr; struct gpio_v2_line_config config; 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) { - return NULL; + if (wiringPiGpioDeviceGetFd() < 0) { + return -1; } - - EdgeMode = isrEdgeMode[pin]; - debounce_period_us = isrDebouncePeriodUs[pin]; - + if (wiringPiDebug) { printf ("interruptHandlerV2: GPIO line %d, edge mode %d, debounce_period_us %lu \n", pin, EdgeMode, debounce_period_us) ; - } - + } + memset(&req, 0, sizeof(req)); memset(&config, 0, sizeof(config)); - + /* setup config */ config.flags = GPIO_V2_LINE_FLAG_INPUT; switch(EdgeMode) { @@ -2912,7 +2902,7 @@ void *interruptHandlerV2(void *arg) if (wiringPiDebug) { printf ("interruptHandlerV2: waitForInterruptMode edge mode INT_EDGE_SETUP - exiting\n") ; } - return NULL; + return 0; case INT_EDGE_FALLING: config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; strmode = "falling"; @@ -2927,7 +2917,7 @@ void *interruptHandlerV2(void *arg) break; } strcpy(req.consumer, "wiringpi_gpio_irq"); - + if (debounce_period_us) { attr = 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.debounce_period_us = debounce_period_us; } - + req.num_lines = 1; req.event_buffer_size = 45; req.offsets[0] = pin; @@ -2944,16 +2934,46 @@ void *interruptHandlerV2(void *arg) ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req); if (ret == -1) { ReportDeviceError("interruptHandlerV2: get line event", pin , strmode, ret); - return NULL; + return -1; } - if (wiringPiDebug) - printf ("interruptHandlerV2: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; + if (wiringPiDebug) { + 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 */ - fd = req.fd; isrFds [pin] = fd; - + (void)piHiPri (55) ; // Only effective if we run as root 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.events = POLLIN | POLLPRI; polls.revents = 0; - + // 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 - + 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); - pthread_exit(NULL); + pthread_exit(NULL); return NULL; // never landing here - } else if (ret == 0) { -// if (wiringPiDebug) + } else if (ret == 0) { +// if (wiringPiDebug) // printf("interruptHandlerV2: timeout: poll returned=%d\n", ret); continue; } else { if (wiringPiDebug) 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 */ readret = read(fd, &evdat, sizeof(evdat)); if (readret >= sizeof(evdat[0])) { @@ -2989,7 +3009,7 @@ void *interruptHandlerV2(void *arg) ret = readret/sizeof(evdat[0]); // number of events read from fd for (i = 0; i < ret; ++i) { 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); wfiStatus.statusOK = 1; wfiStatus.pinBCM = pin; @@ -3006,10 +3026,10 @@ void *interruptHandlerV2(void *arg) break; default: wfiStatus.edge = INT_EDGE_SETUP; // edge = 0 - if (wiringPiDebug) + if (wiringPiDebug) printf("waitForInterrupt2: unknown event\n"); break; - } + } wfiStatus.timeStamp_us = evdat[i].timestamp_ns/1000LL; if (wiringPiDebug) { 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 if (wiringPiDebug) printf ("interruptHandlerV2: reading events from fd received signal, exit thread\n"); - pthread_exit(NULL); + pthread_exit(NULL); return NULL; // never landing here } } @@ -3041,9 +3061,8 @@ void *interruptHandlerV2(void *arg) } } - /* - * wiringPiISR: + * wiringPiISRInternal: * Pi Specific. * Take the details and create an interrupt handler that will do a call- * 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); } 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) { printf("wiringPi: mutex in\n"); } pthread_mutex_lock (&pinMutex) ; - pinPass = pin ; - if (wiringPiDebug) { - printf("wiringPi: pthread_create before 0x%lX\n", (unsigned long)isrThreads[pin]); + struct interrupt_handler_params params = { + .pin = 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) { - 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) - 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"); + if (pthread_create (&isrThreads[pin], NULL, interruptHandlerV2, ¶ms)==0) { + if (wiringPiDebug) { + printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]); + } + } 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 ¶m points into nirwana, + // when it is picked up from interruptHandlerV2. + delay(10); } if (wiringPiDebug) { diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index 819a58f..07cd258 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -1,7 +1,7 @@ /* * wiringPi.h: * Arduino like Wiring library for the Raspberry Pi. - * Copyright (c) 2012-2025 Gordon Henderson + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPi/wiringPiI2C.c b/wiringPi/wiringPiI2C.c index 95131c3..6ec1789 100644 --- a/wiringPi/wiringPiI2C.c +++ b/wiringPi/wiringPiI2C.c @@ -1,7 +1,7 @@ /* * wiringPiI2C.c: * Simplified I2C access routines - * Copyright (c) 2013-2024 Gordon Henderson and contributors + * Copyright (c) 2013–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPi/wiringPiI2C.h b/wiringPi/wiringPiI2C.h index 112257a..22df490 100644 --- a/wiringPi/wiringPiI2C.h +++ b/wiringPi/wiringPiI2C.h @@ -1,7 +1,7 @@ /* * wiringPiI2C.h: * Simplified I2C access routines - * Copyright (c) 2013-2024 Gordon Henderson and contributors + * Copyright (c) 2013–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 581a079..840f175 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -1,7 +1,7 @@ /* * wiringPiSPI.c: * Simplified SPI access routines - * Copyright (c) 2012-2025 Gordon Henderson and contributors + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ @@ -44,9 +44,11 @@ //static const char *spiDev1 = "/dev/spidev0.1" ; static const uint8_t spiBPW = 8 ; 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_MaxSPIChannels = 3 ; +const uint8_t WPI_MaxSPIChannels = 5 ; static uint32_t spiSpeeds [7][3] = diff --git a/wiringPi/wiringPiSPI.h b/wiringPi/wiringPiSPI.h index d60b064..aa15aa6 100644 --- a/wiringPi/wiringPiSPI.h +++ b/wiringPi/wiringPiSPI.h @@ -1,7 +1,7 @@ /* * wiringPiSPI.h: * Simplified SPI access routines - * Copyright (c) 2012-2025 Gordon Henderson and contributors + * Copyright (c) 2012–2019 Gordon Henderson; 2019–2026 Contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/