Commit e5ff5501 authored by Bryant's avatar Bryant

Removed unnecessary qextserialport libray.

Replaced by /libs/serialport
parent 9d32ca15
/*!
* \file qextserialenumerator.h
* \author Michal Policht
* \see QextSerialEnumerator
*/
#ifndef _QEXTSERIALENUMERATOR_H_
#define _QEXTSERIALENUMERATOR_H_
#include <QtCore/qglobal.h>
//#ifdef QEXTSERIALPORT_LIB
//# define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT
//#else
//# define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT
//#endif
#define QEXTSERIALPORT_EXPORT
#include <QString>
#include <QList>
#include <QObject>
//#include "qextserialport_global.h"
#ifdef Q_OS_WIN
#include <windows.h>
#include <setupapi.h>
#include <dbt.h>
#endif /*Q_OS_WIN*/
#ifdef Q_OS_MAC
#include <IOKit/usb/IOUSBLib.h>
#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 <QWidget>
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<QextPortInfo> 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
<a href="http://www.codeproject.com">The Code Project</a> (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<QextPortInfo> & 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<QextPortInfo>* 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<QextPortInfo> & infoList);
static void iterateServicesOSX(io_object_t service, QList<QextPortInfo> & 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<QextPortInfo> & 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<QextPortInfo> 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_*/
#include "qextserialenumerator.h"
#include <QDebug>
#include <QMetaType>
#include <IOKit/serial/IOSerialKeys.h>
#include <CoreFoundation/CFNumber.h>
#include <sys/param.h>
QextSerialEnumerator::QextSerialEnumerator( )
{
if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) )
qRegisterMetaType<QextPortInfo>("QextPortInfo");
}
QextSerialEnumerator::~QextSerialEnumerator( )
{
IONotificationPortDestroy( notificationPortRef );
}
// static
QList<QextPortInfo> QextSerialEnumerator::getPorts()
{
QList<QextPortInfo> 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<QextPortInfo> & 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 );
}
#include "qextserialenumerator.h"
#include <QDebug>
#include <QMetaType>
#include <QStringList>
#include <QDir>
QextSerialEnumerator::QextSerialEnumerator( )
{
if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) )
qRegisterMetaType<QextPortInfo>("QextPortInfo");
}
QextSerialEnumerator::~QextSerialEnumerator( )
{
}
QList<QextPortInfo> QextSerialEnumerator::getPorts()
{
QList<QextPortInfo> 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");
}
#include "qextserialenumerator.h"
#include <QDebug>
#include <QMetaType>
#include <objbase.h>
#include <initguid.h>
//#include "qextserialport.h"
#include <QRegExp>
#ifdef Q_OS_WIN
#ifndef _MSC_VER
#include <windows.h>
#include <dbt.h>
#include <QtCore/qglobal.h>
#endif
#endif
QextSerialEnumerator::QextSerialEnumerator( )
{
if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) )
qRegisterMetaType<QextPortInfo>("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<QextPortInfo> QextSerialEnumerator::getPorts()
{
QList<QextPortInfo> ports;
enumerateDevicesWin(GUID_DEVCLASS_PORTS, &ports);
return ports;
}
void QextSerialEnumerator::enumerateDevicesWin( const GUID & guid, QList<QextPortInfo>* 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);
QRegExp rx("^COM(\\d+)");
QString fullName(getRegKeyValue(devKey, TEXT("PortName")));
if(fullName.contains(rx)) {
int portnum = rx.cap(1).toInt();
if(portnum > 9) // COM ports greater than 9 need \\.\ prepended
fullName.prepend("\\\\.\\");
}
portInfo->portName = fullName;
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment