Results 1 to 2 of 2

Thread: Signals/Slots timing issue in an handshake communication protocol

  1. #1
    Join Date
    Jan 2021
    Posts
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Signals/Slots timing issue in an handshake communication protocol

    My application has to communicate with a custom device through a handshake protocol which provides for a response (ACK or NACK) for every packet/command sent in both directions. Every packets/commands start with 0x02 marker, then two byte for the size, then the type, then data and finally the close marker 0x03. I've created a separate class for the serial communication with `QSerialPort` and created the signals/slots needed:

    Qt Code:
    1. connect( myInterface, &MyInterface::SendPacket, serialConnection, &SerialConnection::SendPacket, Qt::DirectConnection );
    2. connect( myInterface, &MyInterface::SendAck, serialConnection, &SerialConnection::SendAck, Qt::DirectConnection );
    3. connect( myInterface, &MyInterface::SendNack, serialConnection, &SerialConnection::SendNack, Qt::DirectConnection );
    4. connect( serialConnection, &SerialConnection::ReceivePacket, myInterface, &MyInterface::ReceivePacket, Qt::DirectConnection );
    5. connect( serialConnection, &SerialConnection::ReceiveAck, myInterface, &MyInterface::ReceiveAck, Qt::DirectConnection );
    6. connect( serialConnection, &SerialConnection::ReceiveNack, myInterface, &MyInterface::ReceiveNack, Qt::DirectConnection );
    To copy to clipboard, switch view to plain text mode 

    Following my serial communication class (I've omitted the unnecessary parts of code) :

    serialconnection.cpp
    Qt Code:
    1. SerialConnection::SerialConnection( QWidget *parent ) :
    2. QWidget( parent ),
    3. serial( new QSerialPort )
    4. {
    5. connect( serial, &QSerialPort::readyRead, this, &SerialConnection::ReadData );
    6. }
    7.  
    8. SerialConnection::~SerialConnection()
    9. {
    10.  
    11. }
    12.  
    13. void SerialConnection::SendAck()
    14. {
    15.  
    16. [...]
    17.  
    18. serial->write( ack );
    19. qDebug() << "-> ack";
    20. }
    21.  
    22. void SerialConnection::SendNack()
    23. {
    24. QByteArray nack;
    25.  
    26. [...]
    27.  
    28. serial->write( nack );
    29. qDebug() << "-> nack";
    30. }
    31.  
    32. void SerialConnection::SendPacket( QByteArray packet )
    33. {
    34. serial->write( packet );
    35. qDebug() << "-> " + packet.toHex();
    36. }
    37.  
    38. void SerialConnection::ReadData()
    39. {
    40. [...]
    41. if ( packet.at( 3 ) == COMMUNICATION_USB_PACKET_TYPE_ACK )
    42. {
    43. qDebug() << "<- ack";
    44. emit ReceiveAck();
    45. }
    46. else if ( packet.at( 3 ) == COMMUNICATION_USB_PACKET_TYPE_NACK )
    47. {
    48. qDebug() << "<- nack";
    49. emit ReceiveNack();
    50. }
    51. else
    52. {
    53. qDebug() << "<- packet: " + packet.toHex();
    54. emit ReceivePacket( packet );
    55. }
    56. }
    To copy to clipboard, switch view to plain text mode 

    and my interface class:

    myinterface.cpp
    Qt Code:
    1. MyInterface::MyInterface( QWidget *parent ) :
    2. QWidget( parent ),
    3. ui( new Ui::MyInterface )
    4. {
    5. ui->setupUi( this );
    6.  
    7. connect( ui->pushButtonTest, &QPushButton::clicked, this, &MyInterface::Test );
    8. }
    9.  
    10.  
    11. void Onemytis2Interface::ReceiveAck()
    12. {
    13. ackReceived = true;
    14. }
    15.  
    16. void Onemytis2Interface::ReceiveNack()
    17. {
    18. nackReceived = true;
    19. }
    20.  
    21. void Onemytis2Interface::ReceivePacket( QByteArray packet )
    22. {
    23. switch ( packet.at( 4 ) )
    24. {
    25. case COMMUNICATION_USB_RX_COMMAND_DEVICE_SERIAL_NUMBER_GET:
    26. {
    27. if ( packet.size() == COMMUNICATION_USB_RX_COMMAND_DEVICE_SERIAL_NUMBER_GET_SIZE )
    28. {
    29. emit SendAck();
    30. deviceSerialNumber = packet.mid( 5, 16 );
    31. ui->labelSNValue->setText( deviceSerialNumber );
    32. requestReceived = true;
    33. }
    34. else
    35. {
    36. emit SendNack();
    37. }
    38.  
    39. break;
    40. }
    41.  
    42. case COMMUNICATION_USB_RX_COMMAND_DEVICE_TYPE_GET:
    43. {
    44. if ( packet.size() == COMMUNICATION_USB_RX_COMMAND_DEVICE_TYPE_GET_SIZE )
    45. {
    46. emit SendAck();
    47. deviceType = packet.mid( 5, 16 );
    48. ui->labelModelValue->setText( deviceType );
    49. requestReceived = true;
    50. }
    51. else
    52. {
    53. emit SendNack();
    54. }
    55.  
    56. break;
    57. }
    58.  
    59. case COMMUNICATION_USB_RX_COMMAND_TEST:
    60. {
    61.  
    62. break;
    63. }
    64.  
    65. default:
    66. {
    67. qDebug() << "ERROR";
    68. break;
    69. }
    70. }
    71. }
    72.  
    73.  
    74. void MyInterface::Test()
    75. {
    76. RequestType();
    77. RequestSerialNumber();
    78. }
    79.  
    80.  
    81. void MyInterface::RequestType()
    82. {
    83. QByteArray request;
    84. QByteArray cmdSize;
    85. uint16_t cmdSizeTmp;
    86. int retry;
    87.  
    88. request.append( ( char ) COMMUNICATION_USB_PACKET_STX );
    89. request.append( ( char ) 0x00 );
    90. request.append( ( char ) 0x00 );
    91. request.append( ( char ) COMMUNICATION_USB_PACKET_TYPE_COMMAND );
    92. request.append( ( char ) COMMUNICATION_USB_TX_COMMAND_DEVICE_TYPE_GET );
    93. request.append( ( char ) COMMUNICATION_USB_PACKET_ETX );
    94.  
    95. cmdSizeTmp = request.length();
    96. cmdSize.append( *( char * )&cmdSizeTmp );
    97. cmdSize.append( *( ( char * )&cmdSizeTmp + 1 ) );
    98. request.replace( 1, 2, cmdSize );
    99.  
    100. ackReceived = false;
    101. nackReceived = false;
    102. requestReceived = false;
    103. emit SendPacket( request );
    104.  
    105. retry = 0;
    106.  
    107. while ( ackReceived == false && nackReceived == false )
    108. {
    109. retry++;
    110. QThread::msleep( 1 );
    111.  
    112. if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS )
    113. {
    114. qDebug() << "timeout type response";
    115. break;
    116. }
    117. }
    118.  
    119. if ( ackReceived == true )
    120. {
    121. retry = 0;
    122.  
    123. while ( requestReceived == false )
    124. {
    125. retry++;
    126. QThread::msleep( 1 );
    127.  
    128. if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS )
    129. {
    130. qDebug() << "timeout type request";
    131. break;
    132. }
    133. }
    134. }
    135. else
    136. {
    137. ui->labelTypeValue->setText( "error" );
    138. }
    139. }
    140.  
    141.  
    142. void MyInterface::RequestSerialNumber()
    143. {
    144. QByteArray request;
    145. QByteArray cmdSize;
    146. uint16_t cmdSizeTmp;
    147. int retry;
    148.  
    149. request.append( ( char ) COMMUNICATION_USB_PACKET_STX );
    150. request.append( ( char ) 0x00 );
    151. request.append( ( char ) 0x00 );
    152. request.append( ( char ) COMMUNICATION_USB_PACKET_TYPE_COMMAND );
    153. request.append( ( char ) COMMUNICATION_USB_TX_COMMAND_DEVICE_SERIAL_NUMBER_GET );
    154. request.append( ( char ) COMMUNICATION_USB_PACKET_ETX );
    155.  
    156. cmdSizeTmp = request.length();
    157. cmdSize.append( *( char * )&cmdSizeTmp );
    158. cmdSize.append( *( ( char * )&cmdSizeTmp + 1 ) );
    159. request.replace( 1, 2, cmdSize );
    160.  
    161. ackReceived = false;
    162. nackReceived = false;
    163. requestReceived = false;
    164. emit SendPacket( request );
    165.  
    166. retry = 0;
    167.  
    168. while ( ackReceived == false && nackReceived == false )
    169. {
    170. retry++;
    171. QThread::msleep( 1 );
    172.  
    173. if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS )
    174. {
    175. qDebug() << "timeout sn response";
    176. break;
    177. }
    178. }
    179.  
    180. if ( ackReceived == true )
    181. {
    182. retry = 0;
    183.  
    184. while ( requestReceived == false )
    185. {
    186. retry++;
    187. QThread::msleep( 1 );
    188.  
    189. if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS )
    190. {
    191. qDebug() << "timeout sn response";
    192. break;
    193. }
    194. }
    195. }
    196. else
    197. {
    198. ui->labelSNValue->setText( "error" );
    199. }
    200. }
    To copy to clipboard, switch view to plain text mode 

    Now, if I click the Test push button, I expect the following transactions:

    Qt Code:
    1. -> 020600030803 // The interface send the request packet emitting signal in RequestType()
    2. <- ack // The custom device respond with ack, we are waiting it in the RequestType()
    3. <- packet: 02160003034f74686563000000000000000000000003 //The custom device send to interface the requested packet
    4. -> ack // The interface respond with ack
    5. -> 020600030703 // The interface send the request packet emitting signal in RequestSerialNumber()
    6. <- ack // The custom device respond with ack, we are waiting it in the RequestSerialNumber()
    7. <- packet: 02160003034f74686563000000000000000000000003 //The custom device send to interface the requested packet
    8. -> ack // The interface respond with ack
    To copy to clipboard, switch view to plain text mode 

    but the interface doesn't work as I expect. Usign the `qDebug` I get

    Qt Code:
    1. -> 020600030803 // The interface send the request packet emitting signal in RequestType()
    2. timeout type response // I've a timeout waiting the ack/nack for the RequestType() command
    3. -> 020600030703 // The interface send the request packet emitting signal in RequestSerialNumber()
    4. timeout sn response // I've a timeout waiting the ack/nack for the RequestSerialNumber() command
    5. <- ack // HERE I HAVE THE FIRST ACK OF THE RequestType() COMMAND
    6. <- packet: 02160003034f74686563000000000000000000000003
    7. -> ack
    8. <- nack
    To copy to clipboard, switch view to plain text mode 

    As you can see, I receive the ack for the first command `RequestType()` AFTER the `Test` function terminates and it means after I send two packet, and this cause an error in communication. The state variable `ackReceived`/`nackReceived` never change after emit the `SendPacket` signal if I remain in the call function scope, also if a use a `Qt:irectConnection` between signals and slots.

    I've not much experience in the Qt signal/slot context and I want to understand what goin on in my code to achieve my target.

    Anyone can give me some suggestions and/or clarifications?

  2. #2
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,722
    Thanks
    13
    Thanked 1,605 Times in 1,532 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Signals/Slots timing issue in an handshake communication protocol

    Two things.

    No data is sent or received until your code returns to the Qt event loop. From what I can see, your interface code goes into a busy wait loop more-or-less guaranteeing that Qt never gets a chance.

    When you send or receive data (serial or network) it may not arrive at the other end in the same chunks it was sent. You may get neat whole packets but it would be unwise to rely on this. You seem to be using ReadData to handle incoming bytes. That code must accommodate partial packets and not (as appears to be the case) assume a whole packet at the start of the buffer.

Similar Threads

  1. Object communication, signals and slots
    By bikonja in forum Newbie
    Replies: 3
    Last Post: 2nd July 2015, 17:18
  2. Replies: 2
    Last Post: 18th April 2013, 12:15
  3. Custom QTreeWidgetItem class and signals&slots issue
    By devla in forum Qt Programming
    Replies: 3
    Last Post: 7th July 2012, 00:15
  4. Replies: 6
    Last Post: 2nd May 2012, 09:13
  5. Replies: 4
    Last Post: 16th August 2011, 13:37

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.