1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-29 14:52:12 +01:00

Merge remote-tracking branch 'origin/dankers/minor-modem-renames' into next

This commit is contained in:
Brian Webb 2013-05-27 09:44:17 -07:00
commit 50162333d8
30 changed files with 45 additions and 3560 deletions

View File

@ -245,7 +245,7 @@ void processComand(uint8_t *xReceive_Buffer)
}
break;
case Remote_flash_via_spi:
result = false; // No support for this for the PipX
result = false; // No support for this for the OPLink Mini
break;
default:
result = 0;
@ -476,7 +476,7 @@ bool flash_read(uint8_t *buffer, uint32_t adr, DFUProgType type)
{
switch (type) {
case Remote_flash_via_spi:
return false; // We should not get this for the PipX
return false; // We should not get this for the OPLink Mini
break;
case Self_flash:

View File

@ -3,7 +3,7 @@
*
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Defines board specific static initializers for hardware for the PipBee board.
* @brief Defines board specific static initializers for hardware for the CopterControl board.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/

View File

@ -1,3 +1,29 @@
/**
******************************************************************************
*
* @file board_hw_defs.c.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief Defines board hardware for the OpenPilot OPLink Mini board.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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
*/
#if defined(PIOS_INCLUDE_LED)
#include <pios_led_priv.h>

View File

@ -3,7 +3,7 @@
*
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Defines board specific static initializers for hardware for the PipBee board.
* @brief Defines board specific static initializers for hardware for the OPLink Mini board.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/

View File

@ -2,8 +2,8 @@
******************************************************************************
*
* @file pios_board.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Defines board hardware for the OpenPilot Version 1.1 hardware.
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief Defines PiOS board hardware for the OpenPilot OPLink Mini board.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/

View File

@ -33,18 +33,19 @@
#include <pios_usbhook.h> /* PIOS_USBHOOK_* */
#include <pios_usb_util.h> /* PIOS_USB_UTIL_AsciiToUtf8 */
static const uint8_t usb_product_id[20] = {
static const uint8_t usb_product_id[22] = {
sizeof(usb_product_id),
USB_DESC_TYPE_STRING,
'O', 0,
'P', 0,
'L', 0,
'i', 0,
'n', 0,
'k', 0,
'M', 0,
'i', 0,
'n', 0,
'i', 0,
'p', 0,
'X', 0,
't', 0,
'r', 0,
'e', 0,
'm', 0,
'e', 0,
};
static uint8_t usb_serial_number[2 + PIOS_SYS_SERIAL_NUM_ASCII_LEN * 2 + (sizeof(PIOS_USB_BOARD_SN_SUFFIX) - 1) * 2] = {

View File

@ -3,7 +3,7 @@
*
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Defines board specific static initializers for hardware for the PipBee board.
* @brief Defines board specific static initializers for hardware for the OPLink Mini board.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/

View File

@ -116,7 +116,7 @@ public:
idVendor_OpenPilot = 0x20a0,
idProduct_OpenPilot = 0x415a,
idProduct_CopterControl = 0x415b,
idProduct_PipXtreme = 0x415c
idProduct_OPLinkMini = 0x415c
};
static USBMonitor *instance();

View File

@ -1,10 +0,0 @@
<plugin name="RawHID" version="1.0.0" compatVersion="1.0.0">
<vendor>The OpenPilot Project</vendor>
<copyright>(C) 2010 OpenPilot Project</copyright>
<license>GNU Public License (GPL) Version 3</license>
<description>Connection to OpenPilot board using RawHID USB interface</description>
<url>http://www.openpilot.org</url>
<dependencyList>
<dependency name="Core" version="1.0.0"/>
</dependencyList>
</plugin>

View File

@ -1,163 +0,0 @@
/**
******************************************************************************
*
* @file pjrc_rawhid.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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
*/
#ifndef PJRC_RAWHID_H
#define PJRC_RAWHID_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <QDebug>
#include <QMutex>
#include <QString>
#include "rawhid_global.h"
#if defined(Q_OS_MAC)
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDLib.h>
#include <CoreFoundation/CFString.h>
#elif defined(Q_OS_UNIX)
// #elif defined(Q_OS_LINUX)
#include <usb.h>
#include <QDebug>
#include <QString>
#elif defined(Q_OS_WIN32)
#include <windows.h>
#include <setupapi.h>
#include <ddk/hidsdi.h>
#include <ddk/hidclass.h>
#endif
// ************
#if defined(Q_OS_MAC)
// todo:
#elif defined(Q_OS_UNIX)
// #elif defined(Q_OS_LINUX)
typedef struct hid_struct hid_t;
struct hid_struct {
usb_dev_handle *usb;
int open;
int iface;
int ep_in;
int ep_out;
struct hid_struct *prev;
struct hid_struct *next;
};
#elif defined(Q_OS_WIN32)
typedef struct hid_struct hid_t;
struct hid_struct {
HANDLE handle;
int open;
struct hid_struct *prev;
struct hid_struct *next;
};
#endif // if defined(Q_OS_MAC)
class RAWHID_EXPORT pjrc_rawhid : public QObject {
Q_OBJECT
public:
pjrc_rawhid();
~pjrc_rawhid();
int open(int max, int vid, int pid, int usage_page, int usage);
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);
signals:
void deviceUnplugged(int);
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);
// Platform specific handles for the USB device
IOHIDManagerRef hid_manager;
IOHIDDeviceRef dev;
CFRunLoopRef the_correct_runloop;
CFRunLoopRef received_runloop;
static const int BUFFER_SIZE = 64;
uint8_t buffer[BUFFER_SIZE];
int attach_count;
int buffer_count;
bool device_open;
bool unplugged;
QMutex *m_writeMutex;
QMutex *m_readMutex;
#elif defined(Q_OS_UNIX)
hid_t * first_hid;
hid_t *last_hid;
void add_hid(hid_t *h);
hid_t *get_hid(int num);
void free_all_hid(void);
void hid_close(hid_t *hid);
int hid_parse_item(uint32_t *val, uint8_t * *data, const uint8_t *end);
#elif defined(Q_OS_WIN32)
hid_t * first_hid;
hid_t *last_hid;
HANDLE rx_event;
HANDLE tx_event;
CRITICAL_SECTION rx_mutex;
CRITICAL_SECTION tx_mutex;
void add_hid(hid_t *h);
hid_t *get_hid(int num);
void free_all_hid(void);
void hid_close(hid_t *hid);
void print_win32_err(DWORD err);
#endif // if defined(Q_OS_MAC)
};
#endif // ifndef PJRC_RAWHID_H

View File

@ -1,423 +0,0 @@
/* @file pjrc_rawhid_mac.cpp
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/* Simple Raw HID functions for Linux - for use with Teensy RawHID example
* http://www.pjrc.com/teensy/rawhid.html
* Copyright (c) 2009 PJRC.COM, LLC
*
* rawhid_open - open 1 or more devices
* rawhid_recv - receive a packet
* rawhid_send - send a packet
* rawhid_close - close a device
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above description, website URL and copyright notice and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Version 1.0: Initial Release
*/
#include "pjrc_rawhid.h"
#include <unistd.h>
#include <QString>
#include <QThread>
#include <QTimer>
#include <QCoreApplication>
struct timeout_info {
CFRunLoopRef loopRef;
bool timed_out;
};
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;
}
}
/**
* @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)
{
CFMutableDictionaryRef dict;
CFNumberRef num;
IOReturn ret;
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()) {
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,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (!dict) {
return 0;
}
if (vid > 0) {
num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid);
CFDictionarySetValue(dict, CFSTR(kIOHIDVendorIDKey), num);
CFRelease(num);
}
if (pid > 0) {
num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
CFDictionarySetValue(dict, CFSTR(kIOHIDProductIDKey), num);
CFRelease(num);
}
if (usage_page > 0) {
num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page);
CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsagePageKey), num);
CFRelease(num);
}
if (usage > 0) {
num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsageKey), num);
CFRelease(num);
}
IOHIDManagerSetDeviceMatching(hid_manager, dict);
CFRelease(dict);
} 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);
IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, pjrc_rawhid::attach_callback, this);
IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, pjrc_rawhid::dettach_callback, this);
ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
if (ret != kIOReturnSuccess) {
IOHIDManagerUnscheduleFromRunLoop(hid_manager,
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRelease(hid_manager);
return 0;
}
// let it do the callback for all devices
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) {
;
}
// count up how many were added by the callback
return attach_count;
}
/**
* @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)
{
QMutexLocker locker(m_readMutex);
Q_UNUSED(locker);
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;
info.loopRef = CFRunLoopGetCurrent();;
info.timed_out = false;
CFRunLoopTimerContext context;
memset(&context, 0, sizeof(context));
context.info = &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);
received_runloop = CFRunLoopGetCurrent();
// 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) {
len = 0;
break;
}
CFRunLoopRun(); // Wait for data
}
CFRunLoopTimerInvalidate(timer);
CFRelease(timer);
received_runloop = NULL;
return len;
}
/**
* @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, 2, 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, 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)
QMutexLocker locker(m_writeMutex);
Q_UNUSED(locker);
if (!device_open || unplugged) {
return -1;
}
uint8_t *report_buf = (uint8_t *)malloc(len);
memcpy(&report_buf[0], buf, len);
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();
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()) {
// Note: I'm not sure it will always succeed if encoded as MacRoman but that
// is a superset of UTF8 so I think this is fine
CFStringRef str = static_cast<CFStringRef>(serialnum);
int length = CFStringGetLength(str);
if (length == 0) {
return "";
}
char *ptr = (char *)malloc(length + 1);
Boolean ret = CFStringGetCString(str, ptr, length + 1, kCFStringEncodingMacRoman);
QString strResult;
if (ret == true) {
strResult = ptr;
}
free(ptr);
return strResult;
}
return QString("Error");
}
// ! Close the HID device
void pjrc_rawhid::close(int)
{
// Make sure any pending locks are done
QMutexLocker lock(m_writeMutex);
if (device_open) {
device_open = false;
CFRunLoopStop(the_correct_runloop);
if (!unplugged) {
IOHIDDeviceUnscheduleFromRunLoop(dev, the_correct_runloop, kCFRunLoopDefaultMode);
IOHIDDeviceRegisterInputReportCallback(dev, buffer, sizeof(buffer), NULL, NULL);
IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
}
IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, NULL, NULL);
IOHIDManagerClose(hid_manager, 0);
dev = NULL;
hid_manager = NULL;
}
}
/**
* @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)
{
if (!device_open) {
return;
}
if (len > BUFFER_SIZE) {
len = BUFFER_SIZE;
}
// Note: packet preprocessing done in OS independent code
memcpy(buffer, &data[0], len);
buffer_count = len;
if (received_runloop) {
CFRunLoopStop(received_runloop);
}
}
// ! 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);
}
// ! Timeout used for the
void pjrc_rawhid::timeout_callback(CFRunLoopTimerRef, void *i)
{
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)
{
unplugged = true;
if (d == dev) {
emit deviceUnplugged(0);
}
}
// ! Called from the USB system and forwarded to the instance (context)
void pjrc_rawhid::dettach_callback(void *context, IOReturn, void *, IOHIDDeviceRef dev)
{
pjrc_rawhid *p = (pjrc_rawhid *)context;
p->dettach(dev);
}
/**
* @brief Called by the USB system
* @param dev The device that was attached
*/
void pjrc_rawhid::attach(IOHIDDeviceRef d)
{
// Store the device handle
dev = d;
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);
attach_count++;
device_open = true;
unplugged = false;
}
// ! 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)
{
pjrc_rawhid *p = (pjrc_rawhid *)context;
p->attach(dev);
}

