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
989cdcd0
Commit
989cdcd0
authored
Aug 13, 2014
by
Lorenz Meier
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #818 from DonLakeFlyer/FTPProgressBar
FTP progress bar and download speed
parents
0cda5053
5868dbc1
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
285 additions
and
135 deletions
+285
-135
QGCUASFileManagerTest.cc
src/qgcunittest/QGCUASFileManagerTest.cc
+28
-26
QGCUASFileManagerTest.h
src/qgcunittest/QGCUASFileManagerTest.h
+10
-11
QGCUASFileManager.cc
src/uas/QGCUASFileManager.cc
+11
-11
QGCUASFileManager.h
src/uas/QGCUASFileManager.h
+21
-4
QGCUASFileView.cc
src/ui/QGCUASFileView.cc
+171
-71
QGCUASFileView.h
src/ui/QGCUASFileView.h
+19
-10
QGCUASFileView.ui
src/ui/QGCUASFileView.ui
+25
-2
No files found.
src/qgcunittest/QGCUASFileManagerTest.cc
View file @
989cdcd0
...
...
@@ -59,15 +59,17 @@ void QGCUASFileManagerUnitTest::init(void)
Q_ASSERT
(
connected
);
Q_UNUSED
(
connected
);
// Silent release build compiler warning
connected
=
connect
(
_fileManager
,
SIGNAL
(
statusMessage
(
const
QString
&
)),
this
,
SLOT
(
statusMessage
(
const
QString
&
)));
connected
=
connect
(
_fileManager
,
SIGNAL
(
listEntry
(
const
QString
&
)),
this
,
SLOT
(
listEntry
(
const
QString
&
)));
Q_ASSERT
(
connected
);
_rgSignals
[
statusMessageSignalIndex
]
=
SIGNAL
(
statusMessage
(
const
QString
&
));
_rgSignals
[
errorMessageSignalIndex
]
=
SIGNAL
(
errorMessage
(
const
QString
&
));
_rgSignals
[
resetStatusMessagesSignalIndex
]
=
SIGNAL
(
resetStatusMessages
(
void
));
_rgSignals
[
listEntrySignalIndex
]
=
SIGNAL
(
listEntry
(
const
QString
&
));
_rgSignals
[
listCompleteSignalIndex
]
=
SIGNAL
(
listComplete
(
void
));
_rgSignals
[
openFileLengthSignalIndex
]
=
SIGNAL
(
openFileLength
(
unsigned
int
));
_rgSignals
[
downloadFileLengthSignalIndex
]
=
SIGNAL
(
downloadFileLength
(
unsigned
int
));
_rgSignals
[
downloadFileCompleteSignalIndex
]
=
SIGNAL
(
downloadFileComplete
(
void
));
_rgSignals
[
errorMessageSignalIndex
]
=
SIGNAL
(
errorMessage
(
const
QString
&
));
_multiSpy
=
new
MultiSignalSpy
();
Q_CHECK_PTR
(
_multiSpy
);
QCOMPARE
(
_multiSpy
->
init
(
_fileManager
,
_rgSignals
,
_cSignals
),
true
);
...
...
@@ -86,11 +88,11 @@ void QGCUASFileManagerUnitTest::cleanup(void)
_multiSpy
=
NULL
;
}
/// @brief Connected to QGCUASFileManager
statusMessage signal in order to catch list command output
void
QGCUASFileManagerUnitTest
::
statusMessage
(
const
QString
&
msg
)
/// @brief Connected to QGCUASFileManager
listEntry signal in order to catch list entries
void
QGCUASFileManagerUnitTest
::
listEntry
(
const
QString
&
entry
)
{
// Keep a list of all names received so we can test it for correctness
_fileListReceived
+=
msg
;
_fileListReceived
+=
entry
;
}
...
...
@@ -151,14 +153,13 @@ void QGCUASFileManagerUnitTest::_listTest(void)
Q_ASSERT
(
_multiSpy
->
checkNoSignals
()
==
true
);
// QGCUASFileManager::listDirectory signalling as follows:
// Emits the resetStatusMessages signal
// Emits a statusMessage signal for each list entry
// Emits a listEntry signal for each list entry
// Emits an errorMessage signal if:
// It gets a Nak back
// Sequence number is incorrrect on any response
// CRC is incorrect on any responses
// List entry is formatted incorrectly
// It is possible to get a number of good
statusMessage
signals, followed by an errorMessage signal
// It is possible to get a number of good
listEntry
signals, followed by an errorMessage signal
// Emits listComplete after it receives the final list entry
// If an errorMessage signal is signalled no listComplete is signalled
...
...
@@ -166,7 +167,7 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// We should get a single resetStatusMessages signal
// We should get a single errorMessage signal
_fileManager
->
listDirectory
(
"/bogus"
);
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
),
true
);
_multiSpy
->
clearAllSignals
();
// Setup the mock file server with a valid directory list
...
...
@@ -187,15 +188,15 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// For simulated server errors on subsequent Acks, the first Ack will go through. This means we should have gotten some
// partial results. In the case of the directory list test set, all entries fit into the first ack, so we should have
// gotten back all of them.
QCOMPARE
(
_multiSpy
->
getSpyByIndex
(
statusMessage
SignalIndex
)
->
count
(),
fileList
.
count
());
_multiSpy
->
clearSignalByIndex
(
statusMessage
SignalIndex
);
QCOMPARE
(
_multiSpy
->
getSpyByIndex
(
listEntry
SignalIndex
)
->
count
(),
fileList
.
count
());
_multiSpy
->
clearSignalByIndex
(
listEntry
SignalIndex
);
// And then it should have errored out because the next list Request would have failed.
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
),
true
);
}
else
{
// For the simulated errors which failed the intial response we should not have gotten any results back at all.
// Just an error.
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
|
resetStatusMessagesSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
errorMessageSignalMask
),
true
);
}
// Set everything back to initial state
...
...
@@ -206,9 +207,9 @@ void QGCUASFileManagerUnitTest::_listTest(void)
// Send a list command at the root of the directory tree which should succeed
_fileManager
->
listDirectory
(
"/"
);
QCOMPARE
(
_multiSpy
->
checkSignalByMask
(
resetStatusMessagesSignalMask
|
listCompleteSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
checkSignalByMask
(
listCompleteSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
checkNoSignalByMask
(
errorMessageSignalMask
),
true
);
QCOMPARE
(
_multiSpy
->
getSpyByIndex
(
statusMessage
SignalIndex
)
->
count
(),
fileList
.
count
());
QCOMPARE
(
_multiSpy
->
getSpyByIndex
(
listEntry
SignalIndex
)
->
count
(),
fileList
.
count
());
QVERIFY
(
_fileListReceived
==
fileList
);
}
...
...
@@ -238,26 +239,26 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
Q_ASSERT
(
_multiSpy
->
checkNoSignals
()
==
true
);
// QGCUASFileManager::downloadPath works as follows:
// Emits the resetStatusMessages signal
// Sends an Open Command to the server
// Expects an Ack Response back from the server with the correct sequence numner
// Emits an errorMessage signal if it gets a Nak back
// Emits an
open
FileLength signal with the file length if it gets back a good Ack
// Emits an
download
FileLength signal with the file length if it gets back a good Ack
// Sends subsequent Read commands to the server until it gets the full file contents back
// Emits a downloadFileProgress for each read command ack it gets back
// Sends Terminate command to server when download is complete to close Open command
// Mock file server will signal terminateCommandReceived when it gets a Terminate command
// Sends
statusMessag
e signal to indicate the download is complete
// Sends
downloadFileComplet
e signal to indicate the download is complete
// Emits an errorMessage signal if sequence number is incorrrect on any response
// Emits an errorMessage signal if CRC is incorrect on any responses
// Expected signals if the Open command fails for any reason
quint16
signalMaskOpenFailure
=
resetStatusMessagesSignalMask
|
errorMessageSignalMask
;
quint16
signalMaskOpenFailure
=
errorMessageSignalMask
;
// Expected signals if the Read command fails for any reason
quint16
signalMaskReadFailure
=
resetStatusMessagesSignalMask
|
open
FileLengthSignalMask
|
errorMessageSignalMask
;
quint16
signalMaskReadFailure
=
download
FileLengthSignalMask
|
errorMessageSignalMask
;
// Expected signals if the downloadPath command succeeds
quint16
signalMaskDownloadSuccess
=
resetStatusMessagesSignalMask
|
openFileLengthSignalMask
|
statusMessag
eSignalMask
;
quint16
signalMaskDownloadSuccess
=
downloadFileLengthSignalMask
|
downloadFileComplet
eSignalMask
;
// Send a bogus path
// We should get a single resetStatusMessages signal
...
...
@@ -296,7 +297,8 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
// For simulated server errors on subsequent Acks, the first Ack will go through. We must handle things differently depending
// on whether the downloaded file requires multiple packets to complete the download.
if
(
testCase
->
fMultiPacketResponse
)
{
// The downloaded file requires multiple Acks to complete. Hence second Read should have failed.
// The downloaded file requires multiple Acks to complete. Hence first Read should have succeeded and sent one downloadFileComplete.
// Second Read should have failed.
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
signalMaskReadFailure
),
true
);
// Open command succeeded, so we should get a Terminate for the open
...
...
@@ -333,7 +335,7 @@ void QGCUASFileManagerUnitTest::_downloadTest(void)
QCOMPARE
(
_multiSpy
->
checkOnlySignalByMask
(
signalMaskDownloadSuccess
),
true
);
// Make sure the file length coming back through the openFileLength signal is correct
QVERIFY
(
_multiSpy
->
getSpyByIndex
(
open
FileLengthSignalIndex
)
->
takeFirst
().
at
(
0
).
toInt
()
==
testCase
->
length
);
QVERIFY
(
_multiSpy
->
getSpyByIndex
(
download
FileLengthSignalIndex
)
->
takeFirst
().
at
(
0
).
toInt
()
==
testCase
->
length
);
_multiSpy
->
clearAllSignals
();
...
...
src/qgcunittest/QGCUASFileManagerTest.h
View file @
989cdcd0
...
...
@@ -58,29 +58,28 @@ private slots:
void
_listTest
(
void
);
void
_downloadTest
(
void
);
// Connected to QGCUASFileManager
statusMessage
signal
void
statusMessage
(
const
QString
&
);
// Connected to QGCUASFileManager
listEntry
signal
void
listEntry
(
const
QString
&
entry
);
private:
void
_validateFileContents
(
const
QString
&
filePath
,
uint8_t
length
);
enum
{
statusMessageSignalIndex
=
0
,
errorMessageSignalIndex
,
resetStatusMessagesSignalIndex
,
listEntrySignalIndex
=
0
,
listCompleteSignalIndex
,
openFileLengthSignalIndex
,
downloadFileLengthSignalIndex
,
downloadFileCompleteSignalIndex
,
errorMessageSignalIndex
,
maxSignalIndex
};
enum
{
statusMessageSignalMask
=
1
<<
statusMessageSignalIndex
,
errorMessageSignalMask
=
1
<<
errorMessageSignalIndex
,
resetStatusMessagesSignalMask
=
1
<<
resetStatusMessagesSignalIndex
,
listEntrySignalMask
=
1
<<
listEntrySignalIndex
,
listCompleteSignalMask
=
1
<<
listCompleteSignalIndex
,
openFileLengthSignalMask
=
1
<<
openFileLengthSignalIndex
,
downloadFileLengthSignalMask
=
1
<<
downloadFileLengthSignalIndex
,
downloadFileCompleteSignalMask
=
1
<<
downloadFileCompleteSignalIndex
,
errorMessageSignalMask
=
1
<<
errorMessageSignalIndex
,
};
MockUAS
_mockUAS
;
MockMavlinkFileServer
_mockFileServer
;
...
...
src/uas/QGCUASFileManager.cc
View file @
989cdcd0
...
...
@@ -107,7 +107,9 @@ void QGCUASFileManager::_openAckResponse(Request* openAck)
// File length comes back in data
Q_ASSERT
(
openAck
->
hdr
.
size
==
sizeof
(
uint32_t
));
emit
openFileLength
(
openAck
->
openFileLength
);
emit
downloadFileLength
(
openAck
->
openFileLength
);
// Start the sequence of read commands
_readOffset
=
0
;
// Start reading at beginning of file
_readFileAccumulator
.
clear
();
// Start with an empty file
...
...
@@ -142,7 +144,7 @@ void QGCUASFileManager::_closeReadSession(bool success)
}
file
.
close
();
_emitStatusMessage
(
tr
(
"Download complete '%1'"
).
arg
(
downloadFilePath
)
);
emit
downloadFileComplete
(
);
}
// Close the open session
...
...
@@ -167,6 +169,7 @@ void QGCUASFileManager::_readAckResponse(Request* readAck)
}
_readFileAccumulator
.
append
((
const
char
*
)
readAck
->
data
,
readAck
->
hdr
.
size
);
emit
downloadFileProgress
(
_readFileAccumulator
.
length
());
if
(
readAck
->
hdr
.
size
==
sizeof
(
readAck
->
data
))
{
// Possibly still more data to read, send next read request
...
...
@@ -221,7 +224,9 @@ void QGCUASFileManager::_listAckResponse(Request* listAck)
// Returned names are prepended with D for directory, F for file, U for unknown
if
(
*
ptr
==
'F'
||
*
ptr
==
'D'
)
{
// put it in the view
_emitStatusMessage
(
ptr
);
_emitListEntry
(
ptr
);
}
else
{
qDebug
()
<<
"unknown entry"
<<
ptr
;
}
// account for the name + NUL
...
...
@@ -357,9 +362,6 @@ void QGCUASFileManager::listDirectory(const QString& dirPath)
return
;
}
// clear the text widget
emit
resetStatusMessages
();
// initialise the lister
_listPath
=
dirPath
;
_listOffset
=
0
;
...
...
@@ -411,8 +413,6 @@ void QGCUASFileManager::downloadPath(const QString& from, const QDir& downloadDi
i
++
;
// move past slash
_readFileDownloadFilename
=
from
.
right
(
from
.
size
()
-
i
);
emit
resetStatusMessages
();
_currentOperation
=
kCOOpen
;
Request
request
;
...
...
@@ -532,10 +532,10 @@ void QGCUASFileManager::_emitErrorMessage(const QString& msg)
emit
errorMessage
(
msg
);
}
void
QGCUASFileManager
::
_emit
StatusMessage
(
const
QString
&
msg
)
void
QGCUASFileManager
::
_emit
ListEntry
(
const
QString
&
entry
)
{
qDebug
()
<<
"QGCUASFileManager:
Status"
<<
msg
;
emit
statusMessage
(
msg
);
qDebug
()
<<
"QGCUASFileManager:
list entry"
<<
entry
;
emit
listEntry
(
entry
);
}
/// @brief Sends the specified Request out to the UAS.
...
...
src/uas/QGCUASFileManager.h
View file @
989cdcd0
...
...
@@ -45,11 +45,28 @@ public:
static
const
int
ackTimerTimeoutMsecs
=
1000
;
signals:
void
statusMessage
(
const
QString
&
msg
);
void
resetStatusMessages
();
/// @brief Signalled whenever an error occurs during the listDirectory or downloadPath methods.
void
errorMessage
(
const
QString
&
msg
);
// 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.
void
listComplete
(
void
);
void
openFileLength
(
unsigned
int
length
);
// 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
);
/// @brief Signaled to indicate completion of file download. If an error occurs during download this signal will not be emitted.
void
downloadFileComplete
(
void
);
public
slots
:
void
receiveMessage
(
LinkInterface
*
link
,
mavlink_message_t
message
);
...
...
@@ -140,7 +157,7 @@ protected:
void
_setupAckTimeout
(
void
);
void
_clearAckTimeout
(
void
);
void
_emitErrorMessage
(
const
QString
&
msg
);
void
_emit
StatusMessage
(
const
QString
&
msg
);
void
_emit
ListEntry
(
const
QString
&
entry
);
void
_sendRequest
(
Request
*
request
);
void
_fillRequestWithString
(
Request
*
request
,
const
QString
&
str
);
void
_openAckResponse
(
Request
*
openAck
);
...
...
src/ui/QGCUASFileView.cc
View file @
989cdcd0
This diff is collapsed.
Click to expand it.
src/ui/QGCUASFileView.h
View file @
989cdcd0
...
...
@@ -42,29 +42,38 @@ protected:
private
slots
:
void
_refreshTree
(
void
);
void
_downloadFiles
(
void
);
void
_treeStatusMessage
(
const
QString
&
msg
);
void
_treeErrorMessage
(
const
QString
&
msg
);
void
_listEntryReceived
(
const
QString
&
entry
);
void
_listErrorMessage
(
const
QString
&
msg
);
void
_listComplete
(
void
);
void
_downloadStatusMessage
(
const
QString
&
msg
);
void
_downloadFile
(
void
);
void
_downloadLength
(
unsigned
int
length
);
void
_downloadProgress
(
unsigned
int
length
);
void
_downloadErrorMessage
(
const
QString
&
msg
);
void
_downloadComplete
(
void
);
void
_currentItemChanged
(
QTreeWidgetItem
*
current
,
QTreeWidgetItem
*
previous
);
void
_listCompleteTimeout
(
void
);
private:
void
_setupListCompleteTimeout
(
void
);
void
_clearListCompleteTimeout
(
void
);
void
_connectDownloadSignals
(
void
);
void
_disconnectDownloadSignals
(
void
);
void
_connectListSignals
(
void
);
void
_disconnectListSignals
(
void
);
void
_requestDirectoryList
(
const
QString
&
dir
);
static
const
int
_typeFile
=
QTreeWidgetItem
::
UserType
+
1
;
static
const
int
_typeDir
=
QTreeWidgetItem
::
UserType
+
2
;
static
const
int
_typeError
=
QTreeWidgetItem
::
UserType
+
3
;
QTimer
_listCompleteTimer
;
///> Used to signal a timeout waiting for a listComplete signal
static
const
int
_listCompleteTimerTimeoutMsecs
=
5000
;
///> Timeout in msecs for listComplete timer
QList
<
int
>
_walkIndexStack
;
QList
<
QTreeWidgetItem
*>
_walkItemStack
;
Ui
::
QGCUASFileView
_ui
;
QString
_downloadFilename
;
///< File currently being downloaded, not including path
QTime
_downloadStartTime
;
///< Time at which download started
bool
_listInProgress
;
///< Indicates that a listDirectory command is in progress
bool
_downloadInProgress
;
///< Indicates that a downloadPath command is in progress
};
#endif // QGCUASFILEVIEW_H
src/ui/QGCUASFileView.ui
View file @
989cdcd0
...
...
@@ -14,13 +14,23 @@
<string>
Form
</string>
</property>
<layout
class=
"QGridLayout"
name=
"gridLayout"
>
<item
row=
"
1
"
column=
"1"
>
<item
row=
"
3
"
column=
"1"
>
<widget
class=
"QPushButton"
name=
"listFilesButton"
>
<property
name=
"text"
>
<string>
List Files
</string>
</property>
</widget>
</item>
<item
row=
"1"
column=
"0"
colspan=
"3"
>
<widget
class=
"QProgressBar"
name=
"progressBar"
>
<property
name=
"value"
>
<number>
24
</number>
</property>
<property
name=
"textVisible"
>
<bool>
false
</bool>
</property>
</widget>
</item>
<item
row=
"0"
column=
"0"
colspan=
"3"
>
<widget
class=
"QTreeWidget"
name=
"treeWidget"
>
<property
name=
"headerHidden"
>
...
...
@@ -33,7 +43,7 @@
</column>
</widget>
</item>
<item
row=
"
1
"
column=
"2"
>
<item
row=
"
3
"
column=
"2"
>
<widget
class=
"QPushButton"
name=
"downloadButton"
>
<property
name=
"enabled"
>
<bool>
false
</bool>
...
...
@@ -43,6 +53,19 @@
</property>
</widget>
</item>
<item
row=
"2"
column=
"0"
colspan=
"3"
>
<widget
class=
"QLabel"
name=
"statusText"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Preferred"
>
<horstretch>
0
</horstretch>
<verstretch>
0
</verstretch>
</sizepolicy>
</property>
<property
name=
"text"
>
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
...
...
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