Commit 57d0292d authored by DonLakeFlyer's avatar DonLakeFlyer

parent a32d84f8
......@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build
* ArduPilot: Rework Airframe setup ui
* Plan/Pattern: Support named presets to simplify commonly used settings setup. Currently only supported by Survey.
* ArduCopter: Handle 3.7 parameter name change from CH#_OPT to RC#_OPTION.
* Improved support for flashing/connecting to ChibiOS bootloaders boards.
......
......@@ -984,9 +984,7 @@ APMFirmwarePlugin {
HEADERS += \
src/AutoPilotPlugins/APM/APMAirframeComponent.h \
src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.h \
src/AutoPilotPlugins/APM/APMAirframeComponentController.h \
src/AutoPilotPlugins/APM/APMAirframeLoader.h \
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h \
src/AutoPilotPlugins/APM/APMCameraComponent.h \
src/AutoPilotPlugins/APM/APMCompassCal.h \
......@@ -1011,9 +1009,7 @@ APMFirmwarePlugin {
SOURCES += \
src/AutoPilotPlugins/APM/APMAirframeComponent.cc \
src/AutoPilotPlugins/APM/APMAirframeComponentAirframes.cc \
src/AutoPilotPlugins/APM/APMAirframeComponentController.cc \
src/AutoPilotPlugins/APM/APMAirframeLoader.cc \
src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc \
src/AutoPilotPlugins/APM/APMCameraComponent.cc \
src/AutoPilotPlugins/APM/APMCompassCal.cc \
......
......@@ -22,90 +22,155 @@ import QGroundControl.ScreenTools 1.0
SetupPage {
id: airframePage
pageComponent: _useOldFrameParam ? oldFramePageComponent: newFramePageComponent
property real _margins: ScreenTools.defaultFontPixelWidth
property bool _useOldFrameParam: controller.parameterExists(-1, "FRAME")
property Fact _oldFrameParam: controller.getParameterFact(-1, "FRAME", false)
property Fact _newFrameParam: controller.getParameterFact(-1, "FRAME_CLASS", false)
property Fact _frameTypeParam: controller.getParameterFact(-1, "FRAME_TYPE", false)
APMAirframeComponentController {
id: controller
factPanel: airframePage.viewPanel
}
ExclusiveGroup {
id: airframeTypeExclusive
}
pageComponent: pageComponent
Component {
id: oldFramePageComponent
Column {
width: availableWidth
height: 1000
spacing: _margins
RowLayout {
anchors.left: parent.left
anchors.right: parent.right
spacing: _margins
QGCLabel {
font.pointSize: ScreenTools.mediumFontPointSize
wrapMode: Text.WordWrap
text: qsTr("Please select your airframe type")
Layout.fillWidth: true
id: pageComponent
ColumnLayout {
id: mainColumn
width: availableWidth
property real _minW: ScreenTools.defaultFontPixelWidth * 20
property real _boxWidth: _minW
property real _boxSpace: ScreenTools.defaultFontPixelWidth
property real _margins: ScreenTools.defaultFontPixelWidth
property Fact _frameClass: controller.getParameterFact(-1, "FRAME_CLASS")
property Fact _frameType: controller.getParameterFact(-1, "FRAME_TYPE")
readonly property real spacerHeight: ScreenTools.defaultFontPixelHeight
onWidthChanged: computeDimensions()
Component.onCompleted: computeDimensions()
function computeDimensions() {
var sw = 0
var rw = 0
var idx = Math.floor(mainColumn.width / (_minW + ScreenTools.defaultFontPixelWidth))
if(idx < 1) {
_boxWidth = mainColumn.width
_boxSpace = 0
} else {
_boxSpace = 0
if(idx > 1) {
_boxSpace = ScreenTools.defaultFontPixelWidth
sw = _boxSpace * (idx - 1)
}
rw = mainColumn.width - sw
_boxWidth = rw / idx
}
}
Repeater {
model: controller.airframeTypesModel
APMAirframeComponentController {
id: controller
factPanel: airframePage.viewPanel
}
QGCRadioButton {
text: object.name
checked: controller.currentAirframeType == object
exclusiveGroup: airframeTypeExclusive
QGCLabel {
id: helpText
Layout.fillWidth: true
text: (_frameClass.rawValue === 0 ?
qsTr("Airframe is currently not set.") :
qsTr("Currently set to frame class '%1' and frame type '%2'.").arg(_frameClass.enumStringValue).arg(_frameType.enumStringValue)) +
qsTr(" To change this configuration, select the desired frame class below and frame type.")
font.family: ScreenTools.demiboldFontFamily
wrapMode: Text.WordWrap
}
onCheckedChanged: {
if (checked) {
controller.currentAirframeType = object
}
}
}
Item {
id: lastSpacer
height: parent.spacerHeight
width: 10
}
} // Column
} // Component - oldFramePageComponent
Component {
id: newFramePageComponent
Flow {
id: flowView
Layout.fillWidth: true
spacing: _boxSpace
Grid {
width: availableWidth
spacing: _margins
columns: 2
ExclusiveGroup {
id: airframeTypeExclusive
}
QGCLabel {
text: qsTr("Frame Class:")
}
Repeater {
model: controller.frameClassModel
FactComboBox {
fact: _newFrameParam
indexModel: false
width: ScreenTools.defaultFontPixelWidth * 15
}
// Outer summary item rectangle
Rectangle {
id: outerRect
width: _boxWidth
height: ScreenTools.defaultFontPixelHeight * 14
color: qgcPal.window
QGCLabel {
text: qsTr("Frame Type:")
}
readonly property real titleHeight: ScreenTools.defaultFontPixelHeight * 1.75
readonly property real innerMargin: ScreenTools.defaultFontPixelWidth
FactComboBox {
fact: _frameTypeParam
indexModel: false
width: ScreenTools.defaultFontPixelWidth * 15
}
}
}
MouseArea {
anchors.fill: parent
onClicked: airframeCheckBox.checked = true
}
QGCLabel {
id: title
text: object.name
}
Rectangle {
anchors.topMargin: ScreenTools.defaultFontPixelHeight / 2
anchors.top: title.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: airframeCheckBox.checked ? qgcPal.buttonHighlight : qgcPal.windowShade
ColumnLayout {
anchors.margins: innerMargin
anchors.fill: parent
spacing: innerMargin
Image {
id: image
Layout.fillWidth: true
Layout.fillHeight: true
fillMode: Image.PreserveAspectFit
smooth: true
mipmap: true
source: object.imageResource
}
QGCCheckBox {
// Although this item is invisible we still use it to manage state
id: airframeCheckBox
checked: object.frameClass === _frameClass.rawValue
exclusiveGroup: airframeTypeExclusive
visible: false
onCheckedChanged: {
if (checked) {
_frameClass.rawValue = object.frameClass
}
}
}
QGCLabel {
text: qsTr("Frame Type")
font.pointSize: ScreenTools.smallFontPointSize
color: qgcPal.buttonHighlightText
visible: airframeCheckBox.checked && object.frameTypeSupported
}
FactComboBox {
id: combo
Layout.fillWidth: true
fact: _frameType
indexModel: false
visible: airframeCheckBox.checked && object.frameTypeSupported
}
}
}
}
} // Repeater - summary boxes
} // Flow - summary boxes
} // Column
} // Component
} // SetupPage
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "APMAirframeComponentAirframes.h"
#include "APMAirframeComponentController.h"
QMap<QString, APMAirframeComponentAirframes::AirframeType_t*> APMAirframeComponentAirframes::rgAirframeTypes;
QMap<QString, APMAirframeComponentAirframes::AirframeType_t*>& APMAirframeComponentAirframes::get() {
return rgAirframeTypes;
}
void APMAirframeComponentAirframes::insert(const QString& group, int groupId, const QString& image,const QString& name, const QString& file)
{
AirframeType_t *g;
if (!rgAirframeTypes.contains(group)) {
g = new AirframeType_t;
g->name = group;
g->type = groupId;
g->imageResource = image.isEmpty() ? QString() : QStringLiteral("qrc:/qmlimages/") + image;
rgAirframeTypes.insert(group, g);
} else {
g = rgAirframeTypes.value(group);
}
if (!name.isEmpty() && !file.isEmpty())
g->rgAirframeInfo.append(new APMAirframe(name, file, g->type));
}
void APMAirframeComponentAirframes::clear() {
QList<AirframeType_t*> valueList = get().values();
foreach(AirframeType_t *pType, valueList) {
qDeleteAll(pType->rgAirframeInfo);
delete pType;
}
rgAirframeTypes.clear();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef APMAirframeComponentAirframes_H
#define APMAirframeComponentAirframes_H
#include <QObject>
#include <QQuickItem>
#include <QList>
#include <QMap>
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
class APMAirframe;
/// MVC Controller for AirframeComponent.qml.
class APMAirframeComponentAirframes
{
public:
typedef struct {
QString name;
QString imageResource;
int type;
QList<APMAirframe*> rgAirframeInfo;
} AirframeType_t;
typedef QMap<QString, AirframeType_t*> AirframeTypeMap;
static AirframeTypeMap& get();
static void clear();
static void insert(const QString& group, int groupId, const QString& image,const QString& name = QString(), const QString& file = QString());
protected:
static AirframeTypeMap rgAirframeTypes;
private:
};
#endif
......@@ -7,12 +7,7 @@
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "APMAirframeComponentController.h"
#include "APMAirframeComponentAirframes.h"
#include "QGCMAVLink.h"
#include "MultiVehicleManager.h"
#include "QGCApplication.h"
......@@ -26,71 +21,113 @@
#include <QJsonParseError>
#include <QJsonObject>
bool APMAirframeComponentController::_typesRegistered = false;
const char* APMAirframeComponentController::_oldFrameParam = "FRAME";
const char* APMAirframeComponentController::_newFrameParam = "FRAME_CLASS";
APMAirframeComponentController::APMAirframeComponentController(void) :
_airframeTypesModel(new QmlObjectListModel(this))
{
if (!_typesRegistered) {
_typesRegistered = true;
qmlRegisterUncreatableType<APMAirframeType>("QGroundControl.Controllers", 1, 0, "APMAirframeType", QStringLiteral("Can only reference APMAirframeType"));
}
_fillAirFrames();
Fact* frame = NULL;
if (parameterExists(FactSystem::defaultComponentId, _oldFrameParam)) {
frame = getParameterFact(FactSystem::defaultComponentId, _oldFrameParam);
} else if (parameterExists(FactSystem::defaultComponentId, _newFrameParam)){
frame = getParameterFact(FactSystem::defaultComponentId, _newFrameParam);
// These should match the FRAME_CLASS parameter enum meta data
#define FRAME_CLASS_UNDEFINED 0
#define FRAME_CLASS_QUAD 1
#define FRAME_CLASS_HEX 2
#define FRAME_CLASS_OCTA 3
#define FRAME_CLASS_OCTAQUAD 4
#define FRAME_CLASS_Y6 5
#define FRAME_CLASS_HELI 6
#define FRAME_CLASS_TRI 7
#define FRAME_CLASS_SINGLECOPTER 8
#define FRAME_CLASS_COAXCOPTER 9
#define FRAME_CLASS_BICOPTER 10
#define FRAME_CLASS_HELI_DUAL 11
#define FRAME_CLASS_DODECAHEXA 12
#define FRAME_CLASS_HELIQUAD 13
// These should match the FRAME_TYPE parameter enum meta data
#define FRAME_TYPE_PLUS 0
#define FRAME_TYPE_X 1
#define FRAME_TYPE_V 2
#define FRAME_TYPE_H 3
#define FRAME_TYPE_V_TAIL 4
#define FRAME_TYPE_A_TAIL 5
#define FRAME_TYPE_Y6B 10
#define FRAME_TYPE_Y6F 11
#define FRAME_TYPE_BETAFLIGHTX 12
#define FRAME_TYPE_DJIX 13
#define FRAME_TYPE_CLOCKWISEX 14
typedef struct {
int frameClass;
int frameType;
const char* imageResource;
} FrameToImageInfo_t;
static const FrameToImageInfo_t s_rgFrameToImage[] = {
{ FRAME_CLASS_QUAD, FRAME_TYPE_PLUS, "QuadRotorPlus" },
{ FRAME_CLASS_QUAD, FRAME_TYPE_X, "QuadRotorX" },
{ FRAME_CLASS_QUAD, FRAME_TYPE_V, "QuadRotorWide" },
{ FRAME_CLASS_QUAD, FRAME_TYPE_H, "QuadRotorH" },
{ FRAME_CLASS_QUAD, FRAME_TYPE_V_TAIL, "QuadRotorVTail" },
{ FRAME_CLASS_QUAD, FRAME_TYPE_A_TAIL, "QuadRotorATail" },
{ FRAME_CLASS_HEX, FRAME_TYPE_PLUS, "HexaRotorPlus" },
{ FRAME_CLASS_HEX, FRAME_TYPE_X, "HexaRotorX" },
{ FRAME_CLASS_OCTA, FRAME_TYPE_PLUS, "OctoRotorPlus" },
{ FRAME_CLASS_OCTA, FRAME_TYPE_X, "OctoRotorX" },
{ FRAME_CLASS_OCTAQUAD, FRAME_TYPE_PLUS, "OctoRotorPlusCoaxial" },
{ FRAME_CLASS_OCTAQUAD, FRAME_TYPE_X, "OctoRotorXCoaxial" },
{ FRAME_CLASS_Y6, FRAME_TYPE_Y6B, "Y6B" },
{ FRAME_CLASS_Y6, FRAME_TYPE_Y6F, "AirframeUnknown" },
{ FRAME_CLASS_Y6, -1, "Y6A" },
{ FRAME_CLASS_HELI, -1, "Helicopter" },
{ FRAME_CLASS_TRI, -1, "YPlus" },
};
static QString s_findImageResource(int frameClass, int frameType)
{
for (size_t i=0; i<sizeof(s_rgFrameToImage)/sizeof(s_rgFrameToImage[0]); i++) {
const FrameToImageInfo_t* pFrameToImageInfo = &s_rgFrameToImage[i];
if (pFrameToImageInfo->frameClass == frameClass && pFrameToImageInfo->frameType == frameType) {
return pFrameToImageInfo->imageResource;
} else if (pFrameToImageInfo->frameClass == frameClass && pFrameToImageInfo->frameType == -1) {
return pFrameToImageInfo->imageResource;
}
}
if (frame) {
connect(frame, &Fact::rawValueChanged, this, &APMAirframeComponentController::_factFrameChanged);
_factFrameChanged(frame->rawValue());
}
return QStringLiteral("AirframeUnknown");
}
APMAirframeComponentController::~APMAirframeComponentController()
APMAirframeComponentController::APMAirframeComponentController(void)
: _frameClassFact (getParameterFact(FactSystem::defaultComponentId, QStringLiteral("FRAME_CLASS")))
, _frameTypeFact (getParameterFact(FactSystem::defaultComponentId, QStringLiteral("FRAME_TYPE")))
, _frameClassModel (new QmlObjectListModel(this))
{
_fillFrameClasses();
}
void APMAirframeComponentController::_factFrameChanged(QVariant value)
APMAirframeComponentController::~APMAirframeComponentController()
{
FrameId v = (FrameId) value.toInt();
for(int i = 0, size = _airframeTypesModel->count(); i < size; i++ ) {
APMAirframeType *airframeType = qobject_cast<APMAirframeType*>(_airframeTypesModel->get(i));
Q_ASSERT(airframeType);
if (airframeType->type() == v) {
_currentAirframeType = airframeType;
break;
}
}
emit currentAirframeTypeChanged(_currentAirframeType);
}
void APMAirframeComponentController::_fillAirFrames()
void APMAirframeComponentController::_fillFrameClasses()
{
for (int tindex = 0; tindex < APMAirframeComponentAirframes::get().count(); tindex++) {
const APMAirframeComponentAirframes::AirframeType_t* pType = APMAirframeComponentAirframes::get().values().at(tindex);
QList<int> frameTypeNotSupported;
APMAirframeType* airframeType = new APMAirframeType(pType->name, pType->imageResource, pType->type, this);
Q_CHECK_PTR(airframeType);
frameTypeNotSupported << FRAME_CLASS_HELI
<< FRAME_CLASS_SINGLECOPTER
<< FRAME_CLASS_COAXCOPTER
<< FRAME_CLASS_BICOPTER
<< FRAME_CLASS_HELI_DUAL
<< FRAME_CLASS_HELIQUAD;
for (int index = 0; index < pType->rgAirframeInfo.count(); index++) {
const APMAirframe* pInfo = pType->rgAirframeInfo.at(index);
Q_CHECK_PTR(pInfo);
for (int i=1; i<_frameClassFact->enumStrings().count(); i++) {
QString frameClassName = _frameClassFact->enumStrings()[i];
int frameClass = _frameClassFact->enumValues()[i].toInt();
int defaultFrameType;
airframeType->addAirframe(pInfo->name(), pInfo->params(), pInfo->type());
if (frameTypeNotSupported.contains(frameClass)) {
defaultFrameType = -1;
} else {
defaultFrameType = FRAME_TYPE_X;
}
_airframeTypesModel->append(airframeType);
_frameClassModel->append(new APMFrameClass(frameClassName, frameClass, _frameTypeFact, defaultFrameType, _frameClassModel));
}
emit loadAirframesCompleted();
}
void APMAirframeComponentController::_loadParametersFromDownloadFile(const QString& downloadedParamFile)
......@@ -120,86 +157,6 @@ void APMAirframeComponentController::_loadParametersFromDownloadFile(const QStri
_vehicle->parameterManager()->refreshAllParameters();
}
APMAirframeType::APMAirframeType(const QString& name, const QString& imageResource, int type, QObject* parent) :
QObject(parent),
_name(name),
_imageResource(imageResource),
_type(type),
_dirty(false)
{
}
APMAirframeType::~APMAirframeType()
{
}
void APMAirframeType::addAirframe(const QString& name, const QString& file, int type)
{
APMAirframe* airframe = new APMAirframe(name, file, type);
Q_CHECK_PTR(airframe);
_airframes.append(QVariant::fromValue(airframe));
}
APMAirframe::APMAirframe(const QString& name, const QString& paramsFile, int type, QObject* parent) :
QObject(parent),
_name(name),
_paramsFile(paramsFile),
_type(type)
{
}
QString APMAirframe::name() const
{
return _name;
}
QString APMAirframe::params() const
{
return _paramsFile;
}
int APMAirframe::type() const
{
return _type;
}
APMAirframe::~APMAirframe()
{
}
QString APMAirframeType::imageResource() const
{
return _imageResource;
}
QString APMAirframeType::name() const
{
return _name;
}
int APMAirframeType::type() const
{
return _type;
}
APMAirframeType *APMAirframeComponentController::currentAirframeType() const
{
return _currentAirframeType;
}
QString APMAirframeComponentController::currentAirframeTypeName() const
{
return _vehicle->vehicleTypeName();
}
void APMAirframeComponentController::setCurrentAirframeType(APMAirframeType *t)
{
Fact *param = getParameterFact(-1, QStringLiteral("FRAME"));
Q_ASSERT(param);
param->setRawValue(t->type());
}
void APMAirframeComponentController::loadParameters(const QString& paramFile)
{
qgcApp()->setOverrideCursor(Qt::WaitCursor);
......@@ -258,3 +215,25 @@ void APMAirframeComponentController::_paramFileDownloadError(QString errorMsg)
qgcApp()->showMessage(tr("Param file download failed: %1").arg(errorMsg));
qgcApp()->restoreOverrideCursor();
}
APMFrameClass::APMFrameClass(const QString& name, int frameClass, Fact* frameTypeFact, int defaultFrameType, QObject* parent)
: QObject (parent)
, _name (name)
, _frameClass (frameClass)
, _defaultFrameType (defaultFrameType)
, _frameTypeSupported (defaultFrameType != -1)
, _frameTypeFact (frameTypeFact)
{
connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::imageResourceChanged);
connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::frameTypeChanged);
}
APMFrameClass::~APMFrameClass()
{
}
QString APMFrameClass::imageResource(void)
{
return QStringLiteral("/qmlimages/Airframe/%1").arg(s_findImageResource(_frameClass, _frameTypeFact->rawValue().toInt()));
}
......@@ -7,12 +7,7 @@
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#ifndef APMAirframeComponentController_H
#define APMAirframeComponentController_H
#pragma once
#include <QObject>
#include <QQuickItem>
......@@ -22,7 +17,6 @@
#include "UASInterface.h"
#include "AutoPilotPlugin.h"
#include "FactPanelController.h"
#include "APMAirframeComponentAirframes.h"
class APMAirframeModel;
class APMAirframeType;
......@@ -33,98 +27,56 @@ class APMAirframeComponentController : public FactPanelController
Q_OBJECT
public:
enum FrameId{FRAME_TYPE_PLUS = 0,
FRAME_TYPE_X = 1,
FRAME_TYPE_V = 2,
FRAME_TYPE_H = 3,
FRAME_TYPE_NEWY6 = 10};
Q_ENUM(FrameId)
APMAirframeComponentController(void);
~APMAirframeComponentController();
Q_PROPERTY(QmlObjectListModel* airframeTypesModel MEMBER _airframeTypesModel CONSTANT)
Q_PROPERTY(APMAirframeType* currentAirframeType READ currentAirframeType WRITE setCurrentAirframeType NOTIFY currentAirframeTypeChanged)
Q_PROPERTY(QmlObjectListModel* frameClassModel MEMBER _frameClassModel CONSTANT)
Q_INVOKABLE void loadParameters(const QString& paramFile);
int currentAirframeIndex(void);
void setCurrentAirframeIndex(int newIndex);
signals:
void loadAirframesCompleted();
void currentAirframeTypeChanged(APMAirframeType* airframeType);
public slots:
APMAirframeType *currentAirframeType() const;
Q_INVOKABLE QString currentAirframeTypeName() const;
void setCurrentAirframeType(APMAirframeType *t);
private slots:
void _fillAirFrames(void);
void _factFrameChanged(QVariant v);
void _githubJsonDownloadFinished(QString remoteFile, QString localFile);
void _githubJsonDownloadError(QString errorMsg);
void _paramFileDownloadFinished(QString remoteFile, QString localFile);