View File

@ -1,421 +0,0 @@
/* @file pjrc_rawhid_unix.cpp
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/* Simple Raw HID functions for Linux - for use with Teensy RawHID example
* http://www.pjrc.com/teensy/rawhid.html
* Copyright (c) 2009 PJRC.COM, LLC
*
* rawhid_open - open 1 or more devices
* rawhid_recv - receive a packet
* rawhid_send - send a packet
* rawhid_close - close a device
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above description, website URL and copyright notice and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Version 1.0: Initial Release
*/
#include "pjrc_rawhid.h"
#define printf qDebug
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
//
int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage)
{
struct usb_bus *bus;
struct usb_device *dev;
struct usb_interface *iface;
struct usb_interface_descriptor *desc;
struct usb_endpoint_descriptor *ep;
usb_dev_handle *u;
uint8_t buf[1024], *p;
int i, n, len, tag, ep_in, ep_out, count = 0, claimed;
uint32_t val = 0, parsed_usage, parsed_usage_page;
hid_t *hid;
if (first_hid) {
free_all_hid();
}
// printf("pjrc_rawhid_open, max=%d\n", max);
if (max < 1) {
return 0;
}
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (vid > 0 && dev->descriptor.idVendor != vid) {
continue;
}
if (pid > 0 && dev->descriptor.idProduct != pid) {
continue;
}
if (!dev->config) {
continue;
}
if (dev->config->bNumInterfaces < 1) {
continue;
}
printf("device: vid=%04X, pic=%04X, with %d iface",
dev->descriptor.idVendor,
dev->descriptor.idProduct,
dev->config->bNumInterfaces);
iface = dev->config->interface;
u = NULL;
claimed = 0;
for (i = 0; i < dev->config->bNumInterfaces && iface; i++, iface++) {
desc = iface->altsetting;
if (!desc) {
continue;
}
printf(" type %d, %d, %d", desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);
if (desc->bInterfaceClass != 3) {
continue;
}
if (desc->bInterfaceSubClass != 0) {
continue;
}
if (desc->bInterfaceProtocol != 0) {
continue;
}
ep = desc->endpoint;
ep_in = ep_out = 0;
for (n = 0; n < desc->bNumEndpoints; n++, ep++) {
if (ep->bEndpointAddress & 0x80) {
if (!ep_in) {
ep_in = ep->bEndpointAddress & 0x7F;
}
qDebug() << " IN endpoint " << ep_in;
} else {
if (!ep_out) {
ep_out = ep->bEndpointAddress;
}
qDebug() << " OUT endpoint " << ep_out;
}
}
if (!ep_in) {
continue;
}
if (!u) {
u = usb_open(dev);
if (!u) {
qDebug() << " unable to open device";
break;
}
}
qDebug() << " hid interface (generic)";
if (usb_get_driver_np(u, i, (char *)buf, sizeof(buf)) >= 0) {
printf(" in use by driver \"%s\"", buf);
if (usb_detach_kernel_driver_np(u, i) < 0) {
printf(" unable to detach from kernel");
continue;
}
}
if (usb_claim_interface(u, i) < 0) {
printf(" unable claim interface %d", i);
continue;
}
len = usb_control_msg(u, 0x81, 6, 0x2200, i, (char *)buf, sizeof(buf), 250);
printf(" descriptor, len=%d", len);
if (len < 2) {
usb_release_interface(u, i);
continue;
}
p = buf;
parsed_usage_page = parsed_usage = 0;
while ((tag = hid_parse_item(&val, &p, buf + len)) >= 0) {
printf(" tag: %X, val %X", tag, val);
if (tag == 4) {
parsed_usage_page = val;
}
if (tag == 8) {
parsed_usage = val;
}
if (parsed_usage_page && parsed_usage) {
break;
}
}
if ((!parsed_usage_page) || (!parsed_usage) ||
(usage_page > 0 && parsed_usage_page != (uint32_t)usage_page) ||
(usage > 0 && parsed_usage != (uint32_t)usage)) {
usb_release_interface(u, i);
continue;
}
hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
if (!hid) {
usb_release_interface(u, i);
continue;
}
hid->usb = u;
hid->iface = i;
hid->ep_in = ep_in;
hid->ep_out = ep_out;
hid->open = 1;
add_hid(hid);
claimed++;
count++;
if (count >= max) {
return count;
}
}
if (u && !claimed) {
usb_close(u);
}
}
}
return 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)
{
if (!buf) {
return -1;
}
hid_t *hid = get_hid(num);
if (!hid || !hid->open) {
return -1;
}
int r = usb_interrupt_read(hid->usb, hid->ep_in, (char *)buf, len, timeout);
if (r >= 0) {
return r;
}
if (r == -110) {
return 0; // timeout
}
return -1;
}
// 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
//
int pjrc_rawhid::send(int num, void *buf, int len, int timeout)
{
hid_t *hid;
hid = get_hid(num);
if (!hid || !hid->open) {
return -1;
}
if (hid->ep_out) {
return usb_interrupt_write(hid->usb, hid->ep_out, (char *)buf, len, timeout);
} else {
return usb_control_msg(hid->usb, 0x21, 9, 0, hid->iface, (char *)buf, len, timeout);
}
}
// getserial - get the serialnumber of the device
//
// Inputs:
// num = device to close (zero based)
// buf = buffer to read the serialnumber into
// Output
// number of bytes in found, or -1 on error
//
QString pjrc_rawhid::getserial(int num)
{
hid_t *hid;
char buf[128];
hid = get_hid(num);
if (!hid || !hid->open) {
return QString("");
}
int retlen = usb_get_string_simple(hid->usb, 3, buf, 128);
return QString().fromAscii(buf, -1);
}
// close - close a device
//
// Inputs:
// num = device to close (zero based)
// Output
// (nothing)
//
void pjrc_rawhid::close(int num)
{
hid_close(get_hid(num));
}
// Chuck Robey wrote a real HID report parser
// (chuckr@telenix.org) chuckr@chuckr.org
// http://people.freebsd.org/~chuckr/code/python/uhidParser-0.2.tbz
// this tiny thing only needs to extract the top-level usage page
// and usage, and even then is may not be truly correct, but it does
// work with the Teensy Raw HID example.
int pjrc_rawhid::hid_parse_item(uint32_t *val, uint8_t * *data, const uint8_t *end)
{
const uint8_t *p = *data;
uint8_t tag;
int table[4] = { 0, 1, 2, 4 };
int len;
if (p >= end) {
return -1;
}
if (p[0] == 0xFE) {
// long item, HID 1.11, 6.2.2.3, page 27
if (p + 5 >= end || p + p[1] >= end) {
return -1;
}
tag = p[2];
*val = 0;
len = p[1] + 5;
} else {
// short item, HID 1.11, 6.2.2.2, page 26
tag = p[0] & 0xFC;
len = table[p[0] & 0x03];
if (p + len + 1 >= end) {
return -1;
}
switch (p[0] & 0x03) {
case 3: *val = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24); break;
case 2: *val = p[1] | (p[2] << 8); break;
case 1: *val = p[1]; break;
case 0: *val = 0; break;
}
}
*data += len + 1;
return tag;
}
void pjrc_rawhid::add_hid(hid_t *h)
{
if (!h) {
return;
}
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;
}
hid_t *pjrc_rawhid::get_hid(int num)
{
hid_t *p = NULL;
for (p = first_hid; p && num > 0; p = p->next, num--) {
;
}
return p;
}
void pjrc_rawhid::free_all_hid(void)
{
for (hid_t *p = first_hid; p; p = p->next) {
hid_close(p);
}
hid_t *p = first_hid;
while (p) {
hid_t *q = p;
p = p->next;
free(q);
}
first_hid = last_hid = NULL;
}
void pjrc_rawhid::hid_close(hid_t *hid)
{
if (!hid) {
return;
}
if (!hid->open) {
return;
}
usb_release_interface(hid->usb, hid->iface);
int others = 0;
for (hid_t *p = first_hid; p; p = p->next) {
if (p->open && p->usb == hid->usb) {
others++;
}
}
if (!others) {
usb_close(hid->usb);
}
hid->usb = NULL;
hid->open = 0;
}

