Commit 87c06bed authored by Don Gagne's avatar Don Gagne

Much better handling of missing facts

parent 5ae769a1
...@@ -635,7 +635,8 @@ SOURCES += \ ...@@ -635,7 +635,8 @@ SOURCES += \
# Fact System code # Fact System code
INCLUDEPATH += \ INCLUDEPATH += \
src/FactSystem src/FactSystem \
src/FactSystem/FactControls \
HEADERS += \ HEADERS += \
src/FactSystem/Fact.h \ src/FactSystem/Fact.h \
...@@ -644,6 +645,7 @@ HEADERS += \ ...@@ -644,6 +645,7 @@ HEADERS += \
src/FactSystem/FactSystem.h \ src/FactSystem/FactSystem.h \
src/FactSystem/FactValidator.h \ src/FactSystem/FactValidator.h \
src/FactSystem/ParameterLoader.h \ src/FactSystem/ParameterLoader.h \
src/FactSystem/FactControls/FactPanelController.h \
SOURCES += \ SOURCES += \
src/FactSystem/Fact.cc \ src/FactSystem/Fact.cc \
...@@ -652,6 +654,7 @@ SOURCES += \ ...@@ -652,6 +654,7 @@ SOURCES += \
src/FactSystem/FactSystem.cc \ src/FactSystem/FactSystem.cc \
src/FactSystem/FactValidator.cc \ src/FactSystem/FactValidator.cc \
src/FactSystem/ParameterLoader.cc \ src/FactSystem/ParameterLoader.cc \
src/FactSystem/FactControls/FactPanelController.cc \
# Android # Android
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file> <file alias="QmlTest.qml">src/QmlControls/QmlTest.qml</file>
<file alias="QGroundControl/FactControls/qmldir">src/FactSystem/FactControls/qmldir</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/FactLabel.qml">src/FactSystem/FactControls/FactLabel.qml</file>
<file alias="QGroundControl/FactControls/FactTextField.qml">src/FactSystem/FactControls/FactTextField.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> <file alias="QGroundControl/FactControls/FactCheckBox.qml">src/FactSystem/FactControls/FactCheckBox.qml</file>
......
...@@ -31,125 +31,132 @@ import QGroundControl.Palette 1.0 ...@@ -31,125 +31,132 @@ import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0 import QGroundControl.Controllers 1.0
Rectangle { FactPanel {
AirframeComponentController { id: controller } id: panel
QGCPalette { id: qgcPal; colorGroupEnabled: true }
color: qgcPal.window AirframeComponentController { id: controller; factPanel: panel }
Column { Rectangle {
anchors.fill: parent anchors.fill: parent
QGCLabel { QGCPalette { id: qgcPal; colorGroupEnabled: true }
text: "AIRFRAME CONFIG"
font.pointSize: 20
}
Item { height: 20; width: 10 } // spacer color: qgcPal.window
Row { Column {
width: parent.width anchors.fill: parent
QGCLabel { QGCLabel {
width: parent.width - applyButton.width text: "AIRFRAME CONFIG"
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." font.pointSize: 20
wrapMode: Text.WordWrap
} }
QGCButton { Item { height: 20; width: 10 } // spacer
id: applyButton
text: "Apply and Restart"
onClicked: { controller.changeAutostart() }
}
}
Item { height: 20; width: 10 } // spacer Row {
width: parent.width
Flow { QGCLabel {
width: parent.width width: parent.width - applyButton.width
spacing: 10 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 { QGCButton {
id: airframeTypeExclusive id: applyButton
text: "Apply and Restart"
onClicked: { controller.changeAutostart() }
}
} }
Repeater { Item { height: 20; width: 10 } // spacer
model: controller.airframeTypes
// Outer summary item rectangle Flow {
Rectangle { width: parent.width
readonly property real titleHeight: 30 spacing: 10
readonly property real innerMargin: 10
width: 250 ExclusiveGroup {
height: 200 id: airframeTypeExclusive
color: qgcPal.windowShade }
Repeater {
model: controller.airframeTypes
// Outer summary item rectangle
Rectangle { Rectangle {
id: title readonly property real titleHeight: 30
width: parent.width readonly property real innerMargin: 10
height: parent.titleHeight
color: qgcPal.windowShadeDark
Text { width: 250
anchors.fill: parent height: 200
color: qgcPal.windowShade
color: qgcPal.buttonText Rectangle {
font.pixelSize: 12 id: title
text: modelData.name width: parent.width
height: parent.titleHeight
color: qgcPal.windowShadeDark
verticalAlignment: TextEdit.AlignVCenter Text {
horizontalAlignment: TextEdit.AlignHCenter anchors.fill: parent
}
}
Image { color: qgcPal.buttonText
id: image font.pixelSize: 12
x: innerMargin text: modelData.name
width: parent.width - (innerMargin * 2)
height: parent.height - title.height - combo.height - (innerMargin * 3)
anchors.topMargin: innerMargin
anchors.top: title.bottom
source: modelData.imageResource verticalAlignment: TextEdit.AlignVCenter
fillMode: Image.PreserveAspectFit horizontalAlignment: TextEdit.AlignHCenter
smooth: true }
}
} 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: { QGCCheckBox {
if (checked && combo.currentIndex != -1) { id: airframeCheckBox
controller.autostartId = modelData.airframes[combo.currentIndex].autostartId 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 { QGCComboBox {
id: combo id: combo
objectName: modelData.airframeType + "ComboBox" objectName: modelData.airframeType + "ComboBox"
x: innerMargin x: innerMargin
anchors.topMargin: innerMargin anchors.topMargin: innerMargin
anchors.top: image.bottom anchors.top: image.bottom
width: parent.width - (innerMargin * 2) width: parent.width - (innerMargin * 2)
model: modelData.airframes model: modelData.airframes
currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0 currentIndex: (modelData.name == controller.currentAirframeType) ? controller.currentVehicleIndex : 0
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (airframeCheckBox.checked) { if (airframeCheckBox.checked) {
controller.autostartId = modelData.airframes[currentIndex].autostartId controller.autostartId = modelData.airframes[currentIndex].autostartId
}
} }
} }
} }
} }
} }
}
}
} }
} }
\ No newline at end of file
...@@ -37,19 +37,13 @@ ...@@ -37,19 +37,13 @@
bool AirframeComponentController::_typesRegistered = false; bool AirframeComponentController::_typesRegistered = false;
AirframeComponentController::AirframeComponentController(QObject* parent) : AirframeComponentController::AirframeComponentController(void) :
QObject(parent),
_uas(NULL), _uas(NULL),
_autoPilotPlugin(NULL),
_currentVehicleIndex(0), _currentVehicleIndex(0),
_autostartId(0) _autostartId(0)
{ {
_uas = UASManager::instance()->getActiveUAS(); _uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(_uas); Q_ASSERT(_uas);
_autoPilotPlugin = AutoPilotPluginManager::instance()->getInstanceForAutoPilotPlugin(_uas);
Q_ASSERT(_autoPilotPlugin);
Q_ASSERT(_autoPilotPlugin->pluginReady());
if (!_typesRegistered) { if (!_typesRegistered) {
_typesRegistered = true; _typesRegistered = true;
...@@ -57,10 +51,16 @@ AirframeComponentController::AirframeComponentController(QObject* parent) : ...@@ -57,10 +51,16 @@ AirframeComponentController::AirframeComponentController(QObject* parent) :
qmlRegisterUncreatableType<Airframe>("QGroundControl.Controllers", 1, 0, "Aiframe", "Can only reference Airframe"); 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 // Load up member variables
bool autostartFound = false; 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++) { for (const AirframeComponentAirframes::AirframeType_t* pType=&AirframeComponentAirframes::rgAirframeTypes[0]; pType->name != NULL; pType++) {
AirframeType* airframeType = new AirframeType(pType->name, pType->imageResource, this); AirframeType* airframeType = new AirframeType(pType->name, pType->imageResource, this);
...@@ -81,7 +81,7 @@ AirframeComponentController::AirframeComponentController(QObject* parent) : ...@@ -81,7 +81,7 @@ AirframeComponentController::AirframeComponentController(QObject* parent) :
_airframeTypes.append(QVariant::fromValue(airframeType)); _airframeTypes.append(QVariant::fromValue(airframeType));
} }
if (_autostartId != 0) { if (_autostartId != 0) {
// FIXME: Should be a user error // FIXME: Should be a user error
Q_UNUSED(autostartFound); Q_UNUSED(autostartFound);
...@@ -101,8 +101,8 @@ void AirframeComponentController::changeAutostart(void) ...@@ -101,8 +101,8 @@ void AirframeComponentController::changeAutostart(void)
return; return;
} }
_autoPilotPlugin->getParameterFact("SYS_AUTOSTART")->setValue(_autostartId); _autopilot->getParameterFact("SYS_AUTOSTART")->setValue(_autostartId);
_autoPilotPlugin->getParameterFact("SYS_AUTOCONFIG")->setValue(1); _autopilot->getParameterFact("SYS_AUTOCONFIG")->setValue(1);
qgcApp()->setOverrideCursor(Qt::WaitCursor); qgcApp()->setOverrideCursor(Qt::WaitCursor);
......
...@@ -33,14 +33,15 @@ ...@@ -33,14 +33,15 @@
#include "UASInterface.h" #include "UASInterface.h"
#include "AutoPilotPlugin.h" #include "AutoPilotPlugin.h"
#include "FactPanelController.h"
/// MVC Controller for AirframeComponent.qml. /// MVC Controller for AirframeComponent.qml.
class AirframeComponentController : public QObject class AirframeComponentController : public FactPanelController
{ {
Q_OBJECT Q_OBJECT
public: public:
AirframeComponentController(QObject* parent = NULL); AirframeComponentController(void);
~AirframeComponentController(); ~AirframeComponentController();
Q_PROPERTY(QVariantList airframeTypes MEMBER _airframeTypes CONSTANT) Q_PROPERTY(QVariantList airframeTypes MEMBER _airframeTypes CONSTANT)
...@@ -63,7 +64,6 @@ private: ...@@ -63,7 +64,6 @@ private:
static bool _typesRegistered; static bool _typesRegistered;
UASInterface* _uas; UASInterface* _uas;
AutoPilotPlugin* _autoPilotPlugin;
QVariantList _airframeTypes; QVariantList _airframeTypes;
QString _currentAirframeType; QString _currentAirframeType;
QString _currentVehicleName; QString _currentVehicleName;
......
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0 import QGroundControl.Controllers 1.0
Column { FactPanel {
Fact { id: sysIdFact; name: "MAV_SYS_ID" } id: panel
Fact { id: sysAutoStartFact; name: "SYS_AUTOSTART" } anchors.fill: parent
property bool autoStartSet: sysAutoStartFact.value != 0 AirframeComponentController { id: controller; factPanel: panel }
anchors.fill: parent Fact { id: sysIdFact; name: "MAV_SYS_ID"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8 Fact { id: sysAutoStartFact; name: "SYS_AUTOSTART"; onFactMissing: showMissingFactOverlay(name) }
AirframeComponentController { id: controller } property bool autoStartSet: sysAutoStartFact.value != 0
VehicleSummaryRow { Column {
labelText: "System ID:" anchors.fill: parent
valueText: sysIdFact.valueString anchors.margins: 8
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Airframe type:" labelText: "System ID:"
valueText: autoStartSet ? controller.currentAirframeType : "Setup required" valueText: sysIdFact.valueString
} }
VehicleSummaryRow {
labelText: "Airframe type:"
valueText: autoStartSet ? controller.currentAirframeType : "Setup required"
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Vehicle:" labelText: "Vehicle:"
valueText: autoStartSet ? controller.currentVehicleName : "Setup required" valueText: autoStartSet ? controller.currentVehicleName : "Setup required"
}
} }
} }
\ No newline at end of file
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
Column { FactPanel {
Fact { id: modeSwFact; name: "RC_MAP_MODE_SW" } anchors.fill: parent
Fact { id: posCtlSwFact; name: "RC_MAP_POSCTL_SW" }
Fact { id: loiterSwFact; name: "RC_MAP_LOITER_SW" }
Fact { id: returnSwFact; name: "RC_MAP_RETURN_SW" }
anchors.fill: parent Fact { id: modeSwFact; name: "RC_MAP_MODE_SW"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8 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 { Column {
labelText: "Mode switch:" anchors.fill: parent
valueText: modeSwFact.value == 0 ? "Setup required" : modeSwFact.valueString anchors.margins: 8
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Position Ctl switch:" labelText: "Mode switch:"
valueText: posCtlSwFact.value == 0 ? "Disabled" : posCtlSwFact.valueString valueText: modeSwFact.value == 0 ? "Setup required" : modeSwFact.valueString
} }
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Loiter switch:" labelText: "Position Ctl switch:"
valueText: loiterSwFact.value == 0 ? "Disabled" : loiterSwFact.valueString valueText: posCtlSwFact.value == 0 ? "Disabled" : posCtlSwFact.valueString
} }
VehicleSummaryRow {
labelText: "Loiter switch:"
valueText: loiterSwFact.value == 0 ? "Disabled" : loiterSwFact.valueString
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Return switch:" labelText: "Return switch:"
valueText: returnSwFact.value == 0 ? "Disabled" : returnSwFact.valueString valueText: returnSwFact.value == 0 ? "Disabled" : returnSwFact.valueString
}
} }
} }
...@@ -27,32 +27,35 @@ ...@@ -27,32 +27,35 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
Column { FactPanel {
Fact { id: batVChargedFact; name: "BAT_V_CHARGED" } anchors.fill: parent
Fact { id: batVEmptyFact; name: "BAT_V_EMPTY" }
Fact { id: batCellsFact; name: "BAT_N_CELLS" }
anchors.fill: parent Fact { id: batVChargedFact; name: "BAT_V_CHARGED"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8 Fact { id: batVEmptyFact; name: "BAT_V_EMPTY"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: batCellsFact; name: "BAT_N_CELLS"; onFactMissing: showMissingFactOverlay(name) }
VehicleSummaryRow { Column {
labelText: "Battery Full:" anchors.fill: parent
valueText: batVChargedFact.valueString anchors.margins: 8
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Battery Empty:" labelText: "Battery Full:"
valueText: batVEmptyFact.valueString valueText: batVChargedFact.valueString
} }
VehicleSummaryRow {
labelText: "Battery Empty:"
valueText: batVEmptyFact.valueString
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Number of Cells:" labelText: "Number of Cells:"
valueText: batCellsFact.valueString valueText: batCellsFact.valueString
}
} }
} }
\ No newline at end of file
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
Column { FactPanel {
Fact { id: mapRollFact; name: "RC_MAP_ROLL" } anchors.fill: parent
Fact { id: mapPitchFact; name: "RC_MAP_PITCH" }
Fact { id: mapYawFact; name: "RC_MAP_YAW" } Fact { id: mapRollFact; name: "RC_MAP_ROLL"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapThrottleFact; name: "RC_MAP_THROTTLE" } Fact { id: mapPitchFact; name: "RC_MAP_PITCH"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapFlapsFact; name: "RC_MAP_FLAPS" } Fact { id: mapYawFact; name: "RC_MAP_YAW"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapAux1Fact; name: "RC_MAP_AUX1" } Fact { id: mapThrottleFact; name: "RC_MAP_THROTTLE"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapAux2Fact; name: "RC_MAP_AUX2" } Fact { id: mapFlapsFact; name: "RC_MAP_FLAPS"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: mapAux1Fact; name: "RC_MAP_AUX1"; onFactMissing: showMissingFactOverlay(name) }
anchors.fill: parent Fact { id: mapAux2Fact; name: "RC_MAP_AUX2"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8
Column {
VehicleSummaryRow { anchors.fill: parent
labelText: "Roll:" anchors.margins: 8
valueText: mapRollFact.value == 0 ? "Setup required" : mapRollFact.valueString
} VehicleSummaryRow {
labelText: "Roll:"
VehicleSummaryRow { valueText: mapRollFact.value == 0 ? "Setup required" : mapRollFact.valueString
labelText: "Pitch:" }
valueText: mapPitchFact.value == 0 ? "Setup required" : mapPitchFact.valueString
} VehicleSummaryRow {
labelText: "Pitch:"
VehicleSummaryRow { valueText: mapPitchFact.value == 0 ? "Setup required" : mapPitchFact.valueString
labelText: "Yaw:" }
valueText: mapYawFact.value == 0 ? "Setup required" : mapYawFact.valueString
} VehicleSummaryRow {
labelText: "Yaw:"
VehicleSummaryRow { valueText: mapYawFact.value == 0 ? "Setup required" : mapYawFact.valueString
labelText: "Throttle:" }
valueText: mapThrottleFact.value == 0 ? "Setup required" : mapThrottleFact.valueString
} VehicleSummaryRow {
labelText: "Throttle:"
VehicleSummaryRow { valueText: mapThrottleFact.value == 0 ? "Setup required" : mapThrottleFact.valueString
labelText: "Flaps:" }
valueText: mapFlapsFact.value == 0 ? "Disabled" : mapFlapsFact.valueString
} VehicleSummaryRow {
labelText: "Flaps:"
VehicleSummaryRow { valueText: mapFlapsFact.value == 0 ? "Disabled" : mapFlapsFact.valueString
labelText: "Aux1:" }
valueText: mapAux1Fact.value == 0 ? "Disabled" : mapAux1Fact.valueString
} VehicleSummaryRow {
labelText: "Aux1:"
VehicleSummaryRow { valueText: mapAux1Fact.value == 0 ? "Disabled" : mapAux1Fact.valueString
labelText: "Aux2:" }
valueText: mapAux2Fact.value == 0 ? "Disabled" : mapAux2Fact.valueString
VehicleSummaryRow {
labelText: "Aux2:"
valueText: mapAux2Fact.value == 0 ? "Disabled" : mapAux2Fact.valueString
}
} }
} }
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0 import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
Column { FactPanel {
Fact { id: returnAltFact; name: "RTL_RETURN_ALT" } anchors.fill: parent
Fact { id: descendAltFact; name: "RTL_DESCEND_ALT" }
Fact { id: landDelayFact; name: "RTL_LAND_DELAY" } Fact { id: returnAltFact; name: "RTL_RETURN_ALT"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: commDLLossFact; name: "COM_DL_LOSS_EN" } Fact { id: descendAltFact; name: "RTL_DESCEND_ALT"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: commRCLossFact; name: "COM_RC_LOSS_T" } Fact { id: landDelayFact; name: "RTL_LAND_DELAY"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: commDLLossFact; name: "COM_DL_LOSS_EN"; onFactMissing: showMissingFactOverlay(name) }
anchors.fill: parent Fact { id: commRCLossFact; name: "COM_RC_LOSS_T"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8
Column {
VehicleSummaryRow { anchors.fill: parent
labelText: "RTL min alt:" anchors.margins: 8
valueText: returnAltFact.valueString
} VehicleSummaryRow {
labelText: "RTL min alt:"
VehicleSummaryRow { valueText: returnAltFact.valueString
labelText: "RTL home alt:" }
valueText: descendAltFact.valueString
} VehicleSummaryRow {
labelText: "RTL home alt:"
VehicleSummaryRow { valueText: descendAltFact.valueString
labelText: "RTL loiter delay:" }
valueText: landDelayFact.value < 0 ? "Disabled" : landDelayFact.valueString
} VehicleSummaryRow {
labelText: "RTL loiter delay:"
VehicleSummaryRow { valueText: landDelayFact.value < 0 ? "Disabled" : landDelayFact.valueString
labelText: "Telemetry loss RTL:" }
valueText: commDLLossFact.value != -1 ? "Disabled" : commDLLossFact.valueString
} VehicleSummaryRow {
labelText: "Telemetry loss RTL:"
VehicleSummaryRow { valueText: commDLLossFact.value != -1 ? "Disabled" : commDLLossFact.valueString
labelText: "RC loss RTL (seconds):" }
valueText: commRCLossFact.valueString
VehicleSummaryRow {
labelText: "RC loss RTL (seconds):"
valueText: commRCLossFact.valueString
}
} }
} }
...@@ -3,32 +3,37 @@ import QtQuick.Controls 1.2 ...@@ -3,32 +3,37 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
/* /*
IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml
*/ */
Column { FactPanel {
Fact { id: mag0IdFact; name: "CAL_MAG0_ID" } anchors.fill: parent
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID" }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID" }
anchors.fill: parent Fact { id: mag0IdFact; name: "CAL_MAG0_ID"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8 Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID"; onFactMissing: showMissingFactOverlay(name) }
VehicleSummaryRow { Column {
labelText: "Compass:" anchors.fill: parent
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready" anchors.margins: 8
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Gyro:" labelText: "Compass:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready" valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
} }
VehicleSummaryRow {
labelText: "Gyro:"
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
}
VehicleSummaryRow { VehicleSummaryRow {
labelText: "Accelerometer:" labelText: "Accelerometer:"
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready" valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
}
} }
} }
\ No newline at end of file
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QGroundControl.FactSystem 1.0 import QGroundControl.FactSystem 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
/* /*
IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml IMPORTANT NOTE: Any changes made here must also be made to SensorsComponentSummary.qml
*/ */
Column { FactPanel {
Fact { id: mag0IdFact; name: "CAL_MAG0_ID" } anchors.fill: parent
Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID" }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID" } Fact { id: mag0IdFact; name: "CAL_MAG0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: dPressOffFact; name: "SENS_DPRES_OFF" } Fact { id: gyro0IdFact; name: "CAL_GYRO0_ID"; onFactMissing: showMissingFactOverlay(name) }
Fact { id: accel0IdFact; name: "CAL_ACC0_ID"; onFactMissing: showMissingFactOverlay(name) }
anchors.fill: parent Fact { id: dPressOffFact; name: "SENS_DPRES_OFF"; onFactMissing: showMissingFactOverlay(name) }
anchors.margins: 8
Column {
VehicleSummaryRow { anchors.fill: parent
labelText: "Compass:" anchors.margins: 8
valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
} VehicleSummaryRow {
labelText: "Compass:"
VehicleSummaryRow { valueText: mag0IdFact.value == 0 ? "Setup required" : "Ready"
labelText: "Gyro:" }
valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
} VehicleSummaryRow {
labelText: "Gyro:"
VehicleSummaryRow { valueText: gyro0IdFact.value == 0 ? "Setup required" : "Ready"
labelText: "Accelerometer:" }
valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
} VehicleSummaryRow {
labelText: "Accelerometer:"
VehicleSummaryRow { valueText: accel0IdFact.value == 0 ? "Setup required" : "Ready"
labelText: "Airspeed:" }
valueText: dPressOffFact.value == 0 ? "Setup required" : "Ready"
VehicleSummaryRow {
labelText: "Airspeed:"
valueText: dPressOffFact.value == 0 ? "Setup required" : "Ready"
}
} }
} }
...@@ -35,16 +35,11 @@ ...@@ -35,16 +35,11 @@
#include <QDebug> #include <QDebug>
/// @brief A Fact is used to hold a single value within the system. /// @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 class Fact : public QObject
{ {
Q_OBJECT Q_OBJECT
public: 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); Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent = NULL);
// Property system methods // Property system methods
......
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
FactBinder::FactBinder(void) : FactBinder::FactBinder(void) :
_autopilotPlugin(NULL), _autopilotPlugin(NULL),
_fact(NULL), _fact(NULL),
_componentId(FactSystem::defaultComponentId) _componentId(FactSystem::defaultComponentId),
_factMissingSignalConnected(false)
{ {
UASInterface* uas = UASManager::instance()->getActiveUAS(); UASInterface* uas = UASManager::instance()->getActiveUAS();
Q_ASSERT(uas); Q_ASSERT(uas);
...@@ -85,8 +86,12 @@ void FactBinder::setName(const QString& name) ...@@ -85,8 +86,12 @@ void FactBinder::setName(const QString& name)
emit nameChanged(); emit nameChanged();
emit metaDataChanged(); emit metaDataChanged();
} else { } 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()->reportMissingFact(name);
qgcApp()->panicShutdown(panicMessage.arg(_componentId).arg(parsedName)); if (_factMissingSignalConnected) {
emit factMissing(name);
} else {
_missedFactMissingSignals << name;
}
} }
} }
} }
...@@ -208,3 +213,27 @@ bool FactBinder::valueEqualsDefault(void) ...@@ -208,3 +213,27 @@ bool FactBinder::valueEqualsDefault(void)
return false; 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: ...@@ -78,14 +78,24 @@ public:
QString group(void); QString group(void);
signals: signals:
void factMissing(const QString& name);
void nameChanged(void); void nameChanged(void);
void valueChanged(void); void valueChanged(void);
void metaDataChanged(void); void metaDataChanged(void);
private slots:
void _delayedFactMissing(void);
private: private:
// Overrides from QObject
void connectNotify(const QMetaMethod & signal);
void disconnectNotify(const QMetaMethod & signal);
AutoPilotPlugin* _autopilotPlugin; AutoPilotPlugin* _autopilotPlugin;
Fact* _fact; Fact* _fact;
int _componentId; int _componentId;
bool _factMissingSignalConnected;
QStringList _missedFactMissingSignals;
}; };
#endif #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 Module QGroundControl.FactControls
FactPanel 1.0 FactPanel.qml
FactLabel 1.0 FactLabel.qml FactLabel 1.0 FactLabel.qml
FactTextField 1.0 FactTextField.qml FactTextField 1.0 FactTextField.qml
FactCheckBox 1.0 FactCheckBox.qml FactCheckBox 1.0 FactCheckBox.qml
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "QGCApplication.h" #include "QGCApplication.h"
#include "VehicleComponent.h" #include "VehicleComponent.h"
#include "FactBinder.h" #include "FactBinder.h"
#include "FactPanelController.h"
#include <QtQml> #include <QtQml>
...@@ -40,6 +41,7 @@ FactSystem::FactSystem(QObject* parent) : ...@@ -40,6 +41,7 @@ FactSystem::FactSystem(QObject* parent) :
QGCSingleton(parent) QGCSingleton(parent)
{ {
qmlRegisterType<FactBinder>(_factSystemQmlUri, 1, 0, "Fact"); qmlRegisterType<FactBinder>(_factSystemQmlUri, 1, 0, "Fact");
qmlRegisterType<FactPanelController>(_factSystemQmlUri, 1, 0, "FactPanelController");
qmlRegisterUncreatableType<VehicleComponent>(_factSystemQmlUri, 1, 0, "VehicleComponent", "Can only reference, cannot create"); qmlRegisterUncreatableType<VehicleComponent>(_factSystemQmlUri, 1, 0, "VehicleComponent", "Can only reference, cannot create");
} }
......
...@@ -386,8 +386,7 @@ Fact* ParameterLoader::getFact(int componentId, const QString& name) ...@@ -386,8 +386,7 @@ Fact* ParameterLoader::getFact(int componentId, const QString& name)
componentId = _actualComponentId(componentId); componentId = _actualComponentId(componentId);
if (!_mapParameterName2Variant.contains(componentId) || !_mapParameterName2Variant[componentId].contains(name)) { 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."); return NULL;
qgcApp()->panicShutdown(panicMessage.arg(componentId).arg(name));
} }
Fact* fact = _mapParameterName2Variant[componentId][name].value<Fact*>(); Fact* fact = _mapParameterName2Variant[componentId][name].value<Fact*>();
......
...@@ -166,6 +166,10 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) : ...@@ -166,6 +166,10 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting) :
#endif #endif
#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 // Set application information
if (_runningUnitTests) { if (_runningUnitTests) {
...@@ -660,8 +664,28 @@ void QGCApplication::_reconnect(void) ...@@ -660,8 +664,28 @@ void QGCApplication::_reconnect(void)
_reconnectLinkConfig = NULL; _reconnectLinkConfig = NULL;
} }
void QGCApplication::panicShutdown(const QString& panicMessage) void QGCApplication::reportMissingFact(const QString& name)
{ {
QGCMessageBox::critical("Panic Shutdown", panicMessage); _missingFacts += name;
::exit(0); _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 @@ ...@@ -33,6 +33,7 @@
#define QGCAPPLICATION_H #define QGCAPPLICATION_H
#include <QApplication> #include <QApplication>
#include <QTimer>
#include "LinkConfiguration.h" #include "LinkConfiguration.h"
...@@ -98,9 +99,9 @@ public: ...@@ -98,9 +99,9 @@ public:
/// Disconnects the current link and waits for the specified number of seconds before reconnecting. /// Disconnects the current link and waits for the specified number of seconds before reconnecting.
void reconnectAfterWait(int waitSeconds); void reconnectAfterWait(int waitSeconds);
/// Used to shutdown the app if a fatal condition occurs from which it cannot recover /// Used to report a missing Fact. Warning will be displayed to user. Method may be called
/// @param panicMessage Message to display to user /// multiple times.
void panicShutdown(const QString& panicMessage); void reportMissingFact(const QString& name);
public slots: public slots:
/// You can connect to this slot to show an information message box from a different thread. /// You can connect to this slot to show an information message box from a different thread.
...@@ -143,6 +144,7 @@ public: ...@@ -143,6 +144,7 @@ public:
private slots: private slots:
void _reconnect(void); void _reconnect(void);
void _missingFactsDisplay(void);
private: private:
void _createSingletons(void); void _createSingletons(void);
...@@ -165,7 +167,11 @@ private: ...@@ -165,7 +167,11 @@ private:
static const char* _lightStyleFile; static const char* _lightStyleFile;
bool _styleIsDark; ///< true: dark style, false: light style 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 /// Unit Test have access to creating and destroying singletons
friend class UnitTest; 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