How to wait for Qtcpsocket data without freezing the GUI?
-
I have implemented a **QTcpserver ** .After succesfull connection with the client( PLC), both exchange data in a 2 way hand shake.Means Server sends the data with a counter value and client will reply with the same value,the moment server receives the value it send with incremented counter value.This goes on in a loop. I have done using signals and slot.
connect(m_tcpSocket, SIGNAL(readyRead()),this, SLOT(socketReadyRead()));
In the slot of socketReadyRead(), I am emitting the signal to another slot where i send new data with incremented counter value.void TCPCommunicationPort::socketReadyRead() { emit newRawData();//connect to another slot where i send data // qDebug()<<"bytes available "<<m_tcpSocket->bytesAvailable(); QByteArray receivedData = m_tcpSocket->readAll(); //I am updating the GUI written in QML though signals emit sendDatatoQml(byteIndex,-1,overrideValue); .... }
Now, I send 48Bytes of data and I receive **68 bytes **of data from the client. To perform a function called Homing. I need to set/enable particlular bits in 48Bytes of sendData(say bits 1 and 2 of 6th byte ) and wait till particular bit in 68 bytes (Recevied data)(say 3rd bit of 10th byte) is true(this will be after few seconds) and then I have disable the bits 1 and 2 of 6th byte .Meanwhile the server has to keep on sending 48 bytes of data with incremented counter value, otherwise it will disconnect. How to perfome this waiting ? note that already data is exchanging in a loop.
I tried like this but Qt creator and app both freezed and crashed because of infinet while loop.void TCPCommunicationPort::startHoming() { if(!(m_senddataBuffer[CREG1] & (1 << EMSTOP))) { m_senddataBuffer[CREG1] |= 1<<EMSTOP; bool bitvalue = (m_senddataBuffer[CREG1] & (1 << EMSTOP)); dataFromCppUpdate(CREG1,EMSTOP,bitvalue); } if(!(m_senddataBuffer[CREG1] & (1 << MSTOP))) { m_senddataBuffer[CREG1] |= 1<<MSTOP; bool bitvalue = (m_senddataBuffer[CREG1] & (1 << MSTOP)); dataFromCppUpdate(CREG1,MSTOP,bitvalue); } // emit newRawData(); bool enter =true; while(enter) { qDebug()<<"I am waiting.."; if(m_tcpSocket->waitForReadyRead()) { bool bitValue =(receivedData[byteIndex] & (1 << bitIndex));//I am reading the socketReadyRead in SocketReadyready SLOT. If(bitValue) { //disable the bit. } break; } } qDebug()<<"homing is done"; }
Can any one please tell me the logic to wait without freezing the GUI.Do i need to put this function startHoming in separate Qthread ? If so how to do that? Please provide me an example.Thanks a lot
-
Hi,
waitForReadyRead already does the blocking part but plays nicely with the event loop. Remove your while loop
-
@SGaist
Okay,I removed the while loop.I don't know why the debug() statementqDebug()<<"I am waiting.."
is never called.That means I am not entering into the If statementif(m_tcpSocket->waitForReadyRead())
please note that data sending SLOTconnect(this,SIGNAL(newRawData()),this,SLOT(sendRawData()));
is called almost every 30ms, otherwise client will be disconnected.That means already kinda loop is running.Will the program waits at this point if(m_tcpSocket->waitForReadyRead())?void TCPCommunicationPort::startHoming() { qDebug()<<"TCPCommunicationPort::startHoming"; if(!(m_senddataBuffer[CREG1] & (1 << EMSTOP))) { m_senddataBuffer[CREG1] |= 1<<EMSTOP;//set the Bit to true bool bitvalue = (m_senddataBuffer[CREG1] & (1 << EMSTOP)); dataFromCppUpdate(CREG1,EMSTOP,bitvalue); } if(!(m_senddataBuffer[CREG1] & (1 << MSTOP))) { m_senddataBuffer[CREG1] |= 1<<MSTOP; bool bitvalue = (m_senddataBuffer[CREG1] & (1 << MSTOP)); dataFromCppUpdate(CREG1,MSTOP,bitvalue); } // emit newRawData(); if(m_tcpSocket->waitForReadyRead()) { qDebug()<<"I am waiting.."; } qDebug()<<"homing is done"; }
-
It means that there was nothing to read until the timeout of waitForReadyRead
-
@SGaist (
Now It works but I think my explanation is wrong. Let me tell you once again. I am getting data from client almost every 30ms and I am reading it to receivedData[] . That meansconnect(m_tcpSocket, SIGNAL(readyRead()),this, SLOT(socketReadyRead()));
socketReadyRead() is called every 30ms. So my IF statement works.But I must wait till one of the Bit in 68Bytes(say 3rd bit of 10th byte ) of data i receive from client is enabled.It keeps on sending 68 bytes of data(every 30ms) but after some time when the work is done it will send me an Ack (Almost after 10 Sec(i.e 10000ms)) by enabling the 3rd bit(ACKSTART) of 10th byte(SREG1).How should i wait there till that bit is enabled?if(m_tcpSocket->waitForReadyRead()) { qDebug()<<"I am waiting for ACK..."; if((m_oldData[SREG1] & (1 << ACKSTART)))//how should I wait here till that bit is enabled? { qDebug()<<"Ack received"; } } qDebug()<<"homing is done";
-
Don't put any infinite loop because you are waiting for the ACK. Just use a signal to tell your program to continue when you actually received it.
You should maybe consider using a state machine to model that
-
@SGaist
Thanks for the hint. your are right It's like a state machine model .I am using switch case statements. Waiting in a case till that is true and then moving to another state. But it seems to be lot of switch cases and lot of condition check variables. Is there any good practise instead of switch case and if else statements? Thanks -
Well, the Qt State Machine Framework looks like a good place to start
-
This is an old topic, but you can use canReadLine() to check if a complete line has arrived. If not, just don`t read the buffer and wait for the next readyRead(). When a complete line arrive, use readLine(), so the tcp socket will let the contents after the \n to the next read and so on.