Commit 3520241e authored by Don Gagne's avatar Don Gagne

Merge pull request #1537 from DonLakeFlyer/MissingFacts

Much better handling of missing parameters
parents 3f179737 87c06bed
......@@ -625,7 +625,8 @@ SOURCES += \
# Fact System code
INCLUDEPATH += \
src/FactSystem
src/FactSystem \
src/FactSystem/FactControls \
HEADERS += \
src/FactSystem/Fact.h \
......@@ -634,6 +635,7 @@ HEADERS += \
src/FactSystem/FactSystem.h \
src/FactSystem/FactValidator.h \
src/FactSystem/ParameterLoader.h \
src/FactSystem/FactControls/FactPanelController.h \
SOURCES += \
src/FactSystem/Fact.cc \
......@@ -642,6 +644,7 @@ SOURCES += \
src/FactSystem/FactSystem.cc \
src/FactSystem/FactValidator.cc \
src/FactSystem/ParameterLoader.cc \
src/FactSystem/FactControls/FactPanelController.cc \
# Android
......
......@@ -9,6 +9,7 @@
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</file>
<file alias="QGroundControl/FactControls/FactPanel.qml">src/FactSystem/FactControls/FactPanel.qml</file>
<file alias="QGroundControl/FactControls/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.qml</file>
<file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
......
......@@ -31,125 +31,132 @@ import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0
Rectangle {
AirframeComponentController { id: controller }
QGCPalette { id: qgcPal; colorGroupEnabled: true }
FactPanel {
id: panel
color: qgcPal.window
AirframeComponentController { id: controller; factPanel: panel }
Column {
Rectangle {
anchors.fill: parent
QGCLabel {
text: "AIRFRAME CONFIG"
font.pointSize: 20
}
QGCPalette { id: qgcPal; colorGroupEnabled: true }
Item { height: 20; width: 10 } // spacer
color: qgcPal.window
Row {
width: parent.width
Column {
anchors.fill: parent
QGCLabel {
width: parent.width - applyButton.width
text: "Select you airframe type and specific vehicle bellow. Click 'Apply and Restart' when ready and your vehicle will be disconnected, rebooted to the new settings and re-connected."
wrapMode: Text.WordWrap
text: "AIRFRAME CONFIG"
font.pointSize: 20
}
QGCButton {
id: applyButton
text: "Apply and Restart"
onClicked: { controller.changeAutostart() }
}
}
Item { height: 20; width: 10 } // spacer
Item { height: 20; width: 10 } // spacer
Row {
width: parent.width
Flow {
width: parent.width
spacing: 10
QGCLabel {
width: parent.width - applyButton.width
text: "Select you airframe type and specific vehicle bellow. Click 'Apply and Restart' when ready and your vehicle will be disconnected, rebooted to the new settings and re-connected."
wrapMode: Text.WordWrap
}
ExclusiveGroup {
id: airframeTypeExclusive
QGCButton {
id: applyButton
text: "Apply and Restart"
onClicked: { controller.changeAutostart() }
}
}
Repeater {
model: controller.airframeTypes
Item { height: 20; width: 10 } // spacer
// Outer summary item rectangle
Rectangle {
readonly property real titleHeight: 30
readonly property real innerMargin: 10
Flow {
width: parent.width
spacing: 10
width: 250
height: 200
color: qgcPal.windowShade
ExclusiveGroup {
id: airframeTypeExclusive
}
Repeater {
model: controller.airframeTypes
// Outer summary item rectangle
Rectangle {
id: title
width: parent.width
height: parent.titleHeight
color: qgcPal.windowShadeDark
readonly property real titleHeight: 30
readonly property real innerMargin: 10
Text {
anchors.fill: parent
width: 250
height: 200
color: qgcPal.windowShade
color: qgcPal.buttonText
font.pixelSize: 12
text: modelData.name
Rectangle {
id: title
width: parent.width
height: parent.titleHeight
color: qgcPal.windowShadeDark
verticalAlignment: TextEdit.AlignVCenter
horizontalAlignment: TextEdit.AlignHCenter
}
}
Text {
anchors.fill: parent
Image {
id: image
x: innerMargin
width: parent.width - (innerMargin * 2)
height: parent.height - title.height - combo.height - (innerMargin * 3)
anchors.topMargin: innerMargin
anchors.top: title.bottom
color: qgcPal.buttonText
font.pixelSize: 12
text: modelData.name
source: modelData.imageResource
fillMode: Image.PreserveAspectFit
smooth: true
verticalAlignment: TextEdit.AlignVCenter
horizontalAlignment: TextEdit.AlignHCenter
}
}
}
Image {
id: image
x: innerMargin
width: parent.width - (innerMargin * 2)
height: parent.height - title.height - combo.height - (innerMargin * 3)
anchors.topMargin: innerMargin
anchors.top: title.bottom
source: modelData.imageResource
fillMode: Image.PreserveAspectFit
smooth: true
QGCCheckBox {
id: airframeCheckBox
anchors.bottom: image.bottom
anchors.right: image.right
checked: modelData.name == controller.currentAirframeType
exclusiveGroup: airframeTypeExclusive
}
onCheckedChanged: {
if (checked && combo.currentIndex != -1) {
controller.autostartId = modelData.airframes[combo.currentIndex].autostartId
QGCCheckBox {
id: airframeCheckBox
anchors.bottom: image.bottom
anchors.right: image.right
checked: modelData.name == controller.currentAirframeType
exclusiveGroup: airframeTypeExclusive
onCheckedChanged: {
if (checked && combo.currentIndex != -1) {
controller.autostartId = modelData.airframes[combo.currentIndex].autostartId
}
}
}
}
QGCComboBox {
id: combo
objectName: modelData.airframeType + "ComboBox"
x: innerMargin
anchors.topMargin: innerMargin
anchors.top: image.bottom
width: parent.width - (innerMargin * 2)
model: modelData.airframes
currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0
onCurrentIndexChanged: {
if (airframeCheckBox.checked) {
controller.autostartId = modelData.airframes[currentIndex].autostartId
QGCComboBox {
id: combo
objectName: modelData.airframeType + "ComboBox"
x: innerMargin
anchors.topMargin: innerMargin
anchors.top: image.bottom
width: parent.width - (innerMargin * 2)
model: modelData.airframes
currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0
onCurrentIndexChanged: {
if (airframeCheckBox.checked) {
controller.autostartId = modelData.airframes[currentIndex].autostartId
}
}
}
}
}
}
}
}
}
}
}
\ No newline at end of file
......@@ -37,19 +37,13 @@
bool AirframeComponentController::_typesRegistered = false;
AirframeComponentController::AirframeComponentController(QObject* parent) :
QObject(parent),
AirframeComponentController::AirframeComponentController(void) :
_uas(NULL),
_autoPilotPlugin(NULL),
_currentVehicleIndex(0),
_autostartId(0)
{
_uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(_uas);
_autoPilotPlugin = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(_autoPilotPlugin);
Q_ASSERT(_autoPilotPlugin->pluginReady());
if (!_typesRegistered) {
_typesRegistered = true;
......@@ -57,10 +51,16 @@ AirframeComponentController::AirframeComponentController(QObject* parent) :
qmlRegisterUncreatableType<Airframe>("QGroundControl.Controllers", 1, 0, "Aiframe", "Can only reference Airframe");
}
QStringList usedFacts;
usedFacts << "SYS_AUTOSTART" << "SYS_AUTOCONFIG";
if (!_allFactsExists(usedFacts)) {
return;
}
// Load up member variables
bool autostartFound = false;
_autostartId = _autoPilotPlugin->getParameterFact("SYS_AUTOSTART")->value().toInt();
_autostartId = _autopilot->getParameterFact("SYS_AUTOSTART")->value().toInt();
for (const AirframeComponentAirframes::AirframeType_t* pType=&AirframeComponentAirframes::rgAirframeTypes[0]; pType->name != NULL; pType++) {
AirframeType* airframeType = new AirframeType(pType->name, pType->imageResource, this);
......@@ -81,7 +81,7 @@ AirframeComponentController::AirframeComponentController(QObject* parent) :
_airframeTypes.append(QVariant::fromValue(airframeType));
}
if (_autostartId != 0) {
// FIXME: Should be a user error
Q_UNUSED(autostartFound);
......@@ -101,8 +101,8 @@ void AirframeComponentController::changeAutostart(void)
return;
}
_autoPilotPlugin->getParameterFact("SYS_AUTOSTART")->setValue(_autostartId);
_autoPilotPlugin->getParameterFact("SYS_AUTOCONFIG")->setValue(1);
_autopilot->getParameterFact("SYS_AUTOSTART")->setValue(_autostartId);
_autopilot->getParameterFact("SYS_AUTOCONFIG")->setValue(1);
qgcApp()->setOverrideCursor(Qt::WaitCursor);
......
......@@ -33,14 +33,15 @@
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
#include "FactPanelController.h"
/// MVC Controller for AirframeComponent.qml.
class AirframeComponentController : public QObject
class AirframeComponentController : public FactPanelController
{
Q_OBJECT
public:
AirframeComponentController(QObject* parent = NULL);
AirframeComponentController(void);
~AirframeComponentController();
Q_PROPERTY(QVariantList airframeTypes MEMBER _airframeTypes CONSTANT)
......@@ -63,7 +64,6 @@ private:
static bool _typesRegistered;
UASInterface* _uas;
AutoPilotPlugin* _autoPilotPlugin;
QVariantList _airframeTypes;
QString _currentAirframeType;
QString _currentVehicleName;
......
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0
Column {
Fact { id: sysIdFact; name: "MAV_SYS_ID" }
Fact { id: sysAutoStartFact; name: "SYS_AUTOSTART" }
FactPanel {
id: panel
anchors.fill: parent
property bool autoStartSet: sysAutoStartFact.value != 0
AirframeComponentController { id: controller; factPanel: panel }
anchors.fill: parent
anchors.margins: 8
Fact { id: sysIdFact; name: "MAV_SYS_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: sysAutoStartFact; name: "SYS_AUTOSTART"; onFactMissing: showMissingFactOverlay(name) }
AirframeComponentController { id: controller }
property bool autoStartSet: sysAutoStartFact.value != 0
VehicleSummaryRow {
labelText: "System ID:"
valueText: sysIdFact.valueString
}
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Airframe type:"
valueText: autoStartSet ? controller.currentAirframeType : "Setup required"
}
VehicleSummaryRow {
labelText: "System ID:"
valueText: sysIdFact.valueString
}
VehicleSummaryRow {
labelText: "Airframe type:"
valueText: autoStartSet ? controller.currentAirframeType : "Setup required"
}
VehicleSummaryRow {
labelText: "Vehicle:"
valueText: autoStartSet ? controller.currentVehicleName : "Setup required"
VehicleSummaryRow {
labelText: "Vehicle:"
valueText: autoStartSet ? controller.currentVehicleName : "Setup required"
}
}
}
}
\ No newline at end of file
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
Fact { id: modeSwFact; name: "RC_MAP_MODE_SW" }
Fact { id: posCtlSwFact; name: "RC_MAP_POSCTL_SW" }
Fact { id: loiterSwFact; name: "RC_MAP_LOITER_SW" }
Fact { id: returnSwFact; name: "RC_MAP_RETURN_SW" }
FactPanel {
anchors.fill: parent
anchors.fill: parent
anchors.margins: 8
Fact { id: modeSwFact; name: "RC_MAP_MODE_SW"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: posCtlSwFact; name: "RC_MAP_POSCTL_SW"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: loiterSwFact; name: "RC_MAP_LOITER_SW"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: returnSwFact; name: "RC_MAP_RETURN_SW"; onFactMissing: showMissingFactOverlay(name) }
VehicleSummaryRow {
labelText: "Mode switch:"
valueText: modeSwFact.value == 0 ? "Setup required" : modeSwFact.valueString
}
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Position Ctl switch:"
valueText: posCtlSwFact.value == 0 ? "Disabled" : posCtlSwFact.valueString
}
VehicleSummaryRow {
labelText: "Mode switch:"
valueText: modeSwFact.value == 0 ? "Setup required" : modeSwFact.valueString
}
VehicleSummaryRow {
labelText: "Loiter switch:"
valueText: loiterSwFact.value == 0 ? "Disabled" : loiterSwFact.valueString
}
VehicleSummaryRow {
labelText: "Position Ctl switch:"
valueText: posCtlSwFact.value == 0 ? "Disabled" : posCtlSwFact.valueString
}
VehicleSummaryRow {
labelText: "Loiter switch:"
valueText: loiterSwFact.value == 0 ? "Disabled" : loiterSwFact.valueString
}
VehicleSummaryRow {
labelText: "Return switch:"
valueText: returnSwFact.value == 0 ? "Disabled" : returnSwFact.valueString
VehicleSummaryRow {
labelText: "Return switch:"
valueText: returnSwFact.value == 0 ? "Disabled" : returnSwFact.valueString
}
}
}
......@@ -27,32 +27,35 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
Fact { id: batVChargedFact; name: "BAT_V_CHARGED" }
Fact { id: batVEmptyFact; name: "BAT_V_EMPTY" }
Fact { id: batCellsFact; name: "BAT_N_CELLS" }
FactPanel {
anchors.fill: parent
anchors.fill: parent
anchors.margins: 8
Fact { id: batVChargedFact; name: "BAT_V_CHARGED"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: batVEmptyFact; name: "BAT_V_EMPTY"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: batCellsFact; name: "BAT_N_CELLS"; onFactMissing: showMissingFactOverlay(name) }
VehicleSummaryRow {
labelText: "Battery Full:"
valueText: batVChargedFact.valueString
}
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Battery Empty:"
valueText: batVEmptyFact.valueString
}
VehicleSummaryRow {
labelText: "Battery Full:"
valueText: batVChargedFact.valueString
}
VehicleSummaryRow {
labelText: "Battery Empty:"
valueText: batVEmptyFact.valueString
}
VehicleSummaryRow {
labelText: "Number of Cells:"
valueText: batCellsFact.valueString
VehicleSummaryRow {
labelText: "Number of Cells:"
valueText: batCellsFact.valueString
}
}
}
}
\ No newline at end of file
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
Fact { id: mapRollFact; name: "RC_MAP_ROLL" }
Fact { id: mapPitchFact; name: "RC_MAP_PITCH" }
Fact { id: mapYawFact; name: "RC_MAP_YAW" }
Fact { id: mapThrottleFact; name: "RC_MAP_THROTTLE" }
Fact { id: mapFlapsFact; name: "RC_MAP_FLAPS" }
Fact { id: mapAux1Fact; name: "RC_MAP_AUX1" }
Fact { id: mapAux2Fact; name: "RC_MAP_AUX2" }
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Roll:"
valueText: mapRollFact.value == 0 ? "Setup required" : mapRollFact.valueString
}
VehicleSummaryRow {
labelText: "Pitch:"
valueText: mapPitchFact.value == 0 ? "Setup required" : mapPitchFact.valueString
}
VehicleSummaryRow {
labelText: "Yaw:"
valueText: mapYawFact.value == 0 ? "Setup required" : mapYawFact.valueString
}
VehicleSummaryRow {
labelText: "Throttle:"
valueText: mapThrottleFact.value == 0 ? "Setup required" : mapThrottleFact.valueString
}
VehicleSummaryRow {
labelText: "Flaps:"
valueText: mapFlapsFact.value == 0 ? "Disabled" : mapFlapsFact.valueString
}
VehicleSummaryRow {
labelText: "Aux1:"
valueText: mapAux1Fact.value == 0 ? "Disabled" : mapAux1Fact.valueString
}
VehicleSummaryRow {
labelText: "Aux2:"
valueText: mapAux2Fact.value == 0 ? "Disabled" : mapAux2Fact.valueString
FactPanel {
anchors.fill: parent
Fact { id: mapRollFact; name: "RC_MAP_ROLL"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapPitchFact; name: "RC_MAP_PITCH"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapYawFact; name: "RC_MAP_YAW"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapThrottleFact; name: "RC_MAP_THROTTLE"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapFlapsFact; name: "RC_MAP_FLAPS"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapAux1Fact; name: "RC_MAP_AUX1"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapAux2Fact; name: "RC_MAP_AUX2"; onFactMissing: showMissingFactOverlay(name) }
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Roll:"
valueText: mapRollFact.value == 0 ? "Setup required" : mapRollFact.valueString
}
VehicleSummaryRow {
labelText: "Pitch:"
valueText: mapPitchFact.value == 0 ? "Setup required" : mapPitchFact.valueString
}
VehicleSummaryRow {
labelText: "Yaw:"
valueText: mapYawFact.value == 0 ? "Setup required" : mapYawFact.valueString
}
VehicleSummaryRow {
labelText: "Throttle:"
valueText: mapThrottleFact.value == 0 ? "Setup required" : mapThrottleFact.valueString
}
VehicleSummaryRow {
labelText: "Flaps:"
valueText: mapFlapsFact.value == 0 ? "Disabled" : mapFlapsFact.valueString
}
VehicleSummaryRow {
labelText: "Aux1:"
valueText: mapAux1Fact.value == 0 ? "Disabled" : mapAux1Fact.valueString
}
VehicleSummaryRow {
labelText: "Aux2:"
valueText: mapAux2Fact.value == 0 ? "Disabled" : mapAux2Fact.valueString
}
}
}
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
Column {
Fact { id: returnAltFact; name: "RTL_RETURN_ALT" }
Fact { id: descendAltFact; name: "RTL_DESCEND_ALT" }
Fact { id: landDelayFact; name: "RTL_LAND_DELAY" }
Fact { id: commDLLossFact; name: "COM_DL_LOSS_EN" }
Fact { id: commRCLossFact; name: "COM_RC_LOSS_T" }
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "RTL min alt:"
valueText: returnAltFact.valueString
}
VehicleSummaryRow {
labelText: "RTL home alt:"
valueText: descendAltFact.valueString
}
VehicleSummaryRow {
labelText: "RTL loiter delay:"
valueText: landDelayFact.value < 0 ? "Disabled" : landDelayFact.valueString
}
VehicleSummaryRow {
labelText: "Telemetry loss RTL:"
valueText: commDLLossFact.value != -1 ? "Disabled" : commDLLossFact.valueString
}
VehicleSummaryRow {
labelText: "RC loss RTL (seconds):"
valueText: commRCLossFact.valueString
FactPanel {
anchors.fill: parent
Fact { id: returnAltFact; name: "RTL_RETURN_ALT"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: descendAltFact; name: "RTL_DESCEND_ALT"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: landDelayFact; name: "RTL_LAND_DELAY"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: commDLLossFact; name: "COM_DL_LOSS_EN"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: commRCLossFact; name: "COM_RC_LOSS_T"; onFactMissing: showMissingFactOverlay(name) }
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "RTL min alt:"
valueText: returnAltFact.valueString
}
VehicleSummaryRow {
labelText: "RTL home alt:"
valueText: descendAltFact.valueString
}
VehicleSummaryRow {
labelText: "RTL loiter delay:"
valueText: landDelayFact.value < 0 ? "Disabled" : landDelayFact.valueString
}
VehicleSummaryRow {
labelText: "Telemetry loss RTL:"
valueText: commDLLossFact.value != -1 ? "Disabled" : commDLLossFact.valueString
}
VehicleSummaryRow {
labelText: "RC loss RTL (seconds):"
valueText: commRCLossFact.valueString
}
}
}
......@@ -3,32 +3,37 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
/*
IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml
*/
Column {
Fact { id: mag0IdFact; name: "CAL_MAG0_ID" }
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID" }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID" }
FactPanel {
anchors.fill: parent
anchors.fill: parent
anchors.margins: 8
Fact { id: mag0IdFact; name: "CAL_MAG0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID"; onFactMissing: showMissingFactOverlay(name) }
VehicleSummaryRow {
labelText: "Compass:"
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
}
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Gyro:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Compass:"
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Gyro:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Accelerometer:"
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
VehicleSummaryRow {
labelText: "Accelerometer:"
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
}
}
}
}
\ No newline at end of file
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0
/*
IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml
*/
Column {
Fact { id: mag0IdFact; name: "CAL_MAG0_ID" }
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID" }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID" }
Fact { id: dPressOffFact; name: "SENS_DPRES_OFF" }
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Compass:"
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Gyro:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Accelerometer:"
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Airspeed:"
valueText: dPressOffFact.value == 0 ? "Setup required" : "Ready"
FactPanel {
anchors.fill: parent
Fact { id: mag0IdFact; name: "CAL_MAG0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: dPressOffFact; name: "SENS_DPRES_OFF"; onFactMissing: showMissingFactOverlay(name) }
Column {
anchors.fill: parent
anchors.margins: 8
VehicleSummaryRow {
labelText: "Compass:"
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Gyro:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Accelerometer:"
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow {
labelText: "Airspeed:"
valueText: dPressOffFact.value == 0 ? "Setup required" : "Ready"
}
}
}
......@@ -35,16 +35,11 @@
#include <QDebug>
/// @brief A Fact is used to hold a single value within the system.
///
/// Along with the value property is a set of meta data which further describes the Fact. This information is
/// exposed through QObject Properties such that you can bind to it from QML as well as use it within C++ code.
/// Since the meta data is common to all instances of the same Fact, it is acually stored once in a seperate object.
class Fact : public QObject
{
Q_OBJECT
public:
//Fact(int componentId, QString name = "", FactMetaData::ValueType_t type = FactMetaData::valueTypeInt32, QObject* parent = NULL);
Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent = NULL);
// Property system methods
......
......@@ -34,7 +34,8 @@
FactBinder::FactBinder(void) :
_autopilotPlugin(NULL),
_fact(NULL),
_componentId(FactSystem::defaultComponentId)
_componentId(FactSystem::defaultComponentId),
_factMissingSignalConnected(false)
{
UASInterface* uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(uas);
......@@ -85,8 +86,12 @@ void FactBinder::setName(const QString& name)
emit nameChanged();
emit metaDataChanged();
} else {
QString panicMessage("Required parameter (component id: %1, name: %2), is missing from vehicle. QGroundControl cannot operate with this firmware revision. QGroundControl will now shut down.");
qgcApp()->panicShutdown(panicMessage.arg(_componentId).arg(parsedName));
qgcApp()->reportMissingFact(name);
if (_factMissingSignalConnected) {
emit factMissing(name);
} else {
_missedFactMissingSignals << name;
}
}
}
}
......@@ -208,3 +213,27 @@ bool FactBinder::valueEqualsDefault(void)
return false;
}
}
void FactBinder::connectNotify(const QMetaMethod & signal)
{
if (signal == QMetaMethod::fromSignal(&FactBinder::factMissing)) {
_factMissingSignalConnected = true;
if (_missedFactMissingSignals.count()) {
QTimer::singleShot(10, this, &FactBinder::_delayedFactMissing);
}
}
}
void FactBinder::disconnectNotify(const QMetaMethod & signal)
{
if (signal == QMetaMethod::fromSignal(&FactBinder::factMissing)) {
_factMissingSignalConnected = false;
}
}
void FactBinder::_delayedFactMissing(void)
{
foreach (QString name, _missedFactMissingSignals) {
emit factMissing(name);
}
}
\ No newline at end of file
......@@ -78,14 +78,24 @@ public:
QString group(void);
signals:
void factMissing(const QString& name);
void nameChanged(void);
void valueChanged(void);
void metaDataChanged(void);
private slots:
void _delayedFactMissing(void);
private:
// Overrides from QObject
void connectNotify(const QMetaMethod & signal);
void disconnectNotify(const QMetaMethod & signal);
AutoPilotPlugin* _autopilotPlugin;
Fact* _fact;
int _componentId;
bool _factMissingSignalConnected;
QStringList _missedFactMissingSignals;
};
#endif
\ No newline at end of file
/*=====================================================================
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/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
import QtQuick 2.3
import QtQuick.Controls 1.3
import QGroundControl.FactSystem 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
Item {
property string __missingFacts: ""
function showMissingFactOverlay(missingFactName) {
if (__missingFacts.length != 0) {
__missingFacts = __missingFacts.concat(", ")
}
__missingFacts = __missingFacts.concat(missingFactName)
__missingFactOverlay.visible = true
}
Rectangle {
QGCPalette { id: __qgcPal; colorGroupEnabled: true }
id: __missingFactOverlay
anchors.fill: parent
z: 9999
visible: false
color: __qgcPal.window
opacity: 0.85
QGCLabel {
anchors.fill: parent
wrapMode: Text.WordWrap
text: "Fact(s) missing: " + __missingFacts
}
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "FactPanelController.h"
#include "UASManager.h"
#include "AutoPilotPluginManager.h"
#include "QGCMessageBox.h"
/// @file
/// @author Don Gagne <don@thegagnes.com>
FactPanelController::FactPanelController(void) :
_autopilot(NULL),
_factPanel(NULL)
{
UASInterface* uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(uas);
_autopilot = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(uas);
Q_ASSERT(_autopilot);
Q_ASSERT(_autopilot->pluginReady());
// Do a delayed check for the _factPanel finally being set correctly from Qml
QTimer::singleShot(1000, this, &FactPanelController::_checkForMissingFactPanel);
}
QQuickItem* FactPanelController::factPanel(void)
{
return _factPanel;
}
void FactPanelController::setFactPanel(QQuickItem* panel)
{
// Once we finally have the _factPanel member set send any
// missing fact notices that were waiting to go out
_factPanel = panel;
foreach (QString missingFact, _delayedMissingFacts) {
_notifyPanelMissingFact(missingFact);
}
_delayedMissingFacts.clear();
}
void FactPanelController::_notifyPanelMissingFact(const QString& missingFact)
{
QVariant returnedValue;
QMetaObject::invokeMethod(_factPanel,
"showMissingFactOverlay",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, missingFact));
}
void FactPanelController::_reportMissingFact(const QString& missingFact)
{
qgcApp()->reportMissingFact(missingFact);
// If missing facts a reported from the constructor of a derived class we
// will not have access to _factPanel yet. Just record list of missing facts
// in that case instead of notify. Once _factPanel is available they will be
// send out for real.
if (_factPanel) {
_notifyPanelMissingFact(missingFact);
} else {
_delayedMissingFacts += missingFact;
}
}
bool FactPanelController::_allFactsExists(QStringList factList)
{
bool noMissingFacts = true;
foreach (QString fact, factList) {
if (!_autopilot->parameterExists(fact)) {
_reportMissingFact(fact);
noMissingFacts = false;
}
}
return noMissingFacts;
}
void FactPanelController::_checkForMissingFactPanel(void)
{
if (!_factPanel) {
QGCMessageBox::critical("Incorrect FactPanel Qml implementation", "FactPanelController used without passing in factPanel. This could lead to non-functioning user interface being displayed.");
}
}
\ No newline at end of file
/*=====================================================================
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 FactPanelController_H
#define FactPanelController_H
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include <QObject>
#include <QQuickItem>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
#include "UASManagerInterface.h"
/// FactPanelController is used in combination with the FactPanel Qml control for handling
/// missing Facts from C++ code.
class FactPanelController : public QObject
{
Q_OBJECT
public:
FactPanelController(void);
Q_PROPERTY(QQuickItem* factPanel READ factPanel WRITE setFactPanel)
QQuickItem* factPanel(void);
void setFactPanel(QQuickItem* panel);
protected:
/// Checks for existence of the specified facts
/// @return true: all facts exists, false: facts missing and reported
bool _allFactsExists(QStringList factList);
/// Report a missing fact to the FactPanel Qml element
void _reportMissingFact(const QString& missingFact);
AutoPilotPlugin* _autopilot;
private slots:
void _checkForMissingFactPanel(void);
private:
void _notifyPanelMissingFact(const QString& missingFact);
QQuickItem* _factPanel;
QStringList _delayedMissingFacts;
};
#endif
\ No newline at end of file
Module QGroundControl.FactControls
FactPanel 1.0 FactPanel.qml
FactLabel 1.0 FactLabel.qml
FactTextField 1.0 FactTextField.qml
FactCheckBox 1.0 FactCheckBox.qml
......
......@@ -29,6 +29,7 @@
#include "QGCApplication.h"
#include "VehicleComponent.h"
#include "FactBinder.h"
#include "FactPanelController.h"
#include <QtQml>
......@@ -40,6 +41,7 @@ FactSystem::FactSystem(QObject* parent) :
QGCSingleton(parent)
{
qmlRegisterType<FactBinder>(_factSystemQmlUri, 1, 0, "Fact");
qmlRegisterType<FactPanelController>(_factSystemQmlUri, 1, 0, "FactPanelController");
qmlRegisterUncreatableType<VehicleComponent>(_factSystemQmlUri, 1, 0, "VehicleComponent", "Can only reference, cannot create");
}
......
......@@ -386,8 +386,7 @@ Fact* ParameterLoader::getFact(int componentId, const QString& name)
componentId = _actualComponentId(componentId);
if (!_mapParameterName2Variant.contains(componentId) || !_mapParameterName2Variant[componentId].contains(name)) {
QString panicMessage("Required parameter (component id: %1, name: %2), is missing from vehicle. QGroundControl cannot operate with this firmware revision. QGroundControl will now shut down.");
qgcApp()->panicShutdown(panicMessage.arg(componentId).arg(name));
return NULL;
}
Fact* fact = _mapParameterName2Variant[componentId][name].value<Fact*>();
......
......@@ -180,6 +180,10 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) :
#endif
#endif
// Set up timer for delayed missing fact display
_missingFactDelayedDisplayTimer.setSingleShot(true);
_missingFactDelayedDisplayTimer.setInterval(_missingFactDelayedDisplayTimerTimeout);
connect(&_missingFactDelayedDisplayTimer, &QTimer::timeout, this, &QGCApplication::_missingFactsDisplay);
// Set application information
if (_runningUnitTests) {
......@@ -677,8 +681,28 @@ void QGCApplication::_reconnect(void)
_reconnectLinkConfig = NULL;
}
void QGCApplication::panicShutdown(const QString& panicMessage)
void QGCApplication::reportMissingFact(const QString& name)
{
QGCMessageBox::critical("Panic Shutdown", panicMessage);
::exit(0);
_missingFacts += name;
_missingFactDelayedDisplayTimer.start();
}
/// Called when the delay timer fires to show the missing facts warning
void QGCApplication::_missingFactsDisplay(void)
{
Q_ASSERT(_missingFacts.count());
QString facts;
foreach (QString fact, _missingFacts) {
if (facts.isEmpty()) {
facts += fact;
} else {
facts += QString(", %1").arg(fact);
}
}
_missingFacts.clear();
QGCMessageBox::critical("Missing Parameters",
QString("Parameters missing from firmware: %1.\n\n"
"You should quit QGroundControl immediately and update your firmware.").arg(facts));
}
\ No newline at end of file
......@@ -33,6 +33,7 @@
#define QGCAPPLICATION_H
#include <QApplication>
#include <QTimer>
#include "LinkConfiguration.h"
......@@ -98,9 +99,9 @@ public:
/// Disconnects the current link and waits for the specified number of seconds before reconnecting.
void reconnectAfterWait(int waitSeconds);
/// Used to shutdown the app if a fatal condition occurs from which it cannot recover
/// @param panicMessage Message to display to user
void panicShutdown(const QString& panicMessage);
/// Used to report a missing Fact. Warning will be displayed to user. Method may be called
/// multiple times.
void reportMissingFact(const QString& name);
public slots:
/// You can connect to this slot to show an information message box from a different thread.
......@@ -143,6 +144,7 @@ public:
private slots:
void _reconnect(void);
void _missingFactsDisplay(void);
private:
void _createSingletons(void);
......@@ -165,7 +167,11 @@ private:
static const char* _lightStyleFile;
bool _styleIsDark; ///< true: dark style, false: light style
LinkConfiguration* _reconnectLinkConfig; ///< Configuration to reconnect for reconnectAfterWai
LinkConfiguration* _reconnectLinkConfig; ///< Configuration to reconnect for reconnectAfterWait
static const int _missingFactDelayedDisplayTimerTimeout = 1000; ///< Timeout to wait for next missing fact to come in before display
QTimer _missingFactDelayedDisplayTimer; ///< Timer use to delay missing fact display
QStringList _missingFacts; ///< List of missing facts to be displayed
/// Unit Test have access to creating and destroying singletons
friend class UnitTest;
......
Markdown is supported
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