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
93ee9ec2
Commit
93ee9ec2
authored
Oct 26, 2016
by
Gus Grubba
Committed by
GitHub
Oct 26, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4180 from dogmaphobic/MavlinkLogUploader
Mavlink log uploader
parents
5c94cda4
c77d8df1
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1658 additions
and
45 deletions
+1658
-45
qgroundcontrol.pro
qgroundcontrol.pro
+2
-0
QGCToolbox.cc
src/QGCToolbox.cc
+5
-0
QGCToolbox.h
src/QGCToolbox.h
+4
-0
QGroundControlQmlGlobal.cc
src/QmlControls/QGroundControlQmlGlobal.cc
+2
-2
QGroundControlQmlGlobal.h
src/QmlControls/QGroundControlQmlGlobal.h
+3
-0
MavlinkLogManager.cc
src/Vehicle/MavlinkLogManager.cc
+899
-0
MavlinkLogManager.h
src/Vehicle/MavlinkLogManager.h
+207
-0
Vehicle.cc
src/Vehicle/Vehicle.cc
+79
-5
Vehicle.h
src/Vehicle/Vehicle.h
+11
-1
MAVLinkProtocol.cc
src/comm/MAVLinkProtocol.cc
+12
-9
UASInterface.h
src/uas/UASInterface.h
+1
-0
MavlinkSettings.qml
src/ui/preferences/MavlinkSettings.qml
+433
-28
No files found.
qgroundcontrol.pro
View file @
93ee9ec2
...
...
@@ -334,6 +334,7 @@ HEADERS += \
src/uas/UAS.h \
src/uas/UASInterface.h \
src/uas/UASMessageHandler.h \
src/Vehicle/MavlinkLogManager.h \
src/ui/toolbar/MainToolBarController.h \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.h \
src/AutoPilotPlugins/APM/APMAirframeLoader.h \
...
...
@@ -498,6 +499,7 @@ SOURCES += \
src/QmlControls/QmlObjectListModel.cc \
src/uas/UAS.cc \
src/uas/UASMessageHandler.cc \
src/Vehicle/MavlinkLogManager.cc \
src/ui/toolbar/MainToolBarController.cc \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc \
src/AutoPilotPlugins/APM/APMAirframeLoader.cc \
...
...
src/QGCToolbox.cc
View file @
93ee9ec2
...
...
@@ -28,6 +28,7 @@
#include "FollowMe.h"
#include "PositionManager.h"
#include "VideoManager.h"
#include "MavlinkLogManager.h"
QGCToolbox
::
QGCToolbox
(
QGCApplication
*
app
)
:
_audioOutput
(
NULL
)
...
...
@@ -50,6 +51,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
,
_followMe
(
NULL
)
,
_qgcPositionManager
(
NULL
)
,
_videoManager
(
NULL
)
,
_mavlinkLogManager
(
NULL
)
{
_audioOutput
=
new
GAudioOutput
(
app
);
_autopilotPluginManager
=
new
AutoPilotPluginManager
(
app
);
...
...
@@ -71,6 +73,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_qgcPositionManager
=
new
QGCPositionManager
(
app
);
_followMe
=
new
FollowMe
(
app
);
_videoManager
=
new
VideoManager
(
app
);
_mavlinkLogManager
=
new
MavlinkLogManager
(
app
);
}
void
QGCToolbox
::
setChildToolboxes
(
void
)
...
...
@@ -95,11 +98,13 @@ void QGCToolbox::setChildToolboxes(void)
_followMe
->
setToolbox
(
this
);
_qgcPositionManager
->
setToolbox
(
this
);
_videoManager
->
setToolbox
(
this
);
_mavlinkLogManager
->
setToolbox
(
this
);
}
QGCToolbox
::~
QGCToolbox
()
{
delete
_videoManager
;
delete
_mavlinkLogManager
;
delete
_audioOutput
;
delete
_autopilotPluginManager
;
delete
_factSystem
;
...
...
src/QGCToolbox.h
View file @
93ee9ec2
...
...
@@ -32,6 +32,7 @@ class QGCImageProvider;
class
UASMessageHandler
;
class
QGCPositionManager
;
class
VideoManager
;
class
MavlinkLogManager
;
/// This is used to manage all of our top level services/tools
class
QGCToolbox
{
...
...
@@ -56,6 +57,8 @@ public:
FollowMe
*
followMe
(
void
)
{
return
_followMe
;
}
QGCPositionManager
*
qgcPositionManager
(
void
)
{
return
_qgcPositionManager
;
}
VideoManager
*
videoManager
(
void
)
{
return
_videoManager
;
}
MavlinkLogManager
*
mavlinkLogManager
(
void
)
{
return
_mavlinkLogManager
;
}
#ifndef __mobile__
GPSManager
*
gpsManager
(
void
)
{
return
_gpsManager
;
}
#endif
...
...
@@ -83,6 +86,7 @@ private:
FollowMe
*
_followMe
;
QGCPositionManager
*
_qgcPositionManager
;
VideoManager
*
_videoManager
;
MavlinkLogManager
*
_mavlinkLogManager
;
friend
class
QGCApplication
;
};
...
...
src/QmlControls/QGroundControlQmlGlobal.cc
View file @
93ee9ec2
...
...
@@ -44,6 +44,7 @@ QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCApplication* app)
,
_qgcPositionManager
(
NULL
)
,
_missionCommandTree
(
NULL
)
,
_videoManager
(
NULL
)
,
_mavlinkLogManager
(
NULL
)
,
_virtualTabletJoystick
(
false
)
,
_baseFontPointSize
(
0.0
)
{
...
...
@@ -60,7 +61,6 @@ QGroundControlQmlGlobal::~QGroundControlQmlGlobal()
}
void
QGroundControlQmlGlobal
::
setToolbox
(
QGCToolbox
*
toolbox
)
{
QGCTool
::
setToolbox
(
toolbox
);
...
...
@@ -72,9 +72,9 @@ void QGroundControlQmlGlobal::setToolbox(QGCToolbox* toolbox)
_qgcPositionManager
=
toolbox
->
qgcPositionManager
();
_missionCommandTree
=
toolbox
->
missionCommandTree
();
_videoManager
=
toolbox
->
videoManager
();
_mavlinkLogManager
=
toolbox
->
mavlinkLogManager
();
}
void
QGroundControlQmlGlobal
::
saveGlobalSetting
(
const
QString
&
key
,
const
QString
&
value
)
{
QSettings
settings
;
...
...
src/QmlControls/QGroundControlQmlGlobal.h
View file @
93ee9ec2
...
...
@@ -72,6 +72,7 @@ public:
Q_PROPERTY
(
QGCPositionManager
*
qgcPositionManger
READ
qgcPositionManger
CONSTANT
)
Q_PROPERTY
(
MissionCommandTree
*
missionCommandTree
READ
missionCommandTree
CONSTANT
)
Q_PROPERTY
(
VideoManager
*
videoManager
READ
videoManager
CONSTANT
)
Q_PROPERTY
(
MavlinkLogManager
*
mavlinkLogManager
READ
mavlinkLogManager
CONSTANT
)
Q_PROPERTY
(
qreal
zOrderTopMost
READ
zOrderTopMost
CONSTANT
)
///< z order for top most items, toolbar, main window sub view
Q_PROPERTY
(
qreal
zOrderWidgets
READ
zOrderWidgets
CONSTANT
)
///< z order value to widgets, for example: zoom controls, hud widgetss
...
...
@@ -166,6 +167,7 @@ public:
QGCPositionManager
*
qgcPositionManger
()
{
return
_qgcPositionManager
;
}
MissionCommandTree
*
missionCommandTree
()
{
return
_missionCommandTree
;
}
VideoManager
*
videoManager
()
{
return
_videoManager
;
}
MavlinkLogManager
*
mavlinkLogManager
()
{
return
_mavlinkLogManager
;
}
qreal
zOrderTopMost
()
{
return
1000
;
}
qreal
zOrderWidgets
()
{
return
100
;
}
...
...
@@ -237,6 +239,7 @@ private:
QGCPositionManager
*
_qgcPositionManager
;
MissionCommandTree
*
_missionCommandTree
;
VideoManager
*
_videoManager
;
MavlinkLogManager
*
_mavlinkLogManager
;
bool
_virtualTabletJoystick
;
qreal
_baseFontPointSize
;
...
...
src/Vehicle/MavlinkLogManager.cc
0 → 100644
View file @
93ee9ec2
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "MavlinkLogManager.h"
#include "QGCApplication.h"
#include <QQmlContext>
#include <QQmlProperty>
#include <QQmlEngine>
#include <QtQml>
#include <QSettings>
#include <QHttpPart>
#include <QNetworkReply>
#include <QFile>
#include <QFileInfo>
#define kTimeOutMilliseconds 1000
QGC_LOGGING_CATEGORY
(
MavlinkLogManagerLog
,
"MavlinkLogManagerLog"
)
static
const
char
*
kEmailAddressKey
=
"MavlinkLogEmail"
;
static
const
char
*
kDescriptionsKey
=
"MavlinkLogDescription"
;
static
const
char
*
kDefaultDescr
=
"QGroundControl Session"
;
static
const
char
*
kPx4URLKey
=
"MavlinkLogURL"
;
static
const
char
*
kDefaultPx4URL
=
"http://logs.px4.io/upload"
;
static
const
char
*
kEnableAutoUploadKey
=
"EnableAutoUploadKey"
;
static
const
char
*
kEnableAutoStartKey
=
"EnableAutoStartKey"
;
static
const
char
*
kEnableDeletetKey
=
"EnableDeleteKey"
;
static
const
char
*
kUlogExtension
=
".ulg"
;
static
const
char
*
kSidecarExtension
=
".uploaded"
;
//-----------------------------------------------------------------------------
MavlinkLogFiles
::
MavlinkLogFiles
(
MavlinkLogManager
*
manager
,
const
QString
&
filePath
,
bool
newFile
)
:
_manager
(
manager
)
,
_size
(
0
)
,
_selected
(
false
)
,
_uploading
(
false
)
,
_progress
(
0
)
,
_writing
(
false
)
,
_uploaded
(
false
)
{
QFileInfo
fi
(
filePath
);
_name
=
fi
.
baseName
();
if
(
!
newFile
)
{
_size
=
(
quint32
)
fi
.
size
();
QString
sideCar
=
filePath
;
sideCar
.
replace
(
kUlogExtension
,
kSidecarExtension
);
QFileInfo
sc
(
sideCar
);
_uploaded
=
sc
.
exists
();
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setSize
(
quint32
size
)
{
_size
=
size
;
emit
sizeChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setSelected
(
bool
selected
)
{
_selected
=
selected
;
emit
selectedChanged
();
emit
_manager
->
selectedCountChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setUploading
(
bool
uploading
)
{
_uploading
=
uploading
;
emit
uploadingChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setProgress
(
qreal
progress
)
{
_progress
=
progress
;
emit
progressChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setWriting
(
bool
writing
)
{
_writing
=
writing
;
emit
writingChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogFiles
::
setUploaded
(
bool
uploaded
)
{
_uploaded
=
uploaded
;
emit
uploadedChanged
();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
MavlinkLogProcessor
::
MavlinkLogProcessor
()
:
_fd
(
NULL
)
,
_written
(
0
)
,
_sequence
(
-
1
)
,
_numDrops
(
0
)
,
_gotHeader
(
false
)
,
_error
(
false
)
,
_record
(
NULL
)
{
}
//-----------------------------------------------------------------------------
MavlinkLogProcessor
::~
MavlinkLogProcessor
()
{
close
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogProcessor
::
close
()
{
if
(
_fd
)
{
fclose
(
_fd
);
_fd
=
NULL
;
}
}
//-----------------------------------------------------------------------------
bool
MavlinkLogProcessor
::
valid
()
{
return
(
_fd
!=
NULL
)
&&
(
_record
!=
NULL
);
}
//-----------------------------------------------------------------------------
bool
MavlinkLogProcessor
::
create
(
MavlinkLogManager
*
manager
,
const
QString
path
,
uint8_t
id
)
{
_fileName
.
sprintf
(
"%s/%03d-%s%s"
,
path
.
toLatin1
().
data
(),
id
,
QDateTime
::
currentDateTime
().
toString
(
"yyyy-MM-dd-hh-mm-ss-zzz"
).
toLatin1
().
data
(),
kUlogExtension
);
_fd
=
fopen
(
_fileName
.
toLatin1
().
data
(),
"wb"
);
if
(
_fd
)
{
_record
=
new
MavlinkLogFiles
(
manager
,
_fileName
,
true
);
_record
->
setWriting
(
true
);
_sequence
=
-
1
;
return
true
;
}
return
false
;
}
//-----------------------------------------------------------------------------
bool
MavlinkLogProcessor
::
_checkSequence
(
uint16_t
seq
,
int
&
num_drops
)
{
num_drops
=
0
;
//-- Check if a sequence is newer than the one previously received and if
// there were dropped messages between the last one and this.
if
(
_sequence
==
-
1
)
{
_sequence
=
seq
;
return
true
;
}
if
((
uint16_t
)
_sequence
==
seq
)
{
return
false
;
}
if
(
seq
>
(
uint16_t
)
_sequence
)
{
// Account for wrap-arounds, sequence is 2 bytes
if
((
seq
-
_sequence
)
>
(
1
<<
15
))
{
// Assume reordered
return
false
;
}
num_drops
=
seq
-
_sequence
-
1
;
_numDrops
+=
num_drops
;
_sequence
=
seq
;
return
true
;
}
else
{
if
((
_sequence
-
seq
)
>
(
1
<<
15
))
{
num_drops
=
(
1
<<
16
)
-
_sequence
-
1
+
seq
;
_numDrops
+=
num_drops
;
_sequence
=
seq
;
return
true
;
}
return
false
;
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogProcessor
::
_writeData
(
void
*
data
,
int
len
)
{
if
(
!
_error
)
{
_error
=
fwrite
(
data
,
1
,
len
,
_fd
)
!=
(
size_t
)
len
;
if
(
!
_error
)
{
_written
+=
len
;
if
(
_record
)
{
_record
->
setSize
(
_written
);
}
}
else
{
qCDebug
(
MavlinkLogManagerLog
)
<<
"File IO error:"
<<
len
<<
"bytes into"
<<
_fileName
;
}
}
}
//-----------------------------------------------------------------------------
QByteArray
MavlinkLogProcessor
::
_writeUlogMessage
(
QByteArray
&
data
)
{
//-- Write ulog data w/o integrity checking, assuming data starts with a
// valid ulog message. returns the remaining data at the end.
while
(
data
.
length
()
>
2
)
{
uint8_t
*
ptr
=
(
uint8_t
*
)
data
.
data
();
int
message_length
=
ptr
[
0
]
+
(
ptr
[
1
]
*
256
)
+
3
;
// 3 = ULog msg header
if
(
message_length
>
data
.
length
())
break
;
_writeData
(
data
.
data
(),
message_length
);
data
.
remove
(
0
,
message_length
);
return
data
;
}
return
data
;
}
//-----------------------------------------------------------------------------
bool
MavlinkLogProcessor
::
processStreamData
(
uint16_t
sequence
,
uint8_t
first_message
,
QByteArray
data
)
{
int
num_drops
=
0
;
_error
=
false
;
while
(
_checkSequence
(
sequence
,
num_drops
))
{
//-- The first 16 bytes need special treatment (this sounds awfully brittle)
if
(
!
_gotHeader
)
{
if
(
data
.
size
()
<
16
)
{
//-- Shouldn't happen but if it does, we might as well close shop.
qCCritical
(
MavlinkLogManagerLog
)
<<
"Corrupt log header. Canceling log download."
;
return
false
;
}
//-- Write header
_writeData
(
data
.
data
(),
16
);
data
.
remove
(
0
,
16
);
_gotHeader
=
true
;
// What about data start offset now that we removed 16 bytes off the start?
}
if
(
_gotHeader
&&
num_drops
>
0
)
{
if
(
num_drops
>
25
)
num_drops
=
25
;
//-- Hocus Pocus
// Write a dropout message. We don't really know the actual duration,
// so just use the number of drops * 10 ms
uint8_t
bogus
[]
=
{
2
,
0
,
79
,
0
,
0
};
bogus
[
3
]
=
num_drops
*
10
;
_writeData
(
bogus
,
sizeof
(
bogus
));
}
if
(
num_drops
>
0
)
{
_writeUlogMessage
(
_ulogMessage
);
_ulogMessage
.
clear
();
//-- If no usefull information in this message. Drop it.
if
(
first_message
==
255
)
{
break
;
}
if
(
first_message
>
0
)
{
data
.
remove
(
0
,
first_message
);
first_message
=
0
;
}
}
if
(
first_message
==
255
&&
_ulogMessage
.
length
()
>
0
)
{
_ulogMessage
.
append
(
data
);
break
;
}
if
(
_ulogMessage
.
length
())
{
_writeData
(
_ulogMessage
.
data
(),
_ulogMessage
.
length
());
if
(
first_message
)
{
_writeData
(
data
.
left
(
first_message
).
data
(),
first_message
);
}
_ulogMessage
.
clear
();
}
if
(
first_message
)
{
data
.
remove
(
0
,
first_message
);
}
_ulogMessage
=
_writeUlogMessage
(
data
);
break
;
}
return
!
_error
;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
MavlinkLogManager
::
MavlinkLogManager
(
QGCApplication
*
app
)
:
QGCTool
(
app
)
,
_enableAutoUpload
(
true
)
,
_enableAutoStart
(
true
)
,
_nam
(
NULL
)
,
_currentLogfile
(
NULL
)
,
_vehicle
(
NULL
)
,
_logRunning
(
false
)
,
_loggingDisabled
(
false
)
,
_logProcessor
(
NULL
)
,
_deleteAfterUpload
(
false
)
,
_loggingCmdTryCount
(
0
)
{
//-- Get saved settings
QSettings
settings
;
setEmailAddress
(
settings
.
value
(
kEmailAddressKey
,
QString
()).
toString
());
setDescription
(
settings
.
value
(
kDescriptionsKey
,
QString
(
kDefaultDescr
)).
toString
());
setUploadURL
(
settings
.
value
(
kPx4URLKey
,
QString
(
kDefaultPx4URL
)).
toString
());
setEnableAutoUpload
(
settings
.
value
(
kEnableAutoUploadKey
,
true
).
toBool
());
setEnableAutoStart
(
settings
.
value
(
kEnableAutoStartKey
,
true
).
toBool
());
setDeleteAfterUpload
(
settings
.
value
(
kEnableDeletetKey
,
false
).
toBool
());
//-- Logging location
_logPath
=
QStandardPaths
::
writableLocation
(
QStandardPaths
::
AppDataLocation
);
_logPath
+=
"/MavlinkLogs"
;
if
(
!
QDir
(
_logPath
).
exists
())
{
if
(
!
QDir
().
mkpath
(
_logPath
))
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"Could not create Mavlink log download path:"
<<
_logPath
;
_loggingDisabled
=
true
;
}
}
if
(
!
_loggingDisabled
)
{
//-- Load current list of logs
QString
filter
=
"*"
;
filter
+=
kUlogExtension
;
QDirIterator
it
(
_logPath
,
QStringList
()
<<
filter
,
QDir
::
Files
);
while
(
it
.
hasNext
())
{
_insertNewLog
(
new
MavlinkLogFiles
(
this
,
it
.
next
()));
}
qCDebug
(
MavlinkLogManagerLog
)
<<
"Mavlink logs directory:"
<<
_logPath
;
}
}
//-----------------------------------------------------------------------------
MavlinkLogManager
::~
MavlinkLogManager
()
{
_logFiles
.
clear
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setToolbox
(
QGCToolbox
*
toolbox
)
{
QGCTool
::
setToolbox
(
toolbox
);
QQmlEngine
::
setObjectOwnership
(
this
,
QQmlEngine
::
CppOwnership
);
qmlRegisterUncreatableType
<
MavlinkLogManager
>
(
"QGroundControl.MavlinkLogManager"
,
1
,
0
,
"MavlinkLogManager"
,
"Reference only"
);
if
(
!
_loggingDisabled
)
{
connect
(
toolbox
->
multiVehicleManager
(),
&
MultiVehicleManager
::
activeVehicleChanged
,
this
,
&
MavlinkLogManager
::
_activeVehicleChanged
);
connect
(
&
_ackTimer
,
&
QTimer
::
timeout
,
this
,
&
MavlinkLogManager
::
_processCmdAck
);
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setEmailAddress
(
QString
email
)
{
_emailAddress
=
email
;
QSettings
settings
;
settings
.
setValue
(
kEmailAddressKey
,
email
);
emit
emailAddressChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setDescription
(
QString
description
)
{
_description
=
description
;
QSettings
settings
;
settings
.
setValue
(
kDescriptionsKey
,
description
);
emit
descriptionChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setUploadURL
(
QString
url
)
{
_uploadURL
=
url
;
if
(
_uploadURL
.
isEmpty
())
{
_uploadURL
=
kDefaultPx4URL
;
}
QSettings
settings
;
settings
.
setValue
(
kPx4URLKey
,
_uploadURL
);
emit
uploadURLChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setEnableAutoUpload
(
bool
enable
)
{
_enableAutoUpload
=
enable
;
QSettings
settings
;
settings
.
setValue
(
kEnableAutoUploadKey
,
enable
);
emit
enableAutoUploadChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setEnableAutoStart
(
bool
enable
)
{
_enableAutoStart
=
enable
;
QSettings
settings
;
settings
.
setValue
(
kEnableAutoStartKey
,
enable
);
emit
enableAutoStartChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
setDeleteAfterUpload
(
bool
enable
)
{
_deleteAfterUpload
=
enable
;
QSettings
settings
;
settings
.
setValue
(
kEnableDeletetKey
,
enable
);
emit
deleteAfterUploadChanged
();
}
//-----------------------------------------------------------------------------
bool
MavlinkLogManager
::
uploading
()
{
return
_currentLogfile
!=
NULL
;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
uploadLog
()
{
if
(
_currentLogfile
)
{
_currentLogfile
->
setUploading
(
false
);
}
for
(
int
i
=
0
;
i
<
_logFiles
.
count
();
i
++
)
{
_currentLogfile
=
qobject_cast
<
MavlinkLogFiles
*>
(
_logFiles
.
get
(
i
));
Q_ASSERT
(
_currentLogfile
);
if
(
_currentLogfile
->
selected
())
{
_currentLogfile
->
setSelected
(
false
);
if
(
!
_currentLogfile
->
uploaded
()
&&
!
_emailAddress
.
isEmpty
()
&&
!
_uploadURL
.
isEmpty
())
{
_currentLogfile
->
setUploading
(
true
);
_currentLogfile
->
setProgress
(
0.0
);
QString
filePath
=
_makeFilename
(
_currentLogfile
->
name
());
_sendLog
(
filePath
);
emit
uploadingChanged
();
return
;
}
}
}
_currentLogfile
=
NULL
;
emit
uploadingChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_insertNewLog
(
MavlinkLogFiles
*
newLog
)
{
//-- Simpler than trying to sort this thing
int
count
=
_logFiles
.
count
();
if
(
!
count
)
{
_logFiles
.
append
(
newLog
);
}
else
{
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
MavlinkLogFiles
*
f
=
qobject_cast
<
MavlinkLogFiles
*>
(
_logFiles
.
get
(
i
));
if
(
newLog
->
name
()
<
f
->
name
())
{
_logFiles
.
insert
(
i
,
newLog
);
return
;
}
}
_logFiles
.
append
(
newLog
);
}
}
//-----------------------------------------------------------------------------
int
MavlinkLogManager
::
_getFirstSelected
()
{
for
(
int
i
=
0
;
i
<
_logFiles
.
count
();
i
++
)
{
MavlinkLogFiles
*
f
=
qobject_cast
<
MavlinkLogFiles
*>
(
_logFiles
.
get
(
i
));
Q_ASSERT
(
f
);
if
(
f
->
selected
())
{
return
i
;
}
}
return
-
1
;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
deleteLog
()
{
while
(
true
)
{
int
idx
=
_getFirstSelected
();
if
(
idx
<
0
)
{
break
;
}
MavlinkLogFiles
*
log
=
qobject_cast
<
MavlinkLogFiles
*>
(
_logFiles
.
get
(
idx
));
_deleteLog
(
log
);
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_deleteLog
(
MavlinkLogFiles
*
log
)
{
QString
filePath
=
_makeFilename
(
log
->
name
());
QFile
gone
(
filePath
);
if
(
!
gone
.
remove
())
{
qCWarning
(
MavlinkLogManagerLog
)
<<
"Could not delete Mavlink log file:"
<<
_logPath
;
}
//-- Remove sidecar file (if any)
filePath
.
replace
(
kUlogExtension
,
kSidecarExtension
);
QFile
sgone
(
filePath
);
if
(
sgone
.
exists
())
{
sgone
.
remove
();
}
//-- Remove file from list and delete record
_logFiles
.
removeOne
(
log
);
delete
log
;
emit
logFilesChanged
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
cancelUpload
()
{
for
(
int
i
=
0
;
i
<
_logFiles
.
count
();
i
++
)
{
MavlinkLogFiles
*
pLogFile
=
qobject_cast
<
MavlinkLogFiles
*>
(
_logFiles
.
get
(
i
));
Q_ASSERT
(
pLogFile
);
if
(
pLogFile
->
selected
()
&&
pLogFile
!=
_currentLogfile
)
{
pLogFile
->
setSelected
(
false
);
}
}
if
(
_currentLogfile
)
{
emit
abortUpload
();
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
startLogging
()
{
if
(
_vehicle
)
{
if
(
_createNewLog
())
{
_vehicle
->
startMavlinkLog
();
_logRunning
=
true
;
_loggingCmdTryCount
=
0
;
_ackTimer
.
start
(
kTimeOutMilliseconds
);
emit
logRunningChanged
();
}
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
stopLogging
()
{
if
(
_vehicle
)
{
//-- Tell vehicle to stop sending logs
_vehicle
->
stopMavlinkLog
();
}
if
(
_logProcessor
)
{
_logProcessor
->
close
();
if
(
_logProcessor
->
record
())
{
_logProcessor
->
record
()
->
setWriting
(
false
);
if
(
_enableAutoUpload
)
{
//-- Queue log for auto upload (set selected flag)
_logProcessor
->
record
()
->
setSelected
(
true
);
if
(
!
uploading
())
{
uploadLog
();
}
}
}
delete
_logProcessor
;
_logProcessor
=
NULL
;
_logRunning
=
false
;
if
(
_vehicle
)
{
//-- Setup a timer to make sure vehicle received the command
_loggingCmdTryCount
=
0
;
_ackTimer
.
start
(
kTimeOutMilliseconds
);
}
emit
logRunningChanged
();
}
}
//-----------------------------------------------------------------------------
QHttpPart
create_form_part
(
const
QString
&
name
,
const
QString
&
value
)
{
QHttpPart
formPart
;
formPart
.
setHeader
(
QNetworkRequest
::
ContentDispositionHeader
,
QString
(
"form-data; name=
\"
%1
\"
"
).
arg
(
name
));
formPart
.
setBody
(
value
.
toUtf8
());
return
formPart
;
}
//-----------------------------------------------------------------------------
bool
MavlinkLogManager
::
_sendLog
(
const
QString
&
logFile
)
{
QString
defaultDescription
=
_description
;
if
(
_description
.
isEmpty
())
{
qCWarning
(
MavlinkLogManagerLog
)
<<
"Log description missing. Using defaults."
;
defaultDescription
=
kDefaultDescr
;
}
if
(
_emailAddress
.
isEmpty
())
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"User email missing."
;
return
false
;
}
if
(
_uploadURL
.
isEmpty
())
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"Upload URL missing."
;
return
false
;
}
QFileInfo
fi
(
logFile
);
if
(
!
fi
.
exists
())
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"Log file missing:"
<<
logFile
;
return
false
;
}
QFile
*
file
=
new
QFile
(
logFile
);
if
(
!
file
||
!
file
->
open
(
QIODevice
::
ReadOnly
))
{
if
(
file
)
{
delete
file
;
}
qCCritical
(
MavlinkLogManagerLog
)
<<
"Could not open log file:"
<<
logFile
;
return
false
;
}
if
(
!
_nam
)
{
_nam
=
new
QNetworkAccessManager
(
this
);
}
QNetworkProxy
savedProxy
=
_nam
->
proxy
();
QNetworkProxy
tempProxy
;
tempProxy
.
setType
(
QNetworkProxy
::
DefaultProxy
);
_nam
->
setProxy
(
tempProxy
);
//-- Build POST request
QHttpMultiPart
*
multiPart
=
new
QHttpMultiPart
(
QHttpMultiPart
::
FormDataType
);
QHttpPart
emailPart
=
create_form_part
(
"email"
,
_emailAddress
);
QHttpPart
descriptionPart
=
create_form_part
(
"description"
,
_description
);
QHttpPart
sourcePart
=
create_form_part
(
"source"
,
"QGroundControl"
);
QHttpPart
versionPart
=
create_form_part
(
"version"
,
_app
->
applicationVersion
());
QHttpPart
logPart
;
logPart
.
setHeader
(
QNetworkRequest
::
ContentTypeHeader
,
"application/octet-stream"
);
logPart
.
setHeader
(
QNetworkRequest
::
ContentDispositionHeader
,
QString
(
"form-data; name=
\"
filearg
\"
; filename=
\"
%1
\"
"
).
arg
(
fi
.
fileName
()));
logPart
.
setBodyDevice
(
file
);
//-- Assemble request and POST it
multiPart
->
append
(
emailPart
);
multiPart
->
append
(
descriptionPart
);
multiPart
->
append
(
sourcePart
);
multiPart
->
append
(
versionPart
);
multiPart
->
append
(
logPart
);
file
->
setParent
(
multiPart
);
QNetworkRequest
request
(
_uploadURL
);
#if QT_VERSION > 0x050600
request
.
setAttribute
(
QNetworkRequest
::
FollowRedirectsAttribute
,
true
);
#endif
QNetworkReply
*
reply
=
_nam
->
post
(
request
,
multiPart
);
connect
(
reply
,
&
QNetworkReply
::
finished
,
this
,
&
MavlinkLogManager
::
_uploadFinished
);
connect
(
this
,
&
MavlinkLogManager
::
abortUpload
,
reply
,
&
QNetworkReply
::
abort
);
//connect(reply, &QNetworkReply::readyRead, this, &MavlinkLogManager::_dataAvailable);
connect
(
reply
,
&
QNetworkReply
::
uploadProgress
,
this
,
&
MavlinkLogManager
::
_uploadProgress
);
multiPart
->
setParent
(
reply
);
qCDebug
(
MavlinkLogManagerLog
)
<<
"Log"
<<
fi
.
baseName
()
<<
"Uploading."
<<
fi
.
size
()
<<
"bytes."
;
_nam
->
setProxy
(
savedProxy
);
return
true
;
}
//-----------------------------------------------------------------------------
bool
MavlinkLogManager
::
_processUploadResponse
(
int
http_code
,
QByteArray
&
data
)
{
qCDebug
(
MavlinkLogManagerLog
)
<<
"Uploaded response:"
<<
QString
::
fromUtf8
(
data
);
emit
readyRead
(
data
);
return
http_code
==
200
;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_dataAvailable
()
{
QNetworkReply
*
reply
=
qobject_cast
<
QNetworkReply
*>
(
sender
());
if
(
!
reply
)
{
return
;
}
QByteArray
data
=
reply
->
readAll
();
qCDebug
(
MavlinkLogManagerLog
)
<<
"Uploaded response data:"
<<
QString
::
fromUtf8
(
data
);
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_uploadFinished
()
{
QNetworkReply
*
reply
=
qobject_cast
<
QNetworkReply
*>
(
sender
());
if
(
!
reply
)
{
return
;
}
const
int
http_code
=
reply
->
attribute
(
QNetworkRequest
::
HttpStatusCodeAttribute
).
toInt
();
QByteArray
data
=
reply
->
readAll
();
if
(
_processUploadResponse
(
http_code
,
data
))
{
qCDebug
(
MavlinkLogManagerLog
)
<<
"Log uploaded."
;
emit
succeed
();
if
(
_deleteAfterUpload
)
{
if
(
_currentLogfile
)
{
_deleteLog
(
_currentLogfile
);
_currentLogfile
=
NULL
;
}
}
else
{
if
(
_currentLogfile
)
{
_currentLogfile
->
setUploaded
(
true
);
//-- Write side-car file to flag it as uploaded
QString
sideCar
=
_makeFilename
(
_currentLogfile
->
name
());
sideCar
.
replace
(
kUlogExtension
,
kSidecarExtension
);
FILE
*
f
=
fopen
(
sideCar
.
toLatin1
().
data
(),
"wb"
);
if
(
f
)
{
fclose
(
f
);
}
}
}
}
else
{
qCWarning
(
MavlinkLogManagerLog
)
<<
QString
(
"Log Upload Error: %1 status: %2"
).
arg
(
reply
->
errorString
(),
reply
->
attribute
(
QNetworkRequest
::
HttpStatusCodeAttribute
).
toString
());
emit
failed
();
}
reply
->
deleteLater
();
//-- Next (if any)
uploadLog
();
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_uploadProgress
(
qint64
bytesSent
,
qint64
bytesTotal
)
{
if
(
bytesTotal
)
{
qreal
progress
=
(
qreal
)
bytesSent
/
(
qreal
)
bytesTotal
;
if
(
_currentLogfile
)
{
_currentLogfile
->
setProgress
(
progress
);
}
}
qCDebug
(
MavlinkLogManagerLog
)
<<
bytesSent
<<
"of"
<<
bytesTotal
;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_activeVehicleChanged
(
Vehicle
*
vehicle
)
{
//-- TODO: This is not quite right. This is being used to detect when a vehicle
// connects/disconnects. In reality, if QGC is connected to multiple vehicles,
// this is called each time the user switches from one vehicle to another. So
// far, I'm working on the assumption that multiple vehicles is a rare exception.
// For now, we only handle one log download at a time.
// Disconnect the previous one (if any)
if
(
_vehicle
)
{
disconnect
(
_vehicle
,
&
Vehicle
::
armedChanged
,
this
,
&
MavlinkLogManager
::
_armedChanged
);
disconnect
(
_vehicle
,
&
Vehicle
::
mavlinkLogData
,
this
,
&
MavlinkLogManager
::
_mavlinkLogData
);
disconnect
(
_vehicle
,
&
Vehicle
::
commandLongAck
,
this
,
&
MavlinkLogManager
::
_commandLongAck
);
_vehicle
=
NULL
;
//-- Stop logging (if that's the case)
stopLogging
();
emit
canStartLogChanged
();
}
// Connect new system
if
(
vehicle
)
{
_vehicle
=
vehicle
;
connect
(
_vehicle
,
&
Vehicle
::
armedChanged
,
this
,
&
MavlinkLogManager
::
_armedChanged
);
connect
(
_vehicle
,
&
Vehicle
::
mavlinkLogData
,
this
,
&
MavlinkLogManager
::
_mavlinkLogData
);
connect
(
_vehicle
,
&
Vehicle
::
commandLongAck
,
this
,
&
MavlinkLogManager
::
_commandLongAck
);
emit
canStartLogChanged
();
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_processCmdAck
()
{
if
(
_loggingCmdTryCount
++
>
3
)
{
_ackTimer
.
stop
();
//-- Give up
if
(
_logRunning
)
{
qCWarning
(
MavlinkLogManagerLog
)
<<
"Start MAVLink log command had no response."
;
_discardLog
();
}
else
{
qCWarning
(
MavlinkLogManagerLog
)
<<
"Stop MAVLink log command had no response."
;
}
}
else
{
if
(
_vehicle
)
{
if
(
_logRunning
)
{
_vehicle
->
startMavlinkLog
();
qCWarning
(
MavlinkLogManagerLog
)
<<
"Start MAVLink log command sent again."
;
}
else
{
_vehicle
->
stopMavlinkLog
();
qCWarning
(
MavlinkLogManagerLog
)
<<
"Stop MAVLink log command sent again."
;
}
_ackTimer
.
start
(
kTimeOutMilliseconds
);
}
else
{
//-- Vehicle went away on us
_ackTimer
.
stop
();
}
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_mavlinkLogData
(
Vehicle
*
/*vehicle*/
,
uint8_t
/*target_system*/
,
uint8_t
/*target_component*/
,
uint16_t
sequence
,
uint8_t
first_message
,
QByteArray
data
,
bool
/*acked*/
)
{
//-- Disable timer if we got a message before an ACK for the start command
if
(
_logRunning
)
{
_ackTimer
.
stop
();
}
if
(
_logProcessor
&&
_logProcessor
->
valid
())
{
if
(
!
_logProcessor
->
processStreamData
(
sequence
,
first_message
,
data
))
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"Error writing Mavlink log file:"
<<
_logProcessor
->
fileName
();
delete
_logProcessor
;
_logProcessor
=
NULL
;
_logRunning
=
false
;
_vehicle
->
stopMavlinkLog
();
emit
logRunningChanged
();
}
}
else
{
qCWarning
(
MavlinkLogManagerLog
)
<<
"Mavlink log data received when not expected."
;
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_commandLongAck
(
uint8_t
/*compID*/
,
uint16_t
command
,
uint8_t
result
)
{
if
(
command
==
MAV_CMD_LOGGING_START
||
command
==
MAV_CMD_LOGGING_STOP
)
{
_ackTimer
.
stop
();
//-- Did it fail?
if
(
result
)
{
if
(
command
==
MAV_CMD_LOGGING_STOP
)
{
//-- Not that it could happen but...
qCWarning
(
MavlinkLogManagerLog
)
<<
"Stop MAVLink log command failed."
;
}
else
{
//-- Could not start logging for some reason.
qCWarning
(
MavlinkLogManagerLog
)
<<
"Start MAVLink log command failed."
;
_discardLog
();
}
}
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_discardLog
()
{
//-- Delete (empty) log file (and record)
if
(
_logProcessor
)
{
_logProcessor
->
close
();
if
(
_logProcessor
->
record
())
{
_deleteLog
(
_logProcessor
->
record
());
}
delete
_logProcessor
;
_logProcessor
=
NULL
;
}
_logRunning
=
false
;
emit
logRunningChanged
();
}
//-----------------------------------------------------------------------------
bool
MavlinkLogManager
::
_createNewLog
()
{
if
(
_logProcessor
)
{
delete
_logProcessor
;
_logProcessor
=
NULL
;
}
_logProcessor
=
new
MavlinkLogProcessor
;
if
(
_logProcessor
->
create
(
this
,
_logPath
,
_vehicle
->
id
()))
{
_insertNewLog
(
_logProcessor
->
record
());
emit
logFilesChanged
();
}
else
{
qCCritical
(
MavlinkLogManagerLog
)
<<
"Could not create Mavlink log file:"
<<
_logProcessor
->
fileName
();
delete
_logProcessor
;
_logProcessor
=
NULL
;
}
return
_logProcessor
!=
NULL
;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager
::
_armedChanged
(
bool
armed
)
{
if
(
_vehicle
)
{
if
(
armed
)
{
if
(
_enableAutoStart
)
{
startLogging
();
}
}
else
{
if
(
_logRunning
&&
_enableAutoStart
)
{
stopLogging
();
}
}
}
}
//-----------------------------------------------------------------------------
QString
MavlinkLogManager
::
_makeFilename
(
const
QString
&
baseName
)
{
QString
filePath
=
_logPath
;
filePath
+=
"/"
;
filePath
+=
baseName
;
filePath
+=
kUlogExtension
;
return
filePath
;
}
src/Vehicle/MavlinkLogManager.h
0 → 100644
View file @
93ee9ec2
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#ifndef MavlinkLogManager_H
#define MavlinkLogManager_H
#include <QObject>
#include "QmlObjectListModel.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "Vehicle.h"
Q_DECLARE_LOGGING_CATEGORY
(
MavlinkLogManagerLog
)
class
QNetworkAccessManager
;
class
MavlinkLogManager
;
//-----------------------------------------------------------------------------
class
MavlinkLogFiles
:
public
QObject
{
Q_OBJECT
public:
MavlinkLogFiles
(
MavlinkLogManager
*
manager
,
const
QString
&
filePath
,
bool
newFile
=
false
);
Q_PROPERTY
(
QString
name
READ
name
CONSTANT
)
Q_PROPERTY
(
quint32
size
READ
size
NOTIFY
sizeChanged
)
Q_PROPERTY
(
bool
selected
READ
selected
WRITE
setSelected
NOTIFY
selectedChanged
)
Q_PROPERTY
(
bool
uploading
READ
uploading
NOTIFY
uploadingChanged
)
Q_PROPERTY
(
qreal
progress
READ
progress
NOTIFY
progressChanged
)
Q_PROPERTY
(
bool
writing
READ
writing
NOTIFY
writingChanged
)
Q_PROPERTY
(
bool
uploaded
READ
uploaded
NOTIFY
uploadedChanged
)
QString
name
()
{
return
_name
;
}
quint32
size
()
{
return
_size
;
}
bool
selected
()
{
return
_selected
;
}
bool
uploading
()
{
return
_uploading
;
}
qreal
progress
()
{
return
_progress
;
}
bool
writing
()
{
return
_writing
;
}
bool
uploaded
()
{
return
_uploaded
;
}
void
setSelected
(
bool
selected
);
void
setUploading
(
bool
uploading
);
void
setProgress
(
qreal
progress
);
void
setWriting
(
bool
writing
);
void
setSize
(
quint32
size
);
void
setUploaded
(
bool
uploaded
);
signals:
void
sizeChanged
();
void
selectedChanged
();
void
uploadingChanged
();
void
progressChanged
();
void
writingChanged
();
void
uploadedChanged
();
private:
MavlinkLogManager
*
_manager
;
QString
_name
;
quint32
_size
;
bool
_selected
;
bool
_uploading
;
qreal
_progress
;
bool
_writing
;
bool
_uploaded
;
};
//-----------------------------------------------------------------------------
class
MavlinkLogProcessor
{
public:
MavlinkLogProcessor
();
~
MavlinkLogProcessor
();
void
close
();
bool
valid
();
bool
create
(
MavlinkLogManager
*
manager
,
const
QString
path
,
uint8_t
id
);
MavlinkLogFiles
*
record
()
{
return
_record
;
}
QString
fileName
()
{
return
_fileName
;
}
bool
processStreamData
(
uint16_t
_sequence
,
uint8_t
first_message
,
QByteArray
data
);
private:
bool
_checkSequence
(
uint16_t
seq
,
int
&
num_drops
);
QByteArray
_writeUlogMessage
(
QByteArray
&
data
);
void
_writeData
(
void
*
data
,
int
len
);
private:
FILE
*
_fd
;
quint32
_written
;
int
_sequence
;
int
_numDrops
;
bool
_gotHeader
;
bool
_error
;
QByteArray
_ulogMessage
;
QString
_fileName
;
MavlinkLogFiles
*
_record
;
};
//-----------------------------------------------------------------------------
class
MavlinkLogManager
:
public
QGCTool
{
Q_OBJECT
public:
MavlinkLogManager
(
QGCApplication
*
app
);
~
MavlinkLogManager
();
Q_PROPERTY
(
QString
emailAddress
READ
emailAddress
WRITE
setEmailAddress
NOTIFY
emailAddressChanged
)
Q_PROPERTY
(
QString
description
READ
description
WRITE
setDescription
NOTIFY
descriptionChanged
)
Q_PROPERTY
(
QString
uploadURL
READ
uploadURL
WRITE
setUploadURL
NOTIFY
uploadURLChanged
)
Q_PROPERTY
(
bool
enableAutoUpload
READ
enableAutoUpload
WRITE
setEnableAutoUpload
NOTIFY
enableAutoUploadChanged
)
Q_PROPERTY
(
bool
enableAutoStart
READ
enableAutoStart
WRITE
setEnableAutoStart
NOTIFY
enableAutoStartChanged
)
Q_PROPERTY
(
bool
deleteAfterUpload
READ
deleteAfterUpload
WRITE
setDeleteAfterUpload
NOTIFY
deleteAfterUploadChanged
)
Q_PROPERTY
(
bool
uploading
READ
uploading
NOTIFY
uploadingChanged
)
Q_PROPERTY
(
bool
logRunning
READ
logRunning
NOTIFY
logRunningChanged
)
Q_PROPERTY
(
bool
canStartLog
READ
canStartLog
NOTIFY
canStartLogChanged
)
Q_PROPERTY
(
QmlObjectListModel
*
logFiles
READ
logFiles
NOTIFY
logFilesChanged
)
Q_INVOKABLE
void
uploadLog
();
Q_INVOKABLE
void
deleteLog
();
Q_INVOKABLE
void
cancelUpload
();
Q_INVOKABLE
void
startLogging
();
Q_INVOKABLE
void
stopLogging
();
QString
emailAddress
()
{
return
_emailAddress
;
}
QString
description
()
{
return
_description
;
}
QString
uploadURL
()
{
return
_uploadURL
;
}
bool
enableAutoUpload
()
{
return
_enableAutoUpload
;
}
bool
enableAutoStart
()
{
return
_enableAutoStart
;
}
bool
uploading
();
bool
logRunning
()
{
return
_logRunning
;
}
bool
canStartLog
()
{
return
_vehicle
!=
NULL
;
}
bool
deleteAfterUpload
()
{
return
_deleteAfterUpload
;
}
QmlObjectListModel
*
logFiles
()
{
return
&
_logFiles
;
}
void
setEmailAddress
(
QString
email
);
void
setDescription
(
QString
description
);
void
setUploadURL
(
QString
url
);
void
setEnableAutoUpload
(
bool
enable
);
void
setEnableAutoStart
(
bool
enable
);
void
setDeleteAfterUpload
(
bool
enable
);
// Override from QGCTool
void
setToolbox
(
QGCToolbox
*
toolbox
);
signals:
void
emailAddressChanged
();
void
descriptionChanged
();
void
uploadURLChanged
();
void
enableAutoUploadChanged
();
void
enableAutoStartChanged
();
void
logFilesChanged
();
void
selectedCountChanged
();
void
uploadingChanged
();
void
readyRead
(
QByteArray
data
);
void
failed
();
void
succeed
();
void
abortUpload
();
void
logRunningChanged
();
void
canStartLogChanged
();
void
deleteAfterUploadChanged
();
private
slots
:
void
_uploadFinished
();
void
_dataAvailable
();
void
_uploadProgress
(
qint64
bytesSent
,
qint64
bytesTotal
);
void
_activeVehicleChanged
(
Vehicle
*
vehicle
);
void
_mavlinkLogData
(
Vehicle
*
vehicle
,
uint8_t
target_system
,
uint8_t
target_component
,
uint16_t
sequence
,
uint8_t
first_message
,
QByteArray
data
,
bool
acked
);
void
_armedChanged
(
bool
armed
);
void
_commandLongAck
(
uint8_t
compID
,
uint16_t
command
,
uint8_t
result
);
void
_processCmdAck
();
private:
bool
_sendLog
(
const
QString
&
logFile
);
bool
_processUploadResponse
(
int
http_code
,
QByteArray
&
data
);
bool
_createNewLog
();
int
_getFirstSelected
();
void
_insertNewLog
(
MavlinkLogFiles
*
newLog
);
void
_deleteLog
(
MavlinkLogFiles
*
log
);
void
_discardLog
();
QString
_makeFilename
(
const
QString
&
baseName
);
private:
QString
_description
;
QString
_emailAddress
;
QString
_uploadURL
;
QString
_logPath
;
bool
_enableAutoUpload
;
bool
_enableAutoStart
;
QNetworkAccessManager
*
_nam
;
QmlObjectListModel
_logFiles
;
MavlinkLogFiles
*
_currentLogfile
;
Vehicle
*
_vehicle
;
bool
_logRunning
;
bool
_loggingDisabled
;
MavlinkLogProcessor
*
_logProcessor
;
bool
_deleteAfterUpload
;
int
_loggingCmdTryCount
;
QTimer
_ackTimer
;
};
#endif
src/Vehicle/Vehicle.cc
View file @
93ee9ec2
...
...
@@ -400,6 +400,7 @@ Vehicle::resetCounters()
void
Vehicle
::
_mavlinkMessageReceived
(
LinkInterface
*
link
,
mavlink_message_t
message
)
{
if
(
message
.
sysid
!=
_id
&&
message
.
sysid
!=
0
)
{
return
;
}
...
...
@@ -480,7 +481,7 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
_handleCommandAck
(
message
);
break
;
case
MAVLINK_MSG_ID_AUTOPILOT_VERSION
:
_handleAutopilotVersion
(
message
);
_handleAutopilotVersion
(
link
,
message
);
break
;
case
MAVLINK_MSG_ID_WIND_COV
:
_handleWindCov
(
message
);
...
...
@@ -488,6 +489,12 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
case
MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS
:
_handleHilActuatorControls
(
message
);
break
;
case
MAVLINK_MSG_ID_LOGGING_DATA
:
_handleMavlinkLoggingData
(
message
);
break
;
case
MAVLINK_MSG_ID_LOGGING_DATA_ACKED
:
_handleMavlinkLoggingDataAcked
(
message
);
break
;
// Following are ArduPilot dialect messages
...
...
@@ -501,11 +508,17 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
_uas
->
receiveMessage
(
message
);
}
void
Vehicle
::
_handleAutopilotVersion
(
mavlink_message_t
&
message
)
void
Vehicle
::
_handleAutopilotVersion
(
LinkInterface
*
link
,
mavlink_message_t
&
message
)
{
mavlink_autopilot_version_t
autopilotVersion
;
mavlink_msg_autopilot_version_decode
(
&
message
,
&
autopilotVersion
);
bool
isMavlink2
=
(
autopilotVersion
.
capabilities
&
MAV_PROTOCOL_CAPABILITY_MAVLINK2
)
!=
0
;
if
(
isMavlink2
)
{
mavlink_status_t
*
mavlinkStatus
=
mavlink_get_channel_status
(
link
->
mavlinkChannel
());
mavlinkStatus
->
flags
&=
~
MAVLINK_STATUS_FLAG_OUT_MAVLINK1
;
}
if
(
autopilotVersion
.
flight_sw_version
!=
0
)
{
int
majorVersion
,
minorVersion
,
patchVersion
;
FIRMWARE_VERSION_TYPE
versionType
;
...
...
@@ -549,9 +562,14 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message)
emit
commandLongAck
(
message
.
compid
,
ack
.
command
,
ack
.
result
);
if
(
ack
.
command
==
MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES
)
{
// Disregard failures
return
;
// Disregard failures for these (handled above)
switch
(
ack
.
command
)
{
case
MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES
:
case
MAV_CMD_LOGGING_START
:
case
MAV_CMD_LOGGING_STOP
:
return
;
default:
break
;
}
QString
commandName
=
qgcApp
()
->
toolbox
()
->
missionCommandTree
()
->
friendlyName
((
MAV_CMD
)
ack
.
command
);
...
...
@@ -1959,6 +1977,62 @@ VehicleGPSFactGroup::VehicleGPSFactGroup(QObject* parent)
_courseOverGroundFact
.
setRawValue
(
std
::
numeric_limits
<
float
>::
quiet_NaN
());
}
//-----------------------------------------------------------------------------
void
Vehicle
::
startMavlinkLog
()
{
doCommandLong
(
defaultComponentId
(),
MAV_CMD_LOGGING_START
);
}
//-----------------------------------------------------------------------------
void
Vehicle
::
stopMavlinkLog
()
{
doCommandLong
(
defaultComponentId
(),
MAV_CMD_LOGGING_STOP
);
}
//-----------------------------------------------------------------------------
void
Vehicle
::
_ackMavlinkLogData
(
uint16_t
sequence
)
{
mavlink_message_t
msg
;
mavlink_logging_ack_t
ack
;
ack
.
sequence
=
sequence
;
ack
.
target_component
=
defaultComponentId
();
ack
.
target_system
=
id
();
mavlink_msg_logging_ack_encode_chan
(
_mavlink
->
getSystemId
(),
_mavlink
->
getComponentId
(),
priorityLink
()
->
mavlinkChannel
(),
&
msg
,
&
ack
);
sendMessageOnLink
(
priorityLink
(),
msg
);
}
//-----------------------------------------------------------------------------
void
Vehicle
::
_handleMavlinkLoggingData
(
mavlink_message_t
&
message
)
{
mavlink_logging_data_t
log
;
mavlink_msg_logging_data_decode
(
&
message
,
&
log
);
emit
mavlinkLogData
(
this
,
log
.
target_system
,
log
.
target_component
,
log
.
sequence
,
log
.
first_message_offset
,
QByteArray
((
const
char
*
)
log
.
data
,
log
.
length
),
false
);
}
//-----------------------------------------------------------------------------
void
Vehicle
::
_handleMavlinkLoggingDataAcked
(
mavlink_message_t
&
message
)
{
mavlink_logging_data_t
log
;
mavlink_msg_logging_data_decode
(
&
message
,
&
log
);
_ackMavlinkLogData
(
log
.
sequence
);
emit
mavlinkLogData
(
this
,
log
.
target_system
,
log
.
target_component
,
log
.
sequence
,
log
.
first_message_offset
,
QByteArray
((
const
char
*
)
log
.
data
,
log
.
length
),
true
);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void
VehicleGPSFactGroup
::
setVehicle
(
Vehicle
*
vehicle
)
{
_vehicle
=
vehicle
;
...
...
src/Vehicle/Vehicle.h
View file @
93ee9ec2
...
...
@@ -485,6 +485,10 @@ public:
int
flowImageIndex
()
{
return
_flowImageIndex
;
}
//-- Mavlink Logging
void
startMavlinkLog
();
void
stopMavlinkLog
();
/// Requests the specified data stream from the vehicle
/// @param stream Stream which is being requested
/// @param rate Rate at which to send stream in Hz
...
...
@@ -638,6 +642,9 @@ signals:
void
mavlinkScaledImu2
(
mavlink_message_t
message
);
void
mavlinkScaledImu3
(
mavlink_message_t
message
);
// Mavlink Log Download
void
mavlinkLogData
(
Vehicle
*
vehicle
,
uint8_t
target_system
,
uint8_t
target_component
,
uint16_t
sequence
,
uint8_t
first_message
,
QByteArray
data
,
bool
acked
);
private
slots
:
void
_mavlinkMessageReceived
(
LinkInterface
*
link
,
mavlink_message_t
message
);
void
_linkInactiveOrDeleted
(
LinkInterface
*
link
);
...
...
@@ -685,7 +692,7 @@ private:
void
_handleVibration
(
mavlink_message_t
&
message
);
void
_handleExtendedSysState
(
mavlink_message_t
&
message
);
void
_handleCommandAck
(
mavlink_message_t
&
message
);
void
_handleAutopilotVersion
(
mavlink_message_t
&
message
);
void
_handleAutopilotVersion
(
LinkInterface
*
link
,
mavlink_message_t
&
message
);
void
_handleHilActuatorControls
(
mavlink_message_t
&
message
);
void
_missionManagerError
(
int
errorCode
,
const
QString
&
errorMsg
);
void
_geoFenceManagerError
(
int
errorCode
,
const
QString
&
errorMsg
);
...
...
@@ -695,6 +702,9 @@ private:
void
_connectionActive
(
void
);
void
_say
(
const
QString
&
text
);
QString
_vehicleIdSpeech
(
void
);
void
_handleMavlinkLoggingData
(
mavlink_message_t
&
message
);
void
_handleMavlinkLoggingDataAcked
(
mavlink_message_t
&
message
);
void
_ackMavlinkLogData
(
uint16_t
sequence
);
private:
int
_id
;
///< Mavlink system id
...
...
src/comm/MAVLinkProtocol.cc
View file @
93ee9ec2
...
...
@@ -73,7 +73,7 @@ MAVLinkProtocol::MAVLinkProtocol(QGCApplication* app)
MAVLinkProtocol
::~
MAVLinkProtocol
()
{
storeSettings
();
#ifndef __mobile__
_closeLogFile
();
#endif
...
...
@@ -162,7 +162,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
if
(
!
_linkMgr
->
links
()
->
contains
(
link
))
{
return
;
}
// receiveMutex.lock();
mavlink_message_t
message
;
mavlink_status_t
status
;
...
...
@@ -214,6 +214,8 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
{
decodedFirstPacket
=
true
;
/*
* Handled in Vehicle.cc now.
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(mavlinkChannel);
if (!(mavlinkStatus->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) && (mavlinkStatus->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1)) {
qDebug() << "switch to mavlink 2.0" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
...
...
@@ -222,6 +224,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
qDebug() << "switch to mavlink 1.0" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
mavlinkStatus->flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
}
*/
if
(
message
.
msgid
==
MAVLINK_MSG_ID_RADIO_STATUS
)
{
...
...
@@ -255,7 +258,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
#ifndef __mobile__
// Log data
if
(
!
_logSuspendError
&&
!
_logSuspendReplay
&&
_tempLogFile
.
isOpen
())
{
uint8_t
buf
[
MAVLINK_MAX_PACKET_LEN
+
sizeof
(
quint64
)];
...
...
@@ -280,7 +283,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
_stopLogging
();
_logSuspendError
=
true
;
}
// Check for the vehicle arming going by. This is used to trigger log save.
if
(
!
_logPromptForSave
&&
message
.
msgid
==
MAVLINK_MSG_ID_HEARTBEAT
)
{
mavlink_heartbeat_t
state
;
...
...
@@ -412,7 +415,7 @@ bool MAVLinkProtocol::_closeLogFile(void)
return
true
;
}
}
return
false
;
}
...
...
@@ -458,11 +461,11 @@ void MAVLinkProtocol::_stopLogging(void)
void
MAVLinkProtocol
::
checkForLostLogFiles
(
void
)
{
QDir
tempDir
(
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
));
QString
filter
(
QString
(
"*.%1"
).
arg
(
_logFileExtension
));
QFileInfoList
fileInfoList
=
tempDir
.
entryInfoList
(
QStringList
(
filter
),
QDir
::
Files
);
qDebug
()
<<
"Orphaned log file count"
<<
fileInfoList
.
count
();
foreach
(
const
QFileInfo
fileInfo
,
fileInfoList
)
{
qDebug
()
<<
"Orphaned log file"
<<
fileInfo
.
filePath
();
if
(
fileInfo
.
size
()
==
0
)
{
...
...
@@ -488,10 +491,10 @@ void MAVLinkProtocol::suspendLogForReplay(bool suspend)
void
MAVLinkProtocol
::
deleteTempLogFiles
(
void
)
{
QDir
tempDir
(
QStandardPaths
::
writableLocation
(
QStandardPaths
::
TempLocation
));
QString
filter
(
QString
(
"*.%1"
).
arg
(
_logFileExtension
));
QFileInfoList
fileInfoList
=
tempDir
.
entryInfoList
(
QStringList
(
filter
),
QDir
::
Files
);
foreach
(
const
QFileInfo
fileInfo
,
fileInfoList
)
{
QFile
::
remove
(
fileInfo
.
filePath
());
}
...
...
src/uas/UASInterface.h
View file @
93ee9ec2
...
...
@@ -307,6 +307,7 @@ signals:
// 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
);
};
Q_DECLARE_INTERFACE
(
UASInterface
,
"org.qgroundcontrol/1.0"
)
...
...
src/ui/preferences/MavlinkSettings.qml
View file @
93ee9ec2
...
...
@@ -25,56 +25,461 @@ Rectangle {
color
:
qgcPal
.
window
anchors.fill
:
parent
property
real
_labelWidth
:
ScreenTools
.
defaultFontPixelWidth
*
28
property
real
_valueWidth
:
ScreenTools
.
defaultFontPixelWidth
*
24
property
int
_selectedCount
:
0
property
real
_columnSpacing
:
ScreenTools
.
defaultFontPixelHeight
*
0.25
property
bool
_uploadedSelected
:
false
QGCPalette
{
id
:
qgcPal
}
Connections
{
target
:
QGroundControl
.
mavlinkLogManager
onSelectedCountChanged
:
{
_uploadedSelected
=
false
var
selected
=
0
for
(
var
i
=
0
;
i
<
QGroundControl
.
mavlinkLogManager
.
logFiles
.
count
;
i
++
)
{
var
logFile
=
QGroundControl
.
mavlinkLogManager
.
logFiles
.
get
(
i
)
if
(
logFile
.
selected
)
{
selected
++
//-- If an uploaded file is selected, disable "Upload" button
if
(
logFile
.
uploaded
)
{
_uploadedSelected
=
true
}
}
}
_selectedCount
=
selected
}
}
MessageDialog
{
id
:
emptyEmailDialog
visible
:
false
icon
:
StandardIcon
.
Warning
standardButtons
:
StandardButton
.
Close
title
:
qsTr
(
"
MAVLink Logging
"
)
text
:
qsTr
(
"
Please enter an email address before uploading MAVLink log files.
"
)
}
QGCFlickable
{
clip
:
true
anchors.fill
:
parent
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
contentHeight
:
settingsColumn
.
height
contentWidth
:
settingsColumn
.
width
flickableDirection
:
Flickable
.
VerticalFlick
Column
{
id
:
settingsColumn
spacing
:
ScreenTools
.
defaultFontPixelHeight
width
:
__mavlinkRoot
.
width
spacing
:
ScreenTools
.
defaultFontPixelHeight
*
0.5
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.left
:
parent
.
left
anchors.top
:
parent
.
top
//-----------------------------------------------------------------
//-- System ID
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
//-- Ground Station
Item
{
width
:
__mavlinkRoot
.
width
*
0.8
height
:
gcsLabel
.
height
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCLabel
{
text
:
qsTr
(
"
Ground Station MavLink System ID:
"
)
anchors.verticalCenter
:
parent
.
verticalCenter
id
:
gcsLabel
text
:
qsTr
(
"
Ground Station
"
)
font.family
:
ScreenTools
.
demiboldFontFamily
}
QGCTextField
{
id
:
sysidField
text
:
QGroundControl
.
mavlinkSystemID
.
toString
()
width
:
ScreenTools
.
defaultFontPixelWidth
*
6
inputMethodHints
:
Qt
.
ImhFormattedNumbersOnly
anchors.verticalCenter
:
parent
.
verticalCenter
onEditingFinished
:
{
QGroundControl
.
mavlinkSystemID
=
parseInt
(
sysidField
.
text
)
}
Rectangle
{
height
:
gcsColumn
.
height
+
(
ScreenTools
.
defaultFontPixelHeight
*
2
)
width
:
__mavlinkRoot
.
width
*
0.8
color
:
qgcPal
.
windowShade
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
Column
{
id
:
gcsColumn
spacing
:
_columnSpacing
anchors.centerIn
:
parent
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
QGCLabel
{
width
:
_labelWidth
anchors.baseline
:
sysidField
.
baseline
text
:
qsTr
(
"
MavLink System ID:
"
)
}
QGCTextField
{
id
:
sysidField
text
:
QGroundControl
.
mavlinkSystemID
.
toString
()
width
:
_valueWidth
inputMethodHints
:
Qt
.
ImhFormattedNumbersOnly
anchors.verticalCenter
:
parent
.
verticalCenter
onEditingFinished
:
{
QGroundControl
.
mavlinkSystemID
=
parseInt
(
sysidField
.
text
)
}
}
}
//-----------------------------------------------------------------
//-- Mavlink Heartbeats
QGCCheckBox
{
text
:
qsTr
(
"
Emit heartbeat
"
)
checked
:
QGroundControl
.
multiVehicleManager
.
gcsHeartBeatEnabled
onClicked
:
{
QGroundControl
.
multiVehicleManager
.
gcsHeartBeatEnabled
=
checked
}
}
//-----------------------------------------------------------------
//-- Mavlink Version Check
QGCCheckBox
{
text
:
qsTr
(
"
Only accept MAVs with same protocol version
"
)
checked
:
QGroundControl
.
isVersionCheckEnabled
onClicked
:
{
QGroundControl
.
isVersionCheckEnabled
=
checked
}
}
}
}
//-----------------------------------------------------------------
//-- Mavlink Heartbeats
QGCCheckBox
{
text
:
qsTr
(
"
Emit heartbeat
"
)
checked
:
QGroundControl
.
multiVehicleManager
.
gcsHeartBeatEnabled
onClicked
:
{
QGroundControl
.
multiVehicleManager
.
gcsHeartBeatEnabled
=
checked
//-- Mavlink Logging
Item
{
width
:
__mavlinkRoot
.
width
*
0.8
height
:
mavlogLabel
.
height
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCLabel
{
id
:
mavlogLabel
text
:
qsTr
(
"
Vehicle Mavlink Logging
"
)
font.family
:
ScreenTools
.
demiboldFontFamily
}
}
Rectangle
{
height
:
mavlogColumn
.
height
+
(
ScreenTools
.
defaultFontPixelHeight
*
2
)
width
:
__mavlinkRoot
.
width
*
0.8
color
:
qgcPal
.
windowShade
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
Column
{
id
:
mavlogColumn
width
:
gcsColumn
.
width
spacing
:
_columnSpacing
anchors.centerIn
:
parent
//-----------------------------------------------------------------
//-- Manual Start/Stop
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCLabel
{
width
:
_labelWidth
text
:
qsTr
(
"
Manual Start/Stop:
"
)
anchors.verticalCenter
:
parent
.
verticalCenter
}
QGCButton
{
text
:
qsTr
(
"
Start Logging
"
)
width
:
(
_valueWidth
*
0.5
)
-
(
ScreenTools
.
defaultFontPixelWidth
*
0.5
)
enabled
:
!
QGroundControl
.
mavlinkLogManager
.
logRunning
&&
QGroundControl
.
mavlinkLogManager
.
canStartLog
onClicked
:
QGroundControl
.
mavlinkLogManager
.
startLogging
()
anchors.verticalCenter
:
parent
.
verticalCenter
}
QGCButton
{
text
:
qsTr
(
"
Stop Logging
"
)
width
:
(
_valueWidth
*
0.5
)
-
(
ScreenTools
.
defaultFontPixelWidth
*
0.5
)
enabled
:
QGroundControl
.
mavlinkLogManager
.
logRunning
onClicked
:
QGroundControl
.
mavlinkLogManager
.
stopLogging
()
anchors.verticalCenter
:
parent
.
verticalCenter
}
}
//-----------------------------------------------------------------
//-- Enable auto log on arming
QGCCheckBox
{
text
:
qsTr
(
"
Enable automatic logging
"
)
checked
:
QGroundControl
.
mavlinkLogManager
.
enableAutoStart
onClicked
:
{
QGroundControl
.
mavlinkLogManager
.
enableAutoStart
=
checked
}
}
}
}
//-----------------------------------------------------------------
//-- Mavlink Version Check
QGCCheckBox
{
text
:
qsTr
(
"
Only accept MAVs with same protocol version
"
)
checked
:
QGroundControl
.
isVersionCheckEnabled
onClicked
:
{
QGroundControl
.
isVersionCheckEnabled
=
checked
//-- Mavlink Logging
Item
{
width
:
__mavlinkRoot
.
width
*
0.8
height
:
logLabel
.
height
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCLabel
{
id
:
logLabel
text
:
qsTr
(
"
Mavlink Log Uploads
"
)
font.family
:
ScreenTools
.
demiboldFontFamily
}
}
Rectangle
{
height
:
logColumn
.
height
+
(
ScreenTools
.
defaultFontPixelHeight
*
2
)
width
:
__mavlinkRoot
.
width
*
0.8
color
:
qgcPal
.
windowShade
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
Column
{
id
:
logColumn
spacing
:
_columnSpacing
anchors.centerIn
:
parent
//-----------------------------------------------------------------
//-- Email address Field
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
QGCLabel
{
width
:
_labelWidth
anchors.baseline
:
emailField
.
baseline
text
:
qsTr
(
"
Email address for Log Upload:
"
)
}
QGCTextField
{
id
:
emailField
text
:
QGroundControl
.
mavlinkLogManager
.
emailAddress
width
:
_valueWidth
inputMethodHints
:
Qt
.
ImhNoAutoUppercase
|
Qt
.
ImhEmailCharactersOnly
anchors.verticalCenter
:
parent
.
verticalCenter
onEditingFinished
:
{
QGroundControl
.
mavlinkLogManager
.
emailAddress
=
emailField
.
text
if
(
emailField
.
text
===
""
)
{
autoUploadCheck
.
checked
=
false
QGroundControl
.
mavlinkLogManager
.
enableAutoUpload
=
false
console
.
log
(
"
forcing enableAutoUpload to false
"
)
}
}
}
}
//-----------------------------------------------------------------
//-- Description Field
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
QGCLabel
{
width
:
_labelWidth
anchors.baseline
:
descField
.
baseline
text
:
qsTr
(
"
Default Description:
"
)
}
QGCTextField
{
id
:
descField
text
:
QGroundControl
.
mavlinkLogManager
.
description
width
:
_valueWidth
anchors.verticalCenter
:
parent
.
verticalCenter
onEditingFinished
:
{
QGroundControl
.
mavlinkLogManager
.
description
=
descField
.
text
}
}
}
//-----------------------------------------------------------------
//-- Upload URL
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
QGCLabel
{
width
:
_labelWidth
anchors.baseline
:
urlField
.
baseline
text
:
qsTr
(
"
Default Upload URL
"
)
}
QGCTextField
{
id
:
urlField
text
:
QGroundControl
.
mavlinkLogManager
.
uploadURL
width
:
_valueWidth
inputMethodHints
:
Qt
.
ImhNoAutoUppercase
|
Qt
.
ImhUrlCharactersOnly
anchors.verticalCenter
:
parent
.
verticalCenter
onEditingFinished
:
{
QGroundControl
.
mavlinkLogManager
.
uploadURL
=
urlField
.
text
}
}
}
//-----------------------------------------------------------------
//-- Automatic Upload
QGCCheckBox
{
id
:
autoUploadCheck
text
:
qsTr
(
"
Enable automatic log uploads
"
)
checked
:
QGroundControl
.
mavlinkLogManager
.
enableAutoUpload
onClicked
:
{
QGroundControl
.
mavlinkLogManager
.
emailAddress
=
emailField
.
text
if
(
checked
&&
QGroundControl
.
mavlinkLogManager
.
emailAddress
===
""
)
{
checked
=
false
emptyEmailDialog
.
open
()
}
else
{
QGroundControl
.
mavlinkLogManager
.
enableAutoUpload
=
checked
}
}
}
//-----------------------------------------------------------------
//-- Delete log after upload
QGCCheckBox
{
text
:
qsTr
(
"
Delete log file after uploading
"
)
checked
:
QGroundControl
.
mavlinkLogManager
.
deleteAfterUpload
enabled
:
autoUploadCheck
.
checked
onClicked
:
{
QGroundControl
.
mavlinkLogManager
.
deleteAfterUpload
=
checked
}
}
}
}
//-----------------------------------------------------------------
//-- Log Files
Item
{
width
:
__mavlinkRoot
.
width
*
0.8
height
:
logFilesLabel
.
height
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCLabel
{
id
:
logFilesLabel
text
:
qsTr
(
"
Saved Log Files
"
)
font.family
:
ScreenTools
.
demiboldFontFamily
}
}
Rectangle
{
height
:
logFilesColumn
.
height
+
(
ScreenTools
.
defaultFontPixelHeight
*
2
)
width
:
__mavlinkRoot
.
width
*
0.8
color
:
qgcPal
.
windowShade
anchors.margins
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
Column
{
id
:
logFilesColumn
spacing
:
_columnSpacing
*
4
anchors.centerIn
:
parent
width
:
ScreenTools
.
defaultFontPixelWidth
*
68
Rectangle
{
width
:
ScreenTools
.
defaultFontPixelWidth
*
64
height
:
ScreenTools
.
defaultFontPixelHeight
*
14
anchors.horizontalCenter
:
parent
.
horizontalCenter
color
:
qgcPal
.
window
border.color
:
qgcPal
.
text
border.width
:
0.5
ListView
{
width
:
ScreenTools
.
defaultFontPixelWidth
*
56
height
:
ScreenTools
.
defaultFontPixelHeight
*
12
anchors.centerIn
:
parent
orientation
:
ListView
.
Vertical
model
:
QGroundControl
.
mavlinkLogManager
.
logFiles
clip
:
true
delegate
:
Rectangle
{
width
:
ScreenTools
.
defaultFontPixelWidth
*
52
height
:
selectCheck
.
height
color
:
qgcPal
.
window
Row
{
width
:
ScreenTools
.
defaultFontPixelWidth
*
50
anchors.centerIn
:
parent
spacing
:
ScreenTools
.
defaultFontPixelWidth
QGCCheckBox
{
id
:
selectCheck
width
:
ScreenTools
.
defaultFontPixelWidth
*
4
checked
:
object
.
selected
enabled
:
!
object
.
writing
&&
!
object
.
uploading
anchors.verticalCenter
:
parent
.
verticalCenter
onClicked
:
{
object
.
selected
=
checked
}
}
QGCLabel
{
text
:
object
.
name
width
:
ScreenTools
.
defaultFontPixelWidth
*
28
color
:
object
.
writing
?
qgcPal
.
warningText
:
qgcPal
.
text
anchors.verticalCenter
:
parent
.
verticalCenter
}
QGCLabel
{
text
:
Number
(
object
.
size
).
toLocaleString
(
Qt
.
locale
(),
'
f
'
,
0
)
visible
:
!
object
.
uploading
&&
!
object
.
uploaded
width
:
ScreenTools
.
defaultFontPixelWidth
*
20
;
color
:
object
.
writing
?
qgcPal
.
warningText
:
qgcPal
.
text
horizontalAlignment
:
Text
.
AlignRight
anchors.verticalCenter
:
parent
.
verticalCenter
}
QGCLabel
{
text
:
"
Uploaded
"
visible
:
object
.
uploaded
width
:
ScreenTools
.
defaultFontPixelWidth
*
20
;
horizontalAlignment
:
Text
.
AlignRight
anchors.verticalCenter
:
parent
.
verticalCenter
}
ProgressBar
{
visible
:
object
.
uploading
&&
!
object
.
uploaded
width
:
ScreenTools
.
defaultFontPixelWidth
*
20
;
height
:
ScreenTools
.
defaultFontPixelHeight
anchors.verticalCenter
:
parent
.
verticalCenter
minimumValue
:
0
maximumValue
:
100
value
:
object
.
progress
*
100.0
}
}
}
}
}
Row
{
spacing
:
ScreenTools
.
defaultFontPixelWidth
anchors.horizontalCenter
:
parent
.
horizontalCenter
QGCButton
{
text
:
"
Check All
"
enabled
:
!
QGroundControl
.
mavlinkLogManager
.
uploading
&&
!
QGroundControl
.
mavlinkLogManager
.
logRunning
onClicked
:
{
for
(
var
i
=
0
;
i
<
QGroundControl
.
mavlinkLogManager
.
logFiles
.
count
;
i
++
)
{
var
logFile
=
QGroundControl
.
mavlinkLogManager
.
logFiles
.
get
(
i
)
logFile
.
selected
=
true
}
}
}
QGCButton
{
text
:
"
Check None
"
enabled
:
!
QGroundControl
.
mavlinkLogManager
.
uploading
&&
!
QGroundControl
.
mavlinkLogManager
.
logRunning
onClicked
:
{
for
(
var
i
=
0
;
i
<
QGroundControl
.
mavlinkLogManager
.
logFiles
.
count
;
i
++
)
{
var
logFile
=
QGroundControl
.
mavlinkLogManager
.
logFiles
.
get
(
i
)
logFile
.
selected
=
false
}
}
}
QGCButton
{
text
:
"
Delete Selected
"
enabled
:
_selectedCount
>
0
&&
!
QGroundControl
.
mavlinkLogManager
.
uploading
&&
!
QGroundControl
.
mavlinkLogManager
.
logRunning
onClicked
:
deleteDialog
.
open
()
MessageDialog
{
id
:
deleteDialog
visible
:
false
icon
:
StandardIcon
.
Warning
standardButtons
:
StandardButton
.
Yes
|
StandardButton
.
No
title
:
qsTr
(
"
Delete Selected Log Files
"
)
text
:
qsTr
(
"
Confirm deleting selected log files?
"
)
onYes
:
{
QGroundControl
.
mavlinkLogManager
.
deleteLog
()
}
}
}
QGCButton
{
text
:
"
Upload Selected
"
enabled
:
_selectedCount
>
0
&&
!
QGroundControl
.
mavlinkLogManager
.
uploading
&&
!
QGroundControl
.
mavlinkLogManager
.
logRunning
&&
!
_uploadedSelected
visible
:
!
QGroundControl
.
mavlinkLogManager
.
uploading
onClicked
:
{
QGroundControl
.
mavlinkLogManager
.
emailAddress
=
emailField
.
text
if
(
QGroundControl
.
mavlinkLogManager
.
emailAddress
===
""
)
emptyEmailDialog
.
open
()
else
uploadDialog
.
open
()
}
MessageDialog
{
id
:
uploadDialog
visible
:
false
icon
:
StandardIcon
.
Question
standardButtons
:
StandardButton
.
Yes
|
StandardButton
.
No
title
:
qsTr
(
"
Upload Selected Log Files
"
)
text
:
qsTr
(
"
Confirm uploading selected log files?
"
)
onYes
:
{
QGroundControl
.
mavlinkLogManager
.
uploadLog
()
}
}
}
QGCButton
{
text
:
"
Cancel
"
enabled
:
QGroundControl
.
mavlinkLogManager
.
uploading
&&
!
QGroundControl
.
mavlinkLogManager
.
logRunning
visible
:
QGroundControl
.
mavlinkLogManager
.
uploading
onClicked
:
cancelDialog
.
open
()
MessageDialog
{
id
:
cancelDialog
visible
:
false
icon
:
StandardIcon
.
Warning
standardButtons
:
StandardButton
.
Yes
|
StandardButton
.
No
title
:
qsTr
(
"
Cancel Upload
"
)
text
:
qsTr
(
"
Confirm canceling the upload process?
"
)
onYes
:
{
QGroundControl
.
mavlinkLogManager
.
cancelUpload
()
}
}
}
}
}
}
}
...
...
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