diff --git a/README.md b/README.md index 574e017..46759d6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # WiringPi Library + Welcome to the WiringPi Library, the highly performant GPIO access library for Raspberry Pi boards. This library is written in C and is designed to provide fast and efficient control of the GPIO pins by directly accessing the hardware registers using DMA. -**Key Features:** +**Key Features:** + - **Support:** WiringPi supports all Raspberry Pi Boards including Pi 5 ( :construction: On the Pi 5, only the GCLK functionality is currently not supported due to missing documentation of the RP1 chip). - **High Performance:** By directly accessing the hardware registers, WiringPi ensures minimal latency and maximum performance for your GPIO operations. - **Wide Adoption:** WiringPi is widely used in numerous projects, making it a reliable choice for your Raspberry Pi GPIO needs. @@ -50,9 +52,23 @@ cd examples make ``` +To use WiringPi in a project with CMake, the following snippet is all that is required provided that WiringPi is installed. + +```CMake +add_executable(example + # project sources... +) + +target_link_libraries( + example + + PRIVATE wiringPi +) +``` + The tool `gpio` can be used to set single pins as well as get the state of everything at once: -``` +```none pi@wiringdemo:~ $ gpio readall +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | @@ -82,12 +98,10 @@ pi@wiringdemo:~ $ gpio readall +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ ``` - ## Documentation -[German](https://github.com/WiringPi/WiringPi/blob/master/documentation/deutsch/functions.md) -[English](https://github.com/WiringPi/WiringPi/blob/master/documentation/english/functions.md) - +[German](./documentation/deutsch/functions.md) +[English](./documentation/english/functions.md) ## Installing @@ -105,42 +119,42 @@ cd WiringPi # build the package ./build debian -mv debian-template/wiringpi-3.0-1.deb . +mv debian-template/wiringpi-3.x.deb . # install it -sudo apt install ./wiringpi-3.0-1.deb +sudo apt install ./wiringpi-3.x.deb ``` - ### Prebuilt Binaries Grab the latest release from [here](https://github.com/WiringPi/WiringPi/releases). - Unzip/use the portable prebuilt verison: ```sh # unzip the archive -tar -xfv wiringpi_3.0.tar.gz +tar -xfv wiringpi_3.x.tar.gz ``` Install the debian package: ```sh # install a dpkg -sudo apt install ./wiringpi-3.0-1.deb +sudo apt install ./wiringpi-3.x.deb ``` - ## Ports -wiringPi has been wrapped for multiple languages: +wiringPi has been wrapped for multiple languages: -* Node - https://github.com/WiringPi/WiringPi-Node -* Perl - https://github.com/WiringPi/WiringPi-Perl -* PHP - https://github.com/WiringPi/WiringPi-PHP -* Python - https://github.com/WiringPi/WiringPi-Python -* Ruby - https://github.com/WiringPi/WiringPi-Ruby +NOTE: these wrappers are _not_ updated and maintained in sync with WiringPi version 3+, +therefore we cannot guarantee functionality or provide support for a specific implementation. + +- Node - [https://github.com/WiringPi/WiringPi-Node](https://github.com/WiringPi/WiringPi-Node) +- Perl - [https://github.com/WiringPi/WiringPi-Perl](https://github.com/WiringPi/WiringPi-Perl) +- PHP - [https://github.com/WiringPi/WiringPi-PHP](https://github.com/WiringPi/WiringPi-PHP) +- Python - [https://github.com/WiringPi/WiringPi-Python](https://github.com/WiringPi/WiringPi-Python) +- Ruby - [https://github.com/WiringPi/WiringPi-Ruby](https://github.com/WiringPi/WiringPi-Ruby) ## Support @@ -156,9 +170,9 @@ Please don't email GC2 for reporting issues, you might [contact us](mailto:wirin This repository is the continuation of 'Gordon's wiringPi 2.5' which has been [deprecated](https://web.archive.org/web/20220405225008/http://wiringpi.com/wiringpi-deprecated/), a while ago. -* The last "old wiringPi" source of Gordon's release can be found at the +- The last "old wiringPi" source of Gordon's release can be found at the [`final_source_2.50`](https://github.com/WiringPi/WiringPi/tree/final_official_2.50) tag. -* The default `master` branch contains code that has been written since version 2.5 +- The default `master` branch contains code that has been written since version 2.5 to provide support for newer hardware as well as new features. :information_source:️ Since 2024, [GC2](https://github.com/GrazerComputerClub) has taken over maintenance of the project, supporting new OS versions as well as current hardware generations. We are dedicated to keeping the arguably best-performing GPIO Library for Raspberry Pi running smoothly. We strive to do our best, but please note that this is a community effort, and we cannot provide any guarantees or take responsibility for implementing specific features you may need. diff --git a/VERSION b/VERSION index 6324d40..5174c53 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.14 +3.16 diff --git a/devLib/lcd128x64.c b/devLib/lcd128x64.c index e370488..272d6f8 100644 --- a/devLib/lcd128x64.c +++ b/devLib/lcd128x64.c @@ -370,7 +370,7 @@ void lcd128x64rectangle (int x1, int y1, int x2, int y2, int colour, int filled) if (filled) { - /**/ if (x1 == x2) + if (x1 == x2) lcd128x64line (x1, y1, x2, y2, colour) ; else if (x1 < x2) for (x = x1 ; x <= x2 ; ++x) diff --git a/devLib/piGlow.c b/devLib/piGlow.c index 7f1db7c..ebee3c4 100644 --- a/devLib/piGlow.c +++ b/devLib/piGlow.c @@ -47,12 +47,9 @@ void piGlow1 (const int leg, const int ring, const int intensity) if ((leg < 0) || (leg > 2)) return ; if ((ring < 0) || (ring > 5)) return ; - /**/ if (leg == 0) - legLeds = leg0 ; - else if (leg == 1) - legLeds = leg1 ; - else - legLeds = leg2 ; + if (leg == 0) { legLeds = leg0 ; } + else if (leg == 1) { legLeds = leg1 ; } + else { legLeds = leg2 ; } analogWrite (PIGLOW_BASE + legLeds [ring], intensity) ; } @@ -71,12 +68,9 @@ void piGlowLeg (const int leg, const int intensity) if ((leg < 0) || (leg > 2)) return ; - /**/ if (leg == 0) - legLeds = leg0 ; - else if (leg == 1) - legLeds = leg1 ; - else - legLeds = leg2 ; + if (leg == 0) { legLeds = leg0 ; } + else if (leg == 1) { legLeds = leg1 ; } + else { legLeds = leg2 ; } for (i = 0 ; i < 6 ; ++i) analogWrite (PIGLOW_BASE + legLeds [i], intensity) ; diff --git a/devLib/scrollPhat.c b/devLib/scrollPhat.c index d12666c..ca9a8b2 100644 --- a/devLib/scrollPhat.c +++ b/devLib/scrollPhat.c @@ -210,19 +210,21 @@ void scrollPhatRectangle (int x1, int y1, int x2, int y2, int colour, int filled { register int x ; - if (filled) - { - /**/ if (x1 == x2) + if (filled) { + if (x1 == x2) { scrollPhatLine (x1, y1, x2, y2, colour) ; - else if (x1 < x2) - for (x = x1 ; x <= x2 ; ++x) - scrollPhatLine (x, y1, x, y2, colour) ; - else - for (x = x2 ; x <= x1 ; ++x) - scrollPhatLine (x, y1, x, y2, colour) ; - } - else - { + } + else if (x1 < x2) { + for (x = x1 ; x <= x2 ; ++x) { + scrollPhatLine (x, y1, x, y2, colour) ; + } + } + else { + for (x = x2 ; x <= x1 ; ++x) { + scrollPhatLine (x, y1, x, y2, colour) ; + } + } + } else { scrollPhatLine (x1, y1, x2, y1, colour) ; scrollPhatLineTo (x2, y2, colour) ; scrollPhatLineTo (x1, y2, colour) ; diff --git a/documentation/deutsch/functions.md b/documentation/deutsch/functions.md index 95bd1ff..0c86b55 100644 --- a/documentation/deutsch/functions.md +++ b/documentation/deutsch/functions.md @@ -20,13 +20,13 @@ sudo apt install git git clone https://github.com/WiringPi/WiringPi.git cd WiringPi ./build debian -mv debian-template/wiringpi-3.0-1.deb . +mv debian-template/wiringpi_3.16_arm64.deb . ``` **Debian-Paket installieren:** ```bash -sudo apt install ./wiringpi-3.0-1.deb +sudo apt install ./wiringpi_3.16_arm64.deb ``` **Debian-Paket deinstallieren:** @@ -125,10 +125,8 @@ mehr benutzt werden! **Ab Version 3.4:** ``wiringPiSetupPinType`` entscheidet ob nun WiringPi, BCM oder physische Pin-Nummerierung verwendet wird, anhand des Parameters pinType. Es führt also die ersten 3 Setup-Funktionen auf eine zusammen. -``wiringPiSetupGpioDevice`` ist der Nachfolger der ``wiringPiSetupSys`` Funktion und verwendet nun "GPIO Character Device Userspace API" in Version 1 (ab Kernel 5.10 verfügbar). Nähere Informationen findet man bei https://docs.kernel.org/driver-api/gpio/driver.html. Anhand des Parameters pinType wird wieder entschieden, welche Pin-Nummerierung verwendet wird. -Bei dieser Variante wird nicht direkt auf den GPIO-Speicher (DMA) zugegriffen sondern über eine Kernel Schnittstelle, die mit Benutzerrechten verfügbar ist. Nachteil ist der eingeschrenkte Funktionsumfang und die niedrige Performance. - - +``wiringPiSetupGpioDevice`` ist der Nachfolger der ``wiringPiSetupSys`` Funktion und verwendet nun "GPIO Character Device Userspace API" in Version 2 (ab WiringPi Version 3.16). Nähere Informationen findet man bei https://docs.kernel.org/driver-api/gpio/driver.html. Anhand des Parameters pinType wird wieder entschieden, welche Pin-Nummerierung verwendet wird. +Bei dieser Variante wird nicht direkt auf den GPIO-Speicher (DMA) zugegriffen sondern über eine Kernel Schnittstelle, die mit Benutzerrechten verfügbar ist. Nachteil ist der eingeschränkte Funktionsumfang und die niedrige Performance. ### wiringPiSetup V2 (veraltet) @@ -288,6 +286,7 @@ if (value==HIGH) ### wiringPiISR Registriert eine Interrupt Service Routine (ISR) bzw. Funktion die bei Flankenwechsel ausgeführt wird. +Es werden bei dieser klassischen Version keine Parameter and die ISR übergeben. >>> ```C @@ -305,8 +304,44 @@ int wiringPiISR(int pin, int mode, void (*function)(void)); > 0 ... Erfolgreich -Beispiel siehe wiringPiISRStop. +Beispiel siehe [wiringPiISRStop](#wiringPiISRStop). +### wiringPiISR2 + +Registriert eine Interrupt Service Routine (ISR) bzw. Funktion die bei Flankenwechsel ausgeführt wird. +Es werden erweiterte Parameter an die ISR übergeben. + +>>> +```C +int wiringPiISR2(int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus, void* userdata), unsigned long debounce_period_us, void* userdata); +``` + +``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer). + +``edgeMode``: Auslösender Flankenmodus + + - INT_EDGE_RISING ... Steigende Flanke + - INT_EDGE_FALLING ... Fallende Flanke + - INT_EDGE_BOTH ... Steigende und fallende Flanke + +``*function``: Funktionspointer für ISR mit Parameter struct WPIWfiStatus und einem Pointer: +```C +struct WPIWfiStatus { + int statusOK; // -1: error (return of 'poll' command), 0: timeout, 1: irq processed, next data values are valid if needed + unsigned int pinBCM; // gpio as BCM pin + int edge; // INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds +}; +``` + +``debounce_period_us``: Entprellzeit in Microsekunden, 0 schaltet das Entprellen ab +``userdata``: Pointer der beim Aufruf der ISR übergeben wird + +``Rückgabewert``: + > 0 ... Erfolgreich + + + Beispiel siehe [waitForInterrupt2](#waitForInterrupt2). ### wiringPiISRStop @@ -314,50 +349,215 @@ Deregistriert die Interrupt Service Routine (ISR) auf einem Pin. >>> ```C -int wiringPiISRStop (int pin) +int wiringPiISRStop (int pin); ``` ``pin``: Der gewünschte Pin (BCM-, WiringPi- oder Pin-Nummer). ``Rückgabewert``: + > 0 ... Erfolgreich **Beispiel:** +>>> ```C static volatile int edgeCounter; -static void isr(void) { +static void isr(void) { edgeCounter++; } int main (void) { wiringPiSetupPinType(WPI_PIN_BCM); edgeCounter = 0; - wiringPiISR (17, INT_EDGE_RISING, &isr); + + wiringPiISR(17, INT_EDGE_RISING, &isr); + Sleep(1000); - printf("%d rinsing edges\n", ) - wiringPiISRStop(17) ; + printf("%d rising edges\n", edgeCounter); + + wiringPiISRStop(17); } ``` ### waitForInterrupt -Wartet auf einen zuvor definierten Interrupt (wiringPiISR) am GPIO Pin. Diese Funktion sollte nicht verwendet werden. +Funktion ist nicht mehr verfügbar, es wird nur noch die ``waitForInterrupt2`` unterstützt! + + +### waitForInterrupt2 + +Wartet auf einen Aufruf der Interrupt Service Routine (ISR) mit Timeout und Entprellzeit in Mikrosekunden. +Blockiert das Programm bis zum Eintreffen der auslösenden Flanke oder bis zum Ablauf des Timeouts. +Diese Funktion sollte nicht verwendet werden. >>> ```C -int waitForInterrupt (int pin, int mS) +struct WPIWfiStatus wfiStatus waitForInterrupt2(int pin, int edgeMode, int ms, unsigned long debounce_period_us) ``` -``pin``: Der gewünschte Pin (BCM-, WiringPi- oder Pin-Nummer). -``mS``: Timeout in Milisekunden. -``Rückgabewert``: Fehler -> 0 ... Erfolgreich -> -1 ... GPIO Device Chip nicht erfolgreich geöffnet -> -2 ... ISR wurde nicht registriert (wiringPiISR muss aufgerufen werden) +``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer). +``edgeMode``: Auslösender Flankenmodus + + - INT_EDGE_RISING ... Steigende Flanke + - INT_EDGE_FALLING ... Fallende Flanke + - INT_EDGE_BOTH ... Steigende und fallende Flanke + +``ms``: Timeout in Milisekunden. + - \-1 ... Warten ohne Timeout + - 0 ... Wartet nicht + - 1-n ... Wartet maximal n Millisekunden + +``debounce_period_us``: Entprellzeit in Microsekunden, 0 schaltet Entprellen ab. + +``Rückgabewert``: +```C +struct WPIWfiStatus { + int statusOK; // -1: error (return of 'poll' command), 0: timeout, 1: irq processed, next data values are valid if needed + unsigned int pinBCM; // gpio as BCM pin + int edge; // INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds +}; +``` + +**Beispiel:** + +```C +/* + * isr_debounce.c: + * Wait for Interrupt test program WiringPi >=3.16 - ISR2 method + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define BOUNCETIME 3000 // microseconds +#define BOUNCETIME_WFI 300 +#define TIMEOUT 10000 +//************************************* +// BCM pins +// IRQpin : setup as input with internal pullup. Connected with push button to GND with 1K resistor in series. +// OUTpin : connected to a LED with 470 Ohm resistor in series to GND. Toggles LED with every push button pressed. +//************************************* +#define IRQpin 16 +#define OUTpin 12 + +int toggle = 0; + +static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) { +// struct timeval now; + long long int timenow, diff; + struct timespec curr; + char *edgeType; + + if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) { + printf("clock_gettime error"); + return; + } + + timenow = curr.tv_sec * 1000000LL + curr.tv_nsec/1000L; // convert to microseconds + diff = timenow - wfiStatus.timeStamp_us; + if (wfiStatus.edge == INT_EDGE_RISING) + edgeType = "rising"; + else if (wfiStatus.edge == INT_EDGE_FALLING) + 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); + if (toggle == 0) { + digitalWrite (OUTpin, HIGH); + toggle = 1; + } + else { + digitalWrite (OUTpin, LOW); + toggle = 0; + } +} + + +int main (void) +{ + int major, minor; + wiringPiVersion(&major, &minor); + printf("\nISR debounce test (WiringPi %d.%d)\n\n", major, minor); + + wiringPiSetupGpio(); + pinMode(IRQpin, INPUT); + // pull up/down mode (PUD_OFF, PUD_UP, PUD_DOWN) => down + pullUpDnControl(IRQpin, PUD_UP); + pinMode(OUTpin, OUTPUT); + digitalWrite (OUTpin, LOW) ; + + printf("Testing waitForInterrupt 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) { + printf("waitForInterrupt returned error\n"); + pinMode(OUTpin, INPUT); + return 0; + } + else if (wfiStatus.status == 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); + else + printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, 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("To stop program hit return key\n\n"); + + wiringPiISR2(IRQpin, INT_EDGE_BOTH, &wfi, BOUNCETIME, NULL); + + getc(stdin); + + wiringPiISRStop (IRQpin); + pinMode(OUTpin, INPUT); + + return 0; +} +``` + +Ausgabe am Terminal: + +``` +pi@RaspberryPi:~/wiringpi-test-v3.16 $ gcc -o isr_debounce isr_debounce.c -l wiringPi +pi@RaspberryPi:~/wiringpi-test-v3.16 $ ./isr_debounce + +ISR debounce test (WiringPi 3.16) + +Testing waitForInterrupt on both edges IRQ @ GPIO16, timeout is 10000 +waitForInterrupt: GPIO pin 16 falling edge fired at 256522528012 microseconds + +Testing IRQ @ GPIO16 on both edges and bouncetime 3000 microseconds. Toggle LED @ GPIO12 on IRQ. + +To stop program hit return key + +gpio BCM = 16, IRQ edge = rising, timestamp = 256522668010 microseconds, timenow = 256522668017, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256536364014 microseconds, timenow = 256536364021, diff = 7 +gpio BCM = 16, IRQ edge = rising, timestamp = 256536952011 microseconds, timenow = 256536952018, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256537856010 microseconds, timenow = 256537856016, diff = 6 +gpio BCM = 16, IRQ edge = rising, timestamp = 256538744011 microseconds, timenow = 256538744018, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256539664010 microseconds, timenow = 256539664017, diff = 7 +gpio BCM = 16, IRQ edge = rising, timestamp = 256540516010 microseconds, timenow = 256540516016, diff = 6 +gpio BCM = 16, IRQ edge = falling, timestamp = 256541560013 microseconds, timenow = 256541560022, diff = 9 +gpio BCM = 16, IRQ edge = rising, timestamp = 256542360010 microseconds, timenow = 256542360016, diff = 6 +gpio BCM = 16, IRQ edge = falling, timestamp = 256543320012 microseconds, timenow = 256543320020, diff = 8 +gpio BCM = 16, IRQ edge = rising, timestamp = 256544092021 microseconds, timenow = 256544092029, diff = 8 +^C +pi@RaspberryPi:~/wiringpi-test-v3.16 $ +``` ## Hardware PWM (Pulsweitenmodulation) @@ -490,9 +690,21 @@ int fd = wiringPiI2CSetupInterface("/dev/i2c-1", 0x20); ``` -### wiringPiI2CWrite / wiringPiI2CWriteReg8 / wiringPiI2CWriteReg16 / wiringPiI2CWriteBlockData +### wiringPiI2CWrite -... +Einfaches schreiben auf einen I2C-Slave. Manche Geräte benötigen keine Adressierung eines Registers. + +### wiringPiI2CWriteReg8 + +Schreibt 8-Bit Daten auf ein Register am Geräte. + +### wiringPiI2CWriteReg16 + +Schreibt 16-Bit Daten auf ein Register am Geräte. + +### wiringPiI2CWriteBlockData + +Schreibt entsprechend der angeben Größe Daten auf ein Register am Geräte. ### wiringPiI2CRawWrite @@ -525,9 +737,25 @@ if (fd>0) { } ``` -### wiringPiI2CRead / wiringPiI2CReadReg8 / wiringPiI2CReadReg16 / wiringPiI2CReadBlockData -... +### wiringPiI2CRead + +Einfaches lesen vom I2C-Slave. Manche Geräte benötigen keine Adressierung eines Registers. + +### wiringPiI2CReadReg8 + +Liest 8-Bit Daten vom Register am Geräte. + + +### wiringPiI2CReadReg16 + +Liest 16-Bit Daten vom Register am Geräte. + + +### wiringPiI2CReadBlockData + +Liest entsprechend der angeben Größe Daten vom Register am Geräte. + ### wiringPiI2CRawRead @@ -574,8 +802,10 @@ Die alten Funktionen bleiben erhalten beziehen sich allerdings immer auf den SPI >>> ```C -int wiringPiSPISetup (int channel, int speed) -int wiringPiSPISetup (int channel, int speed, int mode) +int wiringPiSPISetup(int channel, int speed) + +int wiringPiSPISetupMode(int channel, int speed, int mode) + int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode) ``` diff --git a/documentation/english/functions.md b/documentation/english/functions.md index a277e80..f13874a 100644 --- a/documentation/english/functions.md +++ b/documentation/english/functions.md @@ -4,42 +4,44 @@ The WiringPi-library enables access to the GPIO pins of the Raspberry Pi. In thi Since Version 3, extensions to the interface have been made again. In the case of new implementations, you should rely on the current / new functions. The old [GPIO Sysfs Interface for Userspace](https://www.kernel.org/doc/Documentation/gpio/sysfs.txt) is no longer supported. -**Attention:** This documentation is still in progress and therefore incomplete. -The content of this documentation was created with care and to the best of our knowledge and belief. However, the authors do not guarantee the correctness, completeness and topicality of the information provided.The content of the documentation is used at your own risk. -No liability is generally assumed for damage caused by material or intangible nature caused by the use or non-use of the information provided or by the use of incorrect and incomplete information. +**Attention:** + +This documentation is still in progress and therefore incomplete. +The content of this documentation was created with care and to the best of our knowledge. However, the authors do not guarantee the correctness, completeness and topicality of the information provided.The content of the documentation is used at your own risk. + +No liability is assumed for material or intangible damage caused by the use or non-use of the information provided or by the use of incorrect or incomplete information. ## Installation -Unfortunately, the WiringPi Library is not directly available in Raspberry Pi OS, so it must be installed manually. Either download a Debian package or create it manually. +The WiringPi Library is not directly available in Raspberry Pi OS, so it must be installed manually. Either download a Debian package or create it manually. -**Create Debian package:** +**Create Debian package:** ```bash sudo apt install git git clone https://github.com/WiringPi/WiringPi.git cd WiringPi ./build debian -mv debian-template/wiringpi-3.0-1.deb . +mv debian-template/wiringpi_3.16_arm64.deb . ``` -**Install Debian package:** +**Install Debian package:** ```bash -sudo apt install ./wiringpi-3.0-1.deb +sudo apt install ./wiringpi_3.16_arm64.deb ``` -**Uninstall Debian package:** +**Uninstall Debian package:** ```bash sudo apt purge wiringpi ``` - ## PIN Numbering and Raspberry Pi Models -GPIOs: https://pinout.xyz/pinout/wiringpi +GPIOs: [https://pinout.xyz/pinout/wiringpi](https://pinout.xyz/pinout/wiringpi) -**Raspberry Pi Models with 40-Pin GPIO J8 Header:** +**Raspberry Pi Models with 40-Pin GPIO J8 Header:** | BCM | WPI | Name | Physical | Name | WPI | BCM | |-----|-----|---------|:---------:|---------|-----|-----| @@ -64,8 +66,7 @@ GPIOs: https://pinout.xyz/pinout/wiringpi | 26 | 25 | GPIO.25 | 37 I 38 | GPIO.28 | 28 | 20 | | | | GND | 39 I 40 | GPIO.29 | 29 | 21 | - -**Raspberry Pi 1B Rev. 2 with 26-Pin GPIO P1 Header:** +**Raspberry Pi 1B Rev. 2 with 26-Pin GPIO P1 Header:** | BCM | WPI | Name | Physical | Name | WPI | BCM | |-----|-----|---------|:--------:|----------|-----|-----| @@ -83,9 +84,7 @@ GPIOs: https://pinout.xyz/pinout/wiringpi | 11 | 14 | SCLK | 23 I 24 | CE0 | 10 | 8 | | | | GND | 25 I 26 | CE1 | 11 | 7 | - - -**Raspberry Pi 1B Rev. 1 with 26-Pin GPIO P1 Header:** +**Raspberry Pi 1B Rev. 1 with 26-Pin GPIO P1 Header:** | BCM | WPI | Name | Physical | Name | WPI | BCM | |-----|-----|---------|:--------:|---------|-----|-----| @@ -103,41 +102,44 @@ GPIOs: https://pinout.xyz/pinout/wiringpi | 11 | 14 | SCLK | 23 I 24 | CE0 | 10 | 8 | | | | GND | 25 I 26 | CE1 | 11 | 7 | - **References** + Note the different pin numbers and the I2C0 at Raspberry Pi 1B Rev. 1! ## Initialization + At the beginning, the WiringPi Library must be initialized. To do this, one of the following functions must be called up: Outdated functions (no longer use): -``wiringPiSetup`` uses Wiringpi numbering (WPI) of the GPIO's and accesses the GPIO register directly. +``wiringPiSetup`` uses WiringPi numbering (WPI) of the GPIOs and accesses the GPIO register directly. ``wiringPiSetupGpio`` uses BCM numbering of the GPIOs and accesses the GPIO registers directly. ``wiringPiSetupPhys`` uses physical PIN numbering of the GPIOs and accesses the GPIO register directly. -``wiringPiSetupSys`` uses BCM numbering and calls the new function ``wiringPiSetupGpioDevice`` from version 3.4 to ensure compatibility with new core. In version 2, the virtual file system/SYS/Class/GPIO was used. However, the GPIO's exports had to take place externally before the initialization! The function is outdated and should not be used! +``wiringPiSetupSys`` uses BCM numbering and calls the new function ``wiringPiSetupGpioDevice`` from version 3.4 to ensure compatibility with new core. In version 2, the virtual file system/SYS/Class/GPIO was used. However, the GPIOs exports had to take place externally before the initialization! The function is outdated and should not be used! **Since Version 3.4:** -``wiringPiSetupPinType`` decides whether WiringPi, BCM or physical PIN numbering is now used, based on the parameter pinType. So it combines the first 3 setup functions together. -``wiringPiSetupGpioDevice`` is the successor to the ``wiringPiSetupSys`` function and now uses "GPIO Character Device Userspace API" in version 1 (from kernel 5.10). More information can be found at [docs.kernel.org/driver-api/gpio/driver.html](https://docs.kernel.org/driver-api/gpio/driver.html) on the parameter pintype, it is again decided which pin numbering is used. + +``wiringPiSetupPinType`` decides whether WiringPi, BCM or physical pin numbering is used, based on the parameter pinType. So it combines the first 3 setup functions together. +``wiringPiSetupGpioDevice`` is the successor to the ``wiringPiSetupSys`` function and now uses "GPIO Character Device Userspace API" in version 2 (WiringPi version 3.16 or higher). More information can be found at [docs.kernel.org/driver-api/gpio/driver.html](https://docs.kernel.org/driver-api/gpio/driver.html) on the parameter pintype, it is again decided which pin numbering is used. In this variant, there is no direct access to the GPIO memory (DMA) but rather through a kernel interface that is available with user permissions. The disadvantage is the limited functionality and low performance. - ### wiringPiSetup V2 (outdated) Inializating WiringPi in a classic way. ->>> + +**Notice:** This function is deprecated and should not be used in modern implementations. + ```C -int wiringPiSetupGpio(void) -``` +int wiringPiSetupGpio(void); +``` ``Return Value``: Error status -> 0 ... No Error +> 0 ... No Error -**Example:** +**Example:** ```C wiringPiSetupGpio(); @@ -146,22 +148,23 @@ wiringPiSetupGpio(); ### wiringPiSetup V3 Initializing WiringPi. ->>> + ```C -int wiringPiSetupPinType(enum WPIPinType pinType) +int wiringPiSetupPinType(enum WPIPinType pinType); ``` ``pinType``: Type of PIN numbering... - - `WPI_PIN_BCM` ... BCM-Numbering - - `WPI_PIN_WPI` ... WiringPi-Numbering - - `WPI_PIN_PHYS` ... Physical Numbering + +- `WPI_PIN_BCM` ... BCM-Numbering +- `WPI_PIN_WPI` ... WiringPi-Numbering +- `WPI_PIN_PHYS` ... Physical Numbering ``Return Value``: Error status > 0 ... No Error > -1 ... Invalid Parameter Error -**Example:** +**Example:** ```C wiringPiSetupPinType(WPI_PIN_BCM); @@ -172,13 +175,14 @@ wiringPiSetupPinType(WPI_PIN_BCM); ### pinMode Changes the mode of a GPIO pins. ->>> + ```C -void pinMode(int pin, int mode) +void pinMode(int pin, int mode); ``` ``Pin``: The desired PIN (BCM, Wiringpi or PIN number). ``Mode``: The desired pin mode... + - `INPUT` ... Input - `OUTPUT` ... Output - `PWM_OUTPUT` ... PWM output (frequency and pulse break ratio can be configured) @@ -187,63 +191,71 @@ void pinMode(int pin, int mode) - `GPIO_CLOCK` ... Frequency output - `PM_OFF` ... Release -**Example:** +**Example:** ```C pinMode(17, OUTPUT); ``` -**Support:** -`PM_OFF` resets the GPIO (Input) and releases it. PWM is stopped. -Raspberry Pi 5 does not support the PWM Bal (Balanced) mode. The MS mode is activated at `PWM_OUTPUT`. -`GPIO_CLOCK` is currently not yet supported in Raspberry Pi 5 (RP1). +**Notice:** + +- `PM_OFF` resets the GPIO (Input) and releases it. PWM is stopped. +- Raspberry Pi 5 does not support the PWM Bal (Balanced) mode. The MS mode is activated at `PWM_OUTPUT`. +- `GPIO_CLOCK` is currently not yet supported in Raspberry Pi 5 (RP1). **PWM Exit** + `PWM_OUTPUT` Activates the specified PWM output with the settings: - - Mode: BAL-Balanced (Pi0-4), MS-Mark/Space (Pi 5) - - Range: 1024 - - Divider: 32 + +- Mode: BAL-Balanced (Pi0-4), MS-Mark/Space (Pi 5) +- Range: 1024 +- Divider: 32 In order to make sure that the output starts without an active frequency, you should execute ``pwmWrite(PWM_GPIO, 0);`` before activating. After that, the corresponding clock and range values ​​can be adapted, without a frequency already being output unintentionally. -### pinMode - ### digitalWrite -Set the value of a GPIO pin. ->>> +Writes the value `HIGH` or `LOW` (1 or 0) to the given pin which must have been previously set as an output. + ```C -void digitalWrite(int pin, int value) +void digitalWrite(int pin, int value); ``` ``pin``: The desired Pin (BCM-, Wiringpi- or PIN number). ``value``: The logical value... - - `HIGH` ... Value 1 (electrical ~ 3.3 V) - - `LOW` ... Value 0 (electrical ~0 V / GND) -**Example:** +- `HIGH` ... Value 1 (electrical ~3.3 V) +- `LOW` ... Value 0 (electrical ~0 V / GND) + +**Example:** ```C pinMode(17, OUTPUT); -DigitalWrite(17, HIGH); + +digitalWrite(17, HIGH); ``` +**Note** + +WiringPi treats any non-zero number as `HIGH`, however 0 is the only representation of `LOW`. + ### pullUpDnControl Changes the internal pull-up / pull-down resistance. ->>> + ```C -void pullUpDnControl (int pin, int pud) +void pullUpDnControl (int pin, int pud); ``` ``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). ``pud``: The resistance type... - - `PUD_OFF` ... No resistance - - `PUD_UP` ... Pull-Up resistance (~50 kOhm) - - `PUD_DOWN` ... Pull-Down resistance (~50 kOhm) -**Example:** +- `PUD_OFF` ... No resistance +- `PUD_UP` ... Pull-Up to pull to 3.3v (~50 kOhm resistance) +- `PUD_DOWN` ... Pull-Down to pull to ground (~50 kOhm resistance) + +**Example:** ```C pullUpDnControl(17, PUD_DOWN); @@ -251,19 +263,19 @@ pullUpDnControl(17, PUD_DOWN); ### digitalRead -Reads the value of one GPIO-Pin. ->>> +Reads the value of the given GPIO-Pin. It will be `HIGH` or `LOW` (1 or 0) depending on the logic level at the pin. + ```C -int digitalRead(int pin) +int digitalRead(int pin); ``` ``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). ``Return Value``: The logical value. > `HIGH` ... Value 1 -> `LOW` ... Value 0 +> `LOW` ... Value 0 -**Example:** +**Example:** ```C pinMode(17, INPUT); @@ -281,36 +293,71 @@ if (value == HIGH) ### wiringPiISR -Registers an Interrupt Service Routine (ISR) / function that is executed on edge detection. +Registers an Interrupt Service Routine (ISR) / function that is executed on edge detection. +In this classic version, no parameters are passed to the ISR. ->>> ```C int wiringPiISR(int pin, int mode, void (*function)(void)); ``` -``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). -``mode``: Triggering edge mode... - - `INT_EDGE_RISING` ... Rising edge - - `INT_EDGE_FALLING` ... Falling edge - - `INT_EDGE_BOTH` ... Rising and falling edge +``pin``: The desired pin (BCM-, WiringPi-, or Pin-number). +``mode``: Triggering edge mode + +- `INT_EDGE_RISING` ... Rising edge +- `INT_EDGE_FALLING` ... Falling edge +- `INT_EDGE_BOTH` ... Rising and falling edge ``*function``: Function pointer for ISR ``Return Value``: - -> 0 ... Successful +> 0 ... Successful -For example see **wiringPiISRStop**. +For example see [wiringPiISRStop](#wiringPiISRStop). + + +### wiringPiISR2 + +Registers an Interrupt Service Routine (ISR) / function that is executed on edge detection. +Extended parameters are passed to the ISR. + +>>> +```C +int wiringPiISR2(int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus, void* userdata), unsigned long debounce_period_us, void* userdata); +``` + +``pin``: The desired pin (BCM-, WiringPi-, or Pin-number). +``edgeMode``: Triggering edge mode + +- `INT_EDGE_RISING` ... Rising edge +- `INT_EDGE_FALLING` ... Falling edge +- `INT_EDGE_BOTH` ... Rising and falling edge + +``*function``: Function pointer for ISR with the parameter struct WPIWfiStatus and a pointer. +```C +struct WPIWfiStatus { + int statusOK; // -1: error (return of 'poll' command), 0: timeout, 1: irq processed, next data values are valid if needed + unsigned int pinBCM; // gpio as BCM pin + int edge; // INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds +}; +``` + +``debounce_period_us``: Debounce time in microseconds, 0 disables debouncing. +``userdata``: Pointer that is passed when calling the ISR. + +``Return Value``: + > 0 ... Successful + + For example see [waitForInterrupt2](#waitForInterrupt2). ### wiringPiISRStop -Deregisters the Interrupt Service Routine (ISR) on a Pin. +Deregisters the Interrupt Service Routine (ISR) on a pin. ->>> ```C -int wiringPiISRStop (int pin) +int wiringPiISRStop (int pin); ``` ``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). @@ -320,8 +367,7 @@ int wiringPiISRStop (int pin) - -**Example:** +**Example:** ```C static volatile int edgeCounter; @@ -334,43 +380,193 @@ int main (void) { wiringPiSetupPinType(WPI_PIN_BCM); edgeCounter = 0; - wiringPiISR (17, INT_EDGE_RISING, &isr); + wiringPiISR(17, INT_EDGE_RISING, &isr); Sleep(1000); - printf("%d rinsing edges\n", ); + printf("%d rising edges\n", edgeCounter); wiringPiISRStop(17); } ``` - ### waitForInterrupt -Waits for a previously defined interrupt (wiringPiISR) on the GPIO pin. This function should not be used. +The function is no longer available, only ``waitForInterrupt2``! + + +### waitForInterrupt2 + +Waits for a call to the Interrupt Service Routine (ISR) with a timeout and debounce time in microseconds. Blocks the program until the triggering edge occurs or the timeout expires. ->>> ```C -int waitForInterrupt (int pin, int mS) +struct WPIWfiStatus wfiStatus waitForInterrupt2(int pin, int edgeMode, int ms, unsigned long debounce_period_us) ``` ``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). -``mS``: Timeout in milliseconds. -``Return Value``: Error -> 0 ... Successful -> -1 ... GPIO Device Chip not successfully opened -> -2 ... ISR was not registered (WiringPiISR must be called) +``ms``: Timeout in milliseconds. + - \-1 ... Wait without timeout + - 0 ... No wait + - 1-n ... Waits for a maximum of n milliseconds + +``debounce_period_us``: Debounce time in microseconds, 0 disables debouncing. + +``Return Value``: +```C +struct WPIWfiStatus { + int statusOK; // -1: error (return of 'poll' command), 0: timeout, 1: irq processed, next data values are valid if needed + unsigned int pinBCM; // gpio as BCM pin + int edge; // INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds +}; +``` + +**Example:** + +```C +/* + * isr_debounce.c: + * Wait for Interrupt test program WiringPi >=3.16 - ISR2 method + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define BOUNCETIME 3000 // microseconds +#define BOUNCETIME_WFI 300 +#define TIMEOUT 10000 +//************************************* +// BCM pins +// IRQpin : setup as input with internal pullup. Connected with push button to GND with 1K resistor in series. +// OUTpin : connected to a LED with 470 Ohm resistor in series to GND. Toggles LED with every push button pressed. +//************************************* +#define IRQpin 16 +#define OUTpin 12 + +int toggle = 0; + +static void wfi(struct WPIWfiStatus wfiStatus, void* userdata) { +// struct timeval now; + long long int timenow, diff; + struct timespec curr; + char *edgeType; + + if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) { + printf("clock_gettime error"); + return; + } + + timenow = curr.tv_sec * 1000000LL + curr.tv_nsec/1000L; // convert to microseconds + diff = timenow - wfiStatus.timeStamp_us; + if (wfiStatus.edge == INT_EDGE_RISING) + edgeType = "rising"; + else if (wfiStatus.edge == INT_EDGE_FALLING) + 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); + if (toggle == 0) { + digitalWrite (OUTpin, HIGH); + toggle = 1; + } + else { + digitalWrite (OUTpin, LOW); + toggle = 0; + } +} + + +int main (void) +{ + int major, minor; + wiringPiVersion(&major, &minor); + printf("\nISR debounce test (WiringPi %d.%d)\n\n", major, minor); + + wiringPiSetupGpio(); + pinMode(IRQpin, INPUT); + // pull up/down mode (PUD_OFF, PUD_UP, PUD_DOWN) => down + pullUpDnControl(IRQpin, PUD_UP); + pinMode(OUTpin, OUTPUT); + digitalWrite (OUTpin, LOW) ; + + printf("Testing waitForInterrupt 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) { + printf("waitForInterrupt returned error\n"); + pinMode(OUTpin, INPUT); + return 0; + } + else if (wfiStatus.status == 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); + else + printf("waitForInterrupt: GPIO pin %d rising edge fired at %lld microseconds\n\n", wfiStatus.gpioPin, 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("To stop program hit return key\n\n"); + + wiringPiISR2(IRQpin, INT_EDGE_BOTH, &wfi, BOUNCETIME, NULL); + + getc(stdin); + + wiringPiISRStop (IRQpin); + pinMode(OUTpin, INPUT); + + return 0; +} +``` + +Output on terminal: + +``` +pi@RaspberryPi:~/wiringpi-test-v3.16 $ gcc -o isr_debounce isr_debounce.c -l wiringPi +pi@RaspberryPi:~/wiringpi-test-v3.16 $ ./isr_debounce + +ISR debounce test (WiringPi 3.16) + +Testing waitForInterrupt on both edges IRQ @ GPIO16, timeout is 10000 +waitForInterrupt: GPIO pin 16 falling edge fired at 256522528012 microseconds + +Testing IRQ @ GPIO16 on both edges and bouncetime 3000 microseconds. Toggle LED @ GPIO12 on IRQ. + +To stop program hit return key + +gpio BCM = 16, IRQ edge = rising, timestamp = 256522668010 microseconds, timenow = 256522668017, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256536364014 microseconds, timenow = 256536364021, diff = 7 +gpio BCM = 16, IRQ edge = rising, timestamp = 256536952011 microseconds, timenow = 256536952018, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256537856010 microseconds, timenow = 256537856016, diff = 6 +gpio BCM = 16, IRQ edge = rising, timestamp = 256538744011 microseconds, timenow = 256538744018, diff = 7 +gpio BCM = 16, IRQ edge = falling, timestamp = 256539664010 microseconds, timenow = 256539664017, diff = 7 +gpio BCM = 16, IRQ edge = rising, timestamp = 256540516010 microseconds, timenow = 256540516016, diff = 6 +gpio BCM = 16, IRQ edge = falling, timestamp = 256541560013 microseconds, timenow = 256541560022, diff = 9 +gpio BCM = 16, IRQ edge = rising, timestamp = 256542360010 microseconds, timenow = 256542360016, diff = 6 +gpio BCM = 16, IRQ edge = falling, timestamp = 256543320012 microseconds, timenow = 256543320020, diff = 8 +gpio BCM = 16, IRQ edge = rising, timestamp = 256544092021 microseconds, timenow = 256544092029, diff = 8 +^C +pi@RaspberryPi:~/wiringpi-test-v3.16 $ +``` ## Hardware Pulse Width Modulation (PWM) -Available GPIOs: https://pinout.xyz/pinout/pwm +Available GPIOs: [https://pinout.xyz/pinout/pwm](https://pinout.xyz/pinout/pwm) ### pwmWrite Changes the PWM value of the pin. Possible values ​​are 0 -> { PWM Range }. ->>> + ```C -pwmWrite(int pin, int value) +pwmWrite(int pin, int value); ``` ``pin``: The desired Pin (BCM-, WiringPi-, or Pin-number). @@ -381,9 +577,9 @@ pwmWrite(int pin, int value) Set the range for the PWM value of all PWM pins or PWM channels. 19200 / divisor / range applies to the calculation of the PWM frequency (m/s mode). If ``pinMode(pin, PWM_OUTPUT)`` The value 1024 is automatically set for the divider. ->>> + ```C -pwmSetRange (unsigned int range) +pwmSetRange (unsigned int range); ``` ``range``: PWM Range @@ -391,60 +587,62 @@ pwmSetRange (unsigned int range) ### pwmSetMode Set the PWM mode for all PWM pins or PWM channels. ->>> + ```C pwmSetMode(int mode); ``` ``mode``: PWM Mode - - `PWM_MODE_MS` ... Mark / Space Mode (PWM Fixed Frequency) - - `PWM_MODE_BAL` ... Balanced Mode (PWM Variable Frequency) -**Support:** +- `PWM_MODE_MS` ... Mark / Space Mode (PWM Fixed Frequency) +- `PWM_MODE_BAL` ... Balanced Mode (PWM Variable Frequency) + +**Notice:** + Raspberry Pi 5 does not support the balanced mode! - ### pwmSetClock Set the divider for the basic PWM. The base clock is standardized for all Raspberry Pi's to 1900 kHz. 19200 / divisor / range applies to the calculation of the PWM frequency (m/s mode). -If ``pinmode(pin, PWM_OUTPUT)`` The value 32 is automatically set for the divider. ->>> +If ``pinMode(pin, PWM_OUTPUT)`` The value 32 is automatically set for the divider. + ```C -pwmSetClock(int divisor) +pwmSetClock(int divisor); ``` -``divisor``: Divider (Raspberry Pi 4: 1-1456, all other 1-4095) +``divisor``: Divider (Raspberry Pi 4: 1-1456, all other 1-4095) - `0` ... Deactivates the PWM clock on Raspberry Pi 5, with other Pi's divisor `1` is used -**Support:** +**Notice:** + Due to its higher internal basic clock, the Raspberry Pi 4 only has a setting range of `1 - 1456`. Otherwise, `0 - 4095` applies to a valid divider. -**Example:** +**Example:** ```C int main (void) { - wiringPiSetupGpio() ; + wiringPiSetupGpio(); pwmSetRange(1024); pwmSetClock(35); pwmWrite(18, 512); - + + // Notice: PWM_BAL_OUTPUT NOT supported on Pi 5 pinMode(18, PWM_MS_OUTPUT); - + double freq = 19200.0 / (double)pwmc / (double)pwmr; - + printf("PWM 50%% @ %g kHz", freq); delay(250); - + pinMode(18, PM_OFF); } ``` - ## I2C - Bus ``wiringPiI2CRawWrite`` and ``wiringPiI2CRawRead`` are the new functions in version 3 that now allow direct sending and reading of I2C data. The other write and read functions use the SMBus protocol, which is commonly used with I2C chips. @@ -453,18 +651,15 @@ int main (void) { Open the default I2C bus on the Raspberry Pi and addresses the specified device / slave. ->>> ```C -wiringPiI2CSetup(const int devId) +wiringPiI2CSetup(const int devId); ``` -``devId``: I2C-Gerät / Slave Adresse. -``Return Value``: File Handle to I2C-Bus +``devId``: I2C device / slave address. +``Return Value``: File handle to I2C bus, or -1 on error. -> -1 ... Error or EXIT (Programm termination) +**Example** -**Example** ->>> ```C int fd = wiringPiI2CSetup(0x20); ``` @@ -473,33 +668,41 @@ int fd = wiringPiI2CSetup(0x20); Opens the specified I2C bus and addresses the specified I2C device / slave. ->>> ```C -wiringPiI2CSetupInterface(const char *device, int devId) +wiringPiI2CSetupInterface(const char *device, int devId); ``` -``devId``: I2C-Gerät / Slave Adresse. -``Return Value``: File Handle to I2C-Bus +``devId``: I2C device / slave address. +``Return Value``: File handle to I2C bus, or -1 on error. -> -1 ... Error or EXIT (Programm termination) +**Example** -**Example** ->>> ```C int fd = wiringPiI2CSetupInterface("/dev/i2c-1", 0x20); ``` +### wiringPiI2CWrite -### wiringPiI2CWrite / wiringPiI2CWriteReg8 / wiringPiI2CWriteReg16 / wiringPiI2CWriteBlockData +Simple device write. Some devices accept data this way without needing to access any internal registers. -... +### wiringPiI2CWriteReg8 + +Writes 8-bit data value to the device register. + +### wiringPiI2CWriteReg16 + +Writes 16-bit data value to the device register. + +### wiringPiI2CWriteBlockData + +Writes specified byte data values to the device register. ### wiringPiI2CRawWrite Writing data about an I2C slave. ->>> + ```C -int wiringPiI2CRawWrite(int fd, const uint8_t *values, uint8_t size) +int wiringPiI2CRawWrite(int fd, const uint8_t *values, uint8_t size); ``` ``fd``: File Handle. @@ -507,8 +710,8 @@ int wiringPiI2CRawWrite(int fd, const uint8_t *values, uint8_t size) ``size``: Number of bytes of the source buffer that should be written. ``Return Value``: Number of bytes that were written. -**Example** ->>> +**Example** + ```C int fd = wiringPiI2CSetup(I2C_ADDR); @@ -527,16 +730,31 @@ else { } ``` -### wiringPiI2CRead / wiringPiI2CReadReg8 / wiringPiI2CReadReg16 / wiringPiI2CReadBlockData -... +### wiringPiI2CRead + + +Simple read from I2C slave. Some devices accept data this way without needing to access any internal registers. + +### wiringPiI2CReadReg8 + +Reads 8-bit data value from the device register. + +### wiringPiI2CReadReg16 + +Reads 16-bit data value from the device register. + + +### wiringPiI2CReadBlockData + +Reads specified byte data values from the device register. ### wiringPiI2CRawRead Reading data from an I2C slave. ->>> + ```C -int wiringPiI2CRawRead(int fd, uint8_t *values, uint8_t size) +int wiringPiI2CRawRead(int fd, uint8_t *values, uint8_t size); ``` ``fd``: File Handle. @@ -544,8 +762,8 @@ int wiringPiI2CRawRead(int fd, uint8_t *values, uint8_t size) ``size``: Number of bytes that are to be read into the target buffer. ``Return Value``: Number of bytes that were read. -**Example** ->>> +**Example** + ```C int fd = wiringPiI2CSetup(I2C_ADDR); @@ -564,32 +782,30 @@ else { } ``` - ## SPI - Bus Functions that start with ``wiringPiSPIx`` are new since version 3, allowing the SPI bus number to be specified. This is especially useful for the Compute Module, which has multiple SPI buses (0-7). The old functions remain available, but they always refer to SPI bus 0, which is available on the 40 pin GPIO connector. - ### wiringPiSPISetup / wiringPiSPISetupMode / wiringPiSPIxSetupMode -Opens the specified SPI bus. +Opens the specified SPI bus. The Raspberry Pi has 2 channels, 0 and 1. The speed parameter is an integer in the range of 500,000 through 32,000,000 and represents the SPI clock speed in Hz. ->>> ```C -int wiringPiSPISetup (int channel, int speed) -int wiringPiSPISetup (int channel, int speed, int mode) -int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode) +int wiringPiSPISetup(int channel, int speed); + +int wiringPiSPISetupMode(int channel, int speed, int mode); + +int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode); ``` -``number``: SPI muber (typically 0, on Compute Module 0-7). +``number``: SPI number (typically 0, on Compute Module 0-7). ``channel``: SPI channel (typically 0 or 1, on Compute Module 0-3). -``speed``: SPI clock. -``mode``: SPI mode (https://www.kernel.org/doc/Documentation/spi/spidev). -``Return Value``: File handle to the SPI bus -> -1 ... Error or EXIT (Programm termination) +``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. + +**Example** -**Example** ->>> ```C const int spiChannel = 1; const int spiSpeedInit = 250000; // Hz @@ -604,25 +820,26 @@ if ((hSPI = wiringPiSPISetup (spiChannel, spiSpeed)) < 0) { wiringPiSPIClose(spiChannel); ``` -### wiringPiSPIDataRW / wiringPiSPIxDataRW +### wiringPiSPIDataRW / wiringPiSPIxDataRW A synchronous fullduplex write and read operation is performed on the opened SPI bus. In the process, the sent data is overwritten by the received data. ->>> ```C -int wiringPiSPIDataRW (int channel, unsigned char *data, int len) -int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data, const int len) +int wiringPiSPIDataRW (int channel, unsigned char *data, int len); + +int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data, const int len); ``` -``number``: SPI muber (typically 0, on Compute Module 0-7). +``number``: SPI number (typically 0, on Compute Module 0-7). ``channel``: SPI channel (typically 0 or 1, on Compute Module 0-3). ``data``: Buffer ``len``: Size of ``data`` buffer or data size. -``Return Value``: Return Value of ``ioctl`` function (https://man7.org/linux/man-pages/man2/ioctl.2.html) -<0 ... Error, see ``errno`` for error number. +``Return Value``: Return Value of ``ioctl`` function ([https://man7.org/linux/man-pages/man2/ioctl.2.html](https://man7.org/linux/man-pages/man2/ioctl.2.html)) + +> 0 ... Error, see ``errno`` for error number. + +**Example** -**Example** ->>> ```C const int spiChannel = 1; const int spiSpeedInit = 250000; // Hz @@ -637,8 +854,9 @@ int returnvalue; spiData[0] = 0b11010000; spiData[1] = 0; spiData[2] = 0; + returnvalue = wiringPiSPIxDataRW(0, spiChannel, spiData, 3); -if (returnvalue<=0) { +if (returnvalue <= 0) { printf("SPI transfer error: %d\n", errno); } @@ -649,24 +867,25 @@ wiringPiSPIxClose(0, spiChannel); Returns the file handle to the opened SPI bus. ->>> ```C -int wiringPiSPIGetFd(int channel) -int wiringPiSPIxGetFd(const int number, int channel) +int wiringPiSPIGetFd(int channel); + +int wiringPiSPIxGetFd(const int number, int channel); ``` -``number``: SPI muber (typically 0, on Compute Module 0-7). +``number``: SPI number (typically 0, on Compute Module 0-7). ``channel``: SPI channel (typically 0 or 1, on Compute Module 0-3). -``Return Value``: File handle to the SPI bus +``Return Value``: File handle to the SPI bus + > -1 ... Invalid or not opened -**Example** ->>> +**Example** + ```C const int spiChannel = 1; const int spiSpeedInit = 250000; // Hz -int hSPI; +int hSPI; if ((hSPI = wiringPiSPISetup (spiChannel, spiSpeed)) < 0) { //error } diff --git a/examples/Gertboard/7segments.c b/examples/Gertboard/7segments.c index 8797e49..b477a5d 100644 --- a/examples/Gertboard/7segments.c +++ b/examples/Gertboard/7segments.c @@ -91,7 +91,7 @@ PI_THREAD (displayDigits) for (segment = 0 ; segment < 7 ; ++segment) { d = toupper (display [digit]) ; - /**/ if ((d >= '0') && (d <= '9')) // Digit + if ((d >= '0') && (d <= '9')) // Digit index = d - '0' ; else if ((d >= 'A') && (d <= 'F')) // Hex index = d - 'A' + 10 ; diff --git a/examples/PiGlow/piglow.c b/examples/PiGlow/piglow.c index be5a5e0..b83be61 100644 --- a/examples/PiGlow/piglow.c +++ b/examples/PiGlow/piglow.c @@ -97,7 +97,7 @@ int main (int argc, char *argv []) { percent = getPercent (argv [2]) ; - /**/ if (strcasecmp (argv [1], "red") == 0) + if (strcasecmp (argv [1], "red") == 0) piGlowRing (PIGLOW_RED, percent) ; else if (strcasecmp (argv [1], "yellow") == 0) piGlowRing (PIGLOW_YELLOW, percent) ; @@ -122,7 +122,7 @@ int main (int argc, char *argv []) if (argc == 4) { - /**/ if (strcasecmp (argv [1], "leg") == 0) + if (strcasecmp (argv [1], "leg") == 0) { leg = atoi (argv [2]) ; if ((leg < 0) || (leg > 2)) diff --git a/examples/ds1302.c b/examples/ds1302.c index 025e79b..fec690b 100644 --- a/examples/ds1302.c +++ b/examples/ds1302.c @@ -205,7 +205,7 @@ int main (int argc, char *argv []) if (argc == 2) { - /**/ if (strcmp (argv [1], "-slc") == 0) + if (strcmp (argv [1], "-slc") == 0) return setLinuxClock () ; else if (strcmp (argv [1], "-sdsc") == 0) return setDSclock () ; diff --git a/examples/isr_debounce.c b/examples/isr_debounce.c new file mode 100644 index 0000000..8ddc9c1 --- /dev/null +++ b/examples/isr_debounce.c @@ -0,0 +1,116 @@ +/* + * isr_debounce.c: + * Wait for Interrupt test program WiringPi >=3.13 - ISR method + * + * + */ + +#include +#include +#include +#include +#include + +#include + +#define BOUNCETIME 300 +#define TIMEOUT 10000 +//************************************* +// BCM pins +// IRQpin : setup as input with internal pullup. Connected with push button to GND with 1K resistor in series. +// OUTpin : connected to a LED with 470 Ohm resistor in series to GND. Toggles LED with every push button pressed. +//************************************* +#define IRQpin 16 +#define OUTpin 12 + +int toggle = 0; + +/* + * myInterrupt: + ********************************************************************************* + */ + +static void wfi (unsigned int gpio, long long int timestamp) { +// struct timeval now; + long long int timenow, diff; + struct timespec curr; + + if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) { + printf("clock_gettime error"); + return; + } + + timenow = curr.tv_sec * 1000000LL + curr.tv_nsec/1000L; // convert to microseconds + diff = timenow - timestamp; + + printf("gpio BCM = %d, IRQ timestamp = %lld microseconds, timenow = %lld, diff = %lld\n", gpio, timestamp, timenow, diff); + if (toggle == 0) { + digitalWrite (OUTpin, HIGH) ; + toggle = 1; + } + else { + digitalWrite (OUTpin, LOW) ; + toggle = 0; + } +} + + + +int main (void) +{ + int major, minor; + long long int ret; + + wiringPiVersion(&major, &minor); + + printf("\nISR debounce test (WiringPi %d.%d)\n\n", major, minor); + + wiringPiSetupGpio() ; + + pinMode(IRQpin, INPUT); + + // pull up/down mode (PUD_OFF, PUD_UP, PUD_DOWN) => down + pullUpDnControl(IRQpin, PUD_UP); + + pinMode(OUTpin, OUTPUT); + digitalWrite (OUTpin, LOW) ; + + // test waitForInterrupt + + ret = waitForInterruptInit (IRQpin, INT_EDGE_FALLING); + if (ret < 0) { + printf("waitForInterruptInit returned error %d\n", ret); + pinMode(OUTpin, INPUT); + return 0; + } + + printf("Testing waitForInterrupt IRQ @ GPIO%d, timeout is %d\n", IRQpin, TIMEOUT); + ret = waitForInterrupt(IRQpin, TIMEOUT, 0); + if (ret < 0) { + printf("waitForInterrupt returned error %lld\n", ret); + wiringPiISRStop (IRQpin) ; + pinMode(OUTpin, INPUT); + return 0; + } + else if (ret == 0) { + printf("waitForInterrupt timed out %lld\n\n", ret); + wiringPiISRStop (IRQpin) ; + } + else { + printf("waitForInterrupt: falling edge fired at %lld microseconds\n\n", ret); + wiringPiISRStop (IRQpin) ; + } + + printf("Testing IRQ @ GPIO%d with trigger @ GPIO%d falling edge and bouncetime %d ms. Toggle LED @ OUTpin on IRQ.\n\n", IRQpin, IRQpin, BOUNCETIME, OUTpin); + printf("To stop program hit return key\n\n"); + + wiringPiISR (IRQpin, INT_EDGE_FALLING, &wfi, BOUNCETIME) ; + +// sleep(30); + getc(stdin); + + wiringPiISRStop (IRQpin) ; + pinMode(OUTpin, INPUT); + + return 0 ; +} \ No newline at end of file diff --git a/examples/scrollPhat/scphat.c b/examples/scrollPhat/scphat.c index cba6c0f..23abcb0 100644 --- a/examples/scrollPhat/scphat.c +++ b/examples/scrollPhat/scphat.c @@ -209,7 +209,7 @@ int main (int argc, char *argv []) while (arg != argc) { command = argv [arg] ; - /**/ if (strcasecmp (command, "clear") == 0) arg += doClear () ; + if (strcasecmp (command, "clear") == 0) arg += doClear () ; else if (strcasecmp (command, "cls") == 0) arg += doClear () ; else if (strcasecmp (command, "bright") == 0) arg += doBright (arg, argc, argv) ; else if (strcasecmp (command, "plot") == 0) arg += doPlot (arg, argc, argv) ; diff --git a/gpio/gpio.c b/gpio/gpio.c index 3fc97a3..b5f0182 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -66,23 +66,27 @@ int wpMode ; char *usage = "Usage: gpio -v\n" " gpio -h\n" " gpio [-g|-1] ...\n" + " where -g: pin numbering according to readall BCM column\n" + " where -1: pin numbering according to readall Physical column\n" + " when omitted: pin numbering according to readall wPi column\n" " gpio [-d] ...\n" " [-x extension:params] [[ -x ...]] ...\n" " gpio [-p] ...\n" " gpio ...\n" " gpio \n" - " gpio readall\n" - " gpio wfi \n" - " gpio drive \n" - " gpio pwm-bal/pwm-ms \n" - " gpio pwmr \n" - " gpio pwmc \n" - " gpio i2cd/i2cdetect\n" - " gpio rbx/rbd\n" - " gpio wb \n" - " gpio usbp high/low\n" - " gpio gbr \n" - " gpio gbw " ; // No trailing newline needed here. + " gpio readall\n" + " gpio wfi \n" + " where can be: rising, falling, both\n" + " gpio drive \n" + " gpio pwm-bal/pwm-ms \n" + " gpio pwmr \n" + " gpio pwmc \n" + " gpio i2cd/i2cdetect\n" + " gpio rbx/rbd\n" + " gpio wb \n" + " gpio usbp high/low\n" + " gpio gbr \n" + " gpio gbw " ; // No trailing newline needed here. #ifdef NOT_FOR_NOW @@ -161,7 +165,7 @@ void LOAD_DEPRECATED(const char *progName) { ********************************************************************************* */ -static volatile int iterations ; +static volatile int globalIterations ; static volatile int globalCounter ; void printgpioflush(const char* text) { @@ -177,59 +181,133 @@ void printgpio(const char* text) { } } -static void wfi (void) { +static void wfi (void) { globalCounter++; - if(globalCounter>=iterations) { + if(globalCounter>=globalIterations) { printgpio("finished\n"); - exit (0) ; + exit(0); } else { printgpioflush("I"); } } -void doWfi (int argc, char *argv []) -{ - int pin, mode; - int timeoutSec = 2147483647; - iterations = 1; +static void wfi2(struct WPIWfiStatus wfiStatus, void* userdata) { + (void)wfiStatus; + (void)userdata; + globalCounter++; + if (globalCounter>=globalIterations) { + switch(wfiStatus.edge) { + case INT_EDGE_FALLING: + printgpio("finished falling\n"); + break; + case INT_EDGE_RISING: + printgpio("finished rising\n"); + break; + default: + printgpio("finished\n"); + break; + } + exit(wfiStatus.edge); + } else { + printgpioflush("I"); + } +} + + +int get_wfi_edge(const char* arg_cmd, const char* arg_mode, int exitcode) { + if (strcasecmp (arg_mode, "rising") == 0) { + return INT_EDGE_RISING ; + } else if (strcasecmp (arg_mode, "falling") == 0) { + return INT_EDGE_FALLING ; + } else if (strcasecmp (arg_mode, "both") == 0) { + return INT_EDGE_BOTH ; + } else { + fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", arg_cmd, arg_mode) ; + exit(exitcode); + } +} + + +void doWfiInternal(const char* cmd, int pin, int mode, int interations, int timeoutSec, int debounce) { + + globalIterations = interations; globalCounter = 0; - if (argc != 4 && argc != 5 && argc != 6) - { - fprintf (stderr, "Usage: %s wfi pin mode [interations] [timeout sec.]\n", argv [0]) ; - exit (1) ; - } - - pin = atoi (argv [2]) ; - - /**/ if (strcasecmp (argv [3], "rising") == 0) mode = INT_EDGE_RISING ; - else if (strcasecmp (argv [3], "falling") == 0) mode = INT_EDGE_FALLING ; - else if (strcasecmp (argv [3], "both") == 0) mode = INT_EDGE_BOTH ; - else - { - fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", argv [1], argv [3]) ; - exit (1) ; - } - if (argc>=5) { - iterations = atoi(argv [4]); - } - if (argc>=6) { - timeoutSec = atoi(argv [5]); - } - - if (wiringPiISR (pin, mode, &wfi) < 0) - { - fprintf (stderr, "%s: wfi: Unable to setup ISR: %s\n", argv [1], strerror (errno)) ; - exit (1) ; + if (debounce>=0) { + // V2 function + if (wiringPiISR2(pin, mode, &wfi2, debounce, NULL) < 0) { + fprintf (stderr, "%s: Unable to setup ISR2: %s\n", cmd, strerror (errno)); + exit(1); + } + } else { + // classic function + if (wiringPiISR(pin, mode, &wfi) < 0) { + fprintf (stderr, "%s: Unable to setup ISR: %s\n", cmd, strerror (errno)); + exit(1); + } } printgpio("wait for interrupt function call\n"); for (int Sec=0; Sec=5) { + interations = atoi(argv[4]); + } + if (argc>=6) { + timeoutSec = atoi(argv[5]); + } + + doWfiInternal(argv[1], pin, mode, interations, timeoutSec, -1); +} + + +void doWfi2(int argc, char *argv []) +{ + int pin, mode, interations=1, debounce=50000; + int timeoutSec = 2147483647; + + if (argc != 4 && argc != 5 && argc != 6 && argc != 7) { + fprintf (stderr, "Usage: %s wfis pin mode [debounce period microsec.] [interations] [timeout sec.]\n", argv [0]); + exit(-2); + } + + pin = atoi (argv[2]) ; + mode = get_wfi_edge(argv[1], argv[3], -1); + if (argc>=5) { + debounce = atoi(argv[4]); + } + if (argc>=6) { + interations = atoi(argv[5]); + } + if (argc>=7) { + timeoutSec = atoi(argv[6]); + } + if (timeoutSec<0 || interations<0 || debounce<0) { + fprintf (stderr, " invalid parameter\n"); + exit(-2); + } + + doWfiInternal(argv[1], pin, mode, interations, timeoutSec, debounce); + exit(-1); // timeout } @@ -292,7 +370,7 @@ void doMode (int argc, char *argv []) mode = argv [3] ; - /**/ if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ; + if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ; else if (strcasecmp (mode, "input") == 0) pinMode (pin, INPUT) ; else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ; else if (strcasecmp (mode, "output") == 0) pinMode (pin, OUTPUT) ; @@ -524,14 +602,14 @@ static void doWrite (int argc, char *argv []) pin = atoi (argv [2]) ; - /**/ if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0)) + if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0)) val = 1 ; else if ((strcasecmp (argv [3], "down") == 0) || (strcasecmp (argv [3], "off") == 0)) val = 0 ; else val = atoi (argv [3]) ; - /**/ if (val == 0) + if (val == 0) digitalWrite (pin, LOW) ; else digitalWrite (pin, HIGH) ; @@ -896,6 +974,10 @@ static void doVersion (char *argv []) } +static void doIs40Pin () +{ + exit(piBoard40Pin() ? EXIT_SUCCESS : EXIT_FAILURE); +} /* * main: @@ -981,7 +1063,7 @@ int main (int argc, char *argv []) // Initial test for /sys/class/gpio operations: --> deprecated, empty but still there - /**/ if (strcasecmp (argv [1], "exports" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } + if (strcasecmp (argv [1], "exports" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } else if (strcasecmp (argv [1], "export" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } else if (strcasecmp (argv [1], "edge" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } else if (strcasecmp (argv [1], "unexport" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } @@ -1012,7 +1094,7 @@ int main (int argc, char *argv []) // Check for -g argument - /**/ if (strcasecmp (argv [1], "-g") == 0) + if (strcasecmp (argv [1], "-g") == 0) { wiringPiSetupGpio () ; @@ -1098,7 +1180,7 @@ int main (int argc, char *argv []) // Core wiringPi functions - /**/ if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ; + if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ; else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ; else if (strcasecmp (argv [1], "write" ) == 0) doWrite (argc, argv) ; else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ; @@ -1130,7 +1212,9 @@ int main (int argc, char *argv []) else if (strcasecmp (argv [1], "rbx" ) == 0) doReadByte (argc, argv, TRUE) ; else if (strcasecmp (argv [1], "rbd" ) == 0) doReadByte (argc, argv, FALSE) ; else if (strcasecmp (argv [1], "clock" ) == 0) doClock (argc, argv) ; + else if (strcasecmp (argv [1], "wfis" ) == 0) doWfi2 (argc, argv) ; else if (strcasecmp (argv [1], "wfi" ) == 0) doWfi (argc, argv) ; + else if (strcasecmp (argv [1], "is40pin" ) == 0) doIs40Pin () ; else { fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ; diff --git a/gpio/readall.c b/gpio/readall.c index cf0caf4..6e2aa18 100644 --- a/gpio/readall.c +++ b/gpio/readall.c @@ -183,7 +183,7 @@ static void readallPhys (int physPin) printf (" | | ") ; else { - /**/ if (wpMode == WPI_MODE_GPIO) + if (wpMode == WPI_MODE_GPIO) pin = physPinToGpio (physPin) ; else if (wpMode == WPI_MODE_PHYS) pin = physPin ; @@ -206,7 +206,7 @@ static void readallPhys (int physPin) printf (" | | ") ; else { - /**/ if (wpMode == WPI_MODE_GPIO) + if (wpMode == WPI_MODE_GPIO) pin = physPinToGpio (physPin) ; else if (wpMode == WPI_MODE_PHYS) pin = physPin ; @@ -380,7 +380,7 @@ void doReadall (void) piBoardId (&model, &rev, &mem, &maker, &overVolted) ; - /**/ if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) + if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) abReadall (model, rev) ; else if ((model == PI_MODEL_BP) || (model == PI_MODEL_AP) || (model == PI_MODEL_2) || diff --git a/gpio/test/gpio_test6_wfi.sh b/gpio/test/gpio_test6_wfi.sh new file mode 100755 index 0000000..5a0d6af --- /dev/null +++ b/gpio/test/gpio_test6_wfi.sh @@ -0,0 +1,219 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # Reset color + +UNITTEST_OK=true +TIMEOUT=8 +iteration=0 +GPIOIN=26 +GPIOOUT=19 +DEBOUNCE=100000 + +wait_with_timeout() { + local pid=$1 + local timeout=$2 + iteration=0 + + local toggle=0 + while kill -0 "$pid" 2>/dev/null; do + if [ $iteration -ge $timeout ]; then + kill -9 "$pid" 2>/dev/null + echo -e "${RED}ERROR: timeout ${timeout}s reached ${NC}" + return -1 + fi + echo -n . + sleep 1 + toggle=$((1 - toggle)) + gpio -g write $GPIOOUT $toggle + echo -n ${toggle} + sleep 0.2 + iteration=$((iteration + 1)) + done + + wait "$pid" + return $? +} + +wfi_test() { + local edge=$1 + local set_iter=$2 + local set_iterOK=$3 + + #wfi call + if [ $iteration -eq 0 ]; then + gpio -g wfi $GPIOIN "$edge" & + else + gpio -g wfi $GPIOIN "$edge" "$set_iter" & + fi + GPIO_PID=$! + wait_with_timeout "$GPIO_PID" "$TIMEOUT" + EXIT_CODE=$? + echo + if [ $EXIT_CODE -eq 0 ]; then + if [ "$set_iter" -gt 0 ]; then + if [ "$iteration" -eq "$set_iterOK" ]; then + echo -e "${GREEN}wfi "$edge" $set_iter iteration passt (exit code 0)${NC}" + else + echo -e "${RED}wfi "$edge" failed, $iteration iterations of $set_iter is wrong${NC}" + UNITTEST_OK=false + fi + else + echo -e "${GREEN}wfi "$edge" passt (exit code 0)${NC}" + fi + else + echo -e "${RED}wfi "$edge" failed (exit code $EXIT_CODE)${NC}" + UNITTEST_OK=false + fi +} + +wfis_test() { + local edge=$1 + local set_iter=$2 + local set_iterOK=$3 + local set_EXITCODE=$4 + + #wfis call + if [ $iteration -eq 0 ]; then + gpio -g wfis $GPIOIN "$edge" $DEBOUNCE & + else + gpio -g wfis $GPIOIN "$edge" $DEBOUNCE "$set_iter" & + fi + GPIO_PID=$! + wait_with_timeout "$GPIO_PID" "$TIMEOUT" + EXIT_CODE=$? + echo + if [ $EXIT_CODE -lt 3 ]; then + + if [ $EXIT_CODE -eq "$set_EXITCODE" ]; then + + if [ "$set_iter" -gt 0 ]; then + if [ "$iteration" -eq "$set_iterOK" ]; then + echo -e "${GREEN}wfis "$edge" $set_iter iteration passt (exit code $EXIT_CODE)${NC}" + else + echo -e "${RED}wfis "$edge" failed, $iteration iterations of $set_iter is wrong${NC}" + UNITTEST_OK=false + fi + else + echo -e "${GREEN}wfi "$edge" passt (exit code $EXIT_CODE)${NC}" + fi + + else + echo -e "${RED}wfis "$edge" failed - wrong exit code $EXIT_CODE${NC}" + UNITTEST_OK=false + fi + + else # negativ + echo -e "${RED}wfis "$edge" failed (exit code $EXIT_CODE)${NC}" + UNITTEST_OK=false + fi +} + +gpio is40pin || { GPIOIN=17; GPIOOUT=18; echo "old 28 pin system"; } + + +echo +echo Unit test gpio GPIO${GPIOOUT} and GPIO${GPIOIN} - functions: mode, write, wfi +echo ------------------------------------------------------------------ +echo + + +#prepare trigger out +gpio -g mode $GPIOOUT out + +gpio -g write $GPIOOUT 0 +wfi_test "rising" 0 0 + +gpio -g write $GPIOOUT 1 +wfi_test "falling" 0 0 + +#wfi iteration test + +gpio -g write $GPIOOUT 0 +wfi_test "rising" 4 7 + +gpio -g write $GPIOOUT 1 +wfi_test "falling" 4 8 + +gpio -g write $GPIOOUT 0 +wfi_test "both" 4 4 + +gpio -g write $GPIOOUT 0 +gpio -g mode $GPIOOUT in + +### #wfi timeout test +gpio -g wfi $GPIOIN rising 2 4 & +GPIO_PID=$! +wait_with_timeout "$GPIO_PID" "$TIMEOUT" +EXIT_CODE=$? +echo +if [ $EXIT_CODE -eq 0 ]; then + echo -e "${GREEN}wfi timeout passed (exit code 0)${NC}" +else + echo -e "${RED}wfi timeout failed (code $EXIT_CODE)${NC}" + UNITTEST_OK=false +fi + + +echo +echo Unit test gpio GPIO${GPIOOUT} and GPIO${GPIOIN} - functions: mode, write, wfis +echo ------------------------------------------------------------------ +echo + +#prepare trigger out +gpio -g mode $GPIOOUT out + +gpio -g write $GPIOOUT 1 +wfis_test "rising" 0 0 2 + +gpio -g write $GPIOOUT 0 +wfis_test "falling" 0 0 1 + +gpio -g write $GPIOOUT 1 +wfis_test "both" 0 0 1 + +gpio -g write $GPIOOUT 0 +wfis_test "both" 0 0 2 + + +#wfi iteration test + +gpio -g write $GPIOOUT 0 +wfis_test "rising" 4 7 2 + +gpio -g write $GPIOOUT 1 +wfis_test "falling" 4 8 1 + +gpio -g write $GPIOOUT 0 +wfis_test "both" 3 3 2 + +gpio -g write $GPIOOUT 1 +wfis_test "both" 3 4 1 + +gpio -g write $GPIOOUT 0 +gpio -g mode $GPIOOUT in + +### #wfi timeout test +gpio -g wfis $GPIOIN rising $DEBOUNCE 2 4 & +GPIO_PID=$! +wait_with_timeout "$GPIO_PID" "$TIMEOUT" +EXIT_CODE=$? +echo +if [ $EXIT_CODE -eq 255 ]; then + echo -e "${GREEN}wfi timeout passed (exit code $EXIT_CODE)${NC}" +else + echo -e "${RED}wfi timeout failed (code $EXIT_CODE)${NC}" + UNITTEST_OK=false +fi + + + + +if [ ${UNITTEST_OK} = true ]; then + echo -e "\n\n${GREEN}Unit test result OK.${NC}" + exit 0 +else + echo -e "\n\n${RED}Unit test result failed.${NC}" + exit 1 +fi \ No newline at end of file diff --git a/gpio/pintest b/gpio/test/pintest.sh similarity index 100% rename from gpio/pintest rename to gpio/test/pintest.sh diff --git a/gpio/test.sh b/gpio/test/test.sh similarity index 100% rename from gpio/test.sh rename to gpio/test/test.sh diff --git a/version.h b/version.h index c2da282..5ea1e8c 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ -#define VERSION "3.14" +#define VERSION "3.16" #define VERSION_MAJOR 3 -#define VERSION_MINOR 14 +#define VERSION_MINOR 16 diff --git a/wiringPi/WiringpiV1.c b/wiringPi/WiringpiV1.c new file mode 100644 index 0000000..fe6b5ce --- /dev/null +++ b/wiringPi/WiringpiV1.c @@ -0,0 +1,246 @@ +#include "Wiringpi.h" + + +int requestLineV1(int pin, unsigned int lineRequestFlags) { + struct gpiohandle_request rq; + + if (lineFds[pin]>=0) { + if (lineRequestFlags == lineFlags[pin]) { + //already requested + return lineFds[pin]; + } else { + //different request -> rerequest + releaseLine(pin); + } + } + + //requested line + if (wiringPiGpioDeviceGetFd()<0) { + return -1; // error + } + rq.lineoffsets[0] = pin; + rq.lines = 1; + rq.flags = 0; + // MAP to V1 Flag + if (lineRequestFlags & WPI_FLAG_INPUT) { + rq.flags |= GPIOHANDLE_REQUEST_INPUT; + } + if (lineRequestFlags & WPI_FLAG_OUTPUT) { + rq.flags |= GPIOHANDLE_REQUEST_OUTPUT; + } + if (lineRequestFlags & WPI_FLAG_BIAS_OFF) { + rq.flags |= GPIOHANDLE_REQUEST_BIAS_DISABLE; + } + if (lineRequestFlags & WPI_FLAG_BIAS_UP) { + rq.flags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP; + } + if (lineRequestFlags & WPI_FLAG_BIAS_DOWN) { + rq.flags |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; + } + int ret = ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &rq); + if (ret || rq.fd<0) { + ReportDeviceError("get line handle", pin, "RequestLineV1", ret); + return -1; // error + } + + lineFlags[pin] = lineRequestFlags; + lineFds[pin] = rq.fd; + if (wiringPiDebug) + printf ("requestLine succeeded: pin:%d, flags: %u, fd :%d\n", pin, lineRequestFlags, lineFds[pin]) ; + return lineFds[pin]; + } + + + int digitalReadDeviceV1(int pin) { // INPUT and OUTPUT should work + + if (lineFds[pin]<0) { + // line not requested - auto request on first read as input + pinModeDevice(pin, INPUT); + } + if (lineFds[pin]>=0) { + struct gpiohandle_data data; + int ret = ioctl(lineFds[pin], GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); + if (ret) { + ReportDeviceError("get line values", pin, "digitalRead", ret); + return LOW; // error + } + return data.values[0]; + } + return LOW; // error , need to request line before + } + + + void digitalWriteDeviceV1(int pin, int value) { + + if (wiringPiDebug) + printf ("digitalWriteDevice: ioctl pin:%d value: %d\n", pin, value) ; + + if (lineFds[pin]<0) { + // line not requested - auto request on first write as output + pinModeDevice(pin, OUTPUT); + } + if (lineFds[pin]>=0 && (lineFlags[pin] & GPIOHANDLE_REQUEST_OUTPUT)>0) { + struct gpiohandle_data data; + data.values[0] = value; + if (wiringPiDebug) + printf ("digitalWriteDevice: ioctl pin:%d cmd: GPIOHANDLE_SET_LINE_VALUES_IOCTL, value: %d\n", pin, value) ; + int ret = ioctl(lineFds[pin], GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); + if (ret) { + ReportDeviceError("set line values", pin, "digitalWrite", ret); + return; // error + } + } else { + fprintf(stderr, "digitalWrite: no output (%d)\n", lineFlags[pin]); + } + return; // error + } + + /* + * waitForInterrupt: + * Pi Specific. + * Wait for Interrupt on a GPIO pin. + * This is actually done via the /dev/gpiochip interface regardless of + * the wiringPi access mode in-use. Maybe sometime it might get a better + * way for a bit more efficiency. + ********************************************************************************* + */ + +int waitForInterruptV1(int pin, int mS) +{ + int fd, ret; + struct pollfd polls ; + struct gpioevent_data evdata; + //struct gpio_v2_line_request req2; + + if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + + if ((fd = isrFds [pin]) == -1) + return -2 ; + + // Setup poll structure + polls.fd = fd; + polls.events = POLLIN | POLLERR ; + polls.revents = 0; + + // Wait for it ... + ret = poll(&polls, 1, mS); + if (ret <= 0) { + fprintf(stderr, "wiringPi: ERROR: poll returned=%d\n", ret); + } else { + //if (polls.revents & POLLIN) + if (wiringPiDebug) { + printf ("wiringPi: IRQ line %d received %d, fd=%d\n", pin, ret, isrFds[pin]) ; + } + /* read event data */ + int readret = read(isrFds [pin], &evdata, sizeof(evdata)); + if (readret == sizeof(evdata)) { + if (wiringPiDebug) { + printf ("wiringPi: IRQ data id: %d, timestamp: %lld\n", evdata.id, evdata.timestamp) ; + } + ret = evdata.id; + } else { + ret = 0; + } + } + return ret; +} + +int waitForInterruptInitV1(int pin, int mode) +{ + const char* strmode = ""; + + if (wiringPiMode == WPI_MODE_PINS) { + pin = pinToGpio [pin] ; + } else if (wiringPiMode == WPI_MODE_PHYS) { + pin = physToGpio [pin] ; + } + + /* open gpio */ + sleep(1); + if (wiringPiGpioDeviceGetFd()<0) { + return -1; + } + + struct gpioevent_request req; + req.lineoffset = pin; + req.handleflags = GPIOHANDLE_REQUEST_INPUT; + switch(mode) { + default: + case INT_EDGE_SETUP: + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptMode mode INT_EDGE_SETUP - exiting\n") ; + } + return -1; + case INT_EDGE_FALLING: + req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; + strmode = "falling"; + break; + case INT_EDGE_RISING: + req.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; + strmode = "rising"; + break; + case INT_EDGE_BOTH: + req.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; + strmode = "both"; + break; + } + strncpy(req.consumer_label, "wiringpi_gpio_irq", sizeof(req.consumer_label) - 1); + + //later implement GPIO_V2_GET_LINE_IOCTL req2 + int ret = ioctl(chipFd, GPIO_GET_LINEEVENT_IOCTL, &req); + if (ret) { + ReportDeviceError("get line event", pin , strmode, ret); + return -1; + } + if (wiringPiDebug) { + printf ("wiringPi: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; + } + + /* set event fd nonbloack read */ + int fd_line = req.fd; + isrFds [pin] = fd_line; + int flags = fcntl(fd_line, F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl(fd_line, F_SETFL, flags); + if (ret) { + fprintf(stderr, "wiringPi: ERROR: fcntl set nonblock return=%d\n", ret); + return -1; + } + + return 0; +} + + +int waitForInterruptClose (int pin) { + if (isrFds[pin]>0) { + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose close thread 0x%lX\n", (unsigned long)isrThreads[pin]) ; + } + if (pthread_cancel(isrThreads[pin]) == 0) { + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose thread canceled successfuly\n") ; + } + } else { + if (wiringPiDebug) { + fprintf (stderr, "wiringPi: waitForInterruptClose could not cancel thread\n"); + } + } + close(isrFds [pin]); + } + isrFds [pin] = -1; + isrFunctions [pin] = NULL; + + /* -not closing so far - other isr may be using it - only close if no other is using - will code later + if (chipFd>0) { + close(chipFd); + } + chipFd = -1; + */ + if (wiringPiDebug) { + printf ("wiringPi: waitForInterruptClose finished\n") ; + } + return 0; +} diff --git a/wiringPi/ads1115.c b/wiringPi/ads1115.c index 94ac22a..44e53cb 100644 --- a/wiringPi/ads1115.c +++ b/wiringPi/ads1115.c @@ -252,7 +252,7 @@ static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int data) reg = chan + 2 ; - /**/ if (data < -32767) + if (data < -32767) ndata = -32767 ; else if (data > 32767) ndata = 32767 ; diff --git a/wiringPi/bmp180.c b/wiringPi/bmp180.c index c273ff3..bf6c209 100644 --- a/wiringPi/bmp180.c +++ b/wiringPi/bmp180.c @@ -164,7 +164,7 @@ static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) bmp180ReadTempPress (node->fd) ; - /**/ if (chan == 0) // Read Temperature + if (chan == 0) // Read Temperature return cTemp ; else if (chan == 1) // Pressure return cPress ; diff --git a/wiringPi/drcNet.c b/wiringPi/drcNet.c index 0fc5d2b..88ff655 100644 --- a/wiringPi/drcNet.c +++ b/wiringPi/drcNet.c @@ -253,24 +253,6 @@ static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) } -/* - * myDigitalWrite8: - ********************************************************************************* - -static void myDigitalWrite8 (struct wiringPiNodeStruct *node, int pin, int value) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_WRITE8 ; - cmd.data = value ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - */ - - /* * myAnalogWrite: ********************************************************************************* @@ -347,26 +329,6 @@ static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) } -/* - * myDigitalRead8: - ********************************************************************************* - -static unsigned int myDigitalRead8 (struct wiringPiNodeStruct *node, int pin) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_READ8 ; - cmd.data = 0 ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; - - return cmd.data ; -} - */ - - /* * drcNet: * Create a new instance of an DRC GPIO interface. @@ -397,8 +359,6 @@ int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, co node->analogWrite = myAnalogWrite ; node->digitalRead = myDigitalRead ; node->digitalWrite = myDigitalWrite ; -//node->digitalRead8 = myDigitalRead8 ; -//node->digitalWrite8 = myDigitalWrite8 ; node->pwmWrite = myPwmWrite ; return TRUE ; diff --git a/wiringPi/drcSerial.c b/wiringPi/drcSerial.c index c5cb2b1..6ffc2b1 100644 --- a/wiringPi/drcSerial.c +++ b/wiringPi/drcSerial.c @@ -41,7 +41,7 @@ static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) { - /**/ if (mode == OUTPUT) + if (mode == OUTPUT) serialPutchar (node->fd, 'o') ; // Input else if (mode == PWM_OUTPUT) serialPutchar (node->fd, 'p') ; // PWM @@ -66,7 +66,7 @@ static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mod serialPutchar (node->fd, 'i' ) ; serialPutchar (node->fd, pin - node->pinBase) ; - /**/ if (mode == PUD_UP) + if (mode == PUD_UP) { serialPutchar (node->fd, '1') ; serialPutchar (node->fd, pin - node->pinBase) ; diff --git a/wiringPi/htu21d.c b/wiringPi/htu21d.c index d47f4de..11f20eb 100644 --- a/wiringPi/htu21d.c +++ b/wiringPi/htu21d.c @@ -59,7 +59,7 @@ static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) double fTemp, fHumid ; int cTemp, cHumid ; - /**/ if (chan == 0) // Read Temperature + if (chan == 0) // Read Temperature { // Send read temperature command: diff --git a/wiringPi/softPwm.c b/wiringPi/softPwm.c index 6dccb05..3f2f42b 100644 --- a/wiringPi/softPwm.c +++ b/wiringPi/softPwm.c @@ -108,10 +108,8 @@ void softPwmWrite (int pin, int value) { if (pin < MAX_PINS) { - /**/ if (value < 0) - value = 0 ; - else if (value > range [pin]) - value = range [pin] ; + if (value < 0) { value = 0 ; } + else if (value > range [pin]) { value = range [pin] ; } marks [pin] = value ; } diff --git a/wiringPi/softServo.c b/wiringPi/softServo.c index f7381cc..2768fdc 100644 --- a/wiringPi/softServo.c +++ b/wiringPi/softServo.c @@ -165,7 +165,7 @@ void softServoWrite (int servoPin, int value) servoPin &= 63 ; - /**/ if (value < -250) + if (value < -250) value = -250 ; else if (value > 1250) value = 1250 ; diff --git a/wiringPi/softTone.c b/wiringPi/softTone.c index 0515336..cae0a96 100644 --- a/wiringPi/softTone.c +++ b/wiringPi/softTone.c @@ -92,7 +92,7 @@ void softToneWrite (int pin, int freq) { pin &= 63 ; - /**/ if (freq < 0) + if (freq < 0) freq = 0 ; else if (freq > 5000) // Max 5KHz freq = 5000 ; diff --git a/wiringPi/test/Makefile b/wiringPi/test/Makefile index 299dcb4..681d14e 100644 --- a/wiringPi/test/Makefile +++ b/wiringPi/test/Makefile @@ -3,7 +3,7 @@ CFLAGS = -Wall LDFLAGS = # Need BCM19 <-> BCM26, +PWM: BCM12 <-> BCM13, BCM18 <-> BCM17 connected (1kOhm) -tests = wiringpi_test0_version wiringpi_test1_sysfs wiringpi_test2_sysfs wiringpi_test3_device_wpi wiringpi_test4_device_phys wiringpi_test5_default wiringpi_test6_isr wiringpi_test7_bench wiringpi_test8_pwm wiringpi_test9_pwm +tests = wiringpi_test0_version wiringpi_test1_sysfs wiringpi_test2_sysfs wiringpi_test3_device_wpi wiringpi_test4_device_phys wiringpi_test5_default wiringpi_test6_isr wiringpi_test61_isr2 wiringpi_test62_isr_wpin wiringpi_test7_bench wiringpi_test8_pwm wiringpi_test9_pwm # Need XO hardware xotests = wiringpi_xotest_test1_spi wiringpi_i2c_test1_pcf8574 wiringpi_test8_pwm wiringpi_test9_pwm @@ -11,7 +11,7 @@ xotests = wiringpi_xotest_test1_spi wiringpi_i2c_test1_pcf8574 wiringpi_test8_pw # Need PiFace hardware and BCM23 <-> BCM24 , BCM18 <-> BCM17 connected (1kOhm), and PiFace Out7<->In4, Out6<->In5, R0_NO<->In6, R0_NO<->In7, R_C<-100Ohm->GND pifacetests = wiringpi_piface_test1 wiringpi_test8_pwm wiringpi_test9_pwm -all: $(tests) $(xotests) $(pifacetests) +all: $(tests) $(xotests) $(pifacetests) .gitignore wiringpi_test0_version: ${CC} ${CFLAGS} wiringpi_test0_version.c -o wiringpi_test0_version -lwiringPi @@ -34,6 +34,12 @@ wiringpi_test5_default: wiringpi_test6_isr: ${CC} ${CFLAGS} wiringpi_test6_isr.c -o wiringpi_test6_isr -lwiringPi +wiringpi_test61_isr2: + ${CC} ${CFLAGS} wiringpi_test61_isr2.c -o wiringpi_test61_isr2 -lwiringPi + +wiringpi_test62_isr_wpin: + ${CC} ${CFLAGS} wiringpi_test62_isr_wpin.c -o wiringpi_test62_isr_wpin -lwiringPi + wiringpi_test7_bench: ${CC} ${CFLAGS} wiringpi_test7_bench.c -o wiringpi_test7_bench -lwiringPi @@ -113,7 +119,23 @@ pifacetest: echo "\n\e[5mPIFACE TEST SUCCESS\e[0m\n"; \ fi +# Add all binaries to a folder-local .gitignore file +.gitignore: + @echo "Updating test directory .gitignore..." + @if ! test -f "./.gitignore"; then \ + echo "# This file is automatically generated by make." >> .gitignore; \ + echo "# Git will ignore this file and all generated WiringPi test binaries in this folder." >> .gitignore; \ + echo "/.gitignore" >> .gitignore; \ + fi + @for t in $(tests) $(xotests) $(pifacetests) ; do \ + if ! grep -q "/$$t" .gitignore; then \ + echo "/$$t" >> .gitignore; \ + echo "Added /$$t to .gitignore"; \ + fi; \ + done + clean: for t in $(tests) $(xotests) $(pifacetests) ; do \ rm -fv $${t} ; \ done + rm -fv .gitignore diff --git a/wiringPi/test/wiringpi_test1_sysfs.c b/wiringPi/test/wiringpi_test1_sysfs.c index a97f85e..cc2af6b 100644 --- a/wiringPi/test/wiringpi_test1_sysfs.c +++ b/wiringPi/test/wiringpi_test1_sysfs.c @@ -52,6 +52,7 @@ int main (void) { delayMicroseconds(600000); } + //Error wrong direction - only for fun digitalWrite(GPIO, LOW); diff --git a/wiringPi/test/wiringpi_test61_isr2.c b/wiringPi/test/wiringpi_test61_isr2.c new file mode 100644 index 0000000..67bb35f --- /dev/null +++ b/wiringPi/test/wiringpi_test61_isr2.c @@ -0,0 +1,279 @@ +// WiringPi test program: 6.1 new ISR2 function with Kernel char device interface / sysfs successor +// Compile: gcc -Wall wiringpi_test61_isr2.c -o wiringpi_test61_isr2 -lwiringPi + +#include "wpi_test.h" +#include +#include +#include +#include + + +int GPIO = 19; +int GPIOIN = 26; +const int ToggleValue = 4; +float irq_timstamp_duration_ms = 0; +float accuracy = 0.015; +float bounce_acc = 1.0; + +static volatile int globalCounter; +volatile long long gStartTime, gEndTime; +struct WPIWfiStatus wfiStatusOld; + +static void ISR(void) { + struct timeval now; + + gettimeofday(&now, 0); + if (0==gStartTime) { + gStartTime = now.tv_sec*1000000LL + now.tv_usec; + } else { + gEndTime = now.tv_sec*1000000LL + now.tv_usec; + } + globalCounter++; +} + + + +static void ISR2(struct WPIWfiStatus wfiStatus, void* userdata) { + struct timeval now; + char strEdge[3][10] = {"unknown", "falling", "raising"}; + int strEdgeidx = 0; //default + int* localCounter = (int*) userdata; + + gettimeofday(&now, 0); + if (0==gStartTime) { + gStartTime = now.tv_sec*1000000LL + now.tv_usec; + } else { + gEndTime = now.tv_sec*1000000LL + now.tv_usec; + } + globalCounter++; + if (localCounter) { + (*localCounter)++; + } + switch(wfiStatus.edge) { + case INT_EDGE_FALLING: strEdgeidx = INT_EDGE_FALLING; break; + case INT_EDGE_RISING: strEdgeidx = INT_EDGE_RISING; break; + } + if (wfiStatusOld.statusOK>0 && wfiStatusOld.pinBCM==wfiStatus.pinBCM) { + irq_timstamp_duration_ms = (wfiStatus.timeStamp_us - wfiStatusOld.timeStamp_us) / 1000.0f; + } else { + irq_timstamp_duration_ms = 0.0f; + } + printf("ISR occured @ %lld us: statusOK=%d, pin=%u, edge=%s (%d), duration=%g ms, userdata=%p\n", + wfiStatus.timeStamp_us, wfiStatus.statusOK, wfiStatus.pinBCM, strEdge[strEdgeidx], wfiStatus.edge, irq_timstamp_duration_ms, userdata); + wfiStatusOld = wfiStatus; +} + + +void digitalWriteBounce(int OUTpin, int value, int bounce) { + digitalWrite(OUTpin, value); + if (bounce>0) { + delay(1); + digitalWrite(OUTpin, !value); + delay(1); + digitalWrite(OUTpin, value); + } +} + + +void DelayAndSumDuration(int ms, float* irq_timstamp_sum, const int doSum) { + delay(20); + if (doSum) { + *irq_timstamp_sum += irq_timstamp_duration_ms; + } + delay(ms-20); +} + + +double StartSequence2(int Edge, int OUTpin, int INpin, int bounce, int* localCounter) { + int expected; + float timeExpected_ms; + float irq_timstamp_sum = 0.0f; + + gStartTime = 0; + gEndTime = 0; + globalCounter = 0; + *localCounter = 0; + printf("Start\n"); + digitalWriteBounce(OUTpin, HIGH, bounce); + delay(200); + + digitalWriteBounce(OUTpin, LOW, bounce); + DelayAndSumDuration(100, &irq_timstamp_sum, INT_EDGE_BOTH == Edge); + + digitalWriteBounce(OUTpin, HIGH, bounce); + DelayAndSumDuration(200, &irq_timstamp_sum, INT_EDGE_RISING == Edge || INT_EDGE_BOTH == Edge); + + digitalWriteBounce(OUTpin, LOW, bounce); + DelayAndSumDuration(100, &irq_timstamp_sum, INT_EDGE_FALLING == Edge || INT_EDGE_BOTH == Edge); + + printf("Stop\n"); + int globalCounterCopy = globalCounter; + + if (INT_EDGE_BOTH == Edge) { + expected = 4; + timeExpected_ms = bounce ? 508: 500; + } else { + expected = 2; + timeExpected_ms = bounce ? 304: 300; + } + + CheckSame("Global counted IRQ", globalCounter, expected); + CheckSame("Userdata pointer / Local counted IRQ ", *localCounter, expected); + + if (globalCounter==expected) { + char str[1024]; + float fTime = (gEndTime - gStartTime) / 1000.0; + sprintf(str, "IRQ measured %g msec (~%g expected)", fTime, timeExpected_ms); + CheckSameFloat(str, fTime, timeExpected_ms, timeExpected_ms*accuracy); + sprintf(str, "IRQ timestamp %g msec (~%g expected)", irq_timstamp_sum, timeExpected_ms); + CheckSameFloat(str, irq_timstamp_sum, timeExpected_ms, timeExpected_ms*accuracy); + // new data struct + CheckSame("GPIO IRQ pin", wfiStatusOld.pinBCM, INpin); + if (INT_EDGE_FALLING==Edge || INT_EDGE_RISING==Edge) { + CheckSame("GPIO IRQ edge", wfiStatusOld.edge, Edge); + } + CheckSame("GPIO IRQ status", wfiStatusOld.statusOK, 1); + return fTime; + } else { + printf("IRQ not worked got %d iterations (%d exprected)\n\n", globalCounterCopy, expected); + return 0; + } +} + + +double DurationTime(int Enge, int OUTpin, int IRQpin, int bounce) { + struct timeval now; + double fTime = 0.0; + const char* strOp = INT_EDGE_RISING == Enge ? "rising" : "fallling"; + gStartTime = 0; + gEndTime = 0; + globalCounter = 0; + //printf("Start\n"); + + digitalWrite(OUTpin, INT_EDGE_RISING == Enge ? LOW : HIGH); + if (bounce>=0) { + printf("\nnew function, bounce time %d ms, %s :\n", bounce, strOp); + wiringPiISR2(IRQpin, Enge, &ISR2, bounce*1000, NULL); + } else { + printf("\nclassic function, %s :\n", strOp); + wiringPiISR(IRQpin, Enge, &ISR); + } + sleep(1); + gettimeofday(&now, 0); + gStartTime = now.tv_sec*1000000LL + now.tv_usec; + digitalWrite(OUTpin, INT_EDGE_RISING == Enge ? HIGH : LOW); + delay(20); + digitalWrite(OUTpin, LOW); + delay(20); + fTime = (gEndTime - gStartTime); + if (bounce<=0) { + printf("IRQ detection time %g usec", fTime); + } else { + printf("IRQ detection time %.1f msec", fTime/1000.0); + } + if (bounce>=0) { + // bounce time + 7ms (addtional bounce time) + 100 us (basic time) + CheckBetween("IRQ detection time with bounce [us]", fTime, 0, bounce*1000+ (bounce>0 ? 7000*bounce_acc : 0)+(100*bounce_acc)); + } else { + CheckBetween("IRQ detection time [us]", fTime, 0, 100*bounce_acc); + } + wiringPiISRStop(IRQpin); + //printf("Stop\n"); + return fTime; +} + + +int main (void) { + + int major=0, minor=0; + + wiringPiVersion(&major, &minor); + + int _is40pin = piBoard40Pin(); + CheckNotSame("40-Pin board: ", _is40pin, -1); + if (_is40pin==0) { + printf("Old 28pin system\n"); + //GPIO = 23; + //GPIOIN = 24; + GPIO = 17; + GPIOIN = 18; + } + + printf("WiringPi GPIO test program 6.2 (using GPIO%d (output) and GPIO%d (input))\n", GPIO, GPIOIN); + printf("ISR and ISR2 test (WiringPi %d.%d)\n", major, minor); + + wiringPiSetupGpio(); + + int RaspberryPiModel, rev, mem, maker, overVolted; + piBoardId(&RaspberryPiModel, &rev, &mem, &maker, &overVolted); + CheckNotSame("Model: ", RaspberryPiModel, -1); + switch(RaspberryPiModel) { + case PI_MODEL_A: + case PI_MODEL_B: //ARM=800MHz + case PI_MODEL_BP: + case PI_MODEL_AP: + case PI_MODEL_CM: + accuracy = 0.02; + bounce_acc = 2.7; + break; + case PI_MODEL_ZERO: + case PI_MODEL_ZERO_W: //ARM=1000MHz + accuracy = 0.02; + bounce_acc = 2.7; + break; + default: + accuracy = 0.012; + bounce_acc = 1.0; + break; + } + int IRQpin = GPIOIN; + int OUTpin = GPIO; + + //wiringPiISR2(13, INT_EDGE_RISING, &ISR2, 0); // next pin + int localCounter; + memset(&wfiStatusOld, 0, sizeof(wfiStatusOld)); + + pinMode(IRQpin, INPUT); + pinMode(OUTpin, OUTPUT); + digitalWrite (OUTpin, LOW) ; + + for (int bounce=0; bounce<=1; bounce++) { + unsigned long bouncetime = 0; + if (0==bounce) { + printf("! --- default test (no bounce) --- !\n"); + } else { + bouncetime = 2000; //2 ms + printf("! --- test with bounce on input --- !\n"); + } + + printf("\nTesting IRQ @ GPIO%d with trigger @ GPIO%d rising\n", IRQpin, OUTpin); + wiringPiISR2(IRQpin, INT_EDGE_RISING, &ISR2, bouncetime, &localCounter); + sleep(1); + StartSequence2(INT_EDGE_RISING, OUTpin, IRQpin, bounce, &localCounter); + printf("Stopp IRQ\n"); + wiringPiISRStop(IRQpin); + + printf("\nTesting IRQ @ GPIO%d with trigger @ GPIO%d falling\n", IRQpin, OUTpin); + wiringPiISR2(IRQpin, INT_EDGE_FALLING, &ISR2, bouncetime, &localCounter); + sleep(1); + StartSequence2(INT_EDGE_FALLING, OUTpin, IRQpin, bounce, &localCounter); + printf("Stopp IRQ\n"); + wiringPiISRStop(IRQpin); + + printf("\nTesting IRQ @ GPIO%d with trigger @ GPIO%d both\n", IRQpin, OUTpin); + wiringPiISR2(IRQpin, INT_EDGE_BOTH, &ISR2, bouncetime, &localCounter); + sleep(1); + StartSequence2(INT_EDGE_BOTH, OUTpin, IRQpin, bounce, &localCounter); + printf("Stopp IRQ\n"); + wiringPiISRStop(IRQpin); + } + + printf("Measuring duration IRQ @ GPIO%d with trigger @ GPIO%d rising and falling\n", IRQpin, OUTpin); + for (int bounce=-1; bounce<=5; bounce++) { + DurationTime(INT_EDGE_RISING, OUTpin, IRQpin, bounce); + DurationTime(INT_EDGE_FALLING, OUTpin, IRQpin, bounce); + } + pinMode(OUTpin, INPUT); + + return UnitTestState(); +} diff --git a/wiringPi/test/wiringpi_test62_isr_wpin.c b/wiringPi/test/wiringpi_test62_isr_wpin.c new file mode 100644 index 0000000..6132d21 --- /dev/null +++ b/wiringPi/test/wiringpi_test62_isr_wpin.c @@ -0,0 +1,129 @@ +// WiringPi test program: Kernel char device interface / sysfs successor +// Compile: gcc -Wall wiringpi_test62_isr_wpin.c -o wiringpi_test62_isr_wpin -lwiringPi + +#include "wpi_test.h" +#include +#include +#include +#include + +//WPI pin numbers +int GPIO = 28; +int GPIOIN = 29; + +static volatile int globalCounter; + + +static void wfiup(void) { + + globalCounter++; + printf("I[%d] ", globalCounter); + fflush(stdout); +} + +static void wfidown(void) { + + globalCounter--; + printf("I[%d] ", globalCounter); + fflush(stdout); +} + + +void StartSequence (int Enge, int OUTpin, int count,int expected) { + /* + int expected = up ? count : 0; + globalCounter = up ? 0 : count; + */ + globalCounter = 0; + + printf("Start: "); + fflush(stdout); + for (int loop=0; loop 28\n"); + + printf("\nWiringPi %d.%d\n", major, minor); + + //printf("Error check - next call create fatal error with exit!\n"); + //CheckSame("wiringPiISRStop with wrong pin, result code:", wiringPiISRStop(5), 0); + + CheckSame("wiringPiSetupPinType(WPI_PIN_WPI)", wiringPiSetupPinType(WPI_PIN_WPI), 0); + + int rev, mem, maker, overVolted, RaspberryPiModel; + piBoardId(&RaspberryPiModel, &rev, &mem, &maker, &overVolted); + + CheckNotSame("piBoardId", RaspberryPiModel, 0); + + int _is40pin = piBoard40Pin(); + CheckNotSame("is40pin", _is40pin, -1); + + if (_is40pin==1) { + + int IRQpin = GPIOIN; + int OUTpin = GPIO; + + pinMode(IRQpin, INPUT); + pinMode(OUTpin, OUTPUT); + digitalWrite(OUTpin, LOW); + delayMicroseconds(100); + CheckSame("Input", digitalRead(IRQpin), LOW); + digitalWrite(OUTpin, HIGH); + delayMicroseconds(100); + if (digitalRead(IRQpin)==HIGH) { + digitalWrite(OUTpin, LOW); + delayMicroseconds(100); + + printf("\nTesting IRQ @ WPI-GPIO%d with trigger @ WPI-GPIO%d rising\n", IRQpin, OUTpin); + CheckSame("wiringPiISR", wiringPiISR(IRQpin, INT_EDGE_RISING, &wfiup), 0); + sleep(1); + StartSequence(INT_EDGE_RISING, OUTpin, 3 , 3); + sleep(1); + CheckSame("wiringPiISRStop", wiringPiISRStop(IRQpin), 0); + printf("\n.IRQ off\n"); + sleep(1); + StartSequence(INT_EDGE_RISING, OUTpin, 2, 0); + + printf("\nTesting IRQ @ WPI-GPIO%d with trigger @ WPI-GPIO%d falling\n", IRQpin, OUTpin); + CheckSame("wiringPiISR", wiringPiISR(IRQpin, INT_EDGE_RISING, &wfidown), 0); + sleep(1); + StartSequence(INT_EDGE_FALLING, OUTpin, 4, -4); + sleep(1); + CheckSame("wiringPiISRStop", wiringPiISRStop(IRQpin), 0); + printf("\n.IRQ off\n"); + sleep(1); + StartSequence(INT_EDGE_RISING, OUTpin, 2, 0); + + printf("Error check - next call must be wrong!\n"); + CheckSame("wiringPiISRStop with wrong pin, result code:", wiringPiISRStop(5555), EINVAL); + } else { + printf("Hardware connection for unit test missing!\n"); + printf("unit test, need connection between Wiringpi pin 28 and 29!\n"); + } + } else { + printf("unit test is for 40-pin hardware only!\n"); + } + + return UnitTestState(); +} diff --git a/wiringPi/test/wiringpi_test7_bench.c b/wiringPi/test/wiringpi_test7_bench.c index f3eb6e2..9c0f221 100644 --- a/wiringPi/test/wiringpi_test7_bench.c +++ b/wiringPi/test/wiringpi_test7_bench.c @@ -66,7 +66,7 @@ int main (void) { case PI_MODEL_ZERO_W: //ARM=1000MHz fExpectTimedigitalWrite = 0.104; //us; fExpectTimedigitalRead = 0.135; //us - fExpectTimepinMode = 0.250; //us + fExpectTimepinMode = 0.360; //us break; case PI_MODEL_2: ToggleValue /= 4; diff --git a/wiringPi/test/wiringpi_test9_pwm.c b/wiringPi/test/wiringpi_test9_pwm.c index a5605f5..88775fc 100644 --- a/wiringPi/test/wiringpi_test9_pwm.c +++ b/wiringPi/test/wiringpi_test9_pwm.c @@ -135,7 +135,7 @@ int main (void) { pinMode(PWM, PWM_OUTPUT); //Mode BAL, pwmr=1024, pwmc=32 printf("pwmc 4.8kHz\n"); pwmSetClock(2000); - delay(250); + delay(1000); printf("Register ISR@%d\n", PWM); // INT_EDGE_BOTH, INT_EDGE_FALLING, INT_EDGE_RISING only one ISR per input diff --git a/wiringPi/test/wpi_test.h b/wiringPi/test/wpi_test.h index f2eb81a..1a76480 100644 --- a/wiringPi/test/wpi_test.h +++ b/wiringPi/test/wpi_test.h @@ -94,6 +94,15 @@ void CheckNotSame(const char* msg, int value, int expect) { } } +void CheckBetween(const char* msg, int value, int min, int max) { + if (value>=min && value<=max) { + printf("%39s (% 3d< % 3d <% 3d) -> %spassed%s\n", msg, min, value, max, COLORGRN, COLORDEF); + } else { + printf("%39s (% 3d< % 3d <% 3d) -> %sfailed%s\n", msg, min, value, max, COLORRED, COLORDEF); + globalError=1; + } +} + void CheckSameFloat(const char* msg, float value, float expect, float epsilon) { if (fabs(value-expect)=min && value<=max) { + printf("%39s (%g< %g <%g) -> %spassed%s\n", msg, min, value, max, COLORGRN, COLORDEF); + } else { + printf("%39s (%g< %g <%g) -> %sfailed%s\n", msg, min, value, max, COLORRED, COLORDEF); + globalError=1; + } +} + void CheckSameDouble(const char* msg, double value, double expect, double epsilon) { if (fabs(value-expect) %spassed%s \n", msg, value, expect, COLORGRN, COLORDEF); diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index 7887633..5bbe5b3 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ #include #include #include +#include #include "softPwm.h" #include "softTone.h" @@ -142,7 +144,6 @@ struct wiringPiNodeStruct *wiringPiNodes = NULL ; // maybe faster then piRP1Model #define ISRP1MODEL (PI_MODEL_5==RaspberryPiModel || PI_MODEL_CM5==RaspberryPiModel|| PI_MODEL_500==RaspberryPiModel || PI_MODEL_CM5L==RaspberryPiModel) - //RP1 chip (@Pi5) RIO address const unsigned int RP1_RIO_OUT = 0x0000; const unsigned int RP1_RIO_OE = (0x0004/4); @@ -453,6 +454,15 @@ int wiringPiReturnCodes = FALSE ; int wiringPiTryGpioMem = FALSE ; +enum WPIFlag { + WPI_FLAG_INPUT = 0x04, + WPI_FLAG_OUTPUT = 0x08, + WPI_FLAG_BIAS_UP = 0x100, + WPI_FLAG_BIAS_DOWN= 0x200, + WPI_FLAG_BIAS_OFF = 0x400, +}; + + static unsigned int lineFlags [64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -477,11 +487,16 @@ static int isrFds [64] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, } ; + + // ISR Data static int chipFd = -1; +static void* isrUserdata[64]; +static void (*isrFunctionsV2[64])(struct WPIWfiStatus, void* userdata) ; static void (*isrFunctions [64])(void) ; static pthread_t isrThreads[64]; -static int isrMode[64]; +static int isrEdgeMode[64]; // irq on rising/falling edge +static unsigned long isrDebouncePeriodUs[64]; // 0: debounce is off // Doing it the Arduino way with lookup tables... // Yes, it's probably more innefficient than all the bit-twidling, but it @@ -631,6 +646,7 @@ int piBoard40Pin() { } } + int piRP1Model() { switch(RaspberryPiModel){ case PI_MODEL_5: @@ -643,8 +659,43 @@ int piRP1Model() { } } + int GetMaxPin() { - return piRP1Model() ? 27 : 63; + if (piRP1Model()) { + switch(wiringPiMode) { + case WPI_MODE_PHYS: + return 40; + case WPI_MODE_PINS: + return 31; + default: + return 27; + } + } else { + return 63; + } +} + + +int ToBCMPin(int* pin) { + if (*pin<0 || *pin>63) { + return FALSE; + } + switch(wiringPiMode) { + case WPI_MODE_PINS: + *pin = pinToGpio[*pin]; + break; + case WPI_MODE_PHYS: + *pin = physToGpio[*pin]; + break; + case WPI_MODE_GPIO: + return TRUE; + default: + return FALSE; + } + if (piRP1Model() && *pin>27) { + return FALSE; + } + return TRUE; } @@ -1166,37 +1217,37 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) // Fill out the replys as appropriate RaspberryPiLayout = GPIO_LAYOUT_DEFAULT ; //default - /**/ if (strcmp (c, "0002") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; RaspberryPiLayout = GPIO_LAYOUT_PI1_REV1; } - else if (strcmp (c, "0003") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; RaspberryPiLayout = GPIO_LAYOUT_PI1_REV1; } + if (strcmp (c, "0002") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; RaspberryPiLayout = GPIO_LAYOUT_PI1_REV1; } + else if (strcmp (c, "0003") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; RaspberryPiLayout = GPIO_LAYOUT_PI1_REV1; } - else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; ; } - else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0010") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0016") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0019") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0010") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0016") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0019") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0017") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "001a") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0017") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "001a") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0018") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "001b") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0018") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "001b") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } + else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } } RaspberryPiModel = *model; @@ -1271,8 +1322,9 @@ int physPinToGpio (int physPin) ********************************************************************************* */ void setPadDrivePin (int pin, int value) { - if (!piRP1Model()) return; - if (pin < 0 || pin > GetMaxPin()) return ; + if (!piRP1Model() || !ToBCMPin(&pin)) { + return; + } uint32_t wrVal; value = value & 3; // 0-3 supported @@ -1353,14 +1405,9 @@ int getAlt (int pin) { int alt; - pin &= 63 ; - - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return 0 ; + if (!ToBCMPin(&pin)) { + return 0; + } if (piRP1Model()) { alt = (gpio[2*pin+1] & RP1_FSEL_NONE_HW); //0-4 function @@ -1571,14 +1618,9 @@ void gpioClockSet (int pin, int freq) int divi, divr, divf ; FailOnModel5("gpioClockSet"); - pin &= 63 ; - - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; + if (!ToBCMPin(&pin)) { + return; + } divi = 19200000 / freq ; divr = 19200000 % freq ; @@ -1622,15 +1664,13 @@ struct wiringPiNodeStruct *wiringPiFindNode (int pin) ********************************************************************************* */ -static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } -static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } -//static unsigned int digitalRead8Dummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return 0 ; } -//static void digitalWrite8Dummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } -static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } -static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } +static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } +static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } +static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } +static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) { @@ -1657,9 +1697,7 @@ struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) node->pinMode = pinModeDummy ; node->pullUpDnControl = pullUpDnControlDummy ; node->digitalRead = digitalReadDummy ; -//node->digitalRead8 = digitalRead8Dummy ; node->digitalWrite = digitalWriteDummy ; -//node->digitalWrite8 = digitalWrite8Dummy ; node->pwmWrite = pwmWriteDummy ; node->analogRead = analogReadDummy ; node->analogWrite = analogWriteDummy ; @@ -1753,11 +1791,15 @@ void releaseLine(int pin) { lineFlags[pin] = 0; close(lineFds[pin]); lineFds[pin] = -1; + isrDebouncePeriodUs[pin] = 0; } -int requestLine(int pin, unsigned int lineRequestFlags) { - struct gpiohandle_request rq; +int requestLineV2(int pin, const unsigned int lineRequestFlags) { + struct gpio_v2_line_request req; + struct gpio_v2_line_config config; + int ret; + if (lineFds[pin]>=0) { if (lineRequestFlags == lineFlags[pin]) { //already requested @@ -1772,19 +1814,44 @@ int requestLine(int pin, unsigned int lineRequestFlags) { if (wiringPiGpioDeviceGetFd()<0) { return -1; // error } - rq.lineoffsets[0] = pin; - rq.lines = 1; - rq.flags = lineRequestFlags; - int ret = ioctl(chipFd, GPIO_GET_LINEHANDLE_IOCTL, &rq); - if (ret || rq.fd<0) { - ReportDeviceError("get line handle", pin, "RequestLine", ret); + + memset(&req, 0, sizeof(req)); + memset(&config, 0, sizeof(config)); + if (lineRequestFlags & WPI_FLAG_INPUT) { + config.flags |= GPIO_V2_LINE_FLAG_INPUT; + } + if (lineRequestFlags & WPI_FLAG_OUTPUT) { + config.flags |= GPIO_V2_LINE_FLAG_OUTPUT; + } + if (lineRequestFlags & WPI_FLAG_BIAS_OFF) { + config.flags |= GPIO_V2_LINE_FLAG_BIAS_DISABLED; + } + if (lineRequestFlags & WPI_FLAG_BIAS_UP) { + config.flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP; + } + if (lineRequestFlags & WPI_FLAG_BIAS_DOWN) { + config.flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN; + } + if (wiringPiDebug) { + printf ("requestLine flags v2: %llu\n", config.flags); + } + strcpy(req.consumer, "wiringpi_gpio_req"); + + req.offsets[0] = pin; + req.num_lines = 1; + req.config = config; + + ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req); + + if (ret || req.fd<0) { + ReportDeviceError("get line handle v2", pin, "RequestLine", ret); return -1; // error } lineFlags[pin] = lineRequestFlags; - lineFds[pin] = rq.fd; + lineFds[pin] = req.fd; if (wiringPiDebug) - printf ("requestLine succeeded: pin:%d, flags: %u, fd :%d\n", pin, lineRequestFlags, lineFds[pin]) ; + printf ("requestLine succeeded: pin:%d, flags: 0x%u, fd :%d\n", pin, lineRequestFlags, lineFds[pin]) ; return lineFds[pin]; } @@ -1804,65 +1871,58 @@ void pinModeAlt (int pin, int mode) { setupCheck ("pinModeAlt") ; - if ((pin & PI_GPIO_MASK) == 0) // On-board pin - { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - if (piRP1Model()) { - //confusion! diffrent to to BCM! this is taking directly the value for the register - int modeRP1; - switch(mode) { - case FSEL_ALT0: - modeRP1 = 0; - break; - case FSEL_ALT1: - modeRP1 = 1; - break; - case FSEL_ALT2: - modeRP1 = 2; - break; - case FSEL_ALT3: - modeRP1 = 3; - break; - case FSEL_ALT4: - modeRP1 = 4; - break; - case FSEL_ALT5: - modeRP1 = 5; - break; - case FSEL_ALT6: - modeRP1 = 6; - break; - case FSEL_ALT7: - modeRP1 = 7; - break; - case FSEL_ALT8: - modeRP1 = 8; - break; - case FSEL_OUTP: - case FSEL_INPT: - modeRP1 = RP1_FSEL_GPIO; - break; - default: - fprintf(stderr, "pinModeAlt: invalid mode %d\n", mode); - return; - } - //printf("pinModeAlt: Pi5 alt pin %d to %d\n", pin, modeRP1); - gpio[2*pin+1] = (modeRP1 & RP1_FSEL_NONE_HW) | RP1_DEBOUNCE_DEFAULT; //0-4 function, 5-11 debounce time - } else { - int fSel = gpioToGPFSEL [pin] ; - int shift = gpioToShift [pin] ; - - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ; - } - + if (!ToBCMPin(&pin)) { + return; } -} + + if (piRP1Model()) { + //confusion! diffrent to to BCM! this is taking directly the value for the register + int modeRP1; + switch(mode) { + case FSEL_ALT0: + modeRP1 = 0; + break; + case FSEL_ALT1: + modeRP1 = 1; + break; + case FSEL_ALT2: + modeRP1 = 2; + break; + case FSEL_ALT3: + modeRP1 = 3; + break; + case FSEL_ALT4: + modeRP1 = 4; + break; + case FSEL_ALT5: + modeRP1 = 5; + break; + case FSEL_ALT6: + modeRP1 = 6; + break; + case FSEL_ALT7: + modeRP1 = 7; + break; + case FSEL_ALT8: + modeRP1 = 8; + break; + case FSEL_OUTP: + case FSEL_INPT: + modeRP1 = RP1_FSEL_GPIO; + break; + default: + fprintf(stderr, "pinModeAlt: invalid mode %d\n", mode); + return; + } + //printf("pinModeAlt: Pi5 alt pin %d to %d\n", pin, modeRP1); + gpio[2*pin+1] = (modeRP1 & RP1_FSEL_NONE_HW) | RP1_DEBOUNCE_DEFAULT; //0-4 function, 5-11 debounce time + } else { + int fSel = gpioToGPFSEL [pin] ; + int shift = gpioToShift [pin] ; + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ; + } + } /* @@ -1877,21 +1937,21 @@ void rp1_set_pad(int pin, int slewfast, int schmitt, int pulldown, int pullup, i pads[1+pin] = (slewfast != 0) | ((schmitt != 0) << 1) | ((pulldown != 0) << 2) | ((pullup != 0) << 3) | ((drive & 0x3) << 4) | ((inputenable != 0) << 6) | ((outputdisable != 0) << 7); } -void pinModeFlagsDevice (int pin, int mode, unsigned int flags) { +void pinModeFlagsDevice (int pin, int mode, const unsigned int flags) { unsigned int lflag = flags; - if (wiringPiDebug) + if (wiringPiDebug) { printf ("pinModeFlagsDevice: pin:%d mode:%d, flags: %u\n", pin, mode, flags) ; - - lflag &= ~(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_OUTPUT); + } + lflag &= ~(WPI_FLAG_INPUT | WPI_FLAG_OUTPUT); switch(mode) { default: fprintf(stderr, "pinMode: invalid mode request (only input und output supported)\n"); return; case INPUT: - lflag |= GPIOHANDLE_REQUEST_INPUT; + lflag |= WPI_FLAG_INPUT; break; case OUTPUT: - lflag |= GPIOHANDLE_REQUEST_OUTPUT; + lflag |= WPI_FLAG_OUTPUT; break; case PM_OFF: pinModeFlagsDevice(pin, INPUT, 0); @@ -1899,7 +1959,7 @@ void pinModeFlagsDevice (int pin, int mode, unsigned int flags) { return; } - requestLine(pin, lflag); + requestLineV2(pin, lflag); } void pinModeDevice (int pin, int mode) { @@ -2057,20 +2117,20 @@ void pinMode (int pin, int mode) */ void pullUpDnControlDevice (int pin, int pud) { unsigned int flag = lineFlags[pin]; - unsigned int biasflags = GPIOHANDLE_REQUEST_BIAS_DISABLE | GPIOHANDLE_REQUEST_BIAS_PULL_UP | GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; + unsigned int biasflags = WPI_FLAG_BIAS_OFF | WPI_FLAG_BIAS_UP | WPI_FLAG_BIAS_DOWN; flag &= ~biasflags; switch (pud){ - case PUD_OFF: flag |= GPIOHANDLE_REQUEST_BIAS_DISABLE; break; - case PUD_UP: flag |= GPIOHANDLE_REQUEST_BIAS_PULL_UP; break; - case PUD_DOWN: flag |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; break; + case PUD_OFF: flag |= WPI_FLAG_BIAS_OFF; break; + case PUD_UP: flag |= WPI_FLAG_BIAS_UP; break; + case PUD_DOWN: flag |= WPI_FLAG_BIAS_DOWN; break; default: return ; /* An illegal value */ } // reset input/output - if (lineFlags[pin] & GPIOHANDLE_REQUEST_OUTPUT) { + if (lineFlags[pin] & WPI_FLAG_OUTPUT) { pinModeFlagsDevice (pin, OUTPUT, flag); - } else if(lineFlags[pin] & GPIOHANDLE_REQUEST_INPUT) { + } else if(lineFlags[pin] & WPI_FLAG_INPUT) { pinModeFlagsDevice (pin, INPUT, flag); } else { lineFlags[pin] = flag; // only store for later @@ -2154,7 +2214,33 @@ void pullUpDnControl (int pin, int pud) } } +/* + helper functions for gpio_v2_line_values bits +*/ +static inline void gpiotools_set_bit(__u64 *b, int n) +{ + *b |= _BITULL(n); +} +static inline void gpiotools_clear_bit(__u64 *b, int n) +{ + *b &= ~_BITULL(n); +} + +static inline void gpiotools_assign_bit(__u64 *b, int n, bool value) +{ + if (value) + gpiotools_set_bit(b, n); + else + gpiotools_clear_bit(b, n); +} + +static inline int gpiotools_test_bit(__u64 b, int n) +{ + return !!(b & _BITULL(n)); +} + +//********************************************* /* @@ -2163,20 +2249,24 @@ void pullUpDnControl (int pin, int pud) ********************************************************************************* */ -int digitalReadDevice (int pin) { // INPUT and OUTPUT should work - - if (lineFds[pin]<0) { +int digitalReadDeviceV2(int pin) { // INPUT and OUTPUT should work + struct gpio_v2_line_values lv; + int ret; + + if (lineFds[pin]<0) { // line not requested - auto request on first read as input - pinModeDevice(pin, INPUT); + pinModeDevice(pin, INPUT); } + lv.mask = 0; + lv.bits = 0; if (lineFds[pin]>=0) { - struct gpiohandle_data data; - int ret = ioctl(lineFds[pin], GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); + gpiotools_set_bit(&lv.mask, 0); + ret = ioctl(lineFds[pin], GPIO_V2_LINE_GET_VALUES_IOCTL, &lv); if (ret) { ReportDeviceError("get line values", pin, "digitalRead", ret); return LOW; // error } - return data.values[0]; + return gpiotools_test_bit(lv.bits, 0); } return LOW; // error , need to request line before } @@ -2199,11 +2289,11 @@ int digitalRead (int pin) pin = physToGpio [pin]; break; case WPI_MODE_GPIO_DEVICE_BCM: - return digitalReadDevice(pin); + return digitalReadDeviceV2(pin); case WPI_MODE_GPIO_DEVICE_WPI: - return digitalReadDevice(pinToGpio[pin]); + return digitalReadDeviceV2(pinToGpio[pin]); case WPI_MODE_GPIO_DEVICE_PHYS: - return digitalReadDevice(physToGpio[pin]); + return digitalReadDeviceV2(physToGpio[pin]); case WPI_MODE_GPIO: break; } @@ -2230,58 +2320,42 @@ int digitalRead (int pin) } -/* - * digitalRead8: - * Read 8-bits (a byte) from given start pin. - ********************************************************************************* - -unsigned int digitalRead8 (int pin) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - return 0 ; - else - { - if ((node = wiringPiFindNode (pin)) == NULL) - return LOW ; - return node->digitalRead8 (node, pin) ; - } -} - */ - - /* * digitalWrite: * Set an output bit ********************************************************************************* */ -void digitalWriteDevice (int pin, int value) { - +void digitalWriteDeviceV2(int pin, int value) { + int ret; + struct gpio_v2_line_values values; + if (wiringPiDebug) - printf ("digitalWriteDevice: ioctl pin:%d value: %d\n", pin, value) ; + printf ("digitalWriteDeviceV2: ioctl pin:%d value: %d\n", pin, value) ; if (lineFds[pin]<0) { // line not requested - auto request on first write as output pinModeDevice(pin, OUTPUT); } - if (lineFds[pin]>=0 && (lineFlags[pin] & GPIOHANDLE_REQUEST_OUTPUT)>0) { - struct gpiohandle_data data; - data.values[0] = value; - if (wiringPiDebug) - printf ("digitalWriteDevice: ioctl pin:%d cmd: GPIOHANDLE_SET_LINE_VALUES_IOCTL, value: %d\n", pin, value) ; - int ret = ioctl(lineFds[pin], GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); - if (ret) { - ReportDeviceError("set line values", pin, "digitalWrite", ret); - return; // error + + if (lineFds[pin]>=0 && (lineFlags[pin] & GPIO_V2_LINE_FLAG_OUTPUT)>0) { + values.mask = 0; + values.bits = 0; + gpiotools_set_bit(&values.mask, 0); + gpiotools_assign_bit(&values.bits, 0, !!value); + + ret = ioctl(lineFds[pin], GPIO_V2_LINE_SET_VALUES_IOCTL, &values); + if (ret == -1) { + ReportDeviceError("digitalWriteDeviceV2", pin, "GPIO_V2_LINE_SET_VALUES_IOCTL", ret); + return; // error } } else { - fprintf(stderr, "digitalWrite: no output (%d)\n", lineFlags[pin]); + fprintf(stderr, "digitalWriteDeviceV2: no output (%d)\n", lineFlags[pin]); } return; // error } + void digitalWrite (int pin, int value) { struct wiringPiNodeStruct *node = wiringPiNodes ; @@ -2299,13 +2373,13 @@ void digitalWrite (int pin, int value) pin = physToGpio [pin]; break; case WPI_MODE_GPIO_DEVICE_BCM: - digitalWriteDevice(pin, value); + digitalWriteDeviceV2(pin, value); return; case WPI_MODE_GPIO_DEVICE_WPI: - digitalWriteDevice(pinToGpio[pin], value); + digitalWriteDeviceV2(pinToGpio[pin], value); return; case WPI_MODE_GPIO_DEVICE_PHYS: - digitalWriteDevice(physToGpio[pin], value); + digitalWriteDeviceV2(physToGpio[pin], value); return; case WPI_MODE_GPIO: break; @@ -2334,32 +2408,6 @@ void digitalWrite (int pin, int value) } -/* - * digitalWrite8: - * Set an output 8-bit byte on the device from the given pin number - ********************************************************************************* - -void digitalWrite8 (int pin, int value) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - return ; - else - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->digitalWrite8 (node, pin, value) ; - } -} - */ - - -/* - * pwmWrite: - * Set an output PWM value - ********************************************************************************* - */ - void pwmWrite (int pin, int value) { struct wiringPiNodeStruct *node = wiringPiNodes ; @@ -2368,12 +2416,9 @@ void pwmWrite (int pin, int value) if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; + if (!ToBCMPin(&pin)) { + return; + } /* would be possible on ms mode but not on bal, deactivated, use pwmc modify instead if (piGpioBase == GPIO_PERI_BASE_2711) { @@ -2579,144 +2624,232 @@ unsigned int digitalReadByte2 (void) } + /* - * waitForInterrupt: - * Pi Specific. - * Wait for Interrupt on a GPIO pin. - * This is actually done via the /dev/gpiochip interface regardless of - * the wiringPi access mode in-use. Maybe sometime it might get a better - * way for a bit more efficiency. + * waitForInterrupt2: + * Wait for Interrupt on a GPIO pin and use v2 of the character device API, need Kernel 5.1 + * Returns struct WPIWfiStatus ********************************************************************************* */ -int waitForInterrupt (int pin, int mS) +struct WPIWfiStatus waitForInterrupt2(int pin, int edgeMode, int ms, unsigned long debounce_period_us) // ms < 0 wait infinite, = 0 return immediately, > 0 wait timeout { - int fd, ret; + int ret; + int fd, attr, status, readret; struct pollfd polls ; - struct gpioevent_data evdata; - //struct gpio_v2_line_request req2; - - if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - - if ((fd = isrFds [pin]) == -1) - return -2 ; - - // Setup poll structure - polls.fd = fd; - polls.events = POLLIN | POLLERR ; - polls.revents = 0; - - // Wait for it ... - ret = poll(&polls, 1, mS); - if (ret <= 0) { - fprintf(stderr, "wiringPi: ERROR: poll returned=%d\n", ret); - } else { - //if (polls.revents & POLLIN) - if (wiringPiDebug) { - printf ("wiringPi: IRQ line %d received %d, fd=%d\n", pin, ret, isrFds[pin]) ; - } - /* read event data */ - int readret = read(isrFds [pin], &evdata, sizeof(evdata)); - if (readret == sizeof(evdata)) { - if (wiringPiDebug) { - printf ("wiringPi: IRQ data id: %d, timestamp: %lld\n", evdata.id, evdata.timestamp) ; - } - ret = evdata.id; - } else { - ret = 0; - } - } - return ret; -} - -int waitForInterruptInit (int pin, int mode) -{ + struct gpio_v2_line_event evdata; + struct gpio_v2_line_config config; + struct gpio_v2_line_request req; const char* strmode = ""; - - if (wiringPiMode == WPI_MODE_PINS) { - pin = pinToGpio [pin] ; - } else if (wiringPiMode == WPI_MODE_PHYS) { - pin = physToGpio [pin] ; - } - + struct WPIWfiStatus wfiStatus; + + memset(&wfiStatus, 0, sizeof(wfiStatus)); /* open gpio */ - sleep(1); - if (wiringPiGpioDeviceGetFd()<0) { - return -1; + if (wiringPiGpioDeviceGetFd()<0 || !ToBCMPin(&pin)) { + wfiStatus.statusOK = -1; + return wfiStatus; } - - struct gpioevent_request req; - req.lineoffset = pin; - req.handleflags = GPIOHANDLE_REQUEST_INPUT; - switch(mode) { + + memset(&req, 0, sizeof(req)); + memset(&config, 0, sizeof(config)); + + /* setup config */ + config.flags = GPIO_V2_LINE_FLAG_INPUT; + + switch(edgeMode) { default: case INT_EDGE_SETUP: if (wiringPiDebug) { - printf ("wiringPi: waitForInterruptMode mode INT_EDGE_SETUP - exiting\n") ; + printf ("waitForInterrupt2: edgeMode INT_EDGE_SETUP - exiting\n") ; } - return -1; + wfiStatus.statusOK = -1; + return wfiStatus; case INT_EDGE_FALLING: - req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; + config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; strmode = "falling"; break; case INT_EDGE_RISING: - req.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; + config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING; strmode = "rising"; break; case INT_EDGE_BOTH: - req.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; + config.flags |= (GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING); strmode = "both"; break; } - strncpy(req.consumer_label, "wiringpi_gpio_irq", sizeof(req.consumer_label) - 1); - - //later implement GPIO_V2_GET_LINE_IOCTL req2 - int ret = ioctl(chipFd, GPIO_GET_LINEEVENT_IOCTL, &req); - if (ret) { - ReportDeviceError("get line event", pin , strmode, ret); - return -1; + strcpy(req.consumer, "wiringpi_gpio_irq"); + + if (debounce_period_us) { + attr = config.num_attrs; + config.num_attrs++; + gpiotools_set_bit(&config.attrs[attr].mask, 0); + config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; + config.attrs[attr].attr.debounce_period_us = debounce_period_us; } + + req.num_lines = 1; + req.offsets[0] = pin; + req.event_buffer_size = 32; + req.config = config; + + status = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req); + if (status == -1) { + ReportDeviceError("GPIO_V2_GET_LINE_IOCTL", pin , strmode, status); + wfiStatus.statusOK = -1; + return wfiStatus; + } + if (wiringPiDebug) { - printf ("wiringPi: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; + printf ("waitForInterrupt2: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; } - - /* set event fd nonbloack read */ - int fd_line = req.fd; - isrFds [pin] = fd_line; - int flags = fcntl(fd_line, F_GETFL); + + fd = req.fd; + isrFds [pin] = fd; + isrDebouncePeriodUs[pin] = debounce_period_us; + +/* set event fd nonbloack read */ + /* + int flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; - ret = fcntl(fd_line, F_SETFL, flags); - if (ret) { - fprintf(stderr, "wiringPi: ERROR: fcntl set nonblock return=%d\n", ret); + status = fcntl(fd, F_SETFL, flags); + if (status) { + fprintf(stderr, "wiringPi: ERROR: fcntl set nonblock return=%d\n", status); return -1; } +*/ - return 0; + // Setup poll structure + polls.fd = fd; + polls.events = POLLIN | POLLPRI; + polls.revents = 0; + + ret = poll(&polls, 1, ms); + if (ret < 0) { + if (wiringPiDebug) { + fprintf(stderr, "waitForInterrupt2: ERROR: poll returned=%d\n", ret); + } + wfiStatus.statusOK = -1; + } else if (ret == 0) { + if (wiringPiDebug) { + fprintf(stderr, "waitForInterrupt2: timeout: poll returned zero\n"); + } + wfiStatus.statusOK = 0; // timeout + } + else { + if (wiringPiDebug) { + printf ("waitForInterrupt2: IRQ line %d received %d, fd=%d\n", pin, ret, isrFds[pin]); + } + if (polls.revents & POLLIN) { + /* read event data */ + readret = read(isrFds [pin], &evdata, sizeof(evdata)); + if (readret == sizeof(evdata)) { + if (wiringPiDebug) { + printf ("waitForInterrupt2: IRQ at PIN: %d, timestamp: %lld\n", evdata.offset, evdata.timestamp_ns) ; + } + switch (evdata.id) { + case GPIO_V2_LINE_EVENT_RISING_EDGE: + wfiStatus.edge = INT_EDGE_RISING; + if (wiringPiDebug) printf("waitForInterrupV2: rising edge\n"); + break; + case GPIO_V2_LINE_EVENT_FALLING_EDGE: + wfiStatus.edge = INT_EDGE_FALLING; + if (wiringPiDebug) printf("waitForInterrupt2: falling edge\n"); + break; + default: + wfiStatus.edge = INT_EDGE_SETUP; // edge = 0 + if (wiringPiDebug) printf("waitForInterrupt2: unknown event\n"); + break; + } + wfiStatus.timeStamp_us = evdata.timestamp_ns / 1000LL; // nanoseconds u64 to microseconds + wfiStatus.pinBCM = evdata.offset; + wfiStatus.statusOK = 1; + } + else { + wfiStatus.statusOK = -1; + } + } + else { + wfiStatus.statusOK = -1; + } + } + + if (isrFds[pin] > 0) { + close(isrFds [pin]); // release line + isrFds [pin] = -1; + isrDebouncePeriodUs[pin] = 0; + } + + return wfiStatus; } +int waitForInterrupt (int pin, int ms) { + struct WPIWfiStatus status; -int waitForInterruptClose (int pin) { - if (isrFds[pin]>0) { - if (wiringPiDebug) { - printf ("wiringPi: waitForInterruptClose close thread 0x%lX\n", (unsigned long)isrThreads[pin]) ; - } - if (pthread_cancel(isrThreads[pin]) == 0) { - if (wiringPiDebug) { - printf ("wiringPi: waitForInterruptClose thread canceled successfuly\n") ; - } - } else { - if (wiringPiDebug) { - fprintf (stderr, "wiringPi: waitForInterruptClose could not cancel thread\n"); + int edgeMode = isrEdgeMode[pin]; + if (edgeMode==0) { + fprintf(stderr, "waitForInterrupt: ERROR: edge mode missing, legacy function, please use waitForInterrupt2!\n"); + return -1; + } + status = waitForInterrupt2(pin, edgeMode, ms, 0); + + return status.statusOK; +} + +/* + * wiringPiISRStop: + * stop interruptHandler thread and + * wait untill stopped. + * close isrFds[pin], reset isrFds[pin], isrFunction[pin] and isrDebouncePeriodUs[pin] + * + ********************************************************************************* + */ + +int wiringPiISRStop(int pin) { + + if (wiringPiMode == WPI_MODE_UNINITIALISED) { + return wiringPiFailure(WPI_FATAL, "wiringPiISRStop: wiringPi has not been initialised. Unable to continue.\n"); + } + if (!ToBCMPin(&pin)) { + fprintf(stderr, "wiringPiISRStop: wrong pin %d (mode: %d) number!\n", pin, wiringPiMode); + return EINVAL; + } + if (wiringPiDebug) { + printf("wiringPiISRStop: pin %d\n", pin) ; + } + + if (isrFds[pin] > 0) { + void *res; + + if (wiringPiDebug) + printf("wiringPiISRStop: close thread 0x%lX\n", (unsigned long)isrThreads[pin]); + + if (isrThreads[pin] != 0) { + if (pthread_cancel(isrThreads[pin]) == 0) { + pthread_join(isrThreads[pin], &res); + if (res == PTHREAD_CANCELED) { + if (wiringPiDebug) + printf("wiringPiISRStop: thread was canceled\n"); + } + else { + if (wiringPiDebug) + printf("wiringPiISRStop: thread was not canceled\n"); + } + } else { + if (wiringPiDebug) + printf("wiringPiISRStop: could not cancel thread\n"); } } close(isrFds [pin]); + } else { + if (wiringPiDebug) + printf("wiringPiISRStop: Warning stop isr, but its not active\n"); } isrFds [pin] = -1; - isrFunctions [pin] = NULL; - + isrFunctions[pin] = NULL; + isrFunctionsV2[pin] = NULL; + isrUserdata[pin] = NULL;; + isrDebouncePeriodUs[pin] = 0; + /* -not closing so far - other isr may be using it - only close if no other is using - will code later if (chipFd>0) { close(chipFd); @@ -2724,53 +2857,187 @@ int waitForInterruptClose (int pin) { chipFd = -1; */ if (wiringPiDebug) { - printf ("wiringPi: waitForInterruptClose finished\n") ; + printf("wiringPiISRStop: wiringPiISRStop finished\n"); } return 0; } - -int wiringPiISRStop (int pin) { - return waitForInterruptClose (pin); +int waitForInterruptClose(int pin) { + return wiringPiISRStop(pin); } /* - * interruptHandler: + * 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 *interruptHandler (UNU void *arg) +void *interruptHandlerV2(void *arg) { - int pin ; + const char* strmode = ""; + int pin, EdgeMode, ret, fd, attr, i; + unsigned int readret; + unsigned long debounce_period_us; + struct pollfd polls ; + 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; + } + + 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) { + default: + case INT_EDGE_SETUP: + if (wiringPiDebug) { + printf ("interruptHandlerV2: waitForInterruptMode edge mode INT_EDGE_SETUP - exiting\n") ; + } + return NULL; + case INT_EDGE_FALLING: + config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; + strmode = "falling"; + break; + case INT_EDGE_RISING: + config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING; + strmode = "rising"; + break; + case INT_EDGE_BOTH: + config.flags |= (GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING); + strmode = "both"; + break; + } + strcpy(req.consumer, "wiringpi_gpio_irq"); + + if (debounce_period_us) { + attr = config.num_attrs; + config.num_attrs++; + gpiotools_set_bit(&config.attrs[attr].mask, 0); + config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; + config.attrs[attr].attr.debounce_period_us = debounce_period_us; + } + + req.num_lines = 1; + req.event_buffer_size = 45; + req.offsets[0] = pin; + req.config = config; + + ret = ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req); + if (ret == -1) { + ReportDeviceError("interruptHandlerV2: get line event", pin , strmode, ret); + return NULL; + } + + if (wiringPiDebug) + printf ("interruptHandlerV2: GPIO get line %d , mode %s succeded, fd=%d\n", pin, strmode, req.fd) ; + + /* set event fd */ + fd = req.fd; + isrFds [pin] = fd; + (void)piHiPri (55) ; // Only effective if we run as root - pin = pinPass ; - pinPass = -1 ; + for (;;) { // check if event data is available, check if interruptHandlerV2 thread must be canceled - for (;;) { - int ret = waitForInterrupt(pin, -1); - if ( ret> 0) { - if (wiringPiDebug) { - printf ("wiringPi: call function\n") ; - } - if(isrFunctions [pin]) { - isrFunctions [pin] () ; - } - // wait again - in the past forever - now can be stopped by waitForInterruptClose - } else if( ret< 0) { - break; // stop thread! + // Setup poll structure + 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) + printf("interruptHandlerV2: ERROR: poll returned=%d\n", ret); + pthread_exit(NULL); + return NULL; // never landing here + } 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) { + /* read event data */ + readret = read(fd, &evdat, sizeof(evdat)); + if (readret >= sizeof(evdat[0])) { + if (wiringPiDebug) + printf ("interruptHandlerV2: IRQ at PIN: %d, events: %u\n", evdat[0].offset, readret/(unsigned int)sizeof(evdat[0])) ; + + ret = readret/sizeof(evdat[0]); // number of events read from fd + for (i = 0; i < ret; ++i) { + if (isrFunctionsV2[pin]) { + 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; + switch (evdat[i].id) { + case GPIO_V2_LINE_EVENT_RISING_EDGE: + wfiStatus.edge = INT_EDGE_RISING; + if (wiringPiDebug) + printf("waitForInterrupt2: rising edge\n"); + break; + case GPIO_V2_LINE_EVENT_FALLING_EDGE: + wfiStatus.edge = INT_EDGE_FALLING; + if (wiringPiDebug) + printf("waitForInterrupt2: falling edge\n"); + break; + default: + wfiStatus.edge = INT_EDGE_SETUP; // edge = 0 + if (wiringPiDebug) + printf("waitForInterrupt2: unknown event\n"); + break; + } + wfiStatus.timeStamp_us = evdat[i].timestamp_ns/1000LL; + if (wiringPiDebug) { + printf( "interruptHandlerV2: call isr function\n"); + } + isrFunctionsV2[pin](wfiStatus, isrUserdata[pin]); + if (wiringPiDebug) { + printf( "interruptHandlerV2: return from isr function\n"); + } + } + if (isrFunctions[pin]) { + if (wiringPiDebug) { + printf( "interruptHandlerV2: call isr function classic\n"); + } + isrFunctions[pin](); + if (wiringPiDebug) { + printf( "interruptHandlerV2: return from isr function classic\n"); + } + } + } + } + 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); + return NULL; // never landing here + } + } } } - - waitForInterruptClose (pin); - if (wiringPiDebug) { - printf ("wiringPi: interruptHandler finished\n") ; - } - return NULL ; } @@ -2779,46 +3046,51 @@ static void *interruptHandler (UNU void *arg) * Pi Specific. * Take the details and create an interrupt handler that will do a call- * back to the user supplied function. + * debounce_period_us in microseconds ********************************************************************************* */ -int wiringPiISR (int pin, int mode, void (*function)(void)) +int wiringPiISRInternal(int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus, void* userdata), void (*functionClassic)(void), unsigned long debounce_period_us, void* userdata) { - const int maxpin = GetMaxPin(); - - if (pin < 0 || pin > maxpin) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-%d (%d)\n", maxpin, pin) ; - if (wiringPiMode == WPI_MODE_UNINITIALISED) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; - if (wiringPiDebug) { - printf ("wiringPi: wiringPiISR pin %d, mode %d\n", pin, mode) ; + if (wiringPiMode == WPI_MODE_UNINITIALISED) { + return wiringPiFailure(WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n"); } - if (isrFunctions [pin]) { - printf ("wiringPi: ISR function alread active, ignoring \n") ; + if (!ToBCMPin(&pin)) { + fprintf(stderr, "wiringPiISRStop: wrong pin %d (mode: %d) number!\n", pin, wiringPiMode); + return EINVAL; + } + if (wiringPiDebug) { + printf("wiringPi: wiringPiISR pin %d, edgeMode %d\n", pin, edgeMode); + } + if (isrFunctions[pin] || isrFunctionsV2[pin]) { + fprintf(stderr, "wiringPi: ISR function already active, ignoring \n"); } - isrFunctions [pin] = function ; - isrMode[pin] = mode; - if(waitForInterruptInit (pin, mode)<0) { - if (wiringPiDebug) { - fprintf (stderr, "wiringPi: waitForInterruptInit failed\n") ; - } - }; - + isrFunctionsV2[pin] = function; + isrUserdata[pin] = userdata; + isrFunctions[pin] = functionClassic; + isrEdgeMode[pin] = edgeMode; + isrDebouncePeriodUs[pin] = debounce_period_us; + if (wiringPiDebug) { - printf ("wiringPi: mutex in\n") ; + 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]); } - if (pthread_create (&isrThreads[pin], NULL, interruptHandler, NULL)==0) { + if (pthread_create (&isrThreads[pin], NULL, interruptHandlerV2, &pin)==0) { if (wiringPiDebug) { printf("wiringPi: pthread_create successed, 0x%lX\n", (unsigned long)isrThreads[pin]); } - while (pinPass != -1) - delay (1) ; +/* while (pinPass != -1) + delay (1) ; */ + // wait so that interruptHandler is up und running. + // when interruptHandler is running, the calling function wiringPiISR + // must be still alive, otherwise the thread argument &pin points into nirwana, + // when it is picked up from interruptHandler. + delay (10); } else { if (wiringPiDebug) { printf("wiringPi: pthread_create failed\n"); @@ -2826,16 +3098,25 @@ int wiringPiISR (int pin, int mode, void (*function)(void)) } if (wiringPiDebug) { - printf ("wiringPi: mutex out\n") ; + printf("wiringPi: mutex out\n"); } pthread_mutex_unlock (&pinMutex) ; if (wiringPiDebug) { - printf ("wiringPi: wiringPiISR finished\n") ; + printf("wiringPi: wiringPiISR finished\n"); } return 0 ; } +int wiringPiISR (int pin, int mode, void (*function)(void)) +{ + return wiringPiISRInternal(pin, mode, NULL, function, 0, NULL); +} + +int wiringPiISR2(int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus, void* userdata), unsigned long debounce_period_us, void* userdata) +{ + return wiringPiISRInternal(pin, edgeMode, function, NULL, debounce_period_us, userdata); +} /* * initialiseEpoch: @@ -2868,12 +3149,12 @@ static void initialiseEpoch (void) ********************************************************************************* */ -void delay (unsigned int howLong) +void delay (unsigned int ms) { struct timespec sleeper, dummy ; - sleeper.tv_sec = (time_t)(howLong / 1000) ; - sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; + sleeper.tv_sec = (time_t)(ms / 1000) ; + sleeper.tv_nsec = (long)(ms % 1000) * 1000000 ; nanosleep (&sleeper, &dummy) ; } @@ -2897,29 +3178,29 @@ void delay (unsigned int howLong) ********************************************************************************* */ -void delayMicrosecondsHard (unsigned int howLong) +void delayMicrosecondsHard (unsigned int us) { struct timeval tNow, tLong, tEnd ; gettimeofday (&tNow, NULL) ; - tLong.tv_sec = howLong / 1000000 ; - tLong.tv_usec = howLong % 1000000 ; + tLong.tv_sec = us / 1000000 ; + tLong.tv_usec = us % 1000000 ; timeradd (&tNow, &tLong, &tEnd) ; while (timercmp (&tNow, &tEnd, <)) gettimeofday (&tNow, NULL) ; } -void delayMicroseconds (unsigned int howLong) +void delayMicroseconds (unsigned int us) { struct timespec sleeper ; - unsigned int uSecs = howLong % 1000000 ; - unsigned int wSecs = howLong / 1000000 ; + unsigned int uSecs = us % 1000000 ; + unsigned int wSecs = us / 1000000 ; - /**/ if (howLong == 0) + if (us == 0) return ; - else if (howLong < 100) - delayMicrosecondsHard (howLong) ; + else if (us < 100) + delayMicrosecondsHard (us) ; else { sleeper.tv_sec = wSecs ; @@ -3168,14 +3449,14 @@ int wiringPiSetup (void) else wiringPiMode = WPI_MODE_PINS ; - /**/ if (piGpioLayout () == GPIO_LAYOUT_PI1_REV1) // A, B, Rev 1, 1.1 + if (piGpioLayout () == GPIO_LAYOUT_PI1_REV1) // A, B, Rev 1, 1.1 { - pinToGpio = pinToGpioR1 ; + pinToGpio = pinToGpioR1 ; physToGpio = physToGpioR1 ; } else // A2, B2, A+, B+, CM, Pi2, Pi3, Zero, Zero W, Zero 2 W { - pinToGpio = pinToGpioR2 ; + pinToGpio = pinToGpioR2 ; physToGpio = physToGpioR2 ; } @@ -3184,7 +3465,7 @@ int wiringPiSetup (void) // Try /dev/mem. If that fails, then // try /dev/gpiomem. If that fails then game over. - const char* gpiomemGlobal = gpiomem_global; + const char* gpiomemGlobal = gpiomem_global; const char* gpiomemModule = gpiomem_BCM; if (piRP1Model()) { @@ -3225,7 +3506,7 @@ int wiringPiSetup (void) printf ("wiringPi: access to %s succeded %d\n", usingGpioMem ? gpiomemModule : gpiomemGlobal, fd) ; } // GPIO: - if (!piRP1Model()) { + if (!piRP1Model()) { //Set the offsets into the memory interface. GPIO_PADS = piGpioBase + 0x00100000 ; diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index f2a4599..aa3c753 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -144,6 +144,7 @@ extern const char *piRevisionNames [16] ; extern const char *piMakerNames [16] ; extern const int piMemorySize [ 8] ; + // Intended for the GPIO program Use at your own risk. // Threads @@ -175,15 +176,13 @@ struct wiringPiNodeStruct unsigned int data2 ; // ditto unsigned int data3 ; // ditto - void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; - void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; - int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; -//unsigned int (*digitalRead8) (struct wiringPiNodeStruct *node, int pin) ; - void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; -// void (*digitalWrite8) (struct wiringPiNodeStruct *node, int pin, int value) ; - void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; - int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; - void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; + void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; + void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; + int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; + void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; + void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; + int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; + void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; struct wiringPiNodeStruct *next ; } ; @@ -254,18 +253,16 @@ enum WPIPinAlt { }; -extern int wiringPiGpioDeviceGetFd(); //Interface V3.3 -extern void pinModeAlt (int pin, int mode) ; -extern enum WPIPinAlt getPinModeAlt (int pin) ; // Interface V3.5, same as getAlt but wie enum -extern void pinMode (int pin, int mode) ; -extern void pullUpDnControl (int pin, int pud) ; -extern int digitalRead (int pin) ; -extern void digitalWrite (int pin, int value) ; -extern unsigned int digitalRead8 (int pin) ; -extern void digitalWrite8 (int pin, int value) ; -extern void pwmWrite (int pin, int value) ; -extern int analogRead (int pin) ; -extern void analogWrite (int pin, int value) ; +extern int wiringPiGpioDeviceGetFd(); //Interface V3.3 +extern void pinModeAlt (int pin, int mode) ; +extern enum WPIPinAlt getPinModeAlt (int pin) ; // Interface V3.5, same as getAlt but wie enum +extern void pinMode (int pin, int mode) ; +extern void pullUpDnControl (int pin, int pud) ; +extern int digitalRead (int pin) ; +extern void digitalWrite (int pin, int value) ; +extern void pwmWrite (int pin, int value) ; +extern int analogRead (int pin) ; +extern void analogWrite (int pin, int value) ; // PiFace specifics // (Deprecated) @@ -280,8 +277,8 @@ extern int piBoardRev (void) ; // Deprecated, but does the sa extern void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) ; extern int piBoard40Pin (void) ; // Interface V3.7 extern int piRP1Model (void) ; // Interface V3.14 -extern int wpiPinToGpio (int wpiPin) ; -extern int physPinToGpio (int physPin) ; +extern int wpiPinToGpio (int wpiPin) ; // please don't use outside 0-63 and on RP1 +extern int physPinToGpio (int physPin) ; // please don't use outside 0-63 and on RP1 extern void setPadDrive (int group, int value) ; extern void setPadDrivePin (int pin, int value); // Interface V3.0 extern int getAlt (int pin) ; @@ -296,12 +293,20 @@ extern void digitalWriteByte (int value) ; extern void digitalWriteByte2 (int value) ; // Interrupts -// (Also Pi hardware specific) +// status returned from waitForInterruptV2 V3.16 +struct WPIWfiStatus { + int statusOK; // -1: error (return of 'poll' command), 0: timeout, 1: irq processed, next data values are valid if needed + unsigned int pinBCM; // gpio as BCM pin + int edge; // INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds +}; -extern int waitForInterrupt (int pin, int mS) ; +//extern int waitForInterrupt (int pin, int ms); unknown if still working, disabled for V3.16, please contact developer via github extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; +extern struct WPIWfiStatus waitForInterrupt2(int pin, int edgeMode, int ms, unsigned long debounce_period_us) ; // V3.16 +extern int wiringPiISR2 (int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus, void* userdata), unsigned long debounce_period_us, void* userdata) ; // V3.16 extern int wiringPiISRStop (int pin) ; //V3.2 -extern int waitForInterruptClose(int pin) ; //V3.2 +extern int waitForInterruptClose(int pin) ; //V3.2 legacy use wiringPiISRStop // Threads @@ -315,8 +320,8 @@ extern int piHiPri (const int pri) ; // Extras from arduino land -extern void delay (unsigned int howLong) ; -extern void delayMicroseconds (unsigned int howLong) ; +extern void delay (unsigned int ms) ; +extern void delayMicroseconds (unsigned int us) ; extern unsigned int millis (void) ; extern unsigned int micros (void) ; diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 4657b38..581a079 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -1,7 +1,7 @@ /* * wiringPiSPI.c: * Simplified SPI access routines - * Copyright (c) 2012-2015 Gordon Henderson + * Copyright (c) 2012-2025 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ @@ -195,6 +195,11 @@ int wiringPiSPISetupMode (int channel, int speed, int mode) { ********************************************************************************* */ +int wiringPiSPIxSetup (const int number, const int channel, const int speed) { + return wiringPiSPIxSetupMode(number, channel, speed, 0) ; +} + + int wiringPiSPISetup (int channel, int speed) { return wiringPiSPIxSetupMode(0, channel, speed, 0) ; } diff --git a/wiringPi/wiringPiSPI.h b/wiringPi/wiringPiSPI.h index cd1bc03..d60b064 100644 --- a/wiringPi/wiringPiSPI.h +++ b/wiringPi/wiringPiSPI.h @@ -1,7 +1,7 @@ /* * wiringPiSPI.h: * Simplified SPI access routines - * Copyright (c) 2012-2024 Gordon Henderson and contributors + * Copyright (c) 2012-2025 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPiD/runRemote.c b/wiringPiD/runRemote.c index 7c6a5cb..d00ddf2 100644 --- a/wiringPiD/runRemote.c +++ b/wiringPiD/runRemote.c @@ -92,7 +92,6 @@ void runRemoteCommands (int fd) break ; case DRCN_DIGITAL_WRITE8: - //digitalWrite8 (pin, cmd.data) ; if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) return ; break ; @@ -104,7 +103,6 @@ void runRemoteCommands (int fd) break ; case DRCN_DIGITAL_READ8: - //cmd.data = digitalRead8 (pin) ; if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) return ; break ;