diff --git a/README.md b/README.md index 794fe4f..425d52b 100644 --- a/README.md +++ b/README.md @@ -119,10 +119,10 @@ 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 @@ -133,14 +133,14 @@ 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 diff --git a/VERSION b/VERSION index 6324d40..5174c53 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.14 +3.16 diff --git a/documentation/deutsch/functions.md b/documentation/deutsch/functions.md index 95bd1ff..3f92674 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.1x.deb . ``` **Debian-Paket installieren:** ```bash -sudo apt install ./wiringpi-3.0-1.deb +sudo apt install ./wiringpi-3.1x.deb ``` **Debian-Paket deinstallieren:** @@ -291,21 +291,33 @@ Registriert eine Interrupt Service Routine (ISR) bzw. Funktion die bei Flankenwe >>> ```C -int wiringPiISR(int pin, int mode, void (*function)(void)); +int wiringPiISR(int pin, int edgeMode, void (*function)(struct WPIWfiStatus wfiStatus), unsigned long bouncetime); ``` -``pin``: Der gewünschte Pin (BCM-, WiringPi- oder Pin-Nummer). -``mode``: Auslösende Flankenmodus +``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer). + +``edgeMode``: Auslösende Flankenmodus - INT_EDGE_RISING ... Steigende Flanke - INT_EDGE_FALLING ... Fallende Flanke - INT_EDGE_BOTH ... Steigende und fallende Flanke -``*function``: Funktionspointer für ISR +``*function``: Funktionspointer für ISR mit Rückgabeparameter struct WPIWfiStatus: +```C +struct WPIWfiStatus { + int status; // -1: error, 0: timeout, 1: valid values for edge and timeStamp_us + unsigned int gpioPin; // gpio as BCM pin + int edge; // One of INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds, when interrupt happened +}; +``` + +``bouncetime``: Entprellzeit in Microsekunden, 0 ms schaltet das Entprellen ab + ``Rückgabewert``: > 0 ... Erfolgreich -Beispiel siehe wiringPiISRStop. +Beispiel siehe waitForInterrupt. ### wiringPiISRStop @@ -323,41 +335,187 @@ int wiringPiISRStop (int pin) -**Beispiel:** - -```C -static volatile int edgeCounter; - -static void isr(void) { - edgeCounter++; -} - -int main (void) { - wiringPiSetupPinType(WPI_PIN_BCM); - edgeCounter = 0; - wiringPiISR (17, INT_EDGE_RISING, &isr); - Sleep(1000); - printf("%d rinsing edges\n", ) - wiringPiISRStop(17) ; -} -``` - - ### waitForInterrupt -Wartet auf einen zuvor definierten Interrupt (wiringPiISR) am GPIO Pin. Diese Funktion sollte nicht verwendet werden. +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 waitForInterrupt (int pin, int edgeMode, int mS, unsigned long bouncetime) ``` -``pin``: Der gewünschte Pin (BCM-, WiringPi- oder Pin-Nummer). +``pin``: Der gewünschte Pin (BCM\-, WiringPi\- oder Pin\-Nummer). + +``edgeMode``: Auslösende Flankenmodus + - INT_EDGE_RISING ... Steigende Flanke + - INT_EDGE_FALLING ... Fallende Flanke + - INT_EDGE_BOTH ... Steigende und fallende Flanke + ``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) + - \-1 warten ohne timeout + - 0 wartet nicht + - 1...n wartet maximal n mS Millisekunden + +``bouncetime``: Entprellzeit in Microsekunden, 0 schaltet Entprellen ab. + +``Rückgabewert``: +```C +struct WPIWfiStatus { + int status; // -1: error, 0: timeout, 1: valid values for edge and timeStamp_us + unsigned int gpioPin; // gpio as BCM pin + int edge; // One of INT_EDGE_FALLING or INT_EDGE_RISING + long long int timeStamp_us; // time stamp in microseconds, when interrupt happened +}; +``` + +**Beispiel:** + +```C +/* + * isr_debounce.c: + * Wait for Interrupt test program WiringPi >=3.16 - ISR 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; + +/* + * myInterrupt: + ********************************************************************************* + */ + +static void wfi (struct WPIWfiStatus wfiStatus) { +// 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 = waitForInterrupt(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 with trigger @ GPIO%d on both edges and bouncetime %d microseconds. Toggle LED @ OUTpin on IRQ.\n\n", IRQpin, IRQpin, BOUNCETIME, OUTpin); + printf("To stop program hit return key\n\n"); + + wiringPiISR (IRQpin, INT_EDGE_BOTH, &wfi, BOUNCETIME) ; + + getc(stdin); + + wiringPiISRStop (IRQpin) ; + pinMode(OUTpin, INPUT); + + return 0 ; +} +``` + +Output auf dem 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 with trigger @ GPIO16 on both edges and bouncetime 3000 microseconds. Toggle LED @ OUTpin 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) 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/gpio/gpio.c b/gpio/gpio.c index 447e53d..8644c4a 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -165,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) { @@ -181,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 } @@ -900,6 +974,10 @@ static void doVersion (char *argv []) } +static void doIs40Pin () +{ + exit(piBoard40Pin() ? EXIT_SUCCESS : EXIT_FAILURE); +} /* * main: @@ -1134,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/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/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/test/Makefile b/wiringPi/test/Makefile index 151a476..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 @@ -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 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..f2e8252 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; } @@ -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 ; @@ -1753,11 +1795,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 +1818,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 +1875,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 +1941,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 +1963,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 +2121,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 +2218,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 +2253,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 +2293,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; } @@ -2257,31 +2351,36 @@ unsigned int digitalRead8 (int pin) ********************************************************************************* */ -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 +2398,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; @@ -2368,12 +2467,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 +2675,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 +2908,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 +3097,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 +3149,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 +3200,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 +3229,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 ; @@ -3170,12 +3502,12 @@ int wiringPiSetup (void) /**/ 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 +3516,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 +3557,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..e9be5a2 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 @@ -280,8 +281,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 +297,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 +324,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) ;