@ -29,6 +29,7 @@ const MockMavlinkFileServer::ErrorMode_t MockMavlinkFileServer::rgFailureModes[]
@@ -29,6 +29,7 @@ const MockMavlinkFileServer::ErrorMode_t MockMavlinkFileServer::rgFailureModes[]
MockMavlinkFileServer : : errModeNoSecondResponse ,
MockMavlinkFileServer : : errModeNakSecondResponse ,
MockMavlinkFileServer : : errModeBadCRC ,
MockMavlinkFileServer : : errModeBadSequence ,
} ;
const size_t MockMavlinkFileServer : : cFailureModes = sizeof ( MockMavlinkFileServer : : rgFailureModes ) / sizeof ( MockMavlinkFileServer : : rgFailureModes [ 0 ] ) ;
@ -52,23 +53,24 @@ MockMavlinkFileServer::MockMavlinkFileServer(void) :
@@ -52,23 +53,24 @@ MockMavlinkFileServer::MockMavlinkFileServer(void) :
/// @brief Handles List command requests. Only supports root folder paths.
/// File list returned is set using the setFileList method.
void MockMavlinkFileServer : : _listCommand ( QGCUASFileManager : : Request * request )
void MockMavlinkFileServer : : _listCommand ( QGCUASFileManager : : Request * request , uint16_t seqNumber )
{
// FIXME: Does not support directories that span multiple packets
QGCUASFileManager : : Request ackResponse ;
QString path ;
uint16_t outgoingSeqNumber = _nextSeqNumber ( seqNumber ) ;
// We only support root path
path = ( char * ) & request - > data [ 0 ] ;
if ( ! path . isEmpty ( ) & & path ! = " / " ) {
_sendNak ( QGCUASFileManager : : kErrNotDir ) ;
_sendNak ( QGCUASFileManager : : kErrNotDir , outgoingSeqNumber ) ;
return ;
}
// Offset requested is past the end of the list
if ( request - > hdr . offset > ( uint32_t ) _fileList . size ( ) ) {
_sendNak ( QGCUASFileManager : : kErrEOF ) ;
_sendNak ( QGCUASFileManager : : kErrEOF , outgoingSeqNumber ) ;
return ;
}
@ -90,25 +92,26 @@ void MockMavlinkFileServer::_listCommand(QGCUASFileManager::Request* request)
@@ -90,25 +92,26 @@ void MockMavlinkFileServer::_listCommand(QGCUASFileManager::Request* request)
bufPtr + = cchFilename + 1 ;
}
_emitResponse ( & ackResponse ) ;
_emitResponse ( & ackResponse , outgoingSeqNumber ) ;
} else if ( _errMode = = errModeNakSecondResponse ) {
// Nak error all subsequent requests
_sendNak ( QGCUASFileManager : : kErrPerm ) ;
_sendNak ( QGCUASFileManager : : kErrPerm , outgoingSeqNumber ) ;
return ;
} else if ( _errMode = = errModeNoSecondResponse ) {
// No response for all subsequent requests
return ;
} else {
// FIXME: Does not support directories that span multiple packets
_sendNak ( QGCUASFileManager : : kErrEOF ) ;
_sendNak ( QGCUASFileManager : : kErrEOF , outgoingSeqNumber ) ;
}
}
/// @brief Handles Open command requests.
void MockMavlinkFileServer : : _openCommand ( QGCUASFileManager : : Request * request )
void MockMavlinkFileServer : : _openCommand ( QGCUASFileManager : : Request * request , uint16_t seqNumber )
{
QGCUASFileManager : : Request response ;
QString path ;
uint16_t outgoingSeqNumber = _nextSeqNumber ( seqNumber ) ;
size_t cchPath = strnlen ( ( char * ) request - > data , sizeof ( request - > data ) ) ;
Q_ASSERT ( cchPath ! = sizeof ( request - > data ) ) ;
@ -126,25 +129,29 @@ void MockMavlinkFileServer::_openCommand(QGCUASFileManager::Request* request)
@@ -126,25 +129,29 @@ void MockMavlinkFileServer::_openCommand(QGCUASFileManager::Request* request)
}
}
if ( ! found ) {
_sendNak ( QGCUASFileManager : : kErrNotFile ) ;
_sendNak ( QGCUASFileManager : : kErrNotFile , outgoingSeqNumber ) ;
return ;
}
response . hdr . magic = ' f ' ;
response . hdr . opcode = QGCUASFileManager : : kRspAck ;
response . hdr . session = _sessionId ;
response . hdr . size = 0 ;
_emitResponse ( & response ) ;
// Data contains file length
response . hdr . size = sizeof ( uint32_t ) ;
* ( ( uint32_t * ) response . data ) = _readFileLength ;
_emitResponse ( & response , outgoingSeqNumber ) ;
}
/// @brief Handles Read command requests.
void MockMavlinkFileServer : : _readCommand ( QGCUASFileManager : : Request * request )
void MockMavlinkFileServer : : _readCommand ( QGCUASFileManager : : Request * request , uint16_t seqNumber )
{
QGCUASFileManager : : Request response ;
QGCUASFileManager : : Request response ;
uint16_t outgoingSeqNumber = _nextSeqNumber ( seqNumber ) ;
if ( request - > hdr . session ! = _sessionId ) {
_sendNak ( QGCUASFileManager : : kErrNoSession ) ;
_sendNak ( QGCUASFileManager : : kErrNoSession , outgoingSeqNumber ) ;
return ;
}
@ -155,7 +162,7 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
@@ -155,7 +162,7 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
// If we get here it means the client is requesting additional data past the first request
if ( _errMode = = errModeNakSecondResponse ) {
// Nak error all subsequent requests
_sendNak ( QGCUASFileManager : : kErrPerm ) ;
_sendNak ( QGCUASFileManager : : kErrPerm , outgoingSeqNumber ) ;
return ;
} else if ( _errMode = = errModeNoSecondResponse ) {
// No rsponse for all subsequent requests
@ -164,7 +171,7 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
@@ -164,7 +171,7 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
}
if ( readOffset > = _readFileLength ) {
_sendNak ( QGCUASFileManager : : kErrEOF ) ;
_sendNak ( QGCUASFileManager : : kErrEOF , outgoingSeqNumber ) ;
return ;
}
@ -182,18 +189,20 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
@@ -182,18 +189,20 @@ void MockMavlinkFileServer::_readCommand(QGCUASFileManager::Request* request)
response . hdr . offset = request - > hdr . offset ;
response . hdr . opcode = QGCUASFileManager : : kRspAck ;
_emitResponse ( & response ) ;
_emitResponse ( & response , outgoingSeqNumber ) ;
}
/// @brief Handles Terminate commands
void MockMavlinkFileServer : : _terminateCommand ( QGCUASFileManager : : Request * request )
void MockMavlinkFileServer : : _terminateCommand ( QGCUASFileManager : : Request * request , uint16_t seqNumber )
{
uint16_t outgoingSeqNumber = _nextSeqNumber ( seqNumber ) ;
if ( request - > hdr . session ! = _sessionId ) {
_sendNak ( QGCUASFileManager : : kErrNoSession ) ;
_sendNak ( QGCUASFileManager : : kErrNoSession , outgoingSeqNumber ) ;
return ;
}
_sendAck ( ) ;
_sendAck ( outgoingSeqNumber ) ;
// Let our test harness know that we got a terminate command. This is used to validate the a Terminate is correctly
// sent after an Open.
@ -203,26 +212,31 @@ void MockMavlinkFileServer::_terminateCommand(QGCUASFileManager::Request* reques
@@ -203,26 +212,31 @@ void MockMavlinkFileServer::_terminateCommand(QGCUASFileManager::Request* reques
/// @brief Handles messages sent to the FTP server.
void MockMavlinkFileServer : : sendMessage ( mavlink_message_t message )
{
QGCUASFileManager : : Request ackResponse ;
QGCUASFileManager : : Request ackResponse ;
Q_ASSERT ( message . msgid = = MAVLINK_MSG_ID_ENCAPSULATED_DATA ) ;
mavlink_encapsulated_data_t requestEncapsulatedData ;
mavlink_msg_encapsulated_data_decode ( & message , & requestEncapsulatedData ) ;
QGCUASFileManager : : Request * request = ( QGCUASFileManager : : Request * ) & requestEncapsulatedData . data [ 0 ] ;
Q_ASSERT ( request - > hdr . magic = = QGCUASFileManager : : kProtocolMagic ) ;
uint16_t incomingSeqNumber = requestEncapsulatedData . seqnr ;
uint16_t outgoingSeqNumber = _nextSeqNumber ( incomingSeqNumber ) ;
if ( _errMode = = errModeNoResponse ) {
// Don't respond to any requests, this shold cause the client to eventually timeout waiting for the ack
return ;
} else if ( _errMode = = errModeNakResponse ) {
// Nak all requests, the actual error send back doesn't really matter as long as it's an error
_sendNak ( QGCUASFileManager : : kErrPerm ) ;
_sendNak ( QGCUASFileManager : : kErrPerm , outgoingSeqNumber ) ;
return ;
}
mavlink_encapsulated_data_t requestEncapsulatedData ;
mavlink_msg_encapsulated_data_decode ( & message , & requestEncapsulatedData ) ;
QGCUASFileManager : : Request * request = ( QGCUASFileManager : : Request * ) & requestEncapsulatedData . data [ 0 ] ;
// Validate CRC
if ( request - > hdr . crc32 ! = QGCUASFileManager : : crc32 ( request ) ) {
_sendNak ( QGCUASFileManager : : kErrCrc ) ;
_sendNak ( QGCUASFileManager : : kErrCrc , outgoingSeqNumber ) ;
}
switch ( request - > hdr . opcode ) {
@ -241,23 +255,23 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
@@ -241,23 +255,23 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
ackResponse . hdr . session = 0 ;
ackResponse . hdr . crc32 = 0 ;
ackResponse . hdr . size = 0 ;
_emitResponse ( & ackResponse ) ;
_emitResponse ( & ackResponse , outgoingSeqNumber ) ;
break ;
case QGCUASFileManager : : kCmdList :
_listCommand ( request ) ;
_listCommand ( request , incomingSeqNumber ) ;
break ;
case QGCUASFileManager : : kCmdOpen :
_openCommand ( request ) ;
_openCommand ( request , incomingSeqNumber ) ;
break ;
case QGCUASFileManager : : kCmdRead :
_readCommand ( request ) ;
_readCommand ( request , incomingSeqNumber ) ;
break ;
case QGCUASFileManager : : kCmdTerminate :
_terminateCommand ( request ) ;
_terminateCommand ( request , incomingSeqNumber ) ;
break ;
// Remainder of commands are NYI
@ -270,13 +284,13 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
@@ -270,13 +284,13 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
// remove file (only if created by server?)
default :
// nack for all NYI opcodes
_sendNak ( QGCUASFileManager : : kErrUnknownCommand ) ;
_sendNak ( QGCUASFileManager : : kErrUnknownCommand , outgoingSeqNumber ) ;
break ;
}
}
/// @brief Sends an Ack
void MockMavlinkFileServer : : _sendAck ( void )
void MockMavlinkFileServer : : _sendAck ( uint16_t seqNumber )
{
QGCUASFileManager : : Request ackResponse ;
@ -285,11 +299,11 @@ void MockMavlinkFileServer::_sendAck(void)
@@ -285,11 +299,11 @@ void MockMavlinkFileServer::_sendAck(void)
ackResponse . hdr . session = 0 ;
ackResponse . hdr . size = 0 ;
_emitResponse ( & ackResponse ) ;
_emitResponse ( & ackResponse , seqNumber ) ;
}
/// @brief Sends a Nak with the specified error code.
void MockMavlinkFileServer : : _sendNak ( QGCUASFileManager : : ErrorCode error )
void MockMavlinkFileServer : : _sendNak ( QGCUASFileManager : : ErrorCode error , uint16_t seqNumber )
{
QGCUASFileManager : : Request nakResponse ;
@ -299,21 +313,34 @@ void MockMavlinkFileServer::_sendNak(QGCUASFileManager::ErrorCode error)
@@ -299,21 +313,34 @@ void MockMavlinkFileServer::_sendNak(QGCUASFileManager::ErrorCode error)
nakResponse . hdr . size = 1 ;
nakResponse . data [ 0 ] = error ;
_emitResponse ( & nakResponse ) ;
_emitResponse ( & nakResponse , seqNumber ) ;
}
/// @brief Emits a Request through the messageReceived signal.
void MockMavlinkFileServer : : _emitResponse ( QGCUASFileManager : : Request * request )
void MockMavlinkFileServer : : _emitResponse ( QGCUASFileManager : : Request * request , uint16_t seqNumber )
{
mavlink_message_t mavlinkMessage ;
request - > hdr . magic = QGCUASFileManager : : kProtocolMagic ;
request - > hdr . crc32 = QGCUASFileManager : : crc32 ( request ) ;
if ( _errMode = = errModeBadCRC ) {
// Return a bad CRC
request - > hdr . crc32 + + ;
}
mavlink_msg_encapsulated_data_pack ( 250 , MAV_COMP_ID_IMU , & mavlinkMessage , 0 /*_encdata_seq*/ , ( uint8_t * ) request ) ;
mavlink_msg_encapsulated_data_pack ( 250 , 50 , & mavlinkMessage , seqNumber , ( uint8_t * ) request ) ;
emit messageReceived ( NULL , mavlinkMessage ) ;
}
/// @brief Generates the next sequence number given an incoming sequence number. Handles generating
/// bad sequence numbers when errModeBadSequence is set.
uint16_t MockMavlinkFileServer : : _nextSeqNumber ( uint16_t seqNumber )
{
uint16_t outgoingSeqNumber = seqNumber + 1 ;
if ( _errMode = = errModeBadSequence ) {
outgoingSeqNumber + + ;
}
return outgoingSeqNumber ;
}