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
95cec0e0
Commit
95cec0e0
authored
Oct 25, 2015
by
Don Gagne
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2109 from DonLakeFlyer/ParamMetaData
Move ParameterLoader override to FirmwarePlugin
parents
60a46a22
f1070496
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
471 additions
and
91 deletions
+471
-91
QGCApplication.pro
QGCApplication.pro
+8
-4
APMAutoPilotPlugin.cc
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc
+79
-0
APMAutoPilotPlugin.h
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h
+52
-0
AutoPilotPlugin.cc
src/AutoPilotPlugins/AutoPilotPlugin.cc
+13
-11
AutoPilotPlugin.h
src/AutoPilotPlugins/AutoPilotPlugin.h
+7
-8
AutoPilotPluginManager.cc
src/AutoPilotPlugins/AutoPilotPluginManager.cc
+8
-4
GenericAutoPilotPlugin.cc
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc
+6
-7
GenericAutoPilotPlugin.h
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h
+3
-9
PX4AutoPilotPlugin.cc
src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc
+5
-10
PX4AutoPilotPlugin.h
src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h
+2
-6
ParameterLoader.h
src/FactSystem/ParameterLoader.h
+4
-4
APMFirmwarePlugin.cc
src/FirmwarePlugin/APM/APMFirmwarePlugin.cc
+20
-2
APMFirmwarePlugin.h
src/FirmwarePlugin/APM/APMFirmwarePlugin.h
+3
-1
APMParameterLoader.cc
src/FirmwarePlugin/APM/APMParameterLoader.cc
+113
-0
APMParameterLoader.h
src/FirmwarePlugin/APM/APMParameterLoader.h
+78
-0
FirmwarePlugin.h
src/FirmwarePlugin/FirmwarePlugin.h
+3
-0
GenericFirmwarePlugin.cc
src/FirmwarePlugin/Generic/GenericFirmwarePlugin.cc
+18
-2
GenericFirmwarePlugin.h
src/FirmwarePlugin/Generic/GenericFirmwarePlugin.h
+4
-0
GenericParameterLoader.cc
src/FirmwarePlugin/Generic/GenericParameterLoader.cc
+9
-7
GenericParameterLoader.h
src/FirmwarePlugin/Generic/GenericParameterLoader.h
+12
-14
PX4FirmwarePlugin.cc
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc
+20
-2
PX4FirmwarePlugin.h
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h
+4
-0
PX4ParameterLoader.cc
src/FirmwarePlugin/PX4/PX4ParameterLoader.cc
+0
-0
PX4ParameterLoader.h
src/FirmwarePlugin/PX4/PX4ParameterLoader.h
+0
-0
No files found.
QGCApplication.pro
View file @
95cec0e0
...
...
@@ -507,8 +507,8 @@ INCLUDEPATH += \
HEADERS
+=
\
src
/
AutoPilotPlugins
/
AutoPilotPlugin
.
h
\
src
/
AutoPilotPlugins
/
AutoPilotPluginManager
.
h
\
src
/
AutoPilotPlugins
/
APM
/
APMAutoPilotPlugin
.
h
\
src
/
AutoPilotPlugins
/
Generic
/
GenericAutoPilotPlugin
.
h
\
src
/
AutoPilotPlugins
/
Generic
/
GenericParameterFacts
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponent
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponentAirframes
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponentController
.
h
\
...
...
@@ -518,7 +518,6 @@ HEADERS+= \
src
/
AutoPilotPlugins
/
PX4
/
PowerComponentController
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
PX4AutoPilotPlugin
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
PX4Component
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
PX4ParameterLoader
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
RadioComponent
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
RadioComponentController
.
h
\
src
/
AutoPilotPlugins
/
PX4
/
SafetyComponent
.
h
\
...
...
@@ -527,11 +526,14 @@ HEADERS+= \
src
/
FirmwarePlugin
/
FirmwarePluginManager
.
h
\
src
/
FirmwarePlugin
/
FirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
APM
/
APMFirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
APM
/
APMParameterLoader
.
h
\
src
/
FirmwarePlugin
/
APM
/
ArduCopterFirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
APM
/
ArduPlaneFirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
APM
/
ArduRoverFirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
Generic
/
GenericFirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
Generic
/
GenericParameterLoader
.
h
\
src
/
FirmwarePlugin
/
PX4
/
PX4FirmwarePlugin
.
h
\
src
/
FirmwarePlugin
/
PX4
/
PX4ParameterLoader
.
h
\
src
/
Vehicle
/
MultiVehicleManager
.
h
\
src
/
Vehicle
/
Vehicle
.
h
\
src
/
VehicleSetup
/
VehicleComponent
.
h
\
...
...
@@ -548,8 +550,8 @@ HEADERS += \
SOURCES
+=
\
src
/
AutoPilotPlugins
/
AutoPilotPlugin
.
cc
\
src
/
AutoPilotPlugins
/
AutoPilotPluginManager
.
cc
\
src
/
AutoPilotPlugins
/
APM
/
APMAutoPilotPlugin
.
cc
\
src
/
AutoPilotPlugins
/
Generic
/
GenericAutoPilotPlugin
.
cc
\
src
/
AutoPilotPlugins
/
Generic
/
GenericParameterFacts
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponent
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponentAirframes
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
AirframeComponentController
.
cc
\
...
...
@@ -559,19 +561,21 @@ SOURCES += \
src
/
AutoPilotPlugins
/
PX4
/
PowerComponentController
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
PX4AutoPilotPlugin
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
PX4Component
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
PX4ParameterLoader
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
RadioComponent
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
RadioComponentController
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
SafetyComponent
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
SensorsComponent
.
cc
\
src
/
AutoPilotPlugins
/
PX4
/
SensorsComponentController
.
cc
\
src
/
FirmwarePlugin
/
APM
/
APMFirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
APM
/
APMParameterLoader
.
cc
\
src
/
FirmwarePlugin
/
APM
/
ArduCopterFirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
APM
/
ArduPlaneFirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
APM
/
ArduRoverFirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
FirmwarePluginManager
.
cc
\
src
/
FirmwarePlugin
/
Generic
/
GenericFirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
Generic
/
GenericParameterLoader
.
cc
\
src
/
FirmwarePlugin
/
PX4
/
PX4FirmwarePlugin
.
cc
\
src
/
FirmwarePlugin
/
PX4
/
PX4ParameterLoader
.
cc
\
src
/
Vehicle
/
MultiVehicleManager
.
cc
\
src
/
Vehicle
/
Vehicle
.
cc
\
src
/
VehicleSetup
/
VehicleComponent
.
cc
\
...
...
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc
0 → 100644
View file @
95cec0e0
/*=====================================================================
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/>.
======================================================================*/
#include "APMAutoPilotPlugin.h"
#include "AutoPilotPluginManager.h"
#include "QGCMessageBox.h"
#include "UAS.h"
#include "FirmwarePlugin/APM/APMParameterLoader.h" // FIXME: Hack
#include "FirmwarePlugin/APM/APMFirmwarePlugin.h" // FIXME: Hack
/// This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_ARDUPILOT type.
APMAutoPilotPlugin
::
APMAutoPilotPlugin
(
Vehicle
*
vehicle
,
QObject
*
parent
)
:
AutoPilotPlugin
(
vehicle
,
parent
),
_incorrectParameterVersion
(
false
)
{
Q_ASSERT
(
vehicle
);
// This kicks off parameter load
_firmwarePlugin
->
getParameterLoader
(
this
,
vehicle
);
}
APMAutoPilotPlugin
::~
APMAutoPilotPlugin
()
{
}
void
APMAutoPilotPlugin
::
clearStaticData
(
void
)
{
APMParameterLoader
::
clearStaticData
();
}
const
QVariantList
&
APMAutoPilotPlugin
::
vehicleComponents
(
void
)
{
static
const
QVariantList
emptyList
;
return
emptyList
;
}
/// This will perform various checks prior to signalling that the plug in ready
void
APMAutoPilotPlugin
::
_parametersReadyPreChecks
(
bool
missingParameters
)
{
#if 0
I believe APM has parameter version stamp, we should check that
// Check for older parameter version set
// FIXME: Firmware is moving to version stamp parameter set. Once that is complete the version stamp
// should be used instead.
if (parameterExists(FactSystem::defaultComponentId, "SENS_GYRO_XOFF")) {
_incorrectParameterVersion = true;
QGCMessageBox::warning("Setup", "This version of GroundControl can only perform vehicle setup on a newer version of firmware. "
"Please perform a Firmware Upgrade if you wish to use Vehicle Setup.");
}
#endif
_parametersReady
=
true
;
_missingParameters
=
missingParameters
;
emit
missingParametersChanged
(
_missingParameters
);
emit
parametersReadyChanged
(
_parametersReady
);
}
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h
0 → 100644
View file @
95cec0e0
/*=====================================================================
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 APMAutoPilotPlugin_H
#define APMAutoPilotPlugin_H
#include "AutoPilotPlugin.h"
#include "Vehicle.h"
/// This is the APM specific implementation of the AutoPilot class.
class
APMAutoPilotPlugin
:
public
AutoPilotPlugin
{
Q_OBJECT
public:
APMAutoPilotPlugin
(
Vehicle
*
vehicle
,
QObject
*
parent
);
~
APMAutoPilotPlugin
();
// Overrides from AutoPilotPlugin
virtual
const
QVariantList
&
vehicleComponents
(
void
);
static
void
clearStaticData
(
void
);
public
slots
:
// FIXME: This is public until we restructure AutoPilotPlugin/FirmwarePlugin/Vehicle
void
_parametersReadyPreChecks
(
bool
missingParameters
);
private:
bool
_incorrectParameterVersion
;
///< true: parameter version incorrect, setup not allowed
};
#endif
src/AutoPilotPlugins/AutoPilotPlugin.cc
View file @
95cec0e0
...
...
@@ -30,10 +30,12 @@
#include "MainWindow.h"
#include "ParameterLoader.h"
#include "UAS.h"
#include "FirmwarePlugin.h"
AutoPilotPlugin
::
AutoPilotPlugin
(
Vehicle
*
vehicle
,
QObject
*
parent
)
:
QObject
(
parent
)
,
_vehicle
(
vehicle
)
,
_firmwarePlugin
(
vehicle
->
firmwarePlugin
())
,
_parametersReady
(
false
)
,
_missingParameters
(
false
)
,
_setupComplete
(
false
)
...
...
@@ -107,34 +109,34 @@ void AutoPilotPlugin::resetAllParametersToDefaults(void)
void
AutoPilotPlugin
::
refreshAllParameters
(
void
)
{
_getParameterLoader
(
)
->
refreshAllParameters
();
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
refreshAllParameters
();
}
void
AutoPilotPlugin
::
refreshParameter
(
int
componentId
,
const
QString
&
name
)
{
_getParameterLoader
(
)
->
refreshParameter
(
componentId
,
name
);
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
refreshParameter
(
componentId
,
name
);
}
void
AutoPilotPlugin
::
refreshParametersPrefix
(
int
componentId
,
const
QString
&
namePrefix
)
{
_getParameterLoader
(
)
->
refreshParametersPrefix
(
componentId
,
namePrefix
);
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
refreshParametersPrefix
(
componentId
,
namePrefix
);
}
bool
AutoPilotPlugin
::
parameterExists
(
int
componentId
,
const
QString
&
name
)
{
return
_
getParameterLoader
(
)
->
parameterExists
(
componentId
,
name
);
return
_
firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
parameterExists
(
componentId
,
name
);
}
Fact
*
AutoPilotPlugin
::
getParameterFact
(
int
componentId
,
const
QString
&
name
)
{
return
_
getParameterLoader
(
)
->
getFact
(
componentId
,
name
);
return
_
firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
getFact
(
componentId
,
name
);
}
bool
AutoPilotPlugin
::
factExists
(
FactSystem
::
Provider_t
provider
,
int
componentId
,
const
QString
&
name
)
{
switch
(
provider
)
{
case
FactSystem
:
:
ParameterProvider
:
return
_
getParameterLoader
(
)
->
parameterExists
(
componentId
,
name
);
return
_
firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
parameterExists
(
componentId
,
name
);
// Other providers will go here once they come online
}
...
...
@@ -147,7 +149,7 @@ Fact* AutoPilotPlugin::getFact(FactSystem::Provider_t provider, int componentId,
{
switch
(
provider
)
{
case
FactSystem
:
:
ParameterProvider
:
return
_
getParameterLoader
(
)
->
getFact
(
componentId
,
name
);
return
_
firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
getFact
(
componentId
,
name
);
// Other providers will go here once they come online
}
...
...
@@ -158,20 +160,20 @@ Fact* AutoPilotPlugin::getFact(FactSystem::Provider_t provider, int componentId,
QStringList
AutoPilotPlugin
::
parameterNames
(
int
componentId
)
{
return
_getParameterLoader
(
)
->
parameterNames
(
componentId
);
return
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
parameterNames
(
componentId
);
}
const
QMap
<
int
,
QMap
<
QString
,
QStringList
>
>&
AutoPilotPlugin
::
getGroupMap
(
void
)
{
return
_
getParameterLoader
(
)
->
getGroupMap
();
return
_
firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
getGroupMap
();
}
void
AutoPilotPlugin
::
writeParametersToStream
(
QTextStream
&
stream
)
{
_getParameterLoader
(
)
->
writeParametersToStream
(
stream
,
_vehicle
->
uas
()
->
getUASName
());
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
writeParametersToStream
(
stream
,
_vehicle
->
uas
()
->
getUASName
());
}
QString
AutoPilotPlugin
::
readParametersFromStream
(
QTextStream
&
stream
)
{
return
_getParameterLoader
(
)
->
readParametersFromStream
(
stream
);
return
_firmwarePlugin
->
getParameterLoader
(
this
,
_vehicle
)
->
readParametersFromStream
(
stream
);
}
src/AutoPilotPlugins/AutoPilotPlugin.h
View file @
95cec0e0
...
...
@@ -38,6 +38,7 @@
class
ParameterLoader
;
class
Vehicle
;
class
FirmwarePlugin
;
/// This is the base class for AutoPilot plugins
///
...
...
@@ -132,20 +133,18 @@ protected:
/// All access to AutoPilotPugin objects is through getInstanceForAutoPilotPlugin
AutoPilotPlugin
(
QObject
*
parent
=
NULL
)
:
QObject
(
parent
)
{
}
/// Returns the ParameterLoader
virtual
ParameterLoader
*
_getParameterLoader
(
void
)
=
0
;
Vehicle
*
_vehicle
;
bool
_parametersReady
;
bool
_missingParameters
;
bool
_setupComplete
;
Vehicle
*
_vehicle
;
FirmwarePlugin
*
_firmwarePlugin
;
bool
_parametersReady
;
bool
_missingParameters
;
bool
_setupComplete
;
private
slots
:
void
_uasDisconnected
(
void
);
void
_parametersReadyChanged
(
bool
parametersReady
);
private:
void
_recalcSetupComplete
(
void
);
void
_recalcSetupComplete
(
void
);
};
#endif
src/AutoPilotPlugins/AutoPilotPluginManager.cc
View file @
95cec0e0
...
...
@@ -26,6 +26,7 @@
#include "AutoPilotPluginManager.h"
#include "PX4/PX4AutoPilotPlugin.h"
#include "APM/APMAutoPilotPlugin.h"
#include "Generic/GenericAutoPilotPlugin.h"
IMPLEMENT_QGC_SINGLETON
(
AutoPilotPluginManager
,
AutoPilotPluginManager
)
...
...
@@ -44,9 +45,12 @@ AutoPilotPluginManager::~AutoPilotPluginManager()
AutoPilotPlugin
*
AutoPilotPluginManager
::
newAutopilotPluginForVehicle
(
Vehicle
*
vehicle
)
{
if
(
vehicle
->
firmwareType
()
==
MAV_AUTOPILOT_PX4
)
{
return
new
PX4AutoPilotPlugin
(
vehicle
,
vehicle
);
}
else
{
return
new
GenericAutoPilotPlugin
(
vehicle
,
vehicle
);
switch
(
vehicle
->
firmwareType
())
{
case
MAV_AUTOPILOT_PX4
:
return
new
PX4AutoPilotPlugin
(
vehicle
,
vehicle
);
case
MAV_AUTOPILOT_ARDUPILOTMEGA
:
return
new
APMAutoPilotPlugin
(
vehicle
,
vehicle
);
default:
return
new
GenericAutoPilotPlugin
(
vehicle
,
vehicle
);
}
}
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc
View file @
95cec0e0
...
...
@@ -25,17 +25,15 @@
/// @author Don Gagne <don@thegagnes.com>
#include "GenericAutoPilotPlugin.h"
#include "FirmwarePlugin/Generic/GenericFirmwarePlugin.h" // FIXME: Hack
GenericAutoPilotPlugin
::
GenericAutoPilotPlugin
(
Vehicle
*
vehicle
,
QObject
*
parent
)
:
AutoPilotPlugin
(
vehicle
,
parent
)
{
Q_ASSERT
(
vehicle
);
_parameterFacts
=
new
GenericParameterFacts
(
this
,
vehicle
,
this
);
Q_CHECK_PTR
(
_parameterFacts
);
connect
(
_parameterFacts
,
&
GenericParameterFacts
::
parametersReady
,
this
,
&
GenericAutoPilotPlugin
::
_parametersReadySlot
);
connect
(
_parameterFacts
,
&
GenericParameterFacts
::
parameterListProgress
,
this
,
&
GenericAutoPilotPlugin
::
parameterListProgress
);
// This kicks off parameter load
_firmwarePlugin
->
getParameterLoader
(
this
,
vehicle
);
}
void
GenericAutoPilotPlugin
::
clearStaticData
(
void
)
...
...
@@ -50,7 +48,8 @@ const QVariantList& GenericAutoPilotPlugin::vehicleComponents(void)
return
emptyList
;
}
void
GenericAutoPilotPlugin
::
_parametersReadySlot
(
bool
missingParameters
)
/// This will perform various checks prior to signalling that the plug in ready
void
GenericAutoPilotPlugin
::
_parametersReadyPreChecks
(
bool
missingParameters
)
{
_parametersReady
=
true
;
_missingParameters
=
missingParameters
;
...
...
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h
View file @
95cec0e0
...
...
@@ -25,7 +25,6 @@
#define GENERICAUTOPILOT_H
#include "AutoPilotPlugin.h"
#include "GenericParameterFacts.h"
/// @file
/// @brief This is the generic implementation of the AutoPilotPlugin class for mavs
...
...
@@ -44,14 +43,9 @@ public:
static
void
clearStaticData
(
void
);
private
slots
:
void
_parametersReadySlot
(
bool
missingParameters
);
private:
// Overrides from AutoPilotPlugin
virtual
ParameterLoader
*
_getParameterLoader
(
void
)
{
return
_parameterFacts
;
}
GenericParameterFacts
*
_parameterFacts
;
public
slots
:
// FIXME: This is public until we restructure AutoPilotPlugin/FirmwarePlugin/Vehicle
void
_parametersReadyPreChecks
(
bool
missingParameters
);
};
#endif
src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc
View file @
95cec0e0
...
...
@@ -23,12 +23,13 @@
#include "PX4AutoPilotPlugin.h"
#include "AutoPilotPluginManager.h"
#include "PX4ParameterLoader.h"
#include "PX4AirframeLoader.h"
#include "FlightModesComponentController.h"
#include "AirframeComponentController.h"
#include "QGCMessageBox.h"
#include "UAS.h"
#include "FirmwarePlugin/PX4/PX4ParameterLoader.h" // FIXME: Hack
#include "FirmwarePlugin/PX4/PX4FirmwarePlugin.h" // FIXME: Hack
/// @file
/// @brief This is the AutoPilotPlugin implementatin for the MAV_AUTOPILOT_PX4 type.
...
...
@@ -66,7 +67,6 @@ union px4_custom_mode {
PX4AutoPilotPlugin
::
PX4AutoPilotPlugin
(
Vehicle
*
vehicle
,
QObject
*
parent
)
:
AutoPilotPlugin
(
vehicle
,
parent
),
_parameterFacts
(
NULL
),
_airframeComponent
(
NULL
),
_radioComponent
(
NULL
),
_flightModesComponent
(
NULL
),
...
...
@@ -77,22 +77,17 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(Vehicle* vehicle, QObject* parent) :
{
Q_ASSERT
(
vehicle
);
_parameterFacts
=
new
PX4ParameterLoader
(
this
,
vehicle
,
this
);
Q_CHECK_PTR
(
_parameterFacts
);
connect
(
_parameterFacts
,
&
PX4ParameterLoader
::
parametersReady
,
this
,
&
PX4AutoPilotPlugin
::
_parametersReadyPreChecks
);
connect
(
_parameterFacts
,
&
PX4ParameterLoader
::
parameterListProgress
,
this
,
&
PX4AutoPilotPlugin
::
parameterListProgress
);
_airframeFacts
=
new
PX4AirframeLoader
(
this
,
_vehicle
->
uas
(),
this
);
Q_CHECK_PTR
(
_airframeFacts
);
PX4ParameterLoader
::
loadParameterFactMetaData
();
PX4AirframeLoader
::
loadAirframeFactMetaData
();
// This kicks off parameter load
_firmwarePlugin
->
getParameterLoader
(
this
,
vehicle
);
}
PX4AutoPilotPlugin
::~
PX4AutoPilotPlugin
()
{
delete
_parameterFacts
;
delete
_airframeFacts
;
}
...
...
src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h
View file @
95cec0e0
...
...
@@ -25,7 +25,6 @@
#define PX4AUTOPILOT_H
#include "AutoPilotPlugin.h"
#include "PX4ParameterLoader.h"
#include "PX4AirframeLoader.h"
#include "AirframeComponent.h"
#include "RadioComponent.h"
...
...
@@ -62,14 +61,11 @@ public:
SafetyComponent
*
safetyComponent
(
void
)
{
return
_safetyComponent
;
}
PowerComponent
*
powerComponent
(
void
)
{
return
_powerComponent
;
}
private
slots
:
public
slots
:
// FIXME: This is public until we restructure AutoPilotPlugin/FirmwarePlugin/Vehicle
void
_parametersReadyPreChecks
(
bool
missingParameters
);
private:
// Overrides from AutoPilotPlugin
virtual
ParameterLoader
*
_getParameterLoader
(
void
)
{
return
_parameterFacts
;
}
PX4ParameterLoader
*
_parameterFacts
;
PX4AirframeLoader
*
_airframeFacts
;
QVariantList
_components
;
AirframeComponent
*
_airframeComponent
;
...
...
src/FactSystem/ParameterLoader.h
View file @
95cec0e0
...
...
@@ -105,6 +105,10 @@ protected:
/// Base implementation adds generic meta data based on variant type. Derived class can override to provide
/// more details meta data.
virtual
void
_addMetaDataToFact
(
Fact
*
fact
);
AutoPilotPlugin
*
_autopilot
;
Vehicle
*
_vehicle
;
MAVLinkProtocol
*
_mavlink
;
private
slots
:
void
_parameterUpdate
(
int
uasId
,
int
componentId
,
QString
parameterName
,
int
parameterCount
,
int
parameterId
,
int
mavType
,
QVariant
value
);
...
...
@@ -128,10 +132,6 @@ private:
void
_saveToEEPROM
(
void
);
void
_checkInitialLoadComplete
(
void
);
AutoPilotPlugin
*
_autopilot
;
Vehicle
*
_vehicle
;
MAVLinkProtocol
*
_mavlink
;
/// First mapping is by component id
/// Second mapping is parameter name, to Fact* in QVariant
QMap
<
int
,
QVariantMap
>
_mapParameterName2Variant
;
...
...
src/FirmwarePlugin/APM/APMFirmwarePlugin.cc
View file @
95cec0e0
...
...
@@ -26,6 +26,7 @@
#include "APMFirmwarePlugin.h"
#include "Generic/GenericFirmwarePlugin.h"
#include "AutoPilotPlugins/APM/APMAutoPilotPlugin.h" // FIXME: Hack
#include "QGCMAVLink.h"
QGC_LOGGING_CATEGORY
(
APMFirmwarePluginLog
,
"APMFirmwarePluginLog"
)
...
...
@@ -138,8 +139,9 @@ QString APMCustomMode::modeString() const
return
mode
;
}
APMFirmwarePlugin
::
APMFirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
APMFirmwarePlugin
::
APMFirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
,
_parameterLoader
(
NULL
)
{
_textSeverityAdjustmentNeeded
=
false
;
}
...
...
@@ -384,3 +386,19 @@ bool APMFirmwarePlugin::sendHomePositionToVehicle(void)
// APM stack wants the home position sent in the first position
return
true
;
}
ParameterLoader
*
APMFirmwarePlugin
::
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
)
{
if
(
!
_parameterLoader
)
{
_parameterLoader
=
new
APMParameterLoader
(
autopilotPlugin
,
vehicle
,
this
);
Q_CHECK_PTR
(
_parameterLoader
);
// FIXME: Why do I need SIGNAL/SLOT to make this work
connect
(
_parameterLoader
,
SIGNAL
(
parametersReady
(
bool
)),
autopilotPlugin
,
SLOT
(
_parametersReadyPreChecks
(
bool
)));
connect
(
_parameterLoader
,
&
APMParameterLoader
::
parameterListProgress
,
autopilotPlugin
,
&
APMAutoPilotPlugin
::
parameterListProgress
);
_parameterLoader
->
loadParameterFactMetaData
();
}
return
_parameterLoader
;
}
src/FirmwarePlugin/APM/APMFirmwarePlugin.h
View file @
95cec0e0
...
...
@@ -29,6 +29,7 @@
#include "FirmwarePlugin.h"
#include "QGCLoggingCategory.h"
#include "APMParameterLoader.h"
Q_DECLARE_LOGGING_CATEGORY
(
APMFirmwarePluginLog
)
...
...
@@ -88,6 +89,7 @@ public:
virtual
void
adjustMavlinkMessage
(
mavlink_message_t
*
message
);
virtual
void
initializeVehicle
(
Vehicle
*
vehicle
);
virtual
bool
sendHomePositionToVehicle
(
void
);
virtual
ParameterLoader
*
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
);
protected:
/// All access to singleton is through stack specific implementation
...
...
@@ -101,7 +103,7 @@ private:
APMFirmwareVersion
_firmwareVersion
;
bool
_textSeverityAdjustmentNeeded
;
QList
<
APMCustomMode
>
_supportedModes
;
APMParameterLoader
*
_parameterLoader
;
};
#endif
src/FirmwarePlugin/APM/APMParameterLoader.cc
0 → 100644
View file @
95cec0e0
/*=====================================================================
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/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "APMParameterLoader.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
QGC_LOGGING_CATEGORY
(
APMParameterLoaderLog
,
"APMParameterLoaderLog"
)
bool
APMParameterLoader
::
_parameterMetaDataLoaded
=
false
;
QMap
<
QString
,
FactMetaData
*>
APMParameterLoader
::
_mapParameterName2FactMetaData
;
APMParameterLoader
::
APMParameterLoader
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
)
:
ParameterLoader
(
autopilot
,
vehicle
,
parent
)
{
Q_ASSERT
(
vehicle
);
}
/// Converts a string to a typed QVariant
/// @param string String to convert
/// @param type Type for Fact which dictates the QVariant type as well
/// @param convertOk Returned: true: conversion success, false: conversion failure
/// @return Returns the correctly type QVariant
QVariant
APMParameterLoader
::
_stringToTypedVariant
(
const
QString
&
string
,
FactMetaData
::
ValueType_t
type
,
bool
*
convertOk
)
{
QVariant
var
(
string
);
int
convertTo
=
QVariant
::
Int
;
// keep compiler warning happy
switch
(
type
)
{
case
FactMetaData
:
:
valueTypeUint8
:
case
FactMetaData
:
:
valueTypeUint16
:
case
FactMetaData
:
:
valueTypeUint32
:
convertTo
=
QVariant
::
UInt
;
break
;
case
FactMetaData
:
:
valueTypeInt8
:
case
FactMetaData
:
:
valueTypeInt16
:
case
FactMetaData
:
:
valueTypeInt32
:
convertTo
=
QVariant
::
Int
;
break
;
case
FactMetaData
:
:
valueTypeFloat
:
convertTo
=
QMetaType
::
Float
;
break
;
case
FactMetaData
:
:
valueTypeDouble
:
convertTo
=
QVariant
::
Double
;
break
;
}
*
convertOk
=
var
.
convert
(
convertTo
);
return
var
;
}
/// Load Parameter Fact meta data
///
/// The meta data comes from firmware parameters.xml file.
void
APMParameterLoader
::
loadParameterFactMetaData
(
void
)
{
if
(
_parameterMetaDataLoaded
)
{
return
;
}
_parameterMetaDataLoaded
=
true
;
// FIXME: NYI
// Static meta data should load all MAV_TYPEs from single meta data file in such a way that the loader
// has multiple sets of static meta data
}
void
APMParameterLoader
::
clearStaticData
(
void
)
{
foreach
(
QString
parameterName
,
_mapParameterName2FactMetaData
.
keys
())
{
delete
_mapParameterName2FactMetaData
[
parameterName
];
}
_mapParameterName2FactMetaData
.
clear
();
_parameterMetaDataLoaded
=
false
;
}
/// Override from FactLoad which connects the meta data to the fact
void
APMParameterLoader
::
_addMetaDataToFact
(
Fact
*
fact
)
{
// FIXME: Will need to switch here based on _vehicle->firmwareType() to pull right set of meta data
// Use generic meta data
ParameterLoader
::
_addMetaDataToFact
(
fact
);
}
src/FirmwarePlugin/APM/APMParameterLoader.h
0 → 100644
View file @
95cec0e0
/*=====================================================================
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 APMParameterLoader_H
#define APMParameterLoader_H
#include <QObject>
#include <QMap>
#include <QXmlStreamReader>
#include <QLoggingCategory>
#include "ParameterLoader.h"
#include "FactSystem.h"
#include "AutoPilotPlugin.h"
#include "Vehicle.h"
/// @file
/// @author Don Gagne <don@thegagnes.com>
Q_DECLARE_LOGGING_CATEGORY
(
APMParameterLoaderLog
)
/// Collection of Parameter Facts for PX4 AutoPilot
class
APMParameterLoader
:
public
ParameterLoader
{
Q_OBJECT
public:
/// @param uas Uas which this set of facts is associated with
APMParameterLoader
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
=
NULL
);
/// Override from ParameterLoader
virtual
QString
getDefaultComponentIdParam
(
void
)
const
{
return
QString
(
"SYSID_SW_TYPE"
);
}
static
void
loadParameterFactMetaData
(
void
);
static
void
clearStaticData
(
void
);
private:
enum
{
XmlStateNone
,
XmlStateFoundParameters
,
XmlStateFoundVersion
,
XmlStateFoundGroup
,
XmlStateFoundParameter
,
XmlStateDone
};
// Overrides from ParameterLoader
virtual
void
_addMetaDataToFact
(
Fact
*
fact
);
// Class methods
static
QVariant
_stringToTypedVariant
(
const
QString
&
string
,
FactMetaData
::
ValueType_t
type
,
bool
*
convertOk
);
static
bool
_parameterMetaDataLoaded
;
///< true: parameter meta data already loaded
static
QMap
<
QString
,
FactMetaData
*>
_mapParameterName2FactMetaData
;
///< Maps from a parameter name to FactMetaData
};
#endif
src/FirmwarePlugin/FirmwarePlugin.h
View file @
95cec0e0
...
...
@@ -105,6 +105,9 @@ public:
/// false: Do not send first item to vehicle, sequence numbers must be adjusted
virtual
bool
sendHomePositionToVehicle
(
void
)
=
0
;
/// Returns the ParameterLoader
virtual
ParameterLoader
*
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
)
=
0
;
protected:
FirmwarePlugin
(
QObject
*
parent
=
NULL
)
:
QGCSingleton
(
parent
)
{
}
};
...
...
src/FirmwarePlugin/Generic/GenericFirmwarePlugin.cc
View file @
95cec0e0
...
...
@@ -25,13 +25,15 @@
/// @author Don Gagne <don@thegagnes.com>
#include "GenericFirmwarePlugin.h"
#include "AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h" // FIXME: Hack
#include <QDebug>
IMPLEMENT_QGC_SINGLETON
(
GenericFirmwarePlugin
,
FirmwarePlugin
)
GenericFirmwarePlugin
::
GenericFirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
GenericFirmwarePlugin
::
GenericFirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
,
_parameterLoader
(
NULL
)
{
}
...
...
@@ -118,3 +120,17 @@ bool GenericFirmwarePlugin::sendHomePositionToVehicle(void)
// This is the mavlink spec default.
return
false
;
}
ParameterLoader
*
GenericFirmwarePlugin
::
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
)
{
if
(
!
_parameterLoader
)
{
_parameterLoader
=
new
GenericParameterLoader
(
autopilotPlugin
,
vehicle
,
this
);
Q_CHECK_PTR
(
_parameterLoader
);
// FIXME: Why do I need SIGNAL/SLOT to make this work
connect
(
_parameterLoader
,
SIGNAL
(
parametersReady
(
bool
)),
autopilotPlugin
,
SLOT
(
_parametersReadyPreChecks
(
bool
)));
connect
(
_parameterLoader
,
&
GenericParameterLoader
::
parameterListProgress
,
autopilotPlugin
,
&
GenericAutoPilotPlugin
::
parameterListProgress
);
}
return
_parameterLoader
;
}
src/FirmwarePlugin/Generic/GenericFirmwarePlugin.h
View file @
95cec0e0
...
...
@@ -28,6 +28,7 @@
#define GenericFirmwarePlugin_H
#include "FirmwarePlugin.h"
#include "GenericParameterLoader.h"
class
GenericFirmwarePlugin
:
public
FirmwarePlugin
{
...
...
@@ -47,10 +48,13 @@ public:
virtual
void
adjustMavlinkMessage
(
mavlink_message_t
*
message
);
virtual
void
initializeVehicle
(
Vehicle
*
vehicle
);
virtual
bool
sendHomePositionToVehicle
(
void
);
virtual
ParameterLoader
*
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
);
private:
/// All access to singleton is through AutoPilotPluginManager::instance
GenericFirmwarePlugin
(
QObject
*
parent
=
NULL
);
GenericParameterLoader
*
_parameterLoader
;
};
#endif
src/
AutoPilotPlugins/Generic/GenericParameterFacts
.cc
→
src/
FirmwarePlugin/Generic/GenericParameterLoader
.cc
View file @
95cec0e0
...
...
@@ -21,15 +21,17 @@
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "GenericParameterLoader.h"
#include "GenericParameterFacts.h"
#include <QDebug>
GenericParameterFacts
::
GenericParameterFacts
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
)
:
GenericParameterLoader
::
GenericParameterLoader
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
)
:
ParameterLoader
(
autopilot
,
vehicle
,
parent
)
{
Q_ASSERT
(
vehicle
);
}
/// Override from ParameterLoader which connects the meta data to the fact
void
GenericParameterLoader
::
_addMetaDataToFact
(
Fact
*
fact
)
{
// Use generic meta data
ParameterLoader
::
_addMetaDataToFact
(
fact
);
}
src/
AutoPilotPlugins/Generic/GenericParameterFacts
.h
→
src/
FirmwarePlugin/Generic/GenericParameterLoader
.h
View file @
95cec0e0
...
...
@@ -21,30 +21,28 @@
======================================================================*/
#ifndef GenericParameterFacts_h
#define GenericParameterFacts_h
#include <QObject>
#ifndef GenericParameterLoader_H
#define GenericParameterLoader_H
#include "ParameterLoader.h"
#include "
UASInterface
.h"
#include "
FactSystem
.h"
#include "AutoPilotPlugin.h"
#include "Vehicle.h"
/// @file
/// @author Don Gagne <don@thegagnes.com>
/// Collection of Parameter Facts for Generic AutoPilot
class
GenericParameterFacts
:
public
ParameterLoader
class
GenericParameterLoader
:
public
ParameterLoader
{
Q_OBJECT
public:
/// @param uas Uas which this set of facts is associated with
GenericParameter
Facts
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
=
NULL
);
GenericParameter
Loader
(
AutoPilotPlugin
*
autopilot
,
Vehicle
*
vehicle
,
QObject
*
parent
=
NULL
);
/// Override from ParameterLoader
virtual
QString
getDefaultComponentIdParam
(
void
)
const
{
return
QString
();
}
private:
// Overrides from ParameterLoader
virtual
void
_addMetaDataToFact
(
Fact
*
fact
);
};
#endif
\ No newline at end of file
#endif
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc
View file @
95cec0e0
...
...
@@ -25,6 +25,7 @@
/// @author Don Gagne <don@thegagnes.com>
#include "PX4FirmwarePlugin.h"
#include "AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h" // FIXME: Hack
#include <QDebug>
...
...
@@ -85,8 +86,9 @@ static const struct Modes2Name rgModes2Name[] = {
};
PX4FirmwarePlugin
::
PX4FirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
PX4FirmwarePlugin
::
PX4FirmwarePlugin
(
QObject
*
parent
)
:
FirmwarePlugin
(
parent
)
,
_parameterLoader
(
NULL
)
{
}
...
...
@@ -207,3 +209,19 @@ bool PX4FirmwarePlugin::sendHomePositionToVehicle(void)
// Subsequent sequence numbers must be adjusted.
return
false
;
}
ParameterLoader
*
PX4FirmwarePlugin
::
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
)
{
if
(
!
_parameterLoader
)
{
_parameterLoader
=
new
PX4ParameterLoader
(
autopilotPlugin
,
vehicle
,
this
);
Q_CHECK_PTR
(
_parameterLoader
);
// FIXME: Why do I need SIGNAL/SLOT to make this work
connect
(
_parameterLoader
,
SIGNAL
(
parametersReady
(
bool
)),
autopilotPlugin
,
SLOT
(
_parametersReadyPreChecks
(
bool
)));
connect
(
_parameterLoader
,
&
PX4ParameterLoader
::
parameterListProgress
,
autopilotPlugin
,
&
PX4AutoPilotPlugin
::
parameterListProgress
);
_parameterLoader
->
loadParameterFactMetaData
();
}
return
_parameterLoader
;
}
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h
View file @
95cec0e0
...
...
@@ -28,6 +28,7 @@
#define PX4FirmwarePlugin_H
#include "FirmwarePlugin.h"
#include "PX4ParameterLoader.h"
class
PX4FirmwarePlugin
:
public
FirmwarePlugin
{
...
...
@@ -47,10 +48,13 @@ public:
virtual
void
adjustMavlinkMessage
(
mavlink_message_t
*
message
);
virtual
void
initializeVehicle
(
Vehicle
*
vehicle
);
virtual
bool
sendHomePositionToVehicle
(
void
);
virtual
ParameterLoader
*
getParameterLoader
(
AutoPilotPlugin
*
autopilotPlugin
,
Vehicle
*
vehicle
);
private:
/// All access to singleton is through AutoPilotPluginManager::instance
PX4FirmwarePlugin
(
QObject
*
parent
=
NULL
);
PX4ParameterLoader
*
_parameterLoader
;
};
#endif
src/
AutoPilotPlugins
/PX4/PX4ParameterLoader.cc
→
src/
FirmwarePlugin
/PX4/PX4ParameterLoader.cc
View file @
95cec0e0
File moved
src/
AutoPilotPlugins
/PX4/PX4ParameterLoader.h
→
src/
FirmwarePlugin
/PX4/PX4ParameterLoader.h
View file @
95cec0e0
File moved
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