From e4535ed575e6f4c5c2780dfbdd992a44a7c9331f Mon Sep 17 00:00:00 2001 From: edouard Date: Thu, 3 Mar 2011 21:44:59 +0000 Subject: [PATCH] OP-334 OP-332 Linux usb monitor working fine now, and rawhidplugin.cpp updated to use this new mechanism, no more polling thread opening the device every second! git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2957 ebee16cc-31ac-478f-84a7-5cbb03baadba --- .../src/plugins/rawhid/pjrc_rawhid_unix.cpp | 3 +- .../src/plugins/rawhid/rawhidplugin.cpp | 122 ++++-------------- .../src/plugins/rawhid/rawhidplugin.h | 36 +----- .../src/plugins/rawhid/usbmonitor_linux.cpp | 49 +++---- 4 files changed, 60 insertions(+), 150 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_unix.cpp b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_unix.cpp index 04b1ec195..bd44a9144 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_unix.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/pjrc_rawhid_unix.cpp @@ -358,7 +358,7 @@ void pjrc_rawhid::hid_close(hid_t *hid) if (!hid) return; if (!hid->open) return; - usb_release_interface(hid->usb, hid->iface); + usb_release_interface(hid->usb, hid->iface); int others = 0; for (hid_t *p = first_hid; p; p = p->next) @@ -370,4 +370,5 @@ void pjrc_rawhid::hid_close(hid_t *hid) usb_close(hid->usb); hid->usb = NULL; + hid->open = 0; } diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp index b9b25599c..df1f77728 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.cpp @@ -36,83 +36,19 @@ #include "rawhid_const.h" -// ********************************************************************** - -RawHIDEnumerationThread::RawHIDEnumerationThread(RawHIDConnection *rawhid) : - QThread(rawhid), // Pip - m_rawhid(rawhid), - m_running(true) -{ - if (m_rawhid) - connect(m_rawhid, SLOT(destroyed(QObject *)), this, SLOT(onRawHidConnectionDestroyed(QObject *))); // Pip -} - -RawHIDEnumerationThread::~RawHIDEnumerationThread() -{ - m_rawhid = NULL; // safe guard - - m_running = false; - - // wait for the thread to terminate - if (!wait(100)) - qDebug() << "Cannot terminate RawHIDEnumerationThread"; -} - -void RawHIDEnumerationThread::onRawHidConnectionDestroyed(QObject *obj) // Pip -{ - if (!m_rawhid || m_rawhid != obj) - return; - - m_rawhid = NULL; -} - -void RawHIDEnumerationThread::run() -{ - QStringList devices = m_rawhid->availableDevices(); - - int counter = 0; - - while (m_running) - { - // update available devices every second (doesn't need more) - if (m_rawhid) - { - if (!m_rawhid->deviceOpened()) // this was stopping us getting enumerations changes fed back - { - if (++counter >= 100) - { - counter = 0; - - QStringList newDev = m_rawhid->availableDevices(); - if (devices != newDev) - { - devices = newDev; - emit enumerationChanged(); - } - } - } -// else -// counter = 0; - } - else - counter = 0; - - msleep(10); - } -} // ********************************************************************** RawHIDConnection::RawHIDConnection() - : m_enumerateThread(this) + : m_usbMonitor(this) { //added by andrew RawHidHandle = NULL; enablePolling = true; - QObject::connect(&m_enumerateThread, SIGNAL(enumerationChanged()), this, SLOT(onEnumerationChanged())); + connect(&m_usbMonitor, SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(onDeviceConnected())); + connect(&m_usbMonitor, SIGNAL(deviceRemoved(USBPortInfo)), this, SLOT(onDeviceDisconnected())); - m_enumerateThread.start(); } RawHIDConnection::~RawHIDConnection() @@ -122,47 +58,42 @@ RawHIDConnection::~RawHIDConnection() } } -void RawHIDConnection::onEnumerationChanged() +/** + The USB monitor tells us a new device appeared + */ +void RawHIDConnection::onDeviceConnected() { - if (RawHidHandle) // Pip - { // check to see if the connection has closed - if (!RawHidHandle->isOpen()) - { // connection has closed .. hmmmm, this connection is still showing as open after the USB device is unplugged from PC - delete RawHidHandle; - RawHidHandle = NULL; - - emit deviceClosed(this); - } - } + emit availableDevChanged(this); +} +/** + The USB monitor tells us a device disappeard + */ +void RawHIDConnection::onDeviceDisconnected() +{ + emit deviceClosed(this); if (enablePolling) emit availableDevChanged(this); } +/** + Returns the list of all currently available devices + */ QStringList RawHIDConnection::availableDevices() { - QMutexLocker locker(&m_enumMutex); - QStringList devices; - if (enablePolling) - { - pjrc_rawhid dev; - - // open all device we can - int opened = dev.open(USB_MAX_DEVICES, USB_VID, USB_PID, USB_USAGE_PAGE, USB_USAGE); - - // for each devices found, get serial number and close it back - for (int i = 0; i < opened; i++) - { - devices.append(dev.getserial(i)); - dev.close(i); - } + QList portsList = m_usbMonitor.availableDevices(); + // We currently list devices by their serial number + foreach(USBPortInfo prt, portsList) { + devices.append(prt.serialNumber); } return devices; } + +/// TODO: still needed ??? void RawHIDConnection::onRawHidDestroyed(QObject *obj) // Pip { if (!RawHidHandle || RawHidHandle != obj) @@ -171,13 +102,11 @@ void RawHIDConnection::onRawHidDestroyed(QObject *obj) // Pip RawHidHandle = NULL; } +/// TODO: still needed ??? void RawHIDConnection::onRawHidClosed() { if (RawHidHandle) { -// delete RawHidHandle; -// RawHidHandle = NULL; - emit deviceClosed(this); } } @@ -201,6 +130,7 @@ QIODevice *RawHIDConnection::openDevice(const QString &deviceName) return RawHidHandle; } + void RawHIDConnection::closeDevice(const QString &deviceName) { Q_UNUSED(deviceName); diff --git a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h index eae9dd785..9d1096b6d 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h +++ b/ground/openpilotgcs/src/plugins/rawhid/rawhidplugin.h @@ -30,6 +30,7 @@ #include "rawhid_global.h" #include "rawhid.h" +#include "usbmonitor.h" #include "coreplugin/iconnection.h" #include @@ -41,32 +42,6 @@ class IConnection; class RawHIDConnection; -/** -* Helper thread to check on device connection/disconnection -* Underlying HID library is not really easy to use, -* so we have to poll for device modification in a separate thread -*/ -class RAWHID_EXPORT RawHIDEnumerationThread : public QThread -{ - Q_OBJECT -public: - RawHIDEnumerationThread(RawHIDConnection *rawhid); - virtual ~RawHIDEnumerationThread(); - - virtual void run(); - -signals: - void enumerationChanged(); - -protected slots: - void onRawHidConnectionDestroyed(QObject *obj); // Pip - -protected: - RawHIDConnection *m_rawhid; - bool m_running; -}; - - /** * Define a connection via the IConnection interface * Plugin will add a instance of this class to the pool, @@ -89,7 +64,7 @@ public: virtual void suspendPolling(); virtual void resumePolling(); - bool deviceOpened() { return (RawHidHandle != NULL); } // Pip + bool deviceOpened() { return (RawHidHandle != NULL); } // Pip signals: void deviceClosed(QObject *obj); // Pip @@ -98,10 +73,11 @@ public slots: void onRawHidClosed(); protected slots: - void onEnumerationChanged(); + void onDeviceConnected(); + void onDeviceDisconnected(); private slots: - void onRawHidDestroyed(QObject *obj); + void onRawHidDestroyed(QObject *obj); private: RawHID *RawHidHandle; @@ -109,7 +85,7 @@ private: protected: QMutex m_enumMutex; - RawHIDEnumerationThread m_enumerateThread; + USBMonitor m_usbMonitor; bool m_deviceOpened; }; diff --git a/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_linux.cpp b/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_linux.cpp index ae585042a..bb811fd58 100644 --- a/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_linux.cpp +++ b/ground/openpilotgcs/src/plugins/rawhid/usbmonitor_linux.cpp @@ -42,12 +42,12 @@ void USBMonitor::deviceEventReceived() { dev = udev_monitor_receive_device(this->monitor); if (dev) { - printf("Got Device"); + printf("------- Got Device Event"); QString action = QString(udev_device_get_action(dev)); - if (action == "add") { + QString devtype = QString(udev_device_get_devtype(dev)); + if (action == "add" && devtype == "usb_device") { emit deviceDiscovered(makePortInfo(dev)); - - } else if (action == "remove"){ + } else if (action == "remove" && devtype == "usb_device"){ emit deviceRemoved(makePortInfo(dev)); } @@ -67,8 +67,8 @@ USBMonitor::USBMonitor(QObject *parent): QThread(parent) { this->context = udev_new(); this->monitor = udev_monitor_new_from_netlink(this->context, "udev"); -// udev_monitor_filter_add_match_subsystem_devtype( -// this->monitor, "hidraw", NULL); + udev_monitor_filter_add_match_subsystem_devtype( + this->monitor, "usb", NULL); udev_monitor_enable_receiving(this->monitor); this->monitorNotifier = new QSocketNotifier( udev_monitor_get_fd(this->monitor), QSocketNotifier::Read, this); @@ -95,7 +95,8 @@ QList USBMonitor::availableDevices() struct udev_device *dev; enumerate = udev_enumerate_new(this->context); - udev_enumerate_add_match_subsystem(enumerate,"hidwraw"); +// udev_enumerate_add_match_subsystem(enumerate,"usb"); + udev_enumerate_add_match_sysattr(enumerate, "idVendor", "20a0"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); // Will use the 'native' udev functions to loop: @@ -113,6 +114,7 @@ QList USBMonitor::availableDevices() subsystem/devtype pair of "usb"/"usb_device". This will be several levels up the tree, but the function will find it.*/ + /* dev = udev_device_get_parent_with_subsystem_devtype( dev, "usb", @@ -121,24 +123,10 @@ QList USBMonitor::availableDevices() printf("Unable to find parent usb device."); return devicesList; } + */ - /* From here, we can call get_sysattr_value() for each file - in the device's /sys entry. The strings passed into these - functions (idProduct, idVendor, serial, etc.) correspond - directly to the files in the directory which represents - the USB device. Note that USB strings are Unicode, UCS2 - encoded, but the strings returned from - udev_device_get_sysattr_value() are UTF-8 encoded. */ - printf(" VID/PID: %s %s\n", - udev_device_get_sysattr_value(dev,"idVendor"), - udev_device_get_sysattr_value(dev, "idProduct")); - printf(" %s\n %s\n", - udev_device_get_sysattr_value(dev,"manufacturer"), - udev_device_get_sysattr_value(dev,"product")); - printf(" serial: %s\n", - udev_device_get_sysattr_value(dev, "serial")); devicesList.append(makePortInfo(dev)); - udev_device_unref(dev); + udev_device_unref(dev); } /* free the enumerator object */ udev_enumerate_unref(enumerate); @@ -171,6 +159,21 @@ USBPortInfo USBMonitor::makePortInfo(struct udev_device *dev) printf(" Subsystem: %s", udev_device_get_subsystem(dev)); printf(" Devtype: %s", udev_device_get_devtype(dev)); printf(" Action: %s", udev_device_get_action(dev)); + /* From here, we can call get_sysattr_value() for each file + in the device's /sys entry. The strings passed into these + functions (idProduct, idVendor, serial, etc.) correspond + directly to the files in the directory which represents + the USB device. Note that USB strings are Unicode, UCS2 + encoded, but the strings returned from + udev_device_get_sysattr_value() are UTF-8 encoded. */ + printf(" VID/PID: %s %s", + udev_device_get_sysattr_value(dev,"idVendor"), + udev_device_get_sysattr_value(dev, "idProduct")); + printf(" %s - %s", + udev_device_get_sysattr_value(dev,"manufacturer"), + udev_device_get_sysattr_value(dev,"product")); + printf(" serial: %s", + udev_device_get_sysattr_value(dev, "serial")); prtInfo.vendorID = QString(udev_device_get_sysattr_value(dev, "idVendor")).toInt(); prtInfo.productID = QString(udev_device_get_sysattr_value(dev, "idProduct")).toInt();