jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

c++ GPIO interrupt approach

Tue Feb 20, 2018 11:21 pm

I’m looking to integrate GPIO interrupts into my existing c++ Qt application, for a range of square wave inputs. The inputs will be filtered and optocoupled to the RPi 3V3 logic level.

I’m prototyping on the RPi, with the intention of moving towards an industrial embedded Linux platform for the production hardware. As such, I’m looking to use SYSFS directly, rather than one of the available (and outstanding) RPi libraries (WiringPi, pigpio, etc.).

I’ve read extensively on the concept of GPIO interrupts in Linux user space, and understand that there will be a delay in receiving the interrupt in user space from the kernel. I’m not looking to undertake any bare metal coding, as the expected delays are significantly less than the required measurement frequency for my use case (<500Hz per GPIO).

My intention is to setup all the necessary GPIOs in a setup function, so that all GPIOs are exported, and have their direction and edge detection method established prior to the main application starting. This is done partly to keep all GPIO initialisation (for on/off inputs and outputs as well as the square wave inputs) together, and partly to ensure the delay relating to udev rules updating GPIOx/ directory permissions isn’t an issue in the main application. I’ve put together the below code as a start, which iterates through each of the input GPIOs requiring interrupts (using GPIOs 22 and 23 as an example):

Code: Select all

string stringList[] = {“22”, "23"};
string exportDirectory = "/sys/class/gpio/export";
for (uint i(0); i < sizeof(stringList)/sizeof(stringList[0]); i++) {
    //Export pins
    int openExportDirectory = open(exportDirectory.c_str(), O_WRONLY|O_SYNC);
    write(openExportDirectory, stringList[i].c_str(), stringList[i].length());
    close(openExportDirectory);
    //Set pin direction
    string directionDirectory = "/sys/class/gpio/gpio" + stringList[i] +  "/direction";

    int error = -1;
    int openDirectionDirectory = error = open(directionDirectory.c_str(), O_WRONLY|O_SYNC);
    
    while (error < 0) {
        //The udev rules may not have been applied yet, so keep trying to open the directory until permissions have been granted
        int openDirectionDirectory = error = open(directionDirectory.c_str(), O_WRONLY|O_SYNC);
    }

    string direction = "in";
    write(openDirectionDirectory, direction.c_str(), direction.length());
    close(openDirectionDirectory);
    //Enable RISING_EDGE pin interrupts
    string edgeDirectory = "/sys/class/gpio/gpio" + stringList[i] + "/edge";

    error = -1;

    int openEdgeDirectory = error = open(edgeDirectory.c_str(), O_WRONLY|O_SYNC);

    while (error < 0) {
        int openEdgeDirectory = error = open(edgeDirectory.c_str(), O_WRONLY|O_SYNC);
    }

    string edge = "rising";
    write(openEdgeDirectory, edge.c_str(), edge.length());
    close(openEdgeDirectory);
}
The above should work as intended. Where I’m not quite sure, is how I then setup a separate poll for each of the initialised, interrupt-enabled GPIOs. The below was provided on this forum (by joan from memory), which should establish a non-blocking poll for a single GPIO (using 22 as an example):

Code: Select all

char str[256];
struct timeval tv;
struct pollfd pfd;
int fd;
int gpio = 22;
char buf[8];

sprintf(str, "/sys/class/gpio/gpio%d/value", gpio);

pfd.fd = fd;
pfd.events = POLLPRI;

lseek(fd, 0, SEEK_SET);
read(fd, buf, sizeof buf);

poll(&pfd, 1, -1);

lseek(fd, 0, SEEK_SET);
int y = read(fd, buf, sizeof buf);

qDebug() << y;
Can I incorporate this code into my earlier for loop, thereby creating n polls for n initialised GPIOs? If so, would I then create another function to receive the GPIO number of the GPIO whose interrupt has just been caught? Is this a recurring poll, or once the first interrupt has been caught I would then need to re-initialise the poll? The desired end state would be a corresponding timevalue (declared in the header) for each of the initialised GPIOs (e.g. tvGPIO22, tvGPIO23, etc.), which would then be compared to the previous rising edge timevalue in order to calculate the frequency of the GPIO’s input square wave.

Any guidance on this would be greatly appreciated!

Heater
Posts: 10257
Joined: Tue Jul 17, 2012 3:02 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 6:56 am

Even if you get GPIO interrupts working you are going to have a hard time measuring frequency like that. The issue is that Linux is not a real time operating system and your program can have multi-millisecond delays as it gets suspended by the kernel when other tasks run.

Have a look in this thread for a solution to that viewtopic.php?f=33&t=205751

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 7:53 am

Thanks for the link, I hadn't come across that particular one just yet.

I think I'm going to need to trawl through pigpio after all and see how joan's put together his alerts and function callbacks. I'm not opposed to using an external microprocessor for reading the signals, but pigpio seems to offer much higher frequency reading of inputs than I'll ever need, so it's worth a go.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 7:58 am

This appears to be exactly what I'm after (from the pigpio website):
int gpioSetISRFunc(unsigned gpio, unsigned edge, int timeout, gpioISRFunc_t f)
Registers a function to be called (a callback) whenever the specified GPIO interrupt occurs.

gpio: 0-53
edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
timeout: interrupt timeout in milliseconds (<=0 to cancel)
f: the callback function


Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_EDGE, or PI_BAD_ISR_INIT.

One function may be registered per GPIO.

The function is passed the GPIO, the current level, and the current tick. The level will be PI_TIMEOUT if the optional interrupt timeout expires.

Parameter Value Meaning

GPIO 0-53 The GPIO which has changed state

level 0-2 0 = change to low (a falling edge)
1 = change to high (a rising edge)
2 = no level change (interrupt timeout)

tick 32 bit The number of microseconds since boot
WARNING: this wraps around from
4294967295 to 0 roughly every 72 minutes


The underlying Linux sysfs GPIO interface is used to provide the interrupt services.

The first time the function is called, with a non-NULL f, the GPIO is exported, set to be an input, and set to interrupt on the given edge and timeout.

Subsequent calls, with a non-NULL f, can vary one or more of the edge, timeout, or function.

The ISR may be cancelled by passing a NULL f, in which case the GPIO is unexported.

The tick is that read at the time the process was informed of the interrupt. This will be a variable number of microseconds after the interrupt occurred. Typically the latency will be of the order of 50 microseconds. The latency is not guaranteed and will vary with system load.

The level is that read at the time the process was informed of the interrupt, or PI_TIMEOUT if the optional interrupt timeout expired. It may not be the same as the expected edge as interrupts happening in rapid succession may be missed by the kernel (i.e. this mechanism can not be used to capture several interrupts only a few microseconds apart).
I understand that the latency between kernel interrupt and user space interrupt is variable, but for my use case, where the maximum input state change frequency is 500Hz, the proposed pigpio latency is satisfactory. Thoughts?

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 8:18 am

For accuracy you would be better off with http://abyz.me.uk/rpi/pigpio/cif.html#gpioSetAlertFunc

You sacrifice half a millisecond of latency for several orders of magnitude more accuracy. Remember the alerts are timestamped when the GPIO level changes, not when they are first seen by your user process (as would be the case with the ISR call).

Heater
Posts: 10257
Joined: Tue Jul 17, 2012 3:02 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 10:40 am

Latency between interrupt and user space code running is one thing. Having your process sleeping because the kernel has scheduled another task else is something else.

What happens when your process is not running for 5, 10 or more milliseconds and half a dozen state changes happen on the pin during that time?

Does that gpioSetAlertFunc queue up such events and then make multiple calls to the callback function? Or does one just a get a single callback for the first/last pin change that happened while the program is descheduled?

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 11:05 am

Heater wrote:
Wed Feb 21, 2018 10:40 am
Latency between interrupt and user space code running is one thing. Having your process sleeping because the kernel has scheduled another task else is something else.

What happens when your process is not running for 5, 10 or more milliseconds and half a dozen state changes happen on the pin during that time?

Does that gpioSetAlertFunc queue up such events and then make multiple calls to the callback function? Or does one just a get a single callback for the first/last pin change that happened while the program is descheduled?
The samples aren't captured by the user process. They are sampled by the DMA hardware and written to a large cyclic buffer in memory accessible to the user process. The contents of the cyclic buffer are emptied by the user process every millisecond or so. The default cyclic buffer size allows for 120 milliseconds worth of samples. I have never seen a user process starved for that length of time (and frankly there would be other issues with the user experience if that happened).

Heater
Posts: 10257
Joined: Tue Jul 17, 2012 3:02 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 11:21 am

Thanks joan. That all sounds most excellent!

So by default that is about 24000 samples in the DMA buffer then?

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 12:10 pm

Heater wrote:
Wed Feb 21, 2018 11:21 am
Thanks joan. That all sounds most excellent!

So by default that is about 24000 samples in the DMA buffer then?
The default sampling rate is 200 thousand per second (5µs) so 0.12 * 200000, so yes, 24000. The user process only goes through the new samples so typically 200 samples per check. Again typically there would be no changes so no alerts to spit out.

I forgot to clarify, yes all level changes will be propagated, not just the end samples.

Heater
Posts: 10257
Joined: Tue Jul 17, 2012 3:02 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 1:56 pm

Sounds clear enough.

Edge events are first in first out and all is well provided the buffer does not overrun.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 7:50 pm

That all sounds great joan, thank you very much.

To clarify, will I (a newcomer to c/c++) be able to piece together your gpioSetAlertFunc in my application without using pigpio itself? As mentioned in my original post, I'm looking to build a solution which is device agnostic (as much as possible), so would prefer to use the underlying method rather than the library itself.

Heater
Posts: 10257
Joined: Tue Jul 17, 2012 3:02 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 8:38 pm

Check out the pigpio source code from here: https://github.com/joan2937/pigpio

And use whatever you need that is applicable to whatever other platform.

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 9:27 pm

jars121 wrote:
Wed Feb 21, 2018 7:50 pm
That all sounds great joan, thank you very much.

To clarify, will I (a newcomer to c/c++) be able to piece together your gpioSetAlertFunc in my application without using pigpio itself? As mentioned in my original post, I'm looking to build a solution which is device agnostic (as much as possible), so would prefer to use the underlying method rather than the library itself.
Absolutely NOT. gpioSetAlertFunc and alerts are tied in to the specific workings of the Raspberry Pi. For instance it will not work on the Pi clones.

If you want device agnostic (but Linux specific) you would have to use the gpioSetISRFunc function which uses the Linux sysfs I/F to the GPIO.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 10:22 pm

Great, thanks for clarifying joan!

I've spent the last hour or so trawling through your source; the ISR function certainly looks more attainable to me than the dedicated RPi gpioSetAlertFunc (in terms of complexity), so I'm more than happy to use the ISR method.

To confirm my understanding:

int gpioSetISRFunc is where I set the gpio number to be monitored, the edge type to be monitored (rising, falling, etc.), the timeout to be used (if any) and the function to be called when the specified edge is found.

static int intGpioSetISRFunc receives the outputs of gpioSetISRFunc, and passes the inputs to the gpioISR struct (e.g. gpiosISR[gpio].gpio, .edge, .timeout, etc.) for the specified gpio. This function will also check whether the specified gpio has been correctly exported, and its direction set. It will then set the edge (if not already done).

The final function appears to be static void *pthISRThread, which establishes a SYSFS-based, non-blocking poll() on the specified gpio. Once the interrupt occurs, this function then calls the specified function (as supplied to gpioSetISRFunc) with the gpio number, level, tick (timestamp from boot), and any specified userdata as parameters.

