Results 1 to 17 of 17

Thread: Architecture problem using threads, custom events and signals/slots

  1. #1
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Architecture problem using threads, custom events and signals/slots

    So it's a bit complicated but I will do my best to explain my problem.

    I am developping some classes to read/write data over a serial port. I am using the Win_QextSerialPort class (and its base class) that can be found on sourceforge. The only thing I'll tell about this class is that it uses in quite every function the QMutex lock/unlock mechanism.

    So, go on, I ddi developp a class called CSerialDataFrameDecoder which uses the Win_QextSerialPort. Mt class inherits from QThread and reimplements the run() method in which I keep reading the serial port buffer and process its data. The process is quite simple, I am looking for some start and stop sequence and create some CSerialDataFrame (it is a class I did developp too). Once a CSerialDataFrame is created I post a custom event to object owner of the CSerialDataFrameDecoder. At the beginning I wished to use the signals/slots mechanism but it is not possible with threads. To test my classes I developped a simple GUI application which reimplements the customEvent function and just display the content of the CSerialDataFrame contained in my custom event. This test application works fine in debug version but it sometime crashes in release version (access violation) ... this is my first problem, but I decided to focus on that problem later on (also because I don't really know how to find out the origin of this problem) because the debug version works.

    After that I decided to developp another class called CSerialPort which inherits from QObject. This class encapsulates the CSerialDataFrameDecoder, stores all CSerialDataFrame into a stack and posts a custom event when it receives a custom event from the CSerialDataFrameDecoder. This class has at least two functions start and stop which respectively starts and stops the CSerialDataFrameDecoder thread. I also developp a GUI test application with a reimplentation of the function customEvent which displays the CSerialDataFrame content using a QListBox object. Here is my second problem because the application blocks, it does not bug or crashes, it just blocks so I must stop and start the CSerialDataFrameDecoder. The application never blocks at the same time and I don't know how to find out the problem.

    If someone have a clue to the answer (even the answer itself) ... thanks in advance.

  2. #2
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    I did a simple change in my code so that the release version is now working with no problem.

    In fact I was allocating a block of n bytes, reading a buffer of n bytes and writing a null character at position n. Now I allocated a block of n+1 bytes.

    My application still blocks (second problem), so if someone could help me with this it would be great.

    Thanks

  3. #3
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Using qDebug helped me to see what is happening and understand that my application does not blocks but seems to be lost. Let's my explain, many times I see that the serialDataFrameDecoded function is called but never returned. I say that because I can read the following messages :
    Qt Code:
    1. qDebug("In CSerialDataFrameDecoder::serialDataFrameDecoded. Before : QApplication::postEvent(objectOwner, ce);");
    2. qDebug("In CSerialDataFrameDecoder::serialDataFrameDecoded. After : QApplication::postEvent(objectOwner, ce);");
    To copy to clipboard, switch view to plain text mode 
    When my application seems to be blocked, I see that the message that should be writen after the serialDataFrameDecoded function call is never writen. Why ? That is what I do not understand. So if someone could help me to understand I whould be great. thanks.

    Here is the code of the run() reimplementation function of my thread, and also the serialDataFrameDecoded fnuction which trigger the custom event :
    Qt Code:
    1. void CSerialDataFrameDecoder::run()
    2. {
    3. int bytesToRead = -1;
    4. Q_LONG bytesRead = 0;
    5.  
    6. int startSequenceIndex = -1;
    7. int stopSequenceIndex = -1;
    8.  
    9. QString buffer("");
    10. QString frame("");
    11.  
    12. while( bMustDecode == true )
    13. {
    14. qDebug("In CSerialDataFrameDecoder. After : while( bMustDecode == true )");
    15. // TO DO
    16. // ... read the com port buffer
    17. // ... decode frames
    18. // ... trigger a custom events each time a complete frame is decoded
    19. if( comPort != 0 )
    20. {
    21. qDebug("In CSerialDataFrameDecoder::run(). After : if( comPort != 0 )");
    22. if( comPort->isOpen() )
    23. {
    24. qDebug("In CSerialDataFrameDecoder::run(). After : if( comPort->isOpen() )");
    25. // Get the number of bytes to read
    26. bytesToRead = comPort->bytesWaiting();
    27. qDebug("In CSerialDataFrameDecoder::run(). After : bytesToRead = comPort->bytesWaiting();");
    28.  
    29. if( bytesToRead != 0 )
    30. {
    31. // Here we can do some stuff
    32. char* buffData = 0;
    33. buffData = new char[bytesToRead+1];
    34. qDebug("In CSerialDataFrameDecoder::run(). After : buffData = new char[bytesToRead+1];");
    35.  
    36. bytesRead = comPort->readBlock(buffData, bytesToRead);
    37. qDebug("In CSerialDataFrameDecoder::run(). After : bytesRead = comPort->readBlock(buffData, bytesToRead);");
    38. buffData[bytesRead] = '\0';
    39. comPort->flush();
    40. qDebug("In CSerialDataFrameDecoder::run(). After : comPort->flush();");
    41.  
    42. buffer = buffData;
    43.  
    44. while( (buffer.length() != 0) && (bMustDecode == true) )
    45. {
    46. qDebug("In CSerialDataFrameDecoder::run(). After : while( (buffer.length() != 0) && (bMustDecode == true) )");
    47.  
    48. startSequenceIndex = buffer.find(startSequence, 0, false);
    49. stopSequenceIndex = buffer.find(stopSequence, 0, false);
    50. qDebug("In CSerialDataFrameDecoder::run(). startSequenceIndex=%d, stopSequenceIndex=%d", startSequenceIndex, stopSequenceIndex);
    51. // Check previous indexes to determine if the frame is complete or not
    52. // CASE 1 : start and stop indexex are found, stop index is greather than start index
    53. // !!! A complete frame can be extracted !!!
    54.  
    55. // CASE 2 and CASE 5 : stop index is found but not start index
    56. // !!! An incomplete frame can be extracted, its beginning is missing !!!
    57.  
    58. // CASE 3 : start index is found but not stop
    59. // !!! An incomplete frame can be extracted, its ending is missing
    60.  
    61. // CASE 4 : start index neither stop are found
    62. // !!! An incomplete frame can be extracted, its beginning and ending are missing
    63.  
    64. // CASE 1
    65. if( (startSequenceIndex == 0) && (stopSequenceIndex != -1) && (stopSequenceIndex>startSequenceIndex) )
    66. {
    67. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE1");
    68. frame = buffer.mid(startSequenceIndex, (stopSequenceIndex-startSequenceIndex)+1);
    69. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    70.  
    71. CSerialDataFrame aFrame;
    72. aFrame.setSerialDataFrameValue(frame);
    73. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusComplete);
    74. qDebug("In CSerialDataFrameDecoder::run(). Before : this->serialDataFrameDecoded(aFrame);");
    75. this->serialDataFrameDecoded(aFrame);
    76. qDebug("In CSerialDataFrameDecoder::run(). After : this->serialDataFrameDecoded(aFrame);");
    77. }
    78. // CASE 2
    79. else if( (startSequenceIndex == -1) && (stopSequenceIndex != -1) )
    80. {
    81. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE2");
    82. frame = buffer.left(stopSequenceIndex+1);
    83. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    84.  
    85. CSerialDataFrame aFrame;
    86. aFrame.setSerialDataFrameValue(frame);
    87. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart);
    88. qDebug("In CSerialDataFrameDecoder::run(). Before : this->serialDataFrameDecoded(aFrame);");
    89. this->serialDataFrameDecoded(aFrame);
    90. qDebug("In CSerialDataFrameDecoder::run(). After : this->serialDataFrameDecoded(aFrame);");
    91. }
    92. // CASE 3
    93. else if( (startSequenceIndex != -1) && (stopSequenceIndex == -1) )
    94. {
    95. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE3");
    96. frame = buffer.mid(0, buffer.length());
    97. buffer.remove(0, buffer.length());
    98.  
    99. CSerialDataFrame aFrame;
    100. aFrame.setSerialDataFrameValue(frame);
    101. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart);
    102. qDebug("In CSerialDataFrameDecoder::run(). Before : this->serialDataFrameDecoded(aFrame);");
    103. this->serialDataFrameDecoded(aFrame);
    104. qDebug("In CSerialDataFrameDecoder::run(). After : this->serialDataFrameDecoded(aFrame);");
    105. }
    106. // CASE 4
    107. else if( (startSequenceIndex == -1) && (stopSequenceIndex == -1) )
    108. {
    109. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE4");
    110. frame = buffer;
    111. buffer.remove(frame);
    112.  
    113. CSerialDataFrame aFrame;
    114. aFrame.setSerialDataFrameValue(frame);
    115. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart);
    116. qDebug("In CSerialDataFrameDecoder::run(). Before : this->serialDataFrameDecoded(aFrame);");
    117. this->serialDataFrameDecoded(aFrame);
    118. qDebug("In CSerialDataFrameDecoder::run(). After this->serialDataFrameDecoded(aFrame);");
    119. }
    120. // CASE 5
    121. else if( (startSequenceIndex != -1) && (stopSequenceIndex != -1) && (stopSequenceIndex<startSequenceIndex) )
    122. {
    123. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE5");
    124. frame = buffer.left(stopSequenceIndex+1);
    125. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    126.  
    127. CSerialDataFrame aFrame;
    128. aFrame.setSerialDataFrameValue(frame);
    129. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart);
    130. qDebug("In CSerialDataFrameDecoder::run(). Before : this->serialDataFrameDecoded(aFrame);");
    131. this->serialDataFrameDecoded(aFrame);
    132. qDebug("In CSerialDataFrameDecoder::run(). After : this->serialDataFrameDecoded(aFrame);");
    133. }
    134. }
    135. }
    136. }
    137. }
    138. }
    139. }
    140.  
    141.  
    142. void CSerialDataFrameDecoder::serialDataFrameDecoded(const CSerialDataFrame& frame)
    143. {
    144. // Allocate some memory for the data
    145. CSerialDataFrame* data = 0;
    146. data = new CSerialDataFrame(frame);
    147. // The allocated memory for the data MUST by freed by the receiver
    148.  
    149. // Allocate some memory for the custom event
    150. QCustomEvent* ce = 0;
    151. ce = new QCustomEvent(1002);
    152. ce->setData(data);
    153.  
    154. // Send the event
    155. qDebug("In CSerialDataFrameDecoder::serialDataFrameDecoded. Before : QApplication::postEvent(objectOwner, ce);");
    156. QApplication::postEvent(objectOwner, ce);
    157. qDebug("In CSerialDataFrameDecoder::serialDataFrameDecoded. After : QApplication::postEvent(objectOwner, ce);");
    158. // The allocated memory for the custum event is freed by Qt so the receiver neither the sender MUST NOT free it
    159. }
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    What member variables does CSerialDataFrame contain? Maybe it uses some Qt classes with implicit sharing?

  5. #5
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Here is the declaration of my CSerialDataFrame class
    Qt Code:
    1. #ifndef _SERIAL_DATA_FRAME_H
    2. #define _SERIAL_DATA_FRAME_H
    3.  
    4. #include <qstring.h>
    5.  
    6. class CSerialDataFrame
    7. {
    8. // Constructor / Destructor
    9. public:
    10. CSerialDataFrame(QString data="");
    11. CSerialDataFrame(const CSerialDataFrame&);
    12.  
    13. const CSerialDataFrame& operator+= (const CSerialDataFrame&);
    14. const CSerialDataFrame& operator= (const CSerialDataFrame&);
    15. bool operator== (const CSerialDataFrame&);
    16.  
    17.  
    18. // Functions
    19. void setSerialDataFrameValue(QString);
    20. QString getSerialDataFrameValue() const;
    21.  
    22. void setSerialDataFrameStatus(int);
    23. int getSerialDataFrameStatus() const;
    24.  
    25. // Members
    26. public:
    27. static const int SerialDataFrameStatusNotDefined;
    28. static const int SerialDataFrameStatusComplete;
    29. static const int SerialDataFrameStatusIncompleteHasJustTheBeginningPart;
    30. static const int SerialDataFrameStatusIncompleteHasJustTheEndingPart;
    31. static const int SerialDataFrameStatusIncompleteHasJustTheMiddlePart;
    32.  
    33. private:
    34. QString serialDataFrameValue;
    35. int serialDataFrameStatus;
    36. };
    37.  
    38. #endif
    To copy to clipboard, switch view to plain text mode 

    and the implementation
    Qt Code:
    1. #include "SerialDataFrame.h"
    2.  
    3. const int CSerialDataFrame::SerialDataFrameStatusNotDefined = -1;
    4. const int CSerialDataFrame::SerialDataFrameStatusComplete = 0;
    5. const int CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart = 1;
    6. const int CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart = 2;
    7. const int CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart = 3;
    8.  
    9.  
    10. // Constructor / Destructor
    11. CSerialDataFrame::CSerialDataFrame(QString data):
    12. serialDataFrameValue(data),
    13. serialDataFrameStatus(SerialDataFrameStatusNotDefined)
    14. {
    15. }
    16.  
    17.  
    18. CSerialDataFrame::CSerialDataFrame(const CSerialDataFrame& frame)
    19. {
    20. this->serialDataFrameValue = frame.serialDataFrameValue;
    21. this->serialDataFrameStatus = frame.serialDataFrameStatus;
    22. }
    23.  
    24.  
    25. const CSerialDataFrame& CSerialDataFrame::operator+=(const CSerialDataFrame& frame)
    26. {
    27. this->serialDataFrameValue += frame.serialDataFrameValue;
    28.  
    29. // Beginnig part + middle part = beginning part
    30. if( (this->serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart) && (frame.serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart) )
    31. {
    32. this->serialDataFrameStatus = CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart;
    33. }
    34. // Beginning part + ending part = complete part
    35. else if( (this->serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart) && (frame.serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart) )
    36. {
    37. this->serialDataFrameStatus = CSerialDataFrame::SerialDataFrameStatusComplete;
    38. }
    39. // Middle part + middle part = middle part
    40. else if( (this->serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart) && (frame.serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart) )
    41. {
    42. this->serialDataFrameStatus = CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart;
    43. }
    44. // Middle part + ending part = ending part
    45. else if( (this->serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart) && (frame.serialDataFrameStatus == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart) )
    46. {
    47. this->serialDataFrameStatus = CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart;
    48. }
    49. // Other cases are not defined
    50. else
    51. this->serialDataFrameStatus = CSerialDataFrame::SerialDataFrameStatusNotDefined;
    52.  
    53. return *this;
    54. }
    55.  
    56.  
    57. const CSerialDataFrame& CSerialDataFrame::operator=(const CSerialDataFrame& frame)
    58. {
    59. this->serialDataFrameValue = frame.serialDataFrameValue;
    60. this->serialDataFrameStatus = frame.serialDataFrameStatus;
    61.  
    62. return *this;
    63. }
    64.  
    65.  
    66. bool CSerialDataFrame::operator==(const CSerialDataFrame& frame)
    67. {
    68. if( (this->serialDataFrameValue == frame.serialDataFrameValue) && (this->serialDataFrameStatus == frame.serialDataFrameStatus) )
    69. return true;
    70. else
    71. return false;
    72. }
    73.  
    74.  
    75. // Functions
    76. void CSerialDataFrame::setSerialDataFrameValue(QString value)
    77. {
    78. serialDataFrameValue = value;
    79. }
    80.  
    81.  
    82. QString CSerialDataFrame::getSerialDataFrameValue() const
    83. {
    84. return serialDataFrameValue;
    85. }
    86.  
    87.  
    88. void CSerialDataFrame::setSerialDataFrameStatus(int value)
    89. {
    90. serialDataFrameStatus = value;
    91. }
    92.  
    93.  
    94. int CSerialDataFrame::getSerialDataFrameStatus() const
    95. {
    96. return serialDataFrameStatus;
    97. }
    To copy to clipboard, switch view to plain text mode 

    All the afternoon I was looking logs delivered by qDebug. What happening is sometime strange. Sometime I can see that my class CSerialDataFrameDecoder is at a particular code line and the next step it is at a previous code line ... and it is not possible

  6. #6
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    An example of a very strange log :
    Sometime qDebug trace tell me that
    Qt Code:
    1. qDebug("In CSerialDataFrameDecoder::run(). Entry : CASE1");
    To copy to clipboard, switch view to plain text mode 
    and the next trace tell me
    Qt Code:
    1. qDebug("In CSerialDataFrameDecoder::run(). After : while( (buffer.length() != 0) && (bMustDecode == true) )");
    To copy to clipboard, switch view to plain text mode 

    I don't understand what is going on and what's wrong with my code ... I thought what I was coding was not that difficult.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Quote Originally Posted by yellowmat
    QString serialDataFrameValue;
    QString data is implicitly shared.

    Try this:
    Qt Code:
    1. CSerialDataFrame::CSerialDataFrame( const CSerialDataFrame& frame )
    2. {
    3. serialDataFrameValue = QDeepCopy<QString>( frame.serialDataFrameValue );
    4. serialDataFrameStatus = frame.serialDataFrameStatus;
    5. }
    6.  
    7. const CSerialDataFrame& CSerialDataFrame::operator=(const CSerialDataFrame& frame)
    8. {
    9. serialDataFrameValue = QDeepCopy<QString>( frame.serialDataFrameValue );
    10. serialDataFrameStatus = frame.serialDataFrameStatus;
    11. return *this;
    12. }
    To copy to clipboard, switch view to plain text mode 

    Quote Originally Posted by yellowmat
    Sometime I can see that my class CSerialDataFrameDecoder is at a particular code line and the next step it is at a previous code line ... and it is not possible
    I'm not sure if qDebug() is thread safe.

  8. #8
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    The same problem occurs despite the modifucation you proposed me to implement.

    Could I post you the source code of my CSerialDataFrameDecoder and CSerialPort ? There must be something that is not architecturaly clear and clean ?

  9. #9
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Sorry, I forget to ask but, why should I use QDeepCopy in my CSerialDataFrame code ? Maybe I should use it somewhere else to because I use QString quite often in my code ?

    Another question, what should I use instead of qDebug to keep a trace of what (should) going on ?

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Quote Originally Posted by yellowmat
    why should I use QDeepCopy in my CSerialDataFrame code ?
    Because you are passing a implicitly shared object (i.e. QString) between two threads.

    http://doc.trolltech.com/3.3/threads.html#9
    http://doc.trolltech.com/3.3/shclass.html

    Quote Originally Posted by yellowmat
    Another question, what should I use instead of qDebug to keep a trace of what (should) going on ?
    First you check whether you can use qDebug() or not, but you can always try writing messages to a text file.

  11. #11
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Sorry Jacek, I know that I should find out by myself but I don't manage to ... so I need some more help please.

    I have modified the source code of my CSerialDataFrame in order to make a deep copy when I call the copy constructor, the equal operator but also the setSerialDataFrameValue. Here I am sure that the copy is deep.

    I have analysed my code and I don't know what could be wrong but I'm sure there is something wrong ... it is starting to drive me crazy

    First, the CSerialDataDecoder code looks fine
    Qt Code:
    1. void CSerialDataFrameDecoder::run()
    2. {
    3. int bytesToRead = -1;
    4. Q_LONG bytesRead = 0;
    5.  
    6. int startSequenceIndex = -1;
    7. int stopSequenceIndex = -1;
    8.  
    9. QString buffer("");
    10. QString frame("");
    11.  
    12. while( bMustDecode == true )
    13. {
    14. msleep(1);
    15. // TO DO
    16. // ... read the com port buffer
    17. // ... decode frames
    18. // ... trigger a custom events each time a complete frame is decoded
    19. if( comPort != 0 )
    20. {
    21. if( comPort->isOpen() )
    22. {
    23. // Get the number of bytes to read
    24. bytesToRead = comPort->bytesWaiting();
    25.  
    26. if( bytesToRead != 0 )
    27. {
    28. // Here we can do some stuff
    29. char* buffData = 0;
    30. buffData = new char[bytesToRead+1];
    31.  
    32. bytesRead = comPort->readBlock(buffData, bytesToRead);
    33. buffData[bytesRead] = '\0';
    34. comPort->flush();
    35.  
    36. buffer = buffData;
    37.  
    38. while( (buffer.length() != 0) && (bMustDecode == true) )
    39. {
    40. msleep(1);
    41.  
    42. startSequenceIndex = buffer.find(startSequence, 0, false);
    43. stopSequenceIndex = buffer.find(stopSequence, 0, false);
    44. // Check previous indexes to determine if the frame is complete or not
    45. // CASE 1 : start and stop indexex are found, stop index is greather than start index
    46. // !!! A complete frame can be extracted !!!
    47.  
    48. // CASE 2 and CASE 5 : stop index is found but not start index
    49. // !!! An incomplete frame can be extracted, its beginning is missing !!!
    50.  
    51. // CASE 3 : start index is found but not stop
    52. // !!! An incomplete frame can be extracted, its ending is missing
    53.  
    54. // CASE 4 : start index neither stop are found
    55. // !!! An incomplete frame can be extracted, its beginning and ending are missing
    56.  
    57. // CASE 1
    58. if( (startSequenceIndex == 0) && (stopSequenceIndex != -1) && (stopSequenceIndex>startSequenceIndex) )
    59. {
    60. frame = buffer.mid(startSequenceIndex, (stopSequenceIndex-startSequenceIndex)+1);
    61. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    62.  
    63. CSerialDataFrame aFrame;
    64. aFrame.setSerialDataFrameValue(frame);
    65. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusComplete);
    66. this->serialDataFrameDecoded(aFrame);
    67. }
    68. // CASE 2
    69. else if( (startSequenceIndex == -1) && (stopSequenceIndex != -1) )
    70. {
    71. frame = buffer.left(stopSequenceIndex+1);
    72. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    73.  
    74. CSerialDataFrame aFrame;
    75. aFrame.setSerialDataFrameValue(frame);
    76. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart);
    77. this->serialDataFrameDecoded(aFrame);
    78. }
    79. // CASE 3
    80. else if( (startSequenceIndex != -1) && (stopSequenceIndex == -1) )
    81. {
    82. frame = buffer.mid(0, buffer.length());
    83. buffer.remove(0, buffer.length());
    84.  
    85. CSerialDataFrame aFrame;
    86. aFrame.setSerialDataFrameValue(frame);
    87. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart);
    88. this->serialDataFrameDecoded(aFrame);
    89. }
    90. // CASE 4
    91. else if( (startSequenceIndex == -1) && (stopSequenceIndex == -1) )
    92. {
    93. frame = buffer;
    94. buffer.remove(frame);
    95.  
    96. CSerialDataFrame aFrame;
    97. aFrame.setSerialDataFrameValue(frame);
    98. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart);
    99. this->serialDataFrameDecoded(aFrame);
    100. }
    101. // CASE 5
    102. else if( (startSequenceIndex != -1) && (stopSequenceIndex != -1) && (stopSequenceIndex<startSequenceIndex) )
    103. {
    104. frame = buffer.left(stopSequenceIndex+1);
    105. buffer.remove(0, stopSequenceIndex+stopSequence.length());
    106.  
    107. CSerialDataFrame aFrame;
    108. aFrame.setSerialDataFrameValue(frame);
    109. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart);
    110. this->serialDataFrameDecoded(aFrame);
    111. }
    112. }
    113. }
    114. }
    115. }
    116. }
    117. }
    118.  
    119.  
    120. void CSerialDataFrameDecoder::serialDataFrameDecoded(const CSerialDataFrame& frame)
    121. {
    122. // Allocate some memory for the data
    123. CSerialDataFrame* data = 0;
    124. data = new CSerialDataFrame(frame);
    125. // The allocated memory for the data MUST by freed by the receiver
    126.  
    127. // Allocate some memory for the custom event
    128. QCustomEvent* ce = 0;
    129. ce = new QCustomEvent(1002);
    130. ce->setData(data);
    131.  
    132. // Send the event
    133. QApplication::postEvent(objectOwner, ce);
    134. // The allocated memory for the custum event is freed by Qt so the receiver neither the sender MUST NOT free it
    135. }
    To copy to clipboard, switch view to plain text mode 

    In my opinion its behaviour is correct and match with the code. It just flush the buffer, reads data from the Win_QextSerialPort and add a null terminating char. Maybe should I make a deep copy of the buffer content and store it into my QString variable buffer ? After that it processes the buffer variable and looks for a start and stop sequence char, extract the data and then update the buffer variable (it removes the extracted data). After extracting the serial data frame, it allocated some memory for a such a frame, make a copy of it and then send this frame using a custom event to the owner of the CSerialDataFrameDecoder which is the CSerialPort object. At this point should I do something else in that code ? (Other deep copy ?, mutex ?).

  12. #12
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Hmm, the other suspicious point may be the CSerialPort class which code is below
    Qt Code:
    1. #include "SerialPort.h"
    2. #include <qapplication.h>
    3. #include <qstring.h>
    4. #include ".\\..\\..\\DataParser\\WidgetSource\\DataParser.h"
    5. #include ".\\qextserialbase.h"
    6. #include ".\\win_qextserialport.h"
    7. #include ".\\..\\..\\SerialDataFrameDecoder\\WidgetSource\\SerialDataFrameDecoder.h"
    8.  
    9.  
    10.  
    11. // Constructor / Destructor
    12. CSerialPort::CSerialPort(QObject* parent/*=0*/, const char* name/*=0*/, const QString& configFileName/*=""*/):
    13. QObject(parent, name),
    14. parser(0),
    15. port(0),
    16. decoder(0),
    17. isDecoding(false),
    18. readSerialDataFrameStartSequence(""),
    19. readSerialDataFrameStopSequence(""),
    20. writeSerialDataFrameStartSequence(""),
    21. writeSerialDataFrameStopSequence("")
    22. {
    23. // Create a serial port object
    24. if( port == 0 )
    25. port = new Win_QextSerialPort(sTemp.ascii(), comSettings);
    26.  
    27. // Open the port
    28. if( port != 0 )
    29. port->open();
    30.  
    31. // Flush the com port$
    32. if( port->isOpen() )
    33. port->flush();
    34.  
    35. // Create a serial data frame decoder
    36. if( decoder == 0 )
    37. decoder = new CSerialDataFrameDecoder(this, port, readSerialDataFrameStartSequence, readSerialDataFrameStopSequence);
    38. }
    39.  
    40.  
    41. CSerialPort::~CSerialPort()
    42. {
    43. // Free memory allocated
    44. // ... to the data parser
    45. if( parser != 0 )
    46. {
    47. delete parser;
    48. parser = 0;
    49. }
    50.  
    51. // ... the serial data frame decoder
    52. if( decoder != 0 )
    53. {
    54. delete decoder;
    55. decoder = 0;
    56. }
    57.  
    58. // ... to the serial port
    59. if( port != 0 )
    60. {
    61. delete port;
    62. port = 0;
    63. }
    64. }
    65.  
    66.  
    67. // Slots
    68. /*
    69. Starts the serial data frames decoding only if all the following conditions are met
    70. There is no decoding running yet
    71. A serial port object has been instanciated and is currently open
    72. */
    73. void CSerialPort::startDecoding()
    74. {
    75. if( !isDecoding && port->isOpen() )
    76. {
    77. decoder->startDecode();
    78. isDecoding = true;
    79. }
    80. }
    81.  
    82.  
    83. /*
    84. Stops the serial data frames decoding only if all the following conditions are met
    85. There is a decoding running
    86. A serial port object has been instanciated and is currently open
    87. */
    88. void CSerialPort::stopDecoding()
    89. {
    90. if( isDecoding && port->isOpen() )
    91. {
    92. decoder->stopDecode();
    93. isDecoding = false;
    94. }
    95. }
    96.  
    97.  
    98. /*
    99. Return a copy of the first serial data frame stored in the fifo.
    100.  
    101. Removes (pop) the returned serial data frame from the fifo
    102. */
    103. CSerialDataFrame CSerialPort::read()
    104. {
    105. // Get the first serial data frame in the stack
    106. // Create a copy of it
    107. // Delete it from the stack if it is a complete serial data frame
    108.  
    109. // Return the serial data frame
    110. return CSerialDataFrame();
    111. }
    112.  
    113.  
    114. /*
    115. Write the serial data frame on the current opened serial port.
    116.  
    117. For the moment this function just write "as it" the serial data frame, it may in a close future process the serial data
    118. frame before sending it on the serial port.
    119. */
    120. void CSerialPort::write(CSerialDataFrame)
    121. {
    122. }
    123.  
    124.  
    125. // Functions
    126. /*
    127. Return the number of serial data frame stored in the fifo
    128. */
    129. int CSerialPort::count()
    130. {
    131. return serialDataFrames.count();
    132. }
    133.  
    134.  
    135. /*
    136. Return the open state of the port
    137. true = the port is open
    138. false = the port is closed
    139. */
    140. bool CSerialPort::isOpen()
    141. {
    142. return port->isOpen();
    143. }
    144.  
    145.  
    146. /*
    147. Intercept the event from CSerialDataFrameDecoder
    148. The only type of custom events we want to deal with is 1002
    149. */
    150. void CSerialPort::customEvent(QCustomEvent* e)
    151. {
    152. if( e->type() == 1002 )
    153. {
    154. CSerialDataFrame* frame = (CSerialDataFrame*)e->data();
    155.  
    156. // Here we process the serial data frame defragmentation if necessary
    157. if( frame->getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusComplete )
    158. {
    159. // If the serial data frame is complete we just append it to the stack
    160. serialDataFrames.append( CSerialDataFrame(*frame) );
    161. serialDataFrameDecoded(*frame);
    162. }
    163. else if( frame->getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart )
    164. {
    165. // We can append the current serial data frame in the two following cases
    166. // Case 1 : there is no frame in the stack yet
    167. // Case 2 : the last frame appended in the stack is a complete one
    168. if( (serialDataFrames.count() == 0) || (serialDataFrames.last().getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusComplete) )
    169. {
    170. serialDataFrames.append( CSerialDataFrame(*frame) );
    171. serialDataFrameDecoded(*frame);
    172. }
    173. }
    174. else if( frame->getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheMiddlePart )
    175. {
    176. // We can append the current serial data frame to the last appended one in the following case
    177. // Case 1 : the last frame has just the beginning part
    178. if( (serialDataFrames.count() > 0) && (serialDataFrames.last().getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart) )
    179. {
    180. serialDataFrames.last() += *frame;
    181. serialDataFrameDecoded(*frame);
    182. }
    183. }
    184. else if( frame->getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart )
    185. {
    186. // We can append the current serial data frame to the last appended one in the following case
    187. if( (serialDataFrames.count() > 0) && (serialDataFrames.last().getSerialDataFrameStatus() == CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheBeginningPart) )
    188. {
    189. serialDataFrames.last() += *frame;
    190. serialDataFrameDecoded(*frame);
    191. }
    192. }
    193. }
    194. }
    195.  
    196.  
    197. void CSerialPort::serialDataFrameDecoded(const CSerialDataFrame& frame)
    198. {
    199. // Allocate some memory for the data
    200. CSerialDataFrame* data = 0;
    201. data = new CSerialDataFrame(frame);
    202. // The allocated memory for the data MUST be freed by the receiver
    203.  
    204. // Allocate some memory for the custom event
    205. QCustomEvent* ce = new QCustomEvent(1002);
    206. ce->setData(data);
    207.  
    208. // Send the event
    209. QApplication::postEvent(parent(), ce);
    210. // The allocated memory for the custum event is freed by Qt so the receiver neither the sender MUST NOT free it
    211. }
    To copy to clipboard, switch view to plain text mode 
    ... but it does not a lot of thing, just analyse the frame received, concatenate some if necessary and add them to a QValueList (I know that the QValueList is an implicitly shared class as QString but as far as deep copy are made into CSerialDataFrame, must I apply some deep operations on my QValueList variables too ?).

    I really need some help, maybe more than a simple guide line to lead me to the solution. I am over this problem since friday morning and I don't understant everything, except that I need some help

  13. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    You create Win_QextSerialPort instance in one thread, but then use it in a different one --- are you sure this is correct?

  14. #14
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    I don't know the "good-way-programming" with thread so I don't know if it is correct to do the way I do. I didn't it was a problem to create an instance in one thread and use it in another ... I didn't knew since it brings me trouble with data sharing and so on
    Last edited by yellowmat; 6th March 2006 at 21:46. Reason: Completion and modification

  15. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Quote Originally Posted by yellowmat
    I don't know the "good-way-programming" with thread so I don't know if it is correct to do the way I do. I didn't it was a problem to create an instance in one thread and use it in another ...
    It looks like QextSerialPort has some protection against problems with multiple threads, but still I think that you should instantiate it in CSerialDataFrameDecoder::run().

    I'm not sure why did you split the decoding in two parts (CSerialDataFrameDecoder::run() and CSerialPort::customEvent()). If you create a separate thread for decoding why don't you let it do the whole job?

    Another thing is that in several places you create a temporary frame object just to copy it later:
    Qt Code:
    1. CSerialDataFrame aFrame;
    2. aFrame.setSerialDataFrameValue(frame);
    3. aFrame.setSerialDataFrameStatus(CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart);
    4. this->serialDataFrameDecoded(aFrame);
    To copy to clipboard, switch view to plain text mode 
    Wouldn't it be easier to allocate that CSerialDataFrame on the heap?
    Qt Code:
    1. CSerialDataFrame *aFrame = new CSerialDataFrame( QDeepCopy<QString>( frame ),
    2. CSerialDataFrame::SerialDataFrameStatusIncompleteHasJustTheEndingPart );
    3. serialDataFrameDecoded( aFrame );
    4.  
    5. //...
    6.  
    7. void CSerialDataFrameDecoder::serialDataFrameDecoded( CSerialDataFrame * frame )
    8. {
    9. // Allocate some memory for the custom event
    10. QCustomEvent* ce = new QCustomEvent( 1002, data );
    11.  
    12. // Send the event
    13. QApplication::postEvent( objectOwner, ce );
    14. // The allocated memory for the custum event is freed by Qt so the receiver neither the sender MUST NOT free it
    15. }
    To copy to clipboard, switch view to plain text mode 

    And the last thing --- you should define that "1002" as constant.

  16. The following user says thank you to jacek for this useful post:

    yellowmat (7th March 2006)

  17. #16
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    Ok.

    I'll do all those changes in CSerialDataFrameDecoder and keep you informed.

    Thanks for your help, it is precious.

  18. #17
    Join Date
    Jan 2006
    Posts
    162
    Thanks
    9
    Qt products
    Qt3
    Platforms
    Windows

    Default Re: Architecture problem using threads, custom events and signals/slots

    That's it !

    Jacek, I followed your advices and my CSerialPort is functionnal.

    So I migrate the Win_QextSerialPort instanciation and the process of all CSerialDataFrames into the CSerialDataFrameDecoder. This object send a custom event each time a complete CSerialDataFrame is available. The CSerialPort object receive the event sended by the CSerialDataFrameDecoder and it stores it in a QValueList, waiting some object to ask him using its function read (it pop the data from the QValueList).

    Thank you very much for your help.

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.