How to read HID devices (/dev/hidrawX) with Qt on Linux? - c++

I'm working on a 'RepRap calibration tool' which would use a mouse attached to the printing platform to measure the movement of the platform.
Right now I'm stuck trying to read raw mouse data from /dev/hidrawX, but I'm unable to read any data.
So far I've tried:
First attempt:
QFile f("/dev/hidraw0");
f.readAll();
Reads nothing.
Second attempt:
m_file = new QFile("/dev/hidraw0");
m_sn= new QSocketNotifier(m_file->handle(), QSocketNotifier::Read);
m_sn->setEnabled(true);
connect(m_sn, SIGNAL(activated(int)), this, SLOT(readyRead()));
then on the readyRead SLOT:
qDebug()<<"Ready Read!!"<<m_file.bytesAvailable();
QTextStream d(&m_file);
qDebug()<< d.read(64);
This code fires the readyRead slot once but it gets stuck on the read(64) call, if I comment the read(64) the slot will be fired each time the mouse its moved.
m_file.bytesAvailable() always reports 0.
Which is the right way to read these devices with Qt?
Solution:
I reworked the code like:
bool rcMouseHandler::openHidraw(QString device)
{
int fd =open(device.toLocal8Bit(),O_NONBLOCK);
if(fd <=0)
{
qDebug()<<"[WARN]rcMouseHandler::open-> Cant open!";
return false;
}
m_sn= new QSocketNotifier(fd, QSocketNotifier::Read);
m_sn->setEnabled(true);
connect(m_sn, SIGNAL(activated(int)), this, SLOT(readyRead()));
return true;
}
void rcMouseHandler::readyRead()
{
qDebug()<<"Ready Read!!";
char buffer[4] = {0,0,0,0};
read(m_sn->socket(),&buffer,4);
qDebug()<<(quint8)buffer[0]<<(quint8)buffer[1]<<(quint8)buffer[2]<<(quint8)buffer[3];
}

