mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-09 20:46:07 +01:00
230 lines
7.8 KiB
C++
230 lines
7.8 KiB
C++
/**
|
|
******************************************************************************
|
|
*
|
|
* @file usbmonitor_mac.cpp
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
* @addtogroup GCSPlugins GCS Plugins
|
|
* @{
|
|
* @addtogroup RawHIDPlugin Raw HID Plugin
|
|
* @{
|
|
* @brief Implements the USB monitor on Mac using XXXXX
|
|
*****************************************************************************/
|
|
/*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
|
|
#include "usbmonitor.h"
|
|
#include <IOKit/IOKitLib.h>
|
|
#include <IOKit/hid/IOHIDLib.h>
|
|
#include <CoreFoundation/CFString.h>
|
|
#include <CoreFoundation/CFArray.h>
|
|
#include <QMutexLocker>
|
|
#include <QDebug>
|
|
|
|
#define printf qDebug
|
|
|
|
//! Local helper functions
|
|
static bool HID_GetIntProperty(IOHIDDeviceRef dev, CFStringRef property, int * value);
|
|
static bool HID_GetStrProperty(IOHIDDeviceRef dev, CFStringRef property, QString & value);
|
|
|
|
/**
|
|
Initialize the USB monitor here
|
|
*/
|
|
USBMonitor::USBMonitor(QObject *parent): QThread(parent) {
|
|
hid_manager=NULL;
|
|
CFMutableDictionaryRef dict;
|
|
CFNumberRef num;
|
|
IOReturn ret;
|
|
|
|
m_instance = this;
|
|
|
|
listMutex = new QMutex();
|
|
knowndevices.clear();
|
|
|
|
hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
|
if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
|
|
if (hid_manager) CFRelease(hid_manager);
|
|
Q_ASSERT(0);
|
|
}
|
|
|
|
// No matching filter
|
|
IOHIDManagerSetDeviceMatching(hid_manager, NULL);
|
|
|
|
// 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);
|
|
ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
|
|
if (ret != kIOReturnSuccess) {
|
|
IOHIDManagerUnscheduleFromRunLoop(hid_manager,
|
|
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
CFRelease(hid_manager);
|
|
return;
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
USBMonitor::~USBMonitor()
|
|
{
|
|
//if(hid_manager != NULL)
|
|
// IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
quit();
|
|
}
|
|
|
|
void USBMonitor::deviceEventReceived() {
|
|
|
|
qDebug() << "Device event";
|
|
}
|
|
|
|
USBMonitor* USBMonitor::instance()
|
|
{
|
|
return m_instance;
|
|
}
|
|
|
|
USBMonitor* USBMonitor::m_instance = 0;
|
|
|
|
|
|
void USBMonitor::removeDevice(IOHIDDeviceRef dev) {
|
|
for( int i = 0; i < knowndevices.length(); i++) {
|
|
USBPortInfo port = knowndevices.at(i);
|
|
if(port.dev_handle == dev) {
|
|
QMutexLocker locker(listMutex);
|
|
knowndevices.removeAt(i);
|
|
emit deviceRemoved(port);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Static callback for the USB driver to indicate device removed
|
|
*/
|
|
void USBMonitor::detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
|
|
{
|
|
qDebug() << "USBMonitor: Device detached event";
|
|
instance()->removeDevice(dev);
|
|
}
|
|
|
|
void USBMonitor::addDevice(USBPortInfo info) {
|
|
QMutexLocker locker(listMutex);
|
|
knowndevices.append(info);
|
|
emit deviceDiscovered(info);
|
|
}
|
|
|
|
void USBMonitor::attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
|
|
{
|
|
bool got_properties = true;
|
|
|
|
CFTypeRef prop;
|
|
USBPortInfo deviceInfo;
|
|
|
|
deviceInfo.dev_handle = dev;
|
|
|
|
qDebug() << "USBMonitor: Device attached event";
|
|
|
|
// Populate the device info structure
|
|
got_properties &= HID_GetIntProperty(dev, CFSTR( kIOHIDVendorIDKey ), &deviceInfo.vendorID);
|
|
got_properties &= HID_GetIntProperty(dev, CFSTR( kIOHIDProductIDKey ), &deviceInfo.productID);
|
|
got_properties &= HID_GetIntProperty(dev, CFSTR( kIOHIDVersionNumberKey ), &deviceInfo.bcdDevice);
|
|
got_properties &= HID_GetStrProperty(dev, CFSTR( kIOHIDSerialNumberKey ), deviceInfo.serialNumber);
|
|
got_properties &= HID_GetStrProperty(dev, CFSTR( kIOHIDProductKey ), deviceInfo.product);
|
|
got_properties &= HID_GetStrProperty(dev, CFSTR( kIOHIDManufacturerKey ), deviceInfo.manufacturer);
|
|
// TOOD: Eventually want to take array of usages if devices start needing that
|
|
got_properties &= HID_GetIntProperty(dev, CFSTR( kIOHIDPrimaryUsageKey ), &deviceInfo.Usage);
|
|
got_properties &= HID_GetIntProperty(dev, CFSTR( kIOHIDPrimaryUsagePageKey ), &deviceInfo.UsagePage);
|
|
|
|
// Currently only enumerating objects that have the complete list of properties
|
|
if(got_properties) {
|
|
qDebug() << "USBMonitor: Adding device";
|
|
instance()->addDevice(deviceInfo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Returns a list of all currently available devices
|
|
*/
|
|
QList<USBPortInfo> USBMonitor::availableDevices()
|
|
{
|
|
//QMutexLocker locker(listMutex);
|
|
return knowndevices;
|
|
}
|
|
|
|
/**
|
|
* @brief Be a bit more picky and ask only for a specific type of device:
|
|
* @param[in] vid VID to screen or -1 to ignore
|
|
* @param[in] pid PID to screen or -1 to ignore
|
|
* @param[in] bcdDeviceMSB MSB of bcdDevice to screen or -1 to ignore
|
|
* @param[in] bcdDeviceLSB LSB of bcdDevice to screen or -1 to ignore
|
|
* @return List of USBPortInfo that meet this criterion
|
|
* @note
|
|
* On OpenPilot, the bcdDeviceLSB indicates the run state: bootloader or running.
|
|
* bcdDeviceMSB indicates the board model.
|
|
*/
|
|
QList<USBPortInfo> USBMonitor::availableDevices(int vid, int pid, int bcdDeviceMSB, int bcdDeviceLSB)
|
|
{
|
|
QList<USBPortInfo> allPorts = availableDevices();
|
|
QList<USBPortInfo> thePortsWeWant;
|
|
|
|
foreach (USBPortInfo port, allPorts) {
|
|
if((port.vendorID==vid || vid==-1) && (port.productID==pid || pid==-1) && ((port.bcdDevice>>8)==bcdDeviceMSB || bcdDeviceMSB==-1) &&
|
|
( (port.bcdDevice&0x00ff) ==bcdDeviceLSB || bcdDeviceLSB==-1))
|
|
thePortsWeWant.append(port);
|
|
}
|
|
|
|
return thePortsWeWant;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function get get a HID integer property
|
|
* @param[in] dev Device reference
|
|
* @param[in] property The property to get (constants defined in IOKIT)
|
|
* @param[out] value Pointer to integer to set
|
|
* @return True if successful, false otherwise
|
|
*/
|
|
static bool HID_GetIntProperty(IOHIDDeviceRef dev, CFStringRef property, int * value) {
|
|
CFTypeRef prop = IOHIDDeviceGetProperty(dev, property);
|
|
if (prop) {
|
|
if (CFNumberGetTypeID() == CFGetTypeID(prop)) { // if a number
|
|
CFNumberGetValue((CFNumberRef) prop, kCFNumberSInt32Type, value);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function get get a HID string property
|
|
* @param[in] dev Device reference
|
|
* @param[in] property The property to get (constants defined in IOKIT)
|
|
* @param[out] value The QString to set
|
|
* @return True if successful, false otherwise
|
|
*/
|
|
static bool HID_GetStrProperty(IOHIDDeviceRef dev, CFStringRef property, QString & value) {
|
|
CFTypeRef prop = IOHIDDeviceGetProperty(dev, property);
|
|
if (prop) {
|
|
if (CFStringGetTypeID() == CFGetTypeID(prop)) { // if a string
|
|
char buffer[2550];
|
|
bool success = CFStringGetCString ( (CFStringRef) prop, buffer, sizeof(buffer), kCFStringEncodingMacRoman );
|
|
value = QString(buffer);
|
|
return success;
|
|
}
|
|
}
|
|
return false;
|
|
}
|