View File

@ -1,483 +0,0 @@
/* @file pjrc_rawhid_windows.cpp
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/* Simple Raw HID functions for Windows - for use with Teensy RawHID example
* http://www.pjrc.com/teensy/rawhid.html
* Copyright (c) 2009 PJRC.COM, LLC
*
* rawhid_open - open 1 or more devices
* rawhid_recv - receive a packet
* rawhid_send - send a packet
* rawhid_close - close a device
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above description, website URL and copyright notice and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Version 1.0: Initial Release
*/
/* See: http://msdn.microsoft.com/en-us/library/ms794141.aspx */
#include "pjrc_rawhid.h"
#include <QString>
#define printf qDebug
pjrc_rawhid::pjrc_rawhid()
{
first_hid = NULL;
last_hid = NULL;
rx_event = NULL;
tx_event = 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
//
int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage)
{
GUID guid;
HDEVINFO info;
DWORD index = 0, reqd_size;
SP_DEVICE_INTERFACE_DATA iface;
SP_DEVICE_INTERFACE_DETAIL_DATA *details;
HIDD_ATTRIBUTES attrib;
PHIDP_PREPARSED_DATA hid_data;
HIDP_CAPS capabilities;
HANDLE h;
BOOL ret;
hid_t *hid;
int count = 0;
if (first_hid) {
free_all_hid();
}
if (max < 1) {
return 0;
}
if (!rx_event) {
rx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
tx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
InitializeCriticalSection(&rx_mutex);
InitializeCriticalSection(&tx_mutex);
}
HidD_GetHidGuid(&guid);
info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (info == INVALID_HANDLE_VALUE) {
return 0;
}
for (index = 0; 1; index++) {
iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
if (!ret) {
return count;
}
SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &reqd_size, NULL);
details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size);
if (details == NULL) {
continue;
}
memset(details, 0, reqd_size);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details, reqd_size, NULL, NULL);
if (!ret) {
free(details);
continue;
}
h = CreateFile(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
// I get ERROR_ACCESS_DENIED with most/all my input devices (mice/trackballs/tablet).
// Let's not log it :)
if (err == ERROR_ACCESS_DENIED) {
free(details);
continue;
}
// qDebug wipes the GetLastError() it seems, so do that after print_win32_err().
print_win32_err(err);
qDebug() << "Problem opening handle, path: " << QString().fromWCharArray(details->DevicePath);
free(details);
continue;
}
free(details);
attrib.Size = sizeof(HIDD_ATTRIBUTES);
ret = HidD_GetAttributes(h, &attrib);
// printf("vid: %4x\n", attrib.VendorID);
if (!ret || (vid > 0 && attrib.VendorID != vid) ||
(pid > 0 && attrib.ProductID != pid) ||
!HidD_GetPreparsedData(h, &hid_data)) {
CloseHandle(h);
continue;
}
if (!HidP_GetCaps(hid_data, &capabilities) ||
(usage_page > 0 && capabilities.UsagePage != usage_page) ||
(usage > 0 && capabilities.Usage != usage)) {
HidD_FreePreparsedData(hid_data);
CloseHandle(h);
continue;
}
HidD_FreePreparsedData(hid_data);
hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
if (!hid) {
CloseHandle(h);
continue;
}
// COMMTIMEOUTS CommTimeouts;
// CommTimeouts.ReadIntervalTimeout = 100; // 100ms
// CommTimeouts.ReadTotalTimeoutConstant = 5; // ms
// CommTimeouts.ReadTotalTimeoutMultiplier = 1; //
// CommTimeouts.WriteTotalTimeoutConstant = 5; // ms
// CommTimeouts.WriteTotalTimeoutMultiplier = 1; //
// if (!SetCommTimeouts(h, &CommTimeouts))
// {
//// DWORD err = GetLastError();
//
// }
qDebug("Open: Handle address: %li for num: %i", (long int)h, count);
hid->handle = h;
add_hid(hid);
count++;
if (count >= max) {
return count;
}
}
return 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)
{
OVERLAPPED ov;
DWORD n;
hid_t *hid = get_hid(num);
if (!hid) {
return -1;
}
if (!hid->handle) {
return -1;
}
EnterCriticalSection(&rx_mutex);
ResetEvent(&rx_event);
memset(&ov, 0, sizeof(ov));
ov.hEvent = rx_event;
if (!ReadFile(hid->handle, buf, len, NULL, &ov)) {
DWORD err = GetLastError();
if (err == ERROR_DEVICE_NOT_CONNECTED) { // the device has been unplugged
print_win32_err(err);
hid_close(hid);
LeaveCriticalSection(&rx_mutex);
emit deviceUnplugged(num);
return -1;
}
if (err != ERROR_IO_PENDING) {
print_win32_err(err);
LeaveCriticalSection(&rx_mutex);
return -1;
}
DWORD r = WaitForSingleObject(rx_event, timeout);
if (r == WAIT_TIMEOUT) {
CancelIo(hid->handle);
LeaveCriticalSection(&rx_mutex);
return 0;
}
if (r != WAIT_OBJECT_0) {
DWORD err = GetLastError();
print_win32_err(err);
LeaveCriticalSection(&rx_mutex);
return -1;
}
}
if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) {
DWORD err = GetLastError();
print_win32_err(err);
if (err == ERROR_DEVICE_NOT_CONNECTED) { // the device has been unplugged
hid_close(hid);
LeaveCriticalSection(&rx_mutex);
emit deviceUnplugged(num);
return -1;
}
LeaveCriticalSection(&rx_mutex);
return -1;
}
LeaveCriticalSection(&rx_mutex);
if (n <= 0) {
return -1;
}
// qDebug("Received %i bytes, first %x, second %x", len, *((char *) buf),*((char *)buf + 1));
if ((int)n > len) {
n = len;
}
return n;
}
// 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
//
int pjrc_rawhid::send(int num, void *buf, int len, int timeout)
{
OVERLAPPED ov;
DWORD n, r;
hid_t *hid = get_hid(num);
if (!hid) {
return -1;
}
if (!hid->handle) {
return -1;
}
// qDebug("Send: Handle address: %li for num: %i", (long int) hid->handle, num);
EnterCriticalSection(&tx_mutex);
ResetEvent(&tx_event);
memset(&ov, 0, sizeof(ov));
ov.hEvent = tx_event;
// qDebug("Trying to write %u bytes. First %x second %x",len, *((char *) buf), *((char *)buf + 1));
if (!WriteFile(hid->handle, buf, len, NULL, &ov)) {
DWORD err = GetLastError();
if (err == ERROR_DEVICE_NOT_CONNECTED) { // the device has been unplugged
hid_close(hid);
LeaveCriticalSection(&tx_mutex);
emit deviceUnplugged(num);
return -1;
}
if (err == ERROR_SUCCESS || err == ERROR_IO_PENDING) {
// qDebug("Waiting for write to finish");
r = WaitForSingleObject(tx_event, timeout);
if (r == WAIT_TIMEOUT) {
CancelIo(hid->handle);
LeaveCriticalSection(&tx_mutex);
return 0;
}
if (r != WAIT_OBJECT_0) {
DWORD err = GetLastError();
print_win32_err(err);
LeaveCriticalSection(&tx_mutex);
return -1;
}
} else {
// qDebug("Error writing to file");
print_win32_err(err);
LeaveCriticalSection(&tx_mutex);
return -1;
}
}
if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) {
DWORD err = GetLastError();
qDebug("Problem getting overlapped result");
print_win32_err(err);
if (err == ERROR_DEVICE_NOT_CONNECTED) { // the device has been unplugged
hid_close(hid);
LeaveCriticalSection(&tx_mutex);
emit deviceUnplugged(num);
return -1;
}
}
LeaveCriticalSection(&tx_mutex);
if (n <= 0) {
return -1;
}
return n;
}
QString pjrc_rawhid::getserial(int num)
{
hid_t *hid = get_hid(num);
if (!hid) {
return "";
}
if (!hid->handle) {
return "";
}
// Should we do some "critical section" stuff here??
char temp[126];
if (!HidD_GetSerialNumberString(hid->handle, temp, sizeof(temp))) {
DWORD err = GetLastError();
print_win32_err(err);
if (err == ERROR_DEVICE_NOT_CONNECTED) { // the device has been unplugged
hid_close(hid);
emit deviceUnplugged(num);
return "";
}
return QString("Error");
}
return QString().fromUtf16((ushort *)temp, -1);
}
// close - close a device
//
// Inputs:
// num = device to close (zero based)
// Output
// (nothing)
//
void pjrc_rawhid::close(int num)
{
hid_close(get_hid(num));
}
void pjrc_rawhid::add_hid(hid_t *h)
{
if (!h) {
return;
}
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;
}
hid_t *pjrc_rawhid::get_hid(int num)
{
hid_t *p;
for (p = first_hid; p && num > 0; p = p->next, num--) {
;
}
return p;
}
void pjrc_rawhid::free_all_hid(void)
{
for (hid_t *p = first_hid; p; p = p->next) {
hid_close(p);
}
hid_t *p = first_hid;
while (p) {
hid_t *q = p;
p = p->next;
free(q);
}
first_hid = last_hid = NULL;
}
void pjrc_rawhid::hid_close(hid_t *hid)
{
if (!hid) {
return;
}
if (!hid->handle) {
return;
}
CloseHandle(hid->handle);
hid->handle = NULL;
}
void pjrc_rawhid::print_win32_err(DWORD err)
{
char buf[256];
char temp[256];
// FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (WCHAR*)buf, sizeof(buf), NULL);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (WCHAR *)buf, sizeof(buf), NULL);
WideCharToMultiByte(CP_ACP, 0, (WCHAR *)buf, sizeof(buf), temp, sizeof(temp), NULL, NULL);
printf("err %ld: %s\n", err, temp);
}

View File

@ -1,465 +0,0 @@
/**
******************************************************************************
*
* @file rawhid.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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 "rawhid.h"
#include "rawhid_const.h"
#include "coreplugin/connectionmanager.h"
#include <extensionsystem/pluginmanager.h>
#include <QtGlobal>
#include <QList>
#include <QMutexLocker>
#include <QWaitCondition>
class IConnection;
// timeout value used when we want to return directly without waiting
static const int READ_TIMEOUT = 200;
static const int READ_SIZE = 64;
static const int WRITE_TIMEOUT = 1000;
static const int WRITE_SIZE = 64;
// *********************************************************************************
/**
* Thread to desynchronize reading from the device
*/
class RawHIDReadThread : public QThread {
public:
RawHIDReadThread(RawHID *hid);
virtual ~RawHIDReadThread();
/** Return the data read so far without waiting */
int getReadData(char *data, int size);
/** return the bytes buffered */
qint64 getBytesAvailable();
public slots:
void terminate()
{
m_running = false;
}
protected:
void run();
/** QByteArray might not be the most efficient way to implement
a circular buffer but it's good enough and very simple */
QByteArray m_readBuffer;
/** A mutex to protect read buffer */
QMutex m_readBufMtx;
RawHID *m_hid;
pjrc_rawhid *hiddev;
int hidno;
bool m_running;
};
// *********************************************************************************
/**
* This class is nearly the same than RawHIDReadThread but for writing
*/
class RawHIDWriteThread : public QThread {
public:
RawHIDWriteThread(RawHID *hid);
virtual ~RawHIDWriteThread();
/** Add some data to be written without waiting */
int pushDataToWrite(const char *data, int size);
/** Return the number of bytes buffered */
qint64 getBytesToWrite();
public slots:
void terminate()
{
m_running = false;
}
protected:
void run();
/** QByteArray might not be the most efficient way to implement
a circular buffer but it's good enough and very simple */
QByteArray m_writeBuffer;
/** A mutex to protect read buffer */
QMutex m_writeBufMtx;
/** Synchronize task with data arival */
QWaitCondition m_newDataToWrite;
RawHID *m_hid;
pjrc_rawhid *hiddev;
int hidno;
bool m_running;
};
// *********************************************************************************
RawHIDReadThread::RawHIDReadThread(RawHID *hid)
: m_hid(hid),
hiddev(&hid->dev),
hidno(hid->m_deviceNo),
m_running(true)
{
hid->m_startedMutex->lock();
}
RawHIDReadThread::~RawHIDReadThread()
{
m_running = false;
// wait for the thread to terminate
if (wait(10000) == false) {
qDebug() << "Cannot terminate RawHIDReadThread";
}
}
void RawHIDReadThread::run()
{
m_running = m_hid->openDevice();
while (m_running) {
// here we use a temporary buffer so we don't need to lock
// the mutex while we are reading from the device
// Want to read in regular chunks that match the packet size the device
// is using. In this case it is 64 bytes (the interrupt packet limit)
// although it would be nice if the device had a different report to
// configure this
char buffer[READ_SIZE] = { 0 };
int ret = hiddev->receive(hidno, buffer, READ_SIZE, READ_TIMEOUT);
if (ret > 0) { // read some data
QMutexLocker lock(&m_readBufMtx);
// Note: Preprocess the USB packets in this OS independent code
// First byte is report ID, second byte is the number of valid bytes
m_readBuffer.append(&buffer[2], buffer[1]);
emit m_hid->readyRead();
} else if (ret == 0) { // nothing read
} else { // < 0 => error
// TODO! make proper error handling, this only quick hack for unplug freeze
m_running = false;
}
}
m_hid->closeDevice();
}
int RawHIDReadThread::getReadData(char *data, int size)
{
QMutexLocker lock(&m_readBufMtx);
size = qMin(size, m_readBuffer.size());
memcpy(data, m_readBuffer.constData(), size);
m_readBuffer.remove(0, size);
return size;
}
qint64 RawHIDReadThread::getBytesAvailable()
{
QMutexLocker lock(&m_readBufMtx);
return m_readBuffer.size();
}
RawHIDWriteThread::RawHIDWriteThread(RawHID *hid)
: m_hid(hid),
hiddev(&hid->dev),
hidno(hid->m_deviceNo),
m_running(true)
{}
// *********************************************************************************
RawHIDWriteThread::~RawHIDWriteThread()
{
m_running = false;
// wait for the thread to terminate
if (wait(10000) == false) {
qDebug() << "Cannot terminate RawHIDReadThread";
}
}
void RawHIDWriteThread::run()
{
while (m_running) {
char buffer[WRITE_SIZE] = { 0 };
m_writeBufMtx.lock();
int size = qMin(WRITE_SIZE - 2, m_writeBuffer.size());
while (size <= 0) {
// wait on new data to write condition, the timeout
// enable the thread to shutdown properly
m_newDataToWrite.wait(&m_writeBufMtx, 200);
if (!m_running) {
return;
}
size = m_writeBuffer.size();
}
// NOTE: data size is limited to 2 bytes less than the
// usb packet size (64 bytes for interrupt) to make room
// for the reportID and valid data length
size = qMin(WRITE_SIZE - 2, m_writeBuffer.size());
memcpy(&buffer[2], m_writeBuffer.constData(), size);
buffer[1] = size; // valid data length
buffer[0] = 2; // reportID
m_writeBufMtx.unlock();
// must hold lock through the send to know how much was sent
int ret = hiddev->send(hidno, buffer, WRITE_SIZE, WRITE_TIMEOUT);
if (ret > 0) {
// only remove the size actually written to the device
QMutexLocker lock(&m_writeBufMtx);
m_writeBuffer.remove(0, size);
emit m_hid->bytesWritten(ret - 2);
} else if (ret < 0) { // < 0 => error
// TODO! make proper error handling, this only quick hack for unplug freeze
m_running = false;
qDebug() << "Error writing to device";
} else {
qDebug() << "No data written to device ??";
}
}
}
int RawHIDWriteThread::pushDataToWrite(const char *data, int size)
{
QMutexLocker lock(&m_writeBufMtx);
m_writeBuffer.append(data, size);
m_newDataToWrite.wakeOne(); // signal that new data arrived
return size;
}
qint64 RawHIDWriteThread::getBytesToWrite()
{
// QMutexLocker lock(&m_writeBufMtx);
return m_writeBuffer.size();
}
// *********************************************************************************
RawHID::RawHID(const QString &deviceName)
: QIODevice(),
serialNumber(deviceName),
m_deviceNo(-1),
m_readThread(NULL),
m_writeThread(NULL),
m_mutex(NULL)
{
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)));
m_writeThread = new RawHIDWriteThread(this);
// Starting the read thread will lock the m_startexMutex until the
// device is opened (which happens in that thread).
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 (serialNumber == dev.getserial(i)) {
m_deviceNo = i;
} else {
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)
device_open = opened >= 0;
if (opened < 0) {
return false;
}
m_writeThread->start();
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()
{
// If the read thread exists then the device is open
if (m_readThread) {
close();
}
}
void RawHID::onDeviceUnplugged(int num)
{
if (num != m_deviceNo) {
return;
}
// the USB device has been unplugged
close();
}
bool RawHID::open(OpenMode mode)
{
QMutexLocker locker(m_mutex);
if (m_deviceNo < 0) {
return false;
}
QIODevice::open(mode);
Q_ASSERT(m_readThread);
Q_ASSERT(m_writeThread);
if (m_readThread) {
m_readThread->start();
}
if (m_writeThread) {
m_writeThread->start();
}
return true;
}
void RawHID::close()
{
qDebug() << "RawHID::close()";
emit aboutToClose();
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";
}
emit closed();
QIODevice::close();
}
bool RawHID::isSequential() const
{
return true;
}
qint64 RawHID::bytesAvailable() const
{
QMutexLocker locker(m_mutex);
if (!m_readThread) {
return -1;
}
return m_readThread->getBytesAvailable() + QIODevice::bytesAvailable();
}
qint64 RawHID::bytesToWrite() const
{
QMutexLocker locker(m_mutex);
if (!m_writeThread) {
return -1;
}
return m_writeThread->getBytesToWrite() + QIODevice::bytesToWrite();
}
qint64 RawHID::readData(char *data, qint64 maxSize)
{
QMutexLocker locker(m_mutex);
if (!m_readThread || !data) {
return -1;
}
return m_readThread->getReadData(data, maxSize);
}
qint64 RawHID::writeData(const char *data, qint64 maxSize)
{
QMutexLocker locker(m_mutex);
if (!m_writeThread || !data) {
return -1;
}
return m_writeThread->pushDataToWrite(data, maxSize);
}
// *********************************************************************************

