From e6bcf96e2af99862c68049b9e76ea2ab76790837 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 12:47:15 -0500 Subject: [PATCH 01/26] GCS USB: Remove unused include file --- ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h index ee9aa49aa..324471a14 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h @@ -31,7 +31,6 @@ #include "rawhid_global.h" #include "rawhid.h" #include "usbmonitor.h" -#include "usbsignalfilter.h" #include "coreplugin/iconnection.h" #include From e5ab9f0fdade3b8604b28e501d1ef3d85777b5f4 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 12:53:00 -0500 Subject: [PATCH 02/26] GCS ConnectionManager: Consolidate the unregistering and registering devices into one method --- .../plugins/coreplugin/connectionmanager.cpp | 30 ++++++++++--------- .../plugins/coreplugin/connectionmanager.h | 3 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index f49d98c0e..41672af1f 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -289,10 +289,11 @@ void ConnectionManager::resumePolling() } /** -* Unregister all devices from one connection plugin -* \param[in] connection Connection type that you want to forget about :) -*/ -void ConnectionManager::unregisterAll(IConnection *connection) + * Synchronize the list of connections displayed with those physically + * present + * @param[in] connection Connection type that you want to forget about :) + */ +void ConnectionManager::updateConnectionList(IConnection *connection) { for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) { @@ -309,6 +310,16 @@ void ConnectionManager::unregisterAll(IConnection *connection) else ++iter; } + + //and add them back in the list + QList availableDev = connection->availableDevices(); + foreach (IConnection::device dev, availableDev) + { + QString cbName = connection->shortName() + ": " + dev.name; + QString disp = connection->shortName() + " : " + dev.displayName; + registerDevice(connection,cbName,dev.name,disp); + } + } /** @@ -344,16 +355,7 @@ void ConnectionManager::devChanged(IConnection *connection) m_availableDevList->clear(); //remove registered devices of this IConnection from the list - unregisterAll(connection); - - //and add them back in the list - QList availableDev = connection->availableDevices(); - foreach (IConnection::device dev, availableDev) - { - QString cbName = connection->shortName() + ": " + dev.name; - QString disp = connection->shortName() + " : " + dev.displayName; - registerDevice(connection,cbName,dev.name,disp); - } + updateConnectionList(connection); //add all the list again to the combobox foreach (devListItem d, m_devList) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 289e65590..06b7afe39 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -81,7 +81,7 @@ public: void resumePolling(); protected: - void unregisterAll(IConnection *connection); + void updateConnectionList(IConnection *connection); void registerDevice(IConnection *conn, const QString &devN, const QString &name, const QString &disp); devListItem findDevice(const QString &devName); @@ -96,7 +96,6 @@ private slots: void onConnectPressed(); void devChanged(IConnection *connection); -// void onConnectionClosed(QObject *obj); void onConnectionDestroyed(QObject *obj); void connectionsCallBack(); //used to call devChange after all the plugins are loaded protected: From 44e7c4542f91b4a987d3348a47cf7aeeb3ec8ff2 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 13:23:37 -0500 Subject: [PATCH 03/26] GCS USB: Implement structure for only adding new devices but need a way of identifying them --- .../plugins/coreplugin/connectionmanager.cpp | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 41672af1f..66cc5fa38 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -295,29 +295,52 @@ void ConnectionManager::resumePolling() */ void ConnectionManager::updateConnectionList(IConnection *connection) { - for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) + QList availableDev = connection->availableDevices(); + + // Go through the list of connections of that type. If they are not in the + // available device list then remove them. If they are connected, then + // disconnect them. + + for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) { if (iter->connection == connection) { - if (m_connectionDevice.connection && m_connectionDevice.connection == connection) - { // we are currently using the one we are about to erase - //onConnectionClosed(m_connectionDevice.connection); - disconnectDevice(); - } + // See if device exists in the updated availability list + bool found = false; + foreach (IConnection::device dev, availableDev) + if (false) // TODO: Need some way of indicating a IOConnection::device matches a devListItem + found = true; - iter = m_devList.erase(iter); + if (!found) { + if (m_connectionDevice.connection && m_connectionDevice.connection == connection) + { // we are currently using the one we are about to erase + //onConnectionClosed(m_connectionDevice.connection); + disconnectDevice(); + } + + iter = m_devList.erase(iter); + } } else ++iter; } + // Go through the list of available devices. If they are not present in the device list + // add them. + //and add them back in the list - QList availableDev = connection->availableDevices(); foreach (IConnection::device dev, availableDev) { - QString cbName = connection->shortName() + ": " + dev.name; - QString disp = connection->shortName() + " : " + dev.displayName; - registerDevice(connection,cbName,dev.name,disp); + bool found = false; + foreach (devListItem devList, m_devList) + if (false) + found = true; + + if (!found) { + QString cbName = connection->shortName() + ": " + dev.name; + QString disp = connection->shortName() + " : " + dev.displayName; + registerDevice(connection,cbName,dev.name,disp); + } } } From 9912432e84debb308245f82a86c8438a867785e3 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 13:33:50 -0500 Subject: [PATCH 04/26] GCS ConnectionManager: Remove some commented code --- .../plugins/coreplugin/connectionmanager.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 66cc5fa38..be39e56a2 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -44,25 +44,18 @@ namespace Core { ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidget *modeStack) : - QWidget(mainWindow), // Pip + QWidget(mainWindow), m_availableDevList(0), m_connectBtn(0), m_ioDev(NULL), m_mainWindow(mainWindow) { - // Q_UNUSED(mainWindow); - -/* QVBoxLayout *top = new QVBoxLayout; - top->setSpacing(0); - top->setMargin(0);*/ - QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing(5); layout->setContentsMargins(5,5,5,5); layout->addWidget(new QLabel(tr("Connections:"))); m_availableDevList = new QComboBox; - //m_availableDevList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_availableDevList->setMinimumWidth(100); m_availableDevList->setMaximumWidth(150); m_availableDevList->setContextMenuPolicy(Qt::CustomContextMenu); @@ -72,13 +65,8 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidge m_connectBtn->setEnabled(false); layout->addWidget(m_connectBtn); -/* Utils::StyledBar *bar = new Utils::StyledBar; - bar->setLayout(layout); - - top->addWidget(bar);*/ setLayout(layout); - // modeStack->insertCornerWidget(modeStack->cornerWidgetCount()-1, this); modeStack->setCornerWidget(this, Qt::TopRightCorner); QObject::connect(m_connectBtn, SIGNAL(pressed()), this, SLOT(onConnectPressed())); @@ -86,8 +74,8 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidge ConnectionManager::~ConnectionManager() { - disconnectDevice(); // Pip - suspendPolling(); // Pip + disconnectDevice(); + suspendPolling(); } void ConnectionManager::init() From 3563c7376f5c01a15175ecc3de9ffda3f53f66cf Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 14:04:59 -0500 Subject: [PATCH 05/26] GCS ConnectionManager: When plugging in a new device don't glitch the connectionwq --- .../plugins/coreplugin/connectionmanager.cpp | 20 +++++++++---------- .../plugins/coreplugin/connectionmanager.h | 4 +++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index be39e56a2..0bacf9921 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -296,7 +296,7 @@ void ConnectionManager::updateConnectionList(IConnection *connection) // See if device exists in the updated availability list bool found = false; foreach (IConnection::device dev, availableDev) - if (false) // TODO: Need some way of indicating a IOConnection::device matches a devListItem + if (iter->device == dev) // TODO: Need some way of indicating a IOConnection::device matches a devListItem found = true; if (!found) { @@ -307,7 +307,8 @@ void ConnectionManager::updateConnectionList(IConnection *connection) } iter = m_devList.erase(iter); - } + } else + ++iter; } else ++iter; @@ -321,13 +322,11 @@ void ConnectionManager::updateConnectionList(IConnection *connection) { bool found = false; foreach (devListItem devList, m_devList) - if (false) + if (devList.device == dev) found = true; if (!found) { - QString cbName = connection->shortName() + ": " + dev.name; - QString disp = connection->shortName() + " : " + dev.displayName; - registerDevice(connection,cbName,dev.name,disp); + registerDevice(connection,dev); } } @@ -339,13 +338,14 @@ void ConnectionManager::updateConnectionList(IConnection *connection) * @param disp is the name that is displayed in the dropdown menu * @param name is the actual device name */ -void ConnectionManager::registerDevice(IConnection *conn, const QString &devN, const QString &name, const QString &disp) +void ConnectionManager::registerDevice(IConnection *conn, IConnection::device device) { devListItem d; d.connection = conn; - d.devName = devN; - d.Name = name; - d.displayName=disp; + d.device = device; + d.devName = conn->shortName() + ": " + device.name; + d.Name = device.name; + d.displayName = conn->shortName() + " : " + device.displayName; m_devList.append(d); } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 06b7afe39..6a6328f9e 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -32,6 +32,7 @@ #include #include "mainwindow.h" #include "generalsettings.h" +#include #include #include #include @@ -58,6 +59,7 @@ namespace Internal { struct devListItem { IConnection *connection; + IConnection::device device; QString devName; QString Name; QString displayName; @@ -82,7 +84,7 @@ public: protected: void updateConnectionList(IConnection *connection); - void registerDevice(IConnection *conn, const QString &devN, const QString &name, const QString &disp); + void registerDevice(IConnection *conn, IConnection::device device); devListItem findDevice(const QString &devName); signals: From 1ca8abb3c8c5b517eb88e2a2ec4a59d23e4992e6 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 14:31:16 -0500 Subject: [PATCH 06/26] GCS ConnectionManager: Properly check it is the active connection before closing it when a USB device is disconnected. --- .../src/plugins/coreplugin/connectionmanager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 0bacf9921..2a158fae4 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -193,8 +193,9 @@ void ConnectionManager::aboutToRemoveObject(QObject *obj) IConnection *connection = Aggregation::query(obj); if (!connection) return; - if (m_connectionDevice.connection && m_connectionDevice.connection == connection) // Pip + if (m_connectionDevice.connection && m_connectionDevice.connection == connection) { // we are currently using the one that is about to be removed + disconnectDevice(); m_connectionDevice.connection = NULL; m_ioDev = NULL; } @@ -204,7 +205,7 @@ void ConnectionManager::aboutToRemoveObject(QObject *obj) } -void ConnectionManager::onConnectionDestroyed(QObject *obj) // Pip +void ConnectionManager::onConnectionDestroyed(QObject *obj) { Q_UNUSED(obj) //onConnectionClosed(obj); @@ -300,7 +301,7 @@ void ConnectionManager::updateConnectionList(IConnection *connection) found = true; if (!found) { - if (m_connectionDevice.connection && m_connectionDevice.connection == connection) + if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) { // we are currently using the one we are about to erase //onConnectionClosed(m_connectionDevice.connection); disconnectDevice(); From 65ef8a59b4f1a8e64440ba59a3a3d35f6d2a8a17 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 15:14:06 -0500 Subject: [PATCH 07/26] GCS ConnectionManager: Get rid of all the copies of various forms of the names and store a handle to the IConnection::device and generate the appropriate names from consistent functions. --- .../plugins/coreplugin/connectionmanager.cpp | 115 ++++++++---------- .../plugins/coreplugin/connectionmanager.h | 13 +- .../plugins/uploader/uploadergadgetwidget.cpp | 4 +- 3 files changed, 65 insertions(+), 67 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 2a158fae4..709dee816 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -45,10 +45,10 @@ namespace Core { ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidget *modeStack) : QWidget(mainWindow), - m_availableDevList(0), + m_availableDevList(0), m_connectBtn(0), - m_ioDev(NULL), - m_mainWindow(mainWindow) + m_ioDev(NULL), + m_mainWindow(mainWindow) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing(5); @@ -69,7 +69,7 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidge modeStack->setCornerWidget(this, Qt::TopRightCorner); - QObject::connect(m_connectBtn, SIGNAL(pressed()), this, SLOT(onConnectPressed())); + QObject::connect(m_connectBtn, SIGNAL(pressed()), this, SLOT(onConnectPressed())); } ConnectionManager::~ConnectionManager() @@ -82,8 +82,8 @@ void ConnectionManager::init() { //register to the plugin manager so we can receive //new connection object from plugins - QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)), this, SLOT(objectAdded(QObject*))); - QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)), this, SLOT(aboutToRemoveObject(QObject*))); + QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)), this, SLOT(objectAdded(QObject*))); + QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)), this, SLOT(aboutToRemoveObject(QObject*))); } /** @@ -95,7 +95,7 @@ bool ConnectionManager::connectDevice() if (!connection_device.connection) return false; - QIODevice *io_dev = connection_device.connection->openDevice(connection_device.Name); + QIODevice *io_dev = connection_device.connection->openDevice(connection_device.device.name); if (!io_dev) return false; @@ -105,15 +105,6 @@ bool ConnectionManager::connectDevice() if (!io_dev->isOpen()) { qDebug() << "Error: io_dev->isOpen() returned FALSE .. could not open connection to " << connection_device.devName << ": " << io_dev->errorString(); - - // close the device - // EDOUARD: why do we close if we could not open ??? - try { - connection_device.connection->closeDevice(connection_device.devName); - } - catch (...) { // handle exception - qDebug() << "Exception: connection_device.connection->closeDevice(" << connection_device.devName << ")"; - } return false; } @@ -150,8 +141,9 @@ bool ConnectionManager::disconnectDevice() emit deviceAboutToDisconnect(); try { - if (m_connectionDevice.connection) - m_connectionDevice.connection->closeDevice(m_connectionDevice.devName); + if (m_connectionDevice.connection) { + m_connectionDevice.connection->closeDevice(m_connectionDevice.getConName()); + } } catch (...) { // handle exception qDebug() << "Exception: m_connectionDevice.connection->closeDevice(" << m_connectionDevice.devName << ")"; } @@ -172,7 +164,7 @@ void ConnectionManager::objectAdded(QObject *obj) { //Check if a plugin added a connection object to the pool IConnection *connection = Aggregation::query(obj); - if (!connection) return; + if (!connection) return; //qDebug() << "Connection object registered:" << connection->connectionName(); //qDebug() << connection->availableDevices(); @@ -184,24 +176,24 @@ void ConnectionManager::objectAdded(QObject *obj) // to do things m_connectionsList.append(connection); - QObject::connect(connection, SIGNAL(availableDevChanged(IConnection *)), this, SLOT(devChanged(IConnection *))); + QObject::connect(connection, SIGNAL(availableDevChanged(IConnection *)), this, SLOT(devChanged(IConnection *))); } void ConnectionManager::aboutToRemoveObject(QObject *obj) { //Check if a plugin added a connection object to the pool IConnection *connection = Aggregation::query(obj); - if (!connection) return; + if (!connection) return; if (m_connectionDevice.connection && m_connectionDevice.connection == connection) - { // we are currently using the one that is about to be removed + { // we are currently using the one that is about to be removed disconnectDevice(); - m_connectionDevice.connection = NULL; - m_ioDev = NULL; - } + m_connectionDevice.connection = NULL; + m_ioDev = NULL; + } - if (m_connectionsList.contains(connection)) - m_connectionsList.removeAt(m_connectionsList.indexOf(connection)); + if (m_connectionsList.contains(connection)) + m_connectionsList.removeAt(m_connectionsList.indexOf(connection)); } @@ -233,9 +225,9 @@ void ConnectionManager::onConnectPressed() */ devListItem ConnectionManager::findDevice(const QString &devName) { - foreach (devListItem d, m_devList) + foreach (devListItem d, m_devList) { - if (d.devName == devName) + if (d.getConName() == devName) return d; } @@ -253,13 +245,13 @@ devListItem ConnectionManager::findDevice(const QString &devName) */ void ConnectionManager::suspendPolling() { - foreach (IConnection *cnx, m_connectionsList) - { + foreach (IConnection *cnx, m_connectionsList) + { cnx->suspendPolling(); } - m_connectBtn->setEnabled(false); - m_availableDevList->setEnabled(false); + m_connectBtn->setEnabled(false); + m_availableDevList->setEnabled(false); } /** @@ -268,13 +260,13 @@ void ConnectionManager::suspendPolling() */ void ConnectionManager::resumePolling() { - foreach (IConnection *cnx, m_connectionsList) - { + foreach (IConnection *cnx, m_connectionsList) + { cnx->resumePolling(); } - m_connectBtn->setEnabled(true); - m_availableDevList->setEnabled(true); + m_connectBtn->setEnabled(true); + m_availableDevList->setEnabled(true); } /** @@ -291,9 +283,9 @@ void ConnectionManager::updateConnectionList(IConnection *connection) // disconnect them. for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) - { - if (iter->connection == connection) - { + { + if (iter->connection == connection) + { // See if device exists in the updated availability list bool found = false; foreach (IConnection::device dev, availableDev) @@ -303,17 +295,16 @@ void ConnectionManager::updateConnectionList(IConnection *connection) if (!found) { if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) { // we are currently using the one we are about to erase - //onConnectionClosed(m_connectionDevice.connection); disconnectDevice(); } iter = m_devList.erase(iter); } else ++iter; - } - else - ++iter; - } + } + else + ++iter; + } // Go through the list of available devices. If they are not present in the device list // add them. @@ -344,9 +335,6 @@ void ConnectionManager::registerDevice(IConnection *conn, IConnection::device de devListItem d; d.connection = conn; d.device = device; - d.devName = conn->shortName() + ": " + device.name; - d.Name = device.name; - d.displayName = conn->shortName() + " : " + device.displayName; m_devList.append(d); } @@ -369,12 +357,24 @@ void ConnectionManager::devChanged(IConnection *connection) //remove registered devices of this IConnection from the list updateConnectionList(connection); + updateConnectionDropdown(); + + + //disable connection button if the liNameif (m_availableDevList->count() > 0) + if (m_availableDevList->count() > 0) + m_connectBtn->setEnabled(true); + else + m_connectBtn->setEnabled(false); +} + +void ConnectionManager::updateConnectionDropdown() +{ //add all the list again to the combobox foreach (devListItem d, m_devList) { - m_availableDevList->addItem(d.displayName); - m_availableDevList->setItemData(m_availableDevList->count()-1,(const QString)d.devName,Qt::ToolTipRole); - if(!m_ioDev && d.displayName.startsWith("USB")) + m_availableDevList->addItem(d.getConName()); + m_availableDevList->setItemData(m_availableDevList->count()-1, d.getConName(), Qt::ToolTipRole); + if(!m_ioDev && d.getConName().startsWith("USB")) { if(m_mainWindow->generalSettings()->autoConnect() || m_mainWindow->generalSettings()->autoSelect()) m_availableDevList->setCurrentIndex(m_availableDevList->count()-1); @@ -389,19 +389,10 @@ void ConnectionManager::devChanged(IConnection *connection) { for(int x=0;xcount();++x) { - if(m_connectionDevice.devName==m_availableDevList->itemData(x,Qt::ToolTipRole).toString()) + if(m_connectionDevice.getConName()==m_availableDevList->itemData(x,Qt::ToolTipRole).toString()) m_availableDevList->setCurrentIndex(x); } } - - - //disable connection button if the liNameif (m_availableDevList->count() > 0) - if (m_availableDevList->count() > 0) - m_connectBtn->setEnabled(true); - else - m_connectBtn->setEnabled(false); -} - } void Core::ConnectionManager::connectionsCallBack() @@ -412,4 +403,6 @@ void Core::ConnectionManager::connectionsCallBack() } connectionBackup.clear(); disconnect(ExtensionSystem::PluginManager::instance(),SIGNAL(pluginsLoadEnded()),this,SLOT(connectionsCallBack())); +} + } //namespace Core diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 6a6328f9e..40990b6ca 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -56,13 +56,17 @@ namespace Internal { } // namespace Internal -struct devListItem +class devListItem { +public: IConnection *connection; IConnection::device device; - QString devName; - QString Name; - QString displayName; + + QString getConName() { + if (connection == NULL) + return ""; + return connection->shortName() + ": " + device.displayName; + } }; @@ -85,6 +89,7 @@ public: protected: void updateConnectionList(IConnection *connection); void registerDevice(IConnection *conn, IConnection::device device); + void updateConnectionDropdown(); devListItem findDevice(const QString &devName); signals: diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index a692433b1..bd8f960a7 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -249,8 +249,8 @@ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) // The board is now reset: we have to disconnect telemetry Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); - QString dli = cm->getCurrentDevice().Name; - QString dlj = cm->getCurrentDevice().devName; + QString dli = cm->getCurrentDevice().getConName(); + QString dlj = cm->getCurrentDevice().getConName(); cm->disconnectDevice(); QTimer::singleShot(200, &m_eventloop, SLOT(quit())); m_eventloop.exec(); From 19eaa77a151cfc3df98e2b04c64da115da221ffc Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 15:29:38 -0500 Subject: [PATCH 08/26] Remove some comments and unused variables --- .../src/plugins/coreplugin/connectionmanager.cpp | 8 +------- .../src/plugins/ipconnection/ipconnectionplugin.cpp | 5 ++--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 709dee816..0e29c20d5 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -103,8 +103,6 @@ bool ConnectionManager::connectDevice() // check if opening the device worked if (!io_dev->isOpen()) { - qDebug() << "Error: io_dev->isOpen() returned FALSE .. could not open connection to " << connection_device.devName - << ": " << io_dev->errorString(); return false; } @@ -145,7 +143,7 @@ bool ConnectionManager::disconnectDevice() m_connectionDevice.connection->closeDevice(m_connectionDevice.getConName()); } } catch (...) { // handle exception - qDebug() << "Exception: m_connectionDevice.connection->closeDevice(" << m_connectionDevice.devName << ")"; + qDebug() << "Exception: m_connectionDevice.connection->closeDevice(" << m_connectionDevice.getConName() << ")"; } m_connectionDevice.connection = NULL; @@ -166,9 +164,6 @@ void ConnectionManager::objectAdded(QObject *obj) IConnection *connection = Aggregation::query(obj); if (!connection) return; - //qDebug() << "Connection object registered:" << connection->connectionName(); - //qDebug() << connection->availableDevices(); - //register devices and populate CB devChanged(connection); @@ -200,7 +195,6 @@ void ConnectionManager::aboutToRemoveObject(QObject *obj) void ConnectionManager::onConnectionDestroyed(QObject *obj) { Q_UNUSED(obj) - //onConnectionClosed(obj); disconnectDevice(); } diff --git a/ground/openpilotgcs/src/plugins/ipconnection/ipconnectionplugin.cpp b/ground/openpilotgcs/src/plugins/ipconnection/ipconnectionplugin.cpp index 5d166584c..c4d95ec4b 100644 --- a/ground/openpilotgcs/src/plugins/ipconnection/ipconnectionplugin.cpp +++ b/ground/openpilotgcs/src/plugins/ipconnection/ipconnectionplugin.cpp @@ -73,7 +73,6 @@ void IPConnection::onOpenDevice(QString HostName, int Port, bool UseTCP) { QAbstractSocket *ipSocket; const int Timeout = 5 * 1000; - int state; ipConMutex.lock(); if (UseTCP) { @@ -175,7 +174,7 @@ QList IPconnectionConnection::availableDevices() return list; } -QIODevice *IPconnectionConnection::openDevice(const QString &deviceName) +QIODevice *IPconnectionConnection::openDevice(const QString &) { QString HostName; int Port; @@ -209,7 +208,7 @@ QIODevice *IPconnectionConnection::openDevice(const QString &deviceName) return ipSocket; } -void IPconnectionConnection::closeDevice(const QString &deviceName) +void IPconnectionConnection::closeDevice(const QString &) { if (ipSocket){ ipConMutex.lock(); From 8e8cbd0b7591cf8fdd86aa9f1f8f56cc505a92fc Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 15:45:08 -0500 Subject: [PATCH 09/26] GCS ConnectionManager: Use some cleaner code coventions --- .../plugins/coreplugin/connectionmanager.cpp | 25 ++++++++----------- .../plugins/coreplugin/connectionmanager.h | 14 +++++++---- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 0e29c20d5..9c75fafa8 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -91,7 +91,7 @@ void ConnectionManager::init() */ bool ConnectionManager::connectDevice() { - devListItem connection_device = findDevice(m_availableDevList->itemData(m_availableDevList->currentIndex(),Qt::ToolTipRole).toString()); + DevListItem connection_device = findDevice(m_availableDevList->itemData(m_availableDevList->currentIndex(),Qt::ToolTipRole).toString()); if (!connection_device.connection) return false; @@ -217,9 +217,9 @@ void ConnectionManager::onConnectPressed() /** * Find a device by its displayed (visible on screen) name */ -devListItem ConnectionManager::findDevice(const QString &devName) +DevListItem ConnectionManager::findDevice(const QString &devName) { - foreach (devListItem d, m_devList) + foreach (DevListItem d, m_devList) { if (d.getConName() == devName) return d; @@ -227,7 +227,7 @@ devListItem ConnectionManager::findDevice(const QString &devName) qDebug() << "findDevice: cannot find " << devName << " in device list"; - devListItem d; + DevListItem d; d.connection = NULL; return d; } @@ -276,21 +276,16 @@ void ConnectionManager::updateConnectionList(IConnection *connection) // available device list then remove them. If they are connected, then // disconnect them. - for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) + for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) { if (iter->connection == connection) { // See if device exists in the updated availability list - bool found = false; - foreach (IConnection::device dev, availableDev) - if (iter->device == dev) // TODO: Need some way of indicating a IOConnection::device matches a devListItem - found = true; - + bool found = availableDev.contains(iter->device); if (!found) { + // we are currently using the one we are about to erase if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) - { // we are currently using the one we are about to erase disconnectDevice(); - } iter = m_devList.erase(iter); } else @@ -307,7 +302,7 @@ void ConnectionManager::updateConnectionList(IConnection *connection) foreach (IConnection::device dev, availableDev) { bool found = false; - foreach (devListItem devList, m_devList) + foreach (DevListItem devList, m_devList) if (devList.device == dev) found = true; @@ -326,7 +321,7 @@ void ConnectionManager::updateConnectionList(IConnection *connection) */ void ConnectionManager::registerDevice(IConnection *conn, IConnection::device device) { - devListItem d; + DevListItem d; d.connection = conn; d.device = device; m_devList.append(d); @@ -364,7 +359,7 @@ void ConnectionManager::devChanged(IConnection *connection) void ConnectionManager::updateConnectionDropdown() { //add all the list again to the combobox - foreach (devListItem d, m_devList) + foreach (DevListItem d, m_devList) { m_availableDevList->addItem(d.getConName()); m_availableDevList->setItemData(m_availableDevList->count()-1, d.getConName(), Qt::ToolTipRole); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 40990b6ca..61344ee1e 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -56,7 +56,7 @@ namespace Internal { } // namespace Internal -class devListItem +class DevListItem { public: IConnection *connection; @@ -67,6 +67,10 @@ public: return ""; return connection->shortName() + ": " + device.displayName; } + + bool operator==(const DevListItem &rhs) { + return connection == rhs.connection && device == rhs.device; + } }; @@ -81,7 +85,7 @@ public: void init(); QIODevice* getCurrentConnection() { return m_ioDev; } - devListItem getCurrentDevice() { return m_connectionDevice;} + DevListItem getCurrentDevice() { return m_connectionDevice;} bool disconnectDevice(); void suspendPolling(); void resumePolling(); @@ -90,7 +94,7 @@ protected: void updateConnectionList(IConnection *connection); void registerDevice(IConnection *conn, IConnection::device device); void updateConnectionDropdown(); - devListItem findDevice(const QString &devName); + DevListItem findDevice(const QString &devName); signals: void deviceConnected(QIODevice *dev); @@ -108,11 +112,11 @@ private slots: protected: QComboBox *m_availableDevList; QPushButton *m_connectBtn; - QLinkedList m_devList; + QLinkedList m_devList; QList m_connectionsList; //currently connected connection plugin - devListItem m_connectionDevice; + DevListItem m_connectionDevice; //currently connected QIODevice QIODevice *m_ioDev; From 6840b8934b4bc5d02d4006e8fc2b711b87296353 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 15:59:54 -0500 Subject: [PATCH 10/26] GCS ConnectionManager: More cleaner code structure. --- .../plugins/coreplugin/connectionmanager.cpp | 44 +++++++------------ .../plugins/coreplugin/connectionmanager.h | 9 +++- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 9c75fafa8..ad1ba9dc4 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -270,47 +270,39 @@ void ConnectionManager::resumePolling() */ void ConnectionManager::updateConnectionList(IConnection *connection) { + // Get the updated list of devices QList availableDev = connection->availableDevices(); // Go through the list of connections of that type. If they are not in the // available device list then remove them. If they are connected, then // disconnect them. - for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ) { - if (iter->connection == connection) - { - // See if device exists in the updated availability list - bool found = availableDev.contains(iter->device); - if (!found) { - // we are currently using the one we are about to erase - if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) - disconnectDevice(); - - iter = m_devList.erase(iter); - } else - ++iter; + if (iter->connection != connection) { + ++iter; + continue; } - else + + // See if device exists in the updated availability list + bool found = availableDev.contains(iter->device); + if (!found) { + // we are currently using the one we are about to erase + if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) + disconnectDevice(); + + iter = m_devList.erase(iter); + } else ++iter; } - // Go through the list of available devices. If they are not present in the device list - // add them. - - //and add them back in the list + // Add any back to list that don't exist foreach (IConnection::device dev, availableDev) { - bool found = false; - foreach (DevListItem devList, m_devList) - if (devList.device == dev) - found = true; - + bool found = m_devList.contains(DevListItem(connection, dev)); if (!found) { registerDevice(connection,dev); } } - } /** @@ -321,9 +313,7 @@ void ConnectionManager::updateConnectionList(IConnection *connection) */ void ConnectionManager::registerDevice(IConnection *conn, IConnection::device device) { - DevListItem d; - d.connection = conn; - d.device = device; + DevListItem d(conn,device); m_devList.append(d); } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 61344ee1e..5bda7a324 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -59,8 +59,10 @@ namespace Internal { class DevListItem { public: - IConnection *connection; - IConnection::device device; + DevListItem(IConnection *c, IConnection::device d) : + connection(c), device(d) { } + + DevListItem() : connection(NULL) { } QString getConName() { if (connection == NULL) @@ -71,6 +73,9 @@ public: bool operator==(const DevListItem &rhs) { return connection == rhs.connection && device == rhs.device; } + + IConnection *connection; + IConnection::device device; }; From 2ec8434941dcea82ba4dc1e4dfa184e225356c5c Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 16:06:01 -0500 Subject: [PATCH 11/26] OSX USB: Make sure to store the run loop handle before connecting the signals that can use it. --- .../openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 382c43829..72d50ede2 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -166,6 +166,10 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) } else { IOHIDManagerSetDeviceMatching(hid_manager, NULL); } + + // Set the run loop reference before configuring the attach callback + the_correct_runloop = CFRunLoopGetCurrent(); + // set up a callbacks for device attach & detach IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); @@ -179,8 +183,6 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) CFRelease(hid_manager); return 0; } - // Set the run loop reference: - the_correct_runloop = CFRunLoopGetCurrent(); printf("run loop\n"); // let it do the callback for all devices while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; @@ -379,7 +381,8 @@ static void input_callback(void *context, IOReturn ret, void *sender, IOHIDRepor hid->last_buffer->next = n; hid->last_buffer = n; } - //qDebug() << "Stop CFRunLoop from input_callback" << CFRunLoopGetCurrent(); + + Q_ASSERT(the_correct_runloop != NULL); CFRunLoopStop(the_correct_runloop); } From 82f752685a885ac49850366f5de25fa0742f849c Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 19:06:03 -0500 Subject: [PATCH 12/26] GCS ConnectionManager: When polling is disabled don't automatically connect to boards either. --- .../src/plugins/coreplugin/connectionmanager.cpp | 5 ++++- .../src/plugins/coreplugin/connectionmanager.h | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index ad1ba9dc4..8a33727de 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -246,6 +246,7 @@ void ConnectionManager::suspendPolling() m_connectBtn->setEnabled(false); m_availableDevList->setEnabled(false); + polling = false; } /** @@ -261,6 +262,7 @@ void ConnectionManager::resumePolling() m_connectBtn->setEnabled(true); m_availableDevList->setEnabled(true); + polling = true; } /** @@ -357,8 +359,9 @@ void ConnectionManager::updateConnectionDropdown() { if(m_mainWindow->generalSettings()->autoConnect() || m_mainWindow->generalSettings()->autoSelect()) m_availableDevList->setCurrentIndex(m_availableDevList->count()-1); - if(m_mainWindow->generalSettings()->autoConnect()) + if(m_mainWindow->generalSettings()->autoConnect() && polling) { + qDebug() << "Automatically opening device"; connectDevice(); qDebug()<<"ConnectionManager::devChanged autoconnected USB device"; } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index 5bda7a324..53c2b4f23 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -113,7 +113,7 @@ private slots: void devChanged(IConnection *connection); void onConnectionDestroyed(QObject *obj); - void connectionsCallBack(); //used to call devChange after all the plugins are loaded + void connectionsCallBack(); //used to call devChange after all the plugins are loaded protected: QComboBox *m_availableDevList; QPushButton *m_connectBtn; @@ -128,8 +128,9 @@ protected: private: bool connectDevice(); - Internal::MainWindow *m_mainWindow; - QList connectionBackup; + bool polling; + Internal::MainWindow *m_mainWindow; + QList connectionBackup; }; From 9b7060a49137270e50943884e4469f941be8410a Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 19:07:14 -0500 Subject: [PATCH 13/26] GCS USB: Increase the max timeout before giving up on stopping the USB threads. --- ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp | 4 ++-- .../src/plugins/uploader/uploadergadgetwidget.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index 4649d6162..eadf55a0c 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -144,7 +144,7 @@ RawHIDReadThread::~RawHIDReadThread() { m_running = false; //wait for the thread to terminate - if(wait(1000) == false) + if(wait(10000) == false) qDebug() << "Cannot terminate RawHIDReadThread"; } @@ -216,7 +216,7 @@ RawHIDWriteThread::~RawHIDWriteThread() { m_running = false; //wait for the thread to terminate - if(wait(1000) == false) + if(wait(10000) == false) qDebug() << "Cannot terminate RawHIDReadThread"; } diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index bd8f960a7..841cb2304 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -456,7 +456,7 @@ void UploaderGadgetWidget::systemRescue() delete dfu; dfu = NULL; } - // Avoid dumb users pressing Rescue twice. It can happen. + // Avoid users pressing Rescue twice. m_config->rescueButton->setEnabled(false); // Now we're good to go: From 1aadcf4e70277e51e2dbe09f76e3b55220d4a6ac Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 19:31:32 -0500 Subject: [PATCH 14/26] GCS USB: Make sure to fully unregister all the callbacks when disconnect. --- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 20 +++++------ .../src/plugins/rawhid/rawhid.cpp | 34 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 72d50ede2..549ec3f24 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -69,18 +69,18 @@ static hid_t *last_hid = NULL; // Make sure we use the correct runloop CFRunLoopRef the_correct_runloop = NULL; struct hid_struct { - IOHIDDeviceRef ref; - int open; - uint8_t buffer[BUFFER_SIZE]; - buffer_t *first_buffer; - buffer_t *last_buffer; - struct hid_struct *prev; - struct hid_struct *next; + IOHIDDeviceRef ref; + int open; + uint8_t buffer[BUFFER_SIZE]; + buffer_t *first_buffer; + buffer_t *last_buffer; + struct hid_struct *prev; + struct hid_struct *next; }; struct buffer_struct { - struct buffer_struct *next; - uint32_t len; - uint8_t buf[BUFFER_SIZE]; + struct buffer_struct *next; + uint32_t len; + uint8_t buf[BUFFER_SIZE]; }; static void add_hid(hid_t *); diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index eadf55a0c..37400dfb1 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -383,29 +383,29 @@ bool RawHID::open(OpenMode mode) void RawHID::close() { - emit aboutToClose(); + emit aboutToClose(); - m_mutex->lock(); + m_mutex->lock(); - if (m_readThread) - { - m_readThread->terminate(); - delete m_readThread; // calls wait - m_readThread = NULL; - } + if (m_readThread) + { + m_readThread->terminate(); + delete m_readThread; // calls wait + m_readThread = NULL; + } - if (m_writeThread) - { - m_writeThread->terminate(); - delete m_writeThread; - m_writeThread = NULL; - } + if (m_writeThread) + { + m_writeThread->terminate(); + delete m_writeThread; + m_writeThread = NULL; + } - dev.close(m_deviceNo); + dev.close(m_deviceNo); - m_mutex->unlock(); + m_mutex->unlock(); - emit closed(); + emit closed(); QIODevice::close(); } From 3f11c398db8c708dcca826b662330bce5416a45a Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 19:45:02 -0500 Subject: [PATCH 15/26] GCS USB: Start with polling enabled so it acts like before and grabs first available USB device --- ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 8a33727de..962af8acb 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -48,6 +48,7 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow, QTabWidge m_availableDevList(0), m_connectBtn(0), m_ioDev(NULL), + polling(true), m_mainWindow(mainWindow) { QHBoxLayout *layout = new QHBoxLayout; From cf1c986550b785adef93f8b7ae98a22c47388c83 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 19:48:33 -0500 Subject: [PATCH 16/26] OSX USB: Close more handles properly --- ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 549ec3f24..28a02a970 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -436,8 +436,12 @@ static void free_all_hid(void) static void hid_close(hid_t *hid) { if (!hid || !hid->open || !hid->ref) return; + IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); IOHIDDeviceUnscheduleFromRunLoop(hid->ref, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode); IOHIDDeviceClose(hid->ref, kIOHIDOptionsTypeNone); + IOHIDManagerClose(hid_manager, 0); hid->ref = NULL; } From 44d271ac791f11465fa77fc260c891f5e2973565 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 20:04:44 -0500 Subject: [PATCH 17/26] GCS USB: Get rid of some unnecessary code --- .../src/plugins/rawhid/rawhid.cpp | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index 37400dfb1..ddead4e5a 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -300,29 +300,18 @@ RawHID::RawHID(const QString &deviceName) m_mutex(NULL) { - m_mutex = new QMutex(QMutex::Recursive); + m_mutex = new QMutex(QMutex::Recursive); - // detect if the USB device is unplugged - QObject::connect(&dev, SIGNAL(deviceUnplugged(int)), this, SLOT(onDeviceUnplugged(int))); + // detect if the USB device is unplugged + QObject::connect(&dev, SIGNAL(deviceUnplugged(int)), this, SLOT(onDeviceUnplugged(int))); - int opened = dev.open(USB_MAX_DEVICES, USBMonitor::idVendor_OpenPilot, -1, USB_USAGE_PAGE, USB_USAGE); - for (int i =0; i< opened; i++) { - if (deviceName == dev.getserial(i)) - m_deviceNo = i; - else - dev.close(i); - } - - /* - // TODO: NOT WORKING FOR MULTIPLE DEVICES with the same PID! - QList devices = USBMonitor::instance()->availableDevices(USBMonitor::idVendor_OpenPilot,-1,-1,USBMonitor::Running); - foreach( USBPortInfo device, devices) { - if (deviceName == device.serialNumber) { - opened = dev.open(1,device.vendorID, device.productID,USB_USAGE_PAGE,USB_USAGE); - break; - } - } - */ + int opened = dev.open(USB_MAX_DEVICES, USBMonitor::idVendor_OpenPilot, -1, USB_USAGE_PAGE, USB_USAGE); + for (int i =0; i< opened; i++) { + if (deviceName == dev.getserial(i)) + m_deviceNo = i; + else + dev.close(i); + } //didn't find the device we are trying to open (shouldnt happen) if (opened < 0) @@ -369,14 +358,10 @@ bool RawHID::open(OpenMode mode) QIODevice::open(mode); - if (!m_readThread) - m_readThread = new RawHIDReadThread(this); - - if (!m_writeThread) - m_writeThread = new RawHIDWriteThread(this); - - if (m_readThread) m_readThread->start(); // Pip - if (m_writeThread) m_writeThread->start(); // Pip + Q_ASSERT(m_readThread); + Q_ASSERT(m_writeThread); + if (m_readThread) m_readThread->start(); + if (m_writeThread) m_writeThread->start(); return true; } From b84f833287c7a1be82862bc3d218820236ea3065 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sat, 8 Sep 2012 20:05:07 -0500 Subject: [PATCH 18/26] GCS Uploader: Remove dialog about another board since it's not used for any boards now. --- .../plugins/uploader/uploadergadgetwidget.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index 841cb2304..0cbd033a0 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -523,25 +523,6 @@ void UploaderGadgetWidget::systemRescue() m_config->rescueButton->setEnabled(true); return; } - if ((eBoardCC != dfu->GetBoardType(0)) && (QMessageBox::question(this,tr("OpenPilot Uploader"),tr("If you want to search for other boards connect power now and press Yes"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes)) - { - log("\nWaiting..."); - QTimer::singleShot(3000, &m_eventloop, SLOT(quit())); - m_eventloop.exec(); - log("Detecting second board..."); - repaint(); - if(!dfu->findDevices()) - { - // We will only end up here in case somehow all the boards - // disappeared, including the one we detected earlier. - log("Could not detect any board, aborting!"); - delete dfu; - dfu = NULL; - cm->resumePolling(); - m_config->rescueButton->setEnabled(true); - return; - } - } log(QString("Found ") + QString::number(dfu->numberOfDevices) + QString(" device(s).")); if (dfu->numberOfDevices > 5) { log("Inconsistent number of devices, aborting!"); From 06fc1ed963d40eb4a24f3881c713d6ea4e24c865 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 9 Sep 2012 11:02:13 -0500 Subject: [PATCH 19/26] GCS USB: More the opening and closing code into the read thread to simplify some threading issues on OSX. Should not influence other operating systems. --- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 5 +- .../src/plugins/rawhid/rawhid.cpp | 67 ++++++++++++------- .../openpilotgcs/src/plugins/rawhid/rawhid.h | 7 ++ 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 28a02a970..a229cfdd2 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -117,7 +117,7 @@ pjrc_rawhid::~pjrc_rawhid() // int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) { - static IOHIDManagerRef hid_manager=NULL; + IOHIDManagerRef hid_manager=NULL; CFMutableDictionaryRef dict; CFNumberRef num; IOReturn ret; @@ -439,7 +439,7 @@ static void hid_close(hid_t *hid) IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); - IOHIDDeviceUnscheduleFromRunLoop(hid->ref, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode); + IOHIDDeviceUnscheduleFromRunLoop(hid->ref, the_correct_runloop, kCFRunLoopDefaultMode); IOHIDDeviceClose(hid->ref, kIOHIDOptionsTypeNone); IOHIDManagerClose(hid_manager, 0); hid->ref = NULL; @@ -463,7 +463,6 @@ static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDevic { struct hid_struct *h; - printf("attach callback\n"); if (IOHIDDeviceOpen(dev, kIOHIDOptionsTypeNone) != kIOReturnSuccess) return; h = (hid_t *)malloc(sizeof(hid_t)); if (!h) return; diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index ddead4e5a..e47f72bac 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -138,6 +138,7 @@ RawHIDReadThread::RawHIDReadThread(RawHID *hid) hidno(hid->m_deviceNo), m_running(true) { + hid->m_startedMutex->lock(); } RawHIDReadThread::~RawHIDReadThread() @@ -151,6 +152,7 @@ RawHIDReadThread::~RawHIDReadThread() void RawHIDReadThread::run() { qDebug() << "Read thread started"; + m_running = m_hid->openDevice(); while(m_running) { //here we use a temporary buffer so we don't need to lock @@ -182,6 +184,7 @@ void RawHIDReadThread::run() m_running=false; } } + m_hid->closeDevice(); } int RawHIDReadThread::getReadData(char *data, int size) @@ -301,13 +304,29 @@ RawHID::RawHID(const QString &deviceName) { m_mutex = new QMutex(QMutex::Recursive); + m_startedMutex = new QMutex(); // detect if the USB device is unplugged QObject::connect(&dev, SIGNAL(deviceUnplugged(int)), this, SLOT(onDeviceUnplugged(int))); + // Starting the read thread will lock the m_startexMutex until the + // device is opened + m_readThread = new RawHIDReadThread(this); + m_readThread->start(); + + m_startedMutex->lock(); +} + +/** + * @brief RawHID::openDevice This method opens the USB connection + * It is uses as a callback from the read thread so that the USB + * system code is registered in that thread instead of the calling + * thread (usually UI) + */ +bool RawHID::openDevice() { int opened = dev.open(USB_MAX_DEVICES, USBMonitor::idVendor_OpenPilot, -1, USB_USAGE_PAGE, USB_USAGE); for (int i =0; i< opened; i++) { - if (deviceName == dev.getserial(i)) + if (serialNumber == dev.getserial(i)) m_deviceNo = i; else dev.close(i); @@ -316,27 +335,31 @@ RawHID::RawHID(const QString &deviceName) //didn't find the device we are trying to open (shouldnt happen) if (opened < 0) { - qDebug() << "Error: cannot open device " << deviceName; - return; + return false; } - //m_deviceNo = 0; - m_readThread = new RawHIDReadThread(this); m_writeThread = new RawHIDWriteThread(this); - - m_readThread->start(); m_writeThread->start(); + + m_startedMutex->unlock(); + + return true; +} + +/** + * @brief RawHID::closeDevice This method closes the USB connection + * It is uses as a callback from the read thread so that the USB + * system code is unregistered from that thread\ + */ +bool RawHID::closeDevice() { + dev.close(m_deviceNo); } RawHID::~RawHID() { - dev.close(m_deviceNo); - - if (m_readThread) - delete m_readThread; - - if (m_writeThread) - delete m_writeThread; + // If the read thread exists then the device is open + if (m_readThread) + close(); } void RawHID::onDeviceUnplugged(int num) @@ -345,7 +368,6 @@ void RawHID::onDeviceUnplugged(int num) return; // the USB device has been unplugged - close(); } @@ -372,13 +394,6 @@ void RawHID::close() m_mutex->lock(); - if (m_readThread) - { - m_readThread->terminate(); - delete m_readThread; // calls wait - m_readThread = NULL; - } - if (m_writeThread) { m_writeThread->terminate(); @@ -386,7 +401,13 @@ void RawHID::close() m_writeThread = NULL; } - dev.close(m_deviceNo); + + if (m_readThread) + { + m_readThread->terminate(); + delete m_readThread; // calls wait + m_readThread = NULL; + } m_mutex->unlock(); diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/rawhid.h index 12ec78384..b12ef159d 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.h @@ -74,6 +74,12 @@ protected: virtual qint64 bytesAvailable() const; virtual qint64 bytesToWrite() const; + //! Callback from the read thread to open the device + bool openDevice(); + + //! Callback from teh read thread to close the device + bool closeDevice(); + QString serialNumber; int m_deviceNo; @@ -83,6 +89,7 @@ protected: RawHIDWriteThread *m_writeThread; QMutex *m_mutex; + QMutex *m_startedMutex; }; #endif // RAWHID_H From 8bb6a2600fa4d2fe55bfd271c90362cf4b59b7bd Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 9 Sep 2012 11:40:14 -0500 Subject: [PATCH 20/26] GCS Serial: Was double detecting USBCDC devices. --- .../src/qextserialenumerator_osx.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/ground/openpilotgcs/src/libs/qextserialport/src/qextserialenumerator_osx.cpp b/ground/openpilotgcs/src/libs/qextserialport/src/qextserialenumerator_osx.cpp index f8db6fbc6..9cf05e69c 100644 --- a/ground/openpilotgcs/src/libs/qextserialport/src/qextserialenumerator_osx.cpp +++ b/ground/openpilotgcs/src/libs/qextserialport/src/qextserialenumerator_osx.cpp @@ -22,8 +22,7 @@ QextSerialEnumerator::~QextSerialEnumerator( ) // static QList QextSerialEnumerator::getPorts() -{ - QList infoList; +{ QList infoList; io_iterator_t serialPortIterator = 0; kern_return_t kernResult = KERN_FAILURE; CFMutableDictionaryRef matchingDictionary; @@ -44,18 +43,6 @@ QList QextSerialEnumerator::getPorts() IOObjectRelease(serialPortIterator); serialPortIterator = 0; - if( !(matchingDictionary = IOServiceNameMatching("AppleUSBCDC")) ) { - qWarning("IOServiceNameMatching returned a NULL dictionary."); - return infoList; - } - - if( IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS ) { - qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult; - return infoList; - } - iterateServicesOSX(serialPortIterator, infoList); - IOObjectRelease(serialPortIterator); - return infoList; } From 741207ddc0d3ac3187de324768ca023c21d70ea5 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 9 Sep 2012 13:03:57 -0500 Subject: [PATCH 21/26] GCS OSX HID: Tweak the closing so that it doesn't crash. Still fails to unregister the input callback. --- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index a229cfdd2..c1cd83312 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -382,8 +382,8 @@ static void input_callback(void *context, IOReturn ret, void *sender, IOHIDRepor hid->last_buffer = n; } - Q_ASSERT(the_correct_runloop != NULL); - CFRunLoopStop(the_correct_runloop); + if (the_correct_runloop) + CFRunLoopStop(the_correct_runloop); } static void timeout_callback(CFRunLoopTimerRef timer, void *info) @@ -437,9 +437,12 @@ static void hid_close(hid_t *hid) { if (!hid || !hid->open || !hid->ref) return; IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (the_correct_runloop) + IOHIDDeviceUnscheduleFromRunLoop(hid->ref, the_correct_runloop, kCFRunLoopDefaultMode); + the_correct_runloop = NULL; + IOHIDDeviceRegisterInputReportCallback(hid->ref, hid->buffer, sizeof(hid->buffer), NULL, hid); IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); - IOHIDDeviceUnscheduleFromRunLoop(hid->ref, the_correct_runloop, kCFRunLoopDefaultMode); IOHIDDeviceClose(hid->ref, kIOHIDOptionsTypeNone); IOHIDManagerClose(hid_manager, 0); hid->ref = NULL; @@ -457,6 +460,10 @@ static void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDevic return; } } + + hid_t *hid = get_hid(0); + if (hid) + hid_close(hid); } static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) @@ -467,6 +474,11 @@ static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDevic h = (hid_t *)malloc(sizeof(hid_t)); if (!h) return; memset(h, 0, sizeof(hid_t)); + + // Disconnect the attach callback since we don't want to automatically reconnect + IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); + IOHIDDeviceScheduleWithRunLoop(dev, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); IOHIDDeviceRegisterInputReportCallback(dev, h->buffer, sizeof(h->buffer), input_callback, h); h->ref = dev; From 604e12525125e53f628d0ae7e0f38e5880050dfa Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 9 Sep 2012 17:10:50 -0500 Subject: [PATCH 22/26] GCS RawHID: Refactor the code to move most of the functionality into one class. Removed support for multiple open devices since we can just use multiple classes. --- .../src/plugins/rawhid/pjrc_rawhid.h | 22 +- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 493 ++++++------------ 2 files changed, 188 insertions(+), 327 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h index 3ff096db5..8ba8d458a 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h @@ -96,7 +96,7 @@ public: pjrc_rawhid(); ~pjrc_rawhid(); int open(int max, int vid, int pid, int usage_page, int usage); - int receive(int num, void *buf, int len, int timeout); + int receive(int, void *buf, int len, int timeout); void close(int num); int send(int num, void *buf, int len, int timeout); QString getserial(int num); @@ -110,6 +110,26 @@ signals: private: #if defined( Q_OS_MAC) + // Static callbacks called by the HID system with handles to the PJRC object + static void attach_callback(void *, IOReturn, void *, IOHIDDeviceRef); + static void dettach_callback(void *, IOReturn, void *hid_mgr, IOHIDDeviceRef dev); + static void input_callback(void *, IOReturn, void *, IOHIDReportType, uint32_t, uint8_t *, CFIndex); + static void timeout_callback(CFRunLoopTimerRef, void *); + + // Non static methods to call into + void attach(IOHIDDeviceRef dev); + void dettach(IOHIDDeviceRef dev); + void input(uint8_t *, CFIndex); + + IOHIDManagerRef hid_manager; + CFRunLoopRef the_correct_runloop; + IOHIDDeviceRef dev; + + static const int BUFFER_SIZE = 64; + uint8_t buffer[BUFFER_SIZE]; + int32_t buffer_count; + bool device_open; + int attach_count; #elif defined(Q_OS_UNIX) //#elif defined(Q_OS_LINUX) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index c1cd83312..b89f200c5 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -40,102 +40,46 @@ #include "pjrc_rawhid.h" #include -#include -#include -#include #include #include #include #include -class delay : public QThread +int register_count = 0; +pjrc_rawhid::pjrc_rawhid() : + device_open(false), hid_manager(NULL), buffer_count(0), attach_count(0) { -public: - static void msleep(unsigned long msecs) - { - QThread::msleep(msecs); - } -}; - -#define BUFFER_SIZE 64 - -//#define printf qDebug -#define printf - -typedef struct hid_struct hid_t; -typedef struct buffer_struct buffer_t; -static hid_t *first_hid = NULL; -static hid_t *last_hid = NULL; -// Make sure we use the correct runloop -CFRunLoopRef the_correct_runloop = NULL; -struct hid_struct { - IOHIDDeviceRef ref; - int open; - uint8_t buffer[BUFFER_SIZE]; - buffer_t *first_buffer; - buffer_t *last_buffer; - struct hid_struct *prev; - struct hid_struct *next; -}; -struct buffer_struct { - struct buffer_struct *next; - uint32_t len; - uint8_t buf[BUFFER_SIZE]; -}; - -static void add_hid(hid_t *); -static hid_t * get_hid(int); -static void free_all_hid(void); -static void hid_close(hid_t *); -static void attach_callback(void *, IOReturn, void *, IOHIDDeviceRef); -static void detach_callback(void *, IOReturn, void *hid_mgr, IOHIDDeviceRef dev); -static void input_callback(void *, IOReturn, void *, IOHIDReportType, uint32_t, uint8_t *, CFIndex); -static void output_callback(hid_t *context, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len); -static void timeout_callback(CFRunLoopTimerRef, void *); - - -pjrc_rawhid::pjrc_rawhid() -{ - first_hid = NULL; - last_hid = NULL; } pjrc_rawhid::~pjrc_rawhid() { } -// open - open 1 or more devices -// -// Inputs: -// max = maximum number of devices to open -// vid = Vendor ID, or -1 if any -// pid = Product ID, or -1 if any -// usage_page = top level usage page, or -1 if any -// usage = top level usage number, or -1 if any -// Output: -// actual number of devices opened -// +/** + * @brief open - open 1 or more devices + * @param[in] max maximum number of devices to open + * @param[in] vid Vendor ID, or -1 if any + * @param[in] pid Product ID, or -1 if any + * @param[in] usage_page top level usage page, or -1 if any + * @param[in] usage top level usage number, or -1 if any + * @returns actual number of devices opened + */ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) { - IOHIDManagerRef hid_manager=NULL; CFMutableDictionaryRef dict; CFNumberRef num; IOReturn ret; - hid_t *p; int count=0; - if (first_hid) free_all_hid(); - //printf("pjrc_rawhid_open, max=%d\n", max); - if (max < 1) return 0; + Q_ASSERT(hid_manager == NULL); + // Start the HID Manager - // http://developer.apple.com/technotes/tn2007/tn2187.html - if (!hid_manager) { - hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) { - if (hid_manager) CFRelease(hid_manager); - return 0; - } + hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) { + if (hid_manager) CFRelease(hid_manager); + return 0; } + if (vid > 0 || pid > 0 || usage_page > 0 || usage > 0) { // Tell the HID Manager what type of devices we want dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, @@ -173,157 +117,116 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) // set up a callbacks for device attach & detach IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL); - IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL); + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, pjrc_rawhid::attach_callback, this); + IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, pjrc_rawhid::dettach_callback, this); ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) { - printf("Could not start IOHIDManager"); + qDebug() << "Could not start IOHIDManager"; IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); CFRelease(hid_manager); return 0; } - printf("run loop\n"); + qDebug() << "run loop"; + // let it do the callback for all devices while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; + + qDebug() << "Attach count: " << attach_count; // count up how many were added by the callback - for (p = first_hid; p; p = p->next) count++; - return count; + return attach_count; } -// recveive - receive a packet -// Inputs: -// num = device to receive from (zero based) -// buf = buffer to receive packet -// len = buffer's size -// timeout = time to wait, in milliseconds -// Output: -// number of bytes received, or -1 on error -// -int pjrc_rawhid::receive(int num, void *buf, int len, int timeout) +/** + * @brief receive - receive a packet + * @param[in] num device to receive from (unused now) + * @param[in] buf buffer to receive packet + * @param[in] len buffer's size + * @param[in] timeout = time to wait, in milliseconds + * @returns number of bytes received, or -1 on error + */ +int pjrc_rawhid::receive(int, void *buf, int len, int timeout) { - hid_t *hid; - buffer_t *b; - CFRunLoopTimerRef timer=NULL; - CFRunLoopTimerContext context; - int ret=0, timeout_occurred=0; + if (!device_open) + return -1; + CFRunLoopTimerRef timer=NULL; + int timeout_occurred=0; - if (len < 1) return 0; - hid = get_hid(num); - if (!hid || !hid->open) return -1; - if ((b = hid->first_buffer) != NULL) { - if (len > b->len) len = b->len; - memcpy(buf, b->buf, len); - hid->first_buffer = b->next; - free(b); - return len; - } - memset(&context, 0, sizeof(context)); - context.info = &timeout_occurred; - timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + - (double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context); - CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); - the_correct_runloop = CFRunLoopGetCurrent(); - //qDebug("--"); - while (1) { - //qDebug("."); - CFRunLoopRun(); // Found the problem: somehow the input_callback does not - // stop this CFRunLoopRun because it is hooked to a different run loop !!! - // Hence the use of the "correct_runloop" variable above. - //qDebug(" .."); + if (buffer_count != 0) { + if (len > buffer_count) len = buffer_count; + memcpy(buf, buffer, len); + return len; + } - if ((b = hid->first_buffer) != NULL) { - if (len > b->len) len = b->len; - memcpy(buf, b->buf, len); - hid->first_buffer = b->next; - free(b); - ret = len; - //qDebug("*************"); - break; - } - if (!hid->open) { - printf("pjrc_rawhid_recv, device not open\n"); - ret = -1; - break; - } - if (timeout_occurred) - break; - } - CFRunLoopTimerInvalidate(timer); - CFRelease(timer); - return ret; + timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + + (double)timeout / 1000.0, 0, 0, 0, timeout_callback, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); + CFRunLoopRun(); // Wait for data + if (buffer_count != 0) { + if (len > buffer_count) len = buffer_count; + memcpy(buf, buffer, len); + buffer_count = 0; + QString buf_message; + for (int i = 0; i < len; i ++) + buf_message.append(QString("%1 ").arg(buffer[i], 0, 16)); + } else + timeout_occurred; + + CFRunLoopTimerInvalidate(timer); + CFRelease(timer); } -// send - send a packet -// Inputs: -// num = device to transmit to (zero based) -// buf = buffer containing packet to send -// len = number of bytes to transmit -// timeout = time to wait, in milliseconds -// Output: -// number of bytes sent, or -1 on error -// +/** + * @brief Helper class that will workaround the fact + * that the HID send is broken on OSX + */ +class Sender : public QThread +{ +public: + Sender(IOHIDDeviceRef d, uint8_t * b, int l) : + dev(d), buf(b), len(l), result(-1) { } + + void run() { + ret = IOHIDDeviceSetReport(dev, kIOHIDReportTypeOutput, buf[0], buf, len); + result = (ret == kIOReturnSuccess) ? len : -1; + } + + int result; + IOReturn ret; +private: + IOHIDDeviceRef dev; + uint8_t * buf; + int len; +}; + +/** + * @brief send - send a packet + * @param[in] num device to transmit to (zero based) + * @param[in] buf buffer containing packet to send + * @param[in] len number of bytes to transmit + * @param[in] timeout = time to wait, in milliseconds + * @returns number of bytes sent, or -1 on error + */ int pjrc_rawhid::send(int num, void *buf, int len, int timeout) { - hid_t *hid; - int result=-100; - - hid = get_hid(num); - if (!hid || !hid->open) return -1; -#if 1 -#warning "Send timeout not implemented on MACOSX" + if(!device_open) + return -1; uint8_t *report_buf = (uint8_t *) malloc(len); memcpy(&report_buf[0], buf,len); - // Note: packet processing done in OS indepdent code - IOReturn ret = IOHIDDeviceSetReport(hid->ref, kIOHIDReportTypeOutput, 2, (uint8_t *)report_buf, len); - result = (ret == kIOReturnSuccess) ? len : -1; - if (err_get_system(ret) == err_get_system(sys_iokit)) - { - // The error was in the I/O Kit system - UInt32 codeValue = err_get_code(ret); - qDebug("Returned: %x", codeValue); - // Can now perform test on error code, display it to user, or whatever. - usleep(1000000); - } + QEventLoop el; + Sender sender(dev, report_buf, len); + connect(&sender, SIGNAL(finished()), &el, SLOT(quit())); + sender.start(); + QTimer::singleShot(timeout, &el, SLOT(quit())); + el.exec(); -#endif -#if 0 - // No matter what I tried this never actually sends an output - // report and output_callback never gets called. Why?? - // Did I miss something? This is exactly the same params as - // the sync call that works. Is it an Apple bug? - // (submitted to Apple on 22-sep-2009, problem ID 7245050) - // - IOHIDDeviceScheduleWithRunLoop(hid->ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - // should already be scheduled with run loop by attach_callback, - // sadly this doesn't make any difference either way - // - IOHIDDeviceSetReportWithCallback(hid->ref, kIOHIDReportTypeOutput, - 0, buf, len, (double)timeout / 1000.0, output_callback, &result); - while (1) { - printf("enter run loop (send)\n"); - CFRunLoopRun(); - printf("leave run loop (send)\n"); - if (result > -100) break; - if (!hid->open) { - result = -1; - break; - } - } -#endif - return result; + return sender.result; } +//! Get the serial number for a HID device QString pjrc_rawhid::getserial(int num) { - hid_t *hid; - char buf[128]; - - hid = get_hid(num); - - if (!hid || !hid->open) return QString("Error"); - - CFTypeRef serialnum = IOHIDDeviceGetProperty(hid->ref, CFSTR(kIOHIDSerialNumberKey)); + CFTypeRef serialnum = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDSerialNumberKey)); if(serialnum && CFGetTypeID(serialnum) == CFStringGetTypeID()) { //Note: I'm not sure it will always succeed if encoded as MacRoman but that @@ -336,165 +239,103 @@ QString pjrc_rawhid::getserial(int num) { return QString("Error"); } -// close - close a device -// -// Inputs: -// num = device to close (zero based) -// Output -// (nothing) -// -void pjrc_rawhid::close(int num) +//! Close the HID device +void pjrc_rawhid::close(int) { - hid_t *hid; + device_open = false; + qDebug() << "hid_close " << CFRunLoopGetCurrent(); + qDebug() << "Registering input report as null"; + IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), NULL, NULL); + register_count--; - hid = get_hid(num); - if (!hid || !hid->open) return; - hid_close(hid); - hid->open = 0; + if (the_correct_runloop) + IOHIDDeviceUnscheduleFromRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode); + the_correct_runloop = NULL; + + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); + IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone); + IOHIDManagerClose(hid_manager, 0); + dev = NULL; + hid_manager = NULL; } -// -// -// Private Functions -// -// -static void input_callback(void *context, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) +/** + * @brief input Called to add input data to the buffer + * @param[in] id Report id + * @param[in] data The data buffer + * @param[in] len The report length + */ +void pjrc_rawhid::input(uint8_t *data, CFIndex len) { - buffer_t *n; - hid_t *hid; - - //qDebug("input_callback, ret: %i - report id: %i buf: %x %x, len: %d\n", ret, id, data[0], data[1], len); - if (ret != kIOReturnSuccess || len < 1) return; - hid = (hid_t*)context; - if (!hid || hid->ref != sender) return; - printf("Processing packet"); - n = (buffer_t *)malloc(sizeof(buffer_t)); - if (!n) return; + if (!device_open) + return; if (len > BUFFER_SIZE) len = BUFFER_SIZE; // Note: packet preprocessing done in OS independent code - memcpy(n->buf, &data[0], len); - n->len = len; - n->next = NULL; - if (!hid->first_buffer || !hid->last_buffer) { - hid->first_buffer = hid->last_buffer = n; - } else { - hid->last_buffer->next = n; - hid->last_buffer = n; - } + memcpy(buffer, &data[0], len); + buffer_count = len; if (the_correct_runloop) CFRunLoopStop(the_correct_runloop); } -static void timeout_callback(CFRunLoopTimerRef timer, void *info) -{ - //qDebug("timeout_callback\n"); - *(int *)info = 1; - //qDebug() << "Stop CFRunLoop from timeout_callback" << CFRunLoopGetCurrent(); - CFRunLoopStop(CFRunLoopGetCurrent()); +//! Callback for the HID driver on an input report +void pjrc_rawhid::input_callback(void *c, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) +{ + if (ret != kIOReturnSuccess || len < 1) return; + + pjrc_rawhid *context = (pjrc_rawhid *) c; + context->input(data, len); } -static void add_hid(hid_t *h) +//! Timeout used for the +void pjrc_rawhid::timeout_callback(CFRunLoopTimerRef, void *) { - if (!first_hid || !last_hid) { - first_hid = last_hid = h; - h->next = h->prev = NULL; - return; - } - last_hid->next = h; - h->prev = last_hid; - h->next = NULL; - last_hid = h; + CFRunLoopStop(CFRunLoopGetCurrent()); } - -static hid_t * get_hid(int num) +//! Called on a dettach event +void pjrc_rawhid::dettach(IOHIDDeviceRef d) { - hid_t *p; - for (p = first_hid; p && num > 0; p = p->next, num--) ; - return p; + qDebug() << "dettach"; + if (d == dev) + close(0); } - -static void free_all_hid(void) +//! Called from the USB system and forwarded to the instance (context) +void pjrc_rawhid::dettach_callback(void *context, IOReturn, void *, IOHIDDeviceRef dev) { - hid_t *p, *q; - - for (p = first_hid; p; p = p->next) { - hid_close(p); - } - p = first_hid; - while (p) { - q = p; - p = p->next; - free(q); - } - first_hid = last_hid = NULL; + pjrc_rawhid *p = (pjrc_rawhid*) context; + p->dettach(dev); } - -static void hid_close(hid_t *hid) +/** + * @brief Called by the USB system + * @param dev The device that was attached + */ +void pjrc_rawhid::attach(IOHIDDeviceRef d) { - if (!hid || !hid->open || !hid->ref) return; - IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - if (the_correct_runloop) - IOHIDDeviceUnscheduleFromRunLoop(hid->ref, the_correct_runloop, kCFRunLoopDefaultMode); - the_correct_runloop = NULL; - IOHIDDeviceRegisterInputReportCallback(hid->ref, hid->buffer, sizeof(hid->buffer), NULL, hid); - IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); - IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); - IOHIDDeviceClose(hid->ref, kIOHIDOptionsTypeNone); - IOHIDManagerClose(hid_manager, 0); - hid->ref = NULL; -} + // Store the device handle + dev = d; -static void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) -{ - hid_t *p; - - printf("detach callback\n"); - for (p = first_hid; p; p = p->next) { - if (p->ref == dev) { - p->open = 0; - CFRunLoopStop(CFRunLoopGetCurrent()); - return; - } - } - - hid_t *hid = get_hid(0); - if (hid) - hid_close(hid); -} - -static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) -{ - struct hid_struct *h; + attach_count++; if (IOHIDDeviceOpen(dev, kIOHIDOptionsTypeNone) != kIOReturnSuccess) return; - h = (hid_t *)malloc(sizeof(hid_t)); - if (!h) return; - memset(h, 0, sizeof(hid_t)); // Disconnect the attach callback since we don't want to automatically reconnect - IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); + IOHIDDeviceScheduleWithRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode); + IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), pjrc_rawhid::input_callback, this); - IOHIDDeviceScheduleWithRunLoop(dev, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOHIDDeviceRegisterInputReportCallback(dev, h->buffer, sizeof(h->buffer), input_callback, h); - h->ref = dev; - h->open = 1; - add_hid(h); + register_count++; + + device_open = true; } -static void output_callback(hid_t *context, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) +//! Called from the USB system and forwarded to the instance (context) +void pjrc_rawhid::attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) { - printf("output_callback, r=%d\n", ret); - if (ret == kIOReturnSuccess) { - *(int *)context = len; - } else { - // timeout if not success? - *(int *)context = 0; - } - CFRunLoopStop(CFRunLoopGetCurrent()); + pjrc_rawhid *p = (pjrc_rawhid*) context; + p->attach(dev); } From 26ff40b5f31369f31b3c1e95335fc6e99e213065 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 9 Sep 2012 17:37:43 -0500 Subject: [PATCH 23/26] GCS OSX: Work on how the receive threads are stopped properly --- .../plugins/coreplugin/connectionmanager.cpp | 3 +- .../src/plugins/rawhid/pjrc_rawhid.h | 19 +-- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 114 ++++++++++-------- .../src/plugins/rawhid/rawhid.cpp | 12 +- .../src/plugins/rawhid/rawhidplugin.cpp | 5 +- .../src/plugins/uploader/op_dfu.cpp | 23 ++-- 6 files changed, 95 insertions(+), 81 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index 962af8acb..1857ca553 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -290,8 +290,9 @@ void ConnectionManager::updateConnectionList(IConnection *connection) bool found = availableDev.contains(iter->device); if (!found) { // we are currently using the one we are about to erase - if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) + if (m_connectionDevice.connection && m_connectionDevice.connection == connection && m_connectionDevice.device == iter->device) { disconnectDevice(); + } iter = m_devList.erase(iter); } else diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h index 8ba8d458a..c2cde4075 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h @@ -37,6 +37,9 @@ #if defined( Q_OS_MAC) +#include +#include +#include #elif defined(Q_OS_UNIX) //#elif defined(Q_OS_LINUX) @@ -100,12 +103,8 @@ public: void close(int num); int send(int num, void *buf, int len, int timeout); QString getserial(int num); - void mytest(int num); signals: - void deviceUnplugged(int);//just to make pips changes compile -#if defined( Q_OS_MAC) - -#endif + void deviceUnplugged(int); private: #if defined( Q_OS_MAC) @@ -121,17 +120,19 @@ private: void dettach(IOHIDDeviceRef dev); void input(uint8_t *, CFIndex); + // Platform specific handles for the USB device IOHIDManagerRef hid_manager; - CFRunLoopRef the_correct_runloop; IOHIDDeviceRef dev; + CFRunLoopRef the_correct_runloop; static const int BUFFER_SIZE = 64; uint8_t buffer[BUFFER_SIZE]; - int32_t buffer_count; - bool device_open; int attach_count; + int buffer_count; + bool device_open; + bool unplugged; + #elif defined(Q_OS_UNIX) - //#elif defined(Q_OS_LINUX) hid_t *first_hid; hid_t *last_hid; diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index b89f200c5..94b4f9444 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -45,9 +45,13 @@ #include #include -int register_count = 0; +struct timeout_info { + CFRunLoopRef loopRef; + bool timed_out; +}; + pjrc_rawhid::pjrc_rawhid() : - device_open(false), hid_manager(NULL), buffer_count(0), attach_count(0) + device_open(false), hid_manager(NULL), buffer_count(0), unplugged(false) { } @@ -127,12 +131,10 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) CFRelease(hid_manager); return 0; } - qDebug() << "run loop"; // let it do the callback for all devices while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; - qDebug() << "Attach count: " << attach_count; // count up how many were added by the callback return attach_count; } @@ -149,31 +151,45 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) { if (!device_open) return -1; - CFRunLoopTimerRef timer=NULL; - int timeout_occurred=0; - if (buffer_count != 0) { - if (len > buffer_count) len = buffer_count; - memcpy(buf, buffer, len); - return len; - } + qDebug() << "receiving"; - timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + - (double)timeout / 1000.0, 0, 0, 0, timeout_callback, NULL); + // Pass information to the callback to stop this run loop and signal if a timeout occurred + struct timeout_info info; + info.loopRef = CFRunLoopGetCurrent();; + info.timed_out = false; + CFRunLoopTimerContext context; + memset(&context, 0, sizeof(context)); + context.info = &info; + + qDebug() << "sending context info" << context.info; + + // Set up the timer for the timeout + CFRunLoopTimerRef timer; + timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + (double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); - CFRunLoopRun(); // Wait for data - if (buffer_count != 0) { - if (len > buffer_count) len = buffer_count; - memcpy(buf, buffer, len); - buffer_count = 0; - QString buf_message; - for (int i = 0; i < len; i ++) - buf_message.append(QString("%1 ").arg(buffer[i], 0, 16)); - } else - timeout_occurred; + + // Run the CFRunLoop until either a timeout or data is available + while(1) { + if (buffer_count != 0) { + if (len > buffer_count) len = buffer_count; + memcpy(buf, buffer, len); + buffer_count = 0; + break; + } else if (info.timed_out) { + qDebug() << "timed out"; + len = 0; + break; + } + CFRunLoopRun(); // Wait for data + } CFRunLoopTimerInvalidate(timer); CFRelease(timer); + + qDebug() << "received"; + + return len; } /** @@ -187,7 +203,7 @@ public: dev(d), buf(b), len(l), result(-1) { } void run() { - ret = IOHIDDeviceSetReport(dev, kIOHIDReportTypeOutput, buf[0], buf, len); + ret = IOHIDDeviceSetReport(dev, kIOHIDReportTypeOutput, 2, buf, len); result = (ret == kIOReturnSuccess) ? len : -1; } @@ -214,12 +230,14 @@ int pjrc_rawhid::send(int num, void *buf, int len, int timeout) uint8_t *report_buf = (uint8_t *) malloc(len); memcpy(&report_buf[0], buf,len); + qDebug() << "sending"; QEventLoop el; Sender sender(dev, report_buf, len); connect(&sender, SIGNAL(finished()), &el, SLOT(quit())); sender.start(); QTimer::singleShot(timeout, &el, SLOT(quit())); el.exec(); + qDebug() << "sent"; return sender.result; } @@ -242,22 +260,22 @@ QString pjrc_rawhid::getserial(int num) { //! Close the HID device void pjrc_rawhid::close(int) { - device_open = false; - qDebug() << "hid_close " << CFRunLoopGetCurrent(); - qDebug() << "Registering input report as null"; - IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), NULL, NULL); - register_count--; + if (device_open) { + device_open = false; + CFRunLoopStop(the_correct_runloop); - if (the_correct_runloop) - IOHIDDeviceUnscheduleFromRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode); - the_correct_runloop = NULL; + if (!unplugged) { + IOHIDDeviceUnscheduleFromRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode); + IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), NULL, NULL); + IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone); + } - IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); - IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); - IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone); - IOHIDManagerClose(hid_manager, 0); - dev = NULL; - hid_manager = NULL; + IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL); + IOHIDManagerClose(hid_manager, 0); + + dev = NULL; + hid_manager = NULL; + } } /** @@ -270,6 +288,7 @@ void pjrc_rawhid::input(uint8_t *data, CFIndex len) { if (!device_open) return; + if (len > BUFFER_SIZE) len = BUFFER_SIZE; // Note: packet preprocessing done in OS independent code memcpy(buffer, &data[0], len); @@ -281,7 +300,7 @@ void pjrc_rawhid::input(uint8_t *data, CFIndex len) //! Callback for the HID driver on an input report void pjrc_rawhid::input_callback(void *c, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) -{ +{ if (ret != kIOReturnSuccess || len < 1) return; pjrc_rawhid *context = (pjrc_rawhid *) c; @@ -289,17 +308,20 @@ void pjrc_rawhid::input_callback(void *c, IOReturn ret, void *sender, IOHIDRepor } //! Timeout used for the -void pjrc_rawhid::timeout_callback(CFRunLoopTimerRef, void *) +void pjrc_rawhid::timeout_callback(CFRunLoopTimerRef, void *i) { - CFRunLoopStop(CFRunLoopGetCurrent()); + qDebug() << "timeout_callback"; + struct timeout_info *info = (struct timeout_info *) i; + info->timed_out = true; + CFRunLoopStop(info->loopRef); } //! Called on a dettach event void pjrc_rawhid::dettach(IOHIDDeviceRef d) { - qDebug() << "dettach"; + unplugged = true; if (d == dev) - close(0); + emit deviceUnplugged(0); } //! Called from the USB system and forwarded to the instance (context) @@ -318,17 +340,13 @@ void pjrc_rawhid::attach(IOHIDDeviceRef d) // Store the device handle dev = d; - attach_count++; - if (IOHIDDeviceOpen(dev, kIOHIDOptionsTypeNone) != kIOReturnSuccess) return; - // Disconnect the attach callback since we don't want to automatically reconnect IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, NULL, NULL); IOHIDDeviceScheduleWithRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode); IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), pjrc_rawhid::input_callback, this); - register_count++; - + attach_count++; device_open = true; } diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index e47f72bac..43226f7cb 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -151,7 +151,6 @@ RawHIDReadThread::~RawHIDReadThread() void RawHIDReadThread::run() { - qDebug() << "Read thread started"; m_running = m_hid->openDevice(); while(m_running) { @@ -225,7 +224,6 @@ RawHIDWriteThread::~RawHIDWriteThread() void RawHIDWriteThread::run() { - qDebug() << "Write thread started"; while(m_running) { char buffer[WRITE_SIZE] = {0}; @@ -390,27 +388,27 @@ bool RawHID::open(OpenMode mode) void RawHID::close() { + qDebug() << "RawHID::close()"; emit aboutToClose(); - - m_mutex->lock(); - if (m_writeThread) { + qDebug() << "About to terminate write thread"; m_writeThread->terminate(); delete m_writeThread; m_writeThread = NULL; + qDebug() << "Write thread terminated"; } if (m_readThread) { + qDebug() << "About to terminate read thread"; m_readThread->terminate(); delete m_readThread; // calls wait m_readThread = NULL; + qDebug() << "Read thread terminated"; } - m_mutex->unlock(); - emit closed(); QIODevice::close(); diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp index d3be05e8d..24276b981 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp @@ -72,6 +72,7 @@ void RawHIDConnection::onDeviceConnected() */ void RawHIDConnection::onDeviceDisconnected() { + qDebug() << "onDeviceDisconnected()"; if (enablePolling) emit availableDevChanged(this); } @@ -110,15 +111,13 @@ QIODevice *RawHIDConnection::openDevice(const QString &deviceName) void RawHIDConnection::closeDevice(const QString &deviceName) { Q_UNUSED(deviceName); - //added by andrew... if (RawHidHandle) { + qDebug() << "Closing the device here"; RawHidHandle->close(); - delete RawHidHandle; RawHidHandle = NULL; } - //end added by andrew } QString RawHIDConnection::connectionName() diff --git a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp index dc08d94f2..84cef5a19 100644 --- a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp @@ -106,17 +106,19 @@ DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): QTimer::singleShot(2000,&m_eventloop, SLOT(quit())); m_eventloop.exec(); devices = USBMonitor::instance()->availableDevices(0x20a0,-1,-1,USBMonitor::Bootloader); + qDebug() << "Devices length: " << devices.length(); if (devices.length()==1) { - if(hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0)==1) + qDebug() << "Opening device"; + if(hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0)==1) { - QTimer::singleShot(200,&m_eventloop, SLOT(quit())); + QTimer::singleShot(200,&m_eventloop, SLOT(quit())); m_eventloop.exec(); qDebug()<<"OP_DFU detected after delay"; mready=true; + qDebug() << "Detected"; break; } - } - else { + } else { qDebug() << devices.length() << " device(s) detected, don't know what to do!"; mready = false; } @@ -590,22 +592,17 @@ bool DFUObject::findDevices() buf[9] = 0; int result = sendData(buf, BUF_LEN); - //int result = hidHandle.send(0,buf, BUF_LEN, 5000); - if(result<1) - { + if (result < 1) return false; - } + result = receiveData(buf,BUF_LEN); - //result = hidHandle.receive(0,buf,BUF_LEN,5000); - if(result<1) - { + if (result < 1) return false; - } + numberOfDevices=buf[7]; RWFlags=buf[8]; RWFlags=RWFlags<<8 | buf[9]; - if(buf[1]==OP_DFU::Rep_Capabilities) { for(int x=0;x Date: Sun, 9 Sep 2012 23:45:04 -0500 Subject: [PATCH 24/26] Remove some comments --- .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 94b4f9444..84874ccec 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -125,7 +125,6 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, pjrc_rawhid::dettach_callback, this); ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) { - qDebug() << "Could not start IOHIDManager"; IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); CFRelease(hid_manager); @@ -152,8 +151,6 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) if (!device_open) return -1; - qDebug() << "receiving"; - // Pass information to the callback to stop this run loop and signal if a timeout occurred struct timeout_info info; info.loopRef = CFRunLoopGetCurrent();; @@ -162,8 +159,6 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) memset(&context, 0, sizeof(context)); context.info = &info; - qDebug() << "sending context info" << context.info; - // Set up the timer for the timeout CFRunLoopTimerRef timer; timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + (double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context); @@ -177,7 +172,6 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) buffer_count = 0; break; } else if (info.timed_out) { - qDebug() << "timed out"; len = 0; break; } @@ -187,8 +181,6 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) CFRunLoopTimerInvalidate(timer); CFRelease(timer); - qDebug() << "received"; - return len; } @@ -230,14 +222,12 @@ int pjrc_rawhid::send(int num, void *buf, int len, int timeout) uint8_t *report_buf = (uint8_t *) malloc(len); memcpy(&report_buf[0], buf,len); - qDebug() << "sending"; QEventLoop el; Sender sender(dev, report_buf, len); connect(&sender, SIGNAL(finished()), &el, SLOT(quit())); sender.start(); QTimer::singleShot(timeout, &el, SLOT(quit())); el.exec(); - qDebug() << "sent"; return sender.result; } @@ -310,7 +300,6 @@ void pjrc_rawhid::input_callback(void *c, IOReturn ret, void *sender, IOHIDRepor //! Timeout used for the void pjrc_rawhid::timeout_callback(CFRunLoopTimerRef, void *i) { - qDebug() << "timeout_callback"; struct timeout_info *info = (struct timeout_info *) i; info->timed_out = true; CFRunLoopStop(info->loopRef); From e027c25071f7e2cda5f2f39e6bc4a6a47df36d66 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Mon, 10 Sep 2012 00:32:40 -0500 Subject: [PATCH 25/26] OSX USB: Add write and read mutexs to avoid closing mid write. --- .../src/plugins/rawhid/pjrc_rawhid.h | 3 ++ .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 47 +++++++++++++++++-- .../src/plugins/rawhid/rawhid.cpp | 5 +- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h index c2cde4075..297ae02f9 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "rawhid_global.h" @@ -132,6 +133,8 @@ private: bool device_open; bool unplugged; + QMutex *m_writeMutex; + QMutex *m_readMutex; #elif defined(Q_OS_UNIX) hid_t *first_hid; diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 84874ccec..2a111baa8 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -53,10 +53,25 @@ struct timeout_info { pjrc_rawhid::pjrc_rawhid() : device_open(false), hid_manager(NULL), buffer_count(0), unplugged(false) { + m_writeMutex = new QMutex(); + m_readMutex = new QMutex(); } pjrc_rawhid::~pjrc_rawhid() { + if (device_open) { + close(0); + } + + if (m_writeMutex) { + delete m_writeMutex; + m_writeMutex = NULL; + } + + if (m_readMutex) { + delete m_readMutex; + m_readMutex = NULL; + } } /** @@ -73,9 +88,9 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) CFMutableDictionaryRef dict; CFNumberRef num; IOReturn ret; - int count=0; Q_ASSERT(hid_manager == NULL); + Q_ASSERT(device_open == false); // Start the HID Manager hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); @@ -148,8 +163,12 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) */ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) { - if (!device_open) + m_readMutex->lock(); + + if (!device_open) { + m_readMutex->unlock(); return -1; + } // Pass information to the callback to stop this run loop and signal if a timeout occurred struct timeout_info info; @@ -181,6 +200,8 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) CFRunLoopTimerInvalidate(timer); CFRelease(timer); + m_readMutex->unlock(); + return len; } @@ -215,10 +236,16 @@ private: * @param[in] timeout = time to wait, in milliseconds * @returns number of bytes sent, or -1 on error */ -int pjrc_rawhid::send(int num, void *buf, int len, int timeout) +int pjrc_rawhid::send(int, void *buf, int len, int timeout) { - if(!device_open) + // This lock ensures that when closing we don't do it until the + // write has terminated (and then the device_open flag is set to false) + m_writeMutex->lock(); + + if(!device_open || unplugged) { return -1; + } + uint8_t *report_buf = (uint8_t *) malloc(len); memcpy(&report_buf[0], buf,len); @@ -229,6 +256,8 @@ int pjrc_rawhid::send(int num, void *buf, int len, int timeout) QTimer::singleShot(timeout, &el, SLOT(quit())); el.exec(); + m_writeMutex->unlock(); + return sender.result; } @@ -250,6 +279,10 @@ QString pjrc_rawhid::getserial(int num) { //! Close the HID device void pjrc_rawhid::close(int) { + // Make sure any pending locks are done + m_writeMutex->lock(); + m_readMutex->lock(); + if (device_open) { device_open = false; CFRunLoopStop(the_correct_runloop); @@ -266,6 +299,12 @@ void pjrc_rawhid::close(int) dev = NULL; hid_manager = NULL; } + + // Must unlock to prevent deadlock in any read/write threads which will then fail + // because device_open is false\ + m_writeMutex->unlock(); + m_readMutex->unlock(); + } /** diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index 43226f7cb..937188917 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -330,6 +330,9 @@ bool RawHID::openDevice() { dev.close(i); } + // Now things are opened or not (from read thread) allow the constructor to complete + m_startedMutex->unlock(); + //didn't find the device we are trying to open (shouldnt happen) if (opened < 0) { @@ -339,8 +342,6 @@ bool RawHID::openDevice() { m_writeThread = new RawHIDWriteThread(this); m_writeThread->start(); - m_startedMutex->unlock(); - return true; } From 59dcbf5cb6a8faca68b864db5125684dc5a907a4 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Mon, 10 Sep 2012 01:57:06 -0500 Subject: [PATCH 26/26] GCS OSX: More refinements to the USB code to make it more robust and work for reset/halt. --- .../src/plugins/rawhid/pjrc_rawhid.h | 1 + .../src/plugins/rawhid/pjrc_rawhid_mac.cpp | 38 ++++++++++--------- .../src/plugins/rawhid/rawhid.cpp | 6 ++- .../openpilotgcs/src/plugins/rawhid/rawhid.h | 1 + .../src/plugins/uploader/op_dfu.cpp | 28 +++++--------- .../plugins/uploader/uploadergadgetwidget.cpp | 4 +- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h index 297ae02f9..f981f6a94 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid.h @@ -125,6 +125,7 @@ private: IOHIDManagerRef hid_manager; IOHIDDeviceRef dev; CFRunLoopRef the_correct_runloop; + CFRunLoopRef received_runloop; static const int BUFFER_SIZE = 64; uint8_t buffer[BUFFER_SIZE]; diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp index 2a111baa8..f5fc3eb4a 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_mac.cpp @@ -92,6 +92,8 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) Q_ASSERT(hid_manager == NULL); Q_ASSERT(device_open == false); + attach_count = 0; + // Start the HID Manager hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) { @@ -163,12 +165,11 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage) */ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) { - m_readMutex->lock(); + QMutexLocker locker(m_readMutex); + Q_UNUSED(locker); - if (!device_open) { - m_readMutex->unlock(); + if (!device_open) return -1; - } // Pass information to the callback to stop this run loop and signal if a timeout occurred struct timeout_info info; @@ -183,6 +184,8 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + (double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); + received_runloop = CFRunLoopGetCurrent(); + // Run the CFRunLoop until either a timeout or data is available while(1) { if (buffer_count != 0) { @@ -200,7 +203,7 @@ int pjrc_rawhid::receive(int, void *buf, int len, int timeout) CFRunLoopTimerInvalidate(timer); CFRelease(timer); - m_readMutex->unlock(); + received_runloop = NULL; return len; } @@ -240,7 +243,8 @@ int pjrc_rawhid::send(int, void *buf, int len, int timeout) { // This lock ensures that when closing we don't do it until the // write has terminated (and then the device_open flag is set to false) - m_writeMutex->lock(); + QMutexLocker locker(m_writeMutex); + Q_UNUSED(locker); if(!device_open || unplugged) { return -1; @@ -256,13 +260,17 @@ int pjrc_rawhid::send(int, void *buf, int len, int timeout) QTimer::singleShot(timeout, &el, SLOT(quit())); el.exec(); - m_writeMutex->unlock(); - return sender.result; } //! Get the serial number for a HID device QString pjrc_rawhid::getserial(int num) { + QMutexLocker locker(m_readMutex); + Q_UNUSED(locker); + + if (!device_open || unplugged) + return ""; + CFTypeRef serialnum = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDSerialNumberKey)); if(serialnum && CFGetTypeID(serialnum) == CFStringGetTypeID()) { @@ -280,8 +288,7 @@ QString pjrc_rawhid::getserial(int num) { void pjrc_rawhid::close(int) { // Make sure any pending locks are done - m_writeMutex->lock(); - m_readMutex->lock(); + QMutexLocker lock(m_writeMutex); if (device_open) { device_open = false; @@ -299,12 +306,6 @@ void pjrc_rawhid::close(int) dev = NULL; hid_manager = NULL; } - - // Must unlock to prevent deadlock in any read/write threads which will then fail - // because device_open is false\ - m_writeMutex->unlock(); - m_readMutex->unlock(); - } /** @@ -323,8 +324,8 @@ void pjrc_rawhid::input(uint8_t *data, CFIndex len) memcpy(buffer, &data[0], len); buffer_count = len; - if (the_correct_runloop) - CFRunLoopStop(the_correct_runloop); + if (received_runloop) + CFRunLoopStop(received_runloop); } //! Callback for the HID driver on an input report @@ -376,6 +377,7 @@ void pjrc_rawhid::attach(IOHIDDeviceRef d) attach_count++; device_open = true; + unplugged = false; } //! Called from the USB system and forwarded to the instance (context) diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp index 937188917..3a1aa896d 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.cpp @@ -307,8 +307,10 @@ RawHID::RawHID(const QString &deviceName) // detect if the USB device is unplugged QObject::connect(&dev, SIGNAL(deviceUnplugged(int)), this, SLOT(onDeviceUnplugged(int))); + m_writeThread = new RawHIDWriteThread(this); + // Starting the read thread will lock the m_startexMutex until the - // device is opened + // device is opened (which happens in that thread). m_readThread = new RawHIDReadThread(this); m_readThread->start(); @@ -334,12 +336,12 @@ bool RawHID::openDevice() { m_startedMutex->unlock(); //didn't find the device we are trying to open (shouldnt happen) + device_open = opened >= 0; if (opened < 0) { return false; } - m_writeThread = new RawHIDWriteThread(this); m_writeThread->start(); return true; diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhid.h b/ground/openpilotgcs/src/plugins/rawhid/rawhid.h index b12ef159d..f3487bf20 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhid.h +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhid.h @@ -84,6 +84,7 @@ protected: int m_deviceNo; pjrc_rawhid dev; + bool device_open; RawHIDReadThread *m_readThread; RawHIDWriteThread *m_writeThread; diff --git a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp index 84cef5a19..810ddfa06 100644 --- a/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/op_dfu.cpp @@ -87,11 +87,13 @@ DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): m_eventloop.exec(); QList devices; devices = USBMonitor::instance()->availableDevices(0x20a0,-1,-1,USBMonitor::Bootloader); - if (devices.length()==1 && hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0)==1) { - qDebug()<<"OP_DFU detected first time"; - mready=true; - QTimer::singleShot(200,&m_eventloop, SLOT(quit())); - m_eventloop.exec(); + if (devices.length()==1) { + if (hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0)==1) { + mready=true; + QTimer::singleShot(200,&m_eventloop, SLOT(quit())); + m_eventloop.exec(); + } else + hidHandle.close(0); } else { // Wait for the board to appear on the USB bus: USBSignalFilter filter(0x20a0,-1,-1,USBMonitor::Bootloader); @@ -117,7 +119,8 @@ DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): mready=true; qDebug() << "Detected"; break; - } + } else + hidHandle.close(0); } else { qDebug() << devices.length() << " device(s) detected, don't know what to do!"; mready = false; @@ -173,7 +176,6 @@ bool DFUObject::enterDFU(int const &devNumber) buf[9] = 1; //DFU Data3 int result = sendData(buf, BUF_LEN); - // int result = hidHandle.send(0,buf, BUF_LEN, 500); if(result<1) return false; if(debug) @@ -218,7 +220,6 @@ bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const & int result = sendData(buf, BUF_LEN); delay::msleep(1000); - // int result = hidHandle.send(0,buf, BUF_LEN, 5000); if(debug) qDebug() << result << " bytes sent"; @@ -443,7 +444,6 @@ bool DFUObject::StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, Tra buf[9] = 1; //DFU Data3 int result = sendData(buf, BUF_LEN); - //int result = hidHandle.send(0,buf, BUF_LEN, 500); if(debug) qDebug() << "StartDownload:"<0) diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index 0cbd033a0..39837e3de 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -378,7 +378,8 @@ void UploaderGadgetWidget::systemSafeBoot() } /** - Tells the system to boot (from Bootloader state) + * Tells the system to boot (from Bootloader state) + * @param[in] safeboot Indicates whether the firmware should use the stock HWSettings */ void UploaderGadgetWidget::commonSystemBoot(bool safeboot) { @@ -547,6 +548,7 @@ void UploaderGadgetWidget::systemRescue() m_config->rescueButton->setEnabled(false); currentStep = IAP_STATE_BOOTLOADER; // So that we can boot from the GUI afterwards. } + void UploaderGadgetWidget::perform() { if(m_progress->value()==19)