QGCUASFileManager.h 9.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*=====================================================================
 
 QGroundControl Open Source Ground Control Station
 
 (c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 
 This file is part of the QGROUNDCONTROL project
 
 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
 
 ======================================================================*/

24 25 26 27
#ifndef QGCUASFILEMANAGER_H
#define QGCUASFILEMANAGER_H

#include <QObject>
28
#include <QDir>
29

30 31 32 33 34 35
#include "UASInterface.h"

class QGCUASFileManager : public QObject
{
    Q_OBJECT
public:
36
    QGCUASFileManager(QObject* parent, UASInterface* uas, uint8_t unitTestSystemIdQGC = 0);
37 38 39 40
    
    /// These methods are only used for testing purposes.
    bool _sendCmdTestAck(void) { return _sendOpcodeOnlyCmd(kCmdNone, kCOAck); };
    bool _sendCmdTestNoAck(void) { return _sendOpcodeOnlyCmd(kCmdTestNoAck, kCOAck); };
41
    bool _sendCmdReset(void) { return _sendOpcodeOnlyCmd(kCmdResetSessions, kCOAck); };
42 43 44 45
    
    /// @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
    /// for the FileManager to timeout.
    static const int ackTimerTimeoutMsecs = 1000;
46 47

signals:
48
    /// @brief Signalled whenever an error occurs during the listDirectory or downloadPath methods.
Don Gagne's avatar
Don Gagne committed
49
    void errorMessage(const QString& msg);
50 51 52 53 54 55 56
    
    // Signals associated with the listDirectory method
    
    /// @brief Signalled to indicate a new directory entry was received.
    void listEntry(const QString& entry);
    
    /// @brief Signalled after listDirectory completes. If an error occurs during directory listing this signal will not be emitted.
Don Gagne's avatar
Don Gagne committed
57
    void listComplete(void);
58 59 60 61 62 63 64 65 66
    
    // Signals associated with the downloadPath method
    
    /// @brief Signalled after downloadPath is called to indicate length of file being downloaded
    void downloadFileLength(unsigned int length);
    
    /// @brief Signalled during file download to indicate download progress
    ///     @param bytesReceived Number of bytes currently received from file
    void downloadFileProgress(unsigned int bytesReceived);
67

68 69
    /// @brief Signaled to indicate completion of file download. If an error occurs during download this signal will not be emitted.
    void downloadFileComplete(void);
70

71 72 73 74 75 76 77 78 79 80
    /// @brief Signalled after createFile acknowledge is returned to indicate length of file being downloaded
    void uploadFileLength(unsigned int length);

    /// @brief Signalled during file upload to indicate progress
    ///     @param bytesReceived Number of bytes currently transmitted to file
    void uploadFileProgress(unsigned int bytesReceived);

    /// @brief Signaled to indicate completion of file upload. If an error occurs during download this signal will not be emitted.
    void uploadFileComplete(void);

81
public slots:
Lorenz Meier's avatar
Lorenz Meier committed
82
    void receiveMessage(LinkInterface* link, mavlink_message_t message);
83
    void listDirectory(const QString& dirPath);
84
    void downloadPath(const QString& from, const QDir& downloadDir);
85
    void uploadPath(const QString& toPath, const QFileInfo& uploadFile);
86 87

protected:
88
    
Don Gagne's avatar
Don Gagne committed
89 90
    /// @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.
Lorenz Meier's avatar
Lorenz Meier committed
91 92
    struct RequestHeader
        {
Don Gagne's avatar
Don Gagne committed
93 94 95 96
            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
97
            uint8_t     req_opcode; ///< Request opcode returned in kRspAck, kRspNak message
98
            uint8_t     padding[2]; ///< 32 bit aligment padding
Don Gagne's avatar
Don Gagne committed
99
            uint32_t    offset;     ///< Offsets for List and Read commands
Lorenz Meier's avatar
Lorenz Meier committed
100 101
        };

102 103 104
    struct Request
    {
        struct RequestHeader hdr;
105

106
        // We use a union here instead of just casting (uint32_t)&payload[0] to not break strict aliasing rules
107
        union {
108
            // The entire Request must fit into the payload member of the mavlink_file_transfer_protocol_t structure. We use as many leftover bytes
109
            // after we use up space for the RequestHeader for the data portion of the Request.
110
            uint8_t data[sizeof(((mavlink_file_transfer_protocol_t*)0)->payload) - sizeof(RequestHeader)];
111 112 113

            // File length returned by Open command
            uint32_t openFileLength;
114 115 116

            // Length of file chunk written by write command
            uint32_t writeFileLength;
117
        };
118 119
    };

none's avatar
none committed
120
    enum Opcode
121 122 123 124 125 126 127 128 129 130 131 132 133
	{
		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>
		kCmdCreateDirectory,	///< Creates directory at <path>
		kCmdRemoveDirectory,	///< Removes Directory at <path>, must be empty
		
134
		kRspAck = 128,          ///< Ack response
135
		kRspNak,                ///< Nak response
none's avatar
none committed
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150
        // Used for testing only, not part of protocol
        kCmdTestNoAck,          ///< ignored, ack not sent back, should timeout waiting for ack
	};
	
	/// @brief Error codes returned in Nak response PayloadHeader.data[0].
	enum ErrorCode
    {
		kErrNone,
		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
151 152 153
        kErrUnknownCommand,          ///< Unknown command opcode
        kErrFailFileExists,         ///< File exists already
        kErrFailFileProtected       ///< File is write protected
154
    };
none's avatar
none committed
155 156 157 158

    enum OperationState
        {
            kCOIdle,    // not doing anything
159
            kCOAck,     // waiting for an Ack
160 161 162
            kCOList,    // waiting for List response
            kCOOpen,    // waiting for Open response
            kCORead,    // waiting for Read response
163 164
            kCOCreate,  // waiting for Create response
            kCOWrite,   // waiting for Write response
none's avatar
none committed
165
        };
166 167 168 169 170 171 172 173 174 175
    
    
protected slots:
    void _ackTimeout(void);
    
protected:
    bool _sendOpcodeOnlyCmd(uint8_t opcode, OperationState newOpState);
    void _setupAckTimeout(void);
    void _clearAckTimeout(void);
    void _emitErrorMessage(const QString& msg);
176
    void _emitListEntry(const QString& entry);
177
    void _sendRequest(Request* request);
178
    void _fillRequestWithString(Request* request, const QString& str);
179 180 181
    void _openAckResponse(Request* openAck);
    void _readAckResponse(Request* readAck);
    void _listAckResponse(Request* listAck);
182 183 184
    void _createAckResponse(Request* createAck);
    void _writeAckResponse(Request* writeAck);
    void _writeFileDatablock(void);
185 186
    void _sendListCommand(void);
    void _sendTerminateCommand(void);
187
    void _closeReadSession(bool success);
188
    
none's avatar
none committed
189
    static QString errorString(uint8_t errorCode);
190

191 192
    OperationState  _currentOperation;              ///< Current operation of state machine
    QTimer          _ackTimer;                      ///< Used to signal a timeout waiting for an ack
193 194
    
    UASInterface* _mav;
195 196
    
    uint16_t _lastOutgoingSeqNumber; ///< Sequence number sent in last outgoing packet
197

198 199 200 201 202
    unsigned    _listOffset;    ///< offset for the current List operation
    QString     _listPath;      ///< path for the current List operation
    
    uint8_t     _activeSession;             ///< currently active session, 0 for none
    uint32_t    _readOffset;                ///< current read offset
203 204 205
    uint32_t    _writeOffset;               ///< current write offset
    uint32_t    _writeSize;                 ///< current write data size
    uint32_t    _writeFileSize;             ///< current write file size
206
    QByteArray  _readFileAccumulator;       ///< Holds file being downloaded
207
    QByteArray  _writeFileAccumulator;      ///< Holds file being uploaded
208 209
    QDir        _readFileDownloadDir;       ///< Directory to download file to
    QString     _readFileDownloadFilename;  ///< Filename (no path) for download file
210

211 212
    uint8_t     _systemIdQGC;               ///< System ID for QGC
    uint8_t     _systemIdServer;            ///< System ID for server
213 214 215 216
    
    // We give MockMavlinkFileServer friend access so that it can use the data structures and opcodes
    // to build a mock mavlink file server for testing.
    friend class MockMavlinkFileServer;
217 218 219
};

#endif // QGCUASFILEMANAGER_H