QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
FTPManager.h
Go to the documentation of this file.
1#pragma once
2
3#include "MAVLinkFTP.h"
4
5#include <QtCore/QObject>
6#include <QtCore/QDir>
7#include <QtCore/QFile>
8#include <QtCore/QTimer>
9class Vehicle;
10
11class FTPManager : public QObject
12{
13 Q_OBJECT
14
15 friend class Vehicle;
16
17public:
18 FTPManager(Vehicle* vehicle);
19
33 bool download(uint8_t fromCompId, const QString& fromURI, const QString& toDir, const QString& fileName="", bool checksize = true);
34
41 bool upload(uint8_t toCompId, const QString& toURI, const QString& fromFile);
42
49 bool listDirectory(uint8_t fromCompId, const QString& fromURI);
50
52 bool listDirectoryWithTimeUnsupported() const { return _listDirWithTimeSupport == WithTimeSupport_t::Unsupported; }
53
59 bool deleteFile(uint8_t fromCompId, const QString& fromURI);
60
63 void cancelDownload();
64
68
71 void cancelDelete();
72
75 void cancelUpload();
76
77 static constexpr const char* mavlinkFTPScheme = "mftp";
78
79signals:
80 void downloadComplete (const QString& file, const QString& errorMsg);
81 void uploadComplete (const QString& file, const QString& errorMsg);
82 void listDirectoryComplete (const QStringList& dirList, const QString& errorMsg);
83 void deleteComplete (const QString& file, const QString& errorMsg);
84
87 void commandProgress(float value);
88
89private slots:
90 void _ackOrNakTimeout(void);
91
92private:
93 typedef void (FTPManager::*StateBeginFn) (void);
94 typedef void (FTPManager::*StateAckNakFn) (const MavlinkFTP::Request* ackOrNak);
95 typedef void (FTPManager::*StateTimeoutFn) (void);
96
97 struct StateFunctions_t {
98 StateBeginFn beginFn;
99 StateAckNakFn ackNakFn;
100 StateTimeoutFn timeoutFn;
101 };
102
103 struct MissingData_t {
104 uint32_t offset;
105 uint32_t cBytesMissing;
106 };
107
108 struct DownloadState_t {
109 uint8_t sessionId;
110 uint32_t expectedOffset;
111 uint32_t bytesWritten;
112 QList<MissingData_t> rgMissingData;
113 QString fullPathOnVehicle;
114 QDir toDir;
115 QString fileName;
116 uint32_t fileSize;
117 QFile file;
118 int retryCount;
119 bool checksize;
120 int sessionReopenCount;
121 int resumeStateIndex;
122 bool active = false;
123
124 bool inProgress() const { return active; }
125
126 void reset() {
127 sessionId = 0;
128 expectedOffset = 0;
129 bytesWritten = 0;
130 retryCount = 0;
131 fileSize = 0;
132 sessionReopenCount = 0;
133 resumeStateIndex = -1;
134 active = false;
135 fullPathOnVehicle.clear();
136 fileName.clear();
137 rgMissingData.clear();
138 file.close();
139 }
140 };
141
142 struct ListDirectoryState_t {
143 uint8_t sessionId;
144 uint32_t expectedOffset;
145 QString fullPathOnVehicle;
146 QStringList rgDirectoryList;
147 int retryCount;
148 MavlinkFTP::OpCode_t opCode;
149
150 bool inProgress() const { return !fullPathOnVehicle.isEmpty(); }
151
152 void reset() {
153 sessionId = 0;
154 expectedOffset = 0;
155 fullPathOnVehicle.clear();
156 rgDirectoryList.clear();
157 retryCount = 0;
159 }
160 };
161
164 enum class WithTimeSupport_t { Unknown, Supported, Unsupported };
165
166 struct DeleteFileState_t {
167 QString fullPathOnVehicle;
168 int retryCount = 0;
169
170 bool inProgress() const { return !fullPathOnVehicle.isEmpty(); }
171
172 void reset() {
173 fullPathOnVehicle.clear();
174 retryCount = 0;
175 }
176 };
177
178 struct UploadState_t {
179 uint8_t sessionId;
180 uint32_t totalBytesSent;
181 uint32_t fileSize;
182 uint32_t lastChunkSize;
183 QFile file;
184 QString fullPathOnVehicle;
185 QString localFilePath;
186 int retryCount;
187 bool cancelled;
188
189 bool inProgress() const { return file.isOpen(); }
190
191 void reset() {
192 sessionId = 0;
193 totalBytesSent = 0;
194 fileSize = 0;
195 lastChunkSize = 0;
196 retryCount = 0;
197 cancelled = false;
198 fullPathOnVehicle.clear();
199 localFilePath.clear();
200 file.close();
201 }
202 };
203
204 void _mavlinkMessageReceived (const mavlink_message_t& message);
205 void _startStateMachine (void);
206 void _advanceStateMachine (void);
207 void _listDirectoryBegin (void);
208 void _listDirectoryAckOrNak (const MavlinkFTP::Request* ackOrNak);
209 void _listDirectoryTimeout (void);
210 void _openFileROBegin (void);
211 void _openFileROAckOrNak (const MavlinkFTP::Request* ackOrNak);
212 void _openFileROTimeout (void);
213 void _burstReadFileBegin (void);
214 void _burstReadFileAckOrNak (const MavlinkFTP::Request* ackOrNak);
215 void _burstReadFileTimeout (void);
216 void _fillMissingBlocksBegin (void);
217 void _fillMissingBlocksAckOrNak (const MavlinkFTP::Request* ackOrNak);
218 void _fillMissingBlocksTimeout (void);
219 void _resetSessionsBegin (void);
220 void _resetSessionsAckOrNak (const MavlinkFTP::Request* ackOrNak);
221 void _resetSessionsTimeout (void);
223 void _clearStaleSessionsBegin (void);
224 void _clearStaleSessionsAckOrNak (const MavlinkFTP::Request* ackOrNak);
225 void _clearStaleSessionsTimeout (void);
227 void _sendResetSessionsNoAck (void);
229 void _setStateMachine (const StateFunctions_t* rgStates, size_t cStates);
230 QString _errorMsgFromNak (const MavlinkFTP::Request* nak);
231 void _sendRequestExpectAck (MavlinkFTP::Request* request);
232 void _downloadCompleteNoError (void) { _downloadComplete(QString()); }
233 void _downloadComplete (const QString& errorMsg);
234 void _fillRequestDataWithString(MavlinkFTP::Request* request, const QString& str);
235 void _fillMissingBlocksWorker (bool firstRequest);
236 void _burstReadFileWorker (bool firstRequest);
238 uint8_t _readChunkSize (void) const;
240 void _downloadSessionLost (void);
242 bool _claimMissingRange (uint32_t offset, uint32_t cBytes);
243 void _listDirectoryWorker (bool firstRequest);
244 bool _parseURI (uint8_t fromCompId, const QString& uri, QString& parsedURI, uint8_t& compId);
245 void _listDirectoryCompleteNoError(void) { _listDirectoryComplete(QString()); }
246 void _listDirectoryComplete (const QString& errorMsg);
247 void _deleteFileBegin (void);
248 void _deleteFileAckOrNak (const MavlinkFTP::Request* ackOrNak);
249 void _deleteFileTimeout (void);
250 void _deleteCompleteNoError (void) { _deleteComplete(QString()); }
251 void _deleteComplete (const QString& errorMsg);
252
253 void _createFileBegin (void);
254 void _createFileAckOrNak (const MavlinkFTP::Request* ackOrNak);
255 void _createFileTimeout (void);
256 void _writeFileBegin (void);
257 void _writeFileAckOrNak (const MavlinkFTP::Request* ackOrNak);
258 void _writeFileTimeout (void);
259 void _writeFileWorker (bool firstRequest);
260 void _uploadFinalize (void);
261 void _uploadComplete (const QString& errorMsg);
262 void _terminateUploadSessionBegin(void);
263 void _terminateUploadSessionAckOrNak(const MavlinkFTP::Request* ackOrNak);
264 void _terminateUploadSessionTimeout(void);
265
266 Vehicle* _vehicle;
267 uint8_t _ftpCompId = MAV_COMP_ID_AUTOPILOT1;
268 QList<StateFunctions_t> _rgStateMachine;
269 DownloadState_t _downloadState;
270 ListDirectoryState_t _listDirectoryState;
271 DeleteFileState_t _deleteState;
272 UploadState_t _uploadState;
273 QTimer _ackOrNakTimeoutTimer;
274 int _currentStateMachineIndex = -1;
275 int _clearStaleSessionsRetryCount = 0;
276 uint16_t _expectedIncomingSeqNumber = 0;
277 WithTimeSupport_t _listDirWithTimeSupport = WithTimeSupport_t::Unknown;
278
279 // Loaded SiK radios queue up to ~2.5s; a shorter timeout misreads that as a dead stream and restarts the burst
280 static const int _ackOrNakTimeoutMsecs = 3000;
281 static const int _maxRetry = 3;
282
283public:
285 static constexpr uint8_t kFullReadChunkSize = sizeof(MavlinkFTP::Request::data);
289 static constexpr uint8_t kRadioReadChunkSize = 110;
291 static constexpr int kMaxDownloadSessionReopens = 2;
293 static constexpr int kTestAckTimeoutMs = 10;
295 static constexpr int kTestOperationMaxWaitMs = 5000;
296};
struct __mavlink_message mavlink_message_t
bool listDirectoryWithTimeUnsupported() const
true when the vehicle NAK'ed kCmdListDirectoryWithTime, i.e. directory listings carry no modification...
Definition FTPManager.h:52
static constexpr int kTestAckTimeoutMs
Ack timeout used in unit tests (much shorter for faster tests)
Definition FTPManager.h:293
void cancelDownload()
bool listDirectory(uint8_t fromCompId, const QString &fromURI)
bool deleteFile(uint8_t fromCompId, const QString &fromURI)
static constexpr uint8_t kRadioReadChunkSize
Definition FTPManager.h:289
bool upload(uint8_t toCompId, const QString &toURI, const QString &fromFile)
Definition FTPManager.cc:89
static constexpr uint8_t kFullReadChunkSize
Bytes requested per ReadFile/BurstReadFile chunk on non-radio links: the full FTP payload.
Definition FTPManager.h:285
static constexpr const char * mavlinkFTPScheme
Definition FTPManager.h:77
void uploadComplete(const QString &file, const QString &errorMsg)
static constexpr int kMaxDownloadSessionReopens
Max times a download re-opens after the server expires the session (PX4 idle timer fires mid-burst)
Definition FTPManager.h:291
void cancelUpload()
static constexpr int kTestOperationMaxWaitMs
Maximum wait time for FTP operations in unit tests (generous for multi-packet transfers)
Definition FTPManager.h:295
void commandProgress(float value)
void downloadComplete(const QString &file, const QString &errorMsg)
void cancelListDirectory()
void deleteComplete(const QString &file, const QString &errorMsg)
void cancelDelete()
bool download(uint8_t fromCompId, const QString &fromURI, const QString &toDir, const QString &fileName="", bool checksize=true)
Definition FTPManager.cc:32
void listDirectoryComplete(const QStringList &dirList, const QString &errorMsg)
@ kCmdListDirectory
List files in <path> from <offset>
Definition MAVLinkFTP.h:42
@ Unsupported
Definition ADSB.h:28