Commit 0a313314 authored by dogmaphobic's avatar dogmaphobic

The ultimate goal is to plug a device, set it up and go fly it without any fuss.

The goal of this first installment is to organize the code a bit so it's more readable,
clean up a bit of left over cruft, and manage link configurations (and links in general).
parent e411b95c
......@@ -271,7 +271,6 @@ INCLUDEPATH += \
FORMS += \
src/ui/MainWindow.ui \
src/ui/CommSettings.ui \
src/ui/SerialSettings.ui \
src/ui/UASControl.ui \
src/ui/UASList.ui \
......@@ -300,7 +299,6 @@ FORMS += \
src/ui/QGCMAVLinkLogPlayer.ui \
src/ui/QGCWaypointListMulti.ui \
src/ui/QGCUASFileViewMulti.ui \
src/ui/QGCUDPLinkConfiguration.ui \
src/ui/QGCTCPLinkConfiguration.ui \
src/ui/SettingsDialog.ui \
src/ui/map/QGCMapTool.ui \
......@@ -344,6 +342,9 @@ FORMS += \
src/ui/QGCUASFileView.ui \
src/QGCQmlWidgetHolder.ui \
src/ui/QGCMapRCToParamDialog.ui \
src/ui/QGCLinkConfiguration.ui \
src/ui/QGCCommConfiguration.ui \
src/ui/QGCUDPLinkConfiguration.ui
HEADERS += \
src/MG.h \
......@@ -354,14 +355,12 @@ HEADERS += \
src/uas/UASManager.h \
src/comm/LinkManager.h \
src/comm/LinkInterface.h \
src/comm/SerialLinkInterface.h \
src/comm/SerialLink.h \
src/comm/ProtocolInterface.h \
src/comm/MAVLinkProtocol.h \
src/comm/QGCFlightGearLink.h \
src/comm/QGCJSBSimLink.h \
src/comm/QGCXPlaneLink.h \
src/ui/CommConfigurationWindow.h \
src/ui/SerialConfigurationWindow.h \
src/ui/MainWindow.h \
src/ui/uas/UASControlWidget.h \
......@@ -416,7 +415,6 @@ HEADERS += \
src/uas/QGCMAVLinkUASFactory.h \
src/ui/QGCWaypointListMulti.h \
src/ui/QGCUASFileViewMulti.h \
src/ui/QGCUDPLinkConfiguration.h \
src/ui/QGCTCPLinkConfiguration.h \
src/ui/SettingsDialog.h \
src/uas/QGCUASParamManager.h \
......@@ -497,6 +495,10 @@ HEADERS += \
src/ui/QGCParamTreeWidget.h \
src/ui/QGCMapRCToParamDialog.h \
src/QGCDockWidget.h \
src/ui/QGCLinkConfiguration.h \
src/comm/LinkConfiguration.h \
src/ui/QGCCommConfiguration.h \
src/ui/QGCUDPLinkConfiguration.h
SOURCES += \
src/main.cc \
......@@ -510,7 +512,6 @@ SOURCES += \
src/comm/QGCFlightGearLink.cc \
src/comm/QGCJSBSimLink.cc \
src/comm/QGCXPlaneLink.cc \
src/ui/CommConfigurationWindow.cc \
src/ui/SerialConfigurationWindow.cc \
src/ui/MainWindow.cc \
src/ui/uas/UASControlWidget.cc \
......@@ -563,7 +564,6 @@ SOURCES += \
src/uas/QGCMAVLinkUASFactory.cc \
src/ui/QGCWaypointListMulti.cc \
src/ui/QGCUASFileViewMulti.cc \
src/ui/QGCUDPLinkConfiguration.cc \
src/ui/QGCTCPLinkConfiguration.cc \
src/ui/SettingsDialog.cc \
src/uas/QGCUASParamManager.cc \
......@@ -639,6 +639,10 @@ SOURCES += \
src/ui/QGCParamTreeWidget.cpp \
src/ui/QGCMapRCToParamDialog.cpp \
src/QGCDockWidget.cc \
src/ui/QGCLinkConfiguration.cc \
src/comm/LinkConfiguration.cc \
src/ui/QGCCommConfiguration.cc \
src/ui/QGCUDPLinkConfiguration.cc
#
# Unit Test specific configuration goes here
......
......@@ -266,7 +266,6 @@ bool QGCApplication::_initForNormalAppBoot(void)
splashScreen->show();
processEvents();
splashScreen->showMessage(tr("Loading application fonts"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
// Exit main application when last window is closed
connect(this, SIGNAL(lastWindowClosed()), this, SLOT(quit()));
......@@ -280,7 +279,8 @@ bool QGCApplication::_initForNormalAppBoot(void)
/// settings.
QString savedFilesLocation = settings.value(_savedFilesLocationKey).toString();
if (savedFilesLocation.isEmpty()) {
QGCMessageBox::warning(tr("Bad save location"),
QGCMessageBox::warning(
tr("Bad save location"),
tr("The location to save files to is invalid, or cannot be written to. Please provide a new one."));
mainWindow->showSettings();
}
......@@ -293,6 +293,9 @@ bool QGCApplication::_initForNormalAppBoot(void)
connect(this, &QGCApplication::checkForLostLogFiles, MAVLinkProtocol::instance(), &MAVLinkProtocol::checkForLostLogFiles);
emit checkForLostLogFiles();
// Load known link configurations
LinkManager::instance()->loadLinkConfigurationList();
return true;
}
......
......@@ -115,6 +115,10 @@ private:
QMessageBox box(icon, emptyTitle, title, buttons, parent);
box.setDefaultButton(defaultButton);
box.setInformativeText(text);
// Get this thing off a proper size
QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
QGridLayout* layout = (QGridLayout*)box.layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
#else
QMessageBox box(icon, title, text, buttons, parent);
box.setDefaultButton(defaultButton);
......
......@@ -21,86 +21,90 @@ This file is part of the QGROUNDCONTROL project
======================================================================*/
/**
* @file
* @brief Definition of class CommConfigurationWindow
*
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#ifndef _COMMCONFIGURATIONWINDOW_H_
#define _COMMCONFIGURATIONWINDOW_H_
#include <QObject>
#include <QDialog>
#include <QAction>
#include "LinkInterface.h"
#include "ProtocolInterface.h"
#include "ui_CommSettings.h"
enum qgc_link_t {
QGC_LINK_SERIAL,
QGC_LINK_UDP,
QGC_LINK_TCP,
QGC_LINK_SIMULATION,
QGC_LINK_FORWARDING,
#ifdef UNITTEST_BUILD
QGC_LINK_MOCK,
#endif
#ifdef QGC_XBEE_ENABLED
QGC_LINK_XBEE,
#endif
#ifdef QGC_RTLAB_ENABLED
QGC_LINK_OPAL
#endif
};
enum qgc_protocol_t {
QGC_PROTOCOL_MAVLINK,
};
#ifdef QGC_RTLAB_ENABLED
#include "OpalLink.h"
#endif
/**
* @brief Configuration window for communication links
*/
class CommConfigurationWindow : public QDialog
{
Q_OBJECT
public:
CommConfigurationWindow(LinkInterface* link, QWidget *parent = 0);
~CommConfigurationWindow();
QAction* getAction();
void setLinkType(qgc_link_t linktype);
/*!
@file
@brief Link specific configuration base class
@author Gus Grubba <mavlink@grubba.com>
*/
private slots:
void linkCurrentIndexChanged(int currentIndex);
#include "LinkConfiguration.h"
#include "SerialLink.h"
#include "UDPLink.h"
#include "MockLink.h"
public slots:
/** @brief Set the protocol for this link */
void setProtocol(int protocol);
void setConnection();
void setLinkName(QString name);
/** @brief Disconnects the associated link, removes it from all menus and closes the window. */
void remove();
#define LINK_SETTING_ROOT "LinkConfigurations"
private slots:
void _linkConnected(void);
void _linkDisconnected(void);
private:
void _connectionState(bool connect);
Ui::commSettings ui;
LinkInterface* link;
QAction* action;
};
LinkConfiguration::LinkConfiguration(const QString& name)
: _preferred(false)
{
_link = NULL;
_name = name;
Q_ASSERT(!_name.isEmpty());
}
LinkConfiguration::LinkConfiguration(LinkConfiguration* copy)
{
_link = copy->getLink();
_name = copy->name();
_preferred = copy->isPreferred();
Q_ASSERT(!_name.isEmpty());
}
#endif // _COMMCONFIGURATIONWINDOW_H_
void LinkConfiguration::copyFrom(LinkConfiguration* source)
{
Q_ASSERT(source != NULL);
_link = source->getLink();
_name = source->name();
_preferred = source->isPreferred();
}
/*!
Where the settings are saved
@return The root path of the setting.
*/
const QString LinkConfiguration::settingsRoot()
{
return QString(LINK_SETTING_ROOT);
}
/*!
Configuration Factory
@return A new instance of the given type
*/
LinkConfiguration* LinkConfiguration::createSettings(int type, const QString& name)
{
LinkConfiguration* config = NULL;
switch(type) {
case LinkConfiguration::TypeSerial:
config = new SerialConfiguration(name);
break;
case LinkConfiguration::TypeUdp:
config = new UDPConfiguration(name);
break;
case LinkConfiguration::TypeMock:
config = new MockConfiguration(name);
break;
}
return config;
}
/*!
Duplicate link settings
@return A new copy of the given settings instance
*/
LinkConfiguration* LinkConfiguration::duplicateSettings(LinkConfiguration* source)
{
LinkConfiguration* dupe = NULL;
switch(source->type()) {
case TypeSerial:
dupe = new SerialConfiguration(dynamic_cast<SerialConfiguration*>(source));
break;
case TypeUdp:
dupe = new UDPConfiguration(dynamic_cast<UDPConfiguration*>(source));
break;
case TypeMock:
dupe = new MockConfiguration(dynamic_cast<MockConfiguration*>(source));
break;
}
return dupe;
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef LINKCONFIGURATION_H
#define LINKCONFIGURATION_H
#include <QSettings>
class LinkInterface;
/// Interface holding link specific settings.
class LinkConfiguration
{
public:
LinkConfiguration(const QString& name);
LinkConfiguration(LinkConfiguration* copy);
virtual ~LinkConfiguration() {}
/// The link types supported by QGC
enum {
TypeSerial, ///< Serial Link
TypeUdp, ///< UDP Link
TypeMock, ///< Mock Link for Unitesting
// TODO Below is not yet implemented
#if 0
TypeTcp, ///< TCP Link
TypeSimulation, ///< Simulation Link
TypeForwarding, ///< Forwarding Link
TypeXbee, ///< XBee Proprietary Link
TypeOpal, ///< Opal-RT Link
#endif
TypeLast // Last type value (type >= TypeLast == invalid)
};
/*!
* @brief Get configuration name
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @return The name of this link.
*/
const QString name() { return _name; }
/*!
* @brief Set the name of this link configuration.
*
* This is the user friendly name shown in the connection drop down box and the name used to save the configuration in the settings.
* @param[in] name The configuration name
*/
void setName(const QString name) {_name = name; }
/*!
* @brief Set the link this configuration is currently attched to.
*
* @param[in] link The pointer to the current LinkInterface instance (if any)
*/
void setLink(LinkInterface* link) { _link = link; }
/*!
* @brief Get the link this configuration is currently attched to.
*
* @return The pointer to the current LinkInterface instance (if any)
*/
LinkInterface* getLink() { return _link; }
/*!
*
* Is this a preferred configuration? (decided at runtime)
* @return True if this is a known configuration (PX4, etc.)
*/
bool isPreferred() { return _preferred; }
/*!
* Set if this is this a preferred configuration. (decided at runtime)
*/
void setPreferred(bool preferred = true) { _preferred = preferred; }
/// Virtual Methods
/*!
* @brief Connection type
*
* Pure virtual method returning one of the -TypeXxx types above.
* @return The type of links these settings belong to.
*/
virtual int type() = 0;
/*!
* @brief Load settings
*
* Pure virtual method telling the instance to load its configuration.
* @param[in] settings The QSettings instance to use
* @param[in] root The root path of the setting.
*/
virtual void loadSettings(QSettings& settings, const QString& root) = 0;
/*!
* @brief Save settings
*
* Pure virtual method telling the instance to save its configuration.
* @param[in] settings The QSettings instance to use
* @param[in] root The root path of the setting.
*/
virtual void saveSettings(QSettings& settings, const QString& root) = 0;
/*!
* @brief Update settings
*
* After editing the settings, use this method to tell the connected link (if any) to reload its configuration.
*/
virtual void updateSettings() {}
/*!
* @brief Copy instance data
*
* When manipulating data, you create a copy of the configuration using the copy constructor,
* edit it and then transfer its content to the original using this method.
* @param[in] source The source instance (the edited copy)
*/
virtual void copyFrom(LinkConfiguration* source);
/// Helper static methods
/*!
* @brief Root path for QSettings
*
* @return The root path of the settings.
*/
static const QString settingsRoot();
/*!
* @brief Create new link configuration instance
*
* Configuration Factory. Creates an appropriate configuration instance based on the given type.
* @return A new instance of the given type
*/
static LinkConfiguration* createSettings(int type, const QString& name);
/*!
* @brief Duplicate configuration instance
*
* Helper method to create a new instance copy for editing.
* @return A new copy of the given settings instance
*/
static LinkConfiguration* duplicateSettings(LinkConfiguration *source);
protected:
LinkInterface* _link; ///< Link currently using this configuration (if any)
private:
QString _name;
bool _preferred; ///< Determined internally if this is a preferred connection. It comes up first in the drop down box.
};
#endif // LINKCONFIGURATION_H
......@@ -39,6 +39,7 @@ along with PIXHAWK. If not, see <http://www.gnu.org/licenses/>.
#include <QMetaType>
class LinkManager;
class LinkConfiguration;
/**
* The link interface defines the interface for all links used to communicate
......@@ -62,24 +63,30 @@ public:
inDataIndex = 0;
outDataIndex = 0;
// Initialize our data rate buffers manually, cause C++<03 is dumb.
for (int i = 0; i < dataRateBufferSize; ++i)
{
inDataWriteAmounts[i] = 0;
inDataWriteTimes[i] = 0;
outDataWriteAmounts[i] = 0;
outDataWriteTimes[i] = 0;
}
// Initialize our data rate buffers.
memset(inDataWriteAmounts, 0, sizeof(inDataWriteAmounts));
memset(inDataWriteTimes, 0, sizeof(inDataWriteTimes));
memset(outDataWriteAmounts,0, sizeof(outDataWriteAmounts));
memset(outDataWriteTimes, 0, sizeof(outDataWriteTimes));
qRegisterMetaType<LinkInterface*>("LinkInterface*");
}
/**
* @brief Destructor
* LinkManager take ownership of Links once they are added to it. Once added to LinkManager
* use LinkManager::deleteLink to remove if necessary.
**/
virtual ~LinkInterface() {
// LinkManager take ownership of Links once they are added to it. Once added to LinkManager
// user LinkManager::deleteLink to remove if necessary/
Q_ASSERT(!_ownedByLinkManager || _deletedByLinkManager);
}
/**
* @brief Get link configuration (if used)
* @return A pointer to the instance of LinkConfiguration if supported. NULL otherwise.
**/
virtual LinkConfiguration* getLinkConfiguration() { return NULL; }
/* Connection management */
/**
......
This diff is collapsed.
......@@ -31,8 +31,14 @@ This file is part of the PIXHAWK project
#include <QMultiMap>
#include <QMutex>
#include "LinkConfiguration.h"
#include "LinkInterface.h"
// Links
#include "SerialLink.h"
#include "UDPLink.h"
#include "MockLink.h"
#include "ProtocolInterface.h"
#include "QGCSingleton.h"
#include "MAVLinkProtocol.h"
......@@ -48,7 +54,6 @@ class LinkManagerTest;
class LinkManager : public QGCSingleton
{
Q_OBJECT
DECLARE_QGC_SINGLETON(LinkManager, LinkManager)
/// Unit Test has access to private constructor/destructor
......@@ -56,6 +61,31 @@ class LinkManager : public QGCSingleton
public:
/*!
Add a new link configuration setting to the list
@param[in] link An instance of the link setting.
*/
void addLinkConfiguration(LinkConfiguration* link);
/*!
Removes (and deletes) an existing link configuration setting from the list
@param[in] link An instance of the link setting.
*/
void removeLinkConfiguration(LinkConfiguration* link);
/// Load list of link configurations from disk
void loadLinkConfigurationList();
/// Save list of link configurations from disk
void saveLinkConfigurationList();
/// Get a list of the configured links. This is the list of configured links that can be used by QGC.
const QList<LinkConfiguration*> getLinkConfigurationList();
/// Suspend automatic confguration updates (during link maintenance for instance)
void suspendConfigurationUpdates(bool suspend);
/// Returns list of all links
const QList<LinkInterface*> getLinks();
......@@ -69,11 +99,20 @@ public:
/// Sets the flag to allow new connections to be made
void setConnectionsAllowed(void) { _connectionsSuspended = false; }
/// Creates (and adds) a link based on the given configuration instance. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
LinkInterface* createLink(LinkConfiguration* config);
/// Creates (and adds) a link based on the given configuration name. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
LinkInterface* createLink(const QString& name);
/// Adds the link to the LinkManager. LinkManager takes ownership of this object. To delete
/// it, call LinkManager::deleteLink.
void addLink(LinkInterface* link);
/// Deletes the specified link. Will disconnect if connected.
// TODO Will also crash if called. MAVLink protocol is not handling the disconnect properly.
void deleteLink(LinkInterface* link);
/// Re-connects all existing links
......@@ -93,6 +132,7 @@ signals:
void linkDeleted(LinkInterface* link);
void linkConnected(LinkInterface* link);
void linkDisconnected(LinkInterface* link);
void linkConfigurationChanged();
private slots:
void _linkConnected(void);
......@@ -106,12 +146,18 @@ private:
virtual void _shutdown(void);
bool _connectionsSuspendedMsg(void);
void _updateConfigurationList(void);
SerialConfiguration* _findSerialConfiguration(const QString& portName);
QList<LinkConfiguration*> _linkConfigurations; ///< List of configured links
QList<LinkInterface*> _links; ///< List of available links
QMutex _linkListMutex; ///< Mutex for thread safe access to _links list
bool _configUpdateSuspended; ///< true: stop updating configuration list
bool _configurationsLoaded; ///< true: Link configurations have been loaded
bool _connectionsSuspended; ///< true: all new connections should not be allowed
QString _connectionsSuspendedReason; ///< User visible reason for suspension
QTimer _portListTimer;
};
#endif
This diff is collapsed.
......@@ -32,18 +32,65 @@ This file is part of the QGROUNDCONTROL project
#ifndef SERIALLINK_H
#define SERIALLINK_H
class LinkInterface;
class SerialConfiguration;
class SerialLink;
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QString>
#include "QGCConfig.h"
#include "SerialLinkInterface.h"
// We use QSerialPort::SerialPortError in a signal so we must declare it as a meta type
#include <QSerialPort>
#include <QMetaType>
// We use QSerialPort::SerialPortError in a signal so we must declare it as a meta type
Q_DECLARE_METATYPE(QSerialPort::SerialPortError)
#include "QGCConfig.h"
#include "LinkManager.h"
class SerialConfiguration : public LinkConfiguration
{
public:
SerialConfiguration(const QString& name);
SerialConfiguration(SerialConfiguration* copy);
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; }
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);
/// From LinkConfiguration
int type() { return LinkConfiguration::TypeSerial; }
void copyFrom(LinkConfiguration* source);
void loadSettings(QSettings& settings, const QString& root);
void saveSettings(QSettings& settings, const QString& root);
void updateSettings();
/*! @brief Get a list of the currently available ports */
static QList<QString> getCurrentPorts();
private:
int _baud;
int _dataBits;
int _flowControl;
int _stopBits;
int _parity;
QString _portName;
};
/**
* @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
......@@ -52,84 +99,36 @@ Q_DECLARE_METATYPE(QSerialPort::SerialPortError)
* safe.
*
*/
class SerialLink : public SerialLinkInterface
class SerialLink : public LinkInterface
{
Q_OBJECT
//Q_INTERFACES(SerialLinkInterface:LinkInterface)
friend class SerialConfiguration;
public:
SerialLink(QString portname = "",
int baudrate=57600,
bool flow=false,
bool parity=false,
int dataBits=8,
int stopBits=1);
~SerialLink();
static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in QGCConfig.h
/** @brief Get a list of the currently available ports */
QList<QString> getCurrentPorts();
SerialLink(SerialConfiguration* config);
~SerialLink();
/** @brief Check if the current port is a bootloader */
bool isBootloader();
// LinkInterface
LinkConfiguration* getLinkConfiguration();
int getId() const;
QString getName() const;
void requestReset();
bool isConnected() const;
/**
* @brief The port handle
*/
QString getPortName() const;
/**
* @brief The human readable port name
*/
QString getName() const;
int getBaudRate() const;
int getDataBits() const;
int getStopBits() const;
// ENUM values
int getBaudRateType() const;
int getFlowType() const;
int getParityType() const;
int getDataBitsType() const;
int getStopBitsType() const;
qint64 getConnectionSpeed() const;
qint64 getCurrentInDataRate() const;
qint64 getCurrentOutDataRate() const;
void loadSettings();
void writeSettings();
void checkIfCDC();
void run();
void run2();
int getId() const;
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
// connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
bool connect(void);
bool disconnect(void);
void run();
static const int poll_interval = SERIAL_POLL_INTERVAL; ///< Polling interval, defined in QGCConfig.h
signals: //[TODO] Refactor to Linkinterface
void updateLink(LinkInterface*);
public slots:
bool setPortName(QString portName);
bool setBaudRate(int rate);
// Set ENUM values
bool setBaudRateType(int rateIndex);
bool setFlowType(int flow);
bool setParityType(int parity);
bool setDataBitsType(int dataBits);
bool setStopBitsType(int stopBits);
void readBytes();
/**
......@@ -143,37 +142,34 @@ public slots:
void linkError(QSerialPort::SerialPortError error);
protected:
quint64 m_bytesRead;
QSerialPort* m_port;
int m_baud;
int m_dataBits;
int m_flowControl;
int m_stopBits;
int m_parity;
QString m_portName;
int m_timeout;
int m_id;
QMutex m_dataMutex; // Mutex for reading data from m_port
QMutex m_writeMutex; // Mutex for accessing the m_transmitBuffer.
QString type;
bool m_is_cdc;
QSerialPort* _port;
quint64 _bytesRead;
int _timeout;
int _id;
QMutex _dataMutex; // Mutex for reading data from _port
QMutex _writeMutex; // Mutex for accessing the _transmitBuffer.
QString _type;
private slots:
void _rerouteDisconnected(void);
private:
// From LinkInterface
virtual bool _connect(void);
virtual bool _disconnect(void);
bool _connect(void);
bool _disconnect(void);
// Internal methods
void _emitLinkError(const QString& errorMsg);
volatile bool m_stopp;
volatile bool m_reqReset;
QMutex m_stoppMutex; // Mutex for accessing m_stopp
QByteArray m_transmitBuffer; // An internal buffer for receiving data from member functions and actually transmitting them via the serial port.
bool hardwareConnect(QString &type);
bool _hardwareConnect(QString &_type);
bool _isBootloader();
void _resetConfiguration();
// Local data
volatile bool _stopp;
volatile bool _reqReset;
QMutex _stoppMutex; // Mutex for accessing _stopp
QByteArray _transmitBuffer; // An internal buffer for receiving data from member functions and actually transmitting them via the serial port.
SerialConfiguration* _config;
signals:
void aboutToCloseFlag();
......
......@@ -37,12 +37,12 @@ This file is part of the QGROUNDCONTROL project
#include <QVector>
#include <LinkInterface.h>
/*
class SerialLinkInterface : public LinkInterface
{
Q_OBJECT
public:
virtual QList<QString> getCurrentPorts() = 0;
virtual QString getPortName() const = 0;
virtual int getBaudRate() const = 0;
virtual int getDataBits() const = 0;
......@@ -66,7 +66,7 @@ public slots:
virtual void writeSettings() = 0;
};
*/
/* Declare C++ interface as Qt interface */
//Q_DECLARE_INTERFACE(SerialLinkInterface, "org.openground.comm.links.SerialLinkInterface/1.0")
......
This diff is collapsed.
......@@ -21,7 +21,7 @@ This file is part of the QGROUNDCONTROL project
======================================================================*/
/**
/*!
* @file
* @brief UDP connection (server) for unmanned vehicles
* @author Lorenz Meier <mavteam@student.ethz.ch>
......@@ -36,39 +36,120 @@ This file is part of the QGROUNDCONTROL project
#include <QMap>
#include <QMutex>
#include <QUdpSocket>
#include <LinkInterface.h>
#include "QGCConfig.h"
#include "LinkManager.h"
#define QGC_UDP_PORT 14550
class UDPConfiguration : public LinkConfiguration
{
public:
/*!
* @brief Regular constructor
*
* @param[in] name Configuration (user friendly) name
*/
UDPConfiguration(const QString& name);
/*!
* @brief Copy contructor
*
* When manipulating data, you create a copy of the configuration, edit it
* and then transfer its content to the original (using copyFrom() below). Use this
* contructor to create an editable copy.
*
* @param[in] source Original configuration
*/
UDPConfiguration(UDPConfiguration* source);
/*!
* @brief Begin iteration through the list of target hosts
*
* @param[out] host Host name
* @param[out] port Port number
* @return Returns false if list is empty
*/
bool firstHost (QString& host, int& port);
/*!
* @brief Continues iteration through the list of target hosts
*
* @param[out] host Host name
* @param[out] port Port number
* @return Returns false if reached the end of the list (in which case, both host and port are unchanged)
*/
bool nextHost (QString& host, int& port);
/*!
* @brief Get the number of target hosts
*
* @return Number of hosts in list
*/
int hostCount () { return _hosts.count(); }
/*!
* @brief The UDP port we bind to
*
* @return Port number
*/
quint16 localPort () { return _localPort; }
/*!
* @brief Add a target host
*
* @param[in] host Host name in standard formatt, e.g. localhost:14551 or 192.168.1.1:14551
*/
void addHost (const QString& host);
/*!
* @brief Add a target host
*
* @param[in] host Host name, e.g. localhost or 192.168.1.1
* @param[in] port Port number
*/
void addHost (const QString& host, int port);
/*!
* @brief Remove a target host from the list
*
* @param[in] host Host name, e.g. localhost or 192.168.1.1
*/
void removeHost (const QString& host);
/*!
* @brief Set the UDP port we bind to
*
* @param[in] port Port number
*/
void setLocalPort (quint16 port);
/// From LinkConfiguration
int type() { return LinkConfiguration::TypeUdp; }
void copyFrom(LinkConfiguration* source);
void loadSettings(QSettings& settings, const QString& root);
void saveSettings(QSettings& settings, const QString& root);
void updateSettings();
private:
QMutex _confMutex;
QMap<QString, int>::iterator _it;
QMap<QString, int> _hosts; ///< ("host", port)
quint16 _localPort;
};
class UDPLink : public LinkInterface
{
Q_OBJECT
//Q_INTERFACES(UDPLinkInterface:LinkInterface)
friend class UDPConfiguration;
public:
UDPLink(QHostAddress host = QHostAddress::Any, quint16 port = 14550);
//UDPLink(QHostAddress host = "239.255.76.67", quint16 port = 7667);
UDPLink(UDPConfiguration* config);
~UDPLink();
void requestReset() { }
bool isConnected() const;
int getPort() const {
return port;
}
/**
* @brief The human readable port name
*/
QString getName() const;
int getBaudRate() const;
int getBaudRateType() const;
int getFlowType() const;
int getParityType() const;
int getDataBitsType() const;
int getStopBitsType() const;
QList<QHostAddress> getHosts() const {
return hosts;
}
// Extensive statistics for scientific purposes
qint64 getConnectionSpeed() const;
......@@ -76,7 +157,6 @@ public:
qint64 getCurrentOutDataRate() const;
void run();
int getId() const;
// These are left unimplemented in order to cause linker errors which indicate incorrect usage of
......@@ -85,16 +165,15 @@ public:
bool disconnect(void);
public slots:
void setAddress(QHostAddress host);
void setPort(int port);
/** @brief Add a new host to broadcast messages to */
void addHost(const QString& host);
/** @brief Remove a host from broadcasting messages to */
void removeHost(const QString& host);
// void readPendingDatagrams();
/*! @brief Add a new host to broadcast messages to */
void addHost (const QString& host);
/*! @brief Remove a host from broadcasting messages to */
void removeHost (const QString& host);
void readBytes();
/**
/*!
* @brief Write a number of bytes to the interface.
*
* @param data Pointer to the data byte array
......@@ -103,25 +182,19 @@ public slots:
void writeBytes(const char* data, qint64 length);
protected:
QString name;
QHostAddress host;
quint16 port;
int id;
QUdpSocket* socket;
bool connectState;
QList<QHostAddress> hosts;
QList<quint16> ports;
QMutex dataMutex;
void setName(QString name);
QUdpSocket* _socket;
UDPConfiguration* _config;
bool _connectState;
int _id;
private:
// From LinkInterface
virtual bool _connect(void);
virtual bool _disconnect(void);
bool hardwareConnect(void);
bool _hardwareConnect();
void _restartConnection();
signals:
//Signals are defined by LinkInterface
......
......@@ -34,8 +34,6 @@ This file is part of the QGROUNDCONTROL project
#include "QGCApplication.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "UnitTest.h"
#include "CmdLineOptParser.h"
......
......@@ -65,7 +65,7 @@ union px4_custom_mode {
float data_float;
};
MockLink::MockLink(void) :
MockLink::MockLink(MockConfiguration* config) :
_linkId(getNextLinkId()),
_name("MockLink"),
_connected(false),
......@@ -77,6 +77,7 @@ MockLink::MockLink(void) :
_mavState(MAV_STATE_STANDBY),
_autopilotType(MAV_AUTOPILOT_PX4)
{
_config = config;
union px4_custom_mode px4_cm;
px4_cm.data = 0;
......
......@@ -28,7 +28,7 @@
#include <QLoggingCategory>
#include "MockLinkMissionItemHandler.h"
#include "LinkInterface.h"
#include "LinkManager.h"
#include "QGCMAVLink.h"
Q_DECLARE_LOGGING_CATEGORY(MockLinkLog)
......@@ -38,12 +38,26 @@ Q_DECLARE_LOGGING_CATEGORY(MockLinkLog)
///
/// @author Don Gagne <don@thegagnes.com>
class MockConfiguration : public LinkConfiguration
{
public:
MockConfiguration(const QString& name) : LinkConfiguration(name) {}
MockConfiguration(MockConfiguration* source) : LinkConfiguration(source) {}
int type() { return LinkConfiguration::TypeMock; }
void copyFrom(LinkConfiguration* source) { LinkConfiguration::copyFrom(source); }
void loadSettings(QSettings& settings, const QString& root) { Q_UNUSED(settings); Q_UNUSED(root); }
void saveSettings(QSettings& settings, const QString& root) { Q_UNUSED(settings); Q_UNUSED(root); }
void updateSettings() {}
};
class MockLink : public LinkInterface
{
Q_OBJECT
public:
MockLink(void);
// LinkConfiguration is optional for MockLink
MockLink(MockConfiguration* config = NULL);
~MockLink(void);
// Virtuals from LinkInterface
......@@ -63,6 +77,8 @@ public:
bool connect(void);
bool disconnect(void);
LinkConfiguration* getLinkConfiguration() { return _config; }
signals:
/// @brief Used internally to move data to the thread.
void _incomingBytes(const QByteArray bytes);
......@@ -127,6 +143,7 @@ private:
uint8_t _mavCustomMode;
uint8_t _mavState;
MockConfiguration* _config;
MAV_AUTOPILOT _autopilotType;
};
......
......@@ -32,6 +32,7 @@
#include "MAVLinkSimulationLink.h"
#include "QGCMAVLink.h"
/* Alreedy defined in MAVLinkSimulationLink.h above!
enum PX_WAYPOINTPLANNER_STATES {
PX_WPP_IDLE = 0,
PX_WPP_SENDLIST,
......@@ -40,6 +41,7 @@ enum PX_WAYPOINTPLANNER_STATES {
PX_WPP_GETLIST_GETWPS,
PX_WPP_GETLIST_GOTALL
};
*/
class MockLinkMissionItemHandler : public QObject
{
......
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>commSettings</class>
<widget class="QWidget" name="commSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>324</width>
<height>475</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Link &amp;Type:</string>
</property>
<property name="buddy">
<cstring>linkType</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="linkType"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="linkGroupBox">
<property name="title">
<string>Link</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="linkScrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>298</width>
<height>90</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="advCheckBox">
<property name="text">
<string>&amp;Show Advanced Protocol Options</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="protocolTypeGroupBox">
<property name="title">
<string>GroupBox</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="connectionType">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&amp;Protocol:</string>
</property>
<property name="buddy">
<cstring>connectionType</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="advancedOptionsCheckBox">
<property name="text">
<string>&amp;Advanced Options</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="protocolGroupBox">
<property name="title">
<string>Protocol</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="protocolScrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>298</width>
<height>90</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>12</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QPushButton" name="connectButton">
<property name="text">
<string>Connect</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete Link</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="connectionStatusLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Disconnected</string>
</property>
</widget>
</item>
</layout>
<action name="actionDelete">
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete this link</string>
</property>
</action>
<action name="actionConnect">
<property name="text">
<string>Connect</string>
</property>
<property name="toolTip">
<string>Connect this link</string>
</property>
</action>
<action name="actionClose">
<property name="text">
<string>Close</string>
</property>
<property name="toolTip">
<string>Close the configuration window</string>
</property>
</action>
<zorder>line</zorder>
<zorder>linkGroupBox</zorder>
<zorder>protocolGroupBox</zorder>
<zorder>connectionStatusLabel</zorder>
<zorder>advCheckBox</zorder>
<zorder>protocolTypeGroupBox</zorder>
<zorder>linkType</zorder>
<zorder>label</zorder>
</widget>
<tabstops>
<tabstop>linkType</tabstop>
<tabstop>linkScrollArea</tabstop>
<tabstop>advCheckBox</tabstop>
<tabstop>connectionType</tabstop>
<tabstop>advancedOptionsCheckBox</tabstop>
<tabstop>protocolScrollArea</tabstop>
<tabstop>connectButton</tabstop>
<tabstop>deleteButton</tabstop>
<tabstop>closeButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>actionClose</sender>
<signal>triggered()</signal>
<receiver>commSettings</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>224</x>
<y>195</y>
</hint>
</hints>
</connection>
</connections>
</ui>
......@@ -42,9 +42,7 @@ This file is part of the QGROUNDCONTROL project
#include "QGC.h"
#include "MAVLinkSimulationLink.h"
#include "SerialLink.h"
#include "UDPLink.h"
#include "MAVLinkProtocol.h"
#include "CommConfigurationWindow.h"
#include "QGCWaypointListMulti.h"
#include "MainWindow.h"
#include "JoystickWidget.h"
......@@ -81,6 +79,9 @@ This file is part of the QGROUNDCONTROL project
#include "LogCompressor.h"
/// The key under which the Main Window settings are saved
const char* MAIN_SETTINGS_GROUP = "QGC_MAINWINDOW";
const char* MainWindow::_uasControlDockWidgetName = "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET";
const char* MainWindow::_uasListDockWidgetName = "UNMANNED_SYSTEM_LIST_DOCKWIDGET";
const char* MainWindow::_waypointsDockWidgetName = "WAYPOINT_LIST_DOCKWIDGET";
......@@ -232,16 +233,6 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) :
// Create actions
connectCommonActions();
// Populate link menu
emit initStatusChanged(tr("Populating link menu"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
QList<LinkInterface*> links = LinkManager::instance()->getLinks();
foreach(LinkInterface* link, links)
{
_addLinkMenu(link);
}
connect(LinkManager::instance(), &LinkManager::newLink, this, &MainWindow::_addLinkMenu);
// Connect user interface devices
emit initStatusChanged(tr("Initializing joystick interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141));
joystick = new JoystickInput();
......@@ -263,14 +254,7 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) :
// Connect link
if (autoReconnect)
{
LinkManager* linkMgr = LinkManager::instance();
Q_ASSERT(linkMgr);
SerialLink* link = new SerialLink();
// Add to registry
linkMgr->addLink(link);
linkMgr->connectLink(link);
restoreLastUsedConnection();
}
// Set low power mode
......@@ -781,6 +765,7 @@ void MainWindow::_loadCustomWidgetFromFile(void)
QGCToolWidget* tool = new QGCToolWidget("", "", this);
if (tool->loadSettings(fileName, true)) {
QString objectName = tool->objectName() + "DOCK";
_createDockWidget(tool->getTitle(), objectName, Qt::LeftDockWidgetArea, tool);
_mapName2DockWidget[objectName]->widget()->setVisible(true);
}
......@@ -790,9 +775,9 @@ void MainWindow::_loadCustomWidgetFromFile(void)
void MainWindow::loadSettings()
{
// Why the screaming?
QSettings settings;
settings.beginGroup("QGC_MAINWINDOW");
settings.beginGroup(MAIN_SETTINGS_GROUP);
autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool();
lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool();
settings.endGroup();
......@@ -802,7 +787,7 @@ void MainWindow::storeSettings()
{
QSettings settings;
settings.beginGroup("QGC_MAINWINDOW");
settings.beginGroup(MAIN_SETTINGS_GROUP);
settings.setValue("AUTO_RECONNECT", autoReconnect);
settings.setValue("LOW_POWER_MODE", lowPowerMode);
settings.endGroup();
......@@ -961,7 +946,7 @@ void MainWindow::connectCommonActions()
ui.actionShutdownMAV->setEnabled(false);
// Connect actions from ui
connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink()));
connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(manageLinks()));
// Connect internal actions
connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
......@@ -1037,33 +1022,6 @@ void MainWindow::showSettings()
settings.exec();
}
// FIXME: Where is this called from
LinkInterface* MainWindow::addLink()
{
SerialLink* link = new SerialLink();
// TODO This should be only done in the dialog itself
LinkManager::instance()->addLink(link);
// Go fishing for this link's configuration window
QList<QAction*> actions = ui.menuNetwork->actions();
const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link));
const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId());
foreach (QAction* act, actions)
{
if (act->data().toInt() == linkID)
{
act->trigger();
break;
}
}
return link;
}
bool MainWindow::configLink(LinkInterface *link)
{
// Go searching for this link's configuration window
......@@ -1086,32 +1044,6 @@ bool MainWindow::configLink(LinkInterface *link)
return found;
}
void MainWindow::_addLinkMenu(LinkInterface *link)
{
// Go fishing for this link's configuration window
QList<QAction*> actions = ui.menuNetwork->actions();
bool alreadyAdded = false;
const int32_t& linkIndex(LinkManager::instance()->getLinks().indexOf(link));
const int32_t& linkID(LinkManager::instance()->getLinks()[linkIndex]->getId());
foreach (QAction* act, actions) {
if (act->data().toInt() == linkID) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, this);
commsWidgetList.append(commWidget);
connect(commWidget,SIGNAL(destroyed(QObject*)),this,SLOT(commsWidgetDestroyed(QObject*)));
QAction* action = commWidget->getAction();
ui.menuNetwork->addAction(action);
}
}
void MainWindow::simulateLink(bool simulate) {
if (simulate) {
if (!simulationLink) {
......@@ -1522,6 +1454,42 @@ void MainWindow::hideSplashScreen(void)
}
}
void MainWindow::manageLinks()
{
SettingsDialog settings(joystick, this, SettingsDialog::ShowCommLinks);
settings.exec();
}
/// @brief Saves the last used connection
void MainWindow::saveLastUsedConnection(const QString connection)
{
QSettings settings;
QString key(MAIN_SETTINGS_GROUP);
key += "/LAST_CONNECTION";
settings.setValue(key, connection);
}
/// @brief Restore (and connects) the last used connection (if any)
void MainWindow::restoreLastUsedConnection()
{
// TODO This should check and see of the port/whatever is present
// first. That is, if the last connection was to a PX4 on some serial
// port, it should check and see if the port is present before making
// the connection.
QSettings settings;
QString key(MAIN_SETTINGS_GROUP);
key += "/LAST_CONNECTION";
QString connection;
if(settings.contains(key)) {
connection = settings.value(connection).toString();
// Create a link for it
LinkInterface* link = LinkManager::instance()->createLink(connection);
if(link) {
// Connect it
LinkManager::instance()->connectLink(link);
}
}
}
#ifdef QGC_MOUSE_ENABLED_LINUX
bool MainWindow::x11Event(XEvent *event)
......
......@@ -120,11 +120,16 @@ public:
void hideSplashScreen(void);
/// @brief Saves the last used connection
void saveLastUsedConnection(const QString connection);
/// @brief Restore (and connects) the last used connection (if any)
void restoreLastUsedConnection();
public slots:
/** @brief Show the application settings */
void showSettings();
/** @brief Add a communication link */
LinkInterface* addLink();
bool configLink(LinkInterface *link);
/** @brief Simulate a link */
void simulateLink(bool simulate);
......@@ -158,6 +163,8 @@ public slots:
void loadGoogleEarthView();
/** @brief Load local 3D view */
void loadLocal3DView();
/** @brief Manage Links */
void manageLinks();
/** @brief Show the online help for users */
void showHelp();
......@@ -290,7 +297,6 @@ protected:
QTimer windowNameUpdateTimer;
private slots:
void _addLinkMenu(LinkInterface* link);
void _showDockWidgetAction(bool show);
void _loadCustomWidgetFromFile(void);
void _createNewCustomWidget(void);
......
......@@ -170,12 +170,8 @@
</property>
</action>
<action name="actionAdd_Link">
<property name="icon">
<iconset resource="../../qgroundcontrol.qrc">
<normaloff>:/files/images/actions/list-add.svg</normaloff>:/files/images/actions/list-add.svg</iconset>
</property>
<property name="text">
<string>Add Link</string>
<string>Manage Links</string>
</property>
</action>
<action name="actionSimulate">
......
#include <QPushButton>
#include "SerialLink.h"
#include "SerialConfigurationWindow.h"
#include "QGCUDPLinkConfiguration.h"
#include "QGCCommConfiguration.h"
#include "ui_QGCCommConfiguration.h"
QGCCommConfiguration::QGCCommConfiguration(QWidget *parent, LinkConfiguration *config) :
QDialog(parent),
_ui(new Ui::QGCCommConfiguration)
{
_ui->setupUi(this);
// Add link types
_config = config;
_ui->typeCombo->addItem(tr("Select Type"), LinkConfiguration::TypeLast);
_ui->typeCombo->addItem(tr("Serial"), LinkConfiguration::TypeSerial);
_ui->typeCombo->addItem(tr("UDP"), LinkConfiguration::TypeUdp);
#ifdef UNITTEST_BUILD
_ui->typeCombo->addItem(tr("Mock"), LinkConfiguration::TypeMock);
#endif
#if 0
_ui->typeCombo->addItem(tr("TCP"), LinkConfiguration::TypeTcp);
#ifdef QGC_RTLAB_ENABLED
_ui->typeCombo->addItem(tr("Opal-RT Link"), LinkConfiguration::TypeOpal);
#endif
#ifdef QGC_XBEE_ENABLED
_ui->typeCombo->addItem(tr("Xbee API"), LinkConfiguration::TypeXbee);
#endif
#endif
_ui->typeCombo->setEditable(false);
if(config && !config->name().isEmpty()) {
_ui->nameEdit->setText(config->name());
} else {
_ui->nameEdit->setText(tr("Unnamed"));
}
if(!config) {
setWindowTitle(tr("Add New Communication Link"));
} else {
setWindowTitle(tr("Edit Communication Link"));
_loadTypeConfigWidget(config->type());
_ui->typeCombo->setEnabled(false);
}
_updateUI();
}
QGCCommConfiguration::~QGCCommConfiguration()
{
delete _ui;
}
void QGCCommConfiguration::on_typeCombo_currentIndexChanged(int index)
{
int type = _ui->typeCombo->itemData(index).toInt();
_changeLinkType(type);
}
void QGCCommConfiguration::_changeLinkType(int type)
{
//-- Do we need to change anything?
if(type == LinkConfiguration::TypeLast || (_config && _config->type() == type)) {
return;
}
// Switching connection type. Delete old config.
delete _config;
// Create new config instance
QString name = _ui->nameEdit->text();
if(name.isEmpty()) {
name = tr("Untitled");
_ui->nameEdit->setText(name);
}
_config = LinkConfiguration::createSettings(type, name);
Q_ASSERT(_config != NULL);
_loadTypeConfigWidget(type);
_updateUI();
}
void QGCCommConfiguration::_loadTypeConfigWidget(int type)
{
Q_ASSERT(_config != NULL);
switch(type) {
case LinkConfiguration::TypeSerial: {
QWidget* conf = new SerialConfigurationWindow((SerialConfiguration*)_config, this);
_ui->linkScrollArea->setWidget(conf);
_ui->linkGroupBox->setTitle(tr("Serial Link"));
_ui->typeCombo->setCurrentIndex(_ui->typeCombo->findData(LinkConfiguration::TypeSerial));
}
break;
case LinkConfiguration::TypeUdp: {
QWidget* conf = new QGCUDPLinkConfiguration((UDPConfiguration*)_config, this);
_ui->linkScrollArea->setWidget(conf);
_ui->linkGroupBox->setTitle(tr("UDP Link"));
_ui->typeCombo->setCurrentIndex(_ui->typeCombo->findData(LinkConfiguration::TypeUdp));
}
break;
case LinkConfiguration::TypeMock: {
_ui->linkScrollArea->setWidget(NULL);
_ui->linkGroupBox->setTitle(tr("Mock Link"));
_ui->typeCombo->setCurrentIndex(_ui->typeCombo->findData(LinkConfiguration::TypeMock));
}
break;
// Cannot be the case, but in case it gets here, we cannot continue.
default:
reject();
break;
}
// Remove "Select Type" once something is selected
int idx = _ui->typeCombo->findData(LinkConfiguration::TypeLast);
if(idx >= 0) {
_ui->typeCombo->removeItem(idx);
}
}
void QGCCommConfiguration::_updateUI()
{
bool enableOK = false;
if(_config) {
if(!_ui->nameEdit->text().isEmpty()) {
enableOK = true;
}
}
QPushButton* ok = _ui->buttonBox->button(QDialogButtonBox::Ok);
Q_ASSERT(ok != NULL);
ok->setEnabled(enableOK);
}
void QGCCommConfiguration::on_buttonBox_accepted()
{
if(_config) {
_config->setName(_ui->nameEdit->text());
}
accept();
}
void QGCCommConfiguration::on_buttonBox_rejected()
{
reject();
}
void QGCCommConfiguration::on_nameEdit_textEdited(const QString &arg1)
{
Q_UNUSED(arg1);
_updateUI();
}
#ifndef QGCCOMMCONFIGURATION_H
#define QGCCOMMCONFIGURATION_H
#include <QWidget>
#include <QDialog>
#include "LinkConfiguration.h"
namespace Ui {
class QGCCommConfiguration;
}
class QGCCommConfiguration : public QDialog
{
Q_OBJECT
public:
explicit QGCCommConfiguration(QWidget *parent, LinkConfiguration* config = 0);
~QGCCommConfiguration();
enum {
QGC_LINK_SERIAL,
QGC_LINK_UDP,
QGC_LINK_TCP,
QGC_LINK_SIMULATION,
QGC_LINK_FORWARDING,
#ifdef UNITTEST_BUILD
QGC_LINK_MOCK,
#endif
#ifdef QGC_XBEE_ENABLED
QGC_LINK_XBEE,
#endif
#ifdef QGC_RTLAB_ENABLED
QGC_LINK_OPAL
#endif
};
LinkConfiguration* getConfig() { return _config; }
private slots:
void on_typeCombo_currentIndexChanged(int index);
void on_buttonBox_accepted();
void on_buttonBox_rejected();
void on_nameEdit_textEdited(const QString &arg1);
private:
void _changeLinkType(int type);
void _loadTypeConfigWidget(int type);
void _updateUI();
Ui::QGCCommConfiguration* _ui;
LinkConfiguration* _config;
};
#endif // QGCCOMMCONFIGURATION_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QGCCommConfiguration</class>
<widget class="QWidget" name="QGCCommConfiguration">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>450</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>450</width>
<height>450</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="nameLabel">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Link Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="typeLabel_3">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Link Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="typeCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="linkGroupBox">
<property name="title">
<string>Link</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="linkScrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>418</width>
<height>304</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Implementation of QGCLinkConfiguration
* @author Gus Grubba <mavlink@grubba.com>
*/
#include "SettingsDialog.h"
#include "QGCLinkConfiguration.h"
#include "ui_QGCLinkConfiguration.h"
#include "QGCCommConfiguration.h"
#include "QGCMessageBox.h"
QGCLinkConfiguration::QGCLinkConfiguration(QWidget *parent) :
QWidget(parent),
_ui(new Ui::QGCLinkConfiguration)
{
// Stop automatic link updates while this UI is up
LinkManager::instance()->suspendConfigurationUpdates(true);
_ui->setupUi(this);
_viewModel = new LinkViewModel;
_ui->linkView->setModel(_viewModel);
_ui->connectLinkButton->setEnabled(false);
_ui->delLinkButton->setEnabled(false);
_ui->editLinkButton->setEnabled(false);
}
QGCLinkConfiguration::~QGCLinkConfiguration()
{
if(_viewModel) delete _viewModel;
if(_ui) delete _ui;
// Resume automatic link updates
LinkManager::instance()->suspendConfigurationUpdates(false);
}
void QGCLinkConfiguration::on_delLinkButton_clicked()
{
QModelIndex index = _ui->linkView->currentIndex();
LinkConfiguration* config = _viewModel->getConfiguration(index.row());
if(config) {
// Ask user if they are sure
QMessageBox::StandardButton button = QGCMessageBox::question(
tr("Delete Link Configuration"),
tr("Are you sure you want to delete %1?\nDeleting a configuration will also disconnect it if connected.").arg(config->name()),
QMessageBox::Yes | QMessageBox::Cancel,
QMessageBox::Cancel);
if (button == QMessageBox::Yes) {
// Get link attached to this configuration (if any)
LinkInterface* iface = config->getLink();
if(iface) {
// Disconnect it (if connected)
LinkManager::instance()->disconnectLink(iface);
}
_viewModel->beginChange();
// Remove configuration
LinkManager::instance()->removeLinkConfiguration(config);
// Save list
LinkManager::instance()->saveLinkConfigurationList();
_viewModel->endChange();
}
}
}
void QGCLinkConfiguration::on_linkView_clicked(const QModelIndex &index)
{
LinkConfiguration* config = _viewModel->getConfiguration(index.row());
bool enabled = (config && !config->getLink());
_ui->connectLinkButton->setEnabled(enabled);
_ui->delLinkButton->setEnabled(config != NULL);
_ui->editLinkButton->setEnabled(config != NULL);
}
void QGCLinkConfiguration::on_connectLinkButton_clicked()
{
QModelIndex index = _ui->linkView->currentIndex();
LinkConfiguration* config = _viewModel->getConfiguration(index.row());
if(config) {
// Only connect if not already connected
if(!config->getLink()) {
LinkInterface* link = LinkManager::instance()->createLink(config);
if(link) {
// Connect it
LinkManager::instance()->connectLink(link);
// Now go hunting for the parent so we can shut this down
QWidget* pQw = parentWidget();
while(pQw) {
SettingsDialog* pDlg = dynamic_cast<SettingsDialog*>(pQw);
if(pDlg) {
pDlg->accept();
break;
}
pQw = pQw->parentWidget();
}
}
}
}
}
void QGCLinkConfiguration::on_editLinkButton_clicked()
{
QModelIndex index = _ui->linkView->currentIndex();
_editLink(index.row());
}
void QGCLinkConfiguration::on_addLinkButton_clicked()
{
QGCCommConfiguration* commDialog = new QGCCommConfiguration(this);
if(commDialog->exec() == QDialog::Accepted) {
// Save changes (if any)
LinkConfiguration* config = commDialog->getConfig();
if(config) {
//-- Check for "Unnamed"
if (config->name() == tr("Unnamed")) {
switch(config->type()) {
case LinkConfiguration::TypeSerial:
config->setName(
QString("Serial Device on %1").arg(dynamic_cast<SerialConfiguration*>(config)->portName()));
break;
case LinkConfiguration::TypeUdp:
config->setName(
QString("UDP Link on Port %1").arg(dynamic_cast<UDPConfiguration*>(config)->localPort()));
break;
case LinkConfiguration::TypeMock:
config->setName(
QString("Mock Link"));
break;
}
}
_viewModel->beginChange();
LinkManager::instance()->addLinkConfiguration(commDialog->getConfig());
LinkManager::instance()->saveLinkConfigurationList();
_viewModel->endChange();
}
}
}
void QGCLinkConfiguration::on_linkView_doubleClicked(const QModelIndex &index)
{
_editLink(index.row());
}
void QGCLinkConfiguration::_editLink(int row)
{
LinkConfiguration* config = _viewModel->getConfiguration(row);
if(config) {
LinkConfiguration* tmpConfig = LinkConfiguration::duplicateSettings(config);
QGCCommConfiguration* commDialog = new QGCCommConfiguration(this, tmpConfig);
if(commDialog->exec() == QDialog::Accepted) {
// Save changes (if any)
if(commDialog->getConfig()) {
_viewModel->beginChange();
config->copyFrom(tmpConfig);
// Save it
LinkManager::instance()->saveLinkConfigurationList();
_viewModel->endChange();
// Tell link about changes (if any)
config->updateSettings();
}
}
// Discard temporary duplicate
if(commDialog->getConfig())
delete commDialog->getConfig();
}
}
LinkViewModel::LinkViewModel(QObject *parent) : QAbstractListModel(parent)
{
Q_UNUSED(parent);
}
int LinkViewModel::rowCount( const QModelIndex & parent) const
{
Q_UNUSED(parent);
QList<LinkConfiguration*> cfgList = LinkManager::instance()->getLinkConfigurationList();
int count = cfgList.count();
return count;
}
QVariant LinkViewModel::data( const QModelIndex & index, int role) const
{
QList<LinkConfiguration*> cfgList = LinkManager::instance()->getLinkConfigurationList();
if (role == Qt::DisplayRole && index.row() < cfgList.count()) {
QString name(cfgList.at(index.row())->name());
return name;
}
return QVariant();
}
LinkConfiguration* LinkViewModel::getConfiguration(int row)
{
QList<LinkConfiguration*> cfgList = LinkManager::instance()->getLinkConfigurationList();
if(row < cfgList.count()) {
return cfgList.at(row);
}
return NULL;
}
#ifndef QGCLINKCONFIGURATION_H
#define QGCLINKCONFIGURATION_H
#include <QWidget>
#include <QListView>
#include "LinkManager.h"
namespace Ui {
class QGCLinkConfiguration;
}
class LinkViewModel;
class QGCLinkConfiguration : public QWidget
{
Q_OBJECT
public:
explicit QGCLinkConfiguration(QWidget *parent = 0);
~QGCLinkConfiguration();
private slots:
void on_delLinkButton_clicked();
void on_editLinkButton_clicked();
void on_addLinkButton_clicked();
void on_linkView_doubleClicked(const QModelIndex &index);
void on_linkView_clicked(const QModelIndex &index);
void on_connectLinkButton_clicked();
private:
void _editLink(int row);
Ui::QGCLinkConfiguration* _ui;
LinkViewModel* _viewModel;
};
class LinkViewModel : public QAbstractListModel
{
public:
LinkViewModel(QObject *parent = 0);
int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
LinkConfiguration* getConfiguration(int row);
void beginChange() { beginResetModel(); }
void endChange() { endResetModel(); }
};
#endif // QGCLINKCONFIGURATION_H
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QGCLinkConfiguration</class>
<widget class="QWidget" name="QGCLinkConfiguration">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>391</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="linkView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="delLinkButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editLinkButton">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addLinkButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="connectLinkButton">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
......@@ -26,13 +26,11 @@ This file is part of the QGROUNDCONTROL project
#include <QSpacerItem>
#include <QSerialPortInfo>
#include "SerialLink.h"
#include "UDPLink.h"
#include "SettingsDialog.h"
#include "QGCToolBar.h"
#include "UASManager.h"
#include "MainWindow.h"
#include "QGCApplication.h"
#include "CommConfigurationWindow.h"
QGCToolBar::QGCToolBar(QWidget *parent) :
QToolBar(parent),
......@@ -49,16 +47,14 @@ QGCToolBar::QGCToolBar(QWidget *parent) :
_linkMgr(LinkManager::instance()),
_linkCombo(NULL),
_linkComboAction(NULL),
_linkSelectedOnce(false),
_baudCombo(NULL),
_baudComboAction(NULL),
_linksConnected(false)
_linksConnected(false),
_linkSelected(false)
{
setObjectName("QGCToolBar");
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
connect(LinkManager::instance(), &LinkManager::linkConnected, this, &QGCToolBar::_linkConnected);
connect(LinkManager::instance(), &LinkManager::linkDisconnected, this, &QGCToolBar::_linkDisconnected);
connect(LinkManager::instance(), &LinkManager::linkConfigurationChanged, this, &QGCToolBar::_updateConfigurations);
}
void QGCToolBar::heartbeatTimeout(bool timeout, unsigned int ms)
......@@ -161,31 +157,14 @@ void QGCToolBar::createUI()
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
addWidget(spacer);
// Links to connect to
_linkCombo = new QComboBox(this);
_linkCombo->addItem("UDP");
connect(_linkCombo, SIGNAL(activated(int)), SLOT(_linkComboActivated(int)));
_linkCombo->setToolTip(tr("Choose the link to use"));
_linkCombo->setEnabled(true);
_linkCombo->setMinimumWidth(100);
_linkCombo->setMinimumWidth(160);
_linkComboAction = addWidget(_linkCombo);
_baudCombo = new QComboBox(this);
_baudCombo->setToolTip(tr("Choose what baud rate to use"));
_baudCombo->setEnabled(true);
_baudCombo->setMinimumWidth(40);
_baudCombo->addItem("9600", 9600);
_baudCombo->addItem("14400", 14400);
_baudCombo->addItem("19200", 19200);
_baudCombo->addItem("38400", 38400);
_baudCombo->addItem("57600", 57600);
_baudCombo->addItem("115200", 115200);
_baudCombo->addItem("230400", 230400);
_baudCombo->addItem("460800", 460800);
_baudCombo->addItem("921600", 921600);
_baudCombo->setCurrentIndex(_baudCombo->findData(57600));
_baudComboAction = addWidget(_baudCombo);
_updateConfigurations();
_connectButton = new QPushButton(tr("Connect"), this);
_connectButton->setObjectName("connectButton");
......@@ -203,9 +182,6 @@ void QGCToolBar::createUI()
setActiveUAS(UASManager::instance()->getActiveUAS());
connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
connect(&_portListTimer, &QTimer::timeout, this, &QGCToolBar::_updatePortList);
_portListTimer.start(500);
toolBarMessageAction->setVisible(false);
toolBarBatteryBarAction->setVisible(false);
......@@ -601,26 +577,6 @@ void QGCToolBar::receiveTextMessage(int uasid, int componentid, int severity, QS
lastSystemMessageTimeMs = QGC::groundTimeMilliseconds();
}
void QGCToolBar::_updatePortList(void)
{
if (!_linkCombo->isVisible()) {
return;
}
QList<QSerialPortInfo> portList = QSerialPortInfo::availablePorts();
foreach (QSerialPortInfo portInfo, portList) {
if (_linkCombo->findText(portInfo.portName()) == -1) {
_linkCombo->addItem(portInfo.portName());
if (!_linkSelectedOnce && portInfo.vendorIdentifier() == 9900) {
// Pre-Select 3DR connection
_linkSelectedOnce = true;
_linkCombo->setCurrentIndex(_linkCombo->findText(portInfo.portName()));
}
}
}
}
void QGCToolBar::_linkConnected(LinkInterface* link)
{
Q_UNUSED(link);
......@@ -636,9 +592,7 @@ void QGCToolBar::_linkDisconnected(LinkInterface* link)
void QGCToolBar::_updateConnectButton(void)
{
QMenu* menu = new QMenu(this);
// If there are multiple connected links add/update the connect button menu
int connectedCount = 0;
QList<LinkInterface*> links = _linkMgr->getLinks();
foreach(LinkInterface* link, links) {
......@@ -649,27 +603,21 @@ void QGCToolBar::_updateConnectButton(void)
connect(action, &QAction::triggered, this, &QGCToolBar::_disconnectFromMenu);
}
}
// Remove old menu
QMenu* oldMenu = _connectButton->menu();
_connectButton->setMenu(NULL);
if (oldMenu) {
oldMenu->deleteLater();
}
// Add new menu if needed
if (connectedCount > 1) {
_connectButton->setMenu(menu);
} else {
delete menu;
}
_linksConnected = connectedCount != 0;
_connectButton->setText(_linksConnected ? tr("Disconnect") : tr("Connect"));
_linkComboAction->setVisible(!_linksConnected);
_baudComboAction->setVisible(!_linksConnected);
toolBarMessageAction->setVisible(_linksConnected);
toolBarWpAction->setVisible(_linksConnected);
}
......@@ -677,12 +625,9 @@ void QGCToolBar::_updateConnectButton(void)
void QGCToolBar::_connectButtonClicked(bool checked)
{
Q_UNUSED(checked);
if (_linksConnected) {
// Disconnect
// Should be just one connected link, disconnect it
int connectedCount = 0;
LinkInterface* connectedLink = NULL;
QList<LinkInterface*> links = _linkMgr->getLinks();
......@@ -694,27 +639,31 @@ void QGCToolBar::_connectButtonClicked(bool checked)
}
Q_ASSERT(connectedCount == 1);
Q_ASSERT(connectedLink);
// TODO The link is "disconnected" but not deleted. On subsequent connections,
// new links are created. Why's that?
_linkMgr->disconnectLink(connectedLink);
} else {
// We don't want the combo box updating under our feet
_linkMgr->suspendConfigurationUpdates(true);
// Connect
QString linkName = _linkCombo->currentText();
if (linkName == "UDP") {
UDPLink* link = new UDPLink;
Q_CHECK_PTR(link);
_linkMgr->addLink(link);
CommConfigurationWindow* commDialog = new CommConfigurationWindow(link, this);
commDialog->exec();
} else {
// Must be a serial port
SerialLink* link = new SerialLink(linkName, _baudCombo->currentText().toInt());
Q_CHECK_PTR(link);
_linkMgr->addLink(link);
int valid = _linkCombo->currentData().toInt();
// Is this a valid option?
if(valid == 1) {
// Get the configuration name
QString confName = _linkCombo->currentText();
// Create a link for it
LinkInterface* link = _linkMgr->createLink(confName);
if(link) {
// Connect it
_linkMgr->connectLink(link);
// Save last used connection
MainWindow::instance()->saveLastUsedConnection(confName);
}
_linkMgr->suspendConfigurationUpdates(false);
// Else, it must be Manage Links
} else if(valid == 0) {
_linkMgr->suspendConfigurationUpdates(false);
MainWindow::instance()->manageLinks();
}
}
}
......@@ -722,13 +671,10 @@ void QGCToolBar::_connectButtonClicked(bool checked)
void QGCToolBar::_disconnectFromMenu(bool checked)
{
Q_UNUSED(checked);
QAction* action = qobject_cast<QAction*>(sender());
Q_ASSERT(action);
LinkInterface* link = (LinkInterface*)(action->data().value<void *>());
Q_ASSERT(link);
_linkMgr->disconnectLink(link);
}
......@@ -743,7 +689,36 @@ void QGCToolBar::clearStatusString()
void QGCToolBar::_linkComboActivated(int index)
{
Q_UNUSED(index);
int type = _linkCombo->itemData(index).toInt();
// Check if we should "Manage Connections"
if(type == 0) {
MainWindow::instance()->manageLinks();
} else {
_linkSelected = true;
}
}
_linkSelectedOnce = true;
void QGCToolBar::_updateConfigurations()
{
bool resetSelected = false;
QString selected = _linkCombo->currentText();
_linkCombo->clear();
_linkCombo->addItem("Manage Links", 0);
QList<LinkConfiguration*> configs = LinkManager::instance()->getLinkConfigurationList();
foreach(LinkConfiguration* conf, configs) {
if(conf) {
_linkCombo->addItem(conf->name(), 1);
if(!_linkSelected && conf->isPreferred()) {
selected = conf->name();
resetSelected = true;
}
}
}
int index = _linkCombo->findText(selected);
if(index >= 0) {
_linkCombo->setCurrentIndex(index);
}
if(resetSelected) {
_linkSelected = false;
}
}
......@@ -120,23 +120,19 @@ private slots:
void _disconnectFromMenu(bool checked);
void _connectButtonClicked(bool checked);
void _linkComboActivated(int index);
void _updateConfigurations();
private:
void _updateConnectButton(void);
void _updatePortList(void);
LinkManager* _linkMgr;
QComboBox* _linkCombo;
QAction* _linkComboAction;
bool _linkSelectedOnce;
QTimer _portListTimer;
QComboBox* _baudCombo;
QAction* _baudComboAction;
QPushButton* _connectButton;
bool _linksConnected;
bool _linkSelected; // User selected a link. Stop autoselecting it.
};
#endif // QGCTOOLBAR_H
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Implementation of QGCUDPLinkConfiguration
* @author Gus Grubba <mavlink@grubba.com>
*/
#include <QInputDialog>
#include "QGCUDPLinkConfiguration.h"
#include "ui_QGCUDPLinkConfiguration.h"
QGCUDPLinkConfiguration::QGCUDPLinkConfiguration(UDPLink* link, QWidget *parent) :
QWidget(parent),
link(link),
ui(new Ui::QGCUDPLinkConfiguration)
QGCUDPLinkConfiguration::QGCUDPLinkConfiguration(UDPConfiguration *config, QWidget *parent)
: QWidget(parent)
, _inConstructor(true)
, _ui(new Ui::QGCUDPLinkConfiguration)
{
ui->setupUi(this);
ui->portSpinBox->setValue(link->getPort());
connect(ui->portSpinBox, SIGNAL(valueChanged(int)), link, SLOT(setPort(int)));
connect(ui->addIPButton, SIGNAL(clicked()), this, SLOT(addHost()));
_config = config;
_ui->setupUi(this);
_viewModel = new UPDViewModel;
_ui->listView->setModel(_viewModel);
_ui->removeHost->setEnabled(false);
_ui->editHost->setEnabled(false);
_ui->portNumber->setRange(1024, 65535);
_ui->portNumber->setValue(_config->localPort());
_reloadList();
_inConstructor = false;
}
QGCUDPLinkConfiguration::~QGCUDPLinkConfiguration()
{
delete ui;
delete _ui;
}
void QGCUDPLinkConfiguration::_reloadList()
{
QString host;
int port;
if(_config->firstHost(host, port)) {
_viewModel->beginChange();
_viewModel->hosts.clear();
do {
_viewModel->hosts.append(QString("%1:%2").arg(host, QString::number(port)));
} while (_config->nextHost(host, port));
_viewModel->endChange();
}
}
void QGCUDPLinkConfiguration::changeEvent(QEvent *e)
void QGCUDPLinkConfiguration::_editHost(int row)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
if(row < _viewModel->hosts.count()) {
bool ok;
QString hostName = QInputDialog::getText(
this, tr("Edit a MAVLink host target"),
tr("Host (hostname:port): "), QLineEdit::Normal, _viewModel->hosts.at(row), &ok);
if (ok && !hostName.isEmpty()) {
_viewModel->beginChange();
_viewModel->hosts.replace(row, hostName);
_viewModel->endChange();
}
}
}
void QGCUDPLinkConfiguration::on_portNumber_valueChanged(int arg1)
{
if(!_inConstructor) {
_config->setLocalPort(arg1);
}
}
void QGCUDPLinkConfiguration::on_listView_clicked(const QModelIndex &index)
{
bool enabled = index.row() < _viewModel->hosts.count();
_ui->removeHost->setEnabled(enabled);
_ui->editHost->setEnabled(enabled);
}
void QGCUDPLinkConfiguration::addHost()
void QGCUDPLinkConfiguration::on_listView_doubleClicked(const QModelIndex &index)
{
_editHost(index.row());
}
void QGCUDPLinkConfiguration::on_addHost_clicked()
{
bool ok;
QString hostName = QInputDialog::getText(this, tr("Add a new IP address / hostname to MAVLink"),
tr("Host (hostname:port):"), QLineEdit::Normal,
"localhost:14555", &ok);
if (ok && !hostName.isEmpty())
link->addHost(hostName);
QString hostName = QInputDialog::getText(
this, tr("Add a host target to MAVLink"),
tr("Host (hostname:port): "),
QLineEdit::Normal, QString("localhost:%1").arg(QGC_UDP_PORT), &ok);
if (ok && !hostName.isEmpty()) {
_config->addHost(hostName);
_reloadList();
}
}
void QGCUDPLinkConfiguration::on_removeHost_clicked()
{
QModelIndex index = _ui->listView->currentIndex();
if(index.row() < _viewModel->hosts.count()) {
_viewModel->hosts.removeAt(index.row());
_reloadList();
}
}
void QGCUDPLinkConfiguration::on_editHost_clicked()
{
QModelIndex index = _ui->listView->currentIndex();
_editHost(index.row());
}
UPDViewModel::UPDViewModel(QObject *parent) : QAbstractListModel(parent)
{
Q_UNUSED(parent);
}
int UPDViewModel::rowCount( const QModelIndex & parent) const
{
Q_UNUSED(parent);
return hosts.count();
}
QVariant UPDViewModel::data( const QModelIndex & index, int role) const
{
if (role == Qt::DisplayRole && index.row() < hosts.count()) {
return hosts.at(index.row());
}
return QVariant();
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -37,7 +37,15 @@ class SettingsDialog : public QDialog
Q_OBJECT
public:
SettingsDialog(JoystickInput *joystick, QWidget *parent = 0, Qt::WindowFlags flags = Qt::Sheet);
enum {
ShowDefault,
ShowCommLinks,
ShowControllers,
ShowMavlink
};
SettingsDialog(JoystickInput *joystick, QWidget *parent = 0, int showTab = ShowDefault, Qt::WindowFlags flags = Qt::Sheet);
~SettingsDialog();
public slots:
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment