Skip to content

Monitoring Sys Files with QFileSystemWatcher

When the driver turns off the ignition in a vehicle, display computers like terminals in harvesters or infotainment systems in cars should be notified. The display computers should save important data and shut down orderly.

When the display computer runs on Linux, it learns the status of the ignition by monitoring the GPIO for clamp 15. Linux writes the value of the GPIO to a special file in the sys filesystem. On one of my display computers, clamp15 is mapped to the special file /sys/class/gpio/gpio72/value. When the ignition is on, this file contains the string “1”. When off, this file contains “0”. The number of GPIO (here: 72) varies from display computer to display computer.

On the Linux command line, we get the value of clamp 15 with this command:

$ cat /sys/class/gpio/gpio72/value

The command returns “0” when the ignition is off and “1” when it is on.

How can a Qt application monitor the status of the GPIO clamp 15 such that it can shut down orderly when the driver turns off the ignition?

Our first idea most likely is to use QFileSystemWatcher on the file /sys/class/gpio/gpio72/value. QFileSystemWatcher does exactly what we want. When the watched file is modified, QFileSystemWatcher emits the signal fileChanged(const QString &path). We connect a slot to this signal and read the value from the sys file.

// In the constructor of SomeClass
    auto clamp15Monitor = new QFileSystemWatcher{this};
    connect(clamp15Monitor, &QFileSystemWatcher::fileChanged,
            this, &HarvesterServicesImpl::onClamp15FileChanged);

The slot onClamp15FileChanged does nothing else but the command cat /sys/class/gpio/gpio72/value. It reads the value from the sys file and prints it.

void SomeClass::onClamp15FileChanged(const QString &path) 
    QFile clamp15File{filePath};
    if (! {
        qWarning() << "ERROR: Could not open clamp15 file.";
    auto clamp15 = clamp15File.readAll();
    if (!clamp15.isEmpty()) {
        qDebug() << "INFO: clamp15 = " <<;

When we run this code, we are flooded with INFO messages. The messages show the correct value of clamp 15 - many times per second. However, we want to see an INFO message only when the value of clamp 15 changes.

We could give up at this point and set up a QTimer, which calls onClamp15FileChanged() every second. We poll the status of the clamp-15 file once a second. This works, but it wastes many CPU cycles.

Fortunately, we can do better. The file /sys/class/gpio/gpio72/edge comes to our rescue. Section "GPIO and sysfs" (p. 394ff) of John Madieu's book "Linux Device Drivers Development" points us in the right direction.

edge determines the signal edge that will let the poll or select function return. Allowed values are none, rising, falling, or both. This file is readable and writable, and exists only if the pin can be configured as an interrupt-generating input pin.

The system functions poll and select monitor I/O activities on file descriptors. John Madieu explains:

[...] one can call the poll (2) system call on that file [/sys/class/gpio/gpio72/value] and poll (2) will return whenever the interrupt was triggered. Using poll (2) will require setting the [event] POLLPRI [...] If one uses select (2) instead, one should set the file descriptor in exceptfds. After poll (2) returns, either lseek (2) to the beginning of the sysfs file and read the new value or close the file and re-open it to read the value.

In other words: If the Linux kernel (the GPIO device driver, to be exact) sees an edge on a GPIO, it triggers an interrupt. The interrupt writes the changed value into the sysfs file corresponding to the GPIO. poll and select see this activity on the monitored file descriptor and return from blocking. The caller of these system functions can read the contents of the sys file.

As QFileSystemWatcher is implemented with one of these system functions, we should get it working properly. The trick is to configure the GPIO device driver to check for edges on GPIO 72. This isn't the case, as the command

$ cat /sys/class/gpio/gpio72/edge

shows. This explains why QFileSystemWatcher has been misbehaving so far. We configure GPIO 72 to check for "both" edges with the following command:

$ echo "both" > /sys/class/gpio/gpio72/edge

When we run our application now, we will see INFO messages only when the value of /sys/class/gpio/gpio72/value changes. We never see the same value twice in a row. QFileSystemWatcher emits its signal fileChanged only if the driver turns the ignition from "on" to "off" or from "off" to "on".