QGCUASFileManager.h 6.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 36
#include "UASInterface.h"

class QGCUASFileManager : public QObject
{
    Q_OBJECT
public:
    QGCUASFileManager(QObject* parent, UASInterface* uas);
37 38 39 40 41
    
    /// 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(kCmdReset, 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:
Lorenz Meier's avatar
Lorenz Meier committed
48
    void statusMessage(const QString& msg);
49
    void resetStatusMessages();
Don Gagne's avatar
Don Gagne committed
50 51
    void errorMessage(const QString& msg);
    void listComplete(void);
52
    void openFileLength(unsigned int length);
53 54

public slots:
Lorenz Meier's avatar
Lorenz Meier committed
55
    void receiveMessage(LinkInterface* link, mavlink_message_t message);
56
    void listDirectory(const QString& dirPath);
57
    void downloadPath(const QString& from, const QDir& downloadDir);
58 59

protected:
60
    static const uint8_t kProtocolMagic = 'f';
Lorenz Meier's avatar
Lorenz Meier committed
61 62
    struct RequestHeader
        {
63 64 65 66 67 68
            uint8_t		magic;      ///> Magic byte 'f' to idenitfy FTP protocol
            uint8_t		session;    ///> Session id for read and write commands
            uint8_t		opcode;     ///> Command opcode
            uint8_t		size;       ///> Size of data
            uint32_t	crc32;      ///> CRC for entire Request structure, with crc32 set to 0
            uint32_t	offset;     ///> Offsets for List and Read commands
Lorenz Meier's avatar
Lorenz Meier committed
69 70
        };

71 72 73 74 75 76 77 78
    struct Request
    {
        struct RequestHeader hdr;
        // The entire Request must fit into the data member of the mavlink_encapsulated_data_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_encapsulated_data_t*)0)->data) - sizeof(RequestHeader)];
    };

none's avatar
none committed
79 80
    enum Opcode
        {
81 82 83 84 85 86 87 88 89 90 91 92 93 94
            // Commands
            kCmdNone,       ///> ignored, always acked
            kCmdTerminate,	///> releases sessionID, closes file
            kCmdReset,      ///> terminates all sessions
            kCmdList,       ///> list files in <path> from <offset>
            kCmdOpen,       ///> opens <path> for reading, returns <session>
            kCmdRead,       ///> reads <size> bytes from <offset> in <session>
            kCmdCreate,     ///> creates <path> for writing, returns <session>
            kCmdWrite,      ///> appends <size> bytes at <offset> in <session>
            kCmdRemove,     ///> remove file (only if created by server?)

            // Responses
            kRspAck,        ///> positive acknowledgement of previous command
            kRspNak,        ///> negative acknowledgement of previous command
95
            
96 97
            // Used for testing only, not part of protocol
            kCmdTestNoAck,  // ignored, ack not sent back, should timeout waiting for ack
none's avatar
none committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111
        };

    enum ErrorCode
        {
            kErrNone,
            kErrNoRequest,
            kErrNoSession,
            kErrSequence,
            kErrNotDir,
            kErrNotFile,
            kErrEOF,
            kErrNotAppend,
            kErrTooBig,
            kErrIO,
112 113 114
            kErrPerm,
            kErrUnknownCommand,
            kErrCrc
none's avatar
none committed
115 116 117 118 119 120
        };


    enum OperationState
        {
            kCOIdle,    // not doing anything
121
            kCOAck,     // waiting for an Ack
122 123 124
            kCOList,    // waiting for List response
            kCOOpen,    // waiting for Open response
            kCORead,    // waiting for Read response
none's avatar
none committed
125
        };
126 127 128 129 130 131 132 133 134 135
    
    
protected slots:
    void _ackTimeout(void);
    
protected:
    bool _sendOpcodeOnlyCmd(uint8_t opcode, OperationState newOpState);
    void _setupAckTimeout(void);
    void _clearAckTimeout(void);
    void _emitErrorMessage(const QString& msg);
136
    void _emitStatusMessage(const QString& msg);
137
    void _sendRequest(Request* request);
138
    void _fillRequestWithString(Request* request, const QString& str);
139 140 141 142 143
    void _openAckResponse(Request* openAck);
    void _readAckResponse(Request* readAck);
    void _listAckResponse(Request* listAck);
    void _sendListCommand(void);
    void _sendTerminateCommand(void);
144
    void _closeReadSession(bool success);
145
    
146
    static quint32 crc32(Request* request, unsigned state = 0);
none's avatar
none committed
147
    static QString errorString(uint8_t errorCode);
148

149 150
    OperationState  _currentOperation;              ///> Current operation of state machine
    QTimer          _ackTimer;                      ///> Used to signal a timeout waiting for an ack
151 152
    
    UASInterface* _mav;
153 154
    
    uint16_t _lastOutgoingSeqNumber; ///< Sequence number sent in last outgoing packet
155

156 157 158 159 160 161 162 163
    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
    QByteArray  _readFileAccumulator;       ///> Holds file being downloaded
    QDir        _readFileDownloadDir;       ///> Directory to download file to
    QString     _readFileDownloadFilename;  ///> Filename (no path) for download file
164 165 166 167
    
    // 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;
168 169 170
};

#endif // QGCUASFILEMANAGER_H