Commit 0f4a168f authored by Don Gagne's avatar Don Gagne
Browse files

Merge pull request #1118 from DonLakeFlyer/FSTest

Combined pulls #1113 and #1115
parents 866c327d fc493d75
import QtQuick 2.0
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl.FactSystem 1.0
......
......@@ -484,7 +484,6 @@ HEADERS += \
src/uas/QGCUASParamManagerInterface.h \
src/uas/QGCUASFileManager.h \
src/ui/QGCUASFileView.h \
src/uas/QGCUASWorker.h \
src/CmdLineOptParser.h \
src/uas/QGXPX4UAS.h \
src/QGCFileDialog.h \
......@@ -625,7 +624,6 @@ SOURCES += \
src/ui/menuactionhelper.cpp \
src/uas/QGCUASFileManager.cc \
src/ui/QGCUASFileView.cc \
src/uas/QGCUASWorker.cc \
src/CmdLineOptParser.cc \
src/uas/QGXPX4UAS.cc \
src/QGCFileDialog.cc \
......@@ -670,7 +668,8 @@ HEADERS += \
src/qgcunittest/LinkManagerTest.h \
src/qgcunittest/MainWindowTest.h \
src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h \
src/qgcunittest/MavlinkLogTest.h
src/qgcunittest/MavlinkLogTest.h \
src/FactSystem/FactSystemTest.h
SOURCES += \
src/qgcunittest/UnitTest.cc \
......@@ -691,7 +690,8 @@ SOURCES += \
src/qgcunittest/LinkManagerTest.cc \
src/qgcunittest/MainWindowTest.cc \
src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc \
src/qgcunittest/MavlinkLogTest.cc
src/qgcunittest/MavlinkLogTest.cc \
src/FactSystem/FactSystemTest.cc
}
#
......
......@@ -230,6 +230,7 @@
</qresource>
<qresource prefix="/unittest">
<file alias="MockLink.param">src/qgcunittest/MockLink.param</file>
<file alias="FactSystemTest.qml">src/FactSystem/FactSystemTest.qml</file>
</qresource>
<qresource prefix="/QLoggingCategory">
<file alias="qtlogging.ini">files/QLoggingCategory/qtlogging.ini</file>
......
......@@ -21,6 +21,9 @@
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef AUTOPILOTPLUGIN_H
#define AUTOPILOTPLUGIN_H
......@@ -33,12 +36,12 @@
#include "VehicleComponent.h"
#include "FactSystem.h"
/// @file
/// @brief The AutoPilotPlugin class is an abstract base class which represent the methods and objects
/// which are specific to a certain AutoPilot. This is the only place where AutoPilot specific
/// code should reside in QGroundControl. The remainder of the QGroundControl source is
/// generic to a common mavlink implementation.
/// @author Don Gagne <don@thegagnes.com>
/// This is the base class for AutoPilot plugins
///
/// The AutoPilotPlugin class is an abstract base class which represent the methods and objects
/// which are specific to a certain AutoPilot. This is the only place where AutoPilot specific
/// code should reside in QGroundControl. The remainder of the QGroundControl source is
/// generic to a common mavlink implementation.
class AutoPilotPlugin : public QObject
{
......@@ -46,21 +49,28 @@ class AutoPilotPlugin : public QObject
public:
/// @brief Returns the list of VehicleComponent objects associated with the AutoPilot.
virtual QList<VehicleComponent*> getVehicleComponents(UASInterface* uas) const = 0;
virtual QList<VehicleComponent*> getVehicleComponents(void) const = 0;
/// Returns the parameter facts for the specified UAS.
///
/// Access to parameter properties is done through QObject::property or the full
/// QMetaObject methods. The property name is the parameter name. You should not
/// request parameter facts until the plugin reports that it is ready.
virtual QObject* parameterFacts(void) const = 0;
typedef struct {
uint8_t baseMode;
uint32_t customMode;
} FullMode_t;
/// Adds the FactSystem properties to the Qml context. You should not call
/// this method until the plugin reports that it is ready.
virtual void addFactsToQmlContext(QQmlContext* context) const = 0;
/// @brief Returns the list of modes which are available for this AutoPilot.
virtual QList<FullMode_t> getModes(void) const = 0;
/// Returns true if the plugin is ready for use
virtual bool pluginIsReady(void) const = 0;
/// @brief Returns a human readable short description for the specified mode.
virtual QString getShortModeText(uint8_t baseMode, uint32_t customMode) const = 0;
/// FIXME: Kind of hacky
static void clearStaticData(void);
/// @brief Adds the FactSystem properties associated with this AutoPilot to the Qml context.
virtual void addFactsToQmlContext(QQmlContext* context, UASInterface* uas) const = 0;
signals:
/// Signalled when plugin is ready for use
void pluginReady(void);
protected:
// All access to AutoPilotPugin objects is through getInstanceForAutoPilotPlugin
......
......@@ -28,29 +28,109 @@
#include "PX4/PX4AutoPilotPlugin.h"
#include "Generic/GenericAutoPilotPlugin.h"
#include "QGCApplication.h"
#include "UASManager.h"
IMPLEMENT_QGC_SINGLETON(AutoPilotPluginManager, AutoPilotPluginManager)
AutoPilotPluginManager::AutoPilotPluginManager(QObject* parent) :
QGCSingleton(parent)
{
// All plugins are constructed here so that they end up on the correct thread
_pluginMap[MAV_AUTOPILOT_PX4] = new PX4AutoPilotPlugin(this);
Q_ASSERT(_pluginMap.contains(MAV_AUTOPILOT_PX4));
UASManagerInterface* uasMgr = UASManager::instance();
Q_ASSERT(uasMgr);
// We need to track uas coming and going so that we can instantiate plugins for each uas
connect(uasMgr, &UASManagerInterface::UASCreated, this, &AutoPilotPluginManager::_uasCreated);
connect(uasMgr, &UASManagerInterface::UASDeleted, this, &AutoPilotPluginManager::_uasDeleted);
}
_pluginMap[MAV_AUTOPILOT_GENERIC] = new GenericAutoPilotPlugin(this);
Q_ASSERT(_pluginMap.contains(MAV_AUTOPILOT_GENERIC));
AutoPilotPluginManager::~AutoPilotPluginManager()
{
#ifdef QT_DEBUG
foreach(MAV_AUTOPILOT mavType, _pluginMap.keys()) {
Q_ASSERT_X(_pluginMap[mavType].count() == 0, "AutoPilotPluginManager", "LinkManager::_shutdown should have already closed all uas");
}
#endif
_pluginMap.clear();
PX4AutoPilotPlugin::clearStaticData();
GenericAutoPilotPlugin::clearStaticData();
}
/// Create the plugin for this uas
void AutoPilotPluginManager::_uasCreated(UASInterface* uas)
{
Q_ASSERT(uas);
MAV_AUTOPILOT autopilotType = static_cast<MAV_AUTOPILOT>(uas->getAutopilotType());
int uasId = uas->getUASID();
Q_ASSERT(uasId != 0);
if (_pluginMap.contains(autopilotType)) {
Q_ASSERT_X(!_pluginMap[autopilotType].contains(uasId), "AutoPilotPluginManager", "Either we have duplicate UAS ids, or a UAS was not removed correctly.");
}
AutoPilotPlugin* plugin;
switch (autopilotType) {
case MAV_AUTOPILOT_PX4:
plugin = new PX4AutoPilotPlugin(uas, this);
Q_CHECK_PTR(plugin);
_pluginMap[MAV_AUTOPILOT_PX4][uasId] = plugin;
break;
case MAV_AUTOPILOT_GENERIC:
default:
plugin = new GenericAutoPilotPlugin(uas, this);
Q_CHECK_PTR(plugin);
_pluginMap[MAV_AUTOPILOT_GENERIC][uasId] = plugin;
}
}
/// Destroy the plugin associated with this uas
void AutoPilotPluginManager::_uasDeleted(UASInterface* uas)
{
Q_ASSERT(uas);
MAV_AUTOPILOT autopilotType = static_cast<MAV_AUTOPILOT>(uas->getAutopilotType());
int uasId = uas->getUASID();
Q_ASSERT(uasId != 0);
Q_ASSERT(_pluginMap.contains(autopilotType));
Q_ASSERT(_pluginMap[autopilotType].contains(uasId));
delete _pluginMap[autopilotType][uasId];
_pluginMap[autopilotType].remove(uasId);
}
AutoPilotPlugin* AutoPilotPluginManager::getInstanceForAutoPilotPlugin(UASInterface* uas)
{
Q_ASSERT(uas);
MAV_AUTOPILOT autopilotType = static_cast<MAV_AUTOPILOT>(uas->getAutopilotType());
int uasId = uas->getUASID();
Q_ASSERT(uasId != 0);
Q_ASSERT(_pluginMap.contains(autopilotType));
Q_ASSERT(_pluginMap[autopilotType].contains(uasId));
return _pluginMap[autopilotType][uasId];
}
QList<AutoPilotPluginManager::FullMode_t> AutoPilotPluginManager::getModes(int autopilotType) const
{
switch (autopilotType) {
case MAV_AUTOPILOT_PX4:
return PX4AutoPilotPlugin::getModes();
case MAV_AUTOPILOT_GENERIC:
default:
return GenericAutoPilotPlugin::getModes();
}
}
AutoPilotPlugin* AutoPilotPluginManager::getInstanceForAutoPilotPlugin(int autopilotType)
QString AutoPilotPluginManager::getShortModeText(uint8_t baseMode, uint32_t customMode, int autopilotType) const
{
switch (autopilotType) {
case MAV_AUTOPILOT_PX4:
Q_ASSERT(_pluginMap.contains(MAV_AUTOPILOT_PX4));
return _pluginMap[MAV_AUTOPILOT_PX4];
return PX4AutoPilotPlugin::getShortModeText(baseMode, customMode);
case MAV_AUTOPILOT_GENERIC:
default:
Q_ASSERT(_pluginMap.contains(MAV_AUTOPILOT_GENERIC));
return _pluginMap[MAV_AUTOPILOT_GENERIC];
return GenericAutoPilotPlugin::getShortModeText(baseMode, customMode);
}
}
......@@ -21,6 +21,9 @@
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef AUTOPILOTPLUGINMANAGER_H
#define AUTOPILOTPLUGINMANAGER_H
......@@ -32,11 +35,10 @@
#include "VehicleComponent.h"
#include "AutoPilotPlugin.h"
#include "QGCSingleton.h"
#include "QGCMAVLink.h"
/// @file
/// @brief The AutoPilotPlugin manager is a singleton which maintains the list of AutoPilotPlugin objects.
///
/// @author Don Gagne <don@thegagnes.com>
/// AutoPilotPlugin manager is a singleton which maintains the list of AutoPilotPlugin objects.
class AutoPilotPluginManager : public QGCSingleton
{
......@@ -45,15 +47,31 @@ class AutoPilotPluginManager : public QGCSingleton
DECLARE_QGC_SINGLETON(AutoPilotPluginManager, AutoPilotPluginManager)
public:
/// @brief Returns the singleton AutoPilot instance for the specified auto pilot type.
/// @param autopilotType Specified using the MAV_AUTOPILOT_* values.
AutoPilotPlugin* getInstanceForAutoPilotPlugin(int autopilotType);
/// Returns the singleton AutoPilotPlugin instance for the specified uas.
/// @param uas Uas to get plugin for
AutoPilotPlugin* getInstanceForAutoPilotPlugin(UASInterface* uas);
typedef struct {
uint8_t baseMode;
uint32_t customMode;
} FullMode_t;
/// Returns the list of modes which are available for the specified autopilot type.
QList<FullMode_t> getModes(int autopilotType) const;
/// @brief Returns a human readable short description for the specified mode.
QString getShortModeText(uint8_t baseMode, uint32_t customMode, int autopilotType) const;
private slots:
void _uasCreated(UASInterface* uas);
void _uasDeleted(UASInterface* uas);
private:
/// All access to singleton is through AutoPilotPluginManager::instance
AutoPilotPluginManager(QObject* parent = NULL);
~AutoPilotPluginManager();
QMap<int, AutoPilotPlugin*> _pluginMap;
QMap<MAV_AUTOPILOT, QMap<int, AutoPilotPlugin*> > _pluginMap; ///< Map of AutoPilot plugins _pluginMap[MAV_TYPE][UASid]
};
#endif
......@@ -26,24 +26,22 @@
#include "GenericAutoPilotPlugin.h"
GenericAutoPilotPlugin::GenericAutoPilotPlugin(QObject* parent) :
GenericAutoPilotPlugin::GenericAutoPilotPlugin(UASInterface* uas, QObject* parent) :
AutoPilotPlugin(parent)
{
Q_UNUSED(uas);
}
QList<VehicleComponent*> GenericAutoPilotPlugin::getVehicleComponents(UASInterface* uas) const
QList<VehicleComponent*> GenericAutoPilotPlugin::getVehicleComponents(void) const
{
Q_UNUSED(uas);
// Generic autopilot has no configurable components
return QList<VehicleComponent*>();
}
QList<AutoPilotPlugin::FullMode_t> GenericAutoPilotPlugin::getModes(void) const
QList<AutoPilotPluginManager::FullMode_t> GenericAutoPilotPlugin::getModes(void)
{
QList<FullMode_t> modeList;
FullMode_t fullMode;
AutoPilotPluginManager::FullMode_t fullMode;
QList<AutoPilotPluginManager::FullMode_t> modeList;
fullMode.customMode = 0;
......@@ -62,7 +60,7 @@ QList<AutoPilotPlugin::FullMode_t> GenericAutoPilotPlugin::getModes(void) const
return modeList;
}
QString GenericAutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMode) const
QString GenericAutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMode)
{
Q_UNUSED(customMode);
......@@ -85,11 +83,20 @@ QString GenericAutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t cust
return mode;
}
void GenericAutoPilotPlugin::addFactsToQmlContext(QQmlContext* context, UASInterface* uas) const
void GenericAutoPilotPlugin::addFactsToQmlContext(QQmlContext* context) const
{
Q_UNUSED(context);
Q_UNUSED(uas);
// Qml not yet supported for Generic
Q_ASSERT(false);
}
QObject* GenericAutoPilotPlugin::parameterFacts(void) const
{
return NULL;
}
void GenericAutoPilotPlugin::clearStaticData(void)
{
// No Static data yet
}
......@@ -25,6 +25,7 @@
#define GENERICAUTOPILOT_H
#include "AutoPilotPlugin.h"
#include "AutoPilotPluginManager.h"
/// @file
/// @brief This is the generic implementation of the AutoPilotPlugin class for mavs
......@@ -36,13 +37,17 @@ class GenericAutoPilotPlugin : public AutoPilotPlugin
Q_OBJECT
public:
GenericAutoPilotPlugin(QObject* parent = NULL);
GenericAutoPilotPlugin(UASInterface* uas, QObject* parent = NULL);
// Overrides from AutoPilotPlugin
virtual QList<VehicleComponent*> getVehicleComponents(UASInterface* uas) const ;
virtual QList<FullMode_t> getModes(void) const;
virtual QString getShortModeText(uint8_t baseMode, uint32_t customMode) const;
virtual void addFactsToQmlContext(QQmlContext* context, UASInterface* uas) const;
virtual QList<VehicleComponent*> getVehicleComponents(void) const ;
virtual void addFactsToQmlContext(QQmlContext* context) const;
virtual QObject* parameterFacts(void) const;
virtual bool pluginIsReady(void) const { return true; }
static QList<AutoPilotPluginManager::FullMode_t> getModes(void);
static QString getShortModeText(uint8_t baseMode, uint32_t customMode);
static void clearStaticData(void);
};
#endif
......@@ -65,59 +65,59 @@ union px4_custom_mode {
float data_float;
};
PX4AutoPilotPlugin::PX4AutoPilotPlugin(QObject* parent) :
AutoPilotPlugin(parent)
PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) :
AutoPilotPlugin(parent),
_uas(uas),
_parameterFacts(NULL)
{
UASManagerInterface* uasMgr = UASManager::instance();
Q_ASSERT(uasMgr);
Q_ASSERT(uas);
_parameterFacts = new PX4ParameterFacts(uas, this);
Q_CHECK_PTR(_parameterFacts);
// We need to track uas coming and going so that we can create PX4ParameterFacts instances for each uas
connect(uasMgr, &UASManagerInterface::UASCreated, this, &PX4AutoPilotPlugin::_uasCreated);
connect(uasMgr, &UASManagerInterface::UASDeleted, this, &PX4AutoPilotPlugin::_uasDeleted);
connect(_parameterFacts, &PX4ParameterFacts::factsReady, this, &PX4AutoPilotPlugin::pluginReady);
PX4ParameterFacts::loadParameterFactMetaData();
}
PX4AutoPilotPlugin::~PX4AutoPilotPlugin()
{
delete _parameterFacts;
PX4ParameterFacts::deleteParameterFactMetaData();
foreach(UASInterface* uas, _mapUas2ParameterFacts.keys()) {
delete _mapUas2ParameterFacts[uas];
}
_mapUas2ParameterFacts.clear();
}
QList<VehicleComponent*> PX4AutoPilotPlugin::getVehicleComponents(UASInterface* uas) const
QList<VehicleComponent*> PX4AutoPilotPlugin::getVehicleComponents(void) const
{
Q_ASSERT(_uas);
QList<VehicleComponent*> components;
VehicleComponent* component;
component = new AirframeComponent(uas);
component = new AirframeComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new RadioComponent(uas);
component = new RadioComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new FlightModesComponent(uas);
component = new FlightModesComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
component = new SensorsComponent(uas);
component = new SensorsComponent(_uas);
Q_CHECK_PTR(component);
components.append(component);
return components;
}
QList<AutoPilotPlugin::FullMode_t> PX4AutoPilotPlugin::getModes(void) const
QList<AutoPilotPluginManager::FullMode_t> PX4AutoPilotPlugin::getModes(void)
{
QList<FullMode_t> modeList;
FullMode_t fullMode;
union px4_custom_mode px4_cm;
union px4_custom_mode px4_cm;
AutoPilotPluginManager::FullMode_t fullMode;
QList<AutoPilotPluginManager::FullMode_t> modeList;
px4_cm.data = 0;
px4_cm.main_mode = PX4_CUSTOM_MAIN_MODE_MANUAL;
......@@ -152,7 +152,7 @@ QList<AutoPilotPlugin::FullMode_t> PX4AutoPilotPlugin::getModes(void) const
return modeList;
}
QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMode) const
QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMode)
{
QString mode;
......@@ -187,51 +187,40 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo
mode = "|OFFBOARD";
}
} else {
mode = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(MAV_AUTOPILOT_GENERIC)->getShortModeText(baseMode, customMode);
// use base_mode - not autopilot-specific
if (baseMode == 0) {
mode = "|PREFLIGHT";
} else if (baseMode & MAV_MODE_FLAG_DECODE_POSITION_AUTO) {
mode = "|AUTO";
} else if (baseMode & MAV_MODE_FLAG_DECODE_POSITION_MANUAL) {
mode = "|MANUAL";
if (baseMode & MAV_MODE_FLAG_DECODE_POSITION_GUIDED) {
mode += "|GUIDED";
} else if (baseMode & MAV_MODE_FLAG_DECODE_POSITION_STABILIZE) {
mode += "|STABILIZED";
}
}
}
return mode;
}
void PX4AutoPilotPlugin::addFactsToQmlContext(QQmlContext* context, UASInterface* uas) const
void PX4AutoPilotPlugin::addFactsToQmlContext(QQmlContext* context) const
{
Q_ASSERT(context);
Q_ASSERT(uas);
QGCUASParamManagerInterface* paramMgr = uas->getParamManager();
Q_UNUSED(paramMgr);
Q_ASSERT(paramMgr);
Q_ASSERT(paramMgr->parametersReady());
PX4ParameterFacts* facts = _parameterFactsForUas(uas);
Q_ASSERT(facts);
Q_ASSERT(_parameterFacts->factsAreReady());
context->setContextProperty("parameterFacts", facts);
context->setContextProperty("parameterFacts", _parameterFacts);
}
/// @brief When a new uas is create we add a new set of parameter facts for it
void PX4AutoPilotPlugin::_uasCreated(UASInterface* uas)
void PX4AutoPilotPlugin::clearStaticData(void)
{
Q_ASSERT(uas);
Q_ASSERT(!_mapUas2ParameterFacts.contains(uas));
// Each uas has it's own set of parameter facts
PX4ParameterFacts* facts = new PX4ParameterFacts(uas, this);
Q_CHECK_PTR(facts);
_mapUas2ParameterFacts[uas] = facts;
PX4ParameterFacts::clearStaticData();
}
/// @brief When the uas is deleted we remove the parameter facts for it from the system
void PX4AutoPilotPlugin::_uasDeleted(UASInterface* uas)
bool PX4AutoPilotPlugin::pluginIsReady(void) const
{
delete _parameterFactsForUas(uas);
_mapUas2ParameterFacts.remove(uas);
}
PX4ParameterFacts* PX4AutoPilotPlugin::_parameterFactsForUas(UASInterface* uas) const
{
Q_ASSERT(uas);
Q_ASSERT(_mapUas2ParameterFacts.contains(uas));
return _mapUas2ParameterFacts[uas];
return _parameterFacts->factsAreReady();
}
......@@ -25,6 +25,7 @@
#define PX4AUTOPILOT_H
#include "AutoPilotPlugin.h"
#include "AutoPilotPluginManager.h"
#include "UASInterface.h"
#include "PX4ParameterFacts.h"
......@@ -37,23 +38,23 @@ class PX4AutoPilotPlugin : public AutoPilotPlugin
Q_OBJECT
public:
PX4AutoPilotPlugin(QObject* parent);
PX4AutoPilotPlugin(UASInterface* uas, QObject* parent);
~PX4AutoPilotPlugin();
// Overrides from AutoPilotPlugin
virtual QList<VehicleComponent*> getVehicleComponents(UASInterface* uas) const ;
virtual QList<FullMode_t> getModes(void) const;
virtual QString getShortModeText(uint8_t baseMode, uint32_t customMode) const;
virtual void addFactsToQmlContext(QQmlContext* context, UASInterface* uas) const;
private slots:
void _uasCreated(UASInterface* uas);
void _uasDeleted(UASInterface* uas);
virtual QList<VehicleComponent*> getVehicleComponents(void) const ;
virtual void addFactsToQmlContext(QQmlContext* context) const;
virtual QObject* parameterFacts(void) const { return _parameterFacts; }
virtual bool pluginIsReady(void) const;
static QList<AutoPilotPluginManager::FullMode_t> getModes(void);
static QString getShortModeText(uint8_t baseMode, uint32_t customMode);
static void clearStaticData(void);
private:
PX4ParameterFacts* _parameterFactsForUas(UASInterface* uas) const;
QMap<UASInterface*, PX4ParameterFacts*> _mapUas2ParameterFacts;
UASInterface* _uas;
PX4ParameterFacts* _parameterFacts;
bool _pluginReady;
};
#endif
......@@ -25,6 +25,7 @@
/// @author Don Gagne <don@thegagnes.com>
#include "PX4ParameterFacts.h"
#include "QGCApplication.h"
#include <QFile>
#include <QDebug>
......@@ -32,12 +33,14 @@
Q_LOGGING_CATEGORY(PX4ParameterFactsLog, "PX4ParameterFactsLog")
Q_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog, "PX4ParameterFactsMetaDataLog")
bool PX4ParameterFacts::_parameterMetaDataLoaded = false;
QMap<QString, FactMetaData*> PX4ParameterFacts::_mapParameterName2FactMetaData;
PX4ParameterFacts::PX4ParameterFacts(UASInterface* uas, QObject* parent) :
QObject(parent),
_lastSeenComponent(-1),
_paramMgr(NULL)
_paramMgr(NULL),
_factsReady(false)
{
Q_ASSERT(uas);
......@@ -46,11 +49,14 @@ PX4ParameterFacts::PX4ParameterFacts(UASInterface* uas, QObject* parent) :
_paramMgr = uas->getParamManager();
Q_ASSERT(_paramMgr);
// We need to be initialized before param mgr starts sending parameters so we catch each one
Q_ASSERT(!_paramMgr->parametersReady());
// We need to know when the param mgr is done sending the initial set of paramters
connect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate()));
// UASInterface::parameterChanged has multiple overrides so we need to use SIGNAL/SLOT style connect
connect(uas, SIGNAL(parameterChanged(int, int, QString, QVariant)), this, SLOT(_parameterChanged(int, int, QString, QVariant)));
// Fact meta data should already be loaded
Q_ASSERT(_mapParameterName2FactMetaData.count() != 0);
}
PX4ParameterFacts::~PX4ParameterFacts()
......@@ -90,7 +96,7 @@ void PX4ParameterFacts::_parameterChanged(int uas, int component, QString parame
// If we don't have meta data for the parameter it can't be part of the FactSystem
if (!_mapParameterName2FactMetaData.contains(parameterName)) {
// FIXME: Debug or Warning. Warning will fail TC
qCDebug(PX4ParameterFactsLog) << "FactSystem meta data out of date. Missing parameter:" << parameterName;
qDebug() << "FactSystem meta data out of date. Missing parameter:" << parameterName;
return;
}
......@@ -99,19 +105,22 @@ void PX4ParameterFacts::_parameterChanged(int uas, int component, QString parame
fact->setMetaData(_mapParameterName2FactMetaData[parameterName]);
// We need to know when the fact changes so that we can send the new value to the parameter managers
connect(fact, &Fact::valueUpdated, this, &PX4ParameterFacts::_valueUpdated);
_mapParameterName2Fact[parameterName] = fact;
_mapFact2ParameterName[fact] = parameterName;
// We need to know when the fact changes so that we can send the new value to the parameter manager
connect(fact, &Fact::_containerValueChanged, this, &PX4ParameterFacts::_valueUpdated);
//qDebug() << "Adding new fact" << parameterName;
}
_mapParameterName2Fact[parameterName]->updateValue(value);
//qDebug() << "Updating fact value" << parameterName << value;
_mapParameterName2Fact[parameterName]->_containerSetValue(value);
}
/// Connected to Fact::valueUpdated
///
/// Sets the new value into the Parameter Manager. Paramter is persisted after send.
void PX4ParameterFacts::_valueUpdated(QVariant& value)
void PX4ParameterFacts::_valueUpdated(QVariant value)
{
Fact* fact = qobject_cast<Fact*>(sender());
Q_ASSERT(fact);
......@@ -285,6 +294,11 @@ QVariant PX4ParameterFacts::_stringToTypedVariant(const QString& string, FactMet
/// The meta data comes from firmware parameters.xml file.
void PX4ParameterFacts::loadParameterFactMetaData(void)
{
if (_parameterMetaDataLoaded) {
return;
}
_parameterMetaDataLoaded = true;
qCDebug(PX4ParameterFactsMetaDataLog) << "Loading PX4 parameter fact meta data";
Q_ASSERT(_mapParameterName2FactMetaData.count() == 0);
......@@ -347,3 +361,29 @@ void PX4ParameterFacts::loadParameterFactMetaData(void)
xml.readNext();
}
}
// Called when param mgr list is up to date
void PX4ParameterFacts::_paramMgrParameterListUpToDate(void)
{
if (!_factsReady) {
_factsReady = true;
// We don't need this any more
disconnect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate()));
// There may be parameterUpdated signals still in our queue. Flush them out.
qgcApp()->processEvents();
// We should have all paramters now so we can signal ready
emit factsReady();
}
}
void PX4ParameterFacts::clearStaticData(void)
{
foreach(QString parameterName, _mapParameterName2FactMetaData.keys()) {
delete _mapParameterName2FactMetaData[parameterName];
}
_mapParameterName2FactMetaData.clear();
_parameterMetaDataLoaded = false;
}
\ No newline at end of file
......@@ -487,6 +487,7 @@ class PX4ParameterFacts : public QObject
Q_PROPERTY(Fact* UAVCAN_BITRATE READ getUAVCAN_BITRATE CONSTANT) Fact* getUAVCAN_BITRATE(void) { return _mapParameterName2Fact["UAVCAN_BITRATE"]; }
Q_PROPERTY(Fact* UAVCAN_ENABLE READ getUAVCAN_ENABLE CONSTANT) Fact* getUAVCAN_ENABLE(void) { return _mapParameterName2Fact["UAVCAN_ENABLE"]; }
Q_PROPERTY(Fact* UAVCAN_NODE_ID READ getUAVCAN_NODE_ID CONSTANT) Fact* getUAVCAN_NODE_ID(void) { return _mapParameterName2Fact["UAVCAN_NODE_ID"]; }
Q_PROPERTY(QString testString READ getTestString CONSTANT)
public:
/// @param uas Uas which this set of facts is associated with
......@@ -496,13 +497,20 @@ public:
static void loadParameterFactMetaData(void);
static void deleteParameterFactMetaData(void);
static void clearStaticData(void);
/// Returns true if the full set of facts are ready
bool factsAreReady(void) { return _factsReady; }
signals:
/// Signalled when the full set of facts are ready
void factsReady(void);
private slots:
/// Connected to UASInterface::parameterChanged
void _parameterChanged(int uas, int component, QString parameterName, QVariant value);
/// Signalled from Fact to indicate value was changed through the property write accessor
void _valueUpdated(QVariant& value);
void _valueUpdated(QVariant value);
void _paramMgrParameterListUpToDate(void);
QString getTestString(void) { return QString("foo"); }
private:
static FactMetaData* _parseParameter(QXmlStreamReader& xml, const QString& group);
......@@ -512,12 +520,15 @@ private:
QMap<QString, Fact*> _mapParameterName2Fact; ///< Maps from a parameter name to a Fact
QMap<Fact*, QString> _mapFact2ParameterName; ///< Maps from a Fact to a parameter name
static bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded
static QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData
int _uasId; ///< Id for uas which this set of Facts are associated with
int _lastSeenComponent;
QGCUASParamManagerInterface* _paramMgr;
bool _factsReady; ///< All facts received from param mgr
};
#endif
\ No newline at end of file
......@@ -93,7 +93,6 @@ void FlightModeConfigTest::init(void)
_configWidget = new FlightModeConfig;
Q_CHECK_PTR(_configWidget);
_configWidget->setVisible(true);
// Setup combo maps
......
......@@ -34,14 +34,15 @@ Fact::Fact(QObject* parent) :
}
void Fact::setValue(QVariant& value)
void Fact::setValue(const QVariant& value)
{
_value = value;
emit valueUpdated(value);
emit valueChanged(_value);
emit _containerValueChanged(_value);
}
void Fact::updateValue(QVariant& value)
void Fact::_containerSetValue(const QVariant& value)
{
_value = value;
emit valueChanged(value);
emit valueChanged(_value);
}
......@@ -62,7 +62,7 @@ public:
QVariant value(void) const { return _value; }
/// Write accessor for value property
void setValue(QVariant& value);
void setValue(const QVariant& value);
/// Read accesor for defaultValue property
QVariant defaultValue(void) { return _metaData->defaultValue; }
......@@ -85,24 +85,21 @@ public:
/// Read accesor for max property
QVariant max(void) { return _metaData->max; }
/// Used to update the value property from C++ code.
///
/// The setValue method is only for use by the QObject Property system. It should not be called directly by C++ app code.
void updateValue(QVariant& value);
/// Sets the meta data associated with the Fact.
void setMetaData(FactMetaData* metaData) { _metaData = metaData; }
void _containerSetValue(const QVariant& value);
signals:
/// QObject Property System signal for value property changes
///
/// This signal is only meant for use by the QT property system. It should not be connected to by client code.
void valueChanged(QVariant& value);
void valueChanged(QVariant value);
/// Signalled when property has been changed by a call to the property write accessor
///
/// This signal is meant for use by client code.
void valueUpdated(QVariant& value);
/// This signal is meant for use by Fact container implementations.
void _containerValueChanged(QVariant& value);
private:
QVariant _value; ///< Fact value
......
......@@ -50,7 +50,6 @@ class FactSystem : public QGCSingleton
private:
/// All access to FactSystem is through FactSystem::instance, so constructor is private
FactSystem(QObject* parent = NULL);
~FactSystem();
static const char* _factSystemQmlUri; ///< URI for FactSystem QML imports
......
/*=====================================================================
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 "FactSystemTest.h"
#include "LinkManager.h"
#include "MockLink.h"
#include "AutoPilotPluginManager.h"
#include "UASManager.h"
#include "QGCApplication.h"
#include "QGCQuickWidget.h"
#include <QQuickItem>
UT_REGISTER_TEST(FactSystemTest)
/// FactSystem Unit Test
FactSystemTest::FactSystemTest(void)
{
}
void FactSystemTest::init(void)
{
UnitTest::init();
LinkManager* _linkMgr = LinkManager::instance();
MockLink* link = new MockLink();
_linkMgr->addLink(link);
_linkMgr->connectLink(link);
// Wait for the uas to work it's way through the various threads
QSignalSpy spyUas(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)));
QCOMPARE(spyUas.wait(5000), true);
_uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(_uas);
_paramMgr = _uas->getParamManager();
Q_ASSERT(_paramMgr);
// Get the plugin for the uas
AutoPilotPluginManager* pluginMgr = AutoPilotPluginManager::instance();
Q_ASSERT(pluginMgr);
_plugin = pluginMgr->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(_plugin);
// Wait for the plugin to be ready
QSignalSpy spyPlugin(_plugin, SIGNAL(pluginReady()));
if (!_plugin->pluginIsReady()) {
QCOMPARE(spyPlugin.wait(5000), true);
}
Q_ASSERT(_plugin->pluginIsReady());
}
void FactSystemTest::cleanup(void)
{
UnitTest::cleanup();
}
/// Basic test of parameter values in Fact System
void FactSystemTest::_parameter_test(void)
{
// Get the parameter facts from the AutoPilot
AutoPilotPluginManager* pluginMgr = AutoPilotPluginManager::instance();
Q_ASSERT(pluginMgr);
AutoPilotPlugin* plugin = pluginMgr->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(plugin);
QObject* parameterFacts = plugin->parameterFacts();
QVERIFY(parameterFacts != NULL);
// Compare the value in the Parameter Manager with the value from the FactSystem
QVariant factVariant = parameterFacts->property("RC_MAP_THROTTLE");
Fact* fact = factVariant.value<Fact*>();
QVERIFY(fact != NULL);
QVariant factValue = fact->value();
QCOMPARE(factValue.isValid(), true);
QVariant paramValue;
Q_ASSERT(_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "RC_MAP_THROTTLE", paramValue));
QCOMPARE(factValue.toInt(), paramValue.toInt());
}
/// Test that QML can reference a Fact
void FactSystemTest::_qml_test(void)
{
QGCQuickWidget* widget = new QGCQuickWidget;
widget->setSource(QUrl::fromUserInput("qrc:unittest/FactSystemTest.qml"));
QQuickItem* rootObject = widget->rootObject();
QObject* control = rootObject->findChild<QObject*>("testControl");
QVERIFY(control != NULL);
QVariant qmlValue = control->property("text").toInt();
QVariant paramMgrValue;
Q_ASSERT(_paramMgr->getParameterValue(_paramMgr->getDefaultComponentId(), "RC_MAP_THROTTLE", paramMgrValue));
QCOMPARE(qmlValue.toInt(), paramMgrValue.toInt());
}
// Test correct behavior when the Param Manager gets a parameter update
void FactSystemTest::_paramMgrSignal_test(void)
{
// Get the parameter Fact from the AutoPilot
AutoPilotPluginManager* pluginMgr = AutoPilotPluginManager::instance();
Q_ASSERT(pluginMgr);
AutoPilotPlugin* plugin = pluginMgr->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(plugin);
QObject* parameterFacts = plugin->parameterFacts();
QVERIFY(parameterFacts != NULL);
QVariant factVariant = parameterFacts->property("RC_MAP_THROTTLE");
Fact* fact = factVariant.value<Fact*>();
QVERIFY(fact != NULL);
// Setting a new value into the parameter should trigger a valueChanged signal on the Fact
QSignalSpy spyFact(fact, SIGNAL(valueChanged(QVariant)));
QVariant paramValue = 12;
_paramMgr->setParameter(_paramMgr->getDefaultComponentId(), "RC_MAP_THROTTLE", paramValue);
_paramMgr->sendPendingParameters(true, false);
// Wait for the Fact::valueChanged signal to come through
QCOMPARE(spyFact.wait(5000), true);
// Make sure the signal has the right value
QList<QVariant> arguments = spyFact.takeFirst();
qDebug() << arguments.at(0).type();
QCOMPARE(arguments.at(0).toInt(), 12);
// Make sure the Fact has the new value
QCOMPARE(fact->value().toInt(), 12);
}
/// Test QML getting an updated Fact value
void FactSystemTest::_qmlUpdate_test(void)
{
QGCQuickWidget* widget = new QGCQuickWidget;
widget->setSource(QUrl::fromUserInput("qrc:unittest/FactSystemTest.qml"));
// Change the value using param manager
QVariant paramValue = 12;
_paramMgr->setParameter(_paramMgr->getDefaultComponentId(), "RC_MAP_THROTTLE", paramValue);
_paramMgr->sendPendingParameters(true, false);
QTest::qWait(500); // Let the signals flow through
// Make sure the qml has the right value
QQuickItem* rootObject = widget->rootObject();
QObject* control = rootObject->findChild<QObject*>("testControl");
QVERIFY(control != NULL);
QCOMPARE(control->property("text").toInt(), 12);
}
/*=====================================================================
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>
#ifndef FactSystemTest_H
#define FactSystemTest_H
#include "UnitTest.h"
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
// Unit Test for Fact System
class FactSystemTest : public UnitTest
{
Q_OBJECT
public:
FactSystemTest(void);
private slots:
void init(void);
void cleanup(void);
void _parameter_test(void);
void _qml_test(void);
void _paramMgrSignal_test(void);
void _qmlUpdate_test(void);
private:
UASInterface* _uas;
QGCUASParamManagerInterface* _paramMgr;
AutoPilotPlugin* _plugin;
LinkManager* _linkMgr;
};
#endif
import QtQuick 2.2
import QtQuick.Controls 1.2
import QGroundControl.FactSystem 1.0
import QGroundControlFactControls 1.0
Item {
TextInput {
objectName: "testControl"
text: parameterFacts.RC_MAP_THROTTLE.value
font.family: "Helvetica"
font.pointSize: 24
color: "red"
focus: true
onAccepted: { parameterFacts.RC_MAP_THROTTLE.value = text; }
}
}
\ No newline at end of file
......@@ -32,37 +32,22 @@ This file is part of the QGROUNDCONTROL project
#include <QApplication>
#include <QSettings>
#include "GAudioOutput.h"
#include <QDebug>
#include <QGC.h>
/**
* This class follows the singleton design pattern
* @see http://en.wikipedia.org/wiki/Singleton_pattern
* A call to this function thus returns the only instance of this object
* the call can occur at any place in the code, no reference to the
* GAudioOutput object has to be passed.
*/
GAudioOutput *GAudioOutput::instance()
{
static GAudioOutput *_instance = 0;
if (_instance == 0)
{
_instance = new GAudioOutput();
// Set the application as parent to ensure that this object
// will be destroyed when the main application exits
_instance->setParent(qApp);
}
#include "GAudioOutput.h"
#include "QGCApplication.h"
#include "QGC.h"
return _instance;
}
IMPLEMENT_QGC_SINGLETON(GAudioOutput, GAudioOutput)
GAudioOutput::GAudioOutput(QObject *parent) : QObject(parent),
GAudioOutput::GAudioOutput(QObject *parent) :
QGCSingleton(parent),
muted(false),
thread(new QThread()),
worker(new QGCAudioWorker())
{
muted = qgcApp()->runningUnitTests();
worker->moveToThread(thread);
connect(this, SIGNAL(textToSpeak(QString,int)), worker, SLOT(say(QString,int)));
connect(this, SIGNAL(beepOnce()), worker, SLOT(beep()));
......@@ -72,9 +57,8 @@ GAudioOutput::GAudioOutput(QObject *parent) : QObject(parent),
GAudioOutput::~GAudioOutput()
{
thread->quit();
while (thread->isRunning()) {
QGC::SLEEP::usleep(100);
}
thread->wait();
delete worker;
delete thread;
}
......@@ -82,19 +66,19 @@ GAudioOutput::~GAudioOutput()
void GAudioOutput::mute(bool mute)
{
// XXX handle muting
Q_UNUSED(mute);
muted = mute;
}
bool GAudioOutput::isMuted()
{
// XXX return right stuff
return false;
return muted;
}
bool GAudioOutput::say(QString text, int severity)
{
emit textToSpeak(text, severity);
if (!muted) {
emit textToSpeak(text, severity);
}
return true;
}
......@@ -103,7 +87,9 @@ bool GAudioOutput::say(QString text, int severity)
*/
bool GAudioOutput::alert(QString text)
{
emit textToSpeak(text, 1);
if (!muted) {
emit textToSpeak(text, 1);
}
return true;
}
......@@ -172,5 +158,7 @@ bool GAudioOutput::stopEmergency()
void GAudioOutput::beep()
{
emit beepOnce();
if (!muted) {
emit beepOnce();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment