From 1adc836d70b6690030c7f75706877cce07105072 Mon Sep 17 00:00:00 2001 From: lm Date: Thu, 14 Jul 2011 08:50:44 +0200 Subject: [PATCH] Cleaning up compile --- qgroundcontrol.pro | 14 +- src/libs/qextserialport/qextserialenumerator.h | 207 +++++++++++++++ .../qextserialport/qextserialenumerator_osx.cpp | 288 +++++++++++++++++++++ .../qextserialport/qextserialenumerator_unix.cpp | 75 ++++++ .../qextserialport/qextserialenumerator_win.cpp | 206 +++++++++++++++ src/libs/utils/qtcolorbutton.cpp | 4 +- src/libs/utils/utils_external.pri | 4 +- 7 files changed, 792 insertions(+), 6 deletions(-) create mode 100644 src/libs/qextserialport/qextserialenumerator.h create mode 100644 src/libs/qextserialport/qextserialenumerator_osx.cpp create mode 100644 src/libs/qextserialport/qextserialenumerator_unix.cpp create mode 100644 src/libs/qextserialport/qextserialenumerator_win.cpp diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index b3207fb..13f9f20 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -152,18 +152,25 @@ DEPENDPATH += . \ plugins \ thirdParty/qserialport/include \ thirdParty/qserialport/include/QtSerialPort \ - thirdParty/qserialport + thirdParty/qserialport \ + src/libs/qextserialport INCLUDEPATH += . \ thirdParty/qserialport/include \ thirdParty/qserialport/include/QtSerialPort \ - thirdParty/qserialport/src + thirdParty/qserialport/src \ + src/libs/qextserialport # Include serial port library # include(src/lib/qextserialport/qextserialport.pri) # include qserial library include(thirdParty/qserialport/qgroundcontrol-qserialport.pri) +# Serial port detection +macx::SOURCES += src/libs/qextserialport/qextserialenumerator_osx.cpp +linux-g++::SOURCES += src/libs/qextserialport/qextserialenumerator_unix.cpp +win32::SOURCES += src/libs/qextserialport/qextserialenumerator_win.cpp + # ../mavlink/include \ # MAVLink/include \ # mavlink/include @@ -330,7 +337,8 @@ HEADERS += src/MG.h \ src/ui/map/Waypoint2DIcon.h \ src/ui/mavlink/QGCMAVLinkTextEdit.h \ src/ui/map/QGCMapTool.h \ - src/ui/map/QGCMapToolBar.h + src/ui/map/QGCMapToolBar.h \ + src/libs/qextserialport/qextserialenumerator.h # Google Earth is only supported on Mac OS and Windows with Visual Studio Compiler macx|win32-msvc2008::HEADERS += src/ui/map3D/QGCGoogleEarthView.h diff --git a/src/libs/qextserialport/qextserialenumerator.h b/src/libs/qextserialport/qextserialenumerator.h new file mode 100644 index 0000000..a87a844 --- /dev/null +++ b/src/libs/qextserialport/qextserialenumerator.h @@ -0,0 +1,207 @@ +/*! + * \file qextserialenumerator.h + * \author Michal Policht + * \see QextSerialEnumerator + */ + +#ifndef _QEXTSERIALENUMERATOR_H_ +#define _QEXTSERIALENUMERATOR_H_ + + +#include + +#ifdef QEXTSERIALPORT_LIB +# define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT +#else +# define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT +#endif + +#include +#include +#include +//#include "qextserialport_global.h" + +#ifdef Q_OS_WIN + #include + #include + #include +#endif /*Q_OS_WIN*/ + +#ifdef Q_OS_MAC + #include +#endif + +/*! + * Structure containing port information. + */ +struct QextPortInfo { + QString portName; ///< Port name. + QString physName; ///< Physical name. + QString friendName; ///< Friendly name. + QString enumName; ///< Enumerator name. + int vendorID; ///< Vendor ID. + int productID; ///< Product ID +}; + +#ifdef Q_OS_WIN +#ifdef QT_GUI_LIB +#include +class QextSerialEnumerator; + +class QextSerialRegistrationWidget : public QWidget +{ + Q_OBJECT + public: + QextSerialRegistrationWidget( QextSerialEnumerator* qese ) { + this->qese = qese; + } + ~QextSerialRegistrationWidget( ) { } + + protected: + QextSerialEnumerator* qese; + bool winEvent( MSG* message, long* result ); +}; +#endif // QT_GUI_LIB +#endif // Q_OS_WIN + +/*! + Provides list of ports available in the system. + + \section Usage + To poll the system for a list of connected devices, simply use getPorts(). Each + QextPortInfo structure will populated with information about the corresponding device. + + \b Example + \code + QList ports = QextSerialEnumerator::getPorts(); + foreach( QextPortInfo port, ports ) { + // inspect port... + } + \endcode + + To enable event-driven notification of device connection events, first call + setUpNotifications() and then connect to the deviceDiscovered() and deviceRemoved() + signals. Event-driven behavior is currently available only on Windows and OS X. + + \b Example + \code + QextSerialEnumerator* enumerator = new QextSerialEnumerator(); + connect(enumerator, SIGNAL(deviceDiscovered(const QextPortInfo &)), + myClass, SLOT(onDeviceDiscovered(const QextPortInfo &))); + connect(enumerator, SIGNAL(deviceRemoved(const QextPortInfo &)), + myClass, SLOT(onDeviceRemoved(const QextPortInfo &))); + \endcode + + \section Credits + Windows implementation is based on Zach Gorman's work from + The Code Project (http://www.codeproject.com/system/setupdi.asp). + + OS X implementation, see + http://developer.apple.com/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Finding_Devices/chapter_4_section_2.html + + \author Michal Policht, Liam Staskawicz +*/ +class QEXTSERIALPORT_EXPORT QextSerialEnumerator : public QObject +{ +Q_OBJECT + public: + QextSerialEnumerator( ); + ~QextSerialEnumerator( ); + + #ifdef Q_OS_WIN + LRESULT onDeviceChangeWin( WPARAM wParam, LPARAM lParam ); + private: + /*! + * Get value of specified property from the registry. + * \param key handle to an open key. + * \param property property name. + * \return property value. + */ + static QString getRegKeyValue(HKEY key, LPCTSTR property); + + /*! + * Get specific property from registry. + * \param devInfo pointer to the device information set that contains the interface + * and its underlying device. Returned by SetupDiGetClassDevs() function. + * \param devData pointer to an SP_DEVINFO_DATA structure that defines the device instance. + * this is returned by SetupDiGetDeviceInterfaceDetail() function. + * \param property registry property. One of defined SPDRP_* constants. + * \return property string. + */ + static QString getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property); + + /*! + * Search for serial ports using setupapi. + * \param infoList list with result. + */ + static void setupAPIScan(QList & infoList); + void setUpNotificationWin( ); + static bool getDeviceDetailsWin( QextPortInfo* portInfo, HDEVINFO devInfo, + PSP_DEVINFO_DATA devData, WPARAM wParam = DBT_DEVICEARRIVAL ); + static void enumerateDevicesWin( const GUID & guidDev, QList* infoList ); + bool matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam); + #ifdef QT_GUI_LIB + QextSerialRegistrationWidget* notificationWidget; + #endif + #endif /*Q_OS_WIN*/ + + #ifdef Q_OS_UNIX + #ifdef Q_OS_MAC + private: + /*! + * Search for serial ports using IOKit. + * \param infoList list with result. + */ + static void scanPortsOSX(QList & infoList); + static void iterateServicesOSX(io_object_t service, QList & infoList); + static bool getServiceDetailsOSX( io_object_t service, QextPortInfo* portInfo ); + + void setUpNotificationOSX( ); + void onDeviceDiscoveredOSX( io_object_t service ); + void onDeviceTerminatedOSX( io_object_t service ); + friend void deviceDiscoveredCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ); + friend void deviceTerminatedCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ); + + IONotificationPortRef notificationPortRef; + + #else // Q_OS_MAC + private: + /*! + * Search for serial ports on unix. + * \param infoList list with result. + */ + static void scanPortsNix(QList & infoList); + #endif // Q_OS_MAC + #endif /* Q_OS_UNIX */ + + public: + /*! + Get list of ports. + \return list of ports currently available in the system. + */ + static QList getPorts(); + /*! + Enable event-driven notifications of board discovery/removal. + */ + void setUpNotifications( ); + + signals: + /*! + A new device has been connected to the system. + + setUpNotifications() must be called first to enable event-driven device notifications. + Currently only implemented on Windows and OS X. + \param info The device that has been discovered. + */ + void deviceDiscovered( const QextPortInfo & info ); + /*! + A device has been disconnected from the system. + + setUpNotifications() must be called first to enable event-driven device notifications. + Currently only implemented on Windows and OS X. + \param info The device that was disconnected. + */ + void deviceRemoved( const QextPortInfo & info ); +}; + +#endif /*_QEXTSERIALENUMERATOR_H_*/ diff --git a/src/libs/qextserialport/qextserialenumerator_osx.cpp b/src/libs/qextserialport/qextserialenumerator_osx.cpp new file mode 100644 index 0000000..229d73f --- /dev/null +++ b/src/libs/qextserialport/qextserialenumerator_osx.cpp @@ -0,0 +1,288 @@ + + + +#include "qextserialenumerator.h" +#include +#include + +#include +#include +#include + +QextSerialEnumerator::QextSerialEnumerator( ) +{ + if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) ) + qRegisterMetaType("QextPortInfo"); +} + +QextSerialEnumerator::~QextSerialEnumerator( ) +{ + IONotificationPortDestroy( notificationPortRef ); +} + +// static +QList QextSerialEnumerator::getPorts() +{ + QList infoList; + io_iterator_t serialPortIterator = 0; + kern_return_t kernResult = KERN_FAILURE; + CFMutableDictionaryRef matchingDictionary; + + // first try to get any serialbsd devices, then try any USBCDC devices + if( !(matchingDictionary = IOServiceMatching(kIOSerialBSDServiceValue) ) ) { + qWarning("IOServiceMatching returned a NULL dictionary."); + return infoList; + } + CFDictionaryAddValue(matchingDictionary, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes)); + + // then create the iterator with all the matching devices + if( IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS ) { + qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult; + return infoList; + } + iterateServicesOSX(serialPortIterator, infoList); + 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; +} + +void QextSerialEnumerator::iterateServicesOSX(io_object_t service, QList & infoList) +{ + // Iterate through all modems found. + io_object_t usbService; + while( ( usbService = IOIteratorNext(service) ) ) + { + QextPortInfo info; + info.vendorID = 0; + info.productID = 0; + getServiceDetailsOSX( usbService, &info ); + infoList.append(info); + } +} + +bool QextSerialEnumerator::getServiceDetailsOSX( io_object_t service, QextPortInfo* portInfo ) +{ + bool retval = true; + CFTypeRef bsdPathAsCFString = NULL; + CFTypeRef productNameAsCFString = NULL; + CFTypeRef vendorIdAsCFNumber = NULL; + CFTypeRef productIdAsCFNumber = NULL; + // check the name of the modem's callout device + bsdPathAsCFString = IORegistryEntryCreateCFProperty(service, CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, 0); + + // wander up the hierarchy until we find the level that can give us the + // vendor/product IDs and the product name, if available + io_registry_entry_t parent; + kern_return_t kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); + while( kernResult == KERN_SUCCESS && !vendorIdAsCFNumber && !productIdAsCFNumber ) + { + if(!productNameAsCFString) + productNameAsCFString = IORegistryEntrySearchCFProperty(parent, + kIOServicePlane, + CFSTR("Product Name"), + kCFAllocatorDefault, 0); + vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent, + kIOServicePlane, + CFSTR(kUSBVendorID), + kCFAllocatorDefault, 0); + productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent, + kIOServicePlane, + CFSTR(kUSBProductID), + kCFAllocatorDefault, 0); + io_registry_entry_t oldparent = parent; + kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent); + IOObjectRelease(oldparent); + } + + io_string_t ioPathName; + IORegistryEntryGetPath( service, kIOServicePlane, ioPathName ); + portInfo->physName = ioPathName; + + if( bsdPathAsCFString ) + { + char path[MAXPATHLEN]; + if( CFStringGetCString((CFStringRef)bsdPathAsCFString, path, + PATH_MAX, kCFStringEncodingUTF8) ) + portInfo->portName = path; + CFRelease(bsdPathAsCFString); + } + + if(productNameAsCFString) + { + char productName[MAXPATHLEN]; + if( CFStringGetCString((CFStringRef)productNameAsCFString, productName, + PATH_MAX, kCFStringEncodingUTF8) ) + portInfo->friendName = productName; + CFRelease(productNameAsCFString); + } + + if(vendorIdAsCFNumber) + { + SInt32 vID; + if(CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberSInt32Type, &vID)) + portInfo->vendorID = vID; + CFRelease(vendorIdAsCFNumber); + } + + if(productIdAsCFNumber) + { + SInt32 pID; + if(CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberSInt32Type, &pID)) + portInfo->productID = pID; + CFRelease(productIdAsCFNumber); + } + IOObjectRelease(service); + return retval; +} + +// IOKit callbacks registered via setupNotifications() +void deviceDiscoveredCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ); +void deviceTerminatedCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ); + +void deviceDiscoveredCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ) +{ + QextSerialEnumerator* qese = (QextSerialEnumerator*)ctxt; + io_object_t serialService; + while ((serialService = IOIteratorNext(serialPortIterator))) + qese->onDeviceDiscoveredOSX(serialService); +} + +void deviceTerminatedCallbackOSX( void *ctxt, io_iterator_t serialPortIterator ) +{ + QextSerialEnumerator* qese = (QextSerialEnumerator*)ctxt; + io_object_t serialService; + while ((serialService = IOIteratorNext(serialPortIterator))) + qese->onDeviceTerminatedOSX(serialService); +} + +/* + A device has been discovered via IOKit. + Create a QextPortInfo if possible, and emit the signal indicating that we've found it. +*/ +void QextSerialEnumerator::onDeviceDiscoveredOSX( io_object_t service ) +{ + QextPortInfo info; + info.vendorID = 0; + info.productID = 0; + if( getServiceDetailsOSX( service, &info ) ) + emit deviceDiscovered( info ); +} + +/* + Notification via IOKit that a device has been removed. + Create a QextPortInfo if possible, and emit the signal indicating that it's gone. +*/ +void QextSerialEnumerator::onDeviceTerminatedOSX( io_object_t service ) +{ + QextPortInfo info; + info.vendorID = 0; + info.productID = 0; + if( getServiceDetailsOSX( service, &info ) ) + emit deviceRemoved( info ); +} + +/* + Create matching dictionaries for the devices we want to get notifications for, + and add them to the current run loop. Invoke the callbacks that will be responding + to these notifications once to arm them, and discover any devices that + are currently connected at the time notifications are setup. +*/ +void QextSerialEnumerator::setUpNotifications( ) +{ + kern_return_t kernResult; + mach_port_t masterPort; + CFRunLoopSourceRef notificationRunLoopSource; + CFMutableDictionaryRef classesToMatch; + CFMutableDictionaryRef cdcClassesToMatch; + io_iterator_t portIterator; + + kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (KERN_SUCCESS != kernResult) { + qDebug() << "IOMasterPort returned:" << kernResult; + return; + } + + classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); + if (classesToMatch == NULL) + qDebug("IOServiceMatching returned a NULL dictionary."); + else + CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes)); + + if( !(cdcClassesToMatch = IOServiceNameMatching("AppleUSBCDC") ) ) { + qWarning("couldn't create cdc matching dict"); + return; + } + + // Retain an additional reference since each call to IOServiceAddMatchingNotification consumes one. + classesToMatch = (CFMutableDictionaryRef) CFRetain(classesToMatch); + cdcClassesToMatch = (CFMutableDictionaryRef) CFRetain(cdcClassesToMatch); + + notificationPortRef = IONotificationPortCreate(masterPort); + if(notificationPortRef == NULL) { + qDebug("IONotificationPortCreate return a NULL IONotificationPortRef."); + return; + } + + notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationPortRef); + if (notificationRunLoopSource == NULL) { + qDebug("IONotificationPortGetRunLoopSource returned NULL CFRunLoopSourceRef."); + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource, kCFRunLoopDefaultMode); + + kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, classesToMatch, + deviceDiscoveredCallbackOSX, this, &portIterator); + if (kernResult != KERN_SUCCESS) { + qDebug() << "IOServiceAddMatchingNotification return:" << kernResult; + return; + } + + // arm the callback, and grab any devices that are already connected + deviceDiscoveredCallbackOSX( this, portIterator ); + + kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, cdcClassesToMatch, + deviceDiscoveredCallbackOSX, this, &portIterator); + if (kernResult != KERN_SUCCESS) { + qDebug() << "IOServiceAddMatchingNotification return:" << kernResult; + return; + } + + // arm the callback, and grab any devices that are already connected + deviceDiscoveredCallbackOSX( this, portIterator ); + + kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, classesToMatch, + deviceTerminatedCallbackOSX, this, &portIterator); + if (kernResult != KERN_SUCCESS) { + qDebug() << "IOServiceAddMatchingNotification return:" << kernResult; + return; + } + + // arm the callback, and clear any devices that are terminated + deviceTerminatedCallbackOSX( this, portIterator ); + + kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, cdcClassesToMatch, + deviceTerminatedCallbackOSX, this, &portIterator); + if (kernResult != KERN_SUCCESS) { + qDebug() << "IOServiceAddMatchingNotification return:" << kernResult; + return; + } + + // arm the callback, and clear any devices that are terminated + deviceTerminatedCallbackOSX( this, portIterator ); +} + diff --git a/src/libs/qextserialport/qextserialenumerator_unix.cpp b/src/libs/qextserialport/qextserialenumerator_unix.cpp new file mode 100644 index 0000000..f43a75b --- /dev/null +++ b/src/libs/qextserialport/qextserialenumerator_unix.cpp @@ -0,0 +1,75 @@ + + + +#include "qextserialenumerator.h" +#include +#include +#include +#include + +QextSerialEnumerator::QextSerialEnumerator( ) +{ + if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) ) + qRegisterMetaType("QextPortInfo"); +} + +QextSerialEnumerator::~QextSerialEnumerator( ) +{ +} + +QList QextSerialEnumerator::getPorts() +{ + QList infoList; +#ifdef Q_OS_LINUX + QStringList portNamePrefixes, portNameList; + portNamePrefixes << "ttyS*"; // list normal serial ports first + + QDir dir("/dev"); + portNameList = dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name); + + // remove the values which are not serial ports for e.g. /dev/ttysa + for (int i = 0; i < portNameList.size(); i++) { + bool ok; + QString current = portNameList.at(i); + // remove the ttyS part, and check, if the other part is a number + current.remove(0,4).toInt(&ok, 10); + if (!ok) { + portNameList.removeAt(i); + i--; + } + } + + // get the non standard serial ports names + // (USB-serial, bluetooth-serial, 18F PICs, and so on) + // if you know an other name prefix for serial ports please let us know + portNamePrefixes.clear(); + portNamePrefixes << "ttyACM*" << "ttyUSB*" << "rfcomm*"; + portNameList.append(dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name)); + + foreach (QString str , portNameList) { + QextPortInfo inf; + inf.physName = "/dev/"+str; + inf.portName = str; + + if (str.contains("ttyS")) { + inf.friendName = "Serial port "+str.remove(0, 4); + } + else if (str.contains("ttyUSB")) { + inf.friendName = "USB-serial adapter "+str.remove(0, 6); + } + else if (str.contains("rfcomm")) { + inf.friendName = "Bluetooth-serial adapter "+str.remove(0, 6); + } + inf.enumName = "/dev"; // is there a more helpful name for this? + infoList.append(inf); + } +#else + qCritical("Enumeration for POSIX systems (except Linux) is not implemented yet."); +#endif + return infoList; +} + +void QextSerialEnumerator::setUpNotifications( ) +{ + qCritical("Notifications for *Nix/FreeBSD are not implemented yet"); +} diff --git a/src/libs/qextserialport/qextserialenumerator_win.cpp b/src/libs/qextserialport/qextserialenumerator_win.cpp new file mode 100644 index 0000000..6026b54 --- /dev/null +++ b/src/libs/qextserialport/qextserialenumerator_win.cpp @@ -0,0 +1,206 @@ + + + +#include "qextserialenumerator.h" +#include +#include + +#include +#include +#include "qextserialport.h" +#include + +QextSerialEnumerator::QextSerialEnumerator( ) +{ + if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) ) + qRegisterMetaType("QextPortInfo"); +#if (defined QT_GUI_LIB) + notificationWidget = 0; +#endif // Q_OS_WIN +} + +QextSerialEnumerator::~QextSerialEnumerator( ) +{ +#if (defined QT_GUI_LIB) + if( notificationWidget ) + delete notificationWidget; +#endif +} + + + +// see http://msdn.microsoft.com/en-us/library/ms791134.aspx for list of GUID classes +#ifndef GUID_DEVCLASS_PORTS + DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 ); +#endif + +/* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */ +#ifdef UNICODE + #define QStringToTCHAR(x) (wchar_t*) x.utf16() + #define PQStringToTCHAR(x) (wchar_t*) x->utf16() + #define TCHARToQString(x) QString::fromUtf16((ushort*)(x)) + #define TCHARToQStringN(x,y) QString::fromUtf16((ushort*)(x),(y)) +#else + #define QStringToTCHAR(x) x.local8Bit().constData() + #define PQStringToTCHAR(x) x->local8Bit().constData() + #define TCHARToQString(x) QString::fromLocal8Bit((x)) + #define TCHARToQStringN(x,y) QString::fromLocal8Bit((x),(y)) +#endif /*UNICODE*/ + + +//static +QString QextSerialEnumerator::getRegKeyValue(HKEY key, LPCTSTR property) +{ + DWORD size = 0; + DWORD type; + RegQueryValueEx(key, property, NULL, NULL, NULL, & size); + BYTE* buff = new BYTE[size]; + QString result; + if( RegQueryValueEx(key, property, NULL, &type, buff, & size) == ERROR_SUCCESS ) + result = TCHARToQString(buff); + RegCloseKey(key); + delete [] buff; + return result; +} + +//static +QString QextSerialEnumerator::getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property) +{ + DWORD buffSize = 0; + SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, & buffSize); + BYTE* buff = new BYTE[buffSize]; + SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL); + QString result = TCHARToQString(buff); + delete [] buff; + return result; +} + +QList QextSerialEnumerator::getPorts() +{ + QList ports; + enumerateDevicesWin(GUID_DEVCLASS_PORTS, &ports); + return ports; +} + +void QextSerialEnumerator::enumerateDevicesWin( const GUID & guid, QList* infoList ) +{ + HDEVINFO devInfo; + if( (devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE) + { + SP_DEVINFO_DATA devInfoData; + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + for(int i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) + { + QextPortInfo info; + info.productID = info.vendorID = 0; + getDeviceDetailsWin( &info, devInfo, &devInfoData ); + infoList->append(info); + } + SetupDiDestroyDeviceInfoList(devInfo); + } +} + +#ifdef QT_GUI_LIB +bool QextSerialRegistrationWidget::winEvent( MSG* message, long* result ) +{ + if ( message->message == WM_DEVICECHANGE ) { + qese->onDeviceChangeWin( message->wParam, message->lParam ); + *result = 1; + return true; + } + return false; +} +#endif + +void QextSerialEnumerator::setUpNotifications( ) +{ + #ifdef QT_GUI_LIB + if(notificationWidget) + return; + notificationWidget = new QextSerialRegistrationWidget(this); + + DEV_BROADCAST_DEVICEINTERFACE dbh; + ZeroMemory(&dbh, sizeof(dbh)); + dbh.dbcc_size = sizeof(dbh); + dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + CopyMemory(&dbh.dbcc_classguid, &GUID_DEVCLASS_PORTS, sizeof(GUID)); + if( RegisterDeviceNotification( notificationWidget->winId( ), &dbh, DEVICE_NOTIFY_WINDOW_HANDLE ) == NULL) + qWarning() << "RegisterDeviceNotification failed:" << GetLastError(); + // setting up notifications doesn't tell us about devices already connected + // so get those manually + foreach( QextPortInfo port, getPorts() ) + emit deviceDiscovered( port ); + #else + qWarning("QextSerialEnumerator: GUI not enabled - can't register for device notifications."); + #endif // QT_GUI_LIB +} + +LRESULT QextSerialEnumerator::onDeviceChangeWin( WPARAM wParam, LPARAM lParam ) +{ + if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam ) + { + PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam; + if( pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE ) + { + PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr; + // delimiters are different across APIs...change to backslash. ugh. + QString deviceID = TCHARToQString(pDevInf->dbcc_name).toUpper().replace("#", "\\"); + + matchAndDispatchChangedDevice(deviceID, GUID_DEVCLASS_PORTS, wParam); + } + } + return 0; +} + +bool QextSerialEnumerator::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam) +{ + bool rv = false; + DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES; + HDEVINFO devInfo; + if( (devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE ) + { + SP_DEVINFO_DATA spDevInfoData; + spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + for(int i=0; SetupDiEnumDeviceInfo(devInfo, i, &spDevInfoData); i++) + { + DWORD nSize=0 ; + TCHAR buf[MAX_PATH]; + if ( SetupDiGetDeviceInstanceId(devInfo, &spDevInfoData, buf, MAX_PATH, &nSize) && + deviceID.contains(TCHARToQString(buf))) // we found a match + { + rv = true; + QextPortInfo info; + info.productID = info.vendorID = 0; + getDeviceDetailsWin( &info, devInfo, &spDevInfoData, wParam ); + if( wParam == DBT_DEVICEARRIVAL ) + emit deviceDiscovered(info); + else if( wParam == DBT_DEVICEREMOVECOMPLETE ) + emit deviceRemoved(info); + break; + } + } + SetupDiDestroyDeviceInfoList(devInfo); + } + return rv; +} + +bool QextSerialEnumerator::getDeviceDetailsWin( QextPortInfo* portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData, WPARAM wParam ) +{ + portInfo->friendName = getDeviceProperty(devInfo, devData, SPDRP_FRIENDLYNAME); + if( wParam == DBT_DEVICEARRIVAL) + portInfo->physName = getDeviceProperty(devInfo, devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME); + portInfo->enumName = getDeviceProperty(devInfo, devData, SPDRP_ENUMERATOR_NAME); + QString hardwareIDs = getDeviceProperty(devInfo, devData, SPDRP_HARDWAREID); + HKEY devKey = SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + portInfo->portName = QextSerialPort::fullPortNameWin( getRegKeyValue(devKey, TEXT("PortName")) ); + QRegExp idRx("VID_(\\w+)&PID_(\\w+)"); + if( hardwareIDs.toUpper().contains(idRx) ) + { + bool dummy; + portInfo->vendorID = idRx.cap(1).toInt(&dummy, 16); + portInfo->productID = idRx.cap(2).toInt(&dummy, 16); + //qDebug() << "got vid:" << vid << "pid:" << pid; + } + return true; +} + diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp index 730a0b6..3f38a01 100644 --- a/src/libs/utils/qtcolorbutton.cpp +++ b/src/libs/utils/qtcolorbutton.cpp @@ -282,4 +282,6 @@ void QtColorButton::dropEvent(QDropEvent *event) } // namespace Utils -//#include "moc_qtcolorbutton.cpp" +// It is unclear why this include directly access the MOC output? + +#include "moc_qtcolorbutton.cpp" diff --git a/src/libs/utils/utils_external.pri b/src/libs/utils/utils_external.pri index 7c7a85c..621e0ca 100644 --- a/src/libs/utils/utils_external.pri +++ b/src/libs/utils/utils_external.pri @@ -13,6 +13,7 @@ DEFINES += EXTERNAL_USE DEFINES += QTCREATOR_UTILS_LIB # submiteditorwidget.h \ +# qtcolorbutton.h \ # Input HEADERS += utils_global.h \ @@ -33,7 +34,6 @@ HEADERS += utils_global.h \ classnamevalidatinglineedit.h \ linecolumnlabel.h \ fancylineedit.h \ - qtcolorbutton.h \ savedaction.h \ abstractprocess.h \ consoleprocess.h \ @@ -82,6 +82,7 @@ SOURCES += consoleprocess_unix.cpp } # submiteditorwidget.cpp \ +# qtcolorbutton.cpp \ SOURCES += reloadpromptutils.cpp \ settingsutils.cpp \ @@ -99,7 +100,6 @@ SOURCES += reloadpromptutils.cpp \ classnamevalidatinglineedit.cpp \ linecolumnlabel.cpp \ fancylineedit.cpp \ - qtcolorbutton.cpp \ savedaction.cpp \ synchronousprocess.cpp \ submitfieldwidget.cpp \