The right way I suppose here to not use Qt. Why you need portable wrapper above POSIX open and read, when this part of your code is not portable (part that work with /dev/*). Open device with "open" "man 2 open" in O_NONBLOCK and call "read" (man 2 read) to get data from it. And you can still use QSocketNotifier with handle that return "open".

Related

Serial connection does not work correctly with QPushbuttons

void CSerialController::sl_executeCommand(const QString s_command,QString&s_result){
QMutexLocker locker(mpo_mutex);
KT_Error t_error = ERROR_NONE;
QByteArray o_serialOutput;
QString s_serialAnswer = "";
char c_serialLetter = ' ';
// Port is already open
mpo_serial->clearBuffer(); // Flush and ReadAll
t_error = mpo_serial->sendStr(s_command); //
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
while ((t_error == ERROR_NONE) && (c_serialLetter != '\n')) // Reads Serial till newline is found
{
t_error = mpo_serial->getChar(c_serialLetter); // -> checks BytesAvailable -> if no bytes available -> waitForReadyRead(1) <- This is in a Loop while given time is over(Timeouttime)
o_serialOutput.append(c_serialLetter);
}
}
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
s_serialAnswer = o_serialOutput;
s_serialAnswer.remove("\r\n");
}
s_result = s_serialAnswer; }
Im working with C++ and Qt 5.5 and i cant get the serial connection to work correctly. Im using signals to connect a QPushButton with a slot in the CSerialController class which calls this function in the same class. I tried this function with a endless while-loop and it works correctly all the time. Its just not working when i use the buttons. First time i use a button it works correctly but the second time i press a button which calls this slot, the serialport only sometimes returns a value. (Writing works just not reading) I even tried changing the Thread of this class but that didnt help aswell. If you want i can post the sendStr and getChar functions aswell but like i said they work without a problem(allready used in a lot of projects)
UPDATE: I tried using the Windows API for the serial connection = problem is gone. Seems like a problem with QSerialPort usage on an old CPU (I7-870)

QAudioInput::notify() isn't executed while capturing sound from mic

I want to use QAudioInput to capture sound from mic, process it and then play. As I understood, I need to connect to notify signal and inside handler for it user readAll() function to get raw data. But the problem is, this handler function is never executed. Here is my code:
void MainWindow::on_pushButton_clicked()
{
QList<QAudioDeviceInfo> list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
if(list.isEmpty())
{
qDebug() << "No audio input device";
return;
}
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
QAudioFormat format;
// Set up the desired format, for example:
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(32);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
if (!info.isFormatSupported(format)) {
qWarning() << "Default format not supported, trying to use the nearest.";
format = info.nearestFormat(format);
}
qDebug() << "input device :" << info.deviceName();
audio = new QAudioInput(info, format);
qDebug("created()");
connect(audio, SIGNAL(notify()), this, SLOT(onNotify()));
audio->setNotifyInterval(10);
bufferInput = audio->start();
}
void MainWindow::onNotify()
{
qDebug() << "onNotify()";
//QByteArray array = bufferInput->readAll();
//bufferOutput->write(array);
}
(audio is of type QAudioInput* and bufferInput is of type QIODevice*)
and when I click the button, "input device = " and "created()" messages are displayed, but "onNotify()" isn't shown.
What am I doing wrong?
QAudioInput seems quite broken. Or I'm utterly misunderstanding something.
The only thing that worked reliably for me was to use the readyRead() signal of the QIODevice buffer returned by start(). Unfortunately, that isn't fired very often on my system (around every 40 to 60ms on my system).
What I've found is that notify() starts firing when I either call resume() on the QAudioInput (because it's in idle state after calling start()) or do a readAll() on the QIODevice (!). But at least with PyQt this leads to a stack overflow after a minute or so.
I would suspect the platform matters as well, as the actual QAudioInput implementation depends on the platform and audio system used (PulseAudio on Fedora 32 in my case).
Connecting a slot to readyRead signal of QAudioInput and reading from QIODevice with readAll is the correct solution. Why do you think 40 or 60 ms interval is inappropriate? QAudioInput object must capture some audio during this interval and send signal after it.

Qt C++ Console Server, Wait for socket connection & accept input at same time?

I am writing a server as a Qt console application. I have the server set up to wait for a socket connection, but I also need to allow a user to input commands into the server for managing it. Both are working independently. However, the problem I ran into is that when I'm in a while loop accepting and processing input commands, the server doesn't accept connections.
I have a Socket class, and in its constructor, I have:
connect(server,SIGNAL(newConnection()),this, SLOT(newConnection()));
Right under that in the constructor, I call a function that has a more in-depth version of this for getting commands from the user:
QTextStream qin(stdin, QIODevice::ReadOnly);
QString usrCmd;
while(usrCmd != "exit" && usrCmd != "EXIT") {
//Get command input and process here
}
Inside newConnection(), I just accept the next connection and then use the socket.
QTcpSocket *serverSocket = server->nextPendingConnection();
How can I make it so the socket can wait for connections and wait for user-inputed commands at the same time?
Problem with your code is because you are blocking event loop with your while loop. So, the solution to your problem is to read from stdin asynchronously. On Linux (and on Mac, I guess), you can use QSocketNotifier to notify when the data is arrived on stdin, and to read it manually), as per various internet sources.
As I am using Windows, I would suggest you to do it in this way (which should work on all platforms):
Open the thread for reading data from stdin
Once you get some data (perhaps line?) you can use Qt signal-slot mechanism to pass the data to main thread for processing without blocking the event loop.
So, this is the pseudocode. MainAppClass should your existing server class, just edit the constructor to create new thread, and add new slot for processing the data.
class Reader: public QThread
{
Q_OBJECT
public:
Reader(QObject * parent = 0 ): QThread(parent){}
void run(void)
{
forever{
std::string data;
std::getline (std::cin, data);
if(data == "exit")
{
emit exitServer();
return;
}
emit dataReady(QString::fromStdString(data));
}
}
signals:
void dataReady(QString data);
void exitServer();
};
class MainAppClass: public QObject
{
Q_OBJECT
public:
MainAppClass()
{
Reader * tr = new Reader(this);
connect(tr, SIGNAL(dataReady(QString)), this, SLOT(processData(QString)));
connect(tr, SIGNAL(exitServer()), this, SLOT(exitServer()));
tr->start();
}
public slots:
void processData(QString data)
{
std::cout << "Command: " << data.toStdString() << std::endl;
}
void exitServer()
{
std::cout << "Exiting..." << std::endl;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainAppClass myapp; //your server
app.exec();
return 0;
}
Since I wrote simple guidelines how to use QTcpSocket, here is the brief
When you get client QTcpSocket, connect readyRead() signal to some slot, and read data from sender() object. You don't need to read anything in the constructor.
For reading you can use standard QIODevice functions.
Note: this is pseudo code, and you may need to change few things (check the state of the stream on reading, save pointer to sockets in some list, subscribe to disconnected() signal, call listen() in constructor, check if QTcpServer is listening, etc).
So, you need to have slot onReadyRead() in your class which will have the following code:
void Server::readyReadSlot()
{
QTcpSocket *client = (QTcpSocket*)sender(); // get socket which emited the signal
while(client->canReadLine()) // read all lines!
// If there is not any lines received (you may not always receive
// whole line as TCP is stream based protocol),
// you will not leave data in the buffer for later processing.
{
QString line = client->readLine();
processLine(line); // or emit new signal if you like
}
}
Inside newConnection() you need to connect readyRead() signal with your slot.
void Server::newConnection()
{
QTcpSocket *clientSocket = server->nextPendingConnection();
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}

Unable to read correctly from socket

I have a server application which sends some xor encrypted strings. I am reading them from my QT client application. Sometimes, the server is slower and I am not able to receive the entire string. I have tried something like below but it gets stuck ( see the comment below). How can I wait until I have the entire data. I tried bytesAviable() but then again i get stuck (infinite loop)
QTcpSocket * sock = static_cast<QTcpSocket*>(this->sender());
if (key == 0)
{
QString recv(sock->readLine());
key = recv.toInt();
qDebug() << "Cheia este " << key;
char * response = enc_dec("#AUTH|admin|admin",strlen("#AUTH|admin|admin"),key);
sock->write(response);
}
else
{
busy = true;
while (sock->bytesAvailable() > 0)
{
unsigned short word;
sock->read((char*)(&word),2);
qDebug()<<word;
//Sleep(100); if i do this than it works great!
QByteArray bts = sock->read(word);
while (bts.length() < word)
{
char bit; //here get's stuck
if (sock->read(&bit,1) > 0)
bts.append(bit);
sock->flush();
}
char * decodat = enc_dec((char*)bts.data(),bts.length() - 2,key);
qDebug() << decodat;
}
}
I don't know what the meaning of key == 0 is, but you are almost certainly misusing available(), like almost everybody else who has ever called it, including me. It tells you how much data can be read without blocking. It has nothing to do with how much data may eventually be delivered down the connection, and the reason is that there are TCP APIs that can tell you the former, but not the latter. Indeed the latter doesn't have any real meaning, considering that the peer could keep writing from now until Doomsday. You should just block and loop until you have read the amount of data you need for the next piece of work.
I offer you to do the following:
QObject::connect(this->m_TCPSocket, SIGNAL(readyRead()), this, SLOT(processRecivedDatagrams()));
Some explanation:
It is convinient to create a class instance of which will manage network;
One has the member which is pointer on TCPSocket;
In constructor implement connection of signal from socket readyRead() which is emmited when needed data was delivered with SLOT(processRecivedDatagrams()). which is responsible for processing recived datagrams/ in this case it is processRecivedDatagrams(), also implement this slot
Mind that class which manages network has to inherit from QObject and also in its declaration include macrosQ_OBject` for MOC.
update:
i also offer you to store recived data in container like stack or queue this will allow you to synhronize sender and reciver (container in this case acts like buffer)
// SLOT:
void Network::processRecivedDatagrams(void)
{
if (!this->m_flagLocked) // use analog of mutex
{
this->m_flagLocked = true; // lock resource
QByteArray datagram;
do
{
datagram.resize(m_TCPSocket->pendingDatagramSize());
m_TCPSocket->readDatagram(datagram.data(), datagram.size());
}
Qt::String YourString; // actualy I don`t remember how to declare Qt string
while (m_TCPSocket->hasPendingDatagrams());
QDataStream in (&datagram, QIODevice::ReadOnly);
in >> YourString
--numberOfDatagrams;
}
this->m_flagLocked = false; // unlock resource
}
}

using QTextStream to read stdin in a non-blocking fashion

Using Qt, I'm attempting to read the contents of the stdin stream in a non-blocking fashion. I'm using the QSocketNotifier to alert me when the socket has recieved some new data. The setup for the notifier looks like this:
QSocketNotifier *pNot = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read, this);
connect(pNot, SIGNAL(activated(int)), this, SLOT(onData()));
pNot->setEnabled(true);
The onData() slot looks like this:
void CIPCListener::onData()
{
qDebug() << Q_FUNC_INFO;
QTextStream stream(stdin, QIODevice::ReadOnly);
QString str;
forever
{
fd_set stdinfd;
FD_ZERO( &stdinfd );
FD_SET( STDIN_FILENO, &stdinfd );
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int ready = select( 1, &stdinfd, NULL, NULL, &tv );
if( ready > 0 )
{
str += stream.readLine();
}
else
{
break;
}
}
qDebug() << "Recieved data:" << str;
}
As you can see I'm attempting to use the select() system call to tell me when I've run out of data to read. However, in practise what is happening is the select() call returns 0 after I've read the first line of text. So, for example, if I write 5 lines of text to the process's stdin stream, I only ever read the first line.
What could be the problem?
Line buffering.
Default is flushing after a "\n". If you write 5 lines to your process, your slot gets called 5 times. If you want to avoid that, you have to call setbuf(stdin, _IOFBF). But even then it is not guaranteed you can read arbitrarily large amounts of data in one chunk.
Edit: It would probably better to use QTextStream::atEnd() instead of select, since QTextStream has its own internal buffers.
I've found and example in other answer that fits almost to this question and with complete and simple code:
https://stackoverflow.com/a/7389622/721929
I've used it to implement a QT console based app with a textual menu to choose on user selection.