diff --git a/QGCCommon.pri b/QGCCommon.pri index 9c72586..5f162ab 100644 --- a/QGCCommon.pri +++ b/QGCCommon.pri @@ -22,6 +22,7 @@ linux { CONFIG += LinuxBuild DEFINES += __STDC_LIMIT_MACROS DEFINES += QGC_GST_TAISYNC_ENABLED + DEFINES += QGC_GST_MICROHARD_ENABLED linux-clang { message("Linux clang") QMAKE_CXXFLAGS += -Qunused-arguments -fcolor-diagnostics @@ -31,12 +32,14 @@ linux { CONFIG += LinuxBuild DEFINES += __STDC_LIMIT_MACROS __rasp_pi2__ DEFINES += QGC_GST_TAISYNC_ENABLED + DEFINES += QGC_GST_MICROHARD_ENABLED } else : android-g++ | android-clang { CONFIG += AndroidBuild MobileBuild DEFINES += __android__ DEFINES += __STDC_LIMIT_MACROS DEFINES += QGC_ENABLE_BLUETOOTH DEFINES += QGC_GST_TAISYNC_ENABLED + DEFINES += QGC_GST_MICROHARD_ENABLED target.path = $$DESTDIR equals(ANDROID_TARGET_ARCH, x86) { CONFIG += Androidx86Build @@ -54,6 +57,7 @@ linux { CONFIG += WindowsBuild DEFINES += __STDC_LIMIT_MACROS DEFINES += QGC_GST_TAISYNC_ENABLED + DEFINES += QGC_GST_MICROHARD_ENABLED } else { error("Unsupported Windows toolchain, only Visual Studio 2015 is supported") } @@ -64,6 +68,7 @@ linux { CONFIG += x86_64 CONFIG -= x86 DEFINES += QGC_GST_TAISYNC_ENABLED + DEFINES += QGC_GST_MICROHARD_ENABLED equals(QT_MAJOR_VERSION, 5) | greaterThan(QT_MINOR_VERSION, 5) { QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 } else { diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index c024873..79b2919 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -1149,6 +1149,23 @@ contains (DEFINES, QGC_GST_TAISYNC_ENABLED) { } #------------------------------------------------------------------------------------- +# Microhard +contains (DEFINES, QGC_GST_MICROHARD_ENABLED) { + INCLUDEPATH += \ + src/Microhard + + HEADERS += \ + src/Microhard/MicrohardManager.h \ + src/Microhard/MicrohardHandler.h \ + src/Microhard/MicrohardSettings.h \ + + SOURCES += \ + src/Microhard/MicrohardManager.cc \ + src/Microhard/MicrohardHandler.cc \ + src/Microhard/MicrohardSettings.cc \ +} + +#------------------------------------------------------------------------------------- # AirMap contains (DEFINES, QGC_AIRMAP_ENABLED) { diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index b811f36..c414f09 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -201,6 +201,7 @@ src/AutoPilotPlugins/Common/SyslinkComponent.qml src/ui/preferences/TcpSettings.qml src/Taisync/TaisyncSettings.qml + src/Microhard/MicrohardSettings.qml src/test.qml src/ui/preferences/UdpSettings.qml src/FlightMap/Widgets/ValuePageWidget.qml diff --git a/src/Microhard/MicrohardHandler.cc b/src/Microhard/MicrohardHandler.cc new file mode 100644 index 0000000..ee61f46 --- /dev/null +++ b/src/Microhard/MicrohardHandler.cc @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "MicrohardHandler.h" +#include "SettingsManager.h" +#include "QGCApplication.h" +#include "VideoManager.h" + +QGC_LOGGING_CATEGORY(MicrohardLog, "MicrohardLog") +QGC_LOGGING_CATEGORY(MicrohardVerbose, "MicrohardVerbose") + +//----------------------------------------------------------------------------- +MicrohardHandler::MicrohardHandler(QObject* parent) + : QObject (parent) +{ +} + +//----------------------------------------------------------------------------- +MicrohardHandler::~MicrohardHandler() +{ + close(); +} + +//----------------------------------------------------------------------------- +bool +MicrohardHandler::close() +{ + bool res = false; + if(_tcpSocket) { + qCDebug(MicrohardLog) << "Close Microhard TCP socket on port" << _tcpSocket->localPort(); + _tcpSocket->close(); + _tcpSocket->deleteLater(); + _tcpSocket = nullptr; + res = true; + } + return res; +} + +//----------------------------------------------------------------------------- +bool +MicrohardHandler::_start(uint16_t port, QHostAddress addr) +{ + close(); + + _tcpSocket = new QTcpSocket(); + QObject::connect(_tcpSocket, &QIODevice::readyRead, this, &MicrohardHandler::_readBytes); + qCDebug(MicrohardLog) << "Connecting to" << addr; + _tcpSocket->connectToHost(addr, port); + if (!_tcpSocket->waitForConnected(1000)) { + close(); + return false; + } + emit connected(); + + return true; +} diff --git a/src/Microhard/MicrohardHandler.h b/src/Microhard/MicrohardHandler.h new file mode 100644 index 0000000..1e46792 --- /dev/null +++ b/src/Microhard/MicrohardHandler.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "QGCLoggingCategory.h" + +#include +#include + +#define MICROHARD_SETTINGS_PORT 23 + +Q_DECLARE_LOGGING_CATEGORY(MicrohardLog) +Q_DECLARE_LOGGING_CATEGORY(MicrohardVerbose) + +class MicrohardHandler : public QObject +{ + Q_OBJECT +public: + + explicit MicrohardHandler (QObject* parent = nullptr); + ~MicrohardHandler (); + virtual bool start () = 0; + virtual bool close (); + +protected: + virtual bool _start (uint16_t port, QHostAddress addr = QHostAddress::AnyIPv4); + +protected slots: + virtual void _readBytes () = 0; + +signals: + void connected (); + void rssiUpdated (int rssi); + +protected: + QTcpSocket* _tcpSocket = nullptr; +}; diff --git a/src/Microhard/MicrohardManager.cc b/src/Microhard/MicrohardManager.cc new file mode 100644 index 0000000..4735de1 --- /dev/null +++ b/src/Microhard/MicrohardManager.cc @@ -0,0 +1,272 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "MicrohardManager.h" +#include "MicrohardSettings.h" +#include "SettingsManager.h" +#include "QGCApplication.h" +#include "QGCCorePlugin.h" + +#include + +#define LONG_TIMEOUT 5000 + +static const char *kMICROHARD_GROUP = "Microhard"; +static const char *kLOCAL_IP = "LocalIP"; +static const char *kREMOTE_IP = "RemoteIP"; +static const char *kGROUND_IP = "GroundIP"; +static const char *kAIR_IP = "AirIP"; +static const char *kNET_MASK = "NetMask"; +static const char *kCFG_PASSWORD = "ConfigPassword"; +static const char *kENC_KEY = "EncryptionKey"; + +//----------------------------------------------------------------------------- +MicrohardManager::MicrohardManager(QGCApplication* app, QGCToolbox* toolbox) + : QGCTool(app, toolbox) +{ + connect(&_workTimer, &QTimer::timeout, this, &MicrohardManager::_checkMicrohard); + _workTimer.setSingleShot(true); + connect(&_locTimer, &QTimer::timeout, this, &MicrohardManager::_locTimeout); + connect(&_remTimer, &QTimer::timeout, this, &MicrohardManager::_remTimeout); + QSettings settings; + settings.beginGroup(kMICROHARD_GROUP); + _localIPAddr = settings.value(kLOCAL_IP, QString("192.168.168.1")).toString(); + _remoteIPAddr = settings.value(kREMOTE_IP, QString("192.168.168.2")).toString(); + _groundIPAddr = settings.value(kGROUND_IP, QString("192.168.168.101")).toString(); + _airIPAddr = settings.value(kAIR_IP, QString("192.168.168.213")).toString(); + _netMask = settings.value(kNET_MASK, QString("255.255.255.0")).toString(); + _configPassword = settings.value(kCFG_PASSWORD, QString("admin")).toString(); + _encryptionKey = settings.value(kENC_KEY, QString("1234567890")).toString(); + settings.endGroup(); +} + +//----------------------------------------------------------------------------- +MicrohardManager::~MicrohardManager() +{ + _close(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_close() +{ + _workTimer.stop(); + _locTimer.stop(); + _remTimer.stop(); + if(_mhSettingsLoc) { + _mhSettingsLoc->close(); + _mhSettingsLoc->deleteLater(); + _mhSettingsLoc = nullptr; + } + if(_mhSettingsRem) { + _mhSettingsRem->close(); + _mhSettingsRem->deleteLater(); + _mhSettingsRem = nullptr; + } +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_reset() +{ + _close(); + _isConnected = false; + emit connectedChanged(); + _linkConnected = false; + emit linkConnectedChanged(); + if(!_appSettings) { + _appSettings = _toolbox->settingsManager()->appSettings(); + connect(_appSettings->enableMicrohard(), &Fact::rawValueChanged, this, &MicrohardManager::_setEnabled); + } + _setEnabled(); +} + +//----------------------------------------------------------------------------- +FactMetaData* +MicrohardManager::_createMetadata(const char* name, QStringList enums) +{ + FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, name, this); + QQmlEngine::setObjectOwnership(metaData, QQmlEngine::CppOwnership); + metaData->setShortDescription(name); + metaData->setLongDescription(name); + metaData->setRawDefaultValue(QVariant(0)); + metaData->setHasControl(true); + metaData->setReadOnly(false); + for(int i = 0; i < enums.size(); i++) { + metaData->addEnumInfo(enums[i], QVariant(i)); + } + metaData->setRawMin(0); + metaData->setRawMin(enums.size() - 1); + return metaData; +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::setToolbox(QGCToolbox* toolbox) +{ + QGCTool::setToolbox(toolbox); + //-- Start it all + _reset(); +} + +//----------------------------------------------------------------------------- +bool +MicrohardManager::setIPSettings(QString localIP_, QString remoteIP_, QString groundIP_, QString airIP_, QString netMask_, QString cfgPassword_, QString encryptionKey_) +{ + if (_localIPAddr != localIP_ || _remoteIPAddr != remoteIP_ || _netMask != netMask_ || + _configPassword != cfgPassword_ || _encryptionKey != encryptionKey_ || _groundIPAddr != groundIP_ || _airIPAddr != airIP_) + { + if (_mhSettingsLoc && _encryptionKey != encryptionKey_) { + _mhSettingsLoc->setEncryptionKey(encryptionKey_); + } + + _localIPAddr = localIP_; + _remoteIPAddr = remoteIP_; + _groundIPAddr = groundIP_; + _airIPAddr = airIP_; + _netMask = netMask_; + _configPassword = cfgPassword_; + _encryptionKey = encryptionKey_; + + QSettings settings; + settings.beginGroup(kMICROHARD_GROUP); + settings.setValue(kLOCAL_IP, localIP_); + settings.setValue(kREMOTE_IP, remoteIP_); + settings.setValue(kGROUND_IP, groundIP_); + settings.setValue(kAIR_IP, airIP_); + settings.setValue(kNET_MASK, netMask_); + settings.setValue(kCFG_PASSWORD, cfgPassword_); + settings.setValue(kENC_KEY, encryptionKey_); + settings.endGroup(); + + _reset(); + + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_setEnabled() +{ + bool enable = _appSettings->enableMicrohard()->rawValue().toBool(); + if(enable) { + if(!_mhSettingsLoc) { + _mhSettingsLoc = new MicrohardSettings(localIPAddr(), this, true); + connect(_mhSettingsLoc, &MicrohardSettings::connected, this, &MicrohardManager::_connectedLoc); + connect(_mhSettingsLoc, &MicrohardSettings::rssiUpdated, this, &MicrohardManager::_rssiUpdatedLoc); + } + if(!_mhSettingsRem) { + _mhSettingsRem = new MicrohardSettings(remoteIPAddr(), this); + connect(_mhSettingsRem, &MicrohardSettings::connected, this, &MicrohardManager::_connectedRem); + connect(_mhSettingsRem, &MicrohardSettings::rssiUpdated, this, &MicrohardManager::_rssiUpdatedRem); + } + _workTimer.start(1000); + } else { + //-- Stop everything + _close(); + } + _enabled = enable; +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_connectedLoc() +{ + qCDebug(MicrohardLog) << "GND Microhard Settings Connected"; + _isConnected = true; + _locTimer.start(LONG_TIMEOUT); + emit connectedChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_connectedRem() +{ + qCDebug(MicrohardLog) << "AIR Microhard Settings Connected"; + _linkConnected = true; + _remTimer.start(LONG_TIMEOUT); + emit linkConnectedChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_rssiUpdatedLoc(int rssi) +{ + _downlinkRSSI = rssi; + _locTimer.stop(); + _locTimer.start(LONG_TIMEOUT); + emit connectedChanged(); + emit linkChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_rssiUpdatedRem(int rssi) +{ + _uplinkRSSI = rssi; + _remTimer.stop(); + _remTimer.start(LONG_TIMEOUT); + emit linkConnectedChanged(); + emit linkChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_locTimeout() +{ + _locTimer.stop(); + _isConnected = false; + if(_mhSettingsLoc) { + _mhSettingsLoc->close(); + _mhSettingsLoc->deleteLater(); + _mhSettingsLoc = nullptr; + } + emit connectedChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_remTimeout() +{ + _remTimer.stop(); + _linkConnected = false; + if(_mhSettingsRem) { + _mhSettingsRem->close(); + _mhSettingsRem->deleteLater(); + _mhSettingsRem = nullptr; + } + emit linkConnectedChanged(); +} + +//----------------------------------------------------------------------------- +void +MicrohardManager::_checkMicrohard() +{ + if(_enabled) { + if(!_mhSettingsLoc || !_mhSettingsRem) { + _setEnabled(); + return; + } + + if(!_isConnected) { + _mhSettingsLoc->start(); + } else { + _mhSettingsLoc->getStatus(); + } + if(!_linkConnected) { + _mhSettingsRem->start(); + } else { + _mhSettingsRem->getStatus(); + } + } + _workTimer.start(_isConnected ? 1000 : LONG_TIMEOUT); +} diff --git a/src/Microhard/MicrohardManager.h b/src/Microhard/MicrohardManager.h new file mode 100644 index 0000000..2dc4904 --- /dev/null +++ b/src/Microhard/MicrohardManager.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "QGCToolbox.h" +#include "QGCLoggingCategory.h" +#include "MicrohardSettings.h" +#include "Fact.h" + +#include +#include + +class AppSettings; +class QGCApplication; + +//----------------------------------------------------------------------------- +class MicrohardManager : public QGCTool +{ + Q_OBJECT +public: + + Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged) + Q_PROPERTY(bool linkConnected READ linkConnected NOTIFY linkConnectedChanged) + Q_PROPERTY(int uplinkRSSI READ uplinkRSSI NOTIFY linkChanged) + Q_PROPERTY(int downlinkRSSI READ downlinkRSSI NOTIFY linkChanged) + Q_PROPERTY(QString localIPAddr READ localIPAddr NOTIFY localIPAddrChanged) + Q_PROPERTY(QString remoteIPAddr READ remoteIPAddr NOTIFY remoteIPAddrChanged) + Q_PROPERTY(QString groundIPAddr READ groundIPAddr NOTIFY groundIPAddrChanged) + Q_PROPERTY(QString airIPAddr READ airIPAddr NOTIFY airIPAddrChanged) + Q_PROPERTY(QString netMask READ netMask NOTIFY netMaskChanged) + Q_PROPERTY(QString configPassword READ configPassword NOTIFY configPasswordChanged) + Q_PROPERTY(QString encryptionKey READ encryptionKey NOTIFY encryptionKeyChanged) + + Q_INVOKABLE bool setIPSettings (QString localIP, QString remoteIP, QString groundIP, QString airIP, QString netMask, QString cfgPassword, QString encyrptionKey); + + explicit MicrohardManager (QGCApplication* app, QGCToolbox* toolbox); + ~MicrohardManager () override; + + void setToolbox (QGCToolbox* toolbox) override; + + bool connected () { return _isConnected && _mhSettingsLoc && _mhSettingsLoc->loggedIn(); } + bool linkConnected () { return _linkConnected && _mhSettingsRem && _mhSettingsRem->loggedIn(); } + int uplinkRSSI () { return _downlinkRSSI; } + int downlinkRSSI () { return _uplinkRSSI; } + QString localIPAddr () { return _localIPAddr; } + QString remoteIPAddr () { return _remoteIPAddr; } + QString airIPAddr () { return _airIPAddr; } + QString groundIPAddr () { return _groundIPAddr; } + QString netMask () { return _netMask; } + QString configPassword () { return _configPassword; } + QString encryptionKey () { return _encryptionKey; } + +signals: + void linkChanged (); + void linkConnectedChanged (); + void connectedChanged (); + void localIPAddrChanged (); + void remoteIPAddrChanged (); + void airIPAddrChanged (); + void groundIPAddrChanged (); + void netMaskChanged (); + void configPasswordChanged (); + void encryptionKeyChanged (); + +private slots: + void _connectedLoc (); + void _rssiUpdatedLoc (int rssi); + void _connectedRem (); + void _rssiUpdatedRem (int rssi); + void _checkMicrohard (); + void _setEnabled (); + void _locTimeout (); + void _remTimeout (); + +private: + void _close (); + void _reset (); + FactMetaData *_createMetadata (const char *name, QStringList enums); + +private: + bool _isConnected = false; + AppSettings* _appSettings = nullptr; + MicrohardSettings* _mhSettingsLoc = nullptr; + MicrohardSettings* _mhSettingsRem = nullptr; + bool _enabled = true; + bool _linkConnected = false; + QTimer _workTimer; + QTimer _locTimer; + QTimer _remTimer; + int _downlinkRSSI = 0; + int _uplinkRSSI = 0; + QString _localIPAddr; + QString _remoteIPAddr; + QString _groundIPAddr; + QString _airIPAddr; + QString _netMask; + QString _configPassword; + QString _encryptionKey; + QTime _timeoutTimer; +}; diff --git a/src/Microhard/MicrohardSettings.cc b/src/Microhard/MicrohardSettings.cc new file mode 100644 index 0000000..5d6c0e7 --- /dev/null +++ b/src/Microhard/MicrohardSettings.cc @@ -0,0 +1,86 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "MicrohardSettings.h" +#include "MicrohardManager.h" +#include "SettingsManager.h" +#include "QGCApplication.h" +#include "VideoManager.h" + +//----------------------------------------------------------------------------- +MicrohardSettings::MicrohardSettings(QString address_, QObject* parent, bool setEncryptionKey) + : MicrohardHandler(parent) +{ + _address = address_; + _setEncryptionKey = setEncryptionKey; +} + +//----------------------------------------------------------------------------- +bool +MicrohardSettings::start() +{ + qCDebug(MicrohardLog) << "Start Microhard Settings"; + _loggedIn = false; + return _start(MICROHARD_SETTINGS_PORT, QHostAddress(_address)); +} + +//----------------------------------------------------------------------------- +void +MicrohardSettings::getStatus() +{ + if (_loggedIn) { + _tcpSocket->write("AT+MWSTATUS\n"); + } +} + +//----------------------------------------------------------------------------- +void +MicrohardSettings::setEncryptionKey(QString key) +{ + QString cmd = "AT+MWVENCRYPT=1," + key + "\n"; + _tcpSocket->write(cmd.toStdString().c_str()); + qCDebug(MicrohardLog) << "setEncryptionKey: " << cmd; +} + +//----------------------------------------------------------------------------- +void +MicrohardSettings::_readBytes() +{ + QByteArray bytesIn = _tcpSocket->read(_tcpSocket->bytesAvailable()); + +// qCDebug(MicrohardVerbose) << "Read bytes: " << bytesIn; + + if (_loggedIn) { + int i1 = bytesIn.indexOf("RSSI (dBm)"); + if (i1 > 0) { + int i2 = bytesIn.indexOf(": ", i1); + if (i2 > 0) { + i2 += 2; + int i3 = bytesIn.indexOf(" ", i2); + int val = bytesIn.mid(i2, i3 - i2).toInt(); + if (val < 0) { + _rssiVal = val; + } + } + } + } else if (bytesIn.contains("UserDevice login:")) { + _tcpSocket->write("admin\n"); + } else if (bytesIn.contains("Password:")) { + std::string pwd = qgcApp()->toolbox()->microhardManager()->configPassword().toStdString() + "\n"; + _tcpSocket->write(pwd.c_str()); + } else if (bytesIn.contains("UserDevice>")) { + if (!loggedIn() && _setEncryptionKey) { + setEncryptionKey(qgcApp()->toolbox()->microhardManager()->encryptionKey()); + } + _loggedIn = true; + } + + emit rssiUpdated(_rssiVal); +} + diff --git a/src/Microhard/MicrohardSettings.h b/src/Microhard/MicrohardSettings.h new file mode 100644 index 0000000..31be24f --- /dev/null +++ b/src/Microhard/MicrohardSettings.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include "MicrohardHandler.h" + +class MicrohardSettings : public MicrohardHandler +{ + Q_OBJECT +public: + explicit MicrohardSettings (QString address, QObject* parent = nullptr, bool setEncryptionKey = false); + bool start () override; + void getStatus (); + void setEncryptionKey (QString key); + bool loggedIn () { return _loggedIn; } + +protected slots: + void _readBytes () override; + +signals: + void updateRSSI (int rssi); + +private: + bool _loggedIn; + int _rssiVal; + QString _address; + bool _setEncryptionKey; +}; diff --git a/src/Microhard/MicrohardSettings.qml b/src/Microhard/MicrohardSettings.qml new file mode 100644 index 0000000..cba0245 --- /dev/null +++ b/src/Microhard/MicrohardSettings.qml @@ -0,0 +1,299 @@ +/**************************************************************************** + * + * (c) 2019 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtGraphicalEffects 1.0 +import QtMultimedia 5.5 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 + +import QGroundControl 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FactControls 1.0 +import QGroundControl.FactSystem 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.SettingsManager 1.0 + +QGCView { + id: _qgcView + viewPanel: panel + color: qgcPal.window + anchors.fill: parent + anchors.margins: ScreenTools.defaultFontPixelWidth + + property real _labelWidth: ScreenTools.defaultFontPixelWidth * 26 + property real _valueWidth: ScreenTools.defaultFontPixelWidth * 20 + property real _panelWidth: _qgcView.width * _internalWidthRatio + property Fact _microhardEnabledFact: QGroundControl.settingsManager.appSettings.enableMicrohard + property bool _microhardEnabled: _microhardEnabledFact.rawValue + + readonly property real _internalWidthRatio: 0.8 + + QGCPalette { id: qgcPal } + + QGCViewPanel { + id: panel + anchors.fill: parent + QGCFlickable { + clip: true + anchors.fill: parent + contentHeight: settingsColumn.height + contentWidth: settingsColumn.width + Column { + id: settingsColumn + width: _qgcView.width + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + anchors.margins: ScreenTools.defaultFontPixelWidth + //----------------------------------------------------------------- + //-- General + Item { + width: _panelWidth + height: generalLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + QGCLabel { + id: generalLabel + text: qsTr("General") + font.family: ScreenTools.demiboldFontFamily + } + } + Rectangle { + height: generalRow.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Row { + id: generalRow + spacing: ScreenTools.defaultFontPixelWidth * 4 + anchors.centerIn: parent + Column { + spacing: ScreenTools.defaultFontPixelWidth + FactCheckBox { + text: qsTr("Enable Microhard") + fact: _microhardEnabledFact + enabled: true + visible: _microhardEnabledFact.visible + } + } + } + } + //----------------------------------------------------------------- + //-- Connection Status + Item { + width: _panelWidth + height: statusLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + visible: _microhardEnabled + QGCLabel { + id: statusLabel + text: qsTr("Connection Status") + font.family: ScreenTools.demiboldFontFamily + } + } + Rectangle { + height: statusCol.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + visible: _microhardEnabled + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Column { + id: statusCol + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + width: parent.width + anchors.centerIn: parent + GridLayout { + anchors.margins: ScreenTools.defaultFontPixelHeight + columnSpacing: ScreenTools.defaultFontPixelWidth * 2 + anchors.horizontalCenter: parent.horizontalCenter + columns: 2 + QGCLabel { + text: qsTr("Ground Unit:") + Layout.minimumWidth: _labelWidth + } + QGCLabel { + text: QGroundControl.microhardManager.connected ? qsTr("Connected") : qsTr("Not Connected") + color: QGroundControl.microhardManager.connected ? qgcPal.colorGreen : qgcPal.colorRed + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Air Unit:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected ? qsTr("Connected") : qsTr("Not Connected") + color: QGroundControl.microhardManager.linkConnected ? qgcPal.colorGreen : qgcPal.colorRed + } + QGCLabel { + text: qsTr("Uplink RSSI:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.uplinkRSSI < 0 ? QGroundControl.microhardManager.uplinkRSSI : "" + } + QGCLabel { + text: qsTr("Downlink RSSI:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.downlinkRSSI < 0 ? QGroundControl.microhardManager.downlinkRSSI : "" + } + } + } + } + //----------------------------------------------------------------- + //-- IP Settings + Item { + width: _panelWidth + height: ipSettingsLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + visible: _microhardEnabled + QGCLabel { + id: ipSettingsLabel + text: qsTr("Network Settings") + font.family: ScreenTools.demiboldFontFamily + } + } + Rectangle { + height: ipSettingsCol.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + visible: _microhardEnabled + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Column { + id: ipSettingsCol + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + width: parent.width + anchors.centerIn: parent + GridLayout { + anchors.margins: ScreenTools.defaultFontPixelHeight + columnSpacing: ScreenTools.defaultFontPixelWidth * 2 + anchors.horizontalCenter: parent.horizontalCenter + columns: 2 + QGCLabel { + text: qsTr("Local IP Address:") + Layout.minimumWidth: _labelWidth + } + QGCTextField { + id: localIP + text: QGroundControl.microhardManager.localIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Remote IP Address:") + } + QGCTextField { + id: remoteIP + text: QGroundControl.microhardManager.remoteIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Ground Unit IP Address:") + Layout.minimumWidth: _labelWidth + } + QGCTextField { + id: groundIP + text: QGroundControl.microhardManager.groundIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Air Unit IP Address:") + } + QGCTextField { + id: airIP + text: QGroundControl.microhardManager.airIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Network Mask:") + } + QGCTextField { + id: netMask + text: QGroundControl.microhardManager.netMask + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Configuration password:") + } + QGCTextField { + id: configPassword + text: QGroundControl.microhardManager.configPassword + enabled: true + inputMethodHints: Qt.ImhHiddenText + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Encryption key:") + } + QGCTextField { + id: encryptionKey + text: QGroundControl.microhardManager.encryptionKey + enabled: true + inputMethodHints: Qt.ImhHiddenText + Layout.minimumWidth: _valueWidth + } + } + Item { + width: 1 + height: ScreenTools.defaultFontPixelHeight + } + QGCButton { + function validateIPaddress(ipaddress) { + if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) + return true + return false + } + function testEnabled() { + if(localIP.text === QGroundControl.microhardManager.localIPAddr && + remoteIP.text === QGroundControl.microhardManager.remoteIPAddr && + groundIP.text === QGroundControl.microhardManager.groundIPAddr && + airIP.text === QGroundControl.microhardManager.airIPAddr && + netMask.text === QGroundControl.microhardManager.netMask && + configPassword.text === QGroundControl.microhardManager.configPassword && + encryptionKey.text === QGroundControl.microhardManager.encryptionKey) + return false + if(!validateIPaddress(localIP.text)) return false + if(!validateIPaddress(remoteIP.text)) return false + if(!validateIPaddress(groundIP.text)) return false + if(!validateIPaddress(airIP.text)) return false + if(!validateIPaddress(netMask.text)) return false + return true + } + enabled: testEnabled() + text: qsTr("Apply") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + QGroundControl.microhardManager.setIPSettings(localIP.text, remoteIP.text, groundIP.text, airIP.text, netMask.text, configPassword.text, encryptionKey.text) + } + + } + } + } + } + } + } +} diff --git a/src/QGCToolbox.cc b/src/QGCToolbox.cc index 4ccde18..f7eca31 100644 --- a/src/QGCToolbox.cc +++ b/src/QGCToolbox.cc @@ -38,6 +38,9 @@ #if defined(QGC_GST_TAISYNC_ENABLED) #include "TaisyncManager.h" #endif +#if defined(QGC_GST_MICROHARD_ENABLED) +#include "MicrohardManager.h" +#endif #if defined(QGC_CUSTOM_BUILD) #include CUSTOMHEADER @@ -78,6 +81,9 @@ QGCToolbox::QGCToolbox(QGCApplication* app) #if defined(QGC_GST_TAISYNC_ENABLED) _taisyncManager = new TaisyncManager (app, this); #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + _microhardManager = new MicrohardManager (app, this); +#endif } void QGCToolbox::setChildToolboxes(void) @@ -107,6 +113,9 @@ void QGCToolbox::setChildToolboxes(void) #if defined(QGC_GST_TAISYNC_ENABLED) _taisyncManager->setToolbox(this); #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + _microhardManager->setToolbox(this); +#endif } void QGCToolbox::_scanAndLoadPlugins(QGCApplication* app) diff --git a/src/QGCToolbox.h b/src/QGCToolbox.h index 8df5642..4daff94 100644 --- a/src/QGCToolbox.h +++ b/src/QGCToolbox.h @@ -36,6 +36,9 @@ class AirspaceManager; #if defined(QGC_GST_TAISYNC_ENABLED) class TaisyncManager; #endif +#if defined(QGC_GST_MICROHARD_ENABLED) +class MicrohardManager; +#endif /// This is used to manage all of our top level services/tools class QGCToolbox : public QObject { @@ -67,6 +70,9 @@ public: #if defined(QGC_GST_TAISYNC_ENABLED) TaisyncManager* taisyncManager () { return _taisyncManager; } #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + MicrohardManager* microhardManager () { return _microhardManager; } +#endif private: void setChildToolboxes(void); @@ -97,6 +103,9 @@ private: #if defined(QGC_GST_TAISYNC_ENABLED) TaisyncManager* _taisyncManager = nullptr; #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + MicrohardManager* _microhardManager = nullptr; +#endif friend class QGCApplication; }; diff --git a/src/QmlControls/QGroundControlQmlGlobal.cc b/src/QmlControls/QGroundControlQmlGlobal.cc index b223793..fbf84f2 100644 --- a/src/QmlControls/QGroundControlQmlGlobal.cc +++ b/src/QmlControls/QGroundControlQmlGlobal.cc @@ -69,6 +69,9 @@ void QGroundControlQmlGlobal::setToolbox(QGCToolbox* toolbox) #if defined(QGC_GST_TAISYNC_ENABLED) _taisyncManager = toolbox->taisyncManager(); #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + _microhardManager = toolbox->microhardManager(); +#endif } void QGroundControlQmlGlobal::saveGlobalSetting (const QString& key, const QString& value) diff --git a/src/QmlControls/QGroundControlQmlGlobal.h b/src/QmlControls/QGroundControlQmlGlobal.h index 26c3631..0a4fb92 100644 --- a/src/QmlControls/QGroundControlQmlGlobal.h +++ b/src/QmlControls/QGroundControlQmlGlobal.h @@ -28,6 +28,11 @@ #else class TaisyncManager; #endif +#if defined(QGC_GST_MICROHARD_ENABLED) +#include "MicrohardManager.h" +#else +class MicrohardManager; +#endif #ifdef QT_DEBUG #include "MockLink.h" @@ -68,6 +73,8 @@ public: Q_PROPERTY(bool airmapSupported READ airmapSupported CONSTANT) Q_PROPERTY(TaisyncManager* taisyncManager READ taisyncManager CONSTANT) Q_PROPERTY(bool taisyncSupported READ taisyncSupported CONSTANT) + Q_PROPERTY(MicrohardManager* microhardManager READ microhardManager CONSTANT) + Q_PROPERTY(bool microhardSupported READ microhardSupported CONSTANT) Q_PROPERTY(int supportedFirmwareCount READ supportedFirmwareCount CONSTANT) Q_PROPERTY(bool px4ProFirmwareSupported READ px4ProFirmwareSupported CONSTANT) @@ -170,6 +177,13 @@ public: bool taisyncSupported () { return false; } #endif + MicrohardManager* microhardManager () { return _microhardManager; } +#if defined(QGC_GST_TAISYNC_ENABLED) + bool microhardSupported () { return true; } +#else + bool microhardSupported () { return false; } +#endif + qreal zOrderTopMost () { return 1000; } qreal zOrderWidgets () { return 100; } qreal zOrderMapItems () { return 50; } @@ -230,6 +244,7 @@ private: FactGroup* _gpsRtkFactGroup = nullptr; AirspaceManager* _airspaceManager = nullptr; TaisyncManager* _taisyncManager = nullptr; + MicrohardManager* _microhardManager = nullptr; bool _skipSetupPage = false; diff --git a/src/Settings/App.SettingsGroup.json b/src/Settings/App.SettingsGroup.json index 67ef154..30472a4 100644 --- a/src/Settings/App.SettingsGroup.json +++ b/src/Settings/App.SettingsGroup.json @@ -221,4 +221,11 @@ "type": "bool", "defaultValue": true } -] +, +{ + "name": "enableMicrohard", + "shortDescription": "Enable Microhard Module Support", + "longDescription": "Enable Microhard Module Support", + "type": "bool", + "defaultValue": false +}] diff --git a/src/Settings/AppSettings.cc b/src/Settings/AppSettings.cc index abfdfb4..ccc5905 100644 --- a/src/Settings/AppSettings.cc +++ b/src/Settings/AppSettings.cc @@ -87,6 +87,7 @@ DECLARE_SETTINGSFACT(AppSettings, followTarget) DECLARE_SETTINGSFACT(AppSettings, apmStartMavlinkStreams) DECLARE_SETTINGSFACT(AppSettings, enableTaisync) DECLARE_SETTINGSFACT(AppSettings, enableTaisyncVideo) +DECLARE_SETTINGSFACT(AppSettings, enableMicrohard) DECLARE_SETTINGSFACT_NO_FUNC(AppSettings, indoorPalette) { diff --git a/src/Settings/AppSettings.h b/src/Settings/AppSettings.h index 37784b9..bafb8c5 100644 --- a/src/Settings/AppSettings.h +++ b/src/Settings/AppSettings.h @@ -45,6 +45,7 @@ public: DEFINE_SETTINGFACT(followTarget) DEFINE_SETTINGFACT(enableTaisync) DEFINE_SETTINGFACT(enableTaisyncVideo) + DEFINE_SETTINGFACT(enableMicrohard) // Although this is a global setting it only affects ArduPilot vehicle since PX4 automatically starts the stream from the vehicle side DEFINE_SETTINGFACT(apmStartMavlinkStreams) diff --git a/src/api/QGCCorePlugin.cc b/src/api/QGCCorePlugin.cc index eeaa267..0a1a6dc 100644 --- a/src/api/QGCCorePlugin.cc +++ b/src/api/QGCCorePlugin.cc @@ -48,6 +48,10 @@ public: if(pTaisync) delete pTaisync; #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + if(pMicrohard) + delete pMicrohard; +#endif #if defined(QGC_AIRMAP_ENABLED) if(pAirmap) delete pAirmap; @@ -72,6 +76,9 @@ public: #if defined(QGC_GST_TAISYNC_ENABLED) QmlComponentInfo* pTaisync = nullptr; #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + QmlComponentInfo* pMicrohard = nullptr; +#endif #if defined(QGC_AIRMAP_ENABLED) QmlComponentInfo* pAirmap = nullptr; #endif @@ -140,6 +147,12 @@ QVariantList &QGCCorePlugin::settingsPages() QUrl::fromUserInput("")); _p->settingsList.append(QVariant::fromValue(reinterpret_cast(_p->pTaisync))); #endif +#if defined(QGC_GST_MICROHARD_ENABLED) + _p->pMicrohard = new QmlComponentInfo(tr("Microhard"), + QUrl::fromUserInput("qrc:/qml/MicrohardSettings.qml"), + QUrl::fromUserInput("")); + _p->settingsList.append(QVariant::fromValue(reinterpret_cast(_p->pMicrohard))); +#endif #if defined(QGC_AIRMAP_ENABLED) _p->pAirmap = new QmlComponentInfo(tr("AirMap"), QUrl::fromUserInput("qrc:/qml/AirmapSettings.qml"),