readyRead() signal behavior
-
I am using the connect() method with the QIODevice::readyRead() signal to read data coming from an ESP32 with Arduino code. Does readyRead() emits a signal every time a new character is received or when the end of line (null) character is received?
Alternatively, since the ESP32 is basically echoing what it receives from Qt, does QSerialPort->write("hello") sends the string with a null character after each character sent? eg h\0 e\0 l\0 l\0 o\0
My code and output is below:
void Dialog::on_connect_clicked() // a slot for a button { if(esp_available){ esp->setPortName(espPortName); esp->setBaudRate(9600); esp->setDataBits(QSerialPort::Data8); esp->setParity(QSerialPort::NoParity); esp->setStopBits(QSerialPort::OneStop); esp->setFlowControl(QSerialPort::NoFlowControl); connect(esp, SIGNAL(readyRead()), this, SLOT(onDataReady())); esp->open(QSerialPort::ReadWrite); esp->clear(); } } void Dialog::on_startStream_clicked() { if(esp->isOpen()){ esp->write("hello"); } } void Dialog::onDataReady() { QByteArray ba; if(esp->canReadLine()){ ba = esp->readLine(); qDebug() << ba; } }
The data from the ESP32 using Arduino code is below and should send "hello\n" to via USB:
bool packet_recevived = false; const int max_packet_size = 10; char incoming_packet[max_packet_size]; int parse_packet(); void setup() { Serial.begin(9600); } void loop() { if (Serial.available() > 0 && packet_recevived == false) { parse_packet(); } } int parse_packet() { int in_size = Serial.available(); for (int i = 0; i <= in_size; i++) { incoming_packet[i] = Serial.read(); } Serial.println(incoming_packet); // should print "hello\n" packet_recevived = false; return 0; }
The output I'm getting from qDebug() is:
"h\xFF\r\n" "e\xFF\r\n" "l\xFF\r\n" "l\xFF\r\n" "o\xFF\r\n"
-
@epicQt The "problem" is that you are assuming something that is not guaranteed. You think that communication is per packet ("hello") but in serial communication it is from byte to byte, therefore 5 blocks travel through the wire (one for each letter) and each time it receives a block it indicates that there is data available. A possible solution is to use a delimiter, for example "\n" then you send
esp->write("hello\n");
, and in the esp2 code accumulate the bytes until you receive the "\n" and then you just send the response. By example usereadStringUntil()
-
@epicQt said in readyRead() signal behavior:
does QSerialPort->write("hello") sends the string with a null character after each character sent?
Why should this be done?
Does readyRead() emits a signal every time a new character is received or when the end of line (null) character is received?
It is fired when data is available. It can fire after each character or whatever it wants.
"hello\n"
You send "hello" so why do you expect to receive "hello\n" ?
First you should output the
in_size
and then every single character which is returned from Serial.read(). Don't know what Serial.println(incoming_packet) is doing with the data though. -
@Christian-Ehrlicher said in readyRead() signal behavior:
It is fired when data is available. It can fire after each character or whatever it wants.
"hello\n"
You send "hello" so why do you expect to receive "hello\n" ?
First you should output the
in_size
and then every single character which is returned from Serial.read(). Don't know what Serial.println(incoming_packet) is doing with the data though.I'm expecting "hello\n" because as far as I know Arduino's Serial.println("hello") will attach an termination character. I don't really care what it attaches, I would like to receive the entire string in one line as opposed to individual characters followed by a termination character (which is what is happening now).
The variable in_size is sending a 1 for every character in "hello". This is what I get in the
qDebug() output. I'm also not sure why the \xFF characters are appearing:"1 h\xFF" "1 e\xFF" "1 l\xFF" "1 l\xFF" "1 o\xFF"
-
@epicQt change
i <= in_size
toi < in_size
. You are reading out of the serial port buffer, for example let's say thatavailable()
returns 5 so you must iterate from 0 to 4 but you are iterating from 0 to 5. And the bytes out of the buffer can have any value. -
@eyllanesc said in readyRead() signal behavior:
@epicQt change
i <= in_size
toi < in_size
. You are reading out of the serial port buffer, for example let's say thatavailable()
returns 5 so you must iterate from 0 to 4 but you are iterating from 0 to 5. And the bytes out of the buffer can have any value.@eyllanesc The took care of the \xFF characters but the output is still coming out as one character at a time as opposed to the entire line. Here is the output:
"h" "e" "l" "l" "o"
-
@epicQt The "problem" is that you are assuming something that is not guaranteed. You think that communication is per packet ("hello") but in serial communication it is from byte to byte, therefore 5 blocks travel through the wire (one for each letter) and each time it receives a block it indicates that there is data available. A possible solution is to use a delimiter, for example "\n" then you send
esp->write("hello\n");
, and in the esp2 code accumulate the bytes until you receive the "\n" and then you just send the response. By example usereadStringUntil()
-
@eyllanesc the problem was my Arduino. I simplified it just to test and based on your suggestion and now it is working properly even at 500K baud:
Arduino code:
char buffer[16]; void process(); void setup() { Serial.begin(500000); } void loop() { process(); } void process() { while (Serial.available() > 1) { Serial.readBytesUntil('\n', buffer, 16); Serial.println(buffer); } }