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:
commit
50162333d8
@ -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:
|
||||
|
@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@ -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] = {
|
||||
|
@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@ -116,7 +116,7 @@ public:
|
||||
idVendor_OpenPilot = 0x20a0,
|
||||
idProduct_OpenPilot = 0x415a,
|
||||
idProduct_CopterControl = 0x415b,
|
||||
idProduct_PipXtreme = 0x415c
|
||||
idProduct_OPLinkMini = 0x415c
|
||||
};
|
||||
|
||||
static USBMonitor *instance();
|
||||
|
@ -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>
|
@ -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
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
include(rawhid_dependencies.pri)
|
||||
|
||||
LIBS *= -l$$qtLibraryName(RawHID)
|
@ -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
|
||||
}
|
@ -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
|
@ -1 +0,0 @@
|
||||
include(../../plugins/coreplugin/coreplugin.pri)
|
@ -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
|
@ -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)
|
||||
|
||||
// **********************************************************************
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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)));
|
||||
}
|
@ -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
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user