Commit bf9553bb authored by Don Gagne's avatar Don Gagne

New burst download for file transfer

parent 3520241e
......@@ -267,7 +267,7 @@ HEADERS += \
src/QmlControls/ParameterEditorController.h \
src/QmlControls/ScreenTools.h \
src/uas/QGCMAVLinkUASFactory.h \
src/uas/QGCUASFileManager.h \
src/uas/FileManager.h \
src/uas/UAS.h \
src/uas/UASInterface.h \
src/uas/UASManager.h \
......@@ -399,7 +399,7 @@ SOURCES += \
src/QmlControls/ParameterEditorController.cc \
src/QmlControls/ScreenTools.cc \
src/uas/QGCMAVLinkUASFactory.cc \
src/uas/QGCUASFileManager.cc \
src/uas/FileManager.cc \
src/uas/UAS.cc \
src/uas/UASManager.cc \
src/uas/UASMessageHandler.cc \
......
......@@ -21,8 +21,8 @@
======================================================================*/
#ifndef QGCUASFILEMANAGERTEST_H
#define QGCUASFILEMANAGERTEST_H
#ifndef FileManagerTEST_H
#define FileManagerTEST_H
#include <QObject>
#include <QtTest/QtTest>
......@@ -30,20 +30,20 @@
#include "UnitTest.h"
#include "MockUAS.h"
#include "MockMavlinkFileServer.h"
#include "QGCUASFileManager.h"
#include "FileManager.h"
#include "MultiSignalSpy.h"
/// @file
/// @brief QGCUASFileManager unit test
/// @brief FileManager unit test
///
/// @author Don Gagne <don@thegagnes.com>
class QGCUASFileManagerUnitTest : public UnitTest
class FileManagerTest : public UnitTest
{
Q_OBJECT
public:
QGCUASFileManagerUnitTest(void);
FileManagerTest(void);
private slots:
// Test case initialization
......@@ -53,13 +53,16 @@ private slots:
void cleanup(void);
// Test cases
#if 0
void _ackTest(void);
void _noAckTest(void);
void _resetTest(void);
void _listTest(void);
void _downloadTest(void);
// Connected to QGCUASFileManager listEntry signal
void _readDownloadTest(void);
#endif
void _streamDownloadTest(void);
// Connected to FileManager listEntry signal
void listEntry(const QString& entry);
private:
......@@ -88,7 +91,7 @@ private:
MockUAS* _mockUAS;
MockMavlinkFileServer _mockFileServer;
QGCUASFileManager* _fileManager;
FileManager* _fileManager;
MultiSignalSpy* _multiSpy;
static const size_t _cSignals = maxSignalIndex;
......@@ -96,7 +99,7 @@ private:
/// @brief This is the amount of time to wait to allow the FileManager enough time to timeout waiting for an Ack.
/// As such it must be larger than the Ack Timeout used by the FileManager.
static const int _ackTimerTimeoutMsecs = QGCUASFileManager::ackTimerTimeoutMsecs * 2;
static const int _ackTimerTimeoutMsecs = FileManager::ackTimerTimeoutMsecs * 2;
QStringList _fileListReceived;
};
......
This diff is collapsed.
......@@ -25,7 +25,7 @@
#define MOCKMAVLINKFILESERVER_H
#include "MockMavlinkInterface.h"
#include "QGCUASFileManager.h"
#include "FileManager.h"
/// @file
/// @brief Mock implementation of Mavlink FTP server. Used as mavlink plugin to MockUAS.
......@@ -77,7 +77,8 @@ public:
struct FileTestCase {
const char* filename; ///< Filename to download
uint8_t length; ///< Length of file in bytes
bool fMultiPacketResponse; ///< true: multiple acks required to download, false: single ack contains entire download
int packetCount; ///< Number of packets required for data
bool exactFit; ///< true: last packet is exact fit, false: last packet is partially filled
};
/// @brief The numbers of test cases in the rgFileTestCases array.
......@@ -91,13 +92,14 @@ signals:
void terminateCommandReceived(void);
private:
void _sendAck(uint16_t seqNumber);
void _sendNak(QGCUASFileManager::ErrorCode error, uint16_t seqNumber);
void _emitResponse(QGCUASFileManager::Request* request, uint16_t seqNumber);
void _listCommand(QGCUASFileManager::Request* request, uint16_t seqNumber);
void _openCommand(QGCUASFileManager::Request* request, uint16_t seqNumber);
void _readCommand(QGCUASFileManager::Request* request, uint16_t seqNumber);
void _terminateCommand(QGCUASFileManager::Request* request, uint16_t seqNumber);
void _sendAck(uint16_t seqNumber, FileManager::Opcode reqOpcode);
void _sendNak(FileManager::ErrorCode error, uint16_t seqNumber, FileManager::Opcode reqOpcode);
void _emitResponse(FileManager::Request* request, uint16_t seqNumber);
void _listCommand(FileManager::Request* request, uint16_t seqNumber);
void _openCommand(FileManager::Request* request, uint16_t seqNumber);
void _readCommand(FileManager::Request* request, uint16_t seqNumber);
void _streamCommand(FileManager::Request* request, uint16_t seqNumber);
void _terminateCommand(FileManager::Request* request, uint16_t seqNumber);
uint16_t _nextSeqNumber(uint16_t seqNumber);
QStringList _fileList; ///< List of files returned by List command
......
......@@ -21,29 +21,46 @@
======================================================================*/
#ifndef QGCUASFILEMANAGER_H
#define QGCUASFILEMANAGER_H
#ifndef FILEMANAGER_H
#define FILEMANAGER_H
#include <QObject>
#include <QDir>
#include "UASInterface.h"
#include "QGCLoggingCategory.h"
class QGCUASFileManager : public QObject
Q_DECLARE_LOGGING_CATEGORY(FileManagerLog)
class FileManager : public QObject
{
Q_OBJECT
public:
QGCUASFileManager(QObject* parent, UASInterface* uas, uint8_t unitTestSystemIdQGC = 0);
FileManager(QObject* parent, UASInterface* uas, uint8_t unitTestSystemIdQGC = 0);
/// These methods are only used for testing purposes.
bool _sendCmdTestAck(void) { return _sendOpcodeOnlyCmd(kCmdNone, kCOAck); };
bool _sendCmdTestNoAck(void) { return _sendOpcodeOnlyCmd(kCmdTestNoAck, kCOAck); };
bool _sendCmdReset(void) { return _sendOpcodeOnlyCmd(kCmdResetSessions, kCOAck); };
/// @brief Timeout in msecs to wait for an Ack time come back. This is public so we can write unit tests which wait long enough
/// Timeout in msecs to wait for an Ack time come back. This is public so we can write unit tests which wait long enough
/// for the FileManager to timeout.
static const int ackTimerTimeoutMsecs = 1000;
static const int ackTimerTimeoutMsecs = 10000;
/// Downloads the specified file.
/// @param from File to download from UAS, fully qualified path
/// @param downloadDir Local directory to download file to
void downloadPath(const QString& from, const QDir& downloadDir);
/// Stream downloads the specified file.
/// @param from File to download from UAS, fully qualified path
/// @param downloadDir Local directory to download file to
void streamPath(const QString& from, const QDir& downloadDir);
/// 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);
signals:
/// @brief Signalled whenever an error occurs during the listDirectory or downloadPath methods.
void errorMessage(const QString& msg);
......@@ -83,20 +100,23 @@ public slots:
void listDirectory(const QString& dirPath);
void downloadPath(const QString& from, const QDir& downloadDir);
void uploadPath(const QString& toPath, const QFileInfo& uploadFile);
private slots:
void _ackTimeout(void);
protected:
private:
/// @brief This is the fixed length portion of the protocol data. Trying to pack structures across differing compilers is
/// questionable, so we pad the structure ourselves to 32 bit alignment which should get us what we want.
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 padding[2]; ///< 32 bit aligment padding
uint32_t offset; ///< Offsets for List and Read commands
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 padding; ///< 32 bit aligment padding
uint32_t offset; ///< Offsets for List and Read commands
};
struct Request
......@@ -108,7 +128,7 @@ protected:
// 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;
......@@ -119,17 +139,22 @@ protected:
enum Opcode
{
kCmdNone, ///< ignored, always acked
kCmdNone, ///< ignored, always acked
kCmdTerminateSession, ///< Terminates open Read session
kCmdResetSessions, ///< Terminates all open Read sessions
kCmdListDirectory, ///< List files in <path> from <offset>
kCmdOpenFile, ///< 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, ///< Appends <size> bytes to file in <session>
kCmdRemoveFile, ///< Remove file at <path>
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
......@@ -155,20 +180,16 @@ protected:
enum OperationState
{
kCOIdle, // not doing anything
kCOAck, // waiting for an Ack
kCOList, // waiting for List response
kCOOpen, // waiting for Open response
kCORead, // waiting for Read response
kCOCreate, // waiting for Create response
kCOWrite, // waiting for Write response
kCOIdle, // not doing anything
kCOAck, // waiting for an Ack
kCOList, // waiting for List response
kCOOpenRead, // waiting for Open response followed by Read download
kCOOpenStream, // waiting for Open response, followed by Stream download
kCORead, // waiting for Read response
kCOBurst, // waiting for Burst response
kCOWrite, // waiting for Write response
};
protected slots:
void _ackTimeout(void);
protected:
bool _sendOpcodeOnlyCmd(uint8_t opcode, OperationState newOpState);
void _setupAckTimeout(void);
void _clearAckTimeout(void);
......@@ -177,14 +198,15 @@ protected:
void _sendRequest(Request* request);
void _fillRequestWithString(Request* request, const QString& str);
void _openAckResponse(Request* openAck);
void _readAckResponse(Request* readAck);
void _downloadAckResponse(Request* readAck, bool readFile);
void _listAckResponse(Request* listAck);
void _createAckResponse(Request* createAck);
void _writeAckResponse(Request* writeAck);
void _writeFileDatablock(void);
void _sendListCommand(void);
void _sendTerminateCommand(void);
void _closeReadSession(bool success);
void _closeDownloadSession(bool success);
void _downloadWorker(const QString& from, const QDir& downloadDir, bool readFile);
static QString errorString(uint8_t errorCode);
......@@ -203,6 +225,7 @@ protected:
uint32_t _writeOffset; ///< current write offset
uint32_t _writeSize; ///< current write data size
uint32_t _writeFileSize; ///< current write file size
uint32_t _downloadOffset; ///< current download offset
QByteArray _readFileAccumulator; ///< Holds file being downloaded
QByteArray _writeFileAccumulator; ///< Holds file being uploaded
QDir _readFileDownloadDir; ///< Directory to download file to
......@@ -216,4 +239,4 @@ protected:
friend class MockMavlinkFileServer;
};
#endif // QGCUASFILEMANAGER_H
#endif // FileManager_H
......@@ -40,7 +40,7 @@ This file is part of the QGROUNDCONTROL project
#include "QGCFlightGearLink.h"
#include "QGCJSBSimLink.h"
#include "QGCXPlaneLink.h"
#include "QGCUASFileManager.h"
#include "FileManager.h"
Q_DECLARE_LOGGING_CATEGORY(UASLog)
......@@ -332,7 +332,7 @@ public:
bool isFixedWing();
friend class UASWaypointManager;
friend class QGCUASFileManager;
friend class FileManager;
protected: //COMMENTS FOR TEST UNIT
/// LINK ID AND STATUS
......@@ -435,7 +435,7 @@ protected: //COMMENTS FOR TEST UNIT
double groundSpeed; ///< Groundspeed
double bearingToWaypoint; ///< Bearing to next waypoint
UASWaypointManager waypointManager;
QGCUASFileManager fileManager;
FileManager fileManager;
/// ATTITUDE
bool attitudeKnown; ///< True if attitude was received, false else
......@@ -487,7 +487,7 @@ public:
return &waypointManager;
}
virtual QGCUASFileManager* getFileManager() {
virtual FileManager* getFileManager() {
return &fileManager;
}
......
......@@ -42,7 +42,7 @@ This file is part of the QGROUNDCONTROL project
#include "ProtocolInterface.h"
#include "UASWaypointManager.h"
class QGCUASFileManager;
class FileManager;
enum BatteryType
{
......@@ -132,7 +132,7 @@ public:
/** @brief Get reference to the waypoint manager **/
virtual UASWaypointManager* getWaypointManager(void) = 0;
virtual QGCUASFileManager* getFileManager() = 0;
virtual FileManager* getFileManager() = 0;
/** @brief Send a message over this link (to this or to all UAS on this link) */
virtual void sendMessage(LinkInterface* link, mavlink_message_t message) = 0;
......
......@@ -22,14 +22,14 @@
======================================================================*/
#include "QGCUASFileView.h"
#include "uas/QGCUASFileManager.h"
#include "uas/FileManager.h"
#include "QGCFileDialog.h"
#include <QFileDialog>
#include <QDir>
#include <QDebug>
QGCUASFileView::QGCUASFileView(QWidget *parent, QGCUASFileManager *manager) :
QGCUASFileView::QGCUASFileView(QWidget *parent, FileManager *manager) :
QWidget(parent),
_manager(manager),
_listInProgress(false),
......@@ -83,13 +83,12 @@ void QGCUASFileView::_downloadFile(void)
path.prepend("/" + name);
item = item->parent();
} while (item);
qDebug() << "Download: " << path;
_ui.downloadButton->setEnabled(false);
_downloadInProgress = true;
_connectDownloadSignals();
_manager->downloadPath(path, QDir(downloadToHere));
_manager->streamPath(path, QDir(downloadToHere));
}
}
......@@ -163,7 +162,7 @@ void QGCUASFileView::_downloadProgress(unsigned int bytesReceived)
}
}
/// @brief Called when the download associated with the QGCUASFileManager::downloadPath command completes.
/// @brief Called when the download associated with the FileManager::downloadPath command completes.
void QGCUASFileView::_downloadComplete(void)
{
Q_ASSERT(_downloadInProgress);
......@@ -305,11 +304,10 @@ void QGCUASFileView::_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetIt
void QGCUASFileView::_requestDirectoryList(const QString& dir)
{
qDebug() << "List:" << dir;
_manager->listDirectory(dir);
}
/// @brief Connects to the signals associated with the QGCUASFileManager::downloadPath method. We only leave these signals connected
/// @brief Connects to the signals associated with the FileManager::downloadPath method. We only leave these signals connected
/// while a download because there may be multiple UAS, which in turn means multiple QGCUASFileView instances. We only want the signals
/// connected to the active FileView which is doing the current download.
void QGCUASFileView::_connectDownloadSignals(void)
......@@ -335,7 +333,7 @@ void QGCUASFileView::_disconnectDownloadSignals(void)
disconnect(_manager, SIGNAL(errorMessage(const QString&)), this, SLOT(_downloadErrorMessage(const QString&)));
}
/// @brief Connects to the signals associated with the QGCUASFileManager::listDirectory method. We only leave these signals connected
/// @brief Connects to the signals associated with the FileManager::listDirectory method. We only leave these signals connected
/// while a download because there may be multiple UAS, which in turn means multiple QGCUASFileView instances. We only want the signals
/// connected to the active FileView which is doing the current download.
void QGCUASFileView::_connectListSignals(void)
......
......@@ -27,7 +27,7 @@
#include <QWidget>
#include <QTreeWidgetItem>
#include "uas/QGCUASFileManager.h"
#include "uas/FileManager.h"
#include "ui_QGCUASFileView.h"
class QGCUASFileView : public QWidget
......@@ -35,10 +35,10 @@ class QGCUASFileView : public QWidget
Q_OBJECT
public:
explicit QGCUASFileView(QWidget *parent, QGCUASFileManager *manager);
explicit QGCUASFileView(QWidget *parent, FileManager *manager);
protected:
QGCUASFileManager* _manager;
FileManager* _manager;
private slots:
void _refreshTree(void);
......
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