PDA

View Full Version : serial port programming in qt



sar_van81
4th May 2007, 06:02
hi ,

i need to develop an application in qt such that it reads the datas whenever data comes from the serial port.Can i use QFile for this ? or is there any other classes.

thanks in advance,

saravanan

marcel
4th May 2007, 06:33
No, but check:

http://www.qtcentre.org/forum/f-qt-programming-2/t-serial-port-communication-5209.html
http://www.qtcentre.org/forum/f-qt-programming-2/t-serial-port-access-in-qt-4090.html

regards

sar_van81
4th May 2007, 08:59
yeah , i googled regarding that and i also downloaded the Qextserial package and compiled that for my linux box too. but after that i dnt know how to use it ? i mean there is no executables created. there are only libraries created.i dnt know what to do with that created libraries. i also checked in the link you sent. there only for windows version of qextserial port is given.


can anybody say me how to use it ?

marcel
4th May 2007, 09:14
QExtSerial is a library which you can use in your application.
I did not used it, but they should have API documentation on their site.

Probably you will have to include some headers and the port initialization and communication should be pretty straightforward.

regards

sar_van81
5th May 2007, 07:18
hi,

i had downloaded and compiled that for my host. But there are only library files created. also after there is no documentation explaining as how to use this with the qt or qwt package. i mean what should be done with this library etc? so i tried my own way. the following is my code:

sample::sample()
{
mouse=open("/dev/ttyS0",O_RDONLY | O_NDELAY);
cout<<" mouse:"<<mouse<<endl;

QSocketNotifier *note;
note =new QSocketNotifier(mouse,QSocketNotifier::Read,this);
connect(note,SIGNAL(activated(int)),this,SLOT(data ()));
}

void sample::data()
{
n=read(mouse,buffer,1);
printf("n:%d\n",n);
for(int i=0;i<n;i++)
printf("buffer:%d\t",buffer[i]);
cout<<"end of reading"<<endl;
}.
this is working when i send some characters from another system connected to this serial port. but when i connect a device to the serial port. the datas are not read successfully. The characteristics of the device is this: it will send some 5 byte data to the serial port. i need to read that datas as soon as it comes in the serial port.


can anyone say me why is that when we i enter the datas are read correctly and when a device sends its not recieved correctly?

can anyone provide me suggestions or solutions for this ?Am i correct ? or is there anyother way for reading the serial port as the datas come ? also if anyone knows how to use the qextserial can you send me the links or docs regarding that ?

gadnio
5th May 2007, 11:55
I still can't get it why you aren't using syscalls for this issue. I haven't programmed any sockets/ports in Windows, but I can give you enough hints for any posix-complient environment (unixes: aix, hpux, etc., linux, *bsds, probably mac os).

If you want to attatch to a device, use the open() function to open the file (the old Unix filosophy that everything is a file works perfectly here).
To read some data, use read().
To poll for available data, use select().
To close the buffer when it's not available anymore, use close().
There is a nice example of using select in its manual page, at least for a linux environment.

I do usually wrap the logic using external devices in separate threads and communicate with signals (Qt4's emit is thread-safe, to my knowleage). A simple example is the following:



class my_mouse_class: public QThread
{
Q_OBJECT
private:
int f_mouse;

protected:
virtual void run() //logic here. poll for data, if found, emit a signal.
{
fd_set rfds;
struct timeval tv;
int retval;

while ( isRunning() )
{
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);

/* Wait up to five microseconds. */
tv.tv_sec = 0;
tv.tv_usec = 5;

retval = select( f_mouse, &rfds, NULL, NULL, &tv );
/* Don’t rely on the value of tv now! */

if ( retval == -1 )
{
perror( "select()" );
}
else
{
if ( retval )
{
printf( "Data is available now.\n" );
/* FD_ISSET(0, &rfds) will be true. */
emit data_available();
}
else
{
printf( "No data within five seconds.\n" );
}
}
}
}

public:
/**
Basic constructor, tries to open the device.
*/
my_mouse_class( QObject * parent ): QThread( parent )
{
f_mouse = open( "/dev/mouse", O_RDONLY );
if ( f_mouse < 3 ) // 1 and 2 are standart output and error output
{
throw DeviceException( "my_mouse_class::my_mouse_class(): Mouse not available." );
}
}

~my_mouse_class()
{
if ( f_mouse > 2 ) //sanity check
{
close( f_mouse ); //close the file descriptor
}
}

//read some data
ssize_t read( void * buffer, ssize_t count )
{
return ::read( f_mouse, buffer, count );
}

signals:
void data_available();
};


I have omitted the headers since they could be retrieved upon issuing the help on each of the functions, presenting in its dedicated manual page (for example, to read the full help of select, use "man select"). Please note that the above example contains code from the glibc's manual page, which is licensed under LGPL, so if you are using it in a commersial application, please modify it.

sar_van81
5th May 2007, 11:58
hi everyone ,

i had compiled my application with the qextserialport package by specifying the INCLUDEPATH and LIBS in the project file(".pro"). but when i execute it , it says "Segmentation fault " error.

can anyone provide me any suggestions or solutions for this ?

marcel
5th May 2007, 12:34
segfaults are caused by very bad mistakes in code :). So we need to see the code before we can give you a solution.

b1
6th May 2007, 05:34
sar_van81

For what its worth I have used QextSerialPort and it works well.
Below is the snippet of code used to setup the port. "portname1" is determined by the OS being used at the time.

Hope this is of some use to you....



void Progarm::setupSerial()
{
serialPort = new QextSerialPort( portname1 );
serialPort->setBaudRate( QextSerialPort::BAUD9600 );
serialPort->setDataBits( QextSerialPort::DATA_8 );
serialPort->setStopBits( QextSerialPort::STOP_1 );
serialPort->setParity( QextSerialPort::PAR_NONE );
serialPort->setFlowControl( QextSerialPort::FLOW_OFF );
serialPort->setTimeout( 0, 500 );
serialPort->open( QIODevice::ReadWrite);
if (!serialPort->isOpen() )
{
QMessageBox::warning( this, "Connection Error",
"Could not open the serial port\n"
"\n"
"Please check connections and try again\n" );
label->setText( "Serial port error" );
return;
}
}


Regards, B1.

sar_van81
7th May 2007, 05:37
B1:

the following is my code:


Widget::Widget( QWidget *parent, const char *name )
: QWidget( parent, name )
{
setMinimumSize(640,480 );
Posix_QextSerialPort *note= new Posix_QextSerialPort("/dev/ttyS0");
note->setBaudRate(Posix_QextSerialPort::BAUD115200);
note->setParity(Posix_QextSerialPort::PAR_NONE);
note->setDataBits(Posix_QextSerialPort::DATA_8);
note->setStopBits(Posix_QextSerialPort::STOP_1);
note->open(IO_ReadOnly);
int n;
n=note->bytesWaiting();
if(n!=0)
printf("\nreading the buffer datas \n");

}
.
Also can you say me how to read the datas from the serial port . i saw that only int Posix_QextSerialPort::getch() is available. is there any function to read a block of datas for example say 10bytes ?

saravanan

b1
7th May 2007, 06:07
sar_van81,

This is what I use in a simple app...bear in mind I am still learning too!!



void Program::dataListener()
{
// see how many bytes available from the serial port
rec = serialPort->bytesAvailable();
if (rec > 0 )
{
if ( rec > 256 ) rec = 256;
z = serialPort->read( buffer, rec);
buffer[z] = '\0';
tempmsg = buffer;
}
dispData();
}


There may be (and probably are!) better ways of doing this but for me it did what I wanted. You can also use serialPort->getChar(buffer) and read the serial port character by character and then process the buffer accordingly.

Hope this helps.

B1.

sar_van81
7th May 2007, 07:55
B1:

Ok. let me try this.but the application does not open successfully.it prompts me for "segmenattion fault error".if i comment the following lines:


Posix_QextSerialPort *note= new Posix_QextSerialPort("/dev/ttyS0");
note->setBaudRate(BAUD115200);
note->setParity(PAR_NONE);
note->setDataBits(DATA_8);
note->setStopBits(STOP_1);
note->open(IO_ReadOnly);
.

the program executes successfully. Did you experience any problem like this ?

Am i missing some thing more ?

high_flyer
7th May 2007, 09:00
Why are you commenting out these lines? with out them you don't have an initialized serial port objet.
Also, QextSerialPort is made crossplatform, so you don't need to explicitly use Posix_QextSerialPort (this wont compile under windows) - there are defines in the code that will select the correct version for you.
Just use QextSerialPort.

sar_van81
7th May 2007, 09:30
high_flyer:

if i use QextSerialPort instead of Posix_QextSerialPort, it shows me the following error:

home/qtprograms/qwt/qextserial/qextserialport-0.8.0/win_qextserialport.h:11:21: error: windows.h: No such file or directory
/home/qtprograms/qwt/qextserial/qextserialport-0.8.0/win_qextserialport.h:57:7: warning: no newline at end of file
In file included from tux.cpp:21:
/home/qtprograms/qwt/qextserial/qextserialport-0.8.0/qextserialport.h:26:7: warning: no newline at end of file
/home/qtprograms/qwt/qextserial/qextserialport-0.8.0/win_qextserialport.h:50: error: ‘HANDLE’ does not name a type
/home/qtprograms/qwt/qextserial/qextserialport-0.8.0/win_qextserialport.h:51: error: ‘COMMCONFIG’ does not name a type
/home/qtprograms/qwt/qextserial/qextserialport-0.8.0/win_qextserialport.h:52: error: ‘COMMTIMEOUTS’ does not name a type
make: *** [tux.o] Error 1
.
So only i used Posix_QextSerialPort. Should i define somewhere about _TTY_POSIX ? Also as i said before when i include them in my code its prompting me segmentation fault.

high_flyer
7th May 2007, 09:39
So only i used Posix_QextSerialPort. Should i define somewhere about _TTY_POSIX ?
Exactly - You should add DEFINES += _TTY_POSIX in your pro file (or if you are using KDevelop it has a field for that in the qmake configuration).

sar_van81
7th May 2007, 10:04
high_flyer:

that parameter has already been set when i untar the qextserial package. should i specify that in my application pro file ?

Let me explain what i have done so far :

1). Downloaded the qextserial package , untarred and entered qmake ,make. there were the following libraries created:
libqextserialport.so libqextserialport.so.1 libqextserialport.so.1.0 libqextserialport.so.1.0.0

2). Then created a directory ,copied my source files. entered the header files and the libraries for qextserial in my project file. then entered make.

is this procedure correct ? else can you say me the correct one ?

high_flyer
7th May 2007, 10:26
should i specify that in my application pro file ?
yes.

is this procedure correct ? else can you say me the correct one ?
It should work.
But I would not copy the header files and libs, I would link to them or user the -L and -I in my make file.
But that is a subjective private taste matter, your way should work just as well.

sar_van81
7th May 2007, 10:42
hi ,

i specified in my project file also and it compiled successfully.but still the same error comes . Is there any permission i need to set to serial port ? i'l post my full code here if any one find any error please point me :


#include <qwidget.h>
#include <qapplication.h>
#include <stdlib.h>

#include <qextserialport.h>

class Widget : public QWidget
{
public:
Widget( QWidget *parent=0, const char *name=0 );
private:
int mouse;
int mouseidx;
};

Widget::Widget( QWidget *parent, const char *name )
: QWidget( parent, name)
{
setMinimumSize(640,480 );

QextSerialPort *note= new QextSerialPort("/dev/ttyS0");
note->setBaudRate(BAUD115200);
note->setParity(PAR_NONE);
note->setDataBits(DATA_8);
note->setStopBits(STOP_1);
note->open(IO_ReadOnly);
}

int main( int argc, char **argv )
{
QApplication a( argc, argv );
Widget connect1;
a.setMainWidget( &connect1 );
connect1.show();
return a.exec();
}

high_flyer
7th May 2007, 10:58
compiled successfully.but still the same error comes .
I guess you mean the segmentation fault.

Your code has the following problems:

QextSerialPort *note= new QextSerialPort("/dev/ttyS0");
You are allocating the serial port on to a local pointer.
You will not be able to access the serial port outside the constructor.
'note' needs to be a member variable.

Where is the code that handels the reading/writing to the serial port?

sar_van81
7th May 2007, 11:41
theLSB:
I did not add the read/write operation. i thougth first let me open the port sucessfuly. then,read that.


'note' needs to be a member variable
Do you mean that i need to declare it under protected and use it in the constructor ?

high_flyer
7th May 2007, 12:19
Do you mean that i need to declare it under protected and use it in the constructor ?

No, you need to declare it as a member variable.
Do you know what a member variable is?


class Widget : public QWidget
{
private: //depends on your needs, this can be any access mode
QextSerialPort *m_note;
public:
Widget( QWidget *parent=0, const char *name=0 );
private:
int mouse;
int mouseidx;
};

Widget::Widget( QWidget *parent, const char *name )
: QWidget( parent, name),
m_note(NULL)
{
setMinimumSize(640,480 );

m_note= new QextSerialPort("/dev/ttyS0");
if(note)
{
m_note->setBaudRate(BAUD115200);
m_note->setParity(PAR_NONE);
m_note->setDataBits(DATA_8);
m_note->setStopBits(STOP_1);
m_note->open(IO_ReadOnly);
}
}

sar_van81
7th May 2007, 12:56
high_flyer:

yeah i did as you said. i tried both the ways-private or protected. But no use.:(

high_flyer
7th May 2007, 13:12
But no use.
Could you be a bit more descriptive?
The access mode has nothing to do with it.

sar_van81
7th May 2007, 13:37
first i tried declaring the Qextserialport as a private member variable, compiled and when i rum the same error came. next i tried declaring it as protected member variable, the same thing happened.

high_flyer
7th May 2007, 13:44
what error? segmentation falut?
Are there any other methods do the Widget class?
Try setting debug messages along the code or run in a debugger and see where the applciation crashes.

EIDT:
Wait, in the code I edited for you, your should change all 'note' instances to 'm_note' did you do that?

sar_van81
7th May 2007, 13:56
Hi,

i solved that problem. i did not declare it in the heap.The following is what i did:


QextSerialPort note("/dev/ttyS0");
note.setBaudRate(BAUD115200);
note.setParity(PAR_NONE);
note.setDataBits(DATA_8);
note.setStopBits(STOP_1);
note.open(IO_ReadOnly);

With this the application opens without segmentation fault. Now i'm finding out how to read the datas ? the suggestion b1 gave did not work out as there is no member function called read in the Qextserialport.

Anyway thanks a lot for all of your kind response .

high_flyer
7th May 2007, 14:01
What you did is no good.
The serial port gets created on the stack, and dies when the constructor ends.
Use the code I gave you.

sar_van81
7th May 2007, 14:34
high_flyer:

Oops. it still not working. This is my code:

ConnectWidget::ConnectWidget( QWidget *parent, const char *name )
: QWidget( parent, name),m_note(NULL)
{
setBackgroundColor( white );
setMinimumSize(640,480 );

m_note= new QextSerialPort("/dev/ttyS0");
if(m_note)
{
m_note->setBaudRate(BAUD115200);
m_note->setParity(PAR_NONE);
m_note->setDataBits(DATA_8);
m_note->setStopBits(STOP_1);
m_note->open(IO_ReadOnly);
}
printf("\n serial port openned \n");
}

Is this what you suggested?

high_flyer
7th May 2007, 14:36
what error? segmentation falut?
Are there any other methods do the Widget class?
Try setting debug messages along the code or run in a debugger and see where the applciation crashes.
And please use code tags.

sar_van81
8th May 2007, 05:17
Sir,

I modified the code. Now i have onely three lines in my code:



class ConnectWidget : public QWidget
{
public:
ConnectWidget( QWidget *parent=0, const char *name=0 );
private:
QextSerialPort *m_note;
};
ConnectWidget::ConnectWidget( QWidget *parent, const char *name )
: QWidget( parent, name),m_note(NULL)
{
setMinimumSize(640,480 );
m_note= new QextSerialPort("/dev/ttyS0");
printf("\n serialport openned \n");
}

I have not added the settings of the serial port.As i found that starting from this line the error pops up. the following is the error message:

suse:/home/qtprograms/roughserial # ./roughserial -qws
Connected to VFB server: 640 x 480 x 32
Segmentation fault
suse:/home/qtprograms/roughserial #

sar_van81
8th May 2007, 06:09
Hi B1,

DId you experience any segementation problem in creating the serialport in heap like mine ? i tried your way of declaring also ? but i still could not make it ?

high_flyer
8th May 2007, 09:28
I have not added the settings of the serial port.As i found that starting from this line the error pops up.
Do you mean that the program crashes on:
m_note->setBaudRate(BAUD115200); ?

This code should run.
How did you discover on which line the program crashes, what method did you use to debug?

sar_van81
8th May 2007, 09:41
high_flyer:

No , the program crashes in the first line itself. i mean :

m_note= new QextSerialPort("/dev/ttyS0");

I had only this line in my constructor ( as i had posted in the above post). i did not have any other line.

high_flyer
8th May 2007, 09:49
I had only this line in my constructor ( as i had posted in the above post). i did not have any other line.
You mean the only line of code in ConnectWidget constructor right?
Does it run if you remove that line as well?
Does it run when this construcotr is empty?
Are you sure you are not trying to use a 'note' or 'm_note' somehwere else in your code?
It would be good if you could post you mail() function.
The problem in your code is not the parts we currently see.
Ofcourse there is also the chance that the QextSerialPort lib is faulty for some reason on your system.

sar_van81
8th May 2007, 10:37
yeah, it runs if i comment that line and place a printf there.And i'm sure i dont use that anywhere in my code.

It would be good if you could post you mail() function.I have not used any thing like this function .

Also i'm using qextserialport-0.8.0 package since only this supports qt-3.3.5 version. remaining packages such as qextserialport-0.9.0,1.0,1.1 supports higher versions of qt. will there be any problem with this version changes ?

high_flyer
8th May 2007, 10:47
I have not used any thing like this function .
Sorry, I meant main().


yeah, it runs if i comment that line and place a printf there.And i'm sure i dont use that anywhere in my code.
Hmm... then from what you have said so far, it all points to a problem in your QextSerialPort lib.

Also i'm using qextserialport-0.8.0 package since only this supports qt-3.3.5 version. remaining packages such as qextserialport-0.9.0,1.0,1.1 supports higher versions of qt. will there be any problem with this version changes ?
What do you mean?
using a Qt4 QextSerialPort with Qt3?
That wont work.

sar_van81
8th May 2007, 11:03
The following in my main():


int main( int argc, char **argv )
{
QApplication a( argc, argv );
ConnectWidget connect1;
a.setMainWidget( &connect1 );
connect1.show();
return a.exec();
}


What do you mean?
using a Qt4 QextSerialPort with Qt3?
That wont work.
No i mean i'm using qt-3.3.5 version and the other versions of qextserialport requires header and libraries of qt 4 or greater version.

high_flyer
8th May 2007, 11:15
Well, from what I can see, there is no problem with the code it self.

You can only link QextSerialPort for Qt3 (which is linked against Qt3) with Qt3 applications.
You can only link QextSerialPort for Qt4 (which is linked against Qt4) with Qt4 applications.

sar_van81
8th May 2007, 12:28
yeah as you said the code is right. and qextserialport package is used is also correct i think. i mean(for qt-3.3.5 package i used qextserialport-0.8.0 package).

I think they may have updated these features in the latest versions.And i'm linking qt3 application with qt3 package only.

high_flyer
8th May 2007, 12:35
And i'm linking qt3 application with qt3 package only.
That is the way it should be.

Strange.:confused:

sar_van81
8th May 2007, 12:51
hi,

i did by using linux syscalls.I used these codes in my qt application. but the i could not get the output i desired. Thats what i went for this package. but this also did not work. :( Looking for some other way..:confused:

high_flyer
8th May 2007, 13:03
Are you working with Qt or QTopia?

sar_van81
8th May 2007, 13:24
I'm working with qt-embedded -3.3.5 version.

high_flyer
8th May 2007, 13:35
I'm working with qt-embedded -3.3.5 version.
It could be the reason this is not working, since it could be that the low level port handling is diefferent on your embeded system.

high_flyer
8th May 2007, 13:40
In the docs of QexstSerialPort 0.70:

Posix_QextSerialPort::Posix_QextSerialPort ( )


Default constructor. Note that the name of the device used by a QextSerialPort constructed with this constructor will be determined by defined constants, or lack thereof - the default behavior is the same as _TTY_LINUX_. Possible naming conventions and their associated constants are:

Constant Used By Naming Convention
---------- ------------- ------------------------
_TTY_WIN_ Windows COM1, COM2
_TTY_IRIX_ SGI/IRIX /dev/ttyf1, /dev/ttyf2
_TTY_HPUX_ HP-UX /dev/tty1p0, /dev/tty2p0
_TTY_SUN_ SunOS/Solaris /dev/ttya, /dev/ttyb
_TTY_DIGITAL_ Digital UNIX /dev/tty01, /dev/tty02
_TTY_LINUX_ Linux /dev/ttyS0, /dev/ttyS1
<none> Linux /dev/ttyS0, /dev/ttyS1

This constructor assigns the device name to the name of the first port on the specified system. See the other constructors if you need to open a different port.
You might try one of these defines, in case your system is compatible with one of them.

And next time post QTopia questions under the QTopia forum.

jagdeep
13th June 2007, 12:17
hello dear all,
will anybody pls post any working qt3 example of qextserial.


thanks in advance

high_flyer
13th June 2007, 12:27
see post 21 in this thread.
It is an example for Qt4, but the differences are minimal, or none.
With reading the docs this example is more then enough to get started.