read from serial port using mavlink protocol with qt c++ - c++

I'm trying to read from ardupilot that using mavlink protocol for sending data. if you visit this site:
http://qgroundcontrol.org/mavlink/start
you can find how mavlink protocol works and what I'm trying to do. at the bottom of the site you can see the header's bytes arrangement.
I wrote some code and it's works correctly but after running for a while runtime error appears. as far as I know this errors are about memory allocations but I can't find where I allocate memory illegally.
Here is my reader thread code:
QByteArray header;
quint8 ID;
QByteArray payload;
QSerialPort *serial;
void mThread::run()
{//1
while(serial->isOpen())
{//2
if(serial->bytesAvailable() >= 200)
{//3
this->msleep(1);
header = serial->read(1);
if(header.contains(254))
{//4
this->msleep(5);
header.append(serial->read(5));
if((header[3] == 1) && (header[4] == 1))
{//5
ID = header[5];
msleep(12);
payload = serial->read(header[1]);
emit updated(payload , ID);
payload.clear();
header.clear();
}//5
else
{//6
header.clear();
}//6
}//4
else
{//7
header.clear();
}//7
}//3
}//2
}//1
I'm using qt5 whit ubuntu 14.04
and I should mention that I'm reading data with 115200baud and it should manage with thread. If not reading from it will lock my ui.

Do you really need all those msleeps... Reading at that baud rate I would think your serial port input buffer would overflow pretty quickly. Might be worth the time to have a look at it.
As a complete different approach why not use the MAVlink generator to generate a library that you could use. This way it saves you from the trouble of parsing the messages and error checking them and all that...

Related

I need help figuring out tcp sockets (clsocket)

I am having trouble figuring out sockets i am just asking the server for data at a position (glm::i64vec4) and expecting a response but the position gets way off when i get the response and the data for that position reflects that (aka my voxel game make a kinda cool looking but useless mess)
It's probably just me not understanding sockets whatsoever or maybe something weird with this library
one thought i had is it was maybe something to do with mismatching blocking and non blocking on the server and client
but when i switched the server to blocking (and put each client in a seperate thread from each other and the accepting process) it did nothing
if i'm doing something really stupid please tell me i know next to nothing about sockets
here is some code that probably looks horrible
Server Code
std::deque <CActiveSocket*> clients;
CPassiveSocket socket;
socket.Initialize();
socket.SetNonblocking();//I'm doing this so i don't need multiple threads for clients
socket.Listen("0.0.0.0",port);
while (1){
{
CActiveSocket* c;
if ((c = socket.Accept()) != NULL){
clients.emplace_back(c);
}
}
for (CActiveSocket*& c : clients){
c->Receive(sizeof(glm::i64vec4));
if (c->GetBytesReceived() == sizeof(glm::i64vec4)){
chkpkt chk;
chk.pos = *(glm::i64vec4*)c->GetData();
LOOP3D(chksize+2){
chk.data(i,j,k).val = chk.pos.y*chksize+j;
chk.data(i,j,k).id=0;
}
while (c->Send((uint8*)&chk,sizeof(chkpkt)) != sizeof(chkpkt)){}
}
}
}
Client Code
//v is a glm::i64vec4
//fsock is set to Blocking
if(fsock.Send((uint8*)&v,sizeof(glm::i64vec4)))
if (fsock.Receive(sizeof(chkpkt))){
tthread::lock_guard<tthread::fast_mutex> lock(wld->filemut);
wld->ichks[v]=(*(chkpkt*)fsock.GetData()).data;//i tried using the position i get back from the server to set this (instead of v) but that made it to where nothing loaded
//i checked it and the chunks position never lines up with what i sent
}
Without your complete application codes it's unrealistic to offer any suggestions of any particular lines of code correction.
But it seems like you are using this library. It doesn't matter if not, because most of time when doing network programming, socket's weird behavior make some problems somewhat universal. Thus there are a few suggestions for the portion of socket application in your project:
It suffices to have BLOCKING sockets.
Most of time socket's read have somewhat weird behavior, that is, it might not receive the requested size of bytes at a time. Due to this, you need to repeatedly call read until the receiving buffer is read thoroughly. For a complete and robust solution you can refer to Stevens's readn routine ([Ref.1], page122).
If you are using exactly the library mentioned above, you can see that your fsock.Receive eventually calls recv. And recv is just an variant of read[Ref.2], thus the solutions for both of them are just identical. And this pattern might help:
while(fsock.Receive(sizeof(chkpkt))>0)
{
// ...
}
Ref.1: https://mathcs.clarku.edu/~jbreecher/cs280/UNIX%20Network%20Programming(Volume1,3rd).pdf
Ref.2: https://man7.org/linux/man-pages/man2/recv.2.html#DESCRIPTION

QSerialPort continuous reading accumulative delay

I am trying to do communication from QT Application to Arduino. The flow is like this: QT Application sends a '1' and Arduino is expected to respond with some data(the data String length is huge, around 300). QT Application is sending '1' at the rate of around 5Hz(every 200ms).
The problem I am facing is, there is an accumulative delay between the Arduino to QT communication. That is, the data I receive from Arduino is not recent data but the frequency of data coming of Arduino is 5Hz only(which is as expected), just the data coming is not recent. This delay keeps on increasing with time. I believe there is some problem with buffer or something.
What I tried:
QSerialPort serialPort; is my device port
serialPort.clear()
serialPort.flush()
Increasing and decreasing Baud Rate from both ends.
Reduce character length from Arduino, here delay reduces significantly but the accumulated delay is observed after a long time.
to clear serial communication buffer, but the issue still persists.
Here is my code snippet:
connect(timer_getdat, SIGNAL(timeout()), this, SLOT(Rec()));
timer_getdat->start(200);
where Rec() is the function where I do communication part.
In Rec():
serialPort.write("1", 2);
// serialPort.waitForBytesWritten(100);
long long bytes_available = serialPort.bytesAvailable();
if (bytes_available >= 1)
{
serialPort.readLine(temp, 500);
serialPort.flush(); // no change
serialPort.clear(); // no change by .clear() also
}
I have been stuck on this issue for a quite long time. The above code snippet is what I think is necessary but if anyone needs more clarification, I may reveal more of the code.
I also encountered with the same issue, and yes QSerialPort.clear() and QSerialPort.flush() doesn't help. Try doing readAll()
So change the part in your Rec() function to something like this:
serialPort.write("1", 2);
long long bytes_available = serialPort.bytesAvailable();
if (bytes_available >= 1)
{
serialPort.readLine(temp, 500);
serialPort.readAll(); // This reads all the data in buffer at once and clears the queue.
}
Even on QT forums, I didn't find the answer to this, was playing with all functions available with QSerialPort class and readAll() seems to work.
About readAll(), Qt documentation says:
Reads all remaining data from the device, and returns it as a byte
array.
My explanation for the resolution is that readAll captures all of the data from the communication buffer and empties it.
This should be the job of clear() function but apparently readAll() seems to work.

QTcpSocket sends more data than wanted - Qt/C++

