qtfile

Reading from a character device with Qt


I have a char device (let's call it /dev/my_light), which is a light sensor. I have to read the data from this file and transform it to the brightness value, and then pass it to the brightness manager that changes the brightness of my screen.

The problem is that when I read the value for some period of time, I get old values from the file. I assume there is a buffer. Whereas, when I use cat /dev/my_light, I see new data!

Is it possible to get rid of the buffer and read new values that were written to the file just right now.

Here is my code in Qt:

void MySensor::updateMySensor()
{
    Packet packet;
    packet.startByte = 0;
    packet.mantissa = 0;
    packet.exp = 0;

    d->device = ::open(d->path.toStdString().c_str(), O_RDONLY);
    if (d->device == -1)
    {
        qDebug() << Q_FUNC_INFO << "can't open the sensor";
        return;
    }

    ssize_t size = ::read(d->device, &packet, sizeof(packet));
    close(d->device);

    if (size == -1)
    {
        qDebug() << errno;
        return;
    }

    packet.exp &= 0x0F;

    float illumination = pow(2, packet.exp) * packet.mantissa * 0.045;

    if(d->singleShot) emit lightSensorIsRunning(true);
    emit illuminationRead(illumination);
}

The mySensor function is called every second. I tried to call it each 200 msec, but it didn't help. The value of illumination stays old for about 7 seconds(!), whereas the value that I get from cat is new just immediately.


Solution

  • I can't test with your specific device, however, I'm using the keyboard as a read only device.

    The program attempts to connect to keyboard and read all keys pressed inside and outside the window. It's a broad solution you'll have to adapt to meet your demands.

    Note that I'm opening the file with O_RDONLY | O_NONBLOCK which means open in read only mode and no wait for the event be triggered(some notifier needed to know when data is ready!) respectively.

    You'll need super user privilege to run this example!

    #include <QtCore>
    #include <fcntl.h>
    #include <linux/input.h>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        const char *device_name = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
    
        int descriptor = open(device_name, O_RDONLY | O_NONBLOCK);
    
        if (descriptor < 0)
        {
            qDebug() << "Error" << strerror(errno);
            return a.exec();
        }
    
        QFile device;
    
        if (!device.open(descriptor, QFile::ReadOnly))
        {
            qDebug() << "Error" << qPrintable(device.errorString());
            return a.exec();
        }
    
        QSocketNotifier notifier(device.handle(), QSocketNotifier::Read);
    
        QObject::connect(&notifier, &QSocketNotifier::activated, &notifier, [&]{
            struct input_event ev;
    
            QByteArray data = device.readAll();
    
            qDebug() << "Event caught:"
                     << "\n\nDATA SIZE" << data.size()
                     << "\nSTRUCT COUNT" << data.size() / int(sizeof(input_event))
                     << "\nSTRUCT SIZE" << sizeof(input_event);
    
            qDebug() << ""; //New line
    
            while (data.size() >= int(sizeof(input_event)))
            {
                memcpy(&ev, data.data(), sizeof(input_event));
    
                data.remove(0, int(sizeof(input_event)));
    
                qDebug() << "TYPE" << ev.type << "CODE" << ev.code << "VALUE" << ev.value << "TIME" << ev.time.tv_sec;
            }
    
            qDebug() << ""; //New line
        });
    
        return a.exec();
    }