diff --git a/src/comm/LinkConfiguration.cc b/src/comm/LinkConfiguration.cc index de05037ff9aec117c1c3bd988be94c75d9071ae0..26d59990b579034ae5d8e87b2359fb3bc5580714 100644 --- a/src/comm/LinkConfiguration.cc +++ b/src/comm/LinkConfiguration.cc @@ -45,6 +45,7 @@ LinkConfiguration::LinkConfiguration(const QString& name) : _link(NULL) , _name(name) , _dynamic(false) + , _autoConnect(false) { _name = name; if (_name.isEmpty()) { @@ -57,6 +58,7 @@ LinkConfiguration::LinkConfiguration(LinkConfiguration* copy) _link = copy->link(); _name = copy->name(); _dynamic = copy->isDynamic(); + _autoConnect= copy->isAutoConnect(); Q_ASSERT(!_name.isEmpty()); } @@ -66,6 +68,7 @@ void LinkConfiguration::copyFrom(LinkConfiguration* source) _link = source->link(); _name = source->name(); _dynamic = source->isDynamic(); + _autoConnect= source->isAutoConnect(); } /*! diff --git a/src/comm/LinkConfiguration.h b/src/comm/LinkConfiguration.h index 7812c8cdaddf9cbbd48838d8b5ec9dac538fbddd..70761ff7370ed5e27d8b55ee33af5f7472329cc0 100644 --- a/src/comm/LinkConfiguration.h +++ b/src/comm/LinkConfiguration.h @@ -40,9 +40,11 @@ public: LinkConfiguration(LinkConfiguration* copy); virtual ~LinkConfiguration() {} - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(LinkInterface* link READ link WRITE setLink NOTIFY linkChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(LinkInterface* link READ link WRITE setLink NOTIFY linkChanged) Q_PROPERTY(LinkType linkType READ type CONSTANT) + Q_PROPERTY(bool dynamic READ isDynamic WRITE setDynamic NOTIFY dynamicChanged) + Q_PROPERTY(bool autoConnect READ isAutoConnect WRITE setAutoConnect NOTIFY autoConnectChanged) // Property accessors @@ -77,10 +79,22 @@ public: */ bool isDynamic() { return _dynamic; } + /*! + * + * Is this an Auto Connect configuration? + * @return True if this is an Auto Connect configuration (connects automatically at boot time). + */ + bool isAutoConnect() { return _autoConnect; } + /*! * Set if this is this a dynamic configuration. (decided at runtime) */ - void setDynamic(bool dynamic = true) { _dynamic = dynamic; } + void setDynamic(bool dynamic = true) { _dynamic = dynamic; emit dynamicChanged(); } + + /*! + * Set if this is this an Auto Connect configuration. + */ + void setAutoConnect(bool autoc = true) { _autoConnect = autoc; emit autoConnectChanged(); } /// Virtual Methods @@ -152,14 +166,17 @@ public: static LinkConfiguration* duplicateSettings(LinkConfiguration *source); signals: - void nameChanged(const QString& name); - void linkChanged(LinkInterface* link); + void nameChanged (const QString& name); + void linkChanged (LinkInterface* link); + void dynamicChanged (); + void autoConnectChanged (); protected: LinkInterface* _link; ///< Link currently using this configuration (if any) private: QString _name; - bool _dynamic; ///< A connection added automatically and not persistent (unless it's edited). + bool _dynamic; ///< A connection added automatically and not persistent (unless it's edited). + bool _autoConnect; ///< This connection is started automatically at boot }; #endif // LINKCONFIGURATION_H diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc index f7116385ee2a56c7feb2d835ef74a32759c48b8a..4b6ee1fa4df279a4d1998f0e1b5fbac792ddc5b2 100644 --- a/src/comm/LinkManager.cc +++ b/src/comm/LinkManager.cc @@ -300,17 +300,17 @@ void LinkManager::saveLinkConfigurationList() { QSettings settings; settings.remove(LinkConfiguration::settingsRoot()); - - for (int i=0; i<_linkConfigurations.count(); i++) { + int trueCount = 0; + for (int i = 0; i < _linkConfigurations.count(); i++) { LinkConfiguration* linkConfig = _linkConfigurations.value(i); - if (linkConfig) { if(!linkConfig->isDynamic()) { QString root = LinkConfiguration::settingsRoot(); - root += QString("/Link%1").arg(i); + root += QString("/Link%1").arg(trueCount++); settings.setValue(root + "/name", linkConfig->name()); settings.setValue(root + "/type", linkConfig->type()); + settings.setValue(root + "/auto", linkConfig->isAutoConnect()); // Have the instance save its own values linkConfig->saveSettings(settings, root); } @@ -318,17 +318,18 @@ void LinkManager::saveLinkConfigurationList() qWarning() << "Internal error"; } } - QString root(LinkConfiguration::settingsRoot()); - settings.setValue(root + "/count", _linkConfigurations.count()); - emit linkConfigurationChanged(); + settings.setValue(root + "/count", trueCount); + emit linkConfigurationsChanged(); } void LinkManager::loadLinkConfigurationList() { bool linksChanged = false; +#ifdef QT_DEBUG + bool mockPresent = false; +#endif QSettings settings; - // Is the group even there? if(settings.contains(LinkConfiguration::settingsRoot() + "/count")) { // Find out how many configurations we have @@ -338,12 +339,13 @@ void LinkManager::loadLinkConfigurationList() root += QString("/Link%1").arg(i); if(settings.contains(root + "/type")) { int type = settings.value(root + "/type").toInt(); - if(type < LinkConfiguration::TypeLast) { + if((LinkConfiguration::LinkType)type < LinkConfiguration::TypeLast) { if(settings.contains(root + "/name")) { QString name = settings.value(root + "/name").toString(); if(!name.isEmpty()) { LinkConfiguration* pLink = NULL; - switch(type) { + bool autoConnect = settings.value(root + "/auto").toBool(); + switch((LinkConfiguration::LinkType)type) { #ifndef __ios__ case LinkConfiguration::TypeSerial: pLink = (LinkConfiguration*)new SerialConfiguration(name); @@ -361,42 +363,48 @@ void LinkManager::loadLinkConfigurationList() #ifdef QT_DEBUG case LinkConfiguration::TypeMock: pLink = (LinkConfiguration*)new MockConfiguration(name); + mockPresent = true; break; #endif + default: + case LinkConfiguration::TypeLast: + break; } if(pLink) { - // Have the instance load its own values + //-- Have the instance load its own values + pLink->setAutoConnect(autoConnect); pLink->loadSettings(settings, root); _linkConfigurations.append(pLink); linksChanged = true; } } else { - qWarning() << "Link Configuration " << root << " has an empty name." ; + qWarning() << "Link Configuration" << root << "has an empty name." ; } } else { - qWarning() << "Link Configuration " << root << " has no name." ; + qWarning() << "Link Configuration" << root << "has no name." ; } } else { - qWarning() << "Link Configuration " << root << " an invalid type: " << type; + qWarning() << "Link Configuration" << root << "an invalid type: " << type; } } else { - qWarning() << "Link Configuration " << root << " has no type." ; + qWarning() << "Link Configuration" << root << "has no type." ; } } } - - // Debug buids always add MockLink automatically + // Debug buids always add MockLink automatically (if one is not already there) #ifdef QT_DEBUG - MockConfiguration* pMock = new MockConfiguration("Mock Link PX4"); - pMock->setDynamic(true); - _linkConfigurations.append(pMock); - linksChanged = true; + if(!mockPresent) + { + MockConfiguration* pMock = new MockConfiguration("Mock Link PX4"); + pMock->setDynamic(true); + _linkConfigurations.append(pMock); + linksChanged = true; + } #endif if(linksChanged) { - emit linkConfigurationChanged(); + emit linkConfigurationsChanged(); } - // Enable automatic Serial PX4/3DR Radio hunting _configurationsLoaded = true; } @@ -431,7 +439,6 @@ void LinkManager::_updateAutoConnectLinks(void) bool foundUDP = false; for (int i=0; i<_links.count(); i++) { LinkConfiguration* linkConfig = _links.value(i)->getLinkConfiguration(); - if (linkConfig->type() == LinkConfiguration::TypeUdp && linkConfig->name() == _defaultUPDLinkName) { foundUDP = true; break; @@ -442,7 +449,9 @@ void LinkManager::_updateAutoConnectLinks(void) UDPConfiguration* udpConfig = new UDPConfiguration(_defaultUPDLinkName); udpConfig->setLocalPort(QGC_UDP_LOCAL_PORT); udpConfig->setDynamic(true); + _linkConfigurations.append(udpConfig); createConnectedLink(udpConfig); + emit linkConfigurationsChanged(); } #ifndef __ios__ @@ -517,9 +526,7 @@ void LinkManager::_updateAutoConnectLinks(void) pSerialConfig->setBaud(boardType == QGCSerialPortInfo::BoardType3drRadio ? 57600 : 115200); pSerialConfig->setDynamic(true); pSerialConfig->setPortName(portInfo.systemLocation()); - _autoconnectConfigurations.append(pSerialConfig); - createConnectedLink(pSerialConfig); } } @@ -530,7 +537,6 @@ void LinkManager::_updateAutoConnectLinks(void) QList _confToDelete; for (int i=0; i<_autoconnectConfigurations.count(); i++) { SerialConfiguration* linkConfig = _autoconnectConfigurations.value(i); - if (linkConfig) { if (!currentPorts.contains(linkConfig->portName())) { // We don't remove links which are still connected even though at this point the cable may @@ -696,19 +702,36 @@ QStringList LinkManager::linkTypeStrings(void) const return list; } -QStringList LinkManager::serialPortStrings(void) +void LinkManager::_updateSerialPorts() { + _commPortList.clear(); + _commPortDisplayList.clear(); #ifndef __ios__ - if(!_commPortList.size()) + QList portList = QSerialPortInfo::availablePorts(); + foreach (const QSerialPortInfo &info, portList) { - QList portList = QSerialPortInfo::availablePorts(); - foreach (const QSerialPortInfo &info, portList) - { - QString name = info.portName(); - _commPortList += name; - } + QString port = info.systemLocation().trimmed(); + _commPortList += port; + _commPortDisplayList += SerialConfiguration::cleanPortDisplayname(port); } #endif +} + +QStringList LinkManager::serialPortStrings(void) +{ + if(!_commPortDisplayList.size()) + { + _updateSerialPorts(); + } + return _commPortDisplayList; +} + +QStringList LinkManager::serialPorts(void) +{ + if(!_commPortList.size()) + { + _updateSerialPorts(); + } return _commPortList; } @@ -722,6 +745,110 @@ QStringList LinkManager::serialBaudRates(void) #endif } +bool LinkManager::endConfigurationEditing(LinkConfiguration* config, LinkConfiguration* editedConfig) +{ + Q_ASSERT(config != NULL); + Q_ASSERT(editedConfig != NULL); + _fixUnnamed(editedConfig); + config->copyFrom(editedConfig); + saveLinkConfigurationList(); + // Tell link about changes (if any) + config->updateSettings(); + // Discard temporary duplicate + delete editedConfig; + return true; +} + +bool LinkManager::endCreateConfiguration(LinkConfiguration* config) +{ + Q_ASSERT(config != NULL); + _fixUnnamed(config); + _linkConfigurations.append(config); + saveLinkConfigurationList(); + return true; +} + +LinkConfiguration* LinkManager::createConfiguration(int type, const QString& name) +{ + if((LinkConfiguration::LinkType)type == LinkConfiguration::TypeSerial) + _updateSerialPorts(); + return LinkConfiguration::createSettings(type, name); +} + +LinkConfiguration* LinkManager::startConfigurationEditing(LinkConfiguration* config) +{ + Q_ASSERT(config != NULL); + if(config->type() == LinkConfiguration::TypeSerial) + _updateSerialPorts(); + return LinkConfiguration::duplicateSettings(config); +} + + +void LinkManager::_fixUnnamed(LinkConfiguration* config) +{ + Q_ASSERT(config != NULL); + //-- Check for "Unnamed" + if (config->name() == "Unnamed") { + switch(config->type()) { +#ifndef __ios__ + case LinkConfiguration::TypeSerial: { + QString tname = dynamic_cast(config)->portName(); +#ifdef Q_OS_WIN32 + tname.replace("\\\\.\\", ""); +#else + tname.replace("/dev/cu.", ""); + tname.replace("/dev/", ""); +#endif + config->setName(QString("Serial Device on %1").arg(tname)); + break; + } +#endif + case LinkConfiguration::TypeUdp: + config->setName( + QString("UDP Link on Port %1").arg(dynamic_cast(config)->localPort())); + break; + case LinkConfiguration::TypeTcp: { + TCPConfiguration* tconfig = dynamic_cast(config); + if(tconfig) { + config->setName( + QString("TCP Link %1:%2").arg(tconfig->address().toString()).arg((int)tconfig->port())); + } + } + break; + case LinkConfiguration::TypeLogReplay: { + LogReplayLinkConfiguration* tconfig = dynamic_cast(config); + if(tconfig) { + config->setName(QString("Log Replay %1").arg(tconfig->logFilenameShort())); + } + } + break; +#ifdef QT_DEBUG + case LinkConfiguration::TypeMock: + config->setName( + QString("Mock Link")); + break; +#endif + case LinkConfiguration::TypeLast: + default: + break; + } + } +} + +void LinkManager::removeConfiguration(LinkConfiguration* config) +{ + Q_ASSERT(config != NULL); + LinkInterface* iface = config->link(); + if(iface) { + disconnectLink(iface); + } + // Remove configuration + _linkConfigurations.removeOne(config); + delete config; + // Save list + saveLinkConfigurationList(); +} + bool LinkManager::isAutoconnectLink(LinkInterface* link) { return _autoconnectConfigurations.contains(link->getLinkConfiguration()); diff --git a/src/comm/LinkManager.h b/src/comm/LinkManager.h index f38a4085ce1dece55bf9a178c6ba34d7c5bfe1a9..f3a38f8b97da3bf588fd62d90853604eecbdb7a6 100644 --- a/src/comm/LinkManager.h +++ b/src/comm/LinkManager.h @@ -80,15 +80,25 @@ public: Q_PROPERTY(bool autoconnectPX4Flow READ autoconnectPX4Flow WRITE setAutoconnectPX4Flow NOTIFY autoconnectPX4FlowChanged) /// LinkInterface Accessor - Q_PROPERTY(QmlObjectListModel* links READ links CONSTANT) + Q_PROPERTY(QmlObjectListModel* links READ links CONSTANT) /// LinkConfiguration Accessor - Q_PROPERTY(QmlObjectListModel* linkConfigurations READ linkConfigurations CONSTANT) + Q_PROPERTY(QmlObjectListModel* linkConfigurations READ linkConfigurations NOTIFY linkConfigurationsChanged) /// List of comm type strings - Q_PROPERTY(QStringList linkTypeStrings READ linkTypeStrings CONSTANT) + Q_PROPERTY(QStringList linkTypeStrings READ linkTypeStrings CONSTANT) /// List of supported baud rates for serial links - Q_PROPERTY(QStringList serialBaudRates READ serialBaudRates CONSTANT) + Q_PROPERTY(QStringList serialBaudRates READ serialBaudRates CONSTANT) + /// List of comm ports display names + Q_PROPERTY(QStringList serialPortStrings READ serialPortStrings NOTIFY commPortStringsChanged) /// List of comm ports - Q_PROPERTY(QStringList serialPortStrings READ serialPortStrings NOTIFY commPortStringsChanged) + Q_PROPERTY(QStringList serialPorts READ serialPorts NOTIFY commPortsChanged) + + // Create/Edit Link Configuration + Q_INVOKABLE LinkConfiguration* createConfiguration (int type, const QString& name); + Q_INVOKABLE LinkConfiguration* startConfigurationEditing (LinkConfiguration* config); + Q_INVOKABLE void cancelConfigurationEditing (LinkConfiguration* config) { delete config; } + Q_INVOKABLE bool endConfigurationEditing (LinkConfiguration* config, LinkConfiguration* editedConfig); + Q_INVOKABLE bool endCreateConfiguration (LinkConfiguration* config); + Q_INVOKABLE void removeConfiguration (LinkConfiguration* config); // Property accessors @@ -104,6 +114,7 @@ public: QStringList linkTypeStrings (void) const; QStringList serialBaudRates (void); QStringList serialPortStrings (void); + QStringList serialPorts (void); void setAutoconnectUDP (bool autoconnect); void setAutoconnectPixhawk (bool autoconnect); @@ -189,8 +200,9 @@ signals: // No longer hearing from any vehicles on this link. void linkInactive(LinkInterface* link); - void linkConfigurationChanged(); void commPortStringsChanged(); + void commPortsChanged(); + void linkConfigurationsChanged(); private slots: void _linkConnected(void); @@ -200,6 +212,8 @@ private slots: private: bool _connectionsSuspendedMsg(void); void _updateAutoConnectLinks(void); + void _updateSerialPorts(); + void _fixUnnamed(LinkConfiguration* config); #ifndef __ios__ SerialConfiguration* _autoconnectConfigurationsContainsPort(const QString& portName); @@ -221,6 +235,7 @@ private: QMap _autoconnectWaitList; ///< key: QGCSerialPortInfo.systemLocation, value: wait count QStringList _commPortList; + QStringList _commPortDisplayList; bool _autoconnectUDP; bool _autoconnectPixhawk; diff --git a/src/comm/SerialLink.cc b/src/comm/SerialLink.cc index e1d06a33897f50568443eb626d00fc5a2cb09153..308537e700f8abae81af54c6975a3aa7138c3a09 100644 --- a/src/comm/SerialLink.cc +++ b/src/comm/SerialLink.cc @@ -400,12 +400,13 @@ SerialConfiguration::SerialConfiguration(const QString& name) : LinkConfiguratio SerialConfiguration::SerialConfiguration(SerialConfiguration* copy) : LinkConfiguration(copy) { - _baud = copy->baud(); - _flowControl= copy->flowControl(); - _parity = copy->parity(); - _dataBits = copy->dataBits(); - _stopBits = copy->stopBits(); - _portName = copy->portName(); + _baud = copy->baud(); + _flowControl = copy->flowControl(); + _parity = copy->parity(); + _dataBits = copy->dataBits(); + _stopBits = copy->stopBits(); + _portName = copy->portName(); + _portDisplayName = copy->portDisplayName(); } void SerialConfiguration::copyFrom(LinkConfiguration *source) @@ -413,12 +414,13 @@ void SerialConfiguration::copyFrom(LinkConfiguration *source) LinkConfiguration::copyFrom(source); SerialConfiguration* ssource = dynamic_cast(source); Q_ASSERT(ssource != NULL); - _baud = ssource->baud(); - _flowControl= ssource->flowControl(); - _parity = ssource->parity(); - _dataBits = ssource->dataBits(); - _stopBits = ssource->stopBits(); - _portName = ssource->portName(); + _baud = ssource->baud(); + _flowControl = ssource->flowControl(); + _parity = ssource->parity(); + _dataBits = ssource->dataBits(); + _stopBits = ssource->stopBits(); + _portName = ssource->portName(); + _portDisplayName = ssource->portDisplayName(); } void SerialConfiguration::updateSettings() @@ -462,30 +464,45 @@ void SerialConfiguration::setPortName(const QString& portName) QString pname = portName.trimmed(); if (!pname.isEmpty() && pname != _portName) { _portName = pname; + _portDisplayName = cleanPortDisplayname(pname); } } +QString SerialConfiguration::cleanPortDisplayname(const QString name) +{ + QString pname = name.trimmed(); +#ifdef Q_OS_WIN32 + pname.replace("\\\\.\\", ""); +#else + pname.replace("/dev/cu.", ""); + pname.replace("/dev/", ""); +#endif + return pname; +} + void SerialConfiguration::saveSettings(QSettings& settings, const QString& root) { settings.beginGroup(root); - settings.setValue("baud", _baud); - settings.setValue("dataBits", _dataBits); - settings.setValue("flowControl", _flowControl); - settings.setValue("stopBits", _stopBits); - settings.setValue("parity", _parity); - settings.setValue("portName", _portName); + settings.setValue("baud", _baud); + settings.setValue("dataBits", _dataBits); + settings.setValue("flowControl", _flowControl); + settings.setValue("stopBits", _stopBits); + settings.setValue("parity", _parity); + settings.setValue("portName", _portName); + settings.setValue("portDisplayName",_portDisplayName); settings.endGroup(); } void SerialConfiguration::loadSettings(QSettings& settings, const QString& root) { settings.beginGroup(root); - if(settings.contains("baud")) _baud = settings.value("baud").toInt(); - if(settings.contains("dataBits")) _dataBits = settings.value("dataBits").toInt(); - if(settings.contains("flowControl")) _flowControl = settings.value("flowControl").toInt(); - if(settings.contains("stopBits")) _stopBits = settings.value("stopBits").toInt(); - if(settings.contains("parity")) _parity = settings.value("parity").toInt(); - if(settings.contains("portName")) _portName = settings.value("portName").toString(); + if(settings.contains("baud")) _baud = settings.value("baud").toInt(); + if(settings.contains("dataBits")) _dataBits = settings.value("dataBits").toInt(); + if(settings.contains("flowControl")) _flowControl = settings.value("flowControl").toInt(); + if(settings.contains("stopBits")) _stopBits = settings.value("stopBits").toInt(); + if(settings.contains("parity")) _parity = settings.value("parity").toInt(); + if(settings.contains("portName")) _portName = settings.value("portName").toString(); + if(settings.contains("portDisplayName"))_portDisplayName= settings.value("portDisplayName").toString(); settings.endGroup(); } diff --git a/src/comm/SerialLink.h b/src/comm/SerialLink.h index d9ab7faad2c9175d50f571bcc3afee3d876a864a..dadc4f73a8742a664729a32bb9816f90c99c190a 100644 --- a/src/comm/SerialLink.h +++ b/src/comm/SerialLink.h @@ -66,22 +66,32 @@ public: SerialConfiguration(const QString& name); SerialConfiguration(SerialConfiguration* copy); + Q_PROPERTY(int baud READ baud WRITE setBaud NOTIFY baudChanged) + Q_PROPERTY(int dataBits READ dataBits WRITE setDataBits NOTIFY dataBitsChanged) + Q_PROPERTY(int flowControl READ flowControl WRITE setFlowControl NOTIFY flowControlChanged) + Q_PROPERTY(int stopBits READ stopBits WRITE setStopBits NOTIFY stopBitsChanged) + Q_PROPERTY(int parity READ parity WRITE setParity NOTIFY parityChanged) + Q_PROPERTY(QString portName READ portName WRITE setPortName NOTIFY portNameChanged) + Q_PROPERTY(QString portDisplayName READ portDisplayName NOTIFY portDisplayNameChanged) + int baud() { return _baud; } int dataBits() { return _dataBits; } int flowControl() { return _flowControl; } ///< QSerialPort Enums int stopBits() { return _stopBits; } int parity() { return _parity; } ///< QSerialPort Enums - const QString portName() { return _portName; } + const QString portName () { return _portName; } + const QString portDisplayName () { return _portDisplayName; } - void setBaud (int baud); - void setDataBits (int databits); - void setFlowControl (int flowControl); ///< QSerialPort Enums - void setStopBits (int stopBits); - void setParity (int parity); ///< QSerialPort Enums - void setPortName (const QString& portName); + void setBaud (int baud); + void setDataBits (int databits); + void setFlowControl (int flowControl); ///< QSerialPort Enums + void setStopBits (int stopBits); + void setParity (int parity); ///< QSerialPort Enums + void setPortName (const QString& portName); static QStringList supportedBaudRates(); + static QString cleanPortDisplayname(const QString name); /// From LinkConfiguration LinkType type() { return LinkConfiguration::TypeSerial; } @@ -90,6 +100,15 @@ public: void saveSettings(QSettings& settings, const QString& root); void updateSettings(); +signals: + void baudChanged (); + void dataBitsChanged (); + void flowControlChanged (); + void stopBitsChanged (); + void parityChanged (); + void portNameChanged (); + void portDisplayNameChanged (); + private: static void _initBaudRates(); @@ -100,9 +119,9 @@ private: int _stopBits; int _parity; QString _portName; + QString _portDisplayName; }; - /** * @brief The SerialLink class provides cross-platform access to serial links. * It takes care of the link management and provides a common API to higher diff --git a/src/ui/preferences/LinkSettings.qml b/src/ui/preferences/LinkSettings.qml index b54499c86e788f0daed5b9d284049dd673be58ac..c2b297cdb53749a72a5291e1972ae23b86cd6c62 100644 --- a/src/ui/preferences/LinkSettings.qml +++ b/src/ui/preferences/LinkSettings.qml @@ -23,6 +23,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.1 import QGroundControl 1.0 import QGroundControl.Controls 1.0 @@ -92,7 +93,7 @@ Rectangle { text: object.name width: _linkRoot.width * 0.5 exclusiveGroup: linkGroup - anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenter: settingsColumn.horizontalCenter onClicked: { checked = true _currentSelection = object @@ -111,8 +112,26 @@ Rectangle { QGCButton { width: ScreenTools.defaultFontPixelWidth * 10 text: "Delete" - enabled: _currentSelection && !_currentSelection.link + enabled: _currentSelection && !_currentSelection.dynamic onClicked: { + if(_currentSelection) + deleteDialog.visible = true + } + MessageDialog { + id: deleteDialog + visible: false + icon: StandardIcon.Warning + standardButtons: StandardButton.Yes | StandardButton.No + title: "Remove Link Configuration" + text: _currentSelection ? "Remove " + _currentSelection.name + ". Is this really what you want?" : "" + onYes: { + if(_currentSelection) + QGroundControl.linkManager.removeConfiguration(_currentSelection) + deleteDialog.visible = false + } + onNo: { + deleteDialog.visible = false + } } } QGCButton { @@ -154,6 +173,7 @@ Rectangle { anchors.fill: parent visible: false property var linkConfig: null + property var editConfig: null } //--------------------------------------------- @@ -163,6 +183,24 @@ Rectangle { Rectangle { color: __qgcPal.window anchors.fill: parent + Component.onCompleted: { + // If editing, create copy for editing + if(linkConfig) { + editConfig = QGroundControl.linkManager.startConfigurationEditing(linkConfig) + } else { + // Create new link configuration + if(ScreenTools.isiOS) + editConfig = QGroundControl.linkManager.createConfiguration(LinkConfiguration.TypeUdp, "Unnamed") + else + editConfig = QGroundControl.linkManager.createConfiguration(LinkConfiguration.TypeSerial, "Unnamed") + } + } + Component.onDestruction: { + if(editConfig) { + QGroundControl.linkManager.cancelConfigurationEditing(editConfig) + editConfig = null + } + } Flickable { clip: true anchors.top: parent.top @@ -199,7 +237,8 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter } QGCTextField { - text: linkConfig ? linkConfig.name : "Untitled" + id: nameField + text: editConfig ? editConfig.name : "" width: _secondColumn anchors.verticalCenter: parent.verticalCenter } @@ -220,8 +259,17 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter Component.onCompleted: { if(linkConfig != null) { - if(linkConfig.linkType === LinkConfiguration.TypeSerial) + var index = linkConfig.linkType + if(index === LinkConfiguration.TypeSerial) linkSettingLoader.sourceComponent = serialLinkSettings + if(index === LinkConfiguration.TypeUdp) + linkSettingLoader.sourceComponent = udpLinkSettings + if(index === LinkConfiguration.TypeTcp) + linkSettingLoader.sourceComponent = tcpLinkSettings + if(index === LinkConfiguration.TypeMock) + linkSettingLoader.sourceComponent = mockLinkSettings + if(index === LinkConfiguration.TypeLogReplay) + linkSettingLoader.sourceComponent = logLinkSettings linkSettingLoader.visible = true } } @@ -235,7 +283,14 @@ Rectangle { model: QGroundControl.linkManager.linkTypeStrings anchors.verticalCenter: parent.verticalCenter onActivated: { - if (index != -1) { + if (index != -1 && index !== editConfig.linkType) { + // Save current name + var name = editConfig.name + // Discard link configuration (old type) + QGroundControl.linkManager.cancelConfigurationEditing(editConfig) + // Create new link configuration + editConfig = QGroundControl.linkManager.createConfiguration(index, name) + // Load appropriate configuration panel linkSettingLoader.sourceComponent = null if(index === LinkConfiguration.TypeSerial) linkSettingLoader.sourceComponent = serialLinkSettings @@ -252,12 +307,40 @@ Rectangle { Component.onCompleted: { if(linkConfig == null) { linkTypeCombo.currentIndex = 0 - linkSettingLoader.sourceComponent = serialLinkSettings + var index = editConfig.linkType + if(index === LinkConfiguration.TypeSerial) + linkSettingLoader.sourceComponent = serialLinkSettings + if(index === LinkConfiguration.TypeUdp) + linkSettingLoader.sourceComponent = udpLinkSettings + if(index === LinkConfiguration.TypeTcp) + linkSettingLoader.sourceComponent = tcpLinkSettings + if(index === LinkConfiguration.TypeMock) + linkSettingLoader.sourceComponent = mockLinkSettings + if(index === LinkConfiguration.TypeLogReplay) + linkSettingLoader.sourceComponent = logLinkSettings linkSettingLoader.visible = true } } } } + Item { + height: ScreenTools.defaultFontPixelHeight * 0.5 + width: parent.width + } + //-- Auto Connect + QGCCheckBox { + text: "Automatically Connect on Start" + checked: false + onCheckedChanged: { + if(editConfig) { + editConfig.autoConnect = checked + } + } + Component.onCompleted: { + if(editConfig) + checked = editConfig.autoConnect + } + } Item { height: ScreenTools.defaultFontPixelHeight width: parent.width @@ -266,7 +349,7 @@ Rectangle { id: linkSettingLoader width: parent.width visible: false - property var config: linkConfig + property var subEditConfig: editConfig } } } @@ -279,7 +362,19 @@ Rectangle { QGCButton { width: ScreenTools.defaultFontPixelWidth * 10 text: "OK" + //-- TODO: For now, only allow Serial (the only one completed) + enabled: editConfig && editConfig.linkType === LinkConfiguration.TypeSerial onClicked: { + // Save editting + editConfig.name = nameField.text + if(linkConfig) { + QGroundControl.linkManager.endConfigurationEditing(linkConfig, editConfig) + } else { + // If it was edited, it's no longer "dynamic" + editConfig.dynamic = false + QGroundControl.linkManager.endCreateConfiguration(editConfig) + } + editConfig = null _linkRoot.closeCommSettings() } } @@ -287,6 +382,8 @@ Rectangle { width: ScreenTools.defaultFontPixelWidth * 10 text: "Cancel" onClicked: { + QGroundControl.linkManager.cancelConfigurationEditing(editConfig) + editConfig = null _linkRoot.closeCommSettings() } } @@ -298,7 +395,7 @@ Rectangle { Component { id: serialLinkSettings Column { - width: parent.width + width: serialLinkSettings.width spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { id: serialLabel @@ -327,10 +424,21 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter onActivated: { if (index != -1) { + subEditConfig.portName = QGroundControl.linkManager.serialPorts[index] } } Component.onCompleted: { - if(config != null) { + if(subEditConfig != null) { + if(subEditConfig.portDisplayName === "") + subEditConfig.portName = QGroundControl.linkManager.serialPorts[0] + var index = commPortCombo.find(subEditConfig.portDisplayName) + if (index === -1) { + console.warn("Serial Port not present", subEditConfig.portName) + } else { + commPortCombo.currentIndex = index + } + } else { + commPortCombo.currentIndex = 0 } } } @@ -349,15 +457,16 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter onActivated: { if (index != -1) { + subEditConfig.baud = parseInt(QGroundControl.linkManager.serialBaudRates[index]) } } Component.onCompleted: { var baud = "57600" - if(config != null) { - // Get baud from config + if(subEditConfig != null) { + baud = subEditConfig.baud.toString() } var index = baudCombo.find(baud) - if (index == -1) { + if (index === -1) { console.warn("Baud rate name not in combo box", baud) } else { baudCombo.currentIndex = index @@ -365,6 +474,128 @@ Rectangle { } } } + Item { + height: ScreenTools.defaultFontPixelHeight / 2 + width: parent.width + } + //----------------------------------------------------------------- + //-- Advanced Serial Settings + QGCCheckBox { + id: showAdvanced + text: "Show Advanced Serial Settings" + } + Item { + height: ScreenTools.defaultFontPixelHeight / 2 + width: parent.width + } + //-- Flow Control + QGCCheckBox { + text: "Enable Flow Control" + checked: subEditConfig ? subEditConfig.flowControl !== 0 : false + visible: showAdvanced.checked + onCheckedChanged: { + if(subEditConfig) { + subEditConfig.flowControl = checked ? 1 : 0 + } + } + } + //-- Parity + Row { + spacing: ScreenTools.defaultFontPixelWidth + visible: showAdvanced.checked + QGCLabel { + text: "Parity:" + width: _firstColumn + anchors.verticalCenter: parent.verticalCenter + } + QGCComboBox { + id: parityCombo + width: _firstColumn + model: ["None", "Even", "Odd"] + anchors.verticalCenter: parent.verticalCenter + onActivated: { + if (index != -1) { + // Hard coded values from qserialport.h + if(index == 0) + subEditConfig.parity = 0 + else if(index == 1) + subEditConfig.parity = 2 + else + subEditConfig.parity = 3 + } + } + Component.onCompleted: { + var index = 0 + if(subEditConfig != null) { + index = subEditConfig.parity + } + if(index > 1) { + index = index - 2 + } + parityCombo.currentIndex = index + } + } + } + //-- Data Bits + Row { + spacing: ScreenTools.defaultFontPixelWidth + visible: showAdvanced.checked + QGCLabel { + text: "Data Bits:" + width: _firstColumn + anchors.verticalCenter: parent.verticalCenter + } + QGCComboBox { + id: dataCombo + width: _firstColumn + model: ["5", "6", "7", "8"] + anchors.verticalCenter: parent.verticalCenter + onActivated: { + if (index != -1) { + subEditConfig.dataBits = index + 5 + } + } + Component.onCompleted: { + var index = 3 + if(subEditConfig != null) { + index = subEditConfig.parity - 5 + if(index < 0) + index = 3 + } + dataCombo.currentIndex = index + } + } + } + //-- Stop Bits + Row { + spacing: ScreenTools.defaultFontPixelWidth + visible: showAdvanced.checked + QGCLabel { + text: "Stop Bits:" + width: _firstColumn + anchors.verticalCenter: parent.verticalCenter + } + QGCComboBox { + id: stopCombo + width: _firstColumn + model: ["1", "2"] + anchors.verticalCenter: parent.verticalCenter + onActivated: { + if (index != -1) { + subEditConfig.stopBits = index + 1 + } + } + Component.onCompleted: { + var index = 0 + if(subEditConfig != null) { + index = subEditConfig.stopBits - 1 + if(index < 0) + index = 0 + } + stopCombo.currentIndex = index + } + } + } } } //--------------------------------------------- @@ -372,7 +603,7 @@ Rectangle { Component { id: udpLinkSettings Column { - width: parent.width + width: udpLinkSettings.width spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { id: udpLabel @@ -408,7 +639,7 @@ Rectangle { Component { id: tcpLinkSettings Column { - width: parent.width + width: tcpLinkSettings.width spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { id: tcpLabel @@ -452,7 +683,7 @@ Rectangle { Component { id: logLinkSettings Column { - width: parent.width + width: logLinkSettings.width spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { text: "Log Replay Link Settings" @@ -471,7 +702,7 @@ Rectangle { Component { id: mockLinkSettings Column { - width: parent.width + width: mockLinkSettings.width spacing: ScreenTools.defaultFontPixelHeight / 2 QGCLabel { text: "Mock Link Settings"