Commit 09c26a30 authored by DonLakeFlyer's avatar DonLakeFlyer

parent 8a95bcb7
...@@ -498,6 +498,8 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { ...@@ -498,6 +498,8 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/qgcunittest/TCPLinkTest.h \ src/qgcunittest/TCPLinkTest.h \
src/qgcunittest/TCPLoopBackServer.h \ src/qgcunittest/TCPLoopBackServer.h \
src/qgcunittest/UnitTest.h \ src/qgcunittest/UnitTest.h \
src/Vehicle/FTPManagerTest.h \
src/Vehicle/InitialConnectTest.h \
src/Vehicle/RequestMessageTest.h \ src/Vehicle/RequestMessageTest.h \
src/Vehicle/SendMavCommandWithHandlerTest.h \ src/Vehicle/SendMavCommandWithHandlerTest.h \
src/Vehicle/SendMavCommandWithSignallingTest.h \ src/Vehicle/SendMavCommandWithSignallingTest.h \
...@@ -543,6 +545,8 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin { ...@@ -543,6 +545,8 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/qgcunittest/TCPLoopBackServer.cc \ src/qgcunittest/TCPLoopBackServer.cc \
src/qgcunittest/UnitTest.cc \ src/qgcunittest/UnitTest.cc \
src/qgcunittest/UnitTestList.cc \ src/qgcunittest/UnitTestList.cc \
src/Vehicle/FTPManagerTest.cc \
src/Vehicle/InitialConnectTest.cc \
src/Vehicle/RequestMessageTest.cc \ src/Vehicle/RequestMessageTest.cc \
src/Vehicle/SendMavCommandWithHandlerTest.cc \ src/Vehicle/SendMavCommandWithHandlerTest.cc \
src/Vehicle/SendMavCommandWithSignallingTest.cc \ src/Vehicle/SendMavCommandWithSignallingTest.cc \
...@@ -679,9 +683,9 @@ HEADERS += \ ...@@ -679,9 +683,9 @@ HEADERS += \
src/Terrain/TerrainQuery.h \ src/Terrain/TerrainQuery.h \
src/TerrainTile.h \ src/TerrainTile.h \
src/Vehicle/ComponentInformationManager.h \ src/Vehicle/ComponentInformationManager.h \
src/Vehicle/FTPManager.h \
src/Vehicle/GPSRTKFactGroup.h \ src/Vehicle/GPSRTKFactGroup.h \
src/Vehicle/InitialConnectStateMachine.h \ src/Vehicle/InitialConnectStateMachine.h \
src/Vehicle/MAVLinkFTPManager.h \
src/Vehicle/MAVLinkLogManager.h \ src/Vehicle/MAVLinkLogManager.h \
src/Vehicle/MultiVehicleManager.h \ src/Vehicle/MultiVehicleManager.h \
src/Vehicle/StateMachine.h \ src/Vehicle/StateMachine.h \
...@@ -705,7 +709,6 @@ HEADERS += \ ...@@ -705,7 +709,6 @@ HEADERS += \
src/uas/UASMessageHandler.h \ src/uas/UASMessageHandler.h \
src/AnalyzeView/GeoTagController.h \ src/AnalyzeView/GeoTagController.h \
src/AnalyzeView/ExifParser.h \ src/AnalyzeView/ExifParser.h \
src/uas/FileManager.h \
contains (DEFINES, QGC_ENABLE_PAIRING) { contains (DEFINES, QGC_ENABLE_PAIRING) {
HEADERS += \ HEADERS += \
...@@ -720,7 +723,7 @@ HEADERS += \ ...@@ -720,7 +723,7 @@ HEADERS += \
DebugBuild { DebugBuild {
HEADERS += \ HEADERS += \
src/comm/MockLink.h \ src/comm/MockLink.h \
src/comm/MockLinkFileServer.h \ src/comm/MockLinkFTP.h \
src/comm/MockLinkMissionItemHandler.h \ src/comm/MockLinkMissionItemHandler.h \
} }
...@@ -895,9 +898,9 @@ SOURCES += \ ...@@ -895,9 +898,9 @@ SOURCES += \
src/Terrain/TerrainQuery.cc \ src/Terrain/TerrainQuery.cc \
src/TerrainTile.cc\ src/TerrainTile.cc\
src/Vehicle/ComponentInformationManager.cc \ src/Vehicle/ComponentInformationManager.cc \
src/Vehicle/FTPManager.cc \
src/Vehicle/GPSRTKFactGroup.cc \ src/Vehicle/GPSRTKFactGroup.cc \
src/Vehicle/InitialConnectStateMachine.cc \ src/Vehicle/InitialConnectStateMachine.cc \
src/Vehicle/MAVLinkFTPManager.cc \
src/Vehicle/MAVLinkLogManager.cc \ src/Vehicle/MAVLinkLogManager.cc \
src/Vehicle/MultiVehicleManager.cc \ src/Vehicle/MultiVehicleManager.cc \
src/Vehicle/StateMachine.cc \ src/Vehicle/StateMachine.cc \
...@@ -921,7 +924,6 @@ SOURCES += \ ...@@ -921,7 +924,6 @@ SOURCES += \
src/uas/UASMessageHandler.cc \ src/uas/UASMessageHandler.cc \
src/AnalyzeView/GeoTagController.cc \ src/AnalyzeView/GeoTagController.cc \
src/AnalyzeView/ExifParser.cc \ src/AnalyzeView/ExifParser.cc \
src/uas/FileManager.cc \
contains (DEFINES, QGC_ENABLE_PAIRING) { contains (DEFINES, QGC_ENABLE_PAIRING) {
SOURCES += \ SOURCES += \
...@@ -931,7 +933,7 @@ contains (DEFINES, QGC_ENABLE_PAIRING) { ...@@ -931,7 +933,7 @@ contains (DEFINES, QGC_ENABLE_PAIRING) {
DebugBuild { DebugBuild {
SOURCES += \ SOURCES += \
src/comm/MockLink.cc \ src/comm/MockLink.cc \
src/comm/MockLinkFileServer.cc \ src/comm/MockLinkFTP.cc \
src/comm/MockLinkMissionItemHandler.cc \ src/comm/MockLinkMissionItemHandler.cc \
} }
......
...@@ -28,30 +28,43 @@ QGCTemporaryFile::QGCTemporaryFile(const QString& fileTemplate, QObject* parent) ...@@ -28,30 +28,43 @@ QGCTemporaryFile::QGCTemporaryFile(const QString& fileTemplate, QObject* parent)
} }
QGCTemporaryFile::~QGCTemporaryFile()
{
if (_autoRemove) {
remove();
}
}
bool QGCTemporaryFile::open(QFile::OpenMode openMode) bool QGCTemporaryFile::open(QFile::OpenMode openMode)
{ {
QDir tempDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)); setFileName(_newTempFileFullyQualifiedName(_template));
return QFile::open(openMode);
}
QString QGCTemporaryFile::_newTempFileFullyQualifiedName(const QString& fileTemplate)
{
QString nameTemplate = fileTemplate;
QDir tempDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
// Generate unique, non-existing filename // Generate unique, non-existing filename
static const char rgDigits[] = "0123456789"; static const char rgDigits[] = "0123456789";
QString tempFilename; QString tempFilename;
do { do {
QString uniqueStr; QString uniqueStr;
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
uniqueStr += rgDigits[QRandomGenerator::global()->generate() % 10]; uniqueStr += rgDigits[QRandomGenerator::global()->generate() % 10];
} }
if (_template.contains("XXXXXX")) { if (fileTemplate.contains("XXXXXX")) {
tempFilename = _template.replace("XXXXXX", uniqueStr, Qt::CaseSensitive); tempFilename = nameTemplate.replace("XXXXXX", uniqueStr, Qt::CaseSensitive);
} else { } else {
tempFilename = _template + uniqueStr; tempFilename = nameTemplate + uniqueStr;
} }
} while (tempDir.exists(tempFilename)); } while (tempDir.exists(tempFilename));
setFileName(tempDir.filePath(tempFilename)); return tempDir.filePath(tempFilename);
return QFile::open(openMode);
} }
...@@ -7,9 +7,7 @@ ...@@ -7,9 +7,7 @@
* *
****************************************************************************/ ****************************************************************************/
#pragma once
#ifndef QGCTemporaryFile_H
#define QGCTemporaryFile_H
#include <QFile> #include <QFile>
...@@ -30,13 +28,15 @@ public: ...@@ -30,13 +28,15 @@ public:
// directory path, only file name. // directory path, only file name.
QGCTemporaryFile(const QString& fileTemplate, QObject* parent = nullptr); QGCTemporaryFile(const QString& fileTemplate, QObject* parent = nullptr);
/// @brief Opens the file in ReadWrite mode. ~QGCTemporaryFile();
/// @returns false - open failed
bool open(OpenMode openMode = ReadWrite); bool open(OpenMode openMode = ReadWrite);
void setAutoRemove(bool autoRemove) { _autoRemove = autoRemove; }
private: private:
static QString _newTempFileFullyQualifiedName(const QString& fileTemplate);
QString _template; QString _template;
bool _autoRemove = false;
}; };
#endif
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#include "ComponentInformationManager.h" #include "ComponentInformationManager.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "FTPManager.h"
#include <QStandardPaths>
QGC_LOGGING_CATEGORY(ComponentInformationManagerLog, "ComponentInformationManagerLog") QGC_LOGGING_CATEGORY(ComponentInformationManagerLog, "ComponentInformationManagerLog")
...@@ -22,6 +25,8 @@ int ComponentInformationManager::_cStates = sizeof(ComponentInformationManager:: ...@@ -22,6 +25,8 @@ int ComponentInformationManager::_cStates = sizeof(ComponentInformationManager::
RequestMetaDataTypeStateMachine::StateFn RequestMetaDataTypeStateMachine::_rgStates[]= { RequestMetaDataTypeStateMachine::StateFn RequestMetaDataTypeStateMachine::_rgStates[]= {
RequestMetaDataTypeStateMachine::_stateRequestCompInfo, RequestMetaDataTypeStateMachine::_stateRequestCompInfo,
RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson,
RequestMetaDataTypeStateMachine::_stateRequestTranslationJson,
}; };
int RequestMetaDataTypeStateMachine::_cStates = sizeof(RequestMetaDataTypeStateMachine::_rgStates) / sizeof(RequestMetaDataTypeStateMachine::_rgStates[0]); int RequestMetaDataTypeStateMachine::_cStates = sizeof(RequestMetaDataTypeStateMachine::_rgStates) / sizeof(RequestMetaDataTypeStateMachine::_rgStates[0]);
...@@ -43,33 +48,6 @@ const ComponentInformationManager::StateFn* ComponentInformationManager::rgState ...@@ -43,33 +48,6 @@ const ComponentInformationManager::StateFn* ComponentInformationManager::rgState
return &_rgStates[0]; return &_rgStates[0];
} }
void ComponentInformationManager::_componentInformationReceived(const mavlink_message_t& message)
{
mavlink_component_information_t componentInformation;
mavlink_msg_component_information_decode(&message, &componentInformation);
ComponentInformation_t* pCompInfo = nullptr;
switch (componentInformation.metadata_type) {
case COMP_METADATA_TYPE_VERSION:
qCDebug(ComponentInformationManagerLog) << "COMPONENT_INFORMATION COMP_METADATA_TYPE_VERSION received";
_versionCompInfoAvailable = true;
pCompInfo = &_versionCompInfo;
break;
case COMP_METADATA_TYPE_PARAMETER:
qCDebug(ComponentInformationManagerLog) << "COMPONENT_INFORMATION COMP_METADATA_TYPE_PARAMETER received";
_paramCompInfoAvailable = true;
pCompInfo = &_parameterCompInfo;
break;
}
if (pCompInfo) {
pCompInfo->metadataUID = componentInformation.metadata_uid;
pCompInfo->metadataURI = componentInformation.metadata_uri;
pCompInfo->translationUID = componentInformation.translation_uid;
pCompInfo->translationURI = componentInformation.translation_uri;
}
}
void ComponentInformationManager::requestAllComponentInformation(RequestAllCompleteFn requestAllCompletFn, void * requestAllCompleteFnData) void ComponentInformationManager::requestAllComponentInformation(RequestAllCompleteFn requestAllCompletFn, void * requestAllCompleteFnData)
{ {
_requestAllCompleteFn = requestAllCompletFn; _requestAllCompleteFn = requestAllCompletFn;
...@@ -110,8 +88,9 @@ RequestMetaDataTypeStateMachine::RequestMetaDataTypeStateMachine(ComponentInform ...@@ -110,8 +88,9 @@ RequestMetaDataTypeStateMachine::RequestMetaDataTypeStateMachine(ComponentInform
void RequestMetaDataTypeStateMachine::request(COMP_METADATA_TYPE type) void RequestMetaDataTypeStateMachine::request(COMP_METADATA_TYPE type)
{ {
_type = type; _compInfoAvailable = false;
_stateIndex = -1; _type = type;
_stateIndex = -1;
start(); start();
} }
...@@ -136,12 +115,24 @@ QString RequestMetaDataTypeStateMachine::typeToString(void) ...@@ -136,12 +115,24 @@ QString RequestMetaDataTypeStateMachine::typeToString(void)
return _type == COMP_METADATA_TYPE_VERSION ? "COMP_METADATA_TYPE_VERSION" : "COMP_METADATA_TYPE_PARAM"; return _type == COMP_METADATA_TYPE_VERSION ? "COMP_METADATA_TYPE_VERSION" : "COMP_METADATA_TYPE_PARAM";
} }
void RequestMetaDataTypeStateMachine::handleComponentInformation(const mavlink_message_t& message)
{
mavlink_component_information_t componentInformation;
mavlink_msg_component_information_decode(&message, &componentInformation);
_compInfo.metadataUID = componentInformation.metadata_uid;
_compInfo.metadataURI = componentInformation.metadata_uri;
_compInfo.translationUID = componentInformation.translation_uid;
_compInfo.translationURI = componentInformation.translation_uri;
_compInfoAvailable = true;
}
static void _requestMessageResultHandler(void* resultHandlerData, MAV_RESULT result, Vehicle::RequestMessageResultHandlerFailureCode_t failureCode, const mavlink_message_t &message) static void _requestMessageResultHandler(void* resultHandlerData, MAV_RESULT result, Vehicle::RequestMessageResultHandlerFailureCode_t failureCode, const mavlink_message_t &message)
{ {
RequestMetaDataTypeStateMachine* requestMachine = static_cast<RequestMetaDataTypeStateMachine*>(resultHandlerData); RequestMetaDataTypeStateMachine* requestMachine = static_cast<RequestMetaDataTypeStateMachine*>(resultHandlerData);
if (result == MAV_RESULT_ACCEPTED) { if (result == MAV_RESULT_ACCEPTED) {
requestMachine->compMgr()->_componentInformationReceived(message); requestMachine->handleComponentInformation(message);
} else { } else {
switch (failureCode) { switch (failureCode) {
case Vehicle::RequestMessageFailureCommandError: case Vehicle::RequestMessageFailureCommandError:
...@@ -180,3 +171,63 @@ void RequestMetaDataTypeStateMachine::_stateRequestCompInfo(StateMachine* stateM ...@@ -180,3 +171,63 @@ void RequestMetaDataTypeStateMachine::_stateRequestCompInfo(StateMachine* stateM
} }
} }
void RequestMetaDataTypeStateMachine::_downloadComplete(const QString& file, const QString& errorMsg)
{
qDebug() << "RequestMetaDataTypeStateMachine::_downloadComplete" << file << errorMsg;
advance();
}
void RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson(StateMachine* stateMachine)
{
RequestMetaDataTypeStateMachine* requestMachine = static_cast<RequestMetaDataTypeStateMachine*>(stateMachine);
Vehicle* vehicle = requestMachine->_compMgr->vehicle();
FTPManager* ftpManager = vehicle->ftpManager();
if (requestMachine->_compInfoAvailable) {
ComponentInformation_t& compInfo = requestMachine->_compInfo;
qCDebug(ComponentInformationManagerLog) << "Downloading metadata json" << compInfo.translationURI;
if (_uriIsFTP(compInfo.metadataURI)) {
connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadComplete);
ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation));
} else {
// FIXME: NYI
qCDebug(ComponentInformationManagerLog) << "Skipping metadata json download. http download NYI";
}
} else {
qCDebug(ComponentInformationManagerLog) << "Skipping metadata json download. Component informatiom not available";
requestMachine->advance();
}
}
void RequestMetaDataTypeStateMachine::_stateRequestTranslationJson(StateMachine* stateMachine)
{
RequestMetaDataTypeStateMachine* requestMachine = static_cast<RequestMetaDataTypeStateMachine*>(stateMachine);
Vehicle* vehicle = requestMachine->_compMgr->vehicle();
FTPManager* ftpManager = vehicle->ftpManager();
if (requestMachine->_compInfoAvailable) {
ComponentInformation_t& compInfo = requestMachine->_compInfo;
if (compInfo.translationURI.isEmpty()) {
qCDebug(ComponentInformationManagerLog) << "Skipping translation json download. No translation json specified";
requestMachine->advance();
} else {
qCDebug(ComponentInformationManagerLog) << "Downloading translation json" << compInfo.translationURI;
if (_uriIsFTP(compInfo.translationURI)) {
connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadComplete);
ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation));
} else {
// FIXME: NYI
qCDebug(ComponentInformationManagerLog) << "Skipping translation json download. http download NYI";
}
}
} else {
qCDebug(ComponentInformationManagerLog) << "Skipping translation json download. Component informatiom not available";
requestMachine->advance();
}
}
bool RequestMetaDataTypeStateMachine::_uriIsFTP(const QString& uri)
{
return uri.startsWith("mavlinkftp", Qt::CaseInsensitive);
}
...@@ -18,27 +18,44 @@ Q_DECLARE_LOGGING_CATEGORY(ComponentInformationManagerLog) ...@@ -18,27 +18,44 @@ Q_DECLARE_LOGGING_CATEGORY(ComponentInformationManagerLog)
class Vehicle; class Vehicle;
class ComponentInformationManager; class ComponentInformationManager;
typedef struct {
uint32_t metadataUID;
QString metadataURI;
uint32_t translationUID;
QString translationURI;
} ComponentInformation_t;
class RequestMetaDataTypeStateMachine : public StateMachine class RequestMetaDataTypeStateMachine : public StateMachine
{ {
Q_OBJECT
public: public:
RequestMetaDataTypeStateMachine(ComponentInformationManager* compMgr); RequestMetaDataTypeStateMachine(ComponentInformationManager* compMgr);
void request(COMP_METADATA_TYPE type); void request (COMP_METADATA_TYPE type);
ComponentInformationManager* compMgr(void) { return _compMgr; } QString typeToString (void);
QString typeToString(void); ComponentInformationManager* compMgr (void) { return _compMgr; }
void handleComponentInformation (const mavlink_message_t& message);
// Overrides from StateMachine // Overrides from StateMachine
int stateCount (void) const final; int stateCount (void) const final;
const StateFn* rgStates (void) const final; const StateFn* rgStates (void) const final;
void statesCompleted (void) const final; void statesCompleted (void) const final;
private slots:
void _downloadComplete(const QString& file, const QString& errorMsg);
private: private:
static void _stateRequestCompInfo (StateMachine* stateMachine); static void _stateRequestCompInfo (StateMachine* stateMachine);
static void _stateRequestMetaDataJson (StateMachine* stateMachine); static void _stateRequestMetaDataJson (StateMachine* stateMachine);
static void _stateRequestTranslationJson (StateMachine* stateMachine); static void _stateRequestTranslationJson (StateMachine* stateMachine);
static bool _uriIsFTP (const QString& uri);
ComponentInformationManager* _compMgr; ComponentInformationManager* _compMgr;
COMP_METADATA_TYPE _type = COMP_METADATA_TYPE_VERSION; COMP_METADATA_TYPE _type = COMP_METADATA_TYPE_VERSION;
bool _compInfoAvailable = false;
ComponentInformation_t _compInfo;
static StateFn _rgStates[]; static StateFn _rgStates[];
static int _cStates; static int _cStates;
...@@ -46,30 +63,23 @@ private: ...@@ -46,30 +63,23 @@ private:
class ComponentInformationManager : public StateMachine class ComponentInformationManager : public StateMachine
{ {
Q_OBJECT
public: public:
ComponentInformationManager(Vehicle* vehicle); ComponentInformationManager(Vehicle* vehicle);
typedef struct {
uint32_t metadataUID;
QString metadataURI;
uint32_t translationUID;
QString translationURI;
} ComponentInformation_t;
typedef void (*RequestAllCompleteFn)(void* requestAllCompleteFnData); typedef void (*RequestAllCompleteFn)(void* requestAllCompleteFnData);
void requestAllComponentInformation (RequestAllCompleteFn requestAllCompletFn, void * requestAllCompleteFnData); void requestAllComponentInformation (RequestAllCompleteFn requestAllCompletFn, void * requestAllCompleteFnData);
Vehicle* vehicle (void) { return _vehicle; } Vehicle* vehicle (void) { return _vehicle; }
// These methods should only be called by RequestMetaDataTypeStateMachine
void _componentInformationReceived(const mavlink_message_t& message);
void _stateRequestCompInfoComplete(void);
// Overrides from StateMachine // Overrides from StateMachine
int stateCount (void) const final; int stateCount (void) const final;
const StateFn* rgStates (void) const final; const StateFn* rgStates (void) const final;
private: private:
void _stateRequestCompInfoComplete(void);
static void _stateRequestCompInfoVersion (StateMachine* stateMachine); static void _stateRequestCompInfoVersion (StateMachine* stateMachine);
static void _stateRequestCompInfoParam (StateMachine* stateMachine); static void _stateRequestCompInfoParam (StateMachine* stateMachine);
static void _stateRequestAllCompInfoComplete (StateMachine* stateMachine); static void _stateRequestAllCompInfoComplete (StateMachine* stateMachine);
...@@ -86,4 +96,6 @@ private: ...@@ -86,4 +96,6 @@ private:
static StateFn _rgStates[]; static StateFn _rgStates[];
static int _cStates; static int _cStates;
friend class RequestMetaDataTypeStateMachine;
}; };
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QObject>
#include <QDir>
#include <QTimer>
#include <QQueue>
#include "UASInterface.h"
#include "QGCLoggingCategory.h"
#include "QGCMAVLink.h"
Q_DECLARE_LOGGING_CATEGORY(FTPManagerLog)
class Vehicle;
class FTPManager : public QObject
{
Q_OBJECT
public:
FTPManager(Vehicle* vehicle);
/// Downloads the specified file.
/// @param from File to download from vehicle, fully qualified path. May be in the format mavlinkftp://...
/// @param toDir Local directory to download file to
/// @return true: download has started, false: error, no download
/// Signals downloadComplete, commandError, commandProgress
bool download(const QString& from, const QString& toDir);
/// Stream downloads the specified file.
/// @param from File to download from UAS, fully qualified path. May be in the format mavlinkftp://...
/// @param toDir Local directory to download file to
/// @return true: download has started, false: error, no download
/// Signals downloadComplete, commandError, commandProgress
bool burstDownload(const QString& from, const QString& toDir);
/// Lists the specified directory. Emits listEntry signal for each entry, followed by listComplete signal.
/// @param dirPath Fully qualified path to list
void listDirectory(const QString& dirPath);
/// Upload the specified file to the specified location
void upload(const QString& toPath, const QFileInfo& uploadFile);
/// Create a remote directory
void createDirectory(const QString& directory);
void mavlinkMessageReceived(mavlink_message_t message);
signals:
void downloadComplete (const QString& file, const QString& errorMsg);
void uploadComplete (const QString& errorMsg);
/// Signalled to indicate a new directory entry was received.
void listEntry(const QString& entry);
// Signals associated with all commands
/// Signalled after a command has completed
void commandComplete(void);
void commandError(const QString& msg);
/// Signalled during a lengthy command to show progress
/// @param value Amount of progress: 0.0 = none, 1.0 = complete
void commandProgress(int value);
private slots:
void _ackTimeout(void);
private:
bool _sendOpcodeOnlyCmd (MavlinkFTP::OpCode_t opcode, MavlinkFTP::OpCode_t newWaitState);
void _setupAckTimeout (void);
void _clearAckTimeout (void);
void _emitErrorMessage (const QString& msg);
void _emitListEntry (const QString& entry);
void _sendRequestExpectAck (MavlinkFTP::Request* request);
void _sendRequestNoAck (MavlinkFTP::Request* request);
void _sendMessageOnLink (LinkInterface* link, mavlink_message_t message);
void _fillRequestWithString (MavlinkFTP::Request* request, const QString& str);
void _handlOpenFileROAck (MavlinkFTP::Request* ack);
void _handleReadFileAck (MavlinkFTP::Request* ack, bool burstReadFile);
void _listAckResponse (MavlinkFTP::Request* listAck);
void _createAckResponse (MavlinkFTP::Request* createAck);
void _writeAckResponse (MavlinkFTP::Request* writeAck);
void _writeFileDatablock (void);
void _sendListCommand (void);
void _sendResetCommand (void);
void _downloadComplete (const QString& errorMsg);
void _uploadComplete (const QString& errorMsg);
bool _downloadWorker (const QString& from, const QString& toDir, bool burstReadFile);
void _requestMissingData (void);
MavlinkFTP::OpCode_t _waitState = MavlinkFTP::kCmdNone; ///< Current operation of state machine
MavlinkFTP::OpCode_t _openFileType = MavlinkFTP::kCmdReadFile; ///< Type of read to use after open file succeeds
QTimer _ackTimer; ///< Used to signal a timeout waiting for an ack
int _ackNumTries; ///< current number of tries
Vehicle* _vehicle;
LinkInterface* _dedicatedLink = nullptr; ///< Link to use for communication
MavlinkFTP::Request _lastOutgoingRequest; ///< contains the last outgoing packet
unsigned _listOffset; ///< offset for the current List operation
QString _listPath; ///< path for the current List operation
uint8_t _activeSession = 0; ///< currently active session, 0 for none
uint32_t _readOffset; ///< current read offset
uint32_t _writeOffset; ///< current write offset
uint32_t _writeSize; ///< current write data size
uint32_t _writeFileSize; ///< Size of file being uploaded
QByteArray _writeFileAccumulator; ///< Holds file being uploaded
struct MissingData {
uint32_t offset;
uint32_t size;
};
uint32_t _requestedDownloadOffset; ///< current download offset
QByteArray _readFileAccumulator; ///< Holds file being downloaded
QDir _readFileDownloadDir; ///< Directory to download file to
QString _readFileDownloadFilename; ///< Filename (no path) for download file
int _downloadFileSize; ///< Size of file being downloaded
static const int _ackTimerTimeoutMsecs = 5000;
static const int _ackTimerMaxRetries = 6;
};
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "FTPManagerTest.h"
#include "MultiVehicleManager.h"
#include "QGCApplication.h"
#include "MockLink.h"
#include "FTPManager.h"
const FTPManagerTest::TestCase_t FTPManagerTest::_rgTestCases[] = {
{ "/version.json" },
};
void FTPManagerTest::_testCaseWorker(const TestCase_t& testCase)
{
_connectMockLinkNoInitialConnectSequence();
MultiVehicleManager* vehicleMgr = qgcApp()->toolbox()->multiVehicleManager();
Vehicle* vehicle = vehicleMgr->activeVehicle();
FTPManager* ftpManager = vehicle->ftpManager();
QSignalSpy spyDownloadComplete(ftpManager, &FTPManager::downloadComplete);
// void downloadComplete (const QString& file, const QString& errorMsg);
ftpManager->download(testCase.file, QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QCOMPARE(spyDownloadComplete.wait(10000), true);
QCOMPARE(spyDownloadComplete.count(), 1);
QList<QVariant> arguments = spyDownloadComplete.takeFirst();
qDebug() << arguments[0].toString();
QVERIFY(arguments[1].toString().isEmpty());
_disconnectMockLink();
}
void FTPManagerTest::_performTestCases(void)
{
int index = 0;
for (const TestCase_t& testCase: _rgTestCases) {
qDebug() << "Testing case" << index++;
_testCaseWorker(testCase);
}
}
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include "UnitTest.h"
class FTPManagerTest : public UnitTest
{
Q_OBJECT
private slots:
void _performTestCases(void);
private:
typedef struct {
const char* file;
} TestCase_t;
void _testCaseWorker(const TestCase_t& testCase);
static const TestCase_t _rgTestCases[];
};
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "InitialConnectTest.h"
#include "MultiVehicleManager.h"
#include "QGCApplication.h"
#include "MockLink.h"
InitialConnectTest::TestCase_t InitialConnectTest::_rgTestCases[] = {
{ MockLink::FailRequestMessageNone, MAV_RESULT_ACCEPTED, Vehicle::RequestMessageNoFailure, false },
{ MockLink::FailRequestMessageCommandAcceptedMsgNotSent, MAV_RESULT_FAILED, Vehicle::RequestMessageFailureMessageNotReceived, false },
{ MockLink::FailRequestMessageCommandUnsupported, MAV_RESULT_UNSUPPORTED, Vehicle::RequestMessageFailureCommandError, false },
{ MockLink::FailRequestMessageCommandNoResponse, MAV_RESULT_FAILED, Vehicle::RequestMessageFailureCommandNotAcked, false },
//{ MockLink::FailRequestMessageCommandAcceptedSecondAttempMsgSent, MAV_RESULT_FAILED, Vehicle::RequestMessageNoFailure, false },
};
void InitialConnectTest::_requestMessageResultHandler(void* resultHandlerData, MAV_RESULT commandResult, Vehicle::RequestMessageResultHandlerFailureCode_t failureCode, const mavlink_message_t& message)
{
TestCase_t* testCase = static_cast<TestCase_t*>(resultHandlerData);
testCase->resultHandlerCalled = true;
QCOMPARE((int)testCase->expectedCommandResult, (int)commandResult);
QCOMPARE((int)testCase->expectedFailureCode, (int)failureCode);
if (testCase->expectedFailureCode == Vehicle::RequestMessageNoFailure) {
QVERIFY(message.msgid == MAVLINK_MSG_ID_DEBUG);
}
}
void InitialConnectTest::_testCaseWorker(TestCase_t& testCase)
{
_connectMockLink();
MultiVehicleManager* vehicleMgr = qgcApp()->toolbox()->multiVehicleManager();
Vehicle* vehicle = vehicleMgr->activeVehicle();
_mockLink->setRequestMessageFailureMode(testCase.failureMode);
vehicle->requestMessage(_requestMessageResultHandler, &testCase, MAV_COMP_ID_ALL, MAVLINK_MSG_ID_DEBUG);
for (int i=0; i<100; i++) {
QTest::qWait(100);
if (testCase.resultHandlerCalled) {
break;
}
}
QVERIFY(testCase.resultHandlerCalled);
_disconnectMockLink();
}
void InitialConnectTest::_test(void)
{
_connectMockLink();
//MultiVehicleManager* vehicleMgr = qgcApp()->toolbox()->multiVehicleManager();
//Vehicle* vehicle = vehicleMgr->activeVehicle();
_disconnectMockLink();
}
void InitialConnectTest::_performTestCases(void)
{
int index = 0;
for (TestCase_t& testCase: _rgTestCases) {
qDebug() << "Testing case" << index++;
_testCaseWorker(testCase);
}
}
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include "UnitTest.h"
#include "MockLink.h"
#include "Vehicle.h"
class InitialConnectTest : public UnitTest
{
Q_OBJECT
signals:
void resultHandlerCalled(void);
private slots:
void _test(void);
private:
void _performTestCases(void);
typedef struct {
MockLink::RequestMessageFailureMode_t failureMode;
MAV_RESULT expectedCommandResult;
Vehicle::RequestMessageResultHandlerFailureCode_t expectedFailureCode;
bool resultHandlerCalled;
} TestCase_t;
void _testCaseWorker(TestCase_t& testCase);
static void _requestMessageResultHandler(void* resultHandlerData, MAV_RESULT commandResult, Vehicle::RequestMessageResultHandlerFailureCode_t failureCode, const mavlink_message_t& message);
bool _resultHandlerCalled;
static TestCase_t _rgTestCases[];
};
This diff is collapsed.
This diff is collapsed.
...@@ -9,8 +9,12 @@ ...@@ -9,8 +9,12 @@
#pragma once #pragma once
class StateMachine #include <QObject>
class StateMachine : public QObject
{ {
Q_OBJECT
public: public:
typedef void (*StateFn)(StateMachine* stateMachine); typedef void (*StateFn)(StateMachine* stateMachine);
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include "QGCGeo.h" #include "QGCGeo.h"
#include "TerrainProtocolHandler.h" #include "TerrainProtocolHandler.h"
#include "ParameterManager.h" #include "ParameterManager.h"
#include "MAVLinkFTPManager.h" #include "FTPManager.h"
#include "ComponentInformationManager.h" #include "ComponentInformationManager.h"
#include "InitialConnectStateMachine.h" #include "InitialConnectStateMachine.h"
...@@ -465,9 +465,9 @@ void Vehicle::_commonInit() ...@@ -465,9 +465,9 @@ void Vehicle::_commonInit()
_parameterManager = new ParameterManager(this); _parameterManager = new ParameterManager(this);
connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady); connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady);
_componentInformationManager = new ComponentInformationManager(this); _componentInformationManager = new ComponentInformationManager (this);
_initialConnectStateMachine = new InitialConnectStateMachine(this); _initialConnectStateMachine = new InitialConnectStateMachine (this);
_mavlinkFTPManager = new MAVLinkFTPManager(this); _ftpManager = new FTPManager (this);
_objectAvoidance = new VehicleObjectAvoidance(this, this); _objectAvoidance = new VehicleObjectAvoidance(this, this);
...@@ -715,6 +715,7 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes ...@@ -715,6 +715,7 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
if (!_terrainProtocolHandler->mavlinkMessageReceived(message)) { if (!_terrainProtocolHandler->mavlinkMessageReceived(message)) {
return; return;
} }
_ftpManager->mavlinkMessageReceived(message);
_waitForMavlinkMessageMessageReceived(message); _waitForMavlinkMessageMessageReceived(message);
......
...@@ -44,7 +44,7 @@ class VehicleObjectAvoidance; ...@@ -44,7 +44,7 @@ class VehicleObjectAvoidance;
class TrajectoryPoints; class TrajectoryPoints;
class TerrainProtocolHandler; class TerrainProtocolHandler;
class ComponentInformationManager; class ComponentInformationManager;
class MAVLinkFTPManager; class FTPManager;
class InitialConnectStateMachine; class InitialConnectStateMachine;
#if defined(QGC_AIRMAP_ENABLED) #if defined(QGC_AIRMAP_ENABLED)
...@@ -1009,7 +1009,7 @@ public: ...@@ -1009,7 +1009,7 @@ public:
ParameterManager* parameterManager () { return _parameterManager; } ParameterManager* parameterManager () { return _parameterManager; }
ParameterManager* parameterManager () const { return _parameterManager; } ParameterManager* parameterManager () const { return _parameterManager; }
MAVLinkFTPManager* mavlinkFTPManager () { return _mavlinkFTPManager; } FTPManager* ftpManager () { return _ftpManager; }
VehicleObjectAvoidance* objectAvoidance () { return _objectAvoidance; } VehicleObjectAvoidance* objectAvoidance () { return _objectAvoidance; }
static const int cMaxRcChannels = 18; static const int cMaxRcChannels = 18;
...@@ -1460,7 +1460,7 @@ private: ...@@ -1460,7 +1460,7 @@ private:
RallyPointManager* _rallyPointManager; RallyPointManager* _rallyPointManager;
ParameterManager* _parameterManager = nullptr; ParameterManager* _parameterManager = nullptr;
MAVLinkFTPManager* _mavlinkFTPManager = nullptr; FTPManager* _ftpManager = nullptr;
ComponentInformationManager* _componentInformationManager = nullptr; ComponentInformationManager* _componentInformationManager = nullptr;
InitialConnectStateMachine* _initialConnectStateMachine = nullptr; InitialConnectStateMachine* _initialConnectStateMachine = nullptr;
VehicleObjectAvoidance* _objectAvoidance = nullptr; VehicleObjectAvoidance* _objectAvoidance = nullptr;
......
...@@ -96,7 +96,7 @@ MockLink::MockLink(SharedLinkConfigurationPointer& config) ...@@ -96,7 +96,7 @@ MockLink::MockLink(SharedLinkConfigurationPointer& config)
px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL; px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL;
_mavCustomMode = px4_cm.data; _mavCustomMode = px4_cm.data;
_fileServer = new MockLinkFileServer(_vehicleSystemId, _vehicleComponentId, this); _fileServer = new MockLinkFTP(_vehicleSystemId, _vehicleComponentId, this);
Q_CHECK_PTR(_fileServer); Q_CHECK_PTR(_fileServer);
moveToThread(this); moveToThread(this);
...@@ -1532,7 +1532,7 @@ bool MockLink::_handleRequestMessage(const mavlink_command_long_t& request, bool ...@@ -1532,7 +1532,7 @@ bool MockLink::_handleRequestMessage(const mavlink_command_long_t& request, bool
void MockLink::_sendVersionMetaData(void) void MockLink::_sendVersionMetaData(void)
{ {
mavlink_message_t responseMsg; mavlink_message_t responseMsg;
char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://version.json"; char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://version.json";
char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = ""; char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = "";
mavlink_msg_component_information_pack_chan(_vehicleSystemId, mavlink_msg_component_information_pack_chan(_vehicleSystemId,
...@@ -1551,7 +1551,7 @@ void MockLink::_sendVersionMetaData(void) ...@@ -1551,7 +1551,7 @@ void MockLink::_sendVersionMetaData(void)
void MockLink::_sendParameterMetaData(void) void MockLink::_sendParameterMetaData(void)
{ {
mavlink_message_t responseMsg; mavlink_message_t responseMsg;
char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://parameter.json"; char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://parameter.json";
char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = ""; char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = "";
mavlink_msg_component_information_pack_chan(_vehicleSystemId, mavlink_msg_component_information_pack_chan(_vehicleSystemId,
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <QGeoCoordinate> #include <QGeoCoordinate>
#include "MockLinkMissionItemHandler.h" #include "MockLinkMissionItemHandler.h"
#include "MockLinkFileServer.h" #include "MockLinkFTP.h"
#include "LinkManager.h" #include "LinkManager.h"
#include "QGCMAVLink.h" #include "QGCMAVLink.h"
...@@ -119,7 +119,7 @@ public: ...@@ -119,7 +119,7 @@ public:
/// Sends the specified mavlink message to QGC /// Sends the specified mavlink message to QGC
void respondWithMavlinkMessage(const mavlink_message_t& msg); void respondWithMavlinkMessage(const mavlink_message_t& msg);
MockLinkFileServer* getFileServer(void) { return _fileServer; } MockLinkFTP* getFileServer(void) { return _fileServer; }
// Overrides from LinkInterface // Overrides from LinkInterface
QString getName (void) const override { return _name; } QString getName (void) const override { return _name; }
...@@ -266,7 +266,7 @@ private: ...@@ -266,7 +266,7 @@ private:
double _vehicleLongitude; double _vehicleLongitude;
double _vehicleAltitude; double _vehicleAltitude;
MockLinkFileServer* _fileServer; MockLinkFTP* _fileServer;
bool _sendStatusText; bool _sendStatusText;
bool _apmSendHomePositionOnEmptyList; bool _apmSendHomePositionOnEmptyList;
......
...@@ -8,24 +8,22 @@ ...@@ -8,24 +8,22 @@
****************************************************************************/ ****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#pragma once #pragma once
#include "FileManager.h" #include "QGCMAVLink.h"
#include <QStringList> #include <QStringList>
#include <QFile>
class MockLink; class MockLink;
/// Mock implementation of Mavlink FTP server. /// Mock implementation of Mavlink FTP server.
class MockLinkFileServer : public QObject class MockLinkFTP : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
MockLinkFileServer(uint8_t systemIdServer, uint8_t componentIdServer, MockLink* mockLink); MockLinkFTP(uint8_t systemIdServer, uint8_t componentIdServer, MockLink* mockLink);
/// @brief Sets the list of files returned by the List command. Prepend names with F or D /// @brief Sets the list of files returned by the List command. Prepend names with F or D
/// to indicate (F)ile or (D)irectory. /// to indicate (F)ile or (D)irectory.
...@@ -54,7 +52,7 @@ public: ...@@ -54,7 +52,7 @@ public:
/// Called to handle an FTP message /// Called to handle an FTP message
void handleFTPMessage(const mavlink_message_t& message); void handleFTPMessage(const mavlink_message_t& message);
/// @brief Used to represent a single test case for download testing. /// @brief Used to represent a single test case for download testing.
struct FileTestCase { struct FileTestCase {
const char* filename; ///< Filename to download const char* filename; ///< Filename to download
...@@ -79,33 +77,34 @@ signals: ...@@ -79,33 +77,34 @@ signals:
void resetCommandReceived(void); void resetCommandReceived(void);
private: private:
void _sendAck(uint8_t targetSystemId, uint8_t targetComponentId, uint16_t seqNumber, FileManager::Opcode reqOpcode); void _sendAck (uint8_t targetSystemId, uint8_t targetComponentId, uint16_t seqNumber, MavlinkFTP::OpCode_t reqOpCode);
void _sendNak(uint8_t targetSystemId, uint8_t targetComponentId, FileManager::ErrorCode error, uint16_t seqNumber, FileManager::Opcode reqOpcode); void _sendNak (uint8_t targetSystemId, uint8_t targetComponentId, MavlinkFTP::ErrorCode_t error, uint16_t seqNumber, MavlinkFTP::OpCode_t reqOpCode);
void _sendResponse(uint8_t targetSystemId, uint8_t targetComponentId, FileManager::Request* request, uint16_t seqNumber); void _sendNakErrno (uint8_t targetSystemId, uint8_t targetComponentId, uint8_t nakErrno, uint16_t seqNumber, MavlinkFTP::OpCode_t reqOpCode);
void _listCommand(uint8_t senderSystemId, uint8_t senderComponentId, FileManager::Request* request, uint16_t seqNumber); void _sendResponse (uint8_t targetSystemId, uint8_t targetComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
void _openCommand(uint8_t senderSystemId, uint8_t senderComponentId, FileManager::Request* request, uint16_t seqNumber); void _listCommand (uint8_t senderSystemId, uint8_t senderComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
void _readCommand(uint8_t senderSystemId, uint8_t senderComponentId, FileManager::Request* request, uint16_t seqNumber); void _openCommand (uint8_t senderSystemId, uint8_t senderComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
void _streamCommand(uint8_t senderSystemId, uint8_t senderComponentId, FileManager::Request* request, uint16_t seqNumber); void _readCommand (uint8_t senderSystemId, uint8_t senderComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
void _terminateCommand(uint8_t senderSystemId, uint8_t senderComponentId, FileManager::Request* request, uint16_t seqNumber); void _burstReadCommand (uint8_t senderSystemId, uint8_t senderComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
void _resetCommand(uint8_t senderSystemId, uint8_t senderComponentId, uint16_t seqNumber); void _terminateCommand (uint8_t senderSystemId, uint8_t senderComponentId, MavlinkFTP::Request* request, uint16_t seqNumber);
uint16_t _nextSeqNumber(uint16_t seqNumber); void _resetCommand (uint8_t senderSystemId, uint8_t senderComponentId, uint16_t seqNumber);
uint16_t _nextSeqNumber (uint16_t seqNumber);
QString _createTestCaseTempFile (const FileTestCase& testCase);
/// if request is a string, this ensures it's null-terminated /// if request is a string, this ensures it's null-terminated
static void ensureNullTemination(FileManager::Request* request); static void ensureNullTemination(MavlinkFTP::Request* request);
QStringList _fileList; ///< List of files returned by List command QStringList _fileList; ///< List of files returned by List command
static const uint8_t _sessionId; QFile _currentFile;
uint8_t _readFileLength; ///< Length of active file being read ErrorMode_t _errMode = errModeNone; ///< Currently set error mode, as specified by setErrorMode
ErrorMode_t _errMode; ///< Currently set error mode, as specified by setErrorMode const uint8_t _systemIdServer; ///< System ID for server
const uint8_t _systemIdServer; ///< System ID for server const uint8_t _componentIdServer; ///< Component ID for server
const uint8_t _componentIdServer; ///< Component ID for server MockLink* _mockLink; ///< MockLink to communicate through
MockLink* _mockLink; ///< MockLink to communicate through bool _lastReplyValid = false;
uint16_t _lastReplySequence = 0;
bool _lastReplyValid; mavlink_message_t _lastReply;
uint16_t _lastReplySequence; bool _randomDropsEnabled = false;
mavlink_message_t _lastReply;
bool _randomDropsEnabled; static const uint8_t _sessionId = 1; ///< We only support a single fixed session
}; };
...@@ -80,3 +80,77 @@ QString QGCMAVLink::mavResultToString(MAV_RESULT result) ...@@ -80,3 +80,77 @@ QString QGCMAVLink::mavResultToString(MAV_RESULT result)
return QStringLiteral("MAV_RESULT unknown %1").arg(result); return QStringLiteral("MAV_RESULT unknown %1").arg(result);
} }
} }
QString MavlinkFTP::opCodeToString(OpCode_t opCode)
{
switch (opCode) {
case kCmdNone:
return "None";
case kCmdTerminateSession:
return "Terminate Session";
case kCmdResetSessions:
return "Reset Sessions";
case kCmdListDirectory:
return "List Directory";
case kCmdOpenFileRO:
return "Open File RO";
case kCmdReadFile:
return "Read File";
case kCmdCreateFile:
return "Create File";
case kCmdWriteFile:
return "Write File";
case kCmdRemoveFile:
return "Remove File";
case kCmdCreateDirectory:
return "Create Directory";
case kCmdRemoveDirectory:
return "Remove Directory";
case kCmdOpenFileWO:
return "Open File WO";
case kCmdTruncateFile:
return "Truncate File";
case kCmdRename:
return "Rename";
case kCmdCalcFileCRC32:
return "Calc File CRC32";
case kCmdBurstReadFile:
return "Burst Read File";
case kRspAck:
return "Ack";
case kRspNak:
return "Nak";
}
return "Unknown OpCode";
}
QString MavlinkFTP::errorCodeToString(ErrorCode_t errorCode)
{
switch (errorCode) {
case kErrNone:
return "None";
case kErrFail:
return "Fail";
case kErrFailErrno:
return "Fail Errorno";
case kErrInvalidDataSize:
return "Invalid Data Size";
case kErrInvalidSession:
return "Invalid Session";
case kErrNoSessionsAvailable:
return "No Sessions Available";
case kErrEOF:
return "EOF";
case kErrUnknownCommand:
return "Unknown Command";
case kErrFailFileExists:
return "File Already Exists";
case kErrFailFileProtected:
return "File Protected";
case kErrFailFileNotFound:
return "File Not Found";
}
return "Unknown Error";
}
...@@ -40,6 +40,12 @@ extern mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS]; ...@@ -40,6 +40,12 @@ extern mavlink_status_t m_mavlink_status[MAVLINK_COMM_NUM_BUFFERS];
#pragma warning(pop, 0) #pragma warning(pop, 0)
#endif #endif
#ifdef __GNUC__
#define PACKED_STRUCT( __Declaration__ ) __Declaration__ __attribute__((packed))
#else
#define PACKED_STRUCT( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
#endif
class QGCMAVLink { class QGCMAVLink {
public: public:
static bool isFixedWing (MAV_TYPE mavType); static bool isFixedWing (MAV_TYPE mavType);
...@@ -50,4 +56,78 @@ public: ...@@ -50,4 +56,78 @@ public:
static QString mavResultToString (MAV_RESULT result); static QString mavResultToString (MAV_RESULT result);
}; };
class MavlinkFTP {
public:
/// This is the fixed length portion of the protocol data.
/// This needs to be packed, because it's typecasted from mavlink_file_transfer_protocol_t.payload, which starts
/// at a 3 byte offset, causing an unaligned access to seq_number and offset
PACKED_STRUCT(
typedef struct RequestHeader {
uint16_t seqNumber; ///< sequence number for message
uint8_t session; ///< Session id for read and write commands
uint8_t opcode; ///< Command opcode
uint8_t size; ///< Size of data
uint8_t req_opcode; ///< Request opcode returned in kRspAck, kRspNak message
uint8_t burstComplete; ///< Only used if req_opcode=kCmdBurstReadFile - 1: set of burst packets complete, 0: More burst packets coming.
uint8_t paddng; ///< 32 bit aligment padding
uint32_t offset; ///< Offsets for List and Read commands
}) RequestHeader;
PACKED_STRUCT(
typedef struct Request{
RequestHeader hdr;
// We use a union here instead of just casting (uint32_t)&payload[0] to not break strict aliasing rules
union {
// The entire Request must fit into the payload member of the mavlink_file_transfer_protocol_t structure. We use as many leftover bytes
// after we use up space for the RequestHeader for the data portion of the Request.
uint8_t data[sizeof(((mavlink_file_transfer_protocol_t*)0)->payload) - sizeof(RequestHeader)];
// File length returned by Open command
uint32_t openFileLength;
// Length of file chunk written by write command
uint32_t writeFileLength;
};
}) Request;
typedef enum {
kCmdNone = 0, ///< ignored, always acked
kCmdTerminateSession, ///< Terminates open Read session
kCmdResetSessions, ///< Terminates all open Read sessions
kCmdListDirectory, ///< List files in <path> from <offset>
kCmdOpenFileRO, ///< Opens file at <path> for reading, returns <session>
kCmdReadFile, ///< Reads <size> bytes from <offset> in <session>
kCmdCreateFile, ///< Creates file at <path> for writing, returns <session>
kCmdWriteFile, ///< Writes <size> bytes to <offset> in <session>
kCmdRemoveFile, ///< Remove file at <path>
kCmdCreateDirectory, ///< Creates directory at <path>
kCmdRemoveDirectory, ///< Removes Directory at <path>, must be empty
kCmdOpenFileWO, ///< Opens file at <path> for writing, returns <session>
kCmdTruncateFile, ///< Truncate file at <path> to <offset> length
kCmdRename, ///< Rename <path1> to <path2>
kCmdCalcFileCRC32, ///< Calculate CRC32 for file at <path>
kCmdBurstReadFile, ///< Burst download session file
kRspAck = 128, ///< Ack response
kRspNak, ///< Nak response
} OpCode_t;
/// @brief Error codes returned in Nak response PayloadHeader.data[0].
typedef enum {
kErrNone = 0,
kErrFail, ///< Unknown failure
kErrFailErrno, ///< errno sent back in PayloadHeader.data[1]
kErrInvalidDataSize, ///< PayloadHeader.size is invalid
kErrInvalidSession, ///< Session is not currently open
kErrNoSessionsAvailable, ///< All available Sessions in use
kErrEOF, ///< Offset past end of file for List and Read commands
kErrUnknownCommand, ///< Unknown command opcode
kErrFailFileExists, ///< File exists already
kErrFailFileProtected, ///< File is write protected
kErrFailFileNotFound
} ErrorCode_t;
static QString opCodeToString (OpCode_t opCode);
static QString errorCodeToString(ErrorCode_t errorCode);
};
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#include "CameraCalcTest.h" #include "CameraCalcTest.h"
#include "FWLandingPatternTest.h" #include "FWLandingPatternTest.h"
#include "RequestMessageTest.h" #include "RequestMessageTest.h"
#include "InitialConnectTest.h"
#include "FTPManagerTest.h"
UT_REGISTER_TEST(FactSystemTestGeneric) UT_REGISTER_TEST(FactSystemTestGeneric)
UT_REGISTER_TEST(FactSystemTestPX4) UT_REGISTER_TEST(FactSystemTestPX4)
...@@ -56,6 +58,8 @@ UT_REGISTER_TEST(LinkManagerTest) ...@@ -56,6 +58,8 @@ UT_REGISTER_TEST(LinkManagerTest)
UT_REGISTER_TEST(SendMavCommandWithSignallingTest) UT_REGISTER_TEST(SendMavCommandWithSignallingTest)
UT_REGISTER_TEST(SendMavCommandWithHandlerTest) UT_REGISTER_TEST(SendMavCommandWithHandlerTest)
UT_REGISTER_TEST(RequestMessageTest) UT_REGISTER_TEST(RequestMessageTest)
UT_REGISTER_TEST(FTPManagerTest)
UT_REGISTER_TEST(InitialConnectTest)
UT_REGISTER_TEST(MissionItemTest) UT_REGISTER_TEST(MissionItemTest)
UT_REGISTER_TEST(SimpleMissionItemTest) UT_REGISTER_TEST(SimpleMissionItemTest)
UT_REGISTER_TEST(MissionControllerTest) UT_REGISTER_TEST(MissionControllerTest)
......
This diff is collapsed.
...@@ -60,10 +60,6 @@ UAS::UAS(MAVLinkProtocol* protocol, Vehicle* vehicle, FirmwarePluginManager * fi ...@@ -60,10 +60,6 @@ UAS::UAS(MAVLinkProtocol* protocol, Vehicle* vehicle, FirmwarePluginManager * fi
controlYawManual(true), controlYawManual(true),
controlThrustManual(true), controlThrustManual(true),
#ifndef __mobile__
fileManager(this, vehicle),
#endif
attitudeKnown(false), attitudeKnown(false),
attitudeStamped(false), attitudeStamped(false),
lastAttitude(0), lastAttitude(0),
...@@ -113,10 +109,6 @@ UAS::UAS(MAVLinkProtocol* protocol, Vehicle* vehicle, FirmwarePluginManager * fi ...@@ -113,10 +109,6 @@ UAS::UAS(MAVLinkProtocol* protocol, Vehicle* vehicle, FirmwarePluginManager * fi
_firmwarePluginManager(firmwarePluginManager) _firmwarePluginManager(firmwarePluginManager)
{ {
#ifndef __mobile__
connect(_vehicle, &Vehicle::mavlinkMessageReceived, &fileManager, &FileManager::receiveMessage);
#endif
} }
/** /**
......
...@@ -20,10 +20,6 @@ ...@@ -20,10 +20,6 @@
#include "Vehicle.h" #include "Vehicle.h"
#include "FirmwarePluginManager.h" #include "FirmwarePluginManager.h"
#ifndef __mobile__
#include "FileManager.h"
#endif
Q_DECLARE_LOGGING_CATEGORY(UASLog) Q_DECLARE_LOGGING_CATEGORY(UASLog)
class Vehicle; class Vehicle;
...@@ -109,10 +105,6 @@ public: ...@@ -109,10 +105,6 @@ public:
temperature_var = var; temperature_var = var;
} }
#ifndef __mobile__
friend class FileManager;
#endif
protected: protected:
/// LINK ID AND STATUS /// LINK ID AND STATUS
int uasId; ///< Unique system ID int uasId; ///< Unique system ID
...@@ -138,10 +130,6 @@ protected: ...@@ -138,10 +130,6 @@ protected:
/// POSITION /// POSITION
bool isGlobalPositionKnown; ///< If the global position has been received for this MAV bool isGlobalPositionKnown; ///< If the global position has been received for this MAV
#ifndef __mobile__
FileManager fileManager;
#endif
/// ATTITUDE /// ATTITUDE
bool attitudeKnown; ///< True if attitude was received, false else bool attitudeKnown; ///< True if attitude was received, false else
bool attitudeStamped; ///< Should arriving data be timestamped with the last attitude? This helps with broken system time clocks on the MAV bool attitudeStamped; ///< Should arriving data be timestamped with the last attitude? This helps with broken system time clocks on the MAV
...@@ -182,10 +170,6 @@ public: ...@@ -182,10 +170,6 @@ public:
/** @brief Get the human-readable status message for this code */ /** @brief Get the human-readable status message for this code */
void getStatusForCode(int statusCode, QString& uasState, QString& stateDescription); void getStatusForCode(int statusCode, QString& uasState, QString& stateDescription);
#ifndef __mobile__
virtual FileManager* getFileManager() { return &fileManager; }
#endif
QImage getImage(); QImage getImage();
void requestImage(); void requestImage();
......
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
#include "LinkInterface.h" #include "LinkInterface.h"
#ifndef __mobile__
class FileManager;
#endif
/** /**
* @brief Interface for all robots. * @brief Interface for all robots.
* *
...@@ -43,10 +39,6 @@ public: ...@@ -43,10 +39,6 @@ public:
/** @brief The time interval the robot is switched on **/ /** @brief The time interval the robot is switched on **/
virtual quint64 getUptime() const = 0; virtual quint64 getUptime() const = 0;
#ifndef __mobile__
virtual FileManager* getFileManager() = 0;
#endif
enum StartCalibrationType { enum StartCalibrationType {
StartCalibrationRadio, StartCalibrationRadio,
StartCalibrationGyro, StartCalibrationGyro,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment