/** ****************************************************************************** * * @file IPconnectionplugin.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup IPConnPlugin IP Telemetry Plugin * @{ * @brief IP Connection Plugin impliment telemetry over TCP/IP and UDP/IP *****************************************************************************/ /* * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // The core of this plugin has been directly copied from the serial plugin and converted to work over a TCP link instead of a direct serial link #include "ipconnectionplugin.h" #include #include #include "ipconnection_internal.h" #include #include #include #include #include #include #include #include #include #include // Communication between IPconnectionConnection::OpenDevice() and IPConnection::onOpenDevice() QString errorMsg; QWaitCondition openDeviceWait; QWaitCondition closeDeviceWait; // QReadWriteLock dummyLock; QMutex ipConMutex; QAbstractSocket *ret; IPConnection::IPConnection(IPconnectionConnection *connection) : QObject() { moveToThread(Core::ICore::instance()->threadManager()->getRealTimeThread()); QObject::connect(connection, SIGNAL(CreateSocket(QString, int, bool)), this, SLOT(onOpenDevice(QString, int, bool))); QObject::connect(connection, SIGNAL(CloseSocket(QAbstractSocket *)), this, SLOT(onCloseDevice(QAbstractSocket *))); } /*IPConnection::~IPConnection() { }*/ void IPConnection::onOpenDevice(QString HostName, int Port, bool UseTCP) { QAbstractSocket *ipSocket; const int Timeout = 5 * 1000; ipConMutex.lock(); if (UseTCP) { ipSocket = new QTcpSocket(this); } else { ipSocket = new QUdpSocket(this); } // do sanity check on hostname and port... if ((HostName.length() == 0) || (Port < 1)) { errorMsg = "Please configure Host and Port options before opening the connection"; } else { // try to connect... ipSocket->connectToHost(HostName, Port); // in blocking mode so we wait for the connection to succeed if (ipSocket->waitForConnected(Timeout)) { ret = ipSocket; openDeviceWait.wakeAll(); ipConMutex.unlock(); return; } // tell user something went wrong errorMsg = ipSocket->errorString(); } /* BUGBUG TODO - returning null here leads to segfault because some caller still calls disconnect without checking our return value properly * someone needs to debug this, I got lost in the calling chain.*/ ret = NULL; openDeviceWait.wakeAll(); ipConMutex.unlock(); } void IPConnection::onCloseDevice(QAbstractSocket *ipSocket) { ipConMutex.lock(); ipSocket->close(); delete (ipSocket); closeDeviceWait.wakeAll(); ipConMutex.unlock(); } IPConnection *connection = 0; IPconnectionConnection::IPconnectionConnection() { ipSocket = NULL; // create all our objects m_config = new IPconnectionConfiguration("IP Network Telemetry", NULL, this); m_config->restoresettings(); m_optionspage = new IPconnectionOptionsPage(m_config, this); if (!connection) { connection = new IPConnection(this); } // just signal whenever we have a device event... QMainWindow *mw = Core::ICore::instance()->mainWindow(); QObject::connect(mw, SIGNAL(deviceChange()), this, SLOT(onEnumerationChanged())); QObject::connect(m_optionspage, SIGNAL(availableDevChanged()), this, SLOT(onEnumerationChanged())); } IPconnectionConnection::~IPconnectionConnection() { // clean up out resources... if (ipSocket) { ipSocket->close(); delete (ipSocket); } if (connection) { delete connection; connection = NULL; } } void IPconnectionConnection::onEnumerationChanged() { // no change from serial plugin emit availableDevChanged(this); } QList IPconnectionConnection::availableDevices() { QList list; device d; if (m_config->HostName().length() > 1) { d.displayName = (const QString)m_config->HostName(); } else { d.displayName = "Unconfigured"; } d.name = (const QString)m_config->HostName(); // we only have one "device" as defined by the configuration m_config list.append(d); return list; } QIODevice *IPconnectionConnection::openDevice(const QString &) { QString HostName; int Port; bool UseTCP; QMessageBox msgBox; // get the configuration info HostName = m_config->HostName(); Port = m_config->Port(); UseTCP = m_config->UseTCP(); if (ipSocket) { // Andrew: close any existing socket... this should never occur ipConMutex.lock(); emit CloseSocket(ipSocket); closeDeviceWait.wait(&ipConMutex); ipConMutex.unlock(); ipSocket = NULL; } ipConMutex.lock(); emit CreateSocket(HostName, Port, UseTCP); openDeviceWait.wait(&ipConMutex); ipConMutex.unlock(); ipSocket = ret; if (ipSocket == NULL) { msgBox.setText((const QString)errorMsg); msgBox.exec(); } return ipSocket; } void IPconnectionConnection::closeDevice(const QString &) { if (ipSocket) { ipConMutex.lock(); emit CloseSocket(ipSocket); closeDeviceWait.wait(&ipConMutex); ipConMutex.unlock(); ipSocket = NULL; } } QString IPconnectionConnection::connectionName() { // updated from serial plugin return QString("Network telemetry port"); } QString IPconnectionConnection::shortName() { // updated from serial plugin if (m_config->UseTCP()) { return QString("TCP"); } else { return QString("UDP"); } } IPconnectionPlugin::IPconnectionPlugin() { // no change from serial plugin } IPconnectionPlugin::~IPconnectionPlugin() { // manually remove the options page object removeObject(m_connection->Optionspage()); } void IPconnectionPlugin::extensionsInitialized() { addAutoReleasedObject(m_connection); } bool IPconnectionPlugin::initialize(const QStringList &arguments, QString *errorString) { Q_UNUSED(arguments); Q_UNUSED(errorString); m_connection = new IPconnectionConnection(); // must manage this registration of child object ourselves // if we use an autorelease here it causes the GCS to crash // as it is deleting objects as the app closes... addObject(m_connection->Optionspage()); return true; }