dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
connectionmanager.cpp
Go to the documentation of this file.
1 
14 /*
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  * for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, see <http://www.gnu.org/licenses/>
27  */
28 
29 #include "connectionmanager.h"
30 #include <coreplugin/icore.h>
31 #include <aggregation/aggregate.h>
32 #include <coreplugin/iconnection.h>
33 #include <coreplugin/idevice.h>
35 #include <QtSerialPort/QSerialPort>
36 #include <QtSerialPort/QSerialPortInfo>
37 #include <QDebug>
38 #include <QLabel>
39 #include <QHBoxLayout>
40 #include <QComboBox>
41 #include <QEventLoop>
42 #include <QMainWindow>
43 #include <alarmsmonitorwidget.h>
44 
45 namespace Core {
46 
48  : QWidget(mainWindow)
49  , m_availableDevList(nullptr)
50  , m_connectBtn(nullptr)
51  , m_ioDev(NULL)
52  , polling(true)
53  , m_mainWindow(mainWindow)
54 {
55  QHBoxLayout *layout = new QHBoxLayout;
56  layout->setSpacing(5);
57  layout->setContentsMargins(0, 0, 9, 0);
58 
62  layout->addWidget(m_monitorWidget, Qt::AlignHCenter | Qt::AlignVCenter);
63 
64  layout->addWidget(new QLabel(tr("Connections:")));
65 
66  m_availableDevList = new QComboBox;
67  m_availableDevList->setMinimumWidth(100);
68  m_availableDevList->setMaximumWidth(150);
69  m_availableDevList->setContextMenuPolicy(Qt::CustomContextMenu);
70  layout->addWidget(m_availableDevList, Qt::AlignVCenter);
71 
72  m_connectBtn = new QPushButton(tr("Connect"));
73  m_connectBtn->setEnabled(false);
74  layout->addWidget(m_connectBtn, Qt::AlignVCenter);
75 
76  setLayout(layout);
77 
78  modeStack->setCornerWidget(this, Qt::TopRightCorner);
79 
80  QObject::connect(m_connectBtn, SIGNAL(clicked()), this, SLOT(onConnectClicked()));
81 
82  // setup our reconnect timers
83  reconnect = new QTimer(this);
84  reconnectCheck = new QTimer(this);
85  connect(reconnect, SIGNAL(timeout()), this, SLOT(reconnectSlot()));
86  connect(reconnectCheck, SIGNAL(timeout()), this, SLOT(reconnectCheckSlot()));
87 }
88 
90 {
93  if (m_monitorWidget)
94  delete m_monitorWidget;
95 }
96 
98 {
99  // register to the plugin manager so we can receive
100  // new connection object from plugins
101  QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject *)),
102  this, SLOT(objectAdded(QObject *)));
103  QObject::connect(ExtensionSystem::PluginManager::instance(),
104  SIGNAL(aboutToRemoveObject(QObject *)), this,
105  SLOT(aboutToRemoveObject(QObject *)));
106 }
107 
112 void ConnectionManager::connectDeviceFailed(DevListItem &device)
113 {
114 
115  QString msg("<span style='color:red'>Failed</span> to connect device: ");
116  if (device.device)
117  msg.append(device.device->getDisplayName());
118  else
119  msg.append("Unknown");
120 
121 #ifdef Q_OS_LINUX
122  if (device.connection && device.connection->shortName() == "USB")
123  msg.append("<br />Have you set udev rules?");
124 #endif
125 
126  QMessageBox msgFailedToConnect(dynamic_cast<QWidget *>(Core::ICore::instance()->mainWindow()));
127  msgFailedToConnect.setText(msg);
128  msgFailedToConnect.open();
129 }
130 
134 bool ConnectionManager::connectDevice(DevListItem device)
135 {
136  if (!device.connection) {
137  return false;
138  }
139 
140  QIODevice *io_dev = device.connection->openDevice(device.device);
141  if (!io_dev) {
142  return false;
143  }
144 
145  io_dev->open(QIODevice::ReadWrite);
146 
147  // check if opening the device worked
148  if (!io_dev->isOpen()) {
149  return false;
150  }
151 
152  // The device is connected make it the one selected on the dropbox
153  for (int x = 0; x < m_availableDevList->count(); ++x) {
154  if (device.getConName() == m_availableDevList->itemData(x, Qt::ToolTipRole).toString())
155  m_availableDevList->setCurrentIndex(x);
156  }
157  // we appear to have connected to the device OK
158  // remember the connection/device details
159  m_connectionDevice = device;
160  m_ioDev = io_dev;
161 
162  connect(m_connectionDevice.connection, SIGNAL(destroyed(QObject *)), this,
163  SLOT(onConnectionDestroyed(QObject *)), Qt::QueuedConnection);
164 
165  // signal interested plugins that we connected to the device
166  emit deviceConnected(io_dev);
167  m_connectBtn->setText("Disconnect");
168  m_availableDevList->setEnabled(false);
169 
170  // tell the monitorwidget we're conneced
172 
173  return true;
174 }
175 
181 {
182  // tell the monitor widget we're disconnected
184 
185  if (!m_ioDev) {
186  // apparently we are already disconnected: this can
187  // happen if a plugin tries to force a disconnect whereas
188  // we are not connected. Just return.
189  return false;
190  }
191 
192  // We are connected - disconnect from the device
193 
194  // stop our timers
195  if (reconnect->isActive())
196  reconnect->stop();
197  if (reconnectCheck->isActive())
198  reconnectCheck->stop();
199 
200  // signal interested plugins that user is disconnecting his device
202 
203  try {
206  }
207  } catch (...) { // handle exception
208  qDebug() << "Exception: m_connectionDevice.connection->closeDevice("
209  << m_connectionDevice.getConName() << ")";
210  }
211 
213  m_ioDev = NULL;
214 
215  emit deviceDisconnected();
216  m_connectBtn->setText("Connect");
217  m_availableDevList->setEnabled(true);
218 
219  return true;
220 }
221 
225 void ConnectionManager::objectAdded(QObject *obj)
226 {
227  // Check if a plugin added a connection object to the pool
228  IConnection *connection = Aggregation::query<IConnection>(obj);
229  if (!connection)
230  return;
231 
232  // register devices and populate CB
233  devChanged(connection);
234 
235  // Keep track of the registration to be able to tell plugins
236  // to do things
237  m_connectionsList.append(connection);
238 
239  QObject::connect(connection, SIGNAL(availableDevChanged(IConnection *)), this,
240  SLOT(devChanged(IConnection *)));
241 }
242 
243 void ConnectionManager::aboutToRemoveObject(QObject *obj)
244 {
245  // Check if a plugin added a connection object to the pool
246  IConnection *connection = Aggregation::query<IConnection>(obj);
247  if (!connection)
248  return;
249 
252  == connection) { // we are currently using the one that is about to be removed
255  m_ioDev = NULL;
256  }
257 
258  if (m_connectionsList.contains(connection))
259  m_connectionsList.removeAt(m_connectionsList.indexOf(connection));
260 }
261 
262 void ConnectionManager::onConnectionDestroyed(QObject *obj)
263 {
264  Q_UNUSED(obj)
266 }
267 
271 void ConnectionManager::onConnectClicked()
272 {
273  // Check if we have a ioDev already created:
274  if (!m_ioDev) {
275  // connecting to currently selected device
276  DevListItem device = findDevice(
277  m_availableDevList->itemData(m_availableDevList->currentIndex(), Qt::ToolTipRole)
278  .toString());
279  if (device.connection) {
280  if (!connectDevice(device)) {
281  connectDeviceFailed(device);
282  }
283  }
284  } else { // disconnecting
286  }
287 }
288 
293 {
294  qDebug() << "TelemetryMonitor: connected";
295 
296  if (reconnectCheck->isActive())
297  reconnectCheck->stop();
298 
299  // tell the monitor we're connected
301 }
302 
307 {
308  qDebug() << "TelemetryMonitor: disconnected";
309 
310  if (m_ioDev) {
311  if (m_connectionDevice.connection->reconnect()) // currently used with bluetooth only
312  {
313  if (!reconnect->isActive())
314  reconnect->start(1000);
315  }
316  }
317  // tell the monitor we're disconnected
319 }
320 
324 void ConnectionManager::telemetryUpdated(double txRate, double rxRate)
325 {
326  m_monitorWidget->updateTelemetry(txRate, rxRate);
327 }
328 
329 void ConnectionManager::reconnectSlot()
330 {
331  qDebug() << "reconnect";
332  if (m_ioDev->isOpen())
333  m_ioDev->close();
334 
335  if (m_ioDev->open(QIODevice::ReadWrite)) {
336  qDebug() << "reconnect successfull";
337  reconnect->stop();
338  reconnectCheck->start(20000);
339  } else
340  qDebug() << "reconnect NOT successfull";
341 }
342 
343 void ConnectionManager::reconnectCheckSlot()
344 {
345  reconnectCheck->stop();
346  reconnect->start(1000);
347 }
348 
353 {
354  foreach (DevListItem d, m_devList) {
355  if (d.getConName() == devName)
356  return d;
357  }
358 
359  qDebug() << "findDevice: cannot find " << devName << " in device list";
360 
361  DevListItem d;
362  d.connection = NULL;
363  return d;
364 }
365 
372 {
373  foreach (IConnection *cnx, m_connectionsList) {
374  cnx->suspendPolling();
375  }
376 
377  m_connectBtn->setEnabled(false);
378  m_availableDevList->setEnabled(false);
379  polling = false;
380 }
381 
387 {
388  foreach (IConnection *cnx, m_connectionsList) {
389  cnx->resumePolling();
390  }
391 
392  m_connectBtn->setEnabled(true);
393  m_availableDevList->setEnabled(true);
394  polling = true;
395 }
396 
401 {
402  return m_mainWindow->generalSettings()->autoConnect();
403 }
404 
411 {
412  // Get the updated list of devices
413  QList<IDevice *> availableDev = connection->availableDevices();
414 
415  // Go through the list of connections of that type. If they are not in the
416  // available device list then remove them. If they are connected, then
417  // disconnect them.
418  for (QLinkedList<DevListItem>::iterator iter = m_devList.begin(); iter != m_devList.end();) {
419  if (iter->connection != connection) {
420  ++iter;
421  continue;
422  }
423 
424  // See if device exists in the updated availability list
425  bool found = availableDev.contains(iter->device);
426  if (!found) {
427  // we are currently using the one we are about to erase
429  && m_connectionDevice.device == iter->device) {
431  }
432 
433  // We have to delete the IDevice in that DevListItem before getting rid
434  // of the iter itself
435  if (!iter->device.isNull())
436  iter->device->deleteLater();
437 
438  iter = m_devList.erase(iter);
439  } else
440  ++iter;
441  }
442 
443  // Add any back to list that don't exist
444  foreach (IDevice *dev, availableDev) {
445  bool found = m_devList.contains(DevListItem(connection, dev));
446  if (!found) {
447  registerDevice(connection, dev);
448  }
449  }
450 }
451 
459 {
460  DevListItem d(conn, device);
461  m_devList.append(d);
462 }
463 
469 void ConnectionManager::devChanged(IConnection *connection)
470 {
471  if (!ExtensionSystem::PluginManager::instance()->allPluginsLoaded()) {
472  connectionBackup.append(connection);
473  connect(ExtensionSystem::PluginManager::instance(), SIGNAL(pluginsLoadEnded()), this,
474  SLOT(connectionsCallBack()), Qt::UniqueConnection);
475  return;
476  }
477  // clear device list combobox
478  m_availableDevList->clear();
479 
480  // remove registered devices of this IConnection from the list
481  updateConnectionList(connection);
482 
484 
486 
487  // disable connection button if the liNameif (m_availableDevList->count() > 0)
488  if (m_availableDevList->count() > 0)
489  m_connectBtn->setEnabled(true);
490  else
491  m_connectBtn->setEnabled(false);
492 }
493 
495 {
496  // add all the list again to the combobox
497  foreach (DevListItem d, m_devList) {
498  m_availableDevList->addItem(d.getConName());
499  m_availableDevList->setItemData(m_availableDevList->count() - 1, d.getConName(),
500  Qt::ToolTipRole);
501  if (!m_ioDev && d.getConName().startsWith("USB")) {
502  if (m_mainWindow->generalSettings()->autoConnect()
503  || m_mainWindow->generalSettings()->autoSelect())
504  m_availableDevList->setCurrentIndex(m_availableDevList->count() - 1);
505 
506  if (m_mainWindow->generalSettings()->autoConnect() && polling) {
507  qDebug() << "Automatically opening device";
508  connectDevice(d);
509  qDebug() << "ConnectionManager::devChanged autoconnected USB device";
510  }
511  }
512  }
513  if (m_ioDev) // if a device is connected make it the one selected on the dropbox
514  {
515  for (int x = 0; x < m_availableDevList->count(); ++x) {
517  == m_availableDevList->itemData(x, Qt::ToolTipRole).toString())
518  m_availableDevList->setCurrentIndex(x);
519  }
520  }
521 }
522 
523 void Core::ConnectionManager::connectionsCallBack()
524 {
525  foreach (IConnection *con, connectionBackup) {
526  devChanged(con);
527  }
528  connectionBackup.clear();
529  disconnect(ExtensionSystem::PluginManager::instance(), SIGNAL(pluginsLoadEnded()), this,
530  SLOT(connectionsCallBack()));
531 }
532 
533 } // namespace Core
virtual QIODevice * openDevice(IDevice *device)=0
iter
Definition: OPPlots.m:115
QList< IConnection * > m_connectionsList
QGraphicsSvgItem * getBackgroundItem()
virtual void suspendPolling()
Definition: iconnection.h:77
QLinkedList< DevListItem > m_devList
virtual void closeDevice(const QString &deviceName)
Definition: iconnection.h:61
virtual bool reconnect()
Used to flag that the device wants that we try to reconnect if it gets disconnected Currently this sh...
Definition: iconnection.h:85
DevListItem findDevice(const QString &devName)
virtual QList< IDevice * > availableDevices()=0
virtual void resumePolling()
Definition: iconnection.h:78
void updateConnectionList(IConnection *connection)
static ICore * instance()
Definition: coreimpl.cpp:46
void init(QSvgRenderer *renderer, QGraphicsSvgItem *graph)
void telemetryUpdated(double txRate, double rxRate)
static AlarmsMonitorWidget & getInstance()
void availableDevicesChanged(const QLinkedList< Core::DevListItem > devices)
IPConnection * connection
IConnection * connection
QPointer< IDevice > device
Internal::GeneralSettings * generalSettings() const
Definition: mainwindow.cpp:975
void registerDevice(IConnection *conn, IDevice *device)
Definition: icore.h:39
ConnectionManager(Internal::MainWindow *mainWindow, QTabWidget *modeStack)
TelemetryMonitorWidget * m_monitorWidget
x
Definition: OPPlots.m:100
void updateTelemetry(double txRate, double rxRate)
Called by the UAVObject which got updated Updates the numeric value and/or the icon if the dial wants...
void deviceConnected(QIODevice *device)
bool connectDevice(DevListItem device)
virtual QString shortName()
Definition: iconnection.h:71