I'm triying to send data from a PSoc via UART to my PC where a want to store data with Qt. The PSoc sends 3 bytes of data. Theses 3 bytes are repeatet with a frequency of 2.5Hz. When I check the signals with my oscilloscope everything is fine. When I receive the data with the software HTerm also everything is as expected. When I use my code written in c++ with Qt I get the problem that not all data are received in Qt, only one third is in the memory. I expected that the signal readyRead is emitted with every new byte? But it seems that the signal is only emitted at the begin of the package of the 3 bytes. Also my qDebug output doesn't react on changes from the PSoc. So when I change values at PSoc the output in qDebug doesn't change.
I already tried reading 3 Bytes (serial->read(3)) and then I first received some single bytes and after a few readings I get the 3 bytes I sended but this is not so reproducible.
connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
serial->setPortName(gui->ui->comboBox->currentData().toString());
serial->setBaudRate(QSerialPort::Baud115200);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
void uart::readData()
{
QByteArray data = serial->read(1);
qDebug() << data;
}
I expect an output like "0x01" "0x02" "0x03" 2.5 times a second, but I get only "0x01"
You are only reading a fixed size with read.
Could it be that you get readyRead signals with varying bytes available but you only read fixed size of them
In your readyRead slot try to read all available bytes.
qint64 available = serial->bytesAvailable();
if (available > 0)
{
QByteArray data = serial->read(available);
qDebug() << data;
}
You can also use readAll() function.
I just found the solution!
You have to set the read-buffer size to the right value.
So for reading a package of three bytes I must set:
serial->setReadBufferSize(3);
Related
In my application, done with Qt5, I would like to set a security system when I download data from internet. First of all, I want to check how many bytes I am downloading and abort if it is the case. I want to set a maximum limit of downloaded bytes, and abort if it is exceeded.
I am using QNetworkReply class.
First of all I checked the size() function, but at that point, I already received all the data (the request is completed), so that is not enough.
Second check, I looked into the signal downloadProgress(qint64 bytesReceived, qint64 bytesTotal). I though, I could check that and abort if bytesReceived are too big. But I am not sure for two motivations: first, as written in the documentation
Note that the values of both bytesReceived and bytesTotal may be different from size(), the total number of bytes obtained through read() or readAll(), or the value of the header(ContentLengthHeader). The reason for that is that there may be protocol overhead or the data may be compressed during the download.
Second, I don't know when I will receive this signal....maybe it will be too late...
Finally, I checked setReadBufferSize(qint64 size). It seems a good solution, but I am not sure about the following two lines in the documentation:
first,
QNetworkReply will try to stop reading from the network once this buffer is full (i.e., bytesAvailable() returns size or more)
What does it mean try? should I rely on that?
second,
Unlike QAbstractSocket::setReadBufferSize(), QNetworkReply cannot guarantee precision in the read buffer size. That is, bytesAvailable() can return more than size.
so, it seems I can not rely on a precise limit to be set.
Someone can suggest me the best way to implement it?
The best solution I found is to use the readyRead signal (QNetworkReply derives from QIODevice), and then implement the security check by myself in a slot:
void onReadyRead()
{
for (;;)
{
QByteArray currentDataRead = httpReply->read(100); // Just read some bytes
if ( currentDataRead.isEmpty() )
return;
myResponseBody.append(currentDataRead);
if (myResponseBody.size() > myMaxResponseSize) // check my limit
{
qDebug() << "Error: response size bigger than expected - aborting";
httpReply->abort();
}
}
}
Note: the inifite for(;;) loop and the check if ( currentDataRead.isEmpty() ) return; are needed in order to not leave some bytes out at the end, because we are inside onReadyRead that is a slot connected to readyRead and from the documentation:
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
--------------------
PS: I am still open to better solutions, possibly native in Qt
I know that TCP guarantees that all packets will arrive. But can a packet be separated into 2 or more? I am using Qt with class QTcpSocket, and I want to know is ReadyRead() signal is emitted only when full packet arrives. Or in other words, is there any sense to send packet size in first bytes and then wait in loop until all bytes had arrived? Or I can just call socket->readAll() and I must get one full packet?
If a large amount of data is sent, the packet can arrive in separate parts. Alternatively, multiple messages can be received in one readyRead slot.
It's good practice to control this by setting the first byte(s) to the number of bytes that will be sent. Then, in readyRead, you read the first bytes and append the data to a buffer until the expected amount of data has been received.
In receiving data, this also means that if multiple messages are received in one call to readyRead(), you can know where the first message ends and the next one begins.
Here's an example of a client that receives data in a readyRead function()
void MyClass::readyRead()
{
// m_pConnection is a QTcpSocket
while(m_pConnection->bytesAvailable())
{
QByteArray buffer;
int dataSize;
m_pConnection->read((char*)&dataSize, sizeof(int));
buffer = m_pConnection->read(dataSize);
while(buffer.size() < dataSize) // only part of the message has been received
{
m_pConnection->waitForReadyRead(); // alternatively, store the buffer and wait for the next readyRead()
buffer.append(m_pConnection->read(dataSize - buffer.size())); // append the remaining bytes of the message
}
QString msg(buffer); // data in this case is JSON, so we can use a QString
emit Log(QString("\tMessage Received: %1").arg(msg));
// Do something with the message
ProcessMessage(msg);
}
}
I want to implement a timeout mechanism such that if the arduino doesn't read the command within one second, it results in a timeout and the new command is discarded and the program runs fine.
But right now, the program hangs if any new command is sent during the execution of the old one.
This is the timeout section of my code:
QByteArray requestData = myRequest.toLocal8Bit();
serial.write(requestData);
if (serial.waitForBytesWritten(waitTime)) {
if (serial.waitForReadyRead(myWaitTimeout)) {
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
emit this->response(response);
} else {
emit timeout(tr("Wait Read Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
} else {
emit timeout(tr("Wait Write Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
The timeout signal is connected to a slot that just prints the timeout message and does nothing.
How can I fix this so that I can achieve what I target?
You are using blocking approach to transmit data via serial port. Unless you are using threads I don't see possibility to send any additional data during execution of previous loop.
BTW: Your program, for example, will block indefinitely if Arduino manages to keep sending something within 10ms periods.
Add couple of QDebug() << "I'm here"; lines to check where your code gets stuck; it is possible that you are blocking somewhere outside code you pasted here. Alternative is to use debugger.
What if previous 'command' you tried to send is still in the buffer ? You'll end up filling output buffer. Check with QDebug how many bytes are in output buffer before writing more data to it. Buffer should be empty. (qint64 QIODevice::bytesToWrite() const).
I know that TCP guarantees that all packets will arrive. But can a packet be separated into 2 or more? I am using Qt with class QTcpSocket, and I want to know is ReadyRead() signal is emitted only when full packet arrives. Or in other words, is there any sense to send packet size in first bytes and then wait in loop until all bytes had arrived? Or I can just call socket->readAll() and I must get one full packet?
If a large amount of data is sent, the packet can arrive in separate parts. Alternatively, multiple messages can be received in one readyRead slot.
It's good practice to control this by setting the first byte(s) to the number of bytes that will be sent. Then, in readyRead, you read the first bytes and append the data to a buffer until the expected amount of data has been received.
In receiving data, this also means that if multiple messages are received in one call to readyRead(), you can know where the first message ends and the next one begins.
Here's an example of a client that receives data in a readyRead function()
void MyClass::readyRead()
{
// m_pConnection is a QTcpSocket
while(m_pConnection->bytesAvailable())
{
QByteArray buffer;
int dataSize;
m_pConnection->read((char*)&dataSize, sizeof(int));
buffer = m_pConnection->read(dataSize);
while(buffer.size() < dataSize) // only part of the message has been received
{
m_pConnection->waitForReadyRead(); // alternatively, store the buffer and wait for the next readyRead()
buffer.append(m_pConnection->read(dataSize - buffer.size())); // append the remaining bytes of the message
}
QString msg(buffer); // data in this case is JSON, so we can use a QString
emit Log(QString("\tMessage Received: %1").arg(msg));
// Do something with the message
ProcessMessage(msg);
}
}
I've got a problem with speed of reading recieved data from serial port. I am using QSerialPort class. I've confgured it right (set the same serial port options as these ones set on transmitter). In MainWindow constructor I've connected signal from QSerialPort to MainWindow's method (readData()) when I'm reading the raw data. It looks like:
MainWindow()
{
std::shared_ptr<QSerialPort> serial; //don't aks me why shared_prt - it has to be shared_ptr, no other option.
serial = std::shared_ptr<QSerialPort>(new QSeralPort)
connect(serial.get(),SIGNAL( readyRead()),this,SLOT(readData()));
}
void MainWindow::readData()
{
QByteArray data = serial->readLine();
qDebug() << data;
}
The data looks like: "s03445\n". Program reads and presents data correctly, but very, very slow (for example it prints "s3445"). Data are send with about 20 Hz frequency (400 samples - after that is one secand pause), but in my program data, are present with frequency about 3-4 Hz. It is also noteworthly that when I connect to my transmitter via simple serial port terminal (Hercules) I recieve data with full speed. What could be reason of that behaviour? What am I doing wrong? Any suggestions?