View File

@ -1,95 +0,0 @@
/**
******************************************************************************
*
* @file rawhid.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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
*/
#ifndef RAWHID_H
#define RAWHID_H
#include "rawhid_global.h"
#include <QThread>
#include <QIODevice>
#include <QMutex>
#include <QByteArray>
#include "pjrc_rawhid.h"
#include "usbmonitor.h"
// helper classes
class RawHIDReadThread;
class RawHIDWriteThread;
/**
* The actual IO device that will be used to communicate
* with the board.
*/
class RAWHID_EXPORT RawHID : public QIODevice {
Q_OBJECT
friend class RawHIDReadThread;
friend class RawHIDWriteThread;
public:
RawHID();
RawHID(const QString &deviceName);
virtual ~RawHID();
virtual bool open(OpenMode mode);
virtual void close();
virtual bool isSequential() const;
signals:
void closed();
public slots:
void onDeviceUnplugged(int num);
protected:
virtual qint64 readData(char *data, qint64 maxSize);
virtual qint64 writeData(const char *data, qint64 maxSize);
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;
pjrc_rawhid dev;
bool device_open;
RawHIDReadThread *m_readThread;
RawHIDWriteThread *m_writeThread;
QMutex *m_mutex;
QMutex *m_startedMutex;
};
#endif // RAWHID_H

View File

@ -1,3 +0,0 @@
include(rawhid_dependencies.pri)
LIBS *= -l$$qtLibraryName(RawHID)

View File

@ -1,52 +0,0 @@
TEMPLATE = lib
TARGET = RawHID
include(../../openpilotgcsplugin.pri)
include(rawhid_dependencies.pri)
HEADERS += rawhid_global.h \
rawhidplugin.h \
rawhid.h \
pjrc_rawhid.h \
rawhid_const.h \
usbmonitor.h \
usbsignalfilter.h
SOURCES += rawhidplugin.cpp \
rawhid.cpp \
usbsignalfilter.cpp
FORMS +=
RESOURCES +=
DEFINES += RAWHID_LIBRARY
OTHER_FILES += RawHID.pluginspec
# Platform Specific USB HID Stuff
win32 {
SOURCES += pjrc_rawhid_win.cpp \
usbmonitor_win.cpp
LIBS += -lhid \
-lsetupapi
}
macx {
SOURCES += pjrc_rawhid_mac.cpp \
usbmonitor_mac.cpp
SDK = /Developer/SDKs/MacOSX10.5.sdk
ARCH = -mmacosx-version-min=10.5 \
-arch \
ppc \
-arch \
i386
LIBS += $(ARCH) \
-Wl,-syslibroot,$(SDK) \
-framework \
IOKit \
-framework \
CoreFoundation
}
linux-g++ {
SOURCES += pjrc_rawhid_unix.cpp \
usbmonitor_linux.cpp
LIBS += -lusb -ludev
}
linux-g++-64 {
SOURCES += pjrc_rawhid_unix.cpp \
usbmonitor_linux.cpp
LIBS += -lusb -ludev
}

View File

@ -1,41 +0,0 @@
/**
******************************************************************************
*
* @file rawhid_const.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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
*/
#ifndef RAWHID_CONST_H
#define RAWHID_CONST_H
static const int USB_MAX_DEVICES = 10;
static const int USB_VID = 0x20A0;
static const int USB_PID = 0x4117;
static const int USB_USAGE_PAGE = 0xFF9C;
static const int USB_USAGE = 0x0001;
static const int USB_DEV_SERIAL_LEN = 24;
#endif // RAWHID_CONST_H

View File

@ -1 +0,0 @@
include(../../plugins/coreplugin/coreplugin.pri)

View File

@ -1,39 +0,0 @@
/**
******************************************************************************
*
* @file rawhid_global.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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
*/
#ifndef RAWHID_GLOBAL_H
#define RAWHID_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(RAWHID_LIBRARY)
# define RAWHID_EXPORT Q_DECL_EXPORT
#else
# define RAWHID_EXPORT Q_DECL_IMPORT
#endif
#endif // RAWHID_GLOBAL_H

View File

