PDA

View Full Version : how to i synchronize serial read and write without using thread?



pooch
22nd January 2014, 11:44
I am using qextserialport library for my serial communication. The thing i do is write to serial every 3 seconds. I have used timer that timeouts every 3 seconds and calls a slot for writing. Also i write to serial port on some button clicks. But sometimes my gui freezes may be due to collision between these write commands, not sure though. How do i synchronize this. is there any way of doing it?

anda_skoa
22nd January 2014, 13:36
If you have one thread it can only do one thing at a time, it is synchronized by default.

The event loop can either execute the slot connected to the timer's signal or the slot connected to the button's signal.

Maybe your freeze is a call blocking, e.g. the write call because there is a limited buffer and it is full, or something like that.

Cheers,
_

pooch
22nd January 2014, 15:11
Thanx. Your comments are clear to me. Is there anyway i could block the other events from processing until my current event is being processed? May be this could solve my problem.For example:if my timer timeouts, and its corresponding write code executes and if user presses a button, it would block the processing of the button click event until the previous code is complete?

anda_skoa
22nd January 2014, 16:03
That happens automatically. While the timeout is being processed, the main thread is doing that processing. So it can go into the event loop and start processing the user interaction with the button.

Cheers,
_

pooch
23rd January 2014, 06:03
If the processing of timeout is handled first, and then my button click is responded, why does it take a lot of time. Sometimes, my GUI freezes and shows not responding.This usually happens when i click my ui pushbutton while the timer event is running. Is there a way i could control it. I have read somewhere about queuing the events like QApplication::processEvents(QEventLoop::ExcludeUse rInputEvents); could work for me or not?

ChrisW67
23rd January 2014, 08:20
If you need processEvents() you are likely to be doing something wrong. Why not post some code so we do not have to guess what you are actually doing?

pooch
24th January 2014, 08:54
here are some portion of my code:

//MaiWindow.cpp


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer_for_read=new QTimer(this); //this timer is used for calling continuous_monitor()
QObject::connect(timer_for_read,SIGNAL(timeout()), this,SLOT(continuous_monitor()));
QObject::connect(timer_for_read,SIGNAL(timeout()), timer_for_read,SLOT(start()));//didnt know ways to restart timer again.
start_check[0]=0;

}
void MainWindow::on_Start1_clicked()
{
if(!modbus_master.port_init)
modbus_master.init_port();
modbus_master.data_buffer.Reset();//these are for data
modbus_master.data_buffer.Append(50);
while (modbus_master.CheckBusy());
modbus_master.WriteOutputReg(10,1000);
start_check[0]=1;
qDebug()<<timer_for_read->isActive();
if(!timer_for_read->isActive())
timer_for_read->start(5000);
}
void MainWindow::continuous_monitor()
{
QApplication::processEvents(QEventLoop::ExcludeUse rInputEvents);//dint know where to do this
if(start_check[0]){
while(modbus_master.CheckBusy());// this checks whether the code is listening to response, returns 1 when listening is done
modbus_master.ReadInputReg(10,1000,4);// reads input register// this writes a message to serial port and listens to response
}
if(start_check[1]){
while(modbus_master.CheckBusy());
modbus_master.ReadInputReg(10,1000,4);
}
}


//ModbuMaster.cpp


ModbusMaster::ModbusMaster()
{
timer=new QTimer(this);
QObject::connect(timer,SIGNAL(timeout()),this,SLOT (onTimeOut()));// onTimeout asserts that the response is invalid
QObject::connect(this,SIGNAL(WriteEmit(char*)),thi s,SLOT(writeData(char*)));
port=new QextSerialPort();
QObject::connect(port,SIGNAL(readyRead()),this,SLO T(readData()));
}

void ModbusMaster::readData()
{
qDebug("read data");
QApplication::processEvents(QEventLoop::ExcludeUse rInputEvents);
port->flush();
// char buff[1024];
// qDebug("read data");
QByteArray response=port->readAll();
for(int i=0;i<response.length();i++)
{
ReadCharacterCB((uint8_t)response[i]); //this function has intrepretation of data
}
}
void ModbusMaster::writeData(char* msg)
{
//qDebug("Writing data");
port->write(msg,1);
port->flush();

}

anda_skoa
24th January 2014, 09:09
First, remove those QApplication::processEvents() that you have right now, they are not needed there.
They currently are in the beginning of slots that are called by the event loop, so there is no point in returning to the event loop again right away.

Second, you don't need the connect of the timer_for_read to its own slot. A QTImer which has not been put into single shot mode will fire continuously on its own.

My guess on your blocking problem are the two while loops. Those obviously keep the main thread spinning in there as long as the condition is true.
Since you are already executing them in a slot that is called regularily, maybe just return if the condition is not true?

I.e.


void MainWindow::continuous_monitor()
{
if(start_check[0]){
if(!modbus_master.CheckBusy()) return;// this checks whether the code is listening to response, returns 1 when listening is done
modbus_master.ReadInputReg(10,1000,4);// reads input register// this writes a message to serial port and listens to response
}
if(start_check[1]){
if(!modbus_master.CheckBusy()) return;
modbus_master.ReadInputReg(10,1000,4);
}
}


Cheers,
_

pooch
24th January 2014, 09:48
I have replaced the while loops with if, but what i observe is the code will now never read the input register. It just skips that part. Also the readyRead signal is not fired at all when i send data using my virtual serial(realterm). I think i am confused between my own stuffs.
Ok, i'll explain the total motive of my project.
what i have to do is:
Write to serialport when buttons are clicked. Also write to serialport continuously every few seconds and receive their response, intrepret it and display in my gui. It seems like i dont get any response. or there's something else wrong. do my readyRead and timer signals interfere with each other?

anda_skoa
24th January 2014, 14:45
The condition is probably the wrong way around. Try


if(modbus_master.CheckBusy()) return;


Not sure why you need that at all, the class seems to be using an event driven I/O (QExtSerialPort) so there should be signals when it becomes read for whatever you are checking.

Cheers,
_

pooch
27th January 2014, 07:32
I remove that part completely, it just works fine. Thanks.