diff --git a/src/QGCConfig.h b/src/QGCConfig.h index 07ae9ac8e9cf60c463c59b78767c908a1aaebaeb..0d8f0754f669caea32357ec5a6db28b09cbbb9e7 100644 --- a/src/QGCConfig.h +++ b/src/QGCConfig.h @@ -12,7 +12,7 @@ // If you need to make an incompatible changes to stored settings, bump this version number // up by 1. This will caused store settings to be cleared on next boot. -#define QGC_SETTINGS_VERSION 5 +#define QGC_SETTINGS_VERSION 6 #define QGC_APPLICATION_NAME "QGroundControl" #define QGC_ORG_NAME "QGroundControl.org" diff --git a/src/comm/LinkConfiguration.cc b/src/comm/LinkConfiguration.cc index 57ee6c929496a9ede30825fd3b12c79f185d718c..b3a351d456346fa4aedf84014976a5f2b36cc701 100644 --- a/src/comm/LinkConfiguration.cc +++ b/src/comm/LinkConfiguration.cc @@ -40,6 +40,7 @@ This file is part of the QGROUNDCONTROL project LinkConfiguration::LinkConfiguration(const QString& name) : _preferred(false) + , _dynamic(false) { _link = NULL; _name = name; @@ -48,18 +49,20 @@ LinkConfiguration::LinkConfiguration(const QString& name) LinkConfiguration::LinkConfiguration(LinkConfiguration* copy) { - _link = copy->getLink(); - _name = copy->name(); - _preferred = copy->isPreferred(); + _link = copy->getLink(); + _name = copy->name(); + _preferred = copy->isPreferred(); + _dynamic = copy->isDynamic(); Q_ASSERT(!_name.isEmpty()); } void LinkConfiguration::copyFrom(LinkConfiguration* source) { Q_ASSERT(source != NULL); - _link = source->getLink(); - _name = source->name(); - _preferred = source->isPreferred(); + _link = source->getLink(); + _name = source->name(); + _preferred = source->isPreferred(); + _dynamic = source->isDynamic(); } /*! diff --git a/src/comm/LinkConfiguration.h b/src/comm/LinkConfiguration.h index 1216d40487d8e1d9ca36a04ce184594e59249de8..dd836e73db9ecd87016fc4814b690e762265ba06 100644 --- a/src/comm/LinkConfiguration.h +++ b/src/comm/LinkConfiguration.h @@ -97,6 +97,18 @@ public: */ void setPreferred(bool preferred = true) { _preferred = preferred; } + /*! + * + * Is this a dynamic configuration? (non persistent) + * @return True if this is an automatically added configuration. + */ + bool isDynamic() { return _dynamic; } + + /*! + * Set if this is this a dynamic configuration. (decided at runtime) + */ + void setDynamic(bool dynamic = true) { _dynamic = dynamic; } + /// Virtual Methods /*! @@ -171,6 +183,7 @@ protected: private: QString _name; bool _preferred; ///< Determined internally if this is a preferred connection. It comes up first in the drop down box. + bool _dynamic; ///< A connection added automatically and not persistent (unless it's edited). }; #endif // LINKCONFIGURATION_H diff --git a/src/comm/LinkManager.cc b/src/comm/LinkManager.cc index 5210aa27bb19260e9dce308975fa5666bd141c8c..91e63ed5c20ee97ad6ffeb7360db866f2b2cd3d9 100644 --- a/src/comm/LinkManager.cc +++ b/src/comm/LinkManager.cc @@ -325,19 +325,22 @@ void LinkManager::saveLinkConfigurationList() { QSettings settings; settings.remove(LinkConfiguration::settingsRoot()); - QString root(LinkConfiguration::settingsRoot()); - settings.setValue(root + "/count", _linkConfigurations.count()); int index = 0; foreach (LinkConfiguration* pLink, _linkConfigurations) { Q_ASSERT(pLink != NULL); - root = LinkConfiguration::settingsRoot(); - root += QString("/Link%1").arg(index++); - settings.setValue(root + "/name", pLink->name()); - settings.setValue(root + "/type", pLink->type()); - settings.setValue(root + "/preferred", pLink->isPreferred()); - // Have the instance save its own values - pLink->saveSettings(settings, root); + if(!pLink->isDynamic()) + { + QString root = LinkConfiguration::settingsRoot(); + root += QString("/Link%1").arg(index++); + settings.setValue(root + "/name", pLink->name()); + settings.setValue(root + "/type", pLink->type()); + settings.setValue(root + "/preferred", pLink->isPreferred()); + // Have the instance save its own values + pLink->saveSettings(settings, root); + } } + QString root(LinkConfiguration::settingsRoot()); + settings.setValue(root + "/count", index); emit linkConfigurationChanged(); } @@ -427,6 +430,7 @@ void LinkManager::_updateConfigurationList(void) return; } bool saveList = false; + QStringList currentPorts; QList portList = QSerialPortInfo::availablePorts(); // Iterate Comm Ports foreach (QSerialPortInfo portInfo, portList) { @@ -439,6 +443,8 @@ void LinkManager::_updateConfigurationList(void) qDebug() << "serialNumber: " << portInfo.serialNumber(); qDebug() << "vendorIdentifier: " << portInfo.vendorIdentifier(); #endif + // Save port name + currentPorts << portInfo.systemLocation(); // Is this a PX4? if (portInfo.vendorIdentifier() == 9900) { SerialConfiguration* pSerial = _findSerialConfiguration(portInfo.systemLocation()); @@ -451,6 +457,7 @@ void LinkManager::_updateConfigurationList(void) } else { // Lets create a new Serial configuration automatically pSerial = new SerialConfiguration(QString("Pixhawk on %1").arg(portInfo.portName().trimmed())); + pSerial->setDynamic(true); pSerial->setPreferred(true); pSerial->setBaud(115200); pSerial->setPortName(portInfo.systemLocation()); @@ -458,6 +465,45 @@ void LinkManager::_updateConfigurationList(void) saveList = true; } } + // Is this an FTDI Chip? It could be a 3DR Modem + if (portInfo.vendorIdentifier() == 1027) { + SerialConfiguration* pSerial = _findSerialConfiguration(portInfo.systemLocation()); + if (pSerial) { + //-- If this port is configured make sure it has the preferred flag set, unless someone else already has it set. + if(!pSerial->isPreferred() && !saveList) { + pSerial->setPreferred(true); + saveList = true; + } + } else { + // Lets create a new Serial configuration automatically (an assumption at best) + pSerial = new SerialConfiguration(QString("3DR Radio on %1").arg(portInfo.portName().trimmed())); + pSerial->setDynamic(true); + pSerial->setPreferred(true); + pSerial->setBaud(57600); + pSerial->setPortName(portInfo.systemLocation()); + addLinkConfiguration(pSerial); + saveList = true; + } + } + } + // Now we go through the current configuration list and make sure any dynamic config has gone away + QList _confToDelete; + foreach (LinkConfiguration* pLink, _linkConfigurations) { + Q_ASSERT(pLink != NULL); + // We only care about dynamic links + if(pLink->isDynamic()) { + if(pLink->type() == LinkConfiguration::TypeSerial) { + SerialConfiguration* pSerial = dynamic_cast(pLink); + if(!currentPorts.contains(pSerial->portName())) { + _confToDelete.append(pSerial); + } + } + } + } + // Now remove all links that are gone + foreach (LinkConfiguration* pDelete, _confToDelete) { + removeLinkConfiguration(pDelete); + saveList = true; } // Save configuration list, which will also trigger a signal for the UI if(saveList) { @@ -468,28 +514,24 @@ void LinkManager::_updateConfigurationList(void) bool LinkManager::containsLink(LinkInterface* link) { bool found = false; - foreach (SharedLinkInterface sharedLink, _links) { if (sharedLink.data() == link) { found = true; break; } } - return found; } bool LinkManager::anyConnectedLinks(void) { bool found = false; - foreach (SharedLinkInterface sharedLink, _links) { if (sharedLink.data()->isConnected()) { found = true; break; } } - return found; } @@ -500,7 +542,6 @@ SharedLinkInterface& LinkManager::sharedPointerForLink(LinkInterface* link) return _links[i]; } } - // This should never happen Q_ASSERT(false); return _nullSharedLink; diff --git a/src/ui/SerialConfigurationWindow.cc b/src/ui/SerialConfigurationWindow.cc index ddefb2d845faa7bffbda0578a79745f26485c926..4b04dc9a207aa83f5320bb3f33c3e380e6d1bac0 100644 --- a/src/ui/SerialConfigurationWindow.cc +++ b/src/ui/SerialConfigurationWindow.cc @@ -215,21 +215,35 @@ bool SerialConfigurationWindow::setupPortList() void SerialConfigurationWindow::enableFlowControl(bool flow) { _config->setFlowControl(flow ? QSerialPort::HardwareControl : QSerialPort::NoFlowControl); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); } void SerialConfigurationWindow::setParityNone(bool accept) { - if (accept) _config->setParity(QSerialPort::NoParity); + if (accept) { + _config->setParity(QSerialPort::NoParity); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); + } } void SerialConfigurationWindow::setParityOdd(bool accept) { - if (accept) _config->setParity(QSerialPort::OddParity); + if (accept) { + _config->setParity(QSerialPort::OddParity); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); + } } void SerialConfigurationWindow::setParityEven(bool accept) { - if (accept) _config->setParity(QSerialPort::EvenParity); + if (accept) { + _config->setParity(QSerialPort::EvenParity); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); + } } void SerialConfigurationWindow::setPortName(int index) @@ -238,6 +252,8 @@ void SerialConfigurationWindow::setPortName(int index) QString pname = _ui.portName->itemData(index).toString(); if (_config->portName() != pname) { _config->setPortName(pname); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); } } @@ -245,14 +261,20 @@ void SerialConfigurationWindow::setBaudRate(int index) { int baud = _ui.baudRate->itemData(index).toInt(); _config->setBaud(baud); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); } void SerialConfigurationWindow::setDataBits(int bits) { _config->setDataBits(bits); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); } void SerialConfigurationWindow::setStopBits(int bits) { _config->setStopBits(bits); + //-- If this was dynamic, it's now edited and persistent + _config->setDynamic(false); } diff --git a/src/ui/toolbar/MainToolBar.cc b/src/ui/toolbar/MainToolBar.cc index 451c98d48e5587c2284434b67380ebafb892b4f2..560c664e9ad3a356ad6e45febccddbe04a4b086a 100644 --- a/src/ui/toolbar/MainToolBar.cc +++ b/src/ui/toolbar/MainToolBar.cc @@ -42,7 +42,6 @@ MainToolBar::MainToolBar(QWidget* parent) , _currentView(ViewNone) , _batteryVoltage(0.0) , _batteryPercent(0.0) - , _linkSelected(false) , _connectionCount(0) , _systemArmed(false) , _currentHeartbeatTimeout(0) @@ -152,60 +151,51 @@ void MainToolBar::onAnalyzeView() MainWindow::instance()->loadAnalyzeView(); } -void MainToolBar::onConnect(QString conf) +void MainToolBar::onDisconnect(QString conf) { - // If no connection, the role is "Connect" - if(_connectionCount == 0) { - // Connect Link - if(_currentConfig.isEmpty()) { - MainWindow::instance()->manageLinks(); - } else { - // We don't want the combo box updating under our feet - LinkManager::instance()->suspendConfigurationUpdates(true); - // Create a link - LinkInterface* link = LinkManager::instance()->createConnectedLink(_currentConfig); - if(link) { - // Save last used connection - MainWindow::instance()->saveLastUsedConnection(_currentConfig); + if(conf.isEmpty()) { + // Disconnect Only Connected Link + int connectedCount = 0; + LinkInterface* connectedLink = NULL; + QList links = LinkManager::instance()->getLinks(); + foreach(LinkInterface* link, links) { + if (link->isConnected()) { + connectedCount++; + connectedLink = link; } - LinkManager::instance()->suspendConfigurationUpdates(false); } + Q_ASSERT(connectedCount == 1); + Q_ASSERT(_connectionCount == 1); + Q_ASSERT(connectedLink); + LinkManager::instance()->disconnectLink(connectedLink); } else { - if(conf.isEmpty()) { - // Disconnect Only Connected Link - int connectedCount = 0; - LinkInterface* connectedLink = NULL; - QList links = LinkManager::instance()->getLinks(); - foreach(LinkInterface* link, links) { - if (link->isConnected()) { - connectedCount++; - connectedLink = link; - } - } - Q_ASSERT(connectedCount == 1); - Q_ASSERT(_connectionCount == 1); - Q_ASSERT(connectedLink); - LinkManager::instance()->disconnectLink(connectedLink); - } else { - // Disconnect Named Connected Link - QList links = LinkManager::instance()->getLinks(); - foreach(LinkInterface* link, links) { - if (link->isConnected()) { - if(link->getLinkConfiguration() && link->getLinkConfiguration()->name() == conf) { - LinkManager::instance()->disconnectLink(link); - } + // Disconnect Named Connected Link + QList links = LinkManager::instance()->getLinks(); + foreach(LinkInterface* link, links) { + if (link->isConnected()) { + if(link->getLinkConfiguration() && link->getLinkConfiguration()->name() == conf) { + LinkManager::instance()->disconnectLink(link); } } } } } -void MainToolBar::onLinkConfigurationChanged(const QString& config) +void MainToolBar::onConnect(QString conf) { - // User selected a link configuration from the combobox - if(_currentConfig != config) { - _currentConfig = config; - _linkSelected = true; + // Connect Link + if(conf.isEmpty()) { + MainWindow::instance()->manageLinks(); + } else { + // We don't want the list updating under our feet + LinkManager::instance()->suspendConfigurationUpdates(true); + // Create a link + LinkInterface* link = LinkManager::instance()->createConnectedLink(conf); + if(link) { + // Save last used connection + MainWindow::instance()->saveLastUsedConnection(conf); + } + LinkManager::instance()->suspendConfigurationUpdates(false); } } @@ -378,16 +368,14 @@ void MainToolBar::_updateBatteryRemaining(UASInterface*, double voltage, double, void MainToolBar::_updateConfigurations() { - bool resetSelected = false; - QString selected = _currentConfig; QStringList tmpList; QList configs = LinkManager::instance()->getLinkConfigurationList(); foreach(LinkConfiguration* conf, configs) { if(conf) { - tmpList << conf->name(); - if((!_linkSelected && conf->isPreferred()) || selected.isEmpty()) { - selected = conf->name(); - resetSelected = true; + if(conf->isPreferred()) { + tmpList.insert(0,conf->name()); + } else { + tmpList << conf->name(); } } } @@ -396,15 +384,6 @@ void MainToolBar::_updateConfigurations() _linkConfigurations = tmpList; emit configListChanged(); } - // Selection change? - if((selected != _currentConfig && _linkConfigurations.contains(selected)) || - (selected.isEmpty())) { - _currentConfig = selected; - emit currentConfigChanged(_currentConfig); - } - if(resetSelected) { - _linkSelected = false; - } } void MainToolBar::_linkConnected(LinkInterface*) diff --git a/src/ui/toolbar/MainToolBar.h b/src/ui/toolbar/MainToolBar.h index 263e5763f2e5e637ef1be3f8b182f6a6930f2cde..09ded36532beed5c6deff598df18c7cae1c50201 100644 --- a/src/ui/toolbar/MainToolBar.h +++ b/src/ui/toolbar/MainToolBar.h @@ -71,7 +71,7 @@ public: Q_INVOKABLE void onFlyView(); Q_INVOKABLE void onAnalyzeView(); Q_INVOKABLE void onConnect(QString conf); - Q_INVOKABLE void onLinkConfigurationChanged(const QString& config); + Q_INVOKABLE void onDisconnect(QString conf); Q_INVOKABLE void onEnterMessageArea(int x, int y); Q_INVOKABLE QString getMavIconColor(); @@ -86,7 +86,6 @@ public: Q_PROPERTY(MessageType_t messageType MEMBER _currentMessageType NOTIFY messageTypeChanged) Q_PROPERTY(int newMessageCount MEMBER _currentMessageCount NOTIFY newMessageCountChanged) Q_PROPERTY(int messageCount MEMBER _messageCount NOTIFY messageCountChanged) - Q_PROPERTY(QString currentConfig MEMBER _currentConfig NOTIFY currentConfigChanged) Q_PROPERTY(QString systemPixmap MEMBER _systemPixmap NOTIFY systemPixmapChanged) Q_PROPERTY(int satelliteCount MEMBER _satelliteCount NOTIFY satelliteCountChanged) Q_PROPERTY(QStringList connectedList MEMBER _connectedList NOTIFY connectedListChanged) @@ -160,8 +159,6 @@ private: double _batteryVoltage; double _batteryPercent; QStringList _linkConfigurations; - QString _currentConfig; - bool _linkSelected; int _connectionCount; bool _systemArmed; QString _currentState; diff --git a/src/ui/toolbar/MainToolBar.qml b/src/ui/toolbar/MainToolBar.qml index 207373e9831ac76de7f03a717e959d1a750cd795..efed1d7f74dac39c0b5de8e73180bd867f534206 100644 --- a/src/ui/toolbar/MainToolBar.qml +++ b/src/ui/toolbar/MainToolBar.qml @@ -472,32 +472,50 @@ Rectangle { anchors.leftMargin: 10 anchors.rightMargin: 10 - QGCComboBox { - id: configList - width: 200 - visible: (mainToolBar.connectionCount === 0 && mainToolBar.configList.length > 0) - anchors.verticalCenter: parent.verticalCenter - model: mainToolBar.configList - onCurrentIndexChanged: { - mainToolBar.onLinkConfigurationChanged(mainToolBar.configList[currentIndex]); - } + Menu { + id: connectMenu Component.onCompleted: { - mainToolBar.currentConfigChanged.connect(configList.onCurrentConfigChanged) + mainToolBar.configListChanged.connect(connectMenu.updateConnectionList); + connectMenu.updateConnectionList(); } - function onCurrentConfigChanged(config) { - var index = configList.find(config); - configList.currentIndex = index; + function addMenuEntry(name) { + var label = "Add Connection" + if(name !== "") + label = name; + var mItem = connectMenu.addItem(label); + var menuSlot = function() {mainToolBar.onConnect(name)}; + mItem.triggered.connect(menuSlot); + } + function updateConnectionList() { + connectMenu.clear(); + for(var i = 0; i < mainToolBar.configList.length; i++) { + connectMenu.addMenuEntry(mainToolBar.configList[i]); + } + if(mainToolBar.configList.length > 0) { + connectMenu.addSeparator(); + } + // Add "Add Connection" to the list + connectMenu.addMenuEntry(""); } } QGCButton { - id: connectButton - width: 100 - visible: (mainToolBar.connectionCount === 0 || mainToolBar.connectionCount === 1) - text: (mainToolBar.configList.length > 0) ? (mainToolBar.connectionCount === 0) ? qsTr("Connect") : qsTr("Disconnect") : qsTr("Add Link") + id: connectButton + width: 100 + visible: mainToolBar.connectionCount === 0 + text: qsTr("Connect") + menu: connectMenu + anchors.verticalCenter: parent.verticalCenter + } + + QGCButton { + id: disconnectButton + width: 100 + visible: mainToolBar.connectionCount === 1 + text: qsTr("Disconnect") anchors.verticalCenter: parent.verticalCenter onClicked: { - mainToolBar.onConnect(""); + mainToolBar.onDisconnect(""); } } @@ -506,23 +524,26 @@ Rectangle { Component.onCompleted: { mainToolBar.connectedListChanged.connect(disconnectMenu.onConnectedListChanged) } + function addMenuEntry(name) { + var mItem = disconnectMenu.addItem(name); + var menuSlot = function() {mainToolBar.onDisconnect(name)}; + mItem.triggered.connect(menuSlot); + } function onConnectedListChanged(conList) { disconnectMenu.clear(); for(var i = 0; i < conList.length; i++) { - var mItem = disconnectMenu.addItem(conList[i]); - var menuSlot = function() {mainToolBar.onConnect(mItem.text)}; - mItem.triggered.connect(menuSlot); + disconnectMenu.addMenuEntry(conList[i]); } } } QGCButton { - id: multidisconnectButton - width: 100 - text: qsTr("Disconnect") - visible: (mainToolBar.connectionCount > 1) + id: multidisconnectButton + width: 100 + text: "Disconnect" + visible: mainToolBar.connectionCount > 1 + menu: disconnectMenu anchors.verticalCenter: parent.verticalCenter - menu: disconnectMenu } }