Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qgroundcontrol
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Valentin Platzgummer
qgroundcontrol
Commits
f12c0bf3
Commit
f12c0bf3
authored
Jun 26, 2014
by
Don Gagne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for FTP open/read commands
parent
e93fd779
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
394 additions
and
83 deletions
+394
-83
MockMavlinkFileServer.cc
src/qgcunittest/MockMavlinkFileServer.cc
+160
-45
MockMavlinkFileServer.h
src/qgcunittest/MockMavlinkFileServer.h
+19
-1
QGCUASFileManagerTest.cc
src/qgcunittest/QGCUASFileManagerTest.cc
+63
-1
QGCUASFileManagerTest.h
src/qgcunittest/QGCUASFileManagerTest.h
+3
-0
QGCUASFileManager.cc
src/uas/QGCUASFileManager.cc
+130
-30
QGCUASFileManager.h
src/uas/QGCUASFileManager.h
+17
-4
QGCUASFileView.cc
src/ui/QGCUASFileView.cc
+2
-2
No files found.
src/qgcunittest/MockMavlinkFileServer.cc
View file @
f12c0bf3
...
...
@@ -23,52 +23,34 @@
#include "MockMavlinkFileServer.h"
void
MockMavlinkFileServer
::
sendMessage
(
mavlink_message_t
message
)
{
QGCUASFileManager
::
Request
ackResponse
;
QString
path
;
Q_ASSERT
(
message
.
msgid
==
MAVLINK_MSG_ID_ENCAPSULATED_DATA
);
mavlink_encapsulated_data_t
requestEncapsulatedData
;
mavlink_msg_encapsulated_data_decode
(
&
message
,
&
requestEncapsulatedData
);
QGCUASFileManager
::
Request
*
request
=
(
QGCUASFileManager
::
Request
*
)
&
requestEncapsulatedData
.
data
[
0
];
const
char
*
MockMavlinkFileServer
::
smallFilename
=
"small"
;
const
char
*
MockMavlinkFileServer
::
largeFilename
=
"large"
;
// Validate CRC
if
(
request
->
hdr
.
crc32
!=
QGCUASFileManager
::
crc32
(
request
))
{
_sendNak
(
QGCUASFileManager
::
kErrCrc
);
}
// FIXME: -2 to avoid eof on full packet
const
uint8_t
MockMavlinkFileServer
::
smallFileLength
=
sizeof
(((
QGCUASFileManager
::
Request
*
)
0
)
->
data
)
-
2
;
const
uint8_t
MockMavlinkFileServer
::
largeFileLength
=
sizeof
(((
QGCUASFileManager
::
Request
*
)
0
)
->
data
)
+
1
;
switch
(
request
->
hdr
.
opcode
)
{
case
QGCUASFileManager
:
:
kCmdTestNoAck
:
// ignored, ack not sent back, for testing only
break
;
const
uint8_t
MockMavlinkFileServer
::
_sessionId
=
1
;
case
QGCUASFileManager
:
:
kCmdReset
:
// terminates all sessions
// Fall through to send back Ack
case
QGCUASFileManager
:
:
kCmdNone
:
// ignored, always acked
ackResponse
.
hdr
.
magic
=
'f'
;
ackResponse
.
hdr
.
opcode
=
QGCUASFileManager
::
kRspAck
;
ackResponse
.
hdr
.
session
=
0
;
ackResponse
.
hdr
.
crc32
=
0
;
ackResponse
.
hdr
.
size
=
0
;
_emitResponse
(
&
ackResponse
);
break
;
/// @brief Handles List command requests. Only supports root folder paths.
/// File list returned is set using the setFileList method.
void
MockMavlinkFileServer
::
_listCommand
(
QGCUASFileManager
::
Request
*
request
)
{
QGCUASFileManager
::
Request
ackResponse
;
QString
path
;
case
QGCUASFileManager
:
:
kCmdList
:
// We only support root path
path
=
(
char
*
)
&
request
->
data
[
0
];
if
(
!
path
.
isEmpty
()
&&
path
!=
"/"
)
{
_sendNak
(
QGCUASFileManager
::
kErrNotDir
);
break
;
return
;
}
// Offset requested is past the end of the list
if
(
request
->
hdr
.
offset
>
(
uint32_t
)
_fileList
.
size
())
{
_sendNak
(
QGCUASFileManager
::
kErrEOF
);
break
;
return
;
}
ackResponse
.
hdr
.
magic
=
'f'
;
...
...
@@ -99,17 +81,148 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
}
_emitResponse
(
&
ackResponse
);
}
/// @brief Handles Open command requests. Two filenames are supported:
/// '/small' - file fits in a single packet
/// '/large' - file requires multiple packets to be sent
/// In all cases file contents are one byte data length, followed by a single
/// byte repeating increasing sequence (0x00, 0x01, .. 0xFF) for specified
/// number of bytes.
void
MockMavlinkFileServer
::
_openCommand
(
QGCUASFileManager
::
Request
*
request
)
{
QGCUASFileManager
::
Request
response
;
QString
path
;
// Make sure one byte of length is enough to overflow into two packets.
Q_ASSERT
((
sizeof
(
request
->
data
)
&
0xFF
)
==
sizeof
(
request
->
data
));
path
=
(
char
*
)
&
request
->
data
[
0
];
if
(
path
==
smallFilename
)
{
_readFileLength
=
smallFileLength
;
qDebug
()
<<
"Reading file length"
<<
smallFileLength
;
}
else
if
(
path
==
largeFilename
)
{
_readFileLength
=
largeFileLength
;
qDebug
()
<<
"Reading file length"
<<
largeFileLength
;
}
else
{
_sendNak
(
QGCUASFileManager
::
kErrNotFile
);
return
;
}
response
.
hdr
.
magic
=
'f'
;
response
.
hdr
.
opcode
=
QGCUASFileManager
::
kRspAck
;
response
.
hdr
.
session
=
_sessionId
;
response
.
hdr
.
size
=
0
;
_emitResponse
(
&
response
);
}
/// @brief Handles Read command requests.
void
MockMavlinkFileServer
::
_readCommand
(
QGCUASFileManager
::
Request
*
request
)
{
qDebug
()
<<
"Read command:"
<<
request
->
hdr
.
offset
;
QGCUASFileManager
::
Request
response
;
if
(
request
->
hdr
.
session
!=
_sessionId
)
{
_sendNak
(
QGCUASFileManager
::
kErrNoSession
);
return
;
}
if
(
request
->
hdr
.
size
>
sizeof
(
response
.
data
))
{
_sendNak
(
QGCUASFileManager
::
kErrPerm
);
return
;
}
uint8_t
size
=
0
;
uint32_t
offset
=
request
->
hdr
.
offset
;
// Offset check is > instead of >= to take into accoutn extra length byte at beginning of file
if
(
offset
>
_readFileLength
)
{
_sendNak
(
QGCUASFileManager
::
kErrIO
);
return
;
}
// Write length byte if needed
if
(
offset
==
0
)
{
response
.
data
[
0
]
=
_readFileLength
;
offset
++
;
size
++
;
}
// Write file bytes. Data is a repeating sequence of 0x00, 0x01, .. 0xFF.
for
(;
size
<
sizeof
(
response
.
data
)
&&
offset
<=
_readFileLength
;
offset
++
,
size
++
)
{
response
.
data
[
size
]
=
(
offset
-
1
)
&
0xFF
;
}
qDebug
()
<<
"_readCommand bytes written"
<<
size
;
// If we didn't write any bytes it was a bad request
if
(
size
==
0
)
{
_sendNak
(
QGCUASFileManager
::
kErrEOF
);
return
;
}
response
.
hdr
.
magic
=
'f'
;
response
.
hdr
.
opcode
=
QGCUASFileManager
::
kRspAck
;
response
.
hdr
.
session
=
_sessionId
;
response
.
hdr
.
size
=
size
;
response
.
hdr
.
offset
=
request
->
hdr
.
offset
;
_emitResponse
(
&
response
);
}
/// @brief Handles messages sent to the FTP server.
void
MockMavlinkFileServer
::
sendMessage
(
mavlink_message_t
message
)
{
QGCUASFileManager
::
Request
ackResponse
;
Q_ASSERT
(
message
.
msgid
==
MAVLINK_MSG_ID_ENCAPSULATED_DATA
);
mavlink_encapsulated_data_t
requestEncapsulatedData
;
mavlink_msg_encapsulated_data_decode
(
&
message
,
&
requestEncapsulatedData
);
QGCUASFileManager
::
Request
*
request
=
(
QGCUASFileManager
::
Request
*
)
&
requestEncapsulatedData
.
data
[
0
];
// Validate CRC
if
(
request
->
hdr
.
crc32
!=
QGCUASFileManager
::
crc32
(
request
))
{
_sendNak
(
QGCUASFileManager
::
kErrCrc
);
}
switch
(
request
->
hdr
.
opcode
)
{
case
QGCUASFileManager
:
:
kCmdTestNoAck
:
// ignored, ack not sent back, for testing only
break
;
case
QGCUASFileManager
:
:
kCmdReset
:
// terminates all sessions
// Fall through to send back Ack
case
QGCUASFileManager
:
:
kCmdNone
:
// ignored, always acked
ackResponse
.
hdr
.
magic
=
'f'
;
ackResponse
.
hdr
.
opcode
=
QGCUASFileManager
::
kRspAck
;
ackResponse
.
hdr
.
session
=
0
;
ackResponse
.
hdr
.
crc32
=
0
;
ackResponse
.
hdr
.
size
=
0
;
_emitResponse
(
&
ackResponse
);
break
;
case
QGCUASFileManager
:
:
kCmdList
:
_listCommand
(
request
);
break
;
case
QGCUASFileManager
:
:
kCmdOpen
:
_openCommand
(
request
);
break
;
case
QGCUASFileManager
:
:
kCmdRead
:
_readCommand
(
request
);
break
;
// Remainder of commands are NYI
case
QGCUASFileManager
:
:
kCmdTerminate
:
// releases sessionID, closes file
case
QGCUASFileManager
:
:
kCmdOpen
:
// opens <path> for reading, returns <session>
case
QGCUASFileManager
:
:
kCmdRead
:
// reads <size> bytes from <offset> in <session>
case
QGCUASFileManager
:
:
kCmdCreate
:
// creates <path> for writing, returns <session>
case
QGCUASFileManager
:
:
kCmdWrite
:
...
...
@@ -123,6 +236,7 @@ void MockMavlinkFileServer::sendMessage(mavlink_message_t message)
}
}
/// @brief Sends a Nak with the specified error code.
void
MockMavlinkFileServer
::
_sendNak
(
QGCUASFileManager
::
ErrorCode
error
)
{
QGCUASFileManager
::
Request
nakResponse
;
...
...
@@ -136,6 +250,7 @@ void MockMavlinkFileServer::_sendNak(QGCUASFileManager::ErrorCode error)
_emitResponse
(
&
nakResponse
);
}
/// @brief Emits a Request through the messageReceived signal.
void
MockMavlinkFileServer
::
_emitResponse
(
QGCUASFileManager
::
Request
*
request
)
{
mavlink_message_t
mavlinkMessage
;
...
...
src/qgcunittest/MockMavlinkFileServer.h
View file @
f12c0bf3
...
...
@@ -27,6 +27,11 @@
#include "MockMavlinkInterface.h"
#include "QGCUASFileManager.h"
/// @file
/// @brief Mock implementation of Mavlink FTP server. Used as mavlink plugin to MockUAS.
/// Only root directory access is supported.
///
/// @author Don Gagne <don@thegagnes.com>
#include <QStringList>
...
...
@@ -37,16 +42,29 @@ class MockMavlinkFileServer : public MockMavlinkInterface
public:
MockMavlinkFileServer
(
void
)
{
};
/// @brief Sets the list of files returned by the List command. Prepend names with F or D
/// to indicate (F)ile or (D)irectory.
void
setFileList
(
QStringList
&
fileList
)
{
_fileList
=
fileList
;
}
// From MockMavlinkInterface
virtual
void
sendMessage
(
mavlink_message_t
message
);
static
const
char
*
smallFilename
;
static
const
char
*
largeFilename
;
static
const
uint8_t
smallFileLength
;
static
const
uint8_t
largeFileLength
;
private:
void
_sendNak
(
QGCUASFileManager
::
ErrorCode
error
);
void
_emitResponse
(
QGCUASFileManager
::
Request
*
request
);
void
_listCommand
(
QGCUASFileManager
::
Request
*
request
);
void
_openCommand
(
QGCUASFileManager
::
Request
*
request
);
void
_readCommand
(
QGCUASFileManager
::
Request
*
request
);
QStringList
_fileList
;
///< List of files returned by List command
QStringList
_fileList
;
static
const
uint8_t
_sessionId
;
uint8_t
_readFileLength
;
///< Length of active file being read
};
#endif
src/qgcunittest/QGCUASFileManagerTest.cc
View file @
f12c0bf3
...
...
@@ -24,7 +24,9 @@
#include "QGCUASFileManagerTest.h"
/// @file
/// @brief QGCUASFileManager unit test
/// @brief QGCUASFileManager unit test. Note: All code here assumes all work between
/// the unit test, mack mavlink file server and file manager is happening on
/// the same thread.
///
/// @author Don Gagne <don@thegagnes.com>
...
...
@@ -154,3 +156,63 @@ void QGCUASFileManagerUnitTest::_listTest(void)
QCOMPARE
(
_multiSpy
->
checkNoSignalByMask
(
errorMessageSignalMask
),
true
);
// We should not get an error signals
QVERIFY
(
_fileListReceived
==
fileListExpected
);
}
void
QGCUASFileManagerUnitTest
::
_validateFileContents
(
const
QString
&
filePath
,
uint8_t
length
)
{
QFile
file
(
filePath
);
QVERIFY
(
file
.
open
(
QIODevice
::
ReadOnly
));
QByteArray
bytes
=
file
.
readAll
();
file
.
close
();
QCOMPARE
(
bytes
.
length
(),
length
+
1
);
// +1 for length byte
// Validate length byte
QCOMPARE
((
uint8_t
)
bytes
[
0
],
length
);
// Validate file contents
for
(
uint8_t
i
=
1
;
i
<
bytes
.
length
();
i
++
)
{
QCOMPARE
((
uint8_t
)
bytes
[
i
],
(
uint8_t
)((
i
-
1
)
&
0xFF
));
}
}
void
QGCUASFileManagerUnitTest
::
_openTest
(
void
)
{
Q_ASSERT
(
_fileManager
);
Q_ASSERT
(
_multiSpy
);
Q_ASSERT
(
_multiSpy
->
checkNoSignals
()
==
true
);
// Send a bogus path
// We should get a single resetStatusMessages signal
// We should get a single errorMessage signal
_fileManager
->
downloadPath
(
"bogus"
,
QDir
::
temp
());
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
_multiSpy
->
clearAllSignals
();
// Clean previous downloads
QString
smallFilePath
;
smallFilePath
=
QDir
::
temp
().
absoluteFilePath
(
MockMavlinkFileServer
::
smallFilename
);
if
(
QFile
::
exists
(
smallFilePath
))
{
Q_ASSERT
(
QFile
::
remove
(
smallFilePath
));
}
QString
largeFilePath
;
largeFilePath
=
QDir
::
temp
().
absoluteFilePath
(
MockMavlinkFileServer
::
largeFilename
);
if
(
QFile
::
exists
(
largeFilePath
))
{
Q_ASSERT
(
QFile
::
remove
(
largeFilePath
));
}
// Send a valid file to download
// We should get a single resetStatusMessages signal
// We should get a single statusMessage signal, which indicated download completion
_fileManager
->
downloadPath
(
MockMavlinkFileServer
::
smallFilename
,
QDir
::
temp
());
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
statusMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
_multiSpy
->
clearAllSignals
();
_validateFileContents
(
smallFilePath
,
MockMavlinkFileServer
::
smallFileLength
);
_fileManager
->
downloadPath
(
MockMavlinkFileServer
::
largeFilename
,
QDir
::
temp
());
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
statusMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
_multiSpy
->
clearAllSignals
();
_validateFileContents
(
largeFilePath
,
MockMavlinkFileServer
::
largeFileLength
);
}
src/qgcunittest/QGCUASFileManagerTest.h
View file @
f12c0bf3
...
...
@@ -56,11 +56,14 @@ private slots:
void
_noAckTest
(
void
);
void
_resetTest
(
void
);
void
_listTest
(
void
);
void
_openTest
(
void
);
// Connected to QGCUASFileManager statusMessage signal
void
statusMessage
(
const
QString
&
);
private:
void
_validateFileContents
(
const
QString
&
filePath
,
uint8_t
length
);
enum
{
statusMessageSignalIndex
=
0
,
errorMessageSignalIndex
,
...
...
src/uas/QGCUASFileManager.cc
View file @
f12c0bf3
...
...
@@ -69,7 +69,8 @@ QGCUASFileManager::QGCUASFileManager(QObject* parent, UASInterface* uas) :
QObject
(
parent
),
_currentOperation
(
kCOIdle
),
_mav
(
uas
),
_encdata_seq
(
0
)
_encdata_seq
(
0
),
_activeSession
(
0
)
{
bool
connected
=
connect
(
&
_ackTimer
,
SIGNAL
(
timeout
()),
this
,
SLOT
(
_ackTimeout
()));
Q_ASSERT
(
connected
);
...
...
@@ -103,6 +104,81 @@ void QGCUASFileManager::nothingMessage()
// FIXME: Connect ui correctly
}
/// @brief Respond to the Ack associated with the Open command.
void
QGCUASFileManager
::
_openResponse
(
Request
*
openAck
)
{
_currentOperation
=
kCORead
;
_activeSession
=
openAck
->
hdr
.
session
;
_readOffset
=
0
;
_readFileAccumulator
.
clear
();
Request
request
;
request
.
hdr
.
magic
=
'f'
;
request
.
hdr
.
session
=
_activeSession
;
request
.
hdr
.
opcode
=
kCmdRead
;
request
.
hdr
.
offset
=
_readOffset
;
request
.
hdr
.
size
=
sizeof
(
request
.
data
);
_sendRequest
(
&
request
);
}
/// @brief Respond to the Ack associated with the Read command.
void
QGCUASFileManager
::
_readResponse
(
Request
*
readAck
)
{
if
(
readAck
->
hdr
.
session
!=
_activeSession
)
{
_currentOperation
=
kCOIdle
;
_readFileAccumulator
.
clear
();
_emitErrorMessage
(
tr
(
"Read: Incorrect session returned"
));
return
;
}
if
(
readAck
->
hdr
.
offset
!=
_readOffset
)
{
_currentOperation
=
kCOIdle
;
_readFileAccumulator
.
clear
();
_emitErrorMessage
(
tr
(
"Read: Offset returned (%1) differs from offset requested (%2)"
).
arg
(
readAck
->
hdr
.
offset
).
arg
(
_readOffset
));
return
;
}
qDebug
()
<<
"Accumulator size"
<<
readAck
->
hdr
.
size
;
_readFileAccumulator
.
append
((
const
char
*
)
readAck
->
data
,
readAck
->
hdr
.
size
);
if
(
readAck
->
hdr
.
size
==
sizeof
(
readAck
->
data
))
{
// Still more data to read
_currentOperation
=
kCORead
;
_readOffset
+=
sizeof
(
readAck
->
data
);
Request
request
;
request
.
hdr
.
magic
=
'f'
;
request
.
hdr
.
session
=
_activeSession
;
request
.
hdr
.
opcode
=
kCmdRead
;
request
.
hdr
.
offset
=
_readOffset
;
request
.
hdr
.
size
=
sizeof
(
request
.
data
);
_sendRequest
(
&
request
);
}
else
{
_currentOperation
=
kCOIdle
;
QString
downloadFilePath
=
_readFileDownloadDir
.
absoluteFilePath
(
_readFileDownloadFilename
);
QFile
file
(
downloadFilePath
);
if
(
!
file
.
open
(
QIODevice
::
WriteOnly
|
QIODevice
::
Truncate
))
{
_emitErrorMessage
(
tr
(
"Unable to open local file for writing (%1)"
).
arg
(
downloadFilePath
));
return
;
}
qint64
bytesWritten
=
file
.
write
((
const
char
*
)
_readFileAccumulator
,
_readFileAccumulator
.
length
());
if
(
bytesWritten
!=
_readFileAccumulator
.
length
())
{
file
.
close
();
_emitErrorMessage
(
tr
(
"Unable to write data to local file (%1)"
).
arg
(
downloadFilePath
));
return
;
}
file
.
close
();
_emitStatusMessage
(
tr
(
"Download complete '%1'"
).
arg
(
downloadFilePath
));
}
}
void
QGCUASFileManager
::
receiveMessage
(
LinkInterface
*
link
,
mavlink_message_t
message
)
{
Q_UNUSED
(
link
);
...
...
@@ -116,8 +192,6 @@ void QGCUASFileManager::receiveMessage(LinkInterface* link, mavlink_message_t me
mavlink_msg_encapsulated_data_decode
(
&
message
,
&
data
);
Request
*
request
=
(
Request
*
)
&
data
.
data
[
0
];
qDebug
()
<<
"FTP: opcode:"
<<
request
->
hdr
.
opcode
;
// FIXME: Check CRC
if
(
request
->
hdr
.
opcode
==
kRspAck
)
{
...
...
@@ -132,7 +206,6 @@ void QGCUASFileManager::receiveMessage(LinkInterface* link, mavlink_message_t me
case
kCOAck
:
// We are expecting an ack back
_clearAckTimeout
();
_currentOperation
=
kCOIdle
;
break
;
...
...
@@ -140,6 +213,14 @@ void QGCUASFileManager::receiveMessage(LinkInterface* link, mavlink_message_t me
listDecode
(
&
request
->
data
[
0
],
request
->
hdr
.
size
);
break
;
case
kCOOpen
:
_openResponse
(
request
);
break
;
case
kCORead
:
_readResponse
(
request
);
break
;
default:
_emitErrorMessage
(
"Ack received in unexpected state"
);
break
;
...
...
@@ -196,7 +277,7 @@ void QGCUASFileManager::listDecode(const uint8_t *data, unsigned len)
}
// put it in the view
emit
s
tatusMessage
(
s
);
_emitS
tatusMessage
(
s
);
// account for the name + NUL
offset
+=
nlen
+
1
;
...
...
@@ -217,6 +298,12 @@ void QGCUASFileManager::listDecode(const uint8_t *data, unsigned len)
}
}
void
QGCUASFileManager
::
_fillRequestWithString
(
Request
*
request
,
const
QString
&
str
)
{
strncpy
((
char
*
)
&
request
->
data
[
0
],
str
.
toStdString
().
c_str
(),
sizeof
(
request
->
data
));
request
->
hdr
.
size
=
strnlen
((
const
char
*
)
&
request
->
data
[
0
],
sizeof
(
request
->
data
));
}
void
QGCUASFileManager
::
sendList
()
{
Request
request
;
...
...
@@ -226,32 +313,44 @@ void QGCUASFileManager::sendList()
request
.
hdr
.
opcode
=
kCmdList
;
request
.
hdr
.
offset
=
_listOffset
;
strncpy
((
char
*
)
&
request
.
data
[
0
],
_listPath
.
toStdString
().
c_str
(),
sizeof
(
request
.
data
));
request
.
hdr
.
size
=
strnlen
((
const
char
*
)
&
request
.
data
[
0
],
sizeof
(
request
.
data
));
_fillRequestWithString
(
&
request
,
_listPath
);
_sendRequest
(
&
request
);
}
void
QGCUASFileManager
::
downloadPath
(
const
QString
&
from
,
const
QString
&
to
)
/// @brief Downloads the specified file.
/// @param from File to download from UAS, fully qualified path
/// @param downloadDir Local directory to download file to
void
QGCUASFileManager
::
downloadPath
(
const
QString
&
from
,
const
QDir
&
downloadDir
)
{
Q_UNUSED
(
from
);
if
(
from
.
isEmpty
())
{
return
;
}
// Send path, e.g. /fs/microsd and download content
// recursively into a local directory
_readFileDownloadDir
.
setPath
(
downloadDir
.
absolutePath
());
char
buf
[
255
];
unsigned
len
=
10
;
// We need to strip off the file name from the fully qualified path. We can't use the usual QDir
// routines because this path does not exist locally.
int
i
;
for
(
i
=
from
.
size
()
-
1
;
i
>=
0
;
i
--
)
{
if
(
from
[
i
]
==
'/'
)
{
break
;
}
}
i
++
;
// move past slash
_readFileDownloadFilename
=
from
.
right
(
from
.
size
()
-
i
);
QByteArray
data
(
buf
,
len
);
QString
filename
=
"log001.bin"
;
// XXX get this from onboard
emit
resetStatusMessages
();
// Qt takes care of slash conversions in paths
QFile
file
(
to
+
QDir
::
separator
()
+
filename
);
file
.
open
(
QIODevice
::
WriteOnly
);
file
.
write
(
data
);
file
.
close
();
_currentOperation
=
kCOOpen
;
emit
statusMessage
(
QString
(
"Downloaded: %1 to directory %2"
).
arg
(
filename
).
arg
(
to
));
Request
request
;
request
.
hdr
.
magic
=
'f'
;
request
.
hdr
.
session
=
0
;
request
.
hdr
.
opcode
=
kCmdOpen
;
request
.
hdr
.
offset
=
0
;
_fillRequestWithString
(
&
request
,
from
);
_sendRequest
(
&
request
);
}
QString
QGCUASFileManager
::
errorString
(
uint8_t
errorCode
)
...
...
@@ -307,7 +406,6 @@ bool QGCUASFileManager::_sendOpcodeOnlyCmd(uint8_t opcode, OperationState newOpS
request
.
hdr
.
size
=
0
;
_currentOperation
=
newOpState
;
_setupAckTimeout
();
_sendRequest
(
&
request
);
...
...
@@ -317,8 +415,6 @@ bool QGCUASFileManager::_sendOpcodeOnlyCmd(uint8_t opcode, OperationState newOpS
/// @brief Starts the ack timeout timer
void
QGCUASFileManager
::
_setupAckTimeout
(
void
)
{
qDebug
()
<<
"Setting Ack"
;
Q_ASSERT
(
!
_ackTimer
.
isActive
());
_ackTimer
.
setSingleShot
(
true
);
...
...
@@ -328,8 +424,6 @@ void QGCUASFileManager::_setupAckTimeout(void)
/// @brief Clears the ack timeout timer
void
QGCUASFileManager
::
_clearAckTimeout
(
void
)
{
qDebug
()
<<
"Clearing Ack"
;
Q_ASSERT
(
_ackTimer
.
isActive
());
_ackTimer
.
stop
();
...
...
@@ -344,10 +438,16 @@ void QGCUASFileManager::_ackTimeout(void)
void
QGCUASFileManager
::
_emitErrorMessage
(
const
QString
&
msg
)
{
qDebug
()
<<
"QGCUASFileManager:"
<<
msg
;
qDebug
()
<<
"QGCUASFileManager:
Error
"
<<
msg
;
emit
errorMessage
(
msg
);
}
void
QGCUASFileManager
::
_emitStatusMessage
(
const
QString
&
msg
)
{
qDebug
()
<<
"QGCUASFileManager: Status"
<<
msg
;
emit
statusMessage
(
msg
);
}
/// @brief Sends the specified Request out to the UAS.
void
QGCUASFileManager
::
_sendRequest
(
Request
*
request
)
{
...
...
src/uas/QGCUASFileManager.h
View file @
f12c0bf3
...
...
@@ -25,6 +25,7 @@
#define QGCUASFILEMANAGER_H
#include <QObject>
#include <QDir>
#include "UASInterface.h"
...
...
@@ -48,7 +49,7 @@ public slots:
void
receiveMessage
(
LinkInterface
*
link
,
mavlink_message_t
message
);
void
nothingMessage
();
void
listRecursively
(
const
QString
&
from
);
void
downloadPath
(
const
QString
&
from
,
const
Q
String
&
to
);
void
downloadPath
(
const
QString
&
from
,
const
Q
Dir
&
downloadDir
);
protected:
struct
RequestHeader
...
...
@@ -109,7 +110,9 @@ protected:
{
kCOIdle
,
// not doing anything
kCOAck
,
// waiting for an Ack
kCOList
,
// waiting for a List response
kCOList
,
// waiting for List response
kCOOpen
,
// waiting for Open response
kCORead
,
// waiting for Read response
};
...
...
@@ -121,7 +124,11 @@ protected:
void
_setupAckTimeout
(
void
);
void
_clearAckTimeout
(
void
);
void
_emitErrorMessage
(
const
QString
&
msg
);
void
_emitStatusMessage
(
const
QString
&
msg
);
void
_sendRequest
(
Request
*
request
);
void
_fillRequestWithString
(
Request
*
request
,
const
QString
&
str
);
void
_openResponse
(
Request
*
openAck
);
void
_readResponse
(
Request
*
readAck
);
void
sendList
();
void
listDecode
(
const
uint8_t
*
data
,
unsigned
len
);
...
...
@@ -136,8 +143,14 @@ protected:
UASInterface
*
_mav
;
quint16
_encdata_seq
;
unsigned
_listOffset
;
// offset for the current List operation
QString
_listPath
;
// path for the current List operation
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
// We give MockMavlinkFileServer friend access so that it can use the data structures and opcodes
// to build a mock mavlink file server for testing.
...
...
src/ui/QGCUASFileView.cc
View file @
f12c0bf3
...
...
@@ -33,10 +33,10 @@ void QGCUASFileView::listFiles()
void
QGCUASFileView
::
downloadFiles
()
{
QString
dir
=
QFileDialog
::
getExistingDirectory
(
this
,
tr
(
"
Open
Directory"
),
QString
dir
=
QFileDialog
::
getExistingDirectory
(
this
,
tr
(
"
Download
Directory"
),
QDir
::
homePath
(),
QFileDialog
::
ShowDirsOnly
|
QFileDialog
::
DontResolveSymlinks
);
// And now download to this location
_manager
->
downloadPath
(
ui
->
pathLineEdit
->
text
(),
dir
);
_manager
->
downloadPath
(
ui
->
pathLineEdit
->
text
(),
QDir
(
dir
)
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment