QSerialPort detecting lost connection - qt

My setup is as follows: Arduino Mega UART3 <--> Voltage Level shifter <--> Rpi4
All the code can be found here
Data is being sent synchronously from the Arduino to the Rpi at 100ms and 1000ms (depending on the importance of the data). And also data is being sent from the Rpi back to the Arduino asynchronously on GUI input (There is also a sync sent at 1000ms in case some frames are lost/corrupted).
Coms are handled in a separate thread than the GUI to provide the best user experience.
Well, all is working fine but I have been trying unsuccessfully to detect if the Rpi has lost connection with the Arduino. (In the other direction is covered with a serial watchdog.)
I wanted to avoid the use of another watchdog in the Qt part but I cannot find a suitable signal to detect the lost serial connection as the QSerialPort keeps reporting a Timeout error randomly... and there are no other methods that detect successfully the disconnection.
Here below is the workaround that I am trying to use without much success: (Probably it needs a major rewrite... but I need to be pointed in the right direction first)
// Serial Port Initialization
m_Serial = new QSerialPort();
m_Serial->setPortName("ttyS0");
//m_Serial->setPortName("ttyUSB0");
m_Serial->setBaudRate(QSerialPort::Baud115200);
m_Serial->setDataBits(QSerialPort::Data8);
m_Serial->setParity(QSerialPort::NoParity);
m_Serial->setStopBits(QSerialPort::OneStop);
m_Serial->setFlowControl(QSerialPort::NoFlowControl);
m_Serial->open(QIODevice::ReadWrite);
qDebug() << "SerialPort Status: " << m_Serial->isOpen();
emit serialConnected(m_Serial->isReadable());
while(!abort)
{
QThread::msleep(5);
while (!isConected(m_Serial)){
emit serialConnected(false);
isSerialConected = false;
QThread::sleep(1);
qDebug() << "Serial Error: ";
//qDebug() << "Is readable?: " << m_Serial->isReadable();
//qDebug() << "Bytes availiable?: " << m_Serial->bytesAvailable();
mutex.lock();
abort = _abort;
mutex.unlock();
}
if (!isSerialConected){
emit serialConnected(true);
isSerialConected=true;
}
mutex.lock();
abort = _abort;
mutex.unlock();
if(!m_outFrameQueue->isEmpty())
{
//qDebug() << "Frame empty";
{ *sendData*}
} else
{
if (m_Serial->waitForReadyRead(10) )
{ *readData*}
And the function that I am trying to use to detect if is actually connected:
bool SerialWorker::isConected(QSerialPort *m_Serial){
// qDebug() << "SerialPort Error: " << m_Serial->error();
// qDebug() << "SerialPort isReadable: " << m_Serial->isReadable();
// qDebug() << "SerialPort isReadable: " << m_Serial->bytesAvailable();
if (m_Serial->error() == QSerialPort::SerialPortError::NoError){
return true;
}
else if (m_Serial->error() == QSerialPort::SerialPortError::TimeoutError){
m_Serial->clearError();
//m_Serial->reset();
return true;
}else{
m_Serial->reset();
m_Serial->close();
m_Serial->clearError();
QThread::sleep(1);
m_Serial->open(QIODevice::ReadWrite);
return false;
}
}

Related

Why 10049 error occurs in udp communication even though ip and port are entered correctly

DWORD WINAPI socketRead(void *lpVoid)
{
while (true)
{
// UDP socket
WSADATA data_s;
WORD version = MAKEWORD(2, 2);
// socket start
int wsok = WSAStartup(version, &data_s);
if (wsok != 0)
{
cout << "Can't start Winsock!" << wsok;
return 0;
}
else
{
cout << "start Winsock!\n";
}
// socket bind
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN serverHint = {};
memset(&serverHint, 0, sizeof(serverHint));
serverHint.sin_family = AF_INET; // IPv4
serverHint.sin_addr.S_un.S_addr = inet_addr("192.168.0.69");
serverHint.sin_port = htons(1480);
if (bind(in, (sockaddr *)&serverHint, sizeof(serverHint)) != SOCKET_ERROR)
{
cout << "bind socket!\n";
}
else
{
cout << "can't bind socket!" << WSAGetLastError() << endl;
// socket clean
int wsokE = WSACleanup();
if (wsokE != 0)
{
cout << "Can't cleanup Winsock!" << wsokE;
}
else
{
cout << "cleanup Winsock!\n";
}
// return 0;
}
}
this is my code. I want to do UDP socket communication using winsocket.
It is trying to do udp communication with another computer.
However, I keep getting error 10049 even though I wrote down the ip address and port number correctly.
The 1480 port I wrote down in the code is what I set arbitrarily. Do I need to do other processing on the computer?
When I use the same ip and port in the incoming and outgoing confirmation program called Ezterm, the values ​​come normally.
In conclusion, we want to receive data from "192.168.0.69".

How to connect using UDP to my pic32 and get an answer from it

I want to connet with Qt on windows to my PIC32 UDP server. With a test program in C, I can connect and get the answer, but with Qt it is impossible. What am I doing wrong ?
As you can see I use an ACTIVE WAITING with the while, and my slot doesn't seems to be triggered. Maybe you can see my mistake here ? I hate active waiting....
Here is my code on Qt :
void MuTweezer::run()
{
QHostAddress sender;
quint16 senderPort;
QByteArray datagram;
qint64 pendingBytes;
int cpt = 0;
// Message to send
QByteArray message("Hello that's charly");
// m_imuRcvSocket.bind(10000); why is it for in a client side !?
// SEEMS to NOT BE TRIGGERED
connect(&m_imuRcvSocket, SIGNAL(readyRead()), this, SLOT(recu()));
while(m_isRunning && cpt++ < 10)
{
// send the initial message
qint64 bytesSent= m_imuRcvSocket.writeDatagram(message, QHostAddress("192.168.0.15"), 10000);
cout << "Bytes sent : " << bytesSent << endl;
// We wait the answer from the server
while(!m_imuRcvSocket.hasPendingDatagrams());
// If there is no datagram available, this function returns -1
if((pendingBytes = m_imuRcvSocket.pendingDatagramSize()) == -1)
continue;
datagram.resize(pendingBytes);
m_imuRcvSocket.readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
cout << "================="
<< "\nMessage from <" << sender.toString().toStdString().substr(7) << "> on port " << senderPort
<< "\nString : " << datagram.data()
<< "\nSize: " << pendingBytes << " Bytes (characters)\n"
<< "=================" <<
endl;
}
}
Here is my code on the PIC32, as you can see, once I receive a message, I send the answer, it allows me to make a bidirectionnal communication :
if(!UDPIsOpened(mySocket)){
DBPRINTF("Socket CLOSED");
continue; // go back to loop beginning
}
DBPRINTF("Socket OPEN");
if(!(lengthToGet = UDPIsGetReady(mySocket)))
continue;
// get the string
// UDPGetArray : returns the number of bytes successfully read from the UDP buffer.
if((lengthWeGot = UDPGetArray(message, lengthToGet)))
UDPDiscard(); // Discards any remaining RX data from a UDP socket.
/* Modifie it and send it back */
if(UDPIsPutReady(mySocket)){
message[20]= 'Z';
message[21]= 'i';
message[22]= 'b';
message[23]= 'o';
UDPPutArray(message, lengthWeGot);
UDPFlush();
}
Any idea ?
Try to use waitForBytesWritten and waitForReadyRead:
// to receive datagrams, the socket needs to be bound to an address and port
m_imuRcvSocket.bind();
// send the initial message
QByteArray message("Hi it's Charly");
qint64 bytesSent= m_imuRcvSocket.writeDatagram(message,
QHostAddress("200.0.0.3"),
10000);
bool datagramWritten = m_imuRcvSocket.waitForBytesWritten();
// add code to check datagramWritten
datagram.resize(50); // random size for testing
bool datagramReady = m_imuRcvSocket.waitForReadyRead() && m_imuRcvSocket.hasPendingDatagrams();
// add code to check datagramReady
m_imuRcvSocket.readDatagram(datagram.data(),
datagram.size(),
&sender,
&senderPort);
cout << "================="
<< "\nMessage from <" << sender << "> on port " << senderPort
<< "\nString : " << datagram
<< "\nSize: " << pendingBytes << " Bytes (characters)\n"
<< "=================" <<
endl;
A better alternative would be to use signals and slots as described in the documentation of QUdpSocket
if you plan to use the microprocessor as a client with UDP you need the MAC address of the destination machine otherwise it will not work. This one took me 4 hours to figure out.

TCP - Identity of timed out client

I want to know the identity of the timed out client ?
how ?
if the function that will receive data like this ..How can I know the client ID ?
your help will be greatly appreciated
Thank you :)
DWORD WINAPI Server::ClientThread(LPVOID lpParam)
{
char receivedData[BUFFER_SIZE];
ThreadData myThreadData = *(ThreadData*)lpParam;
while (1)
{
int returnValue;
// Perform a blocking recv() call
returnValue = recv(myThreadData.clientSocket, receivedData, BUFFER_SIZE, 0);
if (returnValue == 0)
break;
else if (returnValue == SOCKET_ERROR)
{
cout << "recv() failed - Error Code : " << WSAGetLastError() << endl;
}
else
{
receivedData[returnValue] = '\0';
cout << "I am the server and received " << receivedData << endl;
UnderstandComingMessage(receivedData, myThreadData);
}
}
}
I don't know what you mean by 'identity', but you can get the peer IP address and port by calling getpeername() on the socket.

QTcpSocket: Sending data reliable to QTcpServer: Detect unplugged cable

I have to send data reliable from a client using QTcpSocket to a server using QTcpServer.
The connection is established once and the data is send line by line with terminator of "\r\n" (The server is splitting the incoming data on this terminator)
If need to know which line could be successful and which line not.
This works as expected. But if I unplug the server network cable from the network, the client is still writing data and the "bytesWritten" signal is still emitted.
But no write error occurred and the "error" signal is not emitted. It seems QTcpSocket is writing the data to an internal buffer even if the TPC connection is lost. Using flush() has no effect.
Example code based on the fortune client:
Client::Client(QWidget *parent)
: QDialog(parent), networkSession(0)
{
m_messageCount=0;
QString ipAddress= "192.168.1.16";
m_socket = new QTcpSocket(this);
//No effect...
//m_socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
connect(m_socket, SIGNAL(connected()), this, SLOT(Connected()));
connect(m_socket, SIGNAL(disconnected()), this, SLOT(DisConnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(OnBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
void Client::connectToHost()
{
m_socket->connectToHost("192.168.1.16", 1234);
}
void Client::Connected()
{
qDebug() << "Connected()";
QTimer::singleShot(1000, this, SLOT(SendNextRecord()));
}
void Client::DisConnected()
{
qDebug() << "DisConnected()";
}
void Client::SendNextRecord()
{
m_messageCount++;
QByteArray singleRecord=QString("Nr: %1 Some Text").arg(m_messageCount).toUtf8();
singleRecord.append("\r\n");
Q_ASSERT(m_socket->isValid());
qDebug() << "Sending: " <<singleRecord;
//bytesSend always > 0
qint64 bytesSend=m_socket->write(singleRecord);
//No effect
m_socket->flush();
qDebug() <<"bytes Send:" << bytesSend;
}
//Signal is still emitted even if network cable is unplugged
void Client::OnBytesWritten(qint64 bytes)
{
qDebug() << "OnBytesWritten:" << bytes;
//No effect
m_socket->flush();
QTimer::singleShot(1000, this, SLOT(SendNextRecord()));
}
//Signal not emitted even if network cable is unplugged
void Client::displayError(QAbstractSocket::SocketError socketError)
{
qDebug() << "Socket error";
}
Can I change this behaviour ?

message synchronization with boost::mpi send/recv?

I call mpirun with "-np 2". I'm referring to the process with rank 0 as "master" and the process with rank 1 as "slave".
Goal:
master occasionally sends a message to slave such as mpi::send(1, UPDATE, data);. Other message types include DIE, COMPUTE ...etc. Those message types are constant integers with unique values.
slave runs an infinite loop, "listening" to any message from the master. When it receives a message, it sends an acknowledgement back to the master.
Implementation:
slave runs:
...
int updateData, computeData;
mpi::request updateRequest = world.irecv(0,UPDATE, updateData);
mpi::request computeRequest = world.irecv(0,COMPUTE, computeData);
do {
cerr << "slave ready to take a command" << endl;
if(updateRequest.test()) {
cerr << "slave ireceived UPDATE" << endl;
world.send(0, UPDATE_ACK, 0);
cerr << "slave sent UPDATE_ACK" << endl;
/* do something useful
...
...
*/
updateRequest = world.irecv(0, UPDATE, updateData);
} else if (computeRequest.test()) {
...
} else {
boost::this_thread::sleep( boost::posix_time::seconds(1) );
}
}
while the master runs:
...
world.send(1, UPDATE, 10);
cerr << "master sent UPDATE" << endl;
int dummy;
world.recv(1, UPDATE_ACK, dummy);
cerr << "master received UPDATE_ACK" << endl;
...
more context for the master's code:
...
// update1
world.send(1, UPDATE, params);
cerr << "master sent UPDATE" << endl;
int dummy;
world.recv(1, UPDATE_ACK, dummy);
cerr << "master received UPDATE_ACK" << endl;
// update2
world.send(1, UPDATE2, params2);
cerr << "master sent UPDATE2" << endl;
world.recv(1, UPDATE2_ACK, dummy);
cerr << "master received UPDATE2_ACK" << endl;
// update3
world.send(1, UPDATE3, params3);
cerr << "master sent UPDATE3" << endl;
world.recv(1, UPDATE3_ACK, dummy);
cerr << "master received UPDATE3_ACK" << endl;
...
// training iterations
do {
mpi::request computeRecvReq1, computeRecvReq2;
std::map<int, int> result1, result2;
// for each line in a text file, the master asks the slave(s)
// to compute two things and aggregates the results
for(unsigned sentId = 0; sentId != data.size(); sentId++) {
// these two functions won't return until at least one slave is "idle"
CollectSlavesWork1(computeRecvReq1, result1);
CollectSlavesWork2(computeRecvReq2, result2);
// async ask the slave to compute and async get the results
world.isend(1, COMPUTE, sentId);
computeRecvReq1 = world.irecv(1, RESULT1, result1);
computeRecvReq2 = world.irecv(1, RESULT2, result2);
}
// based on the slave(s) work, the master updates params1
// and send them again to the slave(s)
world.send(1, UPDATE, params);
cerr << "master sent UPDATE" << endl;
world.recv(1, UPDATE_ACK, dummy); // PROBLEM HAPPENS HERE
cerr << "master received UPDATE_ACK" << endl;
} while(!ModelIsConverged())
...
Output:
...
slave ready to take a command
master sent UPDATE
slave ireceived UPDATE
slave sent UPDATE_ACK
master received UPDATE_ACK
slave ready to take a command
...
slave ready to take a command
master sent UPDATE
slave ireceived UPDATE
slave sent UPDATE_ACK
slave ready to take a command
...
Problem:
the first time the master sends an UPDATE message everything seems to be alright. However, in the second time, the master doesn't receive the UPDATE_ACK.

Resources