UART to Qt software error - why data always split? - c++

I am tryig to display data I receive via UART on my Qt application.
I send all my data from my microcontroller at once, but my qt application receives it in multiple parts why?
this is what I get: http://imgur.com/kLXRvU5
in stead of: http://imgur.com/h2yNZjl
So every time I receive data my slot function gets called, hence the "data received". But my data is split in two parts. Why please?
my code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)//, mijnAnimatie(new animatie())
{
serialPort->setPortName("COM13");
serialPort->setBaudRate(QSerialPort::Baud115200);
// serialPort->setDataBits(QSerialPort::Data8);
// serialPort->setParity(QSerialPort::NoParity);
// serialPort->setStopBits(QSerialPort::OneStop);
if (!serialPort->open(QIODevice::ReadWrite))
{
qDebug("some error when opening\n");
}
connect(serialPort, SIGNAL(readyRead()), this, SLOT(updateReceivedData()));
}
void MainWindow::updateReceivedData()
{
qDebug("received data\n");
QString m_readData;
ui->receiveLabel->setText(m_readData);
QByteArray result = serialPort->readAll();
QString command(result); //to convert byte array to string
qDebug()<<result;
ui->receiveLabel->setText(command);
}

Streaming connections, like TCP/IP or serial ports, give you zero guaranties about how the data is cut up into pieces. If you want packets, you have to implement them yourself on top of a streaming connection.

Related

How can I wait until data comes in when reading data over Serial Port? QT C++

I need to read ID data through Serial Port. When I send the ID read command with the leather port, the ID data comes to me a little late. Therefore, when I try to split the data and display it on the screen, it comes up blank and the application closes itself. How can I wait until the data comes in?
void productDetail::on_pushButton_clicked()
{
QSerialPortInfo info;
QList<QSerialPortInfo> infoList = QSerialPortInfo::availablePorts();
foreach(info, infoList) QTextStream(stdout) << info.portName();
QString curport = info.portName();
serial.begin(curport, 9600, 8, 0, 1, 0, false);
if(serial.isOpen()){
qDebug()<<"serial open";
QString sendWC= "WR+1121"; //Read ID command
serial.send(sendWC);
QString serialID = serial.getString();
serialID = serialID.trimmed();
QStringList buffer_split = serialID.split(",");
ui->IDlabel->setText(buffer_split[2]; //when I write this program closes
}
}
}
error: ASSERT failure in QList::operator[]: "index out of range",
Qt's QIODevice provides a signal readyRead (https://doc.qt.io/qt-5/qiodevice.html#readyRead) which is emitted once every time new data is available for reading from the device.
In the productDetail class constructor, connect serial port readyRead signal to a slot.
connect(serial, &QSerialPort::readyRead, this, &productDetail::readData);
Define readData method as follows:
void productDetail::readData()
{
const QByteArray data = m_serial->readAll();
}
For serial communication there is no guarantee that you will receive entire message data in a single read. I prefer to store the received data in a circular buffer and process the circular buffer in a separate slot.

Communication error between Arduino and Qt using Xbee PRO S1

I've been trying to do a Lights GUI with an Arduino Mega 2560 with its Xbee Shield and two Xbee Pro S1, one connected to the Arduino and the other one to the PC. My problem is: however I can send data from Qt to my arduino and read it, i can't do the same in the other way. When trying to send a String as "Confirmado\r\n", it arrives to my Qt label wrong, sometimes I get the full String, other ones I receive half of it.
My arduino code is
char buffer[50];
String trama, dir, com, data;
int indexdir, indexcom, indexdata;
void setup(){
Serial.begin(9600);
}
void loop(){
trama= "Confirmado\r\n";
const char *bf = trama.c_str();
if(Serial.available() > 0)
{
Serial.readBytesUntil('/', buffer,500);
Serial.print(bf);
Serial.flush();
}
}
My Qt QSerialPort config is
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
serial = new QSerialPort(this);
serial->setPortName("COM3"); //COM-port your Arduino is connected to
serial->open(QIODevice::ReadWrite);
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
connect(serial,SIGNAL(readyRead()),this,SLOT(serialReceived()));
}
And I send and read data like this
void MainWindow::serialReceived()
{
QByteArray readData = serial->readAll();
//while (serial->waitForReadyRead(500))
// readData.append(serial->readAll());
ui->label->setText(readData);
}
void MainWindow::writeData(const QByteArray &data)
{
serial->write(data);
serial->flush();
serial->waitForBytesWritten(500);
}
The toogle lines means I've tried both options...
I've noticed, doing Debug, that if I place a breakpoint in ui->label->setText(readData);; if it doesnt arrive well (the full "Confirmado\r\n" string), this breakpoint gets twice in this line, the first one readData equals the second half of the string (i.e "mado\r\n") and the other one it values the rest of the string (i.e "Confir").
I've also tried to set a higher baudrate, 57600, but I cant send or receive any data, though I've set the baudrate in the XCTU app before.
Does anyone know a way to receive the full string from Arduino? Or at leats how to setup properly Arduino's and PC's Xbee to work with higher baudrates?
Thanks for the answers, and sorry for my writing skills...
Try use serial->readLine() instead of serial->readall() you can for example wait in loop after the serial->canReadLine() returns the true then you be sure that the data are you received is a full string.

Can QSerialPort read more than 512 bytes of data?

I want to use QSerialPort to read data transmitted from a device. The device transmits a frame of 4000 data bytes each time. I try with the following simple code
QSerialPort *serialPort;
char receivedData[4000];
int numRead = 0;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* Initialize serial port*/
serialPort = new QSerialPort(this);
QString portName = "COM6";
qint32 baudRate = 460800;
serialPort->setPortName(portName);
serialPort->setBaudRate(baudRate);
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
serialPort->setReadBufferSize(4000);
if (!serialPort->open(QIODevice::ReadOnly)) {
qDebug() << "Cannot open comport";
}
connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialReceived()));
}
void MainWindow::serialReceived()
{
numRead = serialPort->read(receivedData, 4000);
serialPort->flush();
}
The problem is: it always shows that only 512 data bytes are read. How can I read the whole 4000 bytes data frame? (when I'm using Matlab to read this 4000 bytes frame, it's working fine)
There's no limit, but you don't necessarily receive all data in single chunk.
You have to keep listening until you have the number of bytes you're waiting for (or a timeout).
void MainWindow::serialReceived()
{
receivedData.append(serialPort->readAll());
if(receivedData.size() >= 4000) {
// we're full
}
}
You generally have to read out the data in a loop (to ensure you get it all), here is a snippet of example code this is equivalent to your serialReceived() function, except it emits the data using emit rxDataReady(newData); to whoever is listening...
void QSerialPortReader::handleReadyRead()
{
QByteArray newData;
// Get the data
while (mp_serialPort->bytesAvailable())
{
newData.append(mp_serialPort->readAll());
}
emit rxDataReady(newData);
}
edit
Although I don't do any max size checking... but that is trivial to add if you need it (i.e. just use read(..., spaceAvail) instead of readAll and then decrement spaceAvail...

QT serial port not working

I'm trying to write \ read from a serial device using a usb / rs 232 cable.
I'm pretty sure that my code writes " #002s " (this is a control code) to the serial device, because
a) the serial port is open
b) the serial port is writable
c) the code successfully navigates "wait For Bytes Written (-1)"
d) when using a serial port sniffer the data is successfully written.
The issue I have is that I don't receive any data, and no data is being emitted from the other device. When using qt terminal writing the same " #002s " produces the correct response.
Any ideas?
many thanks.
#include "test_serial.h"
#include "ui_test_serial.h"
#include <QtSerialPort/QtSerialPort>
#include <QDebug>
QSerialPort *serial;
Test_Serial::Test_Serial(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Test_Serial)
{
ui->setupUi(this);
serial = new QSerialPort(this);
connect(serial,SIGNAL(readyRead()),this,SLOT(serialReceived()));
serial->setPortName("COM1");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadWrite);
if (serial->isOpen() && serial->isWritable())
{
QByteArray input;
input = "#";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "2";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "s";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "\r";
serial->write(input);
serial->waitForBytesWritten(-1);
serial->flush();
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
}}
Test_Serial::~Test_Serial()
{
delete ui;
serial->close();
}
void Test_Serial::serialReceived()
{
QByteArray output;
output = serial->readAll();
ui->label->setText("output");
}
If you want to write " #002s ", Why not write at once? May be the serial device cant identify the control code when you write each character.
void Test_Serial::writeDataToSerialPort()
{
QByteArray input = QString("#002s").toLocal8Bit();
serial->write(input);
}
And no need for this reading part .
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
The Test_Serial::serialReceived will be called any way when you have the response from the serial device.
And you can catch the error on opening the port by using the error signal from QSerialPort
connect(serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(serialPortError(QSerialPort::SerialPortError)));
void Test_Serial::serialPortError(QSerialPort::SerialPortError error)
{
//Print error etc.
}
The issue ended up being that the readyread flag is only emitted if theirs data to read. However I was sending the data too quickly for the external device to receive it. This meant that some data was lost thus the device never recognised it as a valid command.
This meant that it was still waiting for the message to finish, hence the "IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_WAIT_ON_MASK) UP STATUS_CANCELLED COM1" error message upon closing the program. This also explains why their were no error messages with regards to writing data.
This also explains why the same program occasionally managed to read data, and at other times failed, (even without rebuilding the program, just re-running it.) When the data was read, the processor was more loaded, i.e. programs running in the background. This meant that the data was transmitted more slowly and thus the external device could recognise the commands and thus reply.

