You are not logged in.

1

Sunday, May 17th 2009, 5:12pm

QextSerial and ReadLine

Hello,

I'm using the QextSerial to receive ascii lines from a serial connection. Even if the documentation seems to be broken (a lot of file are not found) I'm able to set and open the serial port and to receive some data.

What I can't do is generate en event when a new line is ready to read.

I set the serial port like this:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
serial = new QextSerialPort();
serial->setBaudRate(BAUD9600);
serial->setParity(PAR_NONE);
serial->setDataBits(DATA_8);
serial->setStopBits(STOP_1);
serial->setFlowControl(FLOW_OFF);
serial->setQueryMode(QextSerialPort::EventDriven);
serial->setPortName(cboSerial->currentText());
if (!serial->open(QIODevice::ReadOnly)) {
 	   QMessageBox msgBox;
	msgBox.setText("Warning: COM port is unavailable.");
	msgBox.setIcon(QMessageBox::Critical);
	msgBox.exec();
}         
connect(serial, SIGNAL(readyRead()), this, SLOT(Receive()));


The Receive slot should handle incoming data:

Source code

1
2
3
char data[64];
int bytesRead = serial->readLine(data, 64);     
txtRx->setText(data);



But I get corrupted lines, that is it doesn't read whole lines. I guess because the readyRead signal is emitted when some data is available and the readLine return just what is into the buffer, but it doesn't wait for the newline.
I tried to check the canReadLines (not documented) but with no effect.

What should I do to make the trick?

Thanks
Marco Trapanese
italy

2

Sunday, May 17th 2009, 8:33pm

Source code

1
txtRx->setText(data);

See QString constructors. It expects that data is null terminated c string ('\0' at the end).

I would think about such scheme.
in Receive slot
I. Append data which are available in QIODevice to class variable QByteArray. Don't use readLines. Use QIODevice methods readAll or read or whatever.
II. Examine QByteArray if it contains \n (or \r) (or 0 if string is null terminated) then output/process the chunk else wait for more data. Remove the chunk with the line delimiter.
Fighting fire with fire.
Three can keep a secret if two of them are dead.

3

Sunday, May 17th 2009, 10:26pm

I ended up with this code:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
int start, stop
if (rx.length() < 128)  	       
	rx.append(serial->read(32));     
else 	
	rx = serial->read(32); 
    start = rx.indexOf("$"); 
    if (start == -1) return;     
stop = rx.indexOf(0x0A);     
if (stop == -1) return;     
if (stop - start < 25) return;     
data = rx.mid(start, stop - start - 1);     
rx = rx.mid(stop + 1);


Incoming data has a length of about 26/27 chars.
I don't like very much this code, but it works fine though.

How could I improve it?

Thanks again
Marco

4

Monday, May 18th 2009, 5:51am

Of course everything depends on the protocol.
I think if the device comunicate in multiple sentences (lines) then there is no need to concentrate on the message length.
I would think about something like (I have not the device, I have not the protocol - not sure it is ok, not sure its better)

Source code

1
2
3
4
5
6
7
8
9
10
11
12
rx.append(serial->readAll());
int start, stop;
while ((stop = rx.indexOf(0x0A)) != -1) // analyze while has stop.
{
    start = rx.indexOf('$');
    if (start != -1)
    {
         data = rx.mid(start, stop - 1);
         // process data
    }
    rx = rx.mid(stop + 1);
}
Fighting fire with fire.
Three can keep a secret if two of them are dead.

5

Monday, May 18th 2009, 7:56am

Thank you for your answer!
The protocol is simple: start with $ and end with \r\n (like NMEA sentences for example).
I checked the length of the packed and also of the rx buffer because if the user connects other devices with another protocol the buffer itself will grow dramatically.

Anyway Your code works fine but I can't use the readAll method it returns garbage data. I must use read(i) one instead.

Marco

6

Monday, May 18th 2009, 10:47am

I found out the issue: it always receive garbage data since I don't open the same port with another terminal (e.g. hyperterminal).
In other words:

1) run my program -> get garbage data
2) run hyperterminal
3) run my program -> all works fine

Of course, I double checked the serial port settings and they seem ok.
Are there any initialization one should do before receive any data?

Marco

7

Monday, May 18th 2009, 12:18pm

Where do you see setQueryMode? http://qextserialport.sourceforge.net/qextserialport-1.1.x/
If you use alpha then expect that it works so. Try 1.1 version. Post questions, bugs to the project developers but I see it is not developed since 2007.
Well you can search for any third party library for serial port or develop the QextSerialPort library.
Fighting fire with fire.
Three can keep a secret if two of them are dead.

8

Monday, May 18th 2009, 3:57pm

Yes I use 1.2 because it more recent. Anyway, I'll try the older one.
It's a pity that QT4 doesn't have a serial port library. In my project I use often multiple serial ports so I need a reliable library.

I give it another try and I'll post here the result. If it doens't work I do need another way.

Thanks for your patience!
Marco

9

Wednesday, May 20th 2009, 12:29pm

Yes I use 1.2 because it more recent. Anyway, I'll try the older one.
I can't use the 1.1 because it misses a lot of useful features:

Quoted

Version 1.2win alpha (this version has some major improvements but mostly for Windows)
+ Added QextSerialEnumerator pre-alpha. Works under W2k and later versions of Windows.
+ Event driven mechanism (alternative to polling) is now available on Windows.
- Removed default (=0) parameter from open() functions.
* Fixed bug #1714917 in Win_QextSerialPort::close() method (by Kurt).
* Fixed problem with lack of proper blocking in readData() on win32 (by Brandon Fosdick).
* Removed QT_THREAD_SUPPORT option. Now QextSerialPort must be always compiled with threads support.
* Mutexes are not static.
* setTimeout() now accepts only one parameter.
Is there another *reliable* serial port library for QT? I can't imagine that a language used on embedded systems doesn't support serial communication!

Marco