first of all a little background on my situation:
- Qt/C++ UI desktop application
- embedded device (Stm32l4xx family) +ATWINC1500 wifi module
I'm developing the gui application in order to send commands and files to the emdedded device via sockets.
For simple commands I've done all successfully, but for sending files (text files in GCODE format) I am stuck with some issues.
The embedded device has already a socket management(not written by me, so I have not the possibility to modify the way sockets are managed, coming from third party company), and the reception of that type of files is managed in a way that the API waits for every single line of the file being sent, and then wrotes it into a reserved portion of the flash.
My problem is that when I send file from qt Application(by reading each line and and calling write() on the line, in reality my socket sends an entire chunk of the file, like 50 lines, resulting in my device not managing the file reception.
My sending code is this:
void sendGCODE(const QString fileName)
{
QFile *file = new QFile(fileName,this);
bool result = true;
if (file->open(QIODevice::ReadOnly))
{
while (!file->atEnd())
{
QByteArray bytes(file->readLine());
result = communicationSocket->write(bytes);
communicationSocket->flush();
if(result)
{
console->append("-> GCODE line sent:"+ QString(bytes));
}
else
{
console->append("-> Error sending GCODE line!");
}
}
file->close();
}
}
Have anyone of you guys any hints on what I am doing wrong?
I've already searched and someone suggests on other topic that for this purpose it should be better to use UDP instead of TCP sockets, but unfortunately I cannot touch the embedded-device-side code.
thank you all!
EDIT
After suggestions from comments, I've sniffed tcp packets and the packets are sent correctly(i.e. each packet contains a single line). BUT... at the receiver(device), I understood that there is something regarding memory which is not well managed. an example:
sender sends the line "G1 X470.492 Y599.623 F1000" ; receiver receives correctly the string "G1 X470.492 Y599.623 F1000"
next, if the line length is less than the previous sent, i.e. sending "G1 Z5", the receiver receives: "G1 Z5\n\n.492 Y599.623 F1000", so it is clear that the buffer used to store the data packet is not re-initialized from previous packet content, and the new part overwrites the previous values where the remaining part is from the previous packet
I'm trying to figure out how I could reset that part of memory.
This is all wrong. TCP is not a message-oriented protocol. There is no way to ensure that the TCP packets contain any particular amount of data. The receiver code on the device mustn't expect that either - you perhaps misunderstood the receiver's code, or are otherwise doing something wrong (or the vendor is). What the receiver must do is wait for a packet, add the packet's data to a buffer, then extract and process as many complete lines as it can, then move the remaining data to the beginning of the buffer. And repeat that on every packet.
Thus you're looking for the wrong problem at the wrong place, unless your device never ever had a chance of working. If that device works OK with other software, then your "packetized" TCP assumption doesn't hold any water.
Here's how to proceed:
If the device is commercially available and has been tested to work, then you're looking in the wrong place.
If the device is a new product and still in development, then someone somewhere did something particularly stupid and you either need to fix that stupidity, or have the vendor fix it, or hire a consultant to fix it. But just to be completely clear: that's not how TCP works, and you cannot just accept that "it's how it is".

QTcpSocket Read Error

I have a Qt based TCP client and server making use of QTcpServer and QTcpSocket classes for communication. The server is compiled using Qt 5.3.1 and the client is compiled using Qt 4.8.1. This is done so because the client is a part of a framework that uses Qt 4.8.1 running on Ubuntu 12.04.
Since the classes I make use is available in both Qt versions I assume this wont create a problem.
However my client has some weird issues that it does not receive data from the server! I checked the server side and the data is sent from the server and I can also see the data packet on the wire using wireshark. However on my client code, the data does not arrive!
I investigated this a bit and it led me to a strange conclusion that this happens only if I use the read method of QTcpSocket! If I use the native POSIX read system call, I am able to read the data correctly! Please see my code below:
qDebug() << "QTcpSocket::bytesAvailable() gives" << m_pSocket->bytesAvailable();
char nData;
qint32 szReceived;
if(sizeof(char) != (szReceived = m_pSocket->read((char*)&nData,sizeof(char))))
{
qDebug() << "Error reading data from QTcpSocket::read()" << m_pSocket->errorString();
}
else
{
qDebug() << "QTcpSocket::read() returned" << szReceived;
}
int nDesc = m_pSocket->socketDescriptor();
if(sizeof(char) != (szReceived = read(nDesc, &nData,sizeof(char))))
{
perror("Error reading data from POSIX read()");
}
else
{
qDebug() << "POSIX read() returned" << szReceived;
}
This produces the following output:
QTcpSocket::bytesAvailable() gives 0
Error reading data from QTcpSocket::read() "Network operation timed out"
POSIX read() returned 1
How is it that the POSIX system calls reads the buffered data as expected and the Qt class cannot read it? Plus I have not set any socket options and so I don't know why it reports an error that network operation timed out!
"read" is a blocking call in POSIX, it waits till the data is arrived. while QTcpSocket is non-blocking operation it immediately returns the buffered data. Call waitForReadyRead before doing a read
socket->waitForReadyRead();
if(sizeof(char) != (szReceived = m_pSocket->read((char*)&nData,sizeof(char))))
I think that it is misuse of QTcpSocket concept. QTcpSocket implements asynchronous architecture while POSIX read/write calls are blocking until the success or error of I/O on socket. It is much better to process read in slot for readyRead signal. Consider this:
class MyClient
{
Q_OBJECT
...
private slots:
readFromSocket();
};
In your intialization:
QObject::connect(
m_pSocket, SIGNAL(readyRead()),
this, SLOT(readFromSocket()));
And real job done here:
void
MyClient::readFromSocket()
{
QByteArray buffer = m_pSocket->readAll();
// All your data in buffer.
}
I'm aware of the non-blocking nature of QTcpSocket and blocking nature of POSIX read call. Unfortunately I cannot use the signal readFromSocket because my communication architecture expects a header to be sent before each communication (TCP way) to see the payload that is streamed for that particular message. Hence I have to wait till I receive at least the header.
I do believe that this has something to do with the mode (blocking or non-blocking). I did some more tests and none of them were conclusive. In one of my tests, I tried to call a waitForReadyRead with a timeout of 1ms, 2ms, 3ms. This still wasn't sufficent for the read to succeed! I doubt if the read would need such time to read from the kernel buffers to user space as I can clearly see from wireshark that the message was received within 400ms.
When I give -1 as the timeout value of waitForReadyRead, the read succeeds! To put it in another way, the read succeeds only when the socket waits indefinitely like in the case of POSIX read call.
Another strange thing I observed was, this issue was originally observed when I was running a server compiled using Qt 5.3.1 and client compiled using Qt 4.8.1. When I compile my client to use Qt 5.3.1, I do not see this problem!!! I even tried compiling using Qt 4.7.1 and it worked without any issues!!!
Are there any known issues with socket implementation of Qt 4.8.1? I couldn't find much info regarding this unfortunately.

Blocking Serial Port Read

I have to read many(8) serial devices on my project. They are Pantilt, Camera, GPS, Compass etc. they all are RS232 devices but they have different command structure and behavior. e.g GPS starts sending data as
soon as I open the port. where as PanTilt and Camera only responds when I send specific commands to them.
I use following environment
OS: Ubuntu 11.10
Language: C++
Framework: Qt 4.7
For PanTilt and Camera I want to develop function like this.
int SendCommand(string& command, string& response)
{
port.write(command, strlen(command));
while(1)
{
if(response contains '\n') break;
port.read(response) // Blocking Read
}
return num_of_bytes_read;
}
I want to implement this way as this function will be used as building block for more complex algorithm
like this...
SendCoammd("GET PAN ANGLE", &angle);
if(angle > 60)
SendCommand("STOP PAN", &stopped?);
if(stopped? == true)
SendCommand("REVERSE PAN DIRECTION", &revesed?);
if(reversed? == true)
SendCommand("START PAN", &ok);
To do something like this I need strict synchronous behavior. Anybody has any idea how to approach this?
I found this tutorial very intresting and helpful.
http://www.webalice.it/fede.tft/serial_port/serial_port.html
It shows how boost::asio can be used to perform both sync and async read/write.
Thank You for the help!
what is the problem of using standard file API?
fd = open("/dev/ttyX");
write(fd, command.cstr(), command.size());
vector v(MAX_SIZE);
read(fd,&v[0], MAX_SIZE);
Low-level communication with serial port in Qt can be established with QExtSerialPort library that partially implements QIODevice interface.
The high level protocols you have to implement yourself.