UDP Server-Client Chat in C++/Qt

I'm trying to write a chat program using Qt. It's half completed but it has some problems.
First of all I get an error when I want to send my written message in lineedit to the client. It's a QString, but the writeDatagram only sends a QByteArray. I've googled it and there are some ways for converting QString to QByteArray, but I'm looking for a better solution.
I think I should use connectToHost(), but read() and write() don't work.
Second and main problem is that I can't get to send and receive messages continuously! Obviously this one hasn't occurred yet but I know there is something wrong with it because I've tested it on Qt console and it didn't work there too.
I'm new to GUI and Socket programming, therefore I've searched a lot before I post this topic.
Update: My first problem solved, but now the UDP packets don't get send and receive let alone working like a chat application.
Update: I found out what was the problem and I solved it. The code needed two QUdpSocket Objects. I also updated the code. It's now fully functional.
If you have other inputs I would love to listen to them, otherwise I've got my answer.
Server:
#include "schat.h"
#include "ui_schat.h"
schat::schat(QWidget *parent) :
QWidget(parent),
ui(new Ui::schat)
{
ui->setupUi(this);
socketServerc=new QUdpSocket(this);
socketServer=new QUdpSocket(this);
socketServer->bind(QHostAddress::LocalHost, 8001);
connect(socketServer,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}
schat::~schat()
{
delete ui;
}
void schat::on_sendButton_clicked()
{
QString word=ui->lineEdit->text();
ui->textBrowser->append(word);
QByteArray buffer;
buffer=word.toUtf8();
QHostAddress sender;
quint16 senderPort;
socketServerc->writeDatagram(buffer.data(), QHostAddress::LocalHost, 7000 );
}
void schat::readPendingDatagrams()
{
while (socketServer->hasPendingDatagrams()) {
QByteArray buffer;
buffer.resize(socketServer->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socketServer->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
ui->textBrowser->append(buffer.data());
}
}
Client:
#include "uchat.h"
#include "ui_uchat.h"
uchat::uchat(QWidget *parent) :
QWidget(parent),
ui(new Ui::uchat)
{
ui->setupUi(this);
clientSocket=new QUdpSocket(this);
clientSocketc=new QUdpSocket(this);
clientSocketc->bind(QHostAddress::LocalHost, 7000);
connect(clientSocketc,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}
uchat::~uchat()
{
delete ui;
}
void uchat::on_sendButton_clicked()
{
QString word=ui->lineEdit->text();
ui->textBrowser->append(word);
QByteArray buffer;
buffer.resize(clientSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
buffer=word.toUtf8();
clientSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 8001 );
}
void uchat::readPendingDatagrams()
{
while (clientSocketc->hasPendingDatagrams()) {
QByteArray buffer;
buffer.resize(clientSocketc->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
clientSocketc->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
ui->textBrowser->append(buffer.data());
}
}
Converting the QString to a QByteArray is indeed the thing to do. The reason is that UDP packets carry only a series of bytes -- but a QString does not unambiguously represent a sequence of bytes, it represents a sequence of notional characters (a.k.a. QChars). So in order to place that QString into an array of bytes, you have to decide which binary representation you want to encode it as. For example, if you wanted to encode the string using UTF8 encoding (which I would recommend), you'd use QString's toUtf8() method to get the QByteArray representing the UTF8 encoding, and the receiver would use QString's fromUtf8() method to turn the received bytes back into a QString. There are other encodings also (ascii, latin1, local8Bit) but they may not handle internationalization as well as UTF8 does.
As for your second problem ("I can't get to send and receive messages continuously"), you're going to have to be more explicit and descriptive about what happens vs what you expected to happen. I don't know what "continuously" means in this context.