Sending and receiving multiple serial signals
-
Hi everyone, I have a device connected to a serial port that has a command to send one data point upon request. I'm trying to make several sequential requests while printing the responses to the screen, but when I send more than one request I only get one response.
Here is the serial code:
... connect(&serialPort,SIGNAL(readyRead()),this,SLOT(receiveMessage())); ... void Widget::receiveMessage() { QByteArray data = serialPort.readAll(); QString dataPoint = QString::fromStdString(data.toStdString()); ui->textBrowser->append(dataPoint); } void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); serialPort.write(message.toUtf8()); }
When sending one message, I get one data point printed on my textBrowser, but when I try to write multiple requests like this:
void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); } }
I still get only one data point printed.
I managed to get all 5 points by changing the code to this:void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); serialPort.waitForReadyRead(500); } }
But this blocks my program until all the data is received. Is there a way to get the data without waitForReadyRead? I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
-
Hi everyone, I have a device connected to a serial port that has a command to send one data point upon request. I'm trying to make several sequential requests while printing the responses to the screen, but when I send more than one request I only get one response.
Here is the serial code:
... connect(&serialPort,SIGNAL(readyRead()),this,SLOT(receiveMessage())); ... void Widget::receiveMessage() { QByteArray data = serialPort.readAll(); QString dataPoint = QString::fromStdString(data.toStdString()); ui->textBrowser->append(dataPoint); } void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); serialPort.write(message.toUtf8()); }
When sending one message, I get one data point printed on my textBrowser, but when I try to write multiple requests like this:
void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); } }
I still get only one data point printed.
I managed to get all 5 points by changing the code to this:void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); serialPort.waitForReadyRead(500); } }
But this blocks my program until all the data is received. Is there a way to get the data without waitForReadyRead? I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
@ardmn said in Sending and receiving multiple serial signals:
I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
QSerialPort
can be both. There is a synchronous and asynchronous approach, where the former should be avoided to use in GUI threads for obvious reasons.for (int i = 0; i < 5; i++){
serialPort.write(message.toUtf8());
serialPort.waitForReadyRead(500);
}Here you are mixing both and
serialPort.waitForReadyRead(500)
blocks as you discovered.What does
serialPort.write
return? How many bytes were actually written?message.append("\n");
Depending on your connected device, you sometimes need
CR LF
while sometimes just aLF
is enough, to "confirm" or "close" the current command.
Trymessage.append("\r\n");
Here is the async example of
QSerialPort
-
@ardmn said in Sending and receiving multiple serial signals:
I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
QSerialPort
can be both. There is a synchronous and asynchronous approach, where the former should be avoided to use in GUI threads for obvious reasons.for (int i = 0; i < 5; i++){
serialPort.write(message.toUtf8());
serialPort.waitForReadyRead(500);
}Here you are mixing both and
serialPort.waitForReadyRead(500)
blocks as you discovered.What does
serialPort.write
return? How many bytes were actually written?message.append("\n");
Depending on your connected device, you sometimes need
CR LF
while sometimes just aLF
is enough, to "confirm" or "close" the current command.
Trymessage.append("\r\n");
Here is the async example of
QSerialPort
Hi, thanks for taking your time to answer! I tried your suggestions
What does
serialPort.write
return? How many bytes were actually written?It always returns 7 bytes, even on the for loop, my command is "DATA1".
Depending on your connected device, you sometimes need
CR LF
while sometimes just aLF
is enough, to "confirm" or "close" the current command.
Trymessage.append("\r\n");
Tried it but no luck, still only getting one response on my text box.
Here is the async example of
QSerialPort
Same thing happens when trying with the example code, only one data point gets delivered. I was not using qtimer functions, so maybe it has something to do with that?
-
Hi everyone, I have a device connected to a serial port that has a command to send one data point upon request. I'm trying to make several sequential requests while printing the responses to the screen, but when I send more than one request I only get one response.
Here is the serial code:
... connect(&serialPort,SIGNAL(readyRead()),this,SLOT(receiveMessage())); ... void Widget::receiveMessage() { QByteArray data = serialPort.readAll(); QString dataPoint = QString::fromStdString(data.toStdString()); ui->textBrowser->append(dataPoint); } void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); serialPort.write(message.toUtf8()); }
When sending one message, I get one data point printed on my textBrowser, but when I try to write multiple requests like this:
void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); } }
I still get only one data point printed.
I managed to get all 5 points by changing the code to this:void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); serialPort.waitForReadyRead(500); } }
But this blocks my program until all the data is received. Is there a way to get the data without waitForReadyRead? I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
@ardmn said in Sending and receiving multiple serial signals:
void Widget::receiveMessage()
{
QByteArray data = serialPort.readAll();
QString dataPoint = QString::fromStdString(data.toStdString());
ui->textBrowser->append(dataPoint);
}You might get more than one 'line' here so you have to properly split it up. serial communication is (like socket communication) a stream - there is no 'line' or something else - you have to implement a protocol on top by yourself.
-
@ardmn said in Sending and receiving multiple serial signals:
void Widget::receiveMessage()
{
QByteArray data = serialPort.readAll();
QString dataPoint = QString::fromStdString(data.toStdString());
ui->textBrowser->append(dataPoint);
}You might get more than one 'line' here so you have to properly split it up. serial communication is (like socket communication) a stream - there is no 'line' or something else - you have to implement a protocol on top by yourself.
@Christian-Ehrlicher said in Sending and receiving multiple serial signals:
You might get more than one 'line' here so you have to properly split it up. serial communication is (like socket communication) a stream - there is no 'line' or something else - you have to implement a protocol on top by yourself.
Hi, I'm not exactly sure if this is what you mean but I've tried to make a buffer in the read function like this, the device sends a response that ends with \n
void MainWindow::readData() { byteArray += Serial->readAll(); if(byteArray.contains("\n")){ qDebug() << "received data point" << byteArray; byteArray.clear(); } }
This didn't solve the problem though, the response I get when I loop the QSerialPort.write function is still:
sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" received data point "948302\n"
-
Hi everyone, I have a device connected to a serial port that has a command to send one data point upon request. I'm trying to make several sequential requests while printing the responses to the screen, but when I send more than one request I only get one response.
Here is the serial code:
... connect(&serialPort,SIGNAL(readyRead()),this,SLOT(receiveMessage())); ... void Widget::receiveMessage() { QByteArray data = serialPort.readAll(); QString dataPoint = QString::fromStdString(data.toStdString()); ui->textBrowser->append(dataPoint); } void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); serialPort.write(message.toUtf8()); }
When sending one message, I get one data point printed on my textBrowser, but when I try to write multiple requests like this:
void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); } }
I still get only one data point printed.
I managed to get all 5 points by changing the code to this:void Widget::on_pushButton_clicked() { QString message = ui->lineEdit_2->text(); message.append("\n"); for (int i = 0; i < 5; i++){ serialPort.write(message.toUtf8()); serialPort.waitForReadyRead(500); } }
But this blocks my program until all the data is received. Is there a way to get the data without waitForReadyRead? I thought I'd need to use threads so the program doesn't get blocked, but from what I read, you're not supposed to use threads since QSerialPort is already async.
@ardmn said in Sending and receiving multiple serial signals:
serialPort.waitForReadyRead(500);
I still don't understand what you want to read here...
-
@Christian-Ehrlicher said in Sending and receiving multiple serial signals:
You might get more than one 'line' here so you have to properly split it up. serial communication is (like socket communication) a stream - there is no 'line' or something else - you have to implement a protocol on top by yourself.
Hi, I'm not exactly sure if this is what you mean but I've tried to make a buffer in the read function like this, the device sends a response that ends with \n
void MainWindow::readData() { byteArray += Serial->readAll(); if(byteArray.contains("\n")){ qDebug() << "received data point" << byteArray; byteArray.clear(); } }
This didn't solve the problem though, the response I get when I loop the QSerialPort.write function is still:
sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" sent command: "DATA1" received data point "948302\n"
@ardmn said in Sending and receiving multiple serial signals:
byteArray.clear();
If there is more than one response read into the buffer you will lose it. Only remove up to first
\n
for one response leaving rest in buffer, do it in loop (or call again) for multiple messages. I'm not saying you're necessarily in this state, but make code correct/robust. -
@ardmn said in Sending and receiving multiple serial signals:
serialPort.waitForReadyRead(500);
I still don't understand what you want to read here...
@Christian-Ehrlicher said in Sending and receiving multiple serial signals:
I still don't understand what you want to read here...
Sorry, I'm not that experienced in qt or serial communication, I'll try to explain the problem better.
My device is listening for the "DATA1" command, this command returns a data point, which for testing purposes is just a random six digit number plus a newline operator on the end. What I want to do is write, for example, 5 messages containing the "DATA1" command and receive 5 data points, but with the code I have I can only ever get one response containing one data point, no matter how many I write. I'm also not sure why waitForReadyRead works, I was just testing the wait commands to see if anything different would happen.So my question is: Is this kind of repeated writing and receiving possible? I'm trying to find examples but all of them either only read a stream from the device and never send anything, or only send one thing and get one response.
@JonB said in Sending and receiving multiple serial signals:
@ardmn said in Sending and receiving multiple serial signals:
byteArray.clear();
If there is more than one response read into the buffer you will lose it. Only remove up to first
\n
for one response leaving rest in buffer, do it in loop (or call again) for multiple messages. I'm not saying you're necessarily in this state, but make code correct/robust.Ty for the heads up, I will correct the code.
-
@Christian-Ehrlicher said in Sending and receiving multiple serial signals:
I still don't understand what you want to read here...
Sorry, I'm not that experienced in qt or serial communication, I'll try to explain the problem better.
My device is listening for the "DATA1" command, this command returns a data point, which for testing purposes is just a random six digit number plus a newline operator on the end. What I want to do is write, for example, 5 messages containing the "DATA1" command and receive 5 data points, but with the code I have I can only ever get one response containing one data point, no matter how many I write. I'm also not sure why waitForReadyRead works, I was just testing the wait commands to see if anything different would happen.So my question is: Is this kind of repeated writing and receiving possible? I'm trying to find examples but all of them either only read a stream from the device and never send anything, or only send one thing and get one response.
@JonB said in Sending and receiving multiple serial signals:
@ardmn said in Sending and receiving multiple serial signals:
byteArray.clear();
If there is more than one response read into the buffer you will lose it. Only remove up to first
\n
for one response leaving rest in buffer, do it in loop (or call again) for multiple messages. I'm not saying you're necessarily in this state, but make code correct/robust.Ty for the heads up, I will correct the code.
@ardmn said in Sending and receiving multiple serial signals:
What I want to do is write, for example, 5 messages containing the "DATA1" command and receive 5 data points
Then write one 'DATA1', wait for the response correctly via signals and slots and send the new command when the preivous answers arrived.
-
@ardmn said in Sending and receiving multiple serial signals:
What I want to do is write, for example, 5 messages containing the "DATA1" command and receive 5 data points
Then write one 'DATA1', wait for the response correctly via signals and slots and send the new command when the preivous answers arrived.
@Christian-Ehrlicher said in Sending and receiving multiple serial signals:
Then write one 'DATA1', wait for the response correctly via signals and slots and send the new command when the preivous answers arrived.
Thank you, this is exactly what I want, but I can't wrap my head around how I'd actually do it, I thought my first example would accomplish this but it didn't.
If it's not asking too much, could you please provide a pseudocode example of how that would look like? Thanks again for the help. -
It just clicked in my head that I can just call the write function inside of the slot I'm using for the readyRead() signal, that way it sends another command after the data is received. Can't believe I was racking my brain over something so simple, thanks a lot for the help @Christian-Ehrlicher, @JonB and @Pl45m4!
-
-
It just clicked in my head that I can just call the write function inside of the slot I'm using for the readyRead() signal, that way it sends another command after the data is received. Can't believe I was racking my brain over something so simple, thanks a lot for the help @Christian-Ehrlicher, @JonB and @Pl45m4!
@ardmn
Yes, sorry, didn't get around to saying so, but sounds like you have twigged it. Outline:void Class::onReadyRead() // slot { this->buffer += serial->readAll(); if (!this->buffer.contains("\n") // still no newline received return; QString line = this->buffer.removeTo("\n"); // extract to \n, remove from pending buffer // either call what you want to do directly someFunction(line); // or (possibly nicer) emit your own signal to which you have attached some other handling slot emit myLineReceivedSignal(line); }
Of course if you are going to call this
onReadyRead()
slot every time you received from serial port you are (likely) going to want to store some state somewhere which tells you how far through your protocol/message exchange you are so as to know how you want to handle this latest line/message which has arrived.