@ -1,186 +0,0 @@
/**
******************************************************************************
*
* @file rawhidplugin.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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 "rawhidplugin.h"
#include "rawhid.h"
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QtPlugin>
#include <QtCore/QMutexLocker>
#include "pjrc_rawhid.h"
#include "rawhid_const.h"
// **********************************************************************
RawHIDConnection::RawHIDConnection()
{
// added by andrew
RawHidHandle = NULL;
enablePolling = true;
m_usbMonitor = USBMonitor::instance();
connect(m_usbMonitor, SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(onDeviceConnected()));
connect(m_usbMonitor, SIGNAL(deviceRemoved(USBPortInfo)), this, SLOT(onDeviceDisconnected()));
}
RawHIDConnection::~RawHIDConnection()
{
if (RawHidHandle) {
if (RawHidHandle->isOpen()) {
RawHidHandle->close();
}
}
}
/**
The USB monitor tells us a new device appeared
*/
void RawHIDConnection::onDeviceConnected()
{
emit availableDevChanged(this);
}
/**
The USB monitor tells us a device disappeard
*/
void RawHIDConnection::onDeviceDisconnected()
{
qDebug() << "onDeviceDisconnected()";
if (enablePolling) {
emit availableDevChanged(this);
}
}
/**
Returns the list of all currently available devices
*/
QList < Core::IConnection::device> RawHIDConnection::availableDevices()
{
QList < Core::IConnection::device> devices;
QList<USBPortInfo> portsList = m_usbMonitor->availableDevices(USBMonitor::idVendor_OpenPilot, -1, -1, USBMonitor::Running);
// We currently list devices by their serial number
device dev;
foreach(USBPortInfo prt, portsList) {
dev.name = prt.serialNumber;
dev.displayName = prt.product;
devices.append(dev);
}
return devices;
}
QIODevice *RawHIDConnection::openDevice(const QString &deviceName)
{
// added by andrew
if (RawHidHandle) {
closeDevice(deviceName);
}
// end added by andrew
// return new RawHID(deviceName);
RawHidHandle = new RawHID(deviceName);
return RawHidHandle;
}
void RawHIDConnection::closeDevice(const QString &deviceName)
{
Q_UNUSED(deviceName);
if (RawHidHandle) {
qDebug() << "Closing the device here";
RawHidHandle->close();
delete RawHidHandle;
RawHidHandle = NULL;
}
}
QString RawHIDConnection::connectionName()
{
return QString("Raw HID USB");
}
QString RawHIDConnection::shortName()
{
return QString("USB");
}
/**
Tells the Raw HID plugin to stop polling for USB devices
*/
void RawHIDConnection::suspendPolling()
{
enablePolling = false;
}
/**
Tells the Raw HID plugin to resume polling for USB devices
*/
void RawHIDConnection::resumePolling()
{
enablePolling = true;
}
// **********************************************************************
RawHIDPlugin::RawHIDPlugin()
{
hidConnection = NULL; // Pip
}
RawHIDPlugin::~RawHIDPlugin()
{
m_usbMonitor->quit();
m_usbMonitor->wait(500);
}
void RawHIDPlugin::extensionsInitialized()
{
hidConnection = new RawHIDConnection();
addAutoReleasedObject(hidConnection);
// temp for test
// addAutoReleasedObject(new RawHIDTestThread);
}
bool RawHIDPlugin::initialize(const QStringList & arguments, QString *errorString)
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
// We have to create the USB Monitor here:
m_usbMonitor = new USBMonitor(this);
return true;
}
Q_EXPORT_PLUGIN(RawHIDPlugin)
// **********************************************************************

View File

@ -1,99 +0,0 @@
/**
******************************************************************************
*
* @file rawhid.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Impliments a HID USB connection to the flight hardware as a QIODevice
*****************************************************************************/
/*
* 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
*/
#ifndef RAWHIDPLUGIN_H
#define RAWHIDPLUGIN_H
#include "rawhid_global.h"
#include "rawhid.h"
#include "usbmonitor.h"
#include "coreplugin/iconnection.h"
#include <extensionsystem/iplugin.h>
#include <QtCore/QMutex>
#include <QtCore/QThread>
class IConnection;
class RawHIDConnection;
/**
* Define a connection via the IConnection interface
* Plugin will add a instance of this class to the pool,
* so the connection manager can use it.
*/
class RAWHID_EXPORT RawHIDConnection
: public Core::IConnection {
Q_OBJECT
public:
RawHIDConnection();
virtual ~RawHIDConnection();
virtual QList < Core::IConnection::device> availableDevices();
virtual QIODevice *openDevice(const QString &deviceName);
virtual void closeDevice(const QString &deviceName);
virtual QString connectionName();
virtual QString shortName();
virtual void suspendPolling();
virtual void resumePolling();
bool deviceOpened()
{
return RawHidHandle != NULL;
} // Pip
protected slots:
void onDeviceConnected();
void onDeviceDisconnected();
private:
RawHID *RawHidHandle;
bool enablePolling;
protected:
QMutex m_enumMutex;
USBMonitor *m_usbMonitor;
bool m_deviceOpened;
};
class RAWHID_EXPORT RawHIDPlugin
: public ExtensionSystem::IPlugin {
Q_OBJECT
public:
RawHIDPlugin();
~RawHIDPlugin();
virtual bool initialize(const QStringList &arguments, QString *error_message);
virtual void extensionsInitialized();
private:
RawHIDConnection *hidConnection;
USBMonitor *m_usbMonitor;
};
#endif // RAWHIDPLUGIN_H

View File

@ -1,202 +0,0 @@
/**
******************************************************************************
*
* @file usbmonitor.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup RawHIDPlugin Raw HID Plugin
* @{
* @brief Monitors the USB bus for devince insertion/removal
*****************************************************************************/
/*
* 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
*/
#ifndef USBMONITOR_H
#define USBMONITOR_H
#include "rawhid_global.h"
#include <QThread>
#include <QMutex>
// Depending on the OS, we'll need different things:
#if defined(Q_OS_MAC)
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDLib.h>
#elif defined(Q_OS_UNIX)
#include <libudev.h>
#include <QSocketNotifier>
#elif defined(Q_OS_WIN32)
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0500
#endif
#ifndef WINVER
#define WINVER 0x0500
#endif
#include <windows.h>
#include <dbt.h>
#include <setupapi.h>
#include <ddk/hidsdi.h>
#include <ddk/hidclass.h>
#endif // if defined(Q_OS_MAC)
#ifdef Q_OS_WIN
#ifdef QT_GUI_LIB
#include <QWidget>
class USBMonitor;
class USBRegistrationWidget : public QWidget {
Q_OBJECT
public:
USBRegistrationWidget(USBMonitor *qese)
{
this->qese = qese;
}
~USBRegistrationWidget() {}
protected:
USBMonitor *qese;
bool winEvent(MSG *message, long *result);
};
#endif
#endif
struct USBPortInfo {
// QString friendName; ///< Friendly name.
// QString physName;
// QString enumName; ///< It seems its the only one with meaning
QString serialNumber; // As a string as it can be anything, really...
QString manufacturer;
QString product;
#if defined(Q_OS_WIN32)
QString devicePath; // only has meaning on windows
#elif defined(Q_OS_MAC)
IOHIDDeviceRef dev_handle;
#endif
int UsagePage;
int Usage;
int vendorID; ///< Vendor ID.
int productID; ///< Product ID
int bcdDevice;
};
/**
* A monitoring thread which will wait for device events.
*/
class RAWHID_EXPORT USBMonitor : public QThread {
Q_OBJECT
public:
enum RunState {
Bootloader = 0x01,
Running = 0x02
};
enum USBConstants {
idVendor_OpenPilot = 0x20a0,
idProduct_OpenPilot = 0x415a,
idProduct_CopterControl = 0x415b,
idProduct_PipXtreme = 0x415c
};
static USBMonitor *instance();
USBMonitor(QObject *parent = 0);
~USBMonitor();
QList<USBPortInfo> availableDevices();
QList<USBPortInfo> availableDevices(int vid, int pid, int boardModel, int runState);
#if defined(Q_OS_WIN32)
LRESULT onDeviceChangeWin(WPARAM wParam, LPARAM lParam);
#endif
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 USBPortInfo & 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 USBPortInfo & info);
private slots:
/**
Callback available for whenever the system that is put in place gets
an event
*/
void deviceEventReceived();
private:
// ! Mutex for modifying the list of available devices
QMutex *listMutex;
// ! List of known devices maintained by callbacks
QList<USBPortInfo> knowndevices;
Q_DISABLE_COPY(USBMonitor)
static USBMonitor * m_instance;
// Depending on the OS, we'll need different things:
#if defined(Q_OS_MAC)
static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev);
static void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev);
void addDevice(USBPortInfo info);
void removeDevice(IOHIDDeviceRef dev);
IOHIDManagerRef hid_manager;
#elif defined(Q_OS_UNIX)
struct udev *context;
struct udev_monitor *monitor;
QSocketNotifier *monitorNotifier;
USBPortInfo makePortInfo(struct udev_device *dev);
#elif defined(Q_OS_WIN32)
GUID guid_hid;
void setUpNotifications();
/*!
* 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);
static int infoFromHandle(const GUID & guid, USBPortInfo & info, HDEVINFO & devInfo, DWORD & index);
static void enumerateDevicesWin(const GUID & guidDev, QList<USBPortInfo> *infoList);
bool matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam);
#ifdef QT_GUI_LIB
USBRegistrationWidget *notificationWidget;
#endif
#endif // if defined(Q_OS_MAC)
};
#endif // USBMONITOR_H

View File

@ -1,201 +0,0 @@
/**
******************************************************************************
*
* @file usbmonitor_linux.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 Linux using libudev
*****************************************************************************/
/*
* 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
*/
/*
Need help wihth udev ?
There is a great tuturial at: http://www.signal11.us/oss/udev/
*/
#include "usbmonitor.h"
#include <QDebug>
#define printf qDebug
void printPortInfo(struct udev_device *dev)
{
printf(" Node: %s", udev_device_get_devnode(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/bcdDevice : %s %s %s",
udev_device_get_sysattr_value(dev, "idVendor"),
udev_device_get_sysattr_value(dev, "idProduct"),
udev_device_get_sysattr_value(dev, "bcdDevice"));
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"));
}
void USBMonitor::deviceEventReceived()
{
qDebug() << "Device event";
struct udev_device *dev;
dev = udev_monitor_receive_device(this->monitor);
if (dev) {
printf("------- Got Device Event");
QString action = QString(udev_device_get_action(dev));
QString devtype = QString(udev_device_get_devtype(dev));
if (action == "add" && devtype == "usb_device") {
printPortInfo(dev);
emit deviceDiscovered(makePortInfo(dev));
} else if (action == "remove" && devtype == "usb_device") {
printPortInfo(dev);
emit deviceRemoved(makePortInfo(dev));
}
udev_device_unref(dev);
} else {
printf("No Device from receive_device(). An error occured.");
}
}
USBMonitor *USBMonitor::instance()
{
return m_instance;
}
USBMonitor *USBMonitor::m_instance = 0;
/**
Initialize the udev monitor here
*/
USBMonitor::USBMonitor(QObject *parent) : QThread(parent)
{
m_instance = this;
this->context = udev_new();
this->monitor = udev_monitor_new_from_netlink(this->context, "udev");
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);
connect(this->monitorNotifier, SIGNAL(activated(int)),
this, SLOT(deviceEventReceived()));
qDebug() << "Starting the Udev client";
start(); // Start the thread event loop so that the socketnotifier works
}
USBMonitor::~USBMonitor()
{
quit();
}
/**
Returns a list of all currently available devices
*/
QList<USBPortInfo> USBMonitor::availableDevices()
{
QList<USBPortInfo> devicesList;
struct udev_list_entry *devices, *dev_list_entry;
struct udev_enumerate *enumerate;
struct udev_device *dev;
enumerate = udev_enumerate_new(this->context);
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:
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path;
/* Get the filename of the /sys entry for the device
and create a udev_device object (dev) representing it */
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(this->context, path);
if (QString(udev_device_get_devtype(dev)) == "usb_device") {
devicesList.append(makePortInfo(dev));
}
udev_device_unref(dev);
}
/* free the enumerator object */
udev_enumerate_unref(enumerate);
return devicesList;
}
/**
Be a bit more picky and ask only for a specific type of device:
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;
}
USBPortInfo USBMonitor::makePortInfo(struct udev_device *dev)
{
USBPortInfo prtInfo;
//////////
// Debug info
//////////
#ifdef DEBUG
printPortInfo(dev);
#endif
bool ok;
prtInfo.vendorID = QString(udev_device_get_sysattr_value(dev, "idVendor")).toInt(&ok, 16);
prtInfo.productID = QString(udev_device_get_sysattr_value(dev, "idProduct")).toInt(&ok, 16);
prtInfo.serialNumber = QString(udev_device_get_sysattr_value(dev, "serial"));
prtInfo.manufacturer = QString(udev_device_get_sysattr_value(dev, "manufacturer"));
prtInfo.product = QString(udev_device_get_sysattr_value(dev, "product"));
// prtInfo.UsagePage = QString(udev_device_get_sysattr_value(dev,""));
// prtInfo.Usage = QString(udev_device_get_sysattr_value(dev,""));
prtInfo.bcdDevice = QString(udev_device_get_sysattr_value(dev, "bcdDevice")).toInt(&ok, 16);
return prtInfo;
}

View File

@ -1,243 +0,0 @@
/**
******************************************************************************
*
* @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;
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)
{
Q_UNUSED(context);
Q_UNUSED(r);
Q_UNUSED(hid_mgr);
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)
{
Q_UNUSED(context);
Q_UNUSED(r);
Q_UNUSED(hid_mgr);
bool got_properties = true;
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;
}

View File

@ -1,376 +0,0 @@
/**
******************************************************************************
*
* @file usbmonitor_win.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 Windows using system API
*****************************************************************************/
/*
* 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 <QMetaType>
#include <QString>
#include <initguid.h>
#include <QEventLoop>
#include <QTimer>
#include "usbmonitor.h"
#include <QDebug>
#define printf qDebug
void USBMonitor::deviceEventReceived()
{
qDebug() << "Device event";
// Dispatch and emit the signals here...
}
USBMonitor *USBMonitor::instance()
{
return m_instance;
}
USBMonitor *USBMonitor::m_instance = 0;
USBMonitor::USBMonitor(QObject *parent) : QThread(parent)
{
HidD_GetHidGuid(&guid_hid);
if (!QMetaType::isRegistered(QMetaType::type("USBPortInfo"))) {
qRegisterMetaType<USBPortInfo>("USBPortInfo");
}
#if (defined QT_GUI_LIB)
notificationWidget = 0;
#endif // Q_OS_WIN
setUpNotifications();
m_instance = this;
}
USBMonitor::~USBMonitor()
{
#if (defined QT_GUI_LIB)
if (notificationWidget) {
delete notificationWidget;
}
#endif
quit();
}
/**
Be a bit more picky and ask only for a specific type of device:
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();
qDebug() << "USBMonitor::availableDevices list off all ports:";
qDebug() << "USBMonitor::availableDevices total ports:" << allPorts.length();
foreach(USBPortInfo info, allPorts) {
qDebug() << "----------";
qDebug() << "bcdDevice:" << info.bcdDevice;
qDebug() << "devicePath:" << info.devicePath;
qDebug() << "product:" << info.product;
}
qDebug() << "END OF LIST";
QList<USBPortInfo> thePortsWeWant;
qDebug() << "USBMonitor::availableDevices bcdLSB=" << bcdDeviceLSB;
foreach(USBPortInfo port, allPorts) {
qDebug() << "USBMonitorWin:Port VID=" << port.vendorID << "PID=" << port.productID << "bcddevice=" << port.bcdDevice;
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);
}
}
qDebug() << "USBMonitor::availableDevices list off matching ports vid pid bcdMSD bcdLSD:" << vid << pid << bcdDeviceMSB << bcdDeviceLSB;
qDebug() << "USBMonitor::availableDevices total matching ports:" << thePortsWeWant.length();
foreach(USBPortInfo info, thePortsWeWant) {
qDebug() << "----------";
qDebug() << "bcdDevice:" << info.bcdDevice;
qDebug() << "devicePath:" << info.devicePath;
qDebug() << "product:" << info.product;
}
qDebug() << "END OF LIST";
return thePortsWeWant;
}
// see http://msdn.microsoft.com/en-us/library/ms791134.aspx for list of GUID classes
/*#ifndef GUID_DEVCLASS_PORTS
DEFINE_GUID(GUID_DEVCLASS_PORTS, //0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
//0x745a17a0, 0x74d3, 0x11d0, 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda);
0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
#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*/
void USBMonitor::setUpNotifications()
{
#ifdef QT_GUI_LIB
if (notificationWidget) {
return;
}
notificationWidget = new USBRegistrationWidget(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_hid, 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(USBPortInfo port, availableDevices())
emit deviceDiscovered(port);
#else
qWarning("GUI not enabled - can't register for device notifications.");
#endif // QT_GUI_LIB
}
LRESULT USBMonitor::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_hid, wParam);
}
}
return 0;
}
#ifdef QT_GUI_LIB
bool USBRegistrationWidget::winEvent(MSG *message, long *result)
{
if (message->message == WM_DEVICECHANGE) {
qese->onDeviceChangeWin(message->wParam, message->lParam);
*result = 1;
return true;
}
return false;
}
#endif
bool USBMonitor::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam)
{
qDebug() << "USB_MONITOR matchAndDispatchChangedDevice deviceID=" << deviceID;
bool rv = false;
DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES;
HDEVINFO devInfo;
if ((devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, dwFlag | DIGCF_DEVICEINTERFACE)) != INVALID_HANDLE_VALUE) {
SP_DEVINFO_DATA spDevInfoData;
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD 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
USBPortInfo info;
info.devicePath = deviceID;
if (wParam == DBT_DEVICEARRIVAL) {
qDebug() << "USB_MONITOR INSERTION";
if (infoFromHandle(guid, info, devInfo, i) != 1) {
qDebug() << "USB_MONITOR infoFromHandle failed on matchAndDispatchChangedDevice";
break;
}
bool m_break = false;
foreach(USBPortInfo m_info, knowndevices) {
if (m_info.serialNumber == info.serialNumber && m_info.productID == info.productID && m_info.bcdDevice == info.bcdDevice && m_info.devicePath == info.devicePath) {
qDebug() << "USB_MONITOR device already present don't emit signal";
m_break = true;
}
}
if (m_break) {
break;
}
if (info.bcdDevice == 0 || info.product.isEmpty()) {
qDebug() << "USB_MONITOR empty information on device not emiting signal";
break;
}
knowndevices.append(info);
qDebug() << "USB_MONITOR emit device discovered on device:" << info.product << info.bcdDevice;
emit deviceDiscovered(info);
break;
} else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
bool found = false;
for (int x = 0; x < knowndevices.count(); ++x) {
if (knowndevices[x].devicePath == deviceID) {
USBPortInfo temp = knowndevices.at(x);
knowndevices.removeAt(x);
qDebug() << "USB_MONITOR emit device removed on device:" << temp.product << temp.bcdDevice;
emit deviceRemoved(temp);
found = true;
break;
}
}
if (!found) {
qDebug() << "USB_MONITOR emit device removed on unknown device";
emit deviceRemoved(info);
}
}
break;
}
}
SetupDiDestroyDeviceInfoList(devInfo);
}
return rv;
}
QString USBMonitor::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;
}
/**
Returns a list of all currently available devices
*/
QList<USBPortInfo> USBMonitor::availableDevices()
{
QList<USBPortInfo> ports;
enumerateDevicesWin(guid_hid, &ports);
// qDebug()<<"USBMonitorWin availabledevices="<<ports.count();
return ports;
}
void USBMonitor::enumerateDevicesWin(const GUID & guid, QList<USBPortInfo> *infoList)
{
HDEVINFO devInfo;
USBPortInfo info;
// qDebug()<<"enumerateDevicesWin1";
if ((devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)) != INVALID_HANDLE_VALUE) {
// qDebug()<<"enumerateDevicesWin2";
SP_DEVINFO_DATA devInfoData;
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
int r = infoFromHandle(guid, info, devInfo, i);
if (r == 1) {
infoList->append(info);
} else if (r == 0) {
break;
}
}
SetupDiDestroyDeviceInfoList(devInfo);
}
}
int USBMonitor::infoFromHandle(const GUID & guid, USBPortInfo & info, HDEVINFO & devInfo, DWORD & index)
{
// qDebug()<<"index0="<<index;
bool ret;
HANDLE h;
SP_DEVICE_INTERFACE_DATA iface;
SP_DEVICE_INTERFACE_DETAIL_DATA *details;
DWORD reqd_size;
HIDD_ATTRIBUTES attrib;
PHIDP_PREPARSED_DATA hid_data;
HIDP_CAPS capabilities;
iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
ret = SetupDiEnumDeviceInterfaces(devInfo, NULL, &guid, index, &iface);
if (!ret) {
return 0;
}
// qDebug()<<"index1="<<index;
SetupDiGetInterfaceDeviceDetail(devInfo, &iface, NULL, 0, &reqd_size, NULL);
details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size);
if (details == NULL) {
return 2;
}
// qDebug()<<"index2="<<index;
memset(details, 0, reqd_size);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ret = SetupDiGetDeviceInterfaceDetail(devInfo, &iface, details, reqd_size, NULL, NULL);
if (!ret) {
free(details);
return 2;
}
// qDebug()<<"index3="<<index;
h = CreateFile(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
// I get ERROR_ACCESS_DENIED with most/all my input devices (mice/trackballs/tablet).
// Let's not log it :)
if (err == ERROR_ACCESS_DENIED) {
free(details);
return 2;
}
qDebug() << "Problem opening handle, path: " << QString().fromWCharArray(details->DevicePath);
free(details);
return 2;
}
// qDebug()<<"index4="<<index;
free(details);
// qDebug()<<"DETAILS???"<<QString().fromWCharArray(details->DevicePath).toUpper().replace("#", "\\");
attrib.Size = sizeof(HIDD_ATTRIBUTES);
ret = HidD_GetAttributes(h, &attrib);
info.vendorID = attrib.VendorID;
info.productID = attrib.ProductID;
info.bcdDevice = attrib.VersionNumber;
if (!ret || !HidD_GetPreparsedData(h, &hid_data)) {
CloseHandle(h);
return 2;
}
// qDebug()<<"index5="<<index;
if (!HidP_GetCaps(hid_data, &capabilities)) {
HidD_FreePreparsedData(hid_data);
CloseHandle(h);
return 2;
}
// qDebug()<<"index6="<<index;
info.UsagePage = capabilities.UsagePage;
info.Usage = capabilities.Usage;
HidD_FreePreparsedData(hid_data);
char temp[126];
HidD_GetSerialNumberString(h, temp, sizeof(temp));
info.serialNumber = QString().fromUtf16((ushort *)temp, -1);
HidD_GetManufacturerString(h, temp, sizeof(temp));
info.manufacturer = QString().fromUtf16((ushort *)temp, -1);
HidD_GetProductString(h, temp, sizeof(temp));
info.product = QString().fromUtf16((ushort *)temp, -1);
// qDebug()<<"index="<<index<<"ProductID="<<info.product;
CloseHandle(h);
h = NULL;
return 1;
}