The only aspect of this method which I'm not particularly confident with are the DMA components. Could I replace tick with gettimeofday(), and levels with a simple read of the /gpioX/value file? I've traced back systReg and gpioReg through the source but I can't quite see how I'd make that work in my standalone application.

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 10:53 pm

jars121 wrote:
Wed Feb 21, 2018 10:22 pm
...
The only aspect of this method which I'm not particularly confident with are the DMA components. Could I replace tick with gettimeofday(), and levels with a simple read of the /gpioX/value file? I've traced back systReg and gpioReg through the source but I can't quite see how I'd make that work in my standalone application.
That all seems correct.

gettimeofday() should be fine. I don't know if reading the GPIO file will cause a problem if there is another pending report queued by Linux, but I don't see what else you can do. Please be aware that Linux will miss GPIO level changes if they occur in rapid succession (something like 3 within 100 microseconds) as I think it can only have one pending as it reports the first.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Wed Feb 21, 2018 11:06 pm

Ok thanks for the heads up. The highest frequency I expect to measure is around 500Hz, so I'm hoping not to have any issues given a 2000us period.

I'm going to make an attempt at this today and will report back.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Thu Feb 22, 2018 8:17 am

Ok so I've made some progress today.

I've got a function which exports, set the direction and edge of the GPIOs, and a function which unexports the GPIOs.

I've also got the following function which starts a separate thread for each GPIO, in which the SYSFS poll() is run:

Code: Select all

string pulseStringList[] = {"23"};

//Initialise PulseInput threads
for (uint i(0); i < sizeof(pulseStringList)/sizeof(pulseStringList[0]); i++) {
    std::thread t(&GPIOISR::threadedISR, this, pulseStringList[i]);
    t.detach();
}

return 0;
threadedISR() is the container function where the SYSFS poll for each of the GPIOs is held (using GPIO 23 as an example):

Code: Select all


int GPIOISR::threadedISR(string gpio)
{
    int fd;
    int retval;
    timeval gpio23TvOld{0};
    timeval gpio23TvNew{0};
    double usOld;
    double usNew;
    double diff;
    float t = 0;
    struct pollfd pfd;
    char buf[64];
    int errorStatus = -1;

    string openValueDirectory = "/sys/class/gpio/gpio" + gpio + "/value";

    while (errorStatus < 0) {
        errorStatus = fd = open(openValueDirectory.c_str(), O_RDONLY);
    }

    pfd.fd = fd;
    pfd.events = POLLPRI;

    lseek(fd, 0, SEEK_SET);

    while(1) {
        retval = poll(&pfd, 1, -1);
        if (pfd.revents & POLLPRI) {

            lseek(fd, 0, SEEK_SET);

            retval = read(fd, buf, sizeof buf);

            if (gpio23TvOld.tv_sec != 0 && gpio23TvOld.tv_usec != 0) {
                gettimeofday(&gpio23TvNew, NULL);

                usOld = (gpio23TvOld.tv_sec*1e6) + gpio23TvOld.tv_usec;
                usNew = (gpio23TvNew.tv_sec*1e6) + gpio23TvNew.tv_usec;

                diff = (usNew - usOld)/1e6;

                t = 1/diff;

                std::cout << "Frequency: " << t << std::endl;

                gpio23TvOld.tv_sec = gpio23TvNew.tv_sec;
                gpio23TvOld.tv_usec = gpio23TvNew.tv_usec;

            } else {
                gettimeofday(&gpio23TvOld, NULL);
            }
        }
    }

    return 0;
}

The above code works, but the printed frequency is all over the place:

Code: Select all


