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:
Code:
connect( myInterface, &MyInterface::SendPacket, serialConnection, &SerialConnection::SendPacket, Qt::DirectConnection ); connect( myInterface, &MyInterface::SendAck, serialConnection, &SerialConnection::SendAck, Qt::DirectConnection ); connect( myInterface, &MyInterface::SendNack, serialConnection, &SerialConnection::SendNack, Qt::DirectConnection ); connect( serialConnection, &SerialConnection::ReceivePacket, myInterface, &MyInterface::ReceivePacket, Qt::DirectConnection ); connect( serialConnection, &SerialConnection::ReceiveAck, myInterface, &MyInterface::ReceiveAck, Qt::DirectConnection ); connect( serialConnection, &SerialConnection::ReceiveNack, myInterface, &MyInterface::ReceiveNack, Qt::DirectConnection );
Following my serial communication class (I've omitted the unnecessary parts of code) :
serialconnection.cpp
Code:
serial( new QSerialPort ) { connect( serial, &QSerialPort::readyRead, this, &SerialConnection::ReadData ); } SerialConnection::~SerialConnection() { } void SerialConnection::SendAck() { QByteArray ack; [...] serial->write( ack ); qDebug() << "-> ack"; } void SerialConnection::SendNack() { QByteArray nack; [...] serial->write( nack ); qDebug() << "-> nack"; } { serial->write( packet ); qDebug() << "-> " + packet.toHex(); } void SerialConnection::ReadData() { [...] if ( packet.at( 3 ) == COMMUNICATION_USB_PACKET_TYPE_ACK ) { qDebug() << "<- ack"; emit ReceiveAck(); } else if ( packet.at( 3 ) == COMMUNICATION_USB_PACKET_TYPE_NACK ) { qDebug() << "<- nack"; emit ReceiveNack(); } else { qDebug() << "<- packet: " + packet.toHex(); emit ReceivePacket( packet ); } }
and my interface class:
myinterface.cpp
Code:
ui( new Ui::MyInterface ) { ui->setupUi( this ); connect( ui->pushButtonTest, &QPushButton::clicked, this, &MyInterface::Test ); } void Onemytis2Interface::ReceiveAck() { ackReceived = true; } void Onemytis2Interface::ReceiveNack() { nackReceived = true; } { switch ( packet.at( 4 ) ) { case COMMUNICATION_USB_RX_COMMAND_DEVICE_SERIAL_NUMBER_GET: { if ( packet.size() == COMMUNICATION_USB_RX_COMMAND_DEVICE_SERIAL_NUMBER_GET_SIZE ) { emit SendAck(); deviceSerialNumber = packet.mid( 5, 16 ); ui->labelSNValue->setText( deviceSerialNumber ); requestReceived = true; } else { emit SendNack(); } break; } case COMMUNICATION_USB_RX_COMMAND_DEVICE_TYPE_GET: { if ( packet.size() == COMMUNICATION_USB_RX_COMMAND_DEVICE_TYPE_GET_SIZE ) { emit SendAck(); deviceType = packet.mid( 5, 16 ); ui->labelModelValue->setText( deviceType ); requestReceived = true; } else { emit SendNack(); } break; } case COMMUNICATION_USB_RX_COMMAND_TEST: { break; } default: { qDebug() << "ERROR"; break; } } } void MyInterface::Test() { RequestType(); RequestSerialNumber(); } void MyInterface::RequestType() { QByteArray request; QByteArray cmdSize; uint16_t cmdSizeTmp; int retry; request.append( ( char ) COMMUNICATION_USB_PACKET_STX ); request.append( ( char ) 0x00 ); request.append( ( char ) 0x00 ); request.append( ( char ) COMMUNICATION_USB_PACKET_TYPE_COMMAND ); request.append( ( char ) COMMUNICATION_USB_TX_COMMAND_DEVICE_TYPE_GET ); request.append( ( char ) COMMUNICATION_USB_PACKET_ETX ); cmdSizeTmp = request.length(); cmdSize.append( *( char * )&cmdSizeTmp ); cmdSize.append( *( ( char * )&cmdSizeTmp + 1 ) ); request.replace( 1, 2, cmdSize ); ackReceived = false; nackReceived = false; requestReceived = false; emit SendPacket( request ); retry = 0; while ( ackReceived == false && nackReceived == false ) { retry++; if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS ) { qDebug() << "timeout type response"; break; } } if ( ackReceived == true ) { retry = 0; while ( requestReceived == false ) { retry++; if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS ) { qDebug() << "timeout type request"; break; } } } else { ui->labelTypeValue->setText( "error" ); } } void MyInterface::RequestSerialNumber() { QByteArray request; QByteArray cmdSize; uint16_t cmdSizeTmp; int retry; request.append( ( char ) COMMUNICATION_USB_PACKET_STX ); request.append( ( char ) 0x00 ); request.append( ( char ) 0x00 ); request.append( ( char ) COMMUNICATION_USB_PACKET_TYPE_COMMAND ); request.append( ( char ) COMMUNICATION_USB_TX_COMMAND_DEVICE_SERIAL_NUMBER_GET ); request.append( ( char ) COMMUNICATION_USB_PACKET_ETX ); cmdSizeTmp = request.length(); cmdSize.append( *( char * )&cmdSizeTmp ); cmdSize.append( *( ( char * )&cmdSizeTmp + 1 ) ); request.replace( 1, 2, cmdSize ); ackReceived = false; nackReceived = false; requestReceived = false; emit SendPacket( request ); retry = 0; while ( ackReceived == false && nackReceived == false ) { retry++; if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS ) { qDebug() << "timeout sn response"; break; } } if ( ackReceived == true ) { retry = 0; while ( requestReceived == false ) { retry++; if ( retry > COMMUNICATION_USB_PACKET_WAIT_MAX_MS ) { qDebug() << "timeout sn response"; break; } } } else { ui->labelSNValue->setText( "error" ); } }
Now, if I click the Test push button, I expect the following transactions:
Code:
-> 020600030803 // The interface send the request packet emitting signal in RequestType() <- ack // The custom device respond with ack, we are waiting it in the RequestType() <- packet: 02160003034f74686563000000000000000000000003 //The custom device send to interface the requested packet -> ack // The interface respond with ack -> 020600030703 // The interface send the request packet emitting signal in RequestSerialNumber() <- ack // The custom device respond with ack, we are waiting it in the RequestSerialNumber() <- packet: 02160003034f74686563000000000000000000000003 //The custom device send to interface the requested packet -> ack // The interface respond with ack
but the interface doesn't work as I expect. Usign the `qDebug` I get
Code:
-> 020600030803 // The interface send the request packet emitting signal in RequestType() timeout type response // I've a timeout waiting the ack/nack for the RequestType() command -> 020600030703 // The interface send the request packet emitting signal in RequestSerialNumber() timeout sn response // I've a timeout waiting the ack/nack for the RequestSerialNumber() command <- ack // HERE I HAVE THE FIRST ACK OF THE RequestType() COMMAND <- packet: 02160003034f74686563000000000000000000000003 -> ack <- nack
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::DirectConnection` 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?