View File

@ -1,19 +0,0 @@
#include "usbsignalfilter.h"
#include <QDebug>
void USBSignalFilter::m_deviceDiscovered(USBPortInfo port)
{
if ((port.vendorID == m_vid || m_vid == -1) && (port.productID == m_pid || m_pid == -1) && ((port.bcdDevice >> 8) == m_boardModel || m_boardModel == -1) &&
((port.bcdDevice & 0x00ff) == m_runState || m_runState == -1)) {
qDebug() << "USBSignalFilter emit device discovered";
emit deviceDiscovered();
}
}
USBSignalFilter::USBSignalFilter(int vid, int pid, int boardModel, int runState) :
m_vid(vid),
m_pid(pid),
m_boardModel(boardModel),
m_runState(runState)
{
connect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(m_deviceDiscovered(USBPortInfo)));
}

View File

@ -1,20 +0,0 @@
#ifndef USBSIGNALFILTER_H
#define USBSIGNALFILTER_H
#include <QObject>
#include "usbmonitor.h"
class RAWHID_EXPORT USBSignalFilter : public QObject {
Q_OBJECT
private:
int m_vid;
int m_pid;
int m_boardModel;
int m_runState;
signals:
void deviceDiscovered();
private slots:
void m_deviceDiscovered(USBPortInfo port);
public:
USBSignalFilter(int vid, int pid, int boardModel, int runState);
};
#endif // USBSIGNALFILTER_H

View File

@ -3,7 +3,7 @@
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415a", MODE="0664", GROUP="plugdev"
# OpenPilot coptercontrol flight control board
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415b", MODE="0664", GROUP="plugdev"
# OpenPilot Pipx radio modem board
# OpenPilot OPLink Mini radio modem board
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415c", MODE="0664", GROUP="plugdev"
# unprogrammed openpilot flight control board
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5750", MODE="0664", GROUP="plugdev"

View File

@ -4,7 +4,7 @@
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415a", MODE="0664", GROUP="plugdev"
# OpenPilot CopterControl flight control board
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415b", MODE="0664", GROUP="plugdev"
# OpenPilot Pipx radio modem board
# OpenPilot OPlink Mini radio modem board
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415c", MODE="0664", GROUP="plugdev"
# OpenPilot CopterControl3D flight control board
SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415d", MODE="0664", GROUP="plugdev"