Frequency: 56.0601
Frequency: 71.7514
Frequency: 31.4941
Frequency: 56.0161
Frequency: 71.7875
Frequency: 31.4485
Frequency: 31.4574
Frequency: 31.4624
Frequency: 31.4832
Frequency: 31.4446
Frequency: 56.057
Frequency: 71.7514
Frequency: 56.013
Frequency: 71.7206
Frequency: 56.0412
Frequency: 71.664
Frequency: 56.0381
Frequency: 71.7412
Frequency: 56.1136
Frequency: 71.8081
Frequency: 56.0821
Frequency: 71.736
Frequency: 31.4367
Frequency: 56.0099
Frequency: 71.7309
Frequency: 31.4891
Frequency: 56.1041
Frequency: 71.7
Frequency: 31.4733
Frequency: 56.0193
Frequency: 71.7154
Frequency: 56.0538
Frequency: 71.7051
Frequency: 56.0224
Frequency: 71.8442
Frequency: 56.035
Frequency: 71.7566
Frequency: 31.4772
Frequency: 56.0758
Frequency: 71.6897
Frequency: 31.4436
Frequency: 31.4614
Frequency: 31.4485
Frequency: 31.502
Frequency: 56.0004
Frequency: 71.6692
Frequency: 56.057
Frequency: 71.7154
Frequency: 56.0224
Frequency: 71.7669
Frequency: 56.057
Frequency: 71.6435
Frequency: 31.502
Frequency: 56.0381
Frequency: 71.7051
Frequency: 56.0538
Frequency: 71.7309
Frequency: 56.0381
Frequency: 71.772
Frequency: 56.0193
Frequency: 71.6025
Frequency: 56.057
Frequency: 71.9114
Frequency: 31.4782
Frequency: 56.0318
Frequency: 71.736
Frequency: 31.4406
Frequency: 55.9973
Frequency: 71.623
Frequency: 56.0412
Frequency: 71.8597
Frequency: 56.0884
Frequency: 71.7309
Frequency: 56.0884
Frequency: 71.8597
Frequency: 56.0161
Frequency: 71.736
Frequency: 56.0758
Frequency: 71.5308
Frequency: 55.7072
Frequency: 71.5768
Frequency: 119.005

The source is a square wave generator circuit I built, which outputs a ~30Hz wave. I haven't yet confirmed the exact frequency on my oscilloscope, but it's certainly more stable than the above results suggest.

So, have I missed something simple in my approach? Are the errors above due to Linux latency issues? Should I rather count the number of pulses in a given time frame, or count a given number of pulses and measure the elapsed time?

Any input would be greatly appreciated!

User avatar
joan
Posts: 13614
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: c++ GPIO interrupt approach

Thu Feb 22, 2018 8:31 am

Try running this module at the same time to see if the results compare.

http://abyz.me.uk/rpi/pigpio/examples.h ... ead_PWM_py

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Thu Feb 22, 2018 8:52 am

I've actually used that file on another project for testing, I'm not sure why I didn't think of that :D

With little surprise, your application is perfect joan!

Code: Select all


f=31.5 pw=17840 dc=56.11
f=31.5 pw=17840 dc=56.20
f=31.5 pw=17855 dc=56.17
f=31.5 pw=17825 dc=56.10
f=31.5 pw=17836 dc=56.11
f=31.5 pw=17830 dc=56.11
f=31.5 pw=17814 dc=56.09
f=31.6 pw=17855 dc=56.42
f=31.5 pw=17840 dc=56.12
f=31.4 pw=17831 dc=56.06
f=31.5 pw=17835 dc=56.13
f=31.5 pw=17840 dc=56.12
f=31.5 pw=17805 dc=56.11
f=31.4 pw=17850 dc=56.12
f=31.5 pw=17841 dc=56.23
f=31.5 pw=17840 dc=56.13
f=31.4 pw=17840 dc=56.08
f=31.5 pw=17840 dc=56.14
f=31.4 pw=17856 dc=56.15
f=31.5 pw=17830 dc=56.12
f=31.5 pw=17850 dc=56.14
f=31.5 pw=17825 dc=56.13
f=31.4 pw=17851 dc=56.14
f=31.5 pw=17830 dc=56.12
f=31.5 pw=17851 dc=56.18
f=31.4 pw=17840 dc=56.10
f=31.5 pw=17835 dc=56.09
f=31.5 pw=17845 dc=56.17
f=31.5 pw=17840 dc=56.22
f=31.4 pw=17845 dc=56.12
f=31.5 pw=17800 dc=56.11
f=31.5 pw=17850 dc=56.15
f=31.4 pw=17850 dc=56.11
f=31.5 pw=17840 dc=56.13
f=31.5 pw=17850 dc=56.16
f=31.5 pw=17835 dc=56.14
f=31.4 pw=17845 dc=56.10
f=31.5 pw=17800 dc=56.12
f=31.5 pw=17845 dc=56.15
f=31.4 pw=17840 dc=56.10
f=31.4 pw=17840 dc=56.09
f=31.5 pw=17845 dc=56.15
f=31.5 pw=17800 dc=56.09
f=31.4 pw=17855 dc=56.11
f=31.5 pw=17835 dc=56.13
f=31.5 pw=17834 dc=56.12
f=31.5 pw=17820 dc=56.07
f=31.4 pw=17845 dc=56.12

I'll go through the python file and determine your approach. Thanks again!

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Thu Feb 22, 2018 10:06 am

I've been through joan's method, and it's not dissimilar to my approach. I can't figure out why the value jitters so much, but I have found something interesting. I changed the edge mode from "rising" to "falling", and received the below results:

Code: Select all

31.4535
31.506
31.4743
31.4545
31.4367
31.4733
31.5
31.4931
31.4911
31.4634
31.4594
31.4634
31.4921
31.502
31.4752
31.4525
31.4832
31.4367
31.5159
31.4842
31.4752
31.4703
31.3607
31.5497
31.4901
31.4971
31.4396
31.4822
31.4762
31.4554
It's been a while since I built the wave generator, so I might have to hook up the oscilloscope to see what's going on. There might be something strange going on with the rising edge, but that wouldn't explain why joan's python module reads the frequency perfectly.

jars121
Posts: 123
Joined: Tue Jun 25, 2013 8:35 pm

Re: c++ GPIO interrupt approach

Sat Feb 24, 2018 5:05 am

Bit of an update. I've had my source connected to the oscilloscope, and there doesn't appear to be any reason why the RISING_EDGE detection shouldn't work given the input signal. I'm happy with the FALLING_EDGE method however, which displays the same calculated frequency as my oscilloscope.

I've moved on now to my non-pulse inputs (simple ON/OFF inputs), which are giving me some issues. I have the below code, which is the same structure as the pulse inputs posted previously:

Code: Select all


    int fd;
    int retval;
    struct pollfd pfd;
    char buf[64];
    int errorStatus = -1;

    string openValueDirectory = "/sys/class/gpio/gpio" + gpio + "/value";

    while (errorStatus < 0) {
        errorStatus = fd = open(openValueDirectory.c_str(), O_RDONLY);
    }

    pfd.fd = fd;
    pfd.events = POLLPRI;

    lseek(fd, 0, SEEK_SET);

    while(1) {
        retval = poll(&pfd, 1, -1);
        if (pfd.events & POLLPRI) {

            lseek(fd, 0, SEEK_SET);

            retval = read(fd, buf, sizeof buf);

            std::cout << "Thread: " << std::this_thread::get_id() << " GPIO: " << gpio << " Value : " << retval << std::endl;
        }
    }

However for some reason, I'm receiving std::cout print outs at all sorts of odd times. For example, if I set the input edge detection to "falling", I'll have 5-6 print outs all at once when I turn the input on (i.e. from 0 to 1), which shouldn't register at all as it's not a falling edge? If I swap to "rising" or even "both", the exact same behaviour occurs. Equally as confusing, the value of retval in the print is always "2". My understanding is that retval should be the value stored in the /sys/class/gpio/gpioX/value file, which can only be a 1 or a 0?

Does anyone know what's going on here?

Return to “C/C++”