Results 1 to 13 of 13

Thread: First attempt to display serial port data on GUI

  1. #1
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default First attempt to display serial port data on GUI

    Hi guys,

    I created this Qt Application project under VS2005, and tried to display the GPS data onto GUI---real simple. I can read the data from the serial port fine (using QExtSerialPort class) but I cant display it on the GUI for some reason. The GUI would just be non-responsive and I have to kill it. If you guys could help me out here, that'd be great. I tried to compare this to other existing tutorials I have been working on, but couldnt find anything. In particular, I simply call label->setText() to display the string :

    Qt Code:
    1. #ifndef QTAPP_H
    2. #define QTAPP_H
    3.  
    4. #include <QtGui/QMainWindow>
    5. #include "ui_qtapp.h"
    6. #include <QLabel>
    7. #include <QIODevice>
    8. #include <QString>
    9. #include <QApplication>
    10. #include <QStringList>
    11. #include <QDebug>
    12. #include <QVariant>
    13. #include <QWidget>
    14. #include "qextserialport.h"
    15.  
    16. class QtApp : public QMainWindow
    17. {
    18. Q_OBJECT
    19.  
    20. public:
    21. QtApp(QWidget *parent = 0, Qt::WFlags flags = 0);
    22. ~QtApp();
    23. void Run();
    24.  
    25. private:
    26. Ui::QtAppClass ui;
    27. QString* str;
    28. QStringList* list;
    29. QextSerialPort* port;
    30. };
    31.  
    32. #endif // QTAPP_H
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #include "qtapp.h"
    2.  
    3. QtApp::QtApp(QWidget *parent, Qt::WFlags flags)
    4. : QMainWindow(parent, flags)
    5. {
    6. ui.setupUi(this);
    7.  
    8. str = new QString;
    9. list = new QStringList;
    10. port = new QextSerialPort( "COM1" );
    11. port->setBaudRate(BAUD115200);
    12. port->setFlowControl(FLOW_OFF);
    13. port->setParity(PAR_NONE);
    14. port->setDataBits(DATA_8);
    15. port->setStopBits(STOP_1);
    16.  
    17. // Open port
    18. port->open( QIODevice::ReadOnly );
    19. }
    20.  
    21. QtApp::~QtApp()
    22. {
    23.  
    24. }
    25.  
    26. void QtApp::Run()
    27. {
    28. char data[100];
    29.  
    30. QLabel* label = new QLabel;
    31. while(1)
    32. {
    33. if( !port->bytesAvailable() ) continue;
    34.  
    35. int charIdx = 0;
    36. int bytesRead;
    37.  
    38. //
    39. // Find sync word
    40. do
    41. {
    42. data[charIdx] = 'A';
    43. port->read( data,
    44. 1 );
    45. } while( data[charIdx] != '$' );
    46. charIdx++;
    47.  
    48. //
    49. // Read the rest of the data
    50. do
    51. {
    52. charIdx += port->read( &data[charIdx],
    53. 1 );
    54. } while( data[charIdx-1] != '*' );
    55.  
    56.  
    57. // Read check sum
    58. charIdx += port->read( &data[charIdx],
    59. 2 );
    60. data[charIdx] = '\0';
    61.  
    62.  
    63. // Copy buffer to QString
    64. *str = data;
    65.  
    66. //
    67. // Diplay this on GUI
    68. label->setText( *str );
    69. }
    70. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Hey, where do you call the Run method?
    How often do you receive data from the serial port( at what intervals )?

    Best to do this is to use a thread - to handle the incoming data from the serial port. Or maybe even a QTimer will work.

    Your interface block because of the while(1) loop in Run.

    Regards

  3. The following user says thank you to marcel for this useful post:

    ShaChris23 (2nd May 2007)

  4. #3
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Hi,

    Here's where I call the Run()

    Qt Code:
    1. #include <QtGui/QApplication>
    2. #include "qtapp.h"
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. QtApp w;
    8. w.show();
    9. w.Run();
    10. a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
    11. return a.exec();
    12. }
    To copy to clipboard, switch view to plain text mode 

    The serial port data comes in at about 1 second an interval. When I used the debugger, I could see the data getting read fine, the problem is just the display part.

    My concept of label->setText(str); is just like cout or printf. At least I thought that's how it worked, but maybe not?

  5. #4
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    This is not how I would have done it, but you can make it work.

    Just add QApplication:rocessEvents() as the first line in the while(1) loop. This will make your GUI responsive and you will see data changing in the label.

    But this is not the best way to poll a serial port.

    Regards

  6. The following user says thank you to marcel for this useful post:

    ShaChris23 (2nd May 2007)

  7. #5
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Hi Marcel,

    Yup. That worked perfectly. Though I found the load on my simple application was quite high. This is a testing module only to see if I can finally display something on the GUI. The way I really design this is as follows:

    1) GUI: using Designer to create the GUI that I want, then create a MyWidget class that has this ui as its member. This class will have its slot tied to SerialPortReader thread class' signal.

    2) SerialPortReader: is a thread that emits a signal whenever the blocking port->read() gets a new value. The signal is going to indicate that its value (a QString) changed.

    Do you find the while( 1 ) a bad design? The port->read() is a blocking call, so it shouldn't consume any CLK cycles.

    Let me know what you think about this...Thanks a whole bunch. You've been extremely helpful in my first Qt adventure.

  8. #6
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Do you find the while( 1 ) a bad design? The port->read() is a blocking call, so it shouldn't consume any CLK cycles
    yes, the while(1) loop is not a good solution. The processor load will be almost 1.0 all the time your app runs. Although, you will not notice any lag in the interface, because of processEvents.

    A simpler solution, that doesn't require any fancy synchronization would be:
    Qt Code:
    1. QtApp::QtApp(QWidget *parent, Qt::WFlags flags)
    2. : QMainWindow(parent, flags)
    3. {
    4. ui.setupUi(this);
    5.  
    6. str = new QString;
    7. list = new QStringList;
    8. port = new QextSerialPort( "COM1" );
    9. port->setBaudRate(BAUD115200);
    10. port->setFlowControl(FLOW_OFF);
    11. port->setParity(PAR_NONE);
    12. port->setDataBits(DATA_8);
    13. port->setStopBits(STOP_1);
    14.  
    15. // Open port
    16. port->open( QIODevice::ReadOnly );
    17. mPollTimer = new QTimer( this );
    18. mPollTimer->setInterval( 1000 ); //poll every 1 second
    19. connect( mPollTimer, SIGNAL( timeout() ), this, SLOT( updateSerialData() ) );
    20. mPollTimer->start();
    21. }
    22.  
    23. void QtApp::updateSerialData()
    24. {
    25. char data[100];
    26. QLabel* label = new QLabel;
    27. if( !port->bytesAvailable() )
    28. retrun;
    29.  
    30. int charIdx = 0;
    31. int bytesRead;
    32.  
    33. //
    34. // Find sync word
    35. do
    36. {
    37. data[charIdx] = 'A';
    38. port->read( data, 1 );
    39. } while( data[charIdx] != '$' );
    40. charIdx++;
    41.  
    42. //
    43. // Read the rest of the data
    44. do
    45. {
    46. charIdx += port->read( &data[charIdx], 1 );
    47. } while( data[charIdx-1] != '*' );
    48.  
    49.  
    50. // Read check sum
    51. charIdx += port->read( &data[charIdx], 2 );
    52. data[charIdx] = '\0';
    53.  
    54.  
    55. // Copy buffer to QString
    56. *str = data;
    57.  
    58. //
    59. // Diplay this on GUI
    60. label->setText( *str );
    61. }
    To copy to clipboard, switch view to plain text mode 

    You'll have to declare the updateSerialPort slot in your class.
    Also, declare a private member QTimer* mPollTimer, and don't forget to delete in the constructor.

    This way, you read the serial port every 1 second ( you can modify the interval ).
    This solution has one major drawback - you can loose some data. As far as I know, the serial port buffer is overwritten as soon as neew data comes in, regardless if the old data was read or not.

    This draw back can be overcome by using a thread, and storing all incoming data in a buffer. The GUI just needs to "consume" the data in the buffer.

    Regards

  9. The following user says thank you to marcel for this useful post:

    ShaChris23 (2nd May 2007)

  10. #7
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Also, if I used signal/slot, whenever I call something like:

    Qt Code:
    1. // Somewhere in my class declaration
    2. signals:
    3. stringChanged( QString string );
    4.  
    5. // ...
    6.  
    7. // Somewhere in my code
    8. QString str;
    9.  
    10. ...
    11.  
    12. emit stringChanged( str );
    To copy to clipboard, switch view to plain text mode 

    Does that string gets copied or does Qt actually use a pointer? I'm just concerned about performance because if it's a copy, and the string is really large, wouldnt that be kind of wasteful?

  11. #8
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    No, because you pass the QString parameter by value. If you're connecting to a slot in the same thread, you can pass a reference to your QString.

    Otherwise, if you connect to another thread, you must pass a pointer and also create the QString class member on the heap.

  12. The following user says thank you to marcel for this useful post:

    ShaChris23 (2nd May 2007)

  13. #9
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Hi Marcel,

    For the case of 2 different threads, did you mean that each time the SerialPort class reads a new string, we need to "new" a QString, use signal to pass the pointer, then the consumer (GUI) would display then "delete" that Qstring?

  14. #10
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    No, you just pass the same string, reinitialized. You don't delete it, just empty it. You will delete it just once, in the destructor of the worker thread.

    You only have to be careful that you don't use the pointer to the QString after you delete the worker thread.

    Regards

  15. The following user says thank you to marcel for this useful post:

    ShaChris23 (2nd May 2007)

  16. #11
    Join Date
    Apr 2007
    Posts
    62
    Thanks
    43
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    Here's my "final" implementation. It uses a thread to read data from the serial port, and sends a signal to a GUI class to slot update the value to the screen. The CPU load on this is 0-1% as the Serial Port Read is a true blocking function call.


    There are 2 remarks about this:

    1) I notice that as time goes on, the program's memory keeps increasing (I checked from Windows task manager. Not a lot, about 4 KB per minute. I couldnt think of anything that could cause this. I tried taking out the serial port Read code, and the program's size still kept increasing. Can it be because of signal/slot?

    2) I'm currently passing signal/slot by value. If somebody knows a better way of passing the QString and could show it to me, that'd be great.

    That was fun though, now I start to get a hang of it, and I'm going to start adding features.

    SerialPortReader.hpp
    Qt Code:
    1. #pragma once
    2.  
    3. #include "CSerial.hpp"
    4. #include <QString>
    5. #include <QStringList>
    6. #include <QThread>
    7.  
    8. class SerialPortReader : public QThread
    9. {
    10. Q_OBJECT
    11.  
    12. public:
    13. SerialPortReader();
    14. void run();
    15.  
    16. signals:
    17. void newString( QString string );
    18.  
    19. private:
    20. QString* str;
    21. QStringList* list;
    22. CSerial* port;
    23. };
    To copy to clipboard, switch view to plain text mode 

    SerialPortReader.cpp
    Qt Code:
    1. #include "SerialPortReader.hpp"
    2.  
    3. #include <tchar.h>
    4. #include <assert.h>
    5.  
    6. SerialPortReader::SerialPortReader()
    7. {
    8. str = new QString;
    9. list = new QStringList;
    10. port = new CSerial;
    11.  
    12. LONG stat;
    13.  
    14. stat = port->Open( _T("COM1"), 0, 0, true );
    15. assert( stat == ERROR_SUCCESS );
    16.  
    17. stat = port->Setup( CSerial::EBaud115200,
    18. CSerial::EData8,
    19. CSerial::EParNone,
    20. CSerial::EStop1 );
    21. assert( stat == ERROR_SUCCESS );
    22.  
    23. stat = port->SetupHandshaking( CSerial::EHandshakeOff );
    24. assert( stat == ERROR_SUCCESS );
    25.  
    26. stat = port->SetupReadTimeouts( CSerial::EReadTimeoutBlocking );
    27. assert( stat == ERROR_SUCCESS );
    28.  
    29. }
    30.  
    31. void SerialPortReader::run()
    32. {
    33. char data[100] = "Hey man how are you?";
    34.  
    35. while(1)
    36. {
    37. int charIdx = 0;
    38. DWORD bytesRead;
    39.  
    40. //
    41. // Find sync word
    42. do
    43. {
    44. data[charIdx] = 'A';
    45. port->Read( &data[charIdx],
    46. 1,
    47. &bytesRead );
    48. } while( data[charIdx] != '$' );
    49. charIdx++;
    50.  
    51. //
    52. // Read the rest of the data
    53. do
    54. {
    55. port->Read( &data[charIdx],
    56. 1,
    57. &bytesRead );
    58. charIdx++;
    59. } while( data[charIdx-1] != '*' );
    60.  
    61.  
    62. //
    63. // Read check sum
    64. port->Read( &data[charIdx],
    65. 2,
    66. &bytesRead );
    67. charIdx += 2;
    68. data[charIdx] = '\0';
    69.  
    70. //
    71. // Copy buffer to QString
    72. *str = data;
    73.  
    74. //
    75. // Indicate there's a new string
    76. emit newString( *str );
    77. }
    78. }
    To copy to clipboard, switch view to plain text mode 

    GUI.hpp
    Qt Code:
    1. #ifndef QTAPP_H
    2. #define QTAPP_H
    3.  
    4. #include <QtGui/QMainWindow>
    5. #include "ui_qtapp.h"
    6. #include <QLabel>
    7. #include <QString>
    8. #include "SerialPortReader.hpp"
    9.  
    10. class QtApp : public QMainWindow
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. QtApp(QWidget *parent = 0, Qt::WFlags flags = 0);
    16.  
    17. private:
    18. Ui::QtAppClass ui;
    19. SerialPortReader* portThread;
    20.  
    21. public slots:
    22. void DisplayString( QString string );
    23. };
    24.  
    25. #endif // QTAPP_H
    To copy to clipboard, switch view to plain text mode 

    GUI.cpp
    Qt Code:
    1. #include "qtapp.h"
    2.  
    3. QtApp::QtApp(QWidget *parent, Qt::WFlags flags)
    4. : QMainWindow(parent, flags)
    5. {
    6. ui.setupUi(this);
    7.  
    8. // Start a new thread
    9. portThread = new SerialPortReader;
    10.  
    11. connect( portThread, SIGNAL(newString(QString)),
    12. this, SLOT(DisplayString(QString)) );
    13.  
    14. portThread->start();
    15. }
    16.  
    17. void QtApp::DisplayString( QString string )
    18. {
    19. ui.mLabel->setText( string );
    20. }
    To copy to clipboard, switch view to plain text mode 

    UI Generated by Designer
    Qt Code:
    1. class Ui_QtAppClass
    2. {
    3. public:
    4. QWidget *centralWidget;
    5. QLabel *mLabel;
    6. QStatusBar *statusBar;
    7.  
    8. //....
    9.  
    10. }
    To copy to clipboard, switch view to plain text mode 

  17. The following user says thank you to ShaChris23 for this useful post:

    Rocken (12th March 2012)

  18. #12
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: First attempt to display serial port data on GUI

    I can't see anywhere why you get those mem leaks... Maybe I'm missing something. Anyway, you should really add destructors to your classes and delete all the pointers you allocate. You will have some leaks in the thread class.

    Anyway, why don't you just use a queue of qstrings instead of the single qstring (QQueue. You will pass a pointer to this QQueue to the main GUI, in the rest it is a standard producer/consumer scenario. The GUI thread takse QStrings of the top of the Queue, the worker thread appends them as soon as it gets them.

    I realize now you can't pass a single QString pointer because it could get overwritten in the mean time, before it is displayed in the GUI.

    Regards

  19. The following user says thank you to marcel for this useful post:

    ShaChris23 (3rd May 2007)

  20. #13
    Join Date
    Dec 2006
    Posts
    123
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt/Embedded
    Platforms
    Unix/X11

    Default Re: First attempt to display serial port data on GUI

    ShaChris23:

    can you say me how did you link the qextserial package to qt ? actually i'm trying to read the data's coming from the serial port.i found in the some forum posts that we can use qextserial package. i downloaded and compiled it for my linux PC also .but i could not figure how to use it with the qt. when i compiled it, i found only the libraries where created. In your code i found that you had added the header file "#include "qextserialport.h"" and created an object for qextserial. so i my code if i simply add the header will it work ? or should i place the library in some location in qt-embedded

Similar Threads

  1. Serial Port communication
    By mgurbuz in forum Qt Programming
    Replies: 12
    Last Post: 22nd January 2011, 03:38
  2. Serial Port
    By b1 in forum Qt Programming
    Replies: 2
    Last Post: 18th January 2007, 03:05
  3. Serial Port access in Qt
    By Doug Broadwell in forum Newbie
    Replies: 2
    Last Post: 18th October 2006, 22:03
  4. speed of setdata - lots of items in treeview
    By Big Duck in forum Qt Programming
    Replies: 4
    Last Post: 6th July 2006, 13:53
  5. Replies: 16
    Last Post: 7th March 2006, 16:57

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.