9

I wrote a char device driver and am now writing a QT "wrapper" which part of it is to get a signal to fire when the device becomes readable via the poll mechanism. I had tried to do:

QFile file("/dev/testDriver");
if(file.open(QFile::ReadOnly)) {
  QSocketNotifier sn(file.handle(), , QSocketNotifier::Read);
  sn.setEnabled(true);
  connect(&sn, SIGNAL(activated(int)), &this, SLOT(readyRead()));
}

But readyRead was never called and my driver never reported having its poll method called.

I was able to get the following code to work so I know my driver is working

QFile file("/dev/testDriver");
if(file.open(QFile::ReadOnly)) {
    struct pollfd fd;
    fd.fd = file.handle();
    fd.events = POLLIN;

    struct pollfd fds[] = {fd};
    int ready;
    qDebug() << "Started poll";
    ready = poll(fds, 1, -1);
    qDebug() << "Poll returned: " << ready;

    QTextStream in(&file);
    QTextStream out(stdout);
    out << in.readAll();
}

This properly waits for my driver to call wake_up and I can see two poll calls from my driver. One for the initial poll registration and one for when the wake_up happens.

Doing it this way I would probably have to spawn a separate thread which all it did was poll on this device and throw a signal and loop.

Is it possible to use QSocketNotifier in this way? The documentation of QFile::handle() seems to indicate it should be.

casperOne
  • 73,706
  • 19
  • 184
  • 253
jjcf89
  • 468
  • 1
  • 5
  • 13
  • Did you ever get this working? I wrote something similar, but I couldn't get `file->read(buf, 1)` to work. It would just hang. However, `read(file->handle(), buf, 1)` worked just fine. – Harvey Feb 19 '12 at 01:59
  • @Harvey Yes the answer I checked worked for me. Turned out to be a simple coding error. Also check out my answer to see if it helps you. – jjcf89 Mar 16 '12 at 00:31
  • To revise my earlier comment, it was a misunderstanding on my part of how the device driver worked. Both pieces of code worked, it just happened that my other factors caused the entire test to fail when I was using one of them causing me to make the erroneous connection. – Harvey Mar 24 '12 at 07:25

2 Answers2

16

I'll also mention that QSocketNotifier can be used to watch stdin using the following

#include "ConsoleReader.h"
#include <QTextStream>

#include <unistd.h> //Provides STDIN_FILENO

ConsoleReader::ConsoleReader(QObject *parent) :
    QObject(parent),
    notifier(STDIN_FILENO, QSocketNotifier::Read)
{
    connect(&notifier, SIGNAL(activated(int)), this, SLOT(text()));
}

void ConsoleReader::text()
{
    QTextStream qin(stdin);
    QString line = qin.readLine();
    emit textReceived(line);
}

---Header

#pragma once

#include <QObject>
#include <QSocketNotifier>

class ConsoleReader : public QObject
{
    Q_OBJECT
public:
    explicit ConsoleReader(QObject *parent = 0);
signals:
    void textReceived(QString message);
public slots:
    void text();
private:
    QSocketNotifier notifier;
};
jjcf89
  • 468
  • 1
  • 5
  • 13
  • Thanks for the elegant way of reading from stdin. However, imo there are two issues: 1. std::getline(std::cin, line); should be used instead of QTextStream. The reason is that QTextStream uses some kind of buffering, which is problematic when text with \n is pasted to the terminal (some of the text will be lost). possibly an QTextStream member would also work. 2. it would be better to create notifier on the heap with ConsoleReader as a parent. This way it'll be moved to a new thread together with ConsoleReader automatically if needed in the future. Remember that stdin is not thread safe. – Adam Feb 04 '17 at 15:32
10

Your QSocketNotifer gets destroyed as soon as that if block ends. It doesn't stand a chance of reporting anything.

You must keep that socket notifier alive as long as you want that file to be monitored. The simplest way of doing that is probably keeping a QSocketNotifer* member in one of your classes.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • Thanks mat. Go figure it could be something so simple. QSocketNotifier works just fine now. – jjcf89 Aug 01 '11 at 12:48
  • 1
    You could add QFile as parent of QSocketNotifier and then when QFile is deleted, so is QSocketNotifier – RDP Jun 30 '16 at 20:04