PDA

View Full Version : Reading/Writing SerialPort and Handle Response



mikrocat
13th November 2015, 10:23
I connected the ReadyRead-Signal from my SerialPort to the Slot



void Serial::handlePortReadyRead(){
QByteArray temp = serialPort.readAll();
qDebug()<<"Read from Port" << temp.toHex();
emit ReadFromPort(temp);
}

When I start a process I connect the ReadFromPort(QByteArray)-Signal to a Slot, where I handle the repsonse from the port.


void Process::analyzeFrame(QByteArray temp){
for(int charCount = 0; charCount < temp.count(); charCount++){
char singleInChar = temp.at(charCount);
validationFlag = handleResponse(&response, deviceAddress, FID, singleInChar, false);
break;
}
}
}

handleResponse returns 0 or 1. If it returns 1 I want the process to continue, 0 means I have to wait. If validationFlag does not get 1 within 100 msecs the process should stop.



serialPort.write(dataToSend);
TimerForReadingFromPort->start(100);
do{
QApplication::processEvents();
if(validationFlag == 1){
//analyze response
...
response.clear();
}
else if(TimerForReadingFromPort->remainingTime() == 0){
....
return
}
}
while(validationFlag == 0);//end while-Schleife

So this process is a very long process. Sometimes it get stucked in the middle of the code, I think it is because of the QApplication:rocessEvents().
Is there any better way?

anda_skoa
13th November 2015, 11:27
You could just start a timer with 100 ms and stop it when the validation gets 1.
If the timer fires then you stop.

No need for a loop or anything like that.

Cheers,
_

mikrocat
13th November 2015, 14:35
QTimer *TimerForReadingFromPort = new QTimer;
TimerForReadingFromPort->setSingleShot(true);


serialPort.write(dataToSend);
TimerForReadingFromPort->start(100);
QApplication::processEvents();
if(validationFlag == 1){
TimerForReadingFromPort->stop();
//analyze response
...
response.clear();
}
else if(TimerForReadingFromPort->remainingTime() == 0){
....
return;
}

You mean like this? I don't know how this should work (it doesn't). The function when the Timer times out doesn't get called...

anda_skoa
13th November 2015, 16:37
There is no need for calling processEvents() or the other stuff.

Connect the timer's timeout() signal to a slot.

Stop the timer when handleResponse() returns 1.

Cheers,
_

mikrocat
16th November 2015, 09:18
QTimer *TimerForReadingFromPort = new QTimer;
TimerForReadingFromPort->setSingleShot(true);
TimerForReadingFromPort->setInterval(100);



...
connect(TimerForReadingFromPort,SIGNAL(timeout()), this,SLOT(handleTimeout()));
connect(this,SIGNAL(readCompleteFrame()),TimerForR eadingFromPort,SLOT(stop()));
...
serialPort.write(dataToSend);
TimerForReadingFromPort->start();

if(validationFlag == 1){
//analyze response
...
response.clear();
}


readCompleteFrame is emitted when handleResponse returns 1 and stops the Timer.

anda_skoa
16th November 2015, 10:09
readCompleteFrame is emitted when handleResponse returns 1 and stops the Timer.

Ok. You could also just have stopped the timer.



Because the function to stop the timer gets never called.
So what happens?
You get a timeout but never get into handlePortReadyRead()?
Or you get into handlePortReadyRead() but never into analyzeFrame()?
Or you get into analyzeFrame() but handleResponse() never return 1?

Cheers,
_

mikrocat
16th November 2015, 13:37
Okay this is working now. But now I have following problem:

I have a loop in which i read lines from a file and send it to my device.



while(!Line.isEmpty()){
....
SerialPort.write(dataToSend);
TimerForReadingFromPort->start();


Line = nextLineFromFile();
ProgressValue += Line.size()+3;
setProgressvalue(ProgressValue);
}

So how do i wait for the lines get read from the port before I continue the process?

Lesiok
16th November 2015, 14:20
Remeber that serial port is only a pipe. Physical reading has no connection to the logical structure of the transmitted data.
You must define a protocol which will clearly divided transmitted data into records.

mikrocat
16th November 2015, 14:28
The protocol is already defined

anda_skoa
16th November 2015, 14:59
So how do i wait for the lines get read from the port before I continue the process?
You just don't use a loop.

Instead you process the next line whenever you know that the previous one has completed.

So a very simple function that reads one line, updates progress, sends the line and starts the timer.
You call that when you start the whole process and in the response handler when you know that you can now send the next line.

Cheers,
_

mikrocat
17th November 2015, 11:53
New problem:
When i click at the ui while the process the Timer times out, I can't click my ui anymore but the process is still going on til its finished.

anda_skoa
17th November 2015, 12:27
That is very strange.

Maybe you could post the current state of your code? There have been many iterations since the initial post and it is not at all clear what the current state is.

Cheers,
_

mikrocat
17th November 2015, 12:54
Hm okay I will try



TimerForReadingFromPort = new QTimer();
TimerForReadingFromPort->setSingleShot(true);
TimerForReadingFromPort->setInterval(100);


got Response is emitted when validatioFlag turns 1, means when I build a valid answer from what i read from the port.
handleTimeOut opens a MessageBox that says "No Connection" (which appears when i click on the ui).
Slot getDevicetype() analyses the data read from port. if this was successfull i disconnect gotResponse from the slot and call the next function for reading from the port.


...
connect(TimerForReadingFromPort,SIGNAL(timeout()), this,SLOT(handleTimeOut()));
connect(this,SIGNAL(gotResponse()),this,SLOT(getDe vicetype()));

...
serialPort.write(dataToSend);
TimerForReadingFromPort->start();




void Proccess::getDevicetype(){
... //analysig response
disconnect(this,SIGNAL(gotResponse()),0,0);
jumpToBootloader();
}


void Proccess::jumpToBootloader(){
connect(this,SIGNAL(gotResponse()),this,SLOT(clear Response()));
...
serialPort.write(dataToSend);
TimerForReadingFromPort->start();
}

and so on.

anda_skoa
17th November 2015, 14:16
That looks sensible.

Have you tried explicitly stopping the timer when gotResponse is emitted?
E.g. something like


connect(TimerForReadingFromPort,SIGNAL(timeout()), this,SLOT(handleTimeOut()));
connect(this,SIGNAL(gotResponse()),TimerForReading FromPort, SLOT(stop()));

I.e. each gotResponse() would first stop the timer.

Not sure why clicking the UI would get you into a timeout situation, but maybe the thing you do upon clicking takes longer than allowed for the timeout?

Cheers,
_

mikrocat
17th November 2015, 15:10
That looks sensible.


Yes It is.

Yep that's the way it works. The Timer gets stopped, when the gotResponse() Signal is emitted.

Thought this is the way you told me to do it. I don't know how it should work else...