Results 1 to 11 of 11

Thread: Sequential work with the port

  1. #1
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Sequential work with the port

    Hello. I have a serious problem that I can not solve.
    I have a device that sends a request to the board and is waiting for a response. Work with the device is done in a separate thread, so as not to slow down the gui. Also there is a class of algorithms that works in another thread. The algorithm calls the methods to open / close.

    MainWindow:
    Qt Code:
    1. /***mainwindow.h***/
    2. #ifndef MAINWINDOW_H
    3. #define MAINWINDOW_H
    4.  
    5. #include <QMainWindow>
    6. #include <QThread>
    7. #include "deviceworker.h"
    8. #include "algorithm.h"
    9.  
    10. namespace Ui {
    11. class MainWindow;
    12. }
    13.  
    14. class MainWindow : public QMainWindow
    15. {
    16. Q_OBJECT
    17.  
    18. public:
    19. explicit MainWindow(QWidget *parent = 0);
    20. ~MainWindow();
    21. FirstDevice *device;
    22. Algorithm *algorithm;
    23. QThread *deviceThread;
    24. QThread *algorithmThread;
    25.  
    26. private slots:
    27. void on_pushButton_clicked();
    28.  
    29. private:
    30. Ui::MainWindow *ui;
    31.  
    32. };
    33.  
    34. #endif // MAINWINDOW_H
    35.  
    36. /***mainwindow.cpp***/
    37. #include "ui_mainwindow.h"
    38.  
    39. MainWindow::MainWindow(QWidget *parent) :
    40. QMainWindow(parent),
    41. ui(new Ui::MainWindow)
    42. {
    43. ui->setupUi(this);
    44. }
    45.  
    46. MainWindow::~MainWindow()
    47. {
    48. delete ui;
    49.  
    50. QThread *deviceThread = new QThread();
    51. QThread *algorithmThread = new QThread();
    52. device = new FirstDevice();
    53. device->setReadTimer(333);
    54. device->moveToThread(deviceThread);
    55.  
    56. algorithm = new Algorithm(device);
    57. algorithm->moveToThread(algorithmThread);
    58. deviceThread->start(QThread::TimeCriticalPriority);
    59. algorithmThread->start();
    60. }
    61.  
    62. void MainWindow::on_pushButton_clicked()
    63. {
    64. algorithm->run();
    65. }
    To copy to clipboard, switch view to plain text mode 

    DeviceWorker:
    Qt Code:
    1. /***deviceworker.h***/
    2. #ifndef DEVICEWORKER_H
    3. #define DEVICEWORKER_H
    4.  
    5. #include <QTimer>
    6. #include <QtSerialPort/QSerialPort>
    7. #include <QMutex>
    8. #include <QDebug>
    9. #include <QObject>
    10.  
    11. using namespace std;
    12.  
    13.  
    14. class FirstDevice : public QObject {
    15. Q_OBJECT
    16.  
    17. private:
    18. QTimer readTimer;
    19. public:
    20. explicit FirstDevice(QObject *parent = 0);
    21. ~FirstDevice(){}
    22.  
    23. void setReadTimer(int ms){
    24. readTimer.start(ms);
    25. }
    26.  
    27. public slots:
    28. bool open(int id){
    29. emit switchStateSig(id, true);
    30. }
    31. bool close(int id){
    32. emit switchStateSig(id, false);
    33. }
    34. bool getAllStates();
    35.  
    36. private slots:
    37. bool switchState(int id, bool state);
    38.  
    39. signals:
    40. void remoteSignal(bool);
    41. void status(int, bool, bool);
    42. void switchStateSig(int, bool);
    43. };
    44.  
    45.  
    46. class ComPort : public QObject { //singltone
    47. Q_OBJECT
    48. private:
    49. QSerialPort *serial;
    50. QMutex *mutex;
    51. explicit ComPort(QObject *parent = 0){
    52. mutex = new QMutex();
    53. serial = new QSerialPort();
    54. connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
    55. }
    56.  
    57. ~ComPort(){}
    58. ComPort(ComPort const&) = delete;
    59. ComPort& operator= (ComPort const&) = delete;
    60. public:
    61. static ComPort& get()
    62. {
    63. static ComPort instance;
    64. return instance;
    65. }
    66.  
    67. void open(){
    68. if(serial->isOpen())
    69. close();
    70. serial->setPortName("COM2");
    71. if (serial->open(QIODevice::ReadWrite)) {
    72. if (serial->setBaudRate(QSerialPort::Baud115200)
    73. && serial->setFlowControl(QSerialPort::NoFlowControl)) {
    74. qDebug() << "open";
    75. } else {
    76. qDebug() << QString(serial->errorString());
    77. serial->close();
    78. }
    79. }
    80. }
    81. void close(){serial->close();}
    82. QByteArray requestResponse(const QByteArray &data){
    83. mutex->lock();
    84. qDebug() << "-------------------------";
    85. if(!serial->isOpen())
    86. open();
    87. int attempts = 1;
    88. QByteArray readBuf;
    89. while (attempts <= 3) {
    90. if (serial->isWritable())
    91. {
    92. serial->write(data);
    93. serial->waitForBytesWritten(3);
    94. while (serial->waitForReadyRead(300)) { //(wait 300ms). Here, randomly breaks down
    95. readBuf += serial->readAll();
    96. if (readBuf.size() == 4){
    97. close();
    98. mutex->unlock();
    99. return readBuf;
    100. }
    101. }
    102. readBuf.clear();
    103. close();
    104. open();
    105. attempts++;
    106. }
    107. else
    108. {
    109. qDebug() << "port is not written";
    110. close();
    111. mutex->unlock();
    112. return 0;
    113. }
    114. }
    115. close();
    116. mutex->unlock();
    117. return 0;
    118. }
    119.  
    120. private slots:
    121. void handleError(QSerialPort::SerialPortError error){
    122. if (error == QSerialPort::ResourceError) {
    123. close();
    124. qDebug() << "Error! ";
    125. }
    126. }
    127. };
    128.  
    129. #endif // DEVICEWORKER_H
    130.  
    131.  
    132. /***deviceworker.cpp***/
    133. #include "deviceworker.h"
    134.  
    135.  
    136. FirstDevice::FirstDevice(QObject *parent):QObject(parent)
    137. {
    138. connect(this, SIGNAL(switchStateSig(int, bool)), this, SLOT(switchState(int, bool)));
    139. connect(&readTimer, SIGNAL(timeout()), this, SLOT(getAllStates()));
    140. }
    141.  
    142. bool FirstDevice::getAllStates()
    143. {
    144. arr.resize(2);
    145. arr[0] = 0xAB;
    146. arr[1] = 0x01;
    147. QByteArray response = ComPort::get().requestResponse(arr);
    148. if(response[0] == arr[0])
    149. {
    150. emit remoteSignal(1);
    151. return 1;
    152. }
    153. emit remoteSignal(0);
    154. return 0;
    155. }
    156.  
    157. bool FirstDevice::switchState(int id, bool state)
    158. {
    159. arr.resize(2);
    160. arr[0] = 0xAB;
    161. arr[1] = 0x01;
    162.  
    163. QByteArray response = ComPort::get().requestResponse(arr);
    164. if(response[0] == arr[0]) //ok
    165. {
    166. emit status(id, state, true);
    167. return 1;
    168. }
    169. emit status(id, state, false);
    170. return 0;
    171. }
    To copy to clipboard, switch view to plain text mode 

    algorithm:
    Qt Code:
    1. #ifndef ALGORITHM_H
    2. #define ALGORITHM_H
    3. #include <QObject>
    4. #include "deviceworker.h"
    5. class Algorithm: public QObject
    6. {
    7. Q_OBJECT
    8. private:
    9. FirstDevice *device;
    10. public:
    11. Algorithm(FirstDevice *device_){
    12. device = device_;
    13. }
    14. void run(){
    15. device->open(3); //Here I must wait for an answer
    16. //do something
    17. device->close(3); //Here I must wait for an answer
    18. }
    19. };
    20.  
    21. #endif // ALGORITHM_H
    To copy to clipboard, switch view to plain text mode 

    So, I have two problems:
    1. How to wait for a response from a card without using the method waitForReadyRead()? This is what I need, but I can not use it. The program periodically falls arbitrarily in this place. I read that this function is unstable on windows.
    2. Inside the Algorithm method run(), I open / close the device. But since the device and the algorithm work in different threads, I had to connect them with signals and slots. Therefore, I do not wait for an answer from the board, but I go further. That is, in fact, the board may not respond, and I will ignore it, which is very bad.

    I apologize for the long post, but I do not know how to make it even shorter.

  2. #2
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Sequential work with the port

    As far as I can understand what you asked, both 1 and 2 are the same question - or did I misunderstand?
    Since you already are in a different thread, and from what I understand you want a blocking wait why not just implement your own waitForReadReady()?:
    Qt Code:
    1. //NUM_BYTES is a place holder for the number of bytes you deem as enough to wait on, 1 would be the minimum, but maybe you prefer to wait for a full packet (what ever a full packet is in your case).
    2. void ComPort::waitForReadReady() const
    3. {
    4. while(serial->bytesAvailable() < NUM_BYTES){
    5. //depending on needs you could add a sleep here to no hog the CPU too much
    6. }
    7. }
    To copy to clipboard, switch view to plain text mode 
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  3. #3
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Sequential work with the port

    Quote Originally Posted by high_flyer View Post
    did I misunderstand?
    Not certainly in that way.
    In fact, device->open()/close() is just the emission of a signal. I emit a signal switchStateSig, then the slot switchState in the thread of the device is called. I do not control this, I just go further in the thread of the algorithm.
    I can not call directly, because the device and the algorithm are in different threads, so I had to connect them with a signal and a slot.
    This should work like this: from the thread of the algorithm, I call the open/close of the device, I wait for an answer, and only then I go further. Now I just emit a signal and, without waiting for an answer, I go forward. This is very bad. This is the first problem.

    The second problem is that the function waitForReadyRead() unpredictably breaks the whole program. I tried to do this, but I did not get a single byte. Apparently, something is blocked:
    Qt Code:
    1. void ms_delay(int ms){
    2. QElapsedTimer ms_timer;
    3. ms_timer.start();
    4. while(ms_timer.elapsed() < ms){}
    5. return;
    6. }
    7.  
    8. QByteArray ComPort::requestResponse(const QByteArray &data)
    9. {
    10. mutex->lock();
    11. qDebug() << "-------------------------";
    12. if(!serial->isOpen())
    13. open();
    14. int attempts = 1;
    15. QElapsedTimer waitTimer;
    16. readBuf.clear();
    17. while (attempts <= 3) {
    18. if (serial->isWritable())
    19. {
    20. serial->write(data);
    21. waitTimer.restart();
    22. while (waitTimer.elapsed() < 333){
    23. ms_delay(5);
    24. readBuf += serial->readAll();
    25. if (readBuf.size() == 4){
    26. close();
    27. mutex->unlock();
    28. return readBuf;
    29. }
    30. }
    31. readBuf.clear();
    32. qDebug() << "Timeout...";
    33. close();
    34. open();
    35. attempts++;
    36. }
    37. else
    38. {
    39. qDebug() << "Port is not written";
    40. close();
    41. mutex->unlock();
    42. return 0;
    43. }
    44.  
    45. }
    46. close();
    47. mutex->unlock();
    48. return 0;
    49. }
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Sequential work with the port

    So let me see if I understand:
    Calling the QDevice::waitForReadRead() is not relible on windows, so you don't call it and want to have some other function to call instead that delivers the same functionality.
    Is that correct?
    (All the story around it, how things in other threads are, are not the problem, more the motivation, as far as I can see)

    If so, did you try what I offered in my last post, and if you did, what was the problem?
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  5. #5
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Sequential work with the port

    Quote Originally Posted by high_flyer View Post
    Is that correct?
    Yes that's right. This is problem number 1. I have not tried your method yet, because no access to the board. I would like to monitor the reception with time, because if my request does not reach board for some reason, she will not answer me, no matter how much time I wait. For this reason, I make repeated requests after the timeout.

    Quote Originally Posted by high_flyer View Post
    All the story around it, how things in other threads are, are not the problem, more the motivation, as far as I can see.
    I can not say with certainty. But I tried to call directly device->switchState(7, true); from algorithm, which got the error that you can not call the methods of another thread, being not in the main thread. Therefore, I connected them with signals.
    Last edited by maratk1n; 18th December 2017 at 22:05.

  6. #6
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Sequential work with the port

    because if my request does not reach board for some reason, she will not answer me, no matter how much time I wait. For this reason, I make repeated requests after the timeout.
    or you can set a timeout as well.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  7. #7
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Sequential work with the port

    Quote Originally Posted by high_flyer View Post
    or you can set a timeout as well.
    So, how can I do this?..

  8. #8
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Sequential work with the port

    So, how can I do this?..
    there are several ways...
    Probably the least "intrusive" would be to have a timer run and you can check the elapsed time in your while() loop where you are checking the available bytes from the serial device.
    Once the timeout is reached you simply return from your custom waitForReadRead() with false.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  9. #9
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Sequential work with the port

    Quote Originally Posted by high_flyer View Post
    there are several ways...
    Probably the least "intrusive" would be to have a timer run and you can check the elapsed time in your while() loop where you are checking the available bytes from the serial device.
    Once the timeout is reached you simply return from your custom waitForReadRead() with false.
    Thank for you answer. But I already tried to do this way, the port "was silent".
    http://www.qtcentre.org/threads/6904...574#post301574

  10. #10
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Sequential work with the port

    Thank for you answer. But I already tried to do this way, the port "was silent".
    Do you mean by that the the port didn't answer within the time you specified?
    If yes, then try prolonging the timeout.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  11. #11
    Join Date
    Apr 2017
    Posts
    30
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Sequential work with the port

    Quote Originally Posted by high_flyer View Post
    Do you mean by that the the port didn't answer within the time you specified?
    If yes, then try prolonging the timeout.
    I tried to increase. Ping using the function waitForReadRead() was 2-5 milliseconds. With the use of a timer, the board absolutely did not answer anything for 333 milliseconds and more. I concluded that data reception is somehow blocked.

Similar Threads

  1. Instructions are NOT sequential in qt/qml?!?
    By JaySDC in forum Qt Quick
    Replies: 9
    Last Post: 24th October 2015, 18:41
  2. serial port command doesn't work
    By hovuquocan1997 in forum Qt Programming
    Replies: 4
    Last Post: 20th July 2015, 17:10
  3. Replies: 2
    Last Post: 26th July 2014, 17:36
  4. Sequential animations on each listitem
    By rama.kesi in forum Qt Quick
    Replies: 3
    Last Post: 12th October 2012, 04:36
  5. Sequential animations on each listitem
    By rama.kesi in forum Qt Quick
    Replies: 0
    Last Post: 8th October 2012, 06:24

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.