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
939ee6f4
Commit
939ee6f4
authored
Jan 02, 2016
by
dogmaphobic
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented Log Download
parent
8ccf64f0
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1152 additions
and
23 deletions
+1152
-23
qgroundcontrol.pro
qgroundcontrol.pro
+4
-0
qgroundcontrol.qrc
qgroundcontrol.qrc
+1
-0
QGCApplication.cc
src/QGCApplication.cc
+3
-1
LogDownload.cc
src/ViewWidgets/LogDownload.cc
+34
-0
LogDownload.h
src/ViewWidgets/LogDownload.h
+37
-0
LogDownload.qml
src/ViewWidgets/LogDownload.qml
+210
-0
LogDownloadController.cc
src/ViewWidgets/LogDownloadController.cc
+621
-0
LogDownloadController.h
src/ViewWidgets/LogDownloadController.h
+193
-0
UAS.cc
src/uas/UAS.cc
+17
-0
UASInterface.h
src/uas/UASInterface.h
+24
-20
MainWindow.cc
src/ui/MainWindow.cc
+8
-2
No files found.
qgroundcontrol.pro
View file @
939ee6f4
...
...
@@ -356,6 +356,8 @@ HEADERS += \
src
/
VehicleSetup
/
JoystickConfigController
.
h
\
src
/
ViewWidgets
/
CustomCommandWidget
.
h
\
src
/
ViewWidgets
/
CustomCommandWidgetController
.
h
\
src
/
ViewWidgets
/
LogDownload
.
h
\
src
/
ViewWidgets
/
LogDownloadController
.
h
\
src
/
ViewWidgets
/
ViewWidgetController
.
h
\
}
...
...
@@ -468,6 +470,8 @@ SOURCES += \
src
/
VehicleSetup
/
JoystickConfigController
.
cc
\
src
/
ViewWidgets
/
CustomCommandWidget
.
cc
\
src
/
ViewWidgets
/
CustomCommandWidgetController
.
cc
\
src
/
ViewWidgets
/
LogDownload
.
cc
\
src
/
ViewWidgets
/
LogDownloadController
.
cc
\
src
/
ViewWidgets
/
ViewWidgetController
.
cc
\
}
...
...
qgroundcontrol.qrc
View file @
939ee6f4
...
...
@@ -11,6 +11,7 @@
<file alias="APMAirframeComponent.qml">src/AutoPilotPlugins/APM/APMAirframeComponent.qml</file>
<file alias="APMAirframeComponentSummary.qml">src/AutoPilotPlugins/APM/APMAirframeComponentSummary.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="LogDownload.qml">src/ViewWidgets/LogDownload.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="FlightModesComponent.qml">src/AutoPilotPlugins/PX4/FlightModesComponent.qml</file>
...
...
src/QGCApplication.cc
View file @
939ee6f4
...
...
@@ -95,6 +95,7 @@
#include "FlightDisplayViewController.h"
#include "VideoSurface.h"
#include "VideoReceiver.h"
#include "LogDownloadController.h"
#ifndef __ios__
#include "SerialLink.h"
...
...
@@ -396,6 +397,7 @@ void QGCApplication::_initCommon(void)
qmlRegisterType
<
CustomCommandWidgetController
>
(
"QGroundControl.Controllers"
,
1
,
0
,
"CustomCommandWidgetController"
);
qmlRegisterType
<
FirmwareUpgradeController
>
(
"QGroundControl.Controllers"
,
1
,
0
,
"FirmwareUpgradeController"
);
qmlRegisterType
<
JoystickConfigController
>
(
"QGroundControl.Controllers"
,
1
,
0
,
"JoystickConfigController"
);
qmlRegisterType
<
LogDownloadController
>
(
"QGroundControl.Controllers"
,
1
,
0
,
"LogDownloadController"
);
#endif
// Register Qml Singletons
...
...
src/ViewWidgets/LogDownload.cc
0 → 100644
View file @
939ee6f4
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 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/>.
======================================================================*/
#include "LogDownload.h"
LogDownload
::
LogDownload
(
const
QString
&
title
,
QAction
*
action
,
QWidget
*
parent
)
:
QGCQmlWidgetHolder
(
title
,
action
,
parent
)
{
Q_UNUSED
(
title
);
Q_UNUSED
(
action
);
setSource
(
QUrl
::
fromUserInput
(
"qrc:/qml/LogDownload.qml"
));
loadSettings
();
}
src/ViewWidgets/LogDownload.h
0 → 100644
View file @
939ee6f4
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 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/>.
======================================================================*/
#ifndef LogDownload_H
#define LogDownload_H
#include "QGCQmlWidgetHolder.h"
class
LogDownload
:
public
QGCQmlWidgetHolder
{
Q_OBJECT
public:
LogDownload
(
const
QString
&
title
,
QAction
*
action
,
QWidget
*
parent
=
0
);
};
#endif
src/ViewWidgets/LogDownload.qml
0 → 100644
View file @
939ee6f4
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 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/>.
======================================================================*/
import
QtQuick
2.5
import
QtQuick
.
Controls
1.2
import
QtQuick
.
Controls
.
Styles
1.2
import
QtQuick
.
Dialogs
1.2
import
QGroundControl
.
Palette
1.0
import
QGroundControl
.
Controls
1.0
import
QGroundControl
.
Controllers
1.0
import
QGroundControl
.
ScreenTools
1.0
QGCView
{
viewPanel
:
panel
property
real
_margins
:
ScreenTools
.
defaultFontPixelHeight
function
numberWithCommas
(
x
)
{
return
x
.
toString
().
replace
(
/
\B(?=(\d{3})
+
(?!\d))
/g
,
"
,
"
).
replace
(
/,,/g
,
"
,
"
);
}
LogDownloadController
{
id
:
controller
factPanel
:
panel
onSelectionChanged
:
{
tableView
.
selection
.
clear
()
for
(
var
i
=
0
;
i
<
controller
.
model
.
count
;
i
++
)
{
var
o
=
controller
.
model
.
get
(
i
)
if
(
o
&&
o
.
selected
)
{
tableView
.
selection
.
select
(
i
,
i
)
}
}
}
}
QGCPalette
{
id
:
palette
;
colorGroupEnabled
:
enabled
}
QGCViewPanel
{
id
:
panel
anchors.fill
:
parent
TableView
{
id
:
tableView
anchors.margins
:
_margins
anchors.left
:
parent
.
left
anchors.right
:
refreshButton
.
left
anchors.top
:
parent
.
top
anchors.bottom
:
parent
.
bottom
model
:
controller
.
model
selectionMode
:
SelectionMode
.
MultiSelection
TableViewColumn
{
title
:
"
Id
"
width
:
ScreenTools
.
defaultFontPixelWidth
*
4
horizontalAlignment
:
Text
.
AlignHCenter
delegate
:
Text
{
horizontalAlignment
:
Text
.
AlignHCenter
text
:
{
var
o
=
controller
.
model
.
get
(
styleData
.
row
)
return
o
?
o
.
id
:
""
}
}
}
TableViewColumn
{
title
:
"
Date
"
width
:
ScreenTools
.
defaultFontPixelWidth
*
30
horizontalAlignment
:
Text
.
AlignHCenter
delegate
:
Text
{
text
:
{
var
o
=
controller
.
model
.
get
(
styleData
.
row
)
if
(
o
)
{
//-- Have we received this entry already?
if
(
controller
.
model
.
get
(
styleData
.
row
).
received
)
{
var
d
=
controller
.
model
.
get
(
styleData
.
row
).
time
if
(
d
.
getUTCFullYear
()
<
1980
)
return
"
Date Unknown
"
else
return
d
.
toLocaleString
()
}
}
return
""
}
}
}
TableViewColumn
{
title
:
"
Size
"
width
:
ScreenTools
.
defaultFontPixelWidth
*
12
horizontalAlignment
:
Text
.
AlignHCenter
delegate
:
Text
{
horizontalAlignment
:
Text
.
AlignRight
text
:
{
var
o
=
controller
.
model
.
get
(
styleData
.
row
)
return
o
?
numberWithCommas
(
o
.
size
)
:
""
}
}
}
TableViewColumn
{
title
:
"
Status
"
width
:
ScreenTools
.
defaultFontPixelWidth
*
18
horizontalAlignment
:
Text
.
AlignHCenter
delegate
:
Text
{
horizontalAlignment
:
Text
.
AlignHCenter
text
:
{
var
o
=
controller
.
model
.
get
(
styleData
.
row
)
return
o
?
o
.
status
:
""
}
}
}
}
QGCButton
{
id
:
refreshButton
anchors.margins
:
_margins
anchors.top
:
parent
.
top
anchors.right
:
parent
.
right
enabled
:
!
controller
.
requestingList
&&
!
controller
.
downloadingLogs
text
:
"
Refresh
"
onClicked
:
{
controller
.
refresh
()
}
}
QGCButton
{
id
:
downloadButton
anchors.margins
:
_margins
anchors.top
:
refreshButton
.
bottom
anchors.right
:
parent
.
right
enabled
:
!
controller
.
requestingList
&&
!
controller
.
downloadingLogs
&&
tableView
.
selection
.
count
>
0
text
:
"
Download
"
onClicked
:
{
//-- Clear selection
for
(
var
i
=
0
;
i
<
controller
.
model
.
count
;
i
++
)
{
var
o
=
controller
.
model
.
get
(
i
)
if
(
o
)
o
.
selected
=
false
}
//-- Flag selected log files
tableView
.
selection
.
forEach
(
function
(
rowIndex
){
var
o
=
controller
.
model
.
get
(
rowIndex
)
if
(
o
)
o
.
selected
=
true
})
//-- Download them
controller
.
download
()
}
}
QGCButton
{
id
:
eraseAllButton
anchors.margins
:
_margins
anchors.top
:
downloadButton
.
bottom
anchors.right
:
parent
.
right
enabled
:
!
controller
.
requestingList
&&
!
controller
.
downloadingLogs
&&
controller
.
model
.
count
>
0
text
:
"
Erase All
"
onClicked
:
{
eraseAllDialog
.
visible
=
true
}
MessageDialog
{
id
:
eraseAllDialog
visible
:
false
icon
:
StandardIcon
.
Warning
standardButtons
:
StandardButton
.
Yes
|
StandardButton
.
No
title
:
"
Delete All Log Files
"
text
:
"
All log files will be erased permanently. Is this really what you want?
"
onYes
:
{
controller
.
eraseAll
()
eraseAllDialog
.
visible
=
false
}
onNo
:
{
eraseAllDialog
.
visible
=
false
}
}
}
QGCButton
{
id
:
cancelButton
anchors.margins
:
_margins
anchors.top
:
eraseAllButton
.
bottom
anchors.right
:
parent
.
right
text
:
"
Cancel
"
enabled
:
controller
.
requestingList
||
controller
.
downloadingLogs
onClicked
:
{
controller
.
cancel
()
}
}
}
}
src/ViewWidgets/LogDownloadController.cc
0 → 100644
View file @
939ee6f4
/*=====================================================================
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/>.
======================================================================*/
#include "LogDownloadController.h"
#include "MultiVehicleManager.h"
#include "QGCMAVLink.h"
#include "QGCFileDialog.h"
#include "UAS.h"
#include "QGCApplication.h"
#include "QGCToolbox.h"
#include "Vehicle.h"
#include "MainWindow.h"
#include <qDebug>
#include <QSettings>
#include <QUrl>
#define kTimeOutMilliseconds 500
QGC_LOGGING_CATEGORY
(
LogDownloadLog
,
"LogDownloadLog"
)
//----------------------------------------------------------------------------------------
LogDownloadData
::
LogDownloadData
(
QGCLogEntry
*
entry_
)
:
ID
(
entry_
->
id
())
,
entry
(
entry_
)
,
written
(
0
)
{
}
//----------------------------------------------------------------------------------------
QGCLogEntry
::
QGCLogEntry
(
uint
logId
,
const
QDateTime
&
dateTime
,
uint
logSize
,
bool
received
)
:
_logID
(
logId
)
,
_logSize
(
logSize
)
,
_logTimeUTC
(
dateTime
)
,
_received
(
received
)
,
_selected
(
false
)
{
_status
=
"Pending"
;
}
//----------------------------------------------------------------------------------------
LogDownloadController
::
LogDownloadController
(
void
)
:
_uas
(
NULL
)
,
_downloadData
(
NULL
)
,
_vehicle
(
NULL
)
,
_requestingLogEntries
(
false
)
,
_downloadingLogs
(
false
)
,
_retries
(
0
)
{
MultiVehicleManager
*
manager
=
qgcApp
()
->
toolbox
()
->
multiVehicleManager
();
connect
(
manager
,
&
MultiVehicleManager
::
activeVehicleChanged
,
this
,
&
LogDownloadController
::
_setActiveVehicle
);
connect
(
&
_timer
,
&
QTimer
::
timeout
,
this
,
&
LogDownloadController
::
_processDownload
);
_setActiveVehicle
(
manager
->
activeVehicle
());
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_processDownload
()
{
if
(
_requestingLogEntries
)
{
_findMissingEntries
();
}
else
if
(
_downloadingLogs
)
{
_findMissingData
();
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_setActiveVehicle
(
Vehicle
*
vehicle
)
{
if
((
_uas
&&
vehicle
&&
_uas
==
vehicle
->
uas
())
||
!
vehicle
)
{
return
;
}
_vehicle
=
vehicle
;
if
(
_uas
)
{
_logEntriesModel
.
clear
();
disconnect
(
_uas
,
&
UASInterface
::
logEntry
,
this
,
&
LogDownloadController
::
_logEntry
);
disconnect
(
_uas
,
&
UASInterface
::
logData
,
this
,
&
LogDownloadController
::
_logData
);
_uas
=
NULL
;
}
_uas
=
vehicle
->
uas
();
connect
(
_uas
,
&
UASInterface
::
logEntry
,
this
,
&
LogDownloadController
::
_logEntry
);
connect
(
_uas
,
&
UASInterface
::
logData
,
this
,
&
LogDownloadController
::
_logData
);
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_logEntry
(
UASInterface
*
uas
,
uint32_t
time_utc
,
uint32_t
size
,
uint16_t
id
,
uint16_t
num_logs
,
uint16_t
/*last_log_num*/
)
{
//-- Do we care?
if
(
!
_uas
||
uas
!=
_uas
||
!
_requestingLogEntries
)
{
return
;
}
//-- If this is the first, pre-fill it
if
(
!
_logEntriesModel
.
count
())
{
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
new
QGCLogEntry
(
i
);
_logEntriesModel
.
append
(
entry
);
}
}
//-- Update this log record
if
(
id
<
_logEntriesModel
.
count
())
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
id
];
entry
->
setSize
(
size
);
entry
->
setTime
(
QDateTime
::
fromTime_t
(
time_utc
));
entry
->
setReceived
(
true
);
entry
->
setStatus
(
QString
(
"Available"
));
}
else
{
qWarning
()
<<
"Received log entry for out-of-bound index:"
<<
id
;
}
//-- Reset retry count
_retries
=
0
;
//-- Do we have it all?
if
(
_entriesComplete
())
{
_receivedAllEntries
();
}
else
{
//-- Reset timer
_timer
.
start
(
kTimeOutMilliseconds
);
}
}
//----------------------------------------------------------------------------------------
bool
LogDownloadController
::
_entriesComplete
()
{
//-- Iterate entries and look for a gap
int
num_logs
=
_logEntriesModel
.
count
();
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
i
];
if
(
entry
)
{
if
(
!
entry
->
received
())
{
return
false
;
}
}
}
return
true
;
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_resetSelection
()
{
int
num_logs
=
_logEntriesModel
.
count
();
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
i
];
if
(
entry
)
{
entry
->
setSelected
(
false
);
}
}
emit
selectionChanged
();
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_receivedAllEntries
()
{
_timer
.
stop
();
_requestingLogEntries
=
false
;
emit
requestingListChanged
();
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_findMissingEntries
()
{
int
start
=
-
1
;
int
end
=
-
1
;
int
num_logs
=
_logEntriesModel
.
count
();
//-- Iterate entries and look for a gap
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
i
];
if
(
entry
)
{
if
(
!
entry
->
received
())
{
if
(
start
<
0
)
start
=
i
;
else
end
=
i
;
}
else
{
if
(
start
>=
0
)
{
break
;
}
}
}
}
//-- Is there something missing?
if
(
start
>=
0
)
{
//-- Have we tried too many times?
if
(
_retries
++
>
2
)
{
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
i
];
if
(
entry
&&
!
entry
->
received
())
{
entry
->
setStatus
(
QString
(
"Error"
));
}
}
//-- Give up
_receivedAllEntries
();
qWarning
()
<<
"Too many errors retreiving log list. Giving up."
;
return
;
}
//-- Is it a sequence or just one entry?
if
(
end
<
0
)
{
end
=
start
;
}
//-- Request these entries again
_requestLogList
((
uint32_t
)
start
,
(
uint32_t
)
end
);
}
else
{
_receivedAllEntries
();
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_logData
(
UASInterface
*
uas
,
uint32_t
ofs
,
uint16_t
id
,
uint8_t
count
,
const
uint8_t
*
data
)
{
if
(
!
_uas
||
uas
!=
_uas
||
!
_downloadData
)
{
return
;
}
if
(
_downloadData
->
ID
!=
id
)
{
qWarning
()
<<
"Received log data for wrong log"
;
return
;
}
bool
result
=
false
;
//-- Find offset table entry
uint
o_index
=
ofs
/
MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN
;
if
(
o_index
<=
(
uint
)
_downloadData
->
offsets
.
count
())
{
_downloadData
->
offsets
[
o_index
]
=
count
;
//-- Write chunk to file
if
(
_downloadData
->
file
.
seek
(
ofs
))
{
if
(
_downloadData
->
file
.
write
((
const
char
*
)
data
,
count
))
{
_downloadData
->
written
+=
count
;
//-- Update status
_downloadData
->
entry
->
setStatus
(
QString
::
number
(
_downloadData
->
written
));
result
=
true
;
//-- reset retries
_retries
=
0
;
//-- Reset timer
_timer
.
start
(
kTimeOutMilliseconds
);
//-- Do we have it all?
if
(
_logComplete
())
{
_downloadData
->
entry
->
setStatus
(
QString
(
"Downloaded"
));
//-- Check for more
_receivedAllData
();
}
}
else
{
qWarning
()
<<
"Error while writing log file chunk"
;
}
}
else
{
qWarning
()
<<
"Error while seeking log file offset"
;
}
}
else
{
qWarning
()
<<
"Received log offset greater than expected"
;
}
if
(
!
result
)
{
_downloadData
->
entry
->
setStatus
(
QString
(
"Error"
));
}
}
//----------------------------------------------------------------------------------------
bool
LogDownloadController
::
_logComplete
()
{
//-- Iterate entries and look for a gap
int
num_ofs
=
_downloadData
->
offsets
.
count
();
for
(
int
i
=
0
;
i
<
num_ofs
;
i
++
)
{
if
(
_downloadData
->
offsets
[
i
]
==
0
)
{
return
false
;
}
}
return
true
;
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_receivedAllData
()
{
_timer
.
stop
();
//-- Anything queued up for download?
if
(
_prepareLogDownload
())
{
//-- Request Log
_requestLogData
(
_downloadData
->
ID
,
0
,
_downloadData
->
entry
->
size
());
}
else
{
_resetSelection
();
_downloadingLogs
=
false
;
emit
downloadingLogsChanged
();
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_findMissingData
()
{
int
start
=
-
1
;
int
end
=
-
1
;
int
num_ofs
=
_downloadData
->
offsets
.
count
();
//-- Iterate offsets and look for a gap
for
(
int
i
=
0
;
i
<
num_ofs
;
i
++
)
{
if
(
_downloadData
->
offsets
[
i
]
==
0
)
{
if
(
start
<
0
)
start
=
i
;
else
end
=
i
;
}
else
{
if
(
start
>=
0
)
{
break
;
}
}
}
//-- Is there something missing?
if
(
start
>=
0
)
{
//-- Have we tried too many times?
if
(
_retries
++
>
2
)
{
_downloadData
->
entry
->
setStatus
(
QString
(
"Timed Out"
));
//-- Give up
qWarning
()
<<
"Too many errors retreiving log data. Giving up."
;
_receivedAllData
();
return
;
}
//-- Is it a sequence or just one entry?
if
(
end
<
0
)
{
end
=
start
;
}
//-- Request these log chunks again
_requestLogData
(
_downloadData
->
ID
,
(
uint32_t
)(
start
*
MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN
),
(
uint32_t
)((
end
-
start
+
1
)
*
MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN
));
}
else
{
_receivedAllData
();
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_requestLogData
(
uint8_t
id
,
uint32_t
offset
,
uint32_t
count
)
{
if
(
_vehicle
)
{
qCDebug
(
LogDownloadLog
)
<<
"Request log data (id:"
<<
id
<<
"offset:"
<<
offset
<<
"size:"
<<
count
<<
")"
;
mavlink_message_t
msg
;
mavlink_msg_log_request_data_pack
(
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getSystemId
(),
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getComponentId
(),
&
msg
,
qgcApp
()
->
toolbox
()
->
multiVehicleManager
()
->
activeVehicle
()
->
id
(),
MAV_COMP_ID_ALL
,
id
,
offset
,
count
);
_vehicle
->
sendMessage
(
msg
);
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
refresh
(
void
)
{
_logEntriesModel
.
clear
();
_requestLogList
();
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
_requestLogList
(
uint32_t
start
,
uint32_t
end
)
{
if
(
_vehicle
&&
_uas
)
{
qCDebug
(
LogDownloadLog
)
<<
"Request log entry list ("
<<
start
<<
"through"
<<
end
<<
")"
;
_requestingLogEntries
=
true
;
emit
requestingListChanged
();
mavlink_message_t
msg
;
mavlink_msg_log_request_list_pack
(
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getSystemId
(),
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getComponentId
(),
&
msg
,
_vehicle
->
id
(),
MAV_COMP_ID_ALL
,
start
,
end
);
_vehicle
->
sendMessage
(
msg
);
//-- Wait 2 seconds before bitching about not getting anything
_timer
.
start
(
2000
);
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
download
(
void
)
{
//-- Stop listing just in case
_receivedAllEntries
();
//-- Reset downloads, again just in case
if
(
_downloadData
)
{
delete
_downloadData
;
_downloadData
=
0
;
}
_downloadPath
.
clear
();
_downloadPath
=
QGCFileDialog
::
getExistingDirectory
(
MainWindow
::
instance
(),
"Log Download Directory"
,
QDir
::
homePath
(),
QGCFileDialog
::
ShowDirsOnly
|
QGCFileDialog
::
DontResolveSymlinks
);
if
(
!
_downloadPath
.
isEmpty
())
{
if
(
!
_downloadPath
.
endsWith
(
QDir
::
separator
()))
_downloadPath
+=
QDir
::
separator
();
//-- Start download process
_downloadingLogs
=
true
;
emit
downloadingLogsChanged
();
_receivedAllData
();
}
}
//----------------------------------------------------------------------------------------
QGCLogEntry
*
LogDownloadController
::
_getNextSelected
()
{
//-- Iterate entries and look for a selected file
int
num_logs
=
_logEntriesModel
.
count
();
for
(
int
i
=
0
;
i
<
num_logs
;
i
++
)
{
QGCLogEntry
*
entry
=
_logEntriesModel
[
i
];
if
(
entry
)
{
if
(
entry
->
selected
())
{
return
entry
;
}
}
}
return
NULL
;
}
//----------------------------------------------------------------------------------------
bool
LogDownloadController
::
_prepareLogDownload
()
{
if
(
_downloadData
)
{
delete
_downloadData
;
_downloadData
=
NULL
;
}
QGCLogEntry
*
entry
=
_getNextSelected
();
if
(
!
entry
)
{
return
false
;
}
//-- Deselect file
entry
->
setSelected
(
false
);
emit
selectionChanged
();
bool
result
=
false
;
QString
ftime
;
if
(
entry
->
time
().
date
().
year
()
<
1980
)
{
ftime
=
"UnknownDate"
;
}
else
{
ftime
=
entry
->
time
().
toString
(
"yyyy-M-d-hh-mm-ss"
);
}
_downloadData
=
new
LogDownloadData
(
entry
);
_downloadData
->
filename
=
QString
(
"log_"
)
+
QString
::
number
(
entry
->
id
())
+
"_"
+
ftime
+
".txt"
;
_downloadData
->
file
.
setFileName
(
_downloadPath
+
_downloadData
->
filename
);
//-- Append a number to the end if the filename already exists
if
(
_downloadData
->
file
.
exists
()){
uint
num_dups
=
0
;
QStringList
filename_spl
=
_downloadData
->
filename
.
split
(
'.'
);
do
{
num_dups
+=
1
;
_downloadData
->
file
.
setFileName
(
filename_spl
[
0
]
+
'_'
+
QString
::
number
(
num_dups
)
+
'.'
+
filename_spl
[
1
]);
}
while
(
_downloadData
->
file
.
exists
());
}
//-- Create file
if
(
!
_downloadData
->
file
.
open
(
QIODevice
::
WriteOnly
))
{
qWarning
()
<<
"Failed to create log file:"
<<
_downloadData
->
filename
;
}
else
{
//-- Preallocate file
if
(
!
_downloadData
->
file
.
resize
(
entry
->
size
()))
{
qWarning
()
<<
"Failed to allocate space for log file:"
<<
_downloadData
->
filename
;
}
else
{
//-- Prepare Offset Table
uint
o_count
=
(
uint
)
ceil
(
entry
->
size
()
/
(
double
)
MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN
);
for
(
uint
i
=
0
;
i
<
o_count
;
i
++
)
{
_downloadData
->
offsets
.
append
(
0
);
}
result
=
true
;
}
}
if
(
!
result
)
{
if
(
_downloadData
->
file
.
exists
())
{
_downloadData
->
file
.
remove
();
}
_downloadData
->
entry
->
setStatus
(
QString
(
"Error"
));
delete
_downloadData
;
_downloadData
=
NULL
;
}
return
result
;
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
eraseAll
(
void
)
{
if
(
_vehicle
&&
_uas
)
{
mavlink_message_t
msg
;
mavlink_msg_log_erase_pack
(
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getSystemId
(),
qgcApp
()
->
toolbox
()
->
mavlinkProtocol
()
->
getComponentId
(),
&
msg
,
qgcApp
()
->
toolbox
()
->
multiVehicleManager
()
->
activeVehicle
()
->
id
(),
MAV_COMP_ID_ALL
);
_vehicle
->
sendMessage
(
msg
);
}
}
//----------------------------------------------------------------------------------------
void
LogDownloadController
::
cancel
(
void
)
{
if
(
_uas
){
_receivedAllEntries
();
}
if
(
_downloadData
)
{
_downloadData
->
entry
->
setStatus
(
QString
(
"Canceled"
));
if
(
_downloadData
->
file
.
exists
())
{
_downloadData
->
file
.
remove
();
}
delete
_downloadData
;
_downloadData
=
0
;
}
_resetSelection
();
_downloadingLogs
=
false
;
emit
downloadingLogsChanged
();
}
//-----------------------------------------------------------------------------
QGCLogModel
::
QGCLogModel
(
QObject
*
parent
)
:
QAbstractListModel
(
parent
)
{
}
//-----------------------------------------------------------------------------
QGCLogEntry
*
QGCLogModel
::
get
(
int
index
)
{
if
(
index
<
0
||
index
>=
_logEntries
.
count
())
{
return
NULL
;
}
return
_logEntries
[
index
];
}
//-----------------------------------------------------------------------------
int
QGCLogModel
::
count
()
const
{
return
_logEntries
.
count
();
}
//-----------------------------------------------------------------------------
void
QGCLogModel
::
append
(
QGCLogEntry
*
object
)
{
beginInsertRows
(
QModelIndex
(),
rowCount
(),
rowCount
());
_logEntries
.
append
(
object
);
endInsertRows
();
emit
countChanged
();
}
//-----------------------------------------------------------------------------
void
QGCLogModel
::
clear
(
void
)
{
if
(
!
_logEntries
.
isEmpty
())
{
beginRemoveRows
(
QModelIndex
(),
0
,
_logEntries
.
count
());
while
(
_logEntries
.
count
())
{
QGCLogEntry
*
entry
=
_logEntries
.
last
();
if
(
entry
)
delete
entry
;
_logEntries
.
removeLast
();
}
endRemoveRows
();
emit
countChanged
();
}
}
//-----------------------------------------------------------------------------
QGCLogEntry
*
QGCLogModel
::
operator
[](
int
index
)
{
return
get
(
index
);
}
//-----------------------------------------------------------------------------
int
QGCLogModel
::
rowCount
(
const
QModelIndex
&
/*parent*/
)
const
{
return
_logEntries
.
count
();
}
//-----------------------------------------------------------------------------
QVariant
QGCLogModel
::
data
(
const
QModelIndex
&
index
,
int
role
)
const
{
if
(
index
.
row
()
<
0
||
index
.
row
()
>=
_logEntries
.
count
())
return
QVariant
();
if
(
role
==
ObjectRole
)
return
QVariant
::
fromValue
(
_logEntries
[
index
.
row
()]);
return
QVariant
();
}
//-----------------------------------------------------------------------------
QHash
<
int
,
QByteArray
>
QGCLogModel
::
roleNames
()
const
{
QHash
<
int
,
QByteArray
>
roles
;
roles
[
ObjectRole
]
=
"logEntry"
;
return
roles
;
}
src/ViewWidgets/LogDownloadController.h
0 → 100644
View file @
939ee6f4
/*=====================================================================
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/>.
======================================================================*/
#ifndef LogDownloadController_H
#define LogDownloadController_H
#include <QObject>
#include <QTimer>
#include <QAbstractListModel>
#include <memory>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
#include "FactPanelController.h"
class
MultiVehicleManager
;
class
UASInterface
;
class
Vehicle
;
class
QGCLogEntry
;
class
LogDownloadData
;
Q_DECLARE_LOGGING_CATEGORY
(
LogDownloadLog
)
//-----------------------------------------------------------------------------
class
QGCLogModel
:
public
QAbstractListModel
{
Q_OBJECT
public:
enum
QGCLogModelRoles
{
ObjectRole
=
Qt
::
UserRole
+
1
};
QGCLogModel
(
QObject
*
parent
=
0
);
Q_PROPERTY
(
int
count
READ
count
NOTIFY
countChanged
)
Q_INVOKABLE
QGCLogEntry
*
get
(
int
index
);
int
count
(
void
)
const
;
void
append
(
QGCLogEntry
*
entry
);
void
clear
(
void
);
QGCLogEntry
*
operator
[]
(
int
i
);
int
rowCount
(
const
QModelIndex
&
parent
=
QModelIndex
())
const
;
QVariant
data
(
const
QModelIndex
&
index
,
int
role
=
Qt
::
DisplayRole
)
const
;
signals:
void
countChanged
();
protected:
QHash
<
int
,
QByteArray
>
roleNames
()
const
;
private:
QList
<
QGCLogEntry
*>
_logEntries
;
};
//-----------------------------------------------------------------------------
class
QGCLogEntry
:
public
QObject
{
Q_OBJECT
Q_PROPERTY
(
uint
id
READ
id
CONSTANT
)
Q_PROPERTY
(
QDateTime
time
READ
time
NOTIFY
timeChanged
)
Q_PROPERTY
(
uint
size
READ
size
NOTIFY
sizeChanged
)
Q_PROPERTY
(
bool
received
READ
received
NOTIFY
receivedChanged
)
Q_PROPERTY
(
bool
selected
READ
selected
WRITE
setSelected
NOTIFY
selectedChanged
)
Q_PROPERTY
(
QString
status
READ
status
NOTIFY
statusChanged
)
public:
QGCLogEntry
(
uint
logId
,
const
QDateTime
&
dateTime
=
QDateTime
(),
uint
logSize
=
0
,
bool
received
=
false
);
uint
id
()
const
{
return
_logID
;
}
uint
size
()
const
{
return
_logSize
;
}
QDateTime
time
()
const
{
return
_logTimeUTC
;
}
bool
received
()
const
{
return
_received
;
}
bool
selected
()
const
{
return
_selected
;
}
QString
status
()
const
{
return
_status
;
}
void
setId
(
uint
id_
)
{
_logID
=
id_
;
}
void
setSize
(
uint
size_
)
{
_logSize
=
size_
;
emit
sizeChanged
();
}
void
setTime
(
QDateTime
date_
)
{
_logTimeUTC
=
date_
;
emit
timeChanged
();
}
void
setReceived
(
bool
rec_
)
{
_received
=
rec_
;
emit
receivedChanged
();
}
void
setSelected
(
bool
sel_
)
{
_selected
=
sel_
;
emit
selectedChanged
();
}
void
setStatus
(
QString
stat_
)
{
_status
=
stat_
;
emit
statusChanged
();
}
signals:
void
idChanged
();
void
timeChanged
();
void
sizeChanged
();
void
receivedChanged
();
void
selectedChanged
();
void
statusChanged
();
private:
uint
_logID
;
uint
_logSize
;
QDateTime
_logTimeUTC
;
bool
_received
;
bool
_selected
;
QString
_status
;
};
//-----------------------------------------------------------------------------
class
LogDownloadData
{
public:
LogDownloadData
(
QGCLogEntry
*
entry
);
QList
<
uint
>
offsets
;
QFile
file
;
QString
filename
;
uint
ID
;
QTimer
processDataTimer
;
QGCLogEntry
*
entry
;
uint
written
;
};
//-----------------------------------------------------------------------------
class
LogDownloadController
:
public
FactPanelController
{
Q_OBJECT
public:
LogDownloadController
();
Q_PROPERTY
(
QGCLogModel
*
model
READ
model
NOTIFY
modelChanged
)
Q_PROPERTY
(
bool
requestingList
READ
requestingList
NOTIFY
requestingListChanged
)
Q_PROPERTY
(
bool
downloadingLogs
READ
downloadingLogs
NOTIFY
downloadingLogsChanged
)
QGCLogModel
*
model
()
{
return
&
_logEntriesModel
;
}
bool
requestingList
()
{
return
_requestingLogEntries
;
}
bool
downloadingLogs
()
{
return
_downloadingLogs
;
}
Q_INVOKABLE
void
refresh
();
Q_INVOKABLE
void
download
();
Q_INVOKABLE
void
eraseAll
();
Q_INVOKABLE
void
cancel
();
signals:
void
requestingListChanged
();
void
downloadingLogsChanged
();
void
modelChanged
();
void
selectionChanged
();
private
slots
:
void
_setActiveVehicle
(
Vehicle
*
vehicle
);
void
_logEntry
(
UASInterface
*
uas
,
uint32_t
time_utc
,
uint32_t
size
,
uint16_t
id
,
uint16_t
num_logs
,
uint16_t
last_log_num
);
void
_logData
(
UASInterface
*
uas
,
uint32_t
ofs
,
uint16_t
id
,
uint8_t
count
,
const
uint8_t
*
data
);
void
_processDownload
();
private:
bool
_entriesComplete
();
bool
_logComplete
();
void
_findMissingEntries
();
void
_receivedAllEntries
();
void
_receivedAllData
();
void
_resetSelection
();
void
_findMissingData
();
void
_requestLogList
(
uint32_t
start
=
0
,
uint32_t
end
=
0xFFFF
);
void
_requestLogData
(
uint8_t
id
,
uint32_t
offset
=
0
,
uint32_t
count
=
0xFFFFFFFF
);
bool
_prepareLogDownload
();
QGCLogEntry
*
_getNextSelected
();
UASInterface
*
_uas
;
LogDownloadData
*
_downloadData
;
QTimer
_timer
;
QGCLogModel
_logEntriesModel
;
Vehicle
*
_vehicle
;
bool
_requestingLogEntries
;
bool
_downloadingLogs
;
int
_retries
;
QString
_downloadPath
;
};
#endif
src/uas/UAS.cc
View file @
939ee6f4
...
...
@@ -960,6 +960,23 @@ void UAS::receiveMessage(mavlink_message_t message)
emit
NavigationControllerDataChanged
(
this
,
p
.
nav_roll
,
p
.
nav_pitch
,
p
.
nav_bearing
,
p
.
target_bearing
,
p
.
wp_dist
);
}
break
;
case
MAVLINK_MSG_ID_LOG_ENTRY
:
{
mavlink_log_entry_t
log
;
mavlink_msg_log_entry_decode
(
&
message
,
&
log
);
emit
logEntry
(
this
,
log
.
time_utc
,
log
.
size
,
log
.
id
,
log
.
num_logs
,
log
.
last_log_num
);
}
break
;
case
MAVLINK_MSG_ID_LOG_DATA
:
{
mavlink_log_data_t
log
;
mavlink_msg_log_data_decode
(
&
message
,
&
log
);
emit
logData
(
this
,
log
.
ofs
,
log
.
id
,
log
.
count
,
log
.
data
);
}
break
;
default:
break
;
}
...
...
src/uas/UASInterface.h
View file @
939ee6f4
...
...
@@ -323,6 +323,10 @@ signals:
// HOME POSITION / ORIGIN CHANGES
void
homePositionChanged
(
int
uas
,
double
lat
,
double
lon
,
double
alt
);
// Log Download Signals
void
logEntry
(
UASInterface
*
uas
,
uint32_t
time_utc
,
uint32_t
size
,
uint16_t
id
,
uint16_t
num_logs
,
uint16_t
last_log_num
);
void
logData
(
UASInterface
*
uas
,
uint32_t
ofs
,
uint16_t
id
,
uint8_t
count
,
const
uint8_t
*
data
);
protected:
// TIMEOUT CONSTANTS
...
...
src/ui/MainWindow.cc
View file @
939ee6f4
...
...
@@ -65,6 +65,7 @@ This file is part of the QGROUNDCONTROL project
#include "QGCDockWidget.h"
#include "UASInfoWidget.h"
#include "HILDockWidget.h"
#include "LogDownload.h"
#endif
#ifndef __ios__
...
...
@@ -86,7 +87,8 @@ enum DockWidgetTypes {
STATUS_DETAILS
,
INFO_VIEW
,
HIL_CONFIG
,
ANALYZE
ANALYZE
,
LOG_DOWNLOAD
};
static
const
char
*
rgDockWidgetNames
[]
=
{
...
...
@@ -96,7 +98,8 @@ static const char *rgDockWidgetNames[] = {
"Status Details"
,
"Info View"
,
"HIL Config"
,
"Analyze"
"Analyze"
,
"Log Download"
};
#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
...
...
@@ -358,6 +361,9 @@ void MainWindow::_createInnerDockWidget(const QString& widgetName)
case
ONBOARD_FILES
:
widget
=
new
QGCUASFileViewMulti
(
widgetName
,
action
,
this
);
break
;
case
LOG_DOWNLOAD
:
widget
=
new
LogDownload
(
widgetName
,
action
,
this
);
break
;
case
STATUS_DETAILS
:
widget
=
new
UASInfoWidget
(
widgetName
,
action
,
this
);
break
;
...
...
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