summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKari Oikarinen <kari.oikarinen@qt.io>2016-08-29 12:10:11 +0300
committerKari Oikarinen <kari.oikarinen@qt.io>2016-10-18 12:36:31 +0000
commit1a8ff526eb750c6629c03c694c07be8d0bebffe2 (patch)
tree3a9d343562132413bb652d8a8a484d37a8a50840
parentc8cda60d49adb562405794ab5ac496c2fd01e1e3 (diff)
Handle multiple USB devices
Add a new qdb subcommand "devices". It lists the USB devices that are available and have a QDB interface. Their serial numbers are retrieved from the USB interface description. All the other commands now use --device option to decide which device to connect to. libusb_context is managed in a separate singleton, because managing its lifetime between the DeviceManager and UsbConnection would be awkward otherwise. The library-wide initialization is anyway meant to happen just once and the deinitialization just before quitting the executable. Task-number: QTBUG-54405 Change-Id: I8dd4f759e2e0906e0b9d121eb9f1221ee4de55ca Reviewed-by: Samuli Piippo <samuli.piippo@qt.io>
-rw-r--r--client/client.pro4
-rw-r--r--client/main.cpp83
-rw-r--r--client/networkmanagercontrol.cpp5
-rw-r--r--libqdb/libqdb.pro9
-rw-r--r--libqdb/protocol/protocol.h2
-rw-r--r--libqdb/usb/devicemanagement.cpp136
-rw-r--r--libqdb/usb/devicemanagement.h30
-rw-r--r--libqdb/usb/libusbcontext.cpp51
-rw-r--r--libqdb/usb/usbcommon.h37
-rw-r--r--libqdb/usb/usbconnection.cpp94
-rw-r--r--libqdb/usb/usbconnection.h11
-rw-r--r--libqdb/usb/usbdevice.h60
-rw-r--r--tests/servicetest.cpp3
-rw-r--r--tests/streamtest.cpp5
14 files changed, 415 insertions, 115 deletions
diff --git a/client/client.pro b/client/client.pro
index 3ea5839..0bae2f4 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -17,7 +17,7 @@ HEADERS += \
handshakeservice.h \
networkmanagercontrol.h \
processservice.h \
- service.h
+ service.h \
SOURCES += \
connection.cpp \
@@ -28,7 +28,7 @@ SOURCES += \
main.cpp \
networkmanagercontrol.cpp \
processservice.cpp \
- service.cpp
+ service.cpp \
INCLUDEPATH += $$PWD/../libqdb
diff --git a/client/main.cpp b/client/main.cpp
index cbef27c..91ab3e6 100644
--- a/client/main.cpp
+++ b/client/main.cpp
@@ -18,6 +18,7 @@
** $QT_END_LICENSE$
**
******************************************************************************/
+#include "../libqdb/usb/devicemanagement.h"
#include "../libqdb/usb/usbconnection.h"
#include "../libqdb/protocol/qdbtransport.h"
#include "connection.h"
@@ -32,9 +33,12 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qregularexpression.h>
#include <QtCore/qtimer.h>
#include <QtDBus/QDBusObjectPath>
+#include <iostream>
+
void setupFilePullService(Connection *connection, const QString &sourcePath, const QString &sinkPath)
{
auto *service = new FilePullService{connection};
@@ -43,11 +47,11 @@ void setupFilePullService(Connection *connection, const QString &sourcePath, con
service, &QObject::deleteLater);
QObject::connect(service, &FilePullService::pulled,
[]() {
- qDebug() << "File pull finished.";
+ std::cout << "File pull finished.\n";
QCoreApplication::quit();
});
QObject::connect(service, &FilePullService::error, []() {
- qDebug() << "Error while pulling file.";
+ std::cerr << "Error while pulling file.\n";
QCoreApplication::exit(1);
});
QObject::connect(service, &Service::initialized, [=]() {
@@ -65,11 +69,11 @@ void setupFilePushService(Connection *connection, const QString &sourcePath, con
service, &QObject::deleteLater);
QObject::connect(service, &FilePushService::pushed,
[]() {
- qDebug() << "File transfer finished.";
+ std::cout << "File transfer finished.\n";
QCoreApplication::quit();
});
QObject::connect(service, &FilePushService::error, []() {
- qDebug() << "Error while pushing file.";
+ std::cerr << "Error while pushing file.\n";
QCoreApplication::exit(1);
});
QObject::connect(service, &Service::initialized, [=]() {
@@ -87,18 +91,21 @@ void setupProcessService(Connection *connection, const QString &processName, con
service, &QObject::deleteLater);
QObject::connect(service, &ProcessService::executed,
[](int exitCode, QProcess::ExitStatus exitStatus, QString output) {
- qDebug() << "Process run, exit code:" << exitCode << exitStatus << output;
+ std::printf("Process run, exit code %d (%s):\n%s",
+ exitCode,
+ exitStatus == QProcess::NormalExit ? "NormalExit" : "CrashExit",
+ qUtf8Printable(output));
QTimer::singleShot(1, []() { QCoreApplication::quit(); });
});
QObject::connect(service, &ProcessService::executionError, [](QProcess::ProcessError error) {
- qDebug() << "Process not run, error:" << error;
+ std::cerr << "Process not run, error: " << error << std::endl;
QTimer::singleShot(1, []() {QCoreApplication::exit(1); });
});
QObject::connect(service, &ProcessService::started, []() {
- qDebug() << "Process started";
+ std::cout << "Process started.\n";
});
QObject::connect(service, &ProcessService::readyRead, [=]() {
- qDebug() << "Process output:" << service->read();
+ std::cout << "Process output: " << qUtf8Printable(service->read()) << std::endl;
});
QObject::connect(service, &Service::initialized, [=]() {
service->execute(processName, arguments);
@@ -176,11 +183,12 @@ int main(int argc, char *argv[])
QCommandLineParser parser;
parser.addHelpOption();
- parser.addOption({{"d","debug-transport"}, "Print each message that is sent."});
+ parser.addOption({"debug-transport", "Print each message that is sent."});
parser.addOption({"debug-connection", "Show enqueued messages"});
+ parser.addOption({{"d", "device"}, "Run the command on <device>. Device is specified with a substring of the device serial number.", "device"});
parser.addPositionalArgument("command",
"Subcommand of qdb to run. Possible commands are: "
- "run, push, pull");
+ "run, push, pull, devices, handshake, network");
parser.process(app);
QString filterRules;
@@ -190,9 +198,53 @@ int main(int argc, char *argv[])
filterRules.append("connection=false\n");
QLoggingCategory::setFilterRules(filterRules);
- Connection connection{new QdbTransport{new UsbConnection{}}};
+ const QStringList arguments = parser.positionalArguments();
+ if (arguments.size() < 1)
+ parser.showHelp(1);
+ const QString command = arguments[0];
+
+ const auto devices = listUsbDevices();
+ if (devices.empty()) {
+ std::cerr << "No QDB devices found.\n";
+ return 1;
+ }
+
+ if (command == "devices") {
+ std::cout << "USB devices:\n";
+ for (const auto &device : devices) {
+ std::cout << " " << qUtf8Printable(device.serial) << std::endl;
+ }
+ return 0;
+ }
+
+ std::vector<UsbDevice> matchingDevices;
+ if (parser.isSet("device")) {
+ QRegularExpression regexp{parser.value("device")};
+
+ std::copy_if(devices.begin(), devices.end(), std::back_inserter(matchingDevices), [&](const UsbDevice &device) {
+ return regexp.match(device.serial).hasMatch();
+ });
+ } else {
+ matchingDevices = devices;
+ }
+
+ if (matchingDevices.size() == 0) {
+ std::cerr << "No device matching \"" << qUtf8Printable(parser.value("device")) << "\" found.\n";
+ return 1;
+ }
+ if (matchingDevices.size() > 1) {
+ std::cerr << "Device \"" << qUtf8Printable(parser.value("device"))
+ << "\" could mean any of the following devices:\n";
+ for (const auto &device : devices)
+ std::cout << " " << qUtf8Printable(device.serial) << std::endl;
+ return 1;
+ }
+ UsbDevice targetDevice = matchingDevices[0];
+ qDebug() << "Executing commands for" << targetDevice.serial;
+
+ Connection connection{new QdbTransport{new UsbConnection{targetDevice}}};
if (!connection.initialize()) {
- qDebug() << "could not initialize Connection";
+ std::cerr << "Could not initialize connection to \"" << qUtf8Printable(targetDevice.serial) << "\".\n";
return 1;
}
@@ -204,11 +256,6 @@ int main(int argc, char *argv[])
connection.connect();
qDebug() << "initialized connection";
- QStringList arguments = parser.positionalArguments();
- if (arguments.size() < 1)
- return 0;
-
- QString command = arguments[0];
if (command == "run") {
Q_ASSERT(arguments.size() >= 2);
setupProcessService(&connection, arguments[1], arguments.mid(2));
@@ -230,7 +277,7 @@ int main(int argc, char *argv[])
} else if (command == "handshake") {
setupHandshakeService(&connection);
} else {
- qDebug() << "Unrecognized command:" << command;
+ std::cerr << "Unrecognized command: " << qUtf8Printable(command) << std::endl;
return 1;
}
diff --git a/client/networkmanagercontrol.cpp b/client/networkmanagercontrol.cpp
index ed0fff0..09edae5 100644
--- a/client/networkmanagercontrol.cpp
+++ b/client/networkmanagercontrol.cpp
@@ -296,8 +296,9 @@ QVariant NetworkManagerControl::findNetworkDeviceByMac(const QString &macAddress
QVariant macResult = wiredDeviceInterface.property("HwAddress");
if (!macResult.isValid()) {
const auto error = wiredDeviceInterface.lastError();
- // Non-wired devices result in InvalidArgs due to no MAC address and need not be warned about
- if (error.type() != QDBusError::InvalidArgs)
+ // Non-wired devices result into errors due to no MAC address and need not be warned about.
+ // For some reason the error type in this case can be either UnknownInterface or InvalidArgs.
+ if (error.type() != QDBusError::UnknownInterface && error.type() != QDBusError::InvalidArgs)
qWarning() << "Could not fetch hw address for" << device.path() << error;
continue;
}
diff --git a/libqdb/libqdb.pro b/libqdb/libqdb.pro
index ec5fadf..eeacb7e 100644
--- a/libqdb/libqdb.pro
+++ b/libqdb/libqdb.pro
@@ -15,18 +15,21 @@ DEFINES += LIBQDB_LIBRARY
SOURCES += \
abstractconnection.cpp \
+ interruptsignalhandler.cpp \
protocol/qdbmessage.cpp \
protocol/qdbtransport.cpp \
stream.cpp \
streampacket.cpp \
+ usb/devicemanagement.cpp \
+ usb/libusbcontext.cpp \
usb/usbconnection.cpp \
usb/usbconnectionreader.cpp \
- interruptsignalhandler.cpp \
HEADERS += \
abstractconnection.h \
filepullcommon.h \
filepushcommon.h \
+ interruptsignalhandler.h \
libqdb_global.h \
processcommon.h \
protocol/protocol.h \
@@ -35,9 +38,11 @@ HEADERS += \
protocol/services.h \
stream.h \
streampacket.h \
+ usb/devicemanagement.h \
+ usb/usbcommon.h \
usb/usbconnection.h \
usb/usbconnectionreader.h \
- interruptsignalhandler.h \
+ usb/usbdevice.h \
unix {
target.path = $$[QT_INSTALL_LIBS]
diff --git a/libqdb/protocol/protocol.h b/libqdb/protocol/protocol.h
index 42a3081..c0ae09b 100644
--- a/libqdb/protocol/protocol.h
+++ b/libqdb/protocol/protocol.h
@@ -21,7 +21,7 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
-#include <stdint.h>
+#include <cstdint>
const uint8_t qdbUsbClassId = 0xff;
const uint8_t qdbUsbSubclassId = 0x52;
diff --git a/libqdb/usb/devicemanagement.cpp b/libqdb/usb/devicemanagement.cpp
new file mode 100644
index 0000000..3f67cd6
--- /dev/null
+++ b/libqdb/usb/devicemanagement.cpp
@@ -0,0 +1,136 @@
+/******************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "devicemanagement.h"
+#include "protocol/protocol.h"
+#include "usbcommon.h"
+#include "usbconnection.h"
+#include "../utils/scopeguard.h"
+
+#include <QtCore/qdebug.h>
+
+#include <libusb.h>
+
+bool isQdbInterface(const libusb_interface &interface)
+{
+ const libusb_interface_descriptor *descriptor = &interface.altsetting[0];
+ return descriptor->bInterfaceClass == qdbUsbClassId && descriptor->bInterfaceSubClass == qdbUsbSubclassId;
+}
+
+std::pair<bool, UsbInterfaceInfo> findQdbInterface(libusb_device *device)
+{
+ libusb_config_descriptor *config;
+ const int ret = libusb_get_active_config_descriptor(device, &config);
+ if (ret) {
+ qCritical() << "Could not get config descriptor" << libusb_error_name(ret);
+ return std::make_pair(false, UsbInterfaceInfo{});
+ }
+ ScopeGuard configGuard = [&]() {
+ libusb_free_config_descriptor(config);
+ };
+
+ const auto last = config->interface + config->bNumInterfaces;
+ const auto qdbInterface = std::find_if(config->interface, last, isQdbInterface);
+ if (qdbInterface == last) {
+ return std::make_pair(false, UsbInterfaceInfo{});;
+ }
+
+ const int inEndpointIndex = 1;
+ const int outEndpointIndex = 0;
+
+ const libusb_interface_descriptor *interface = &qdbInterface->altsetting[0];
+ const auto interfaceNumber = interface->bInterfaceNumber;
+ const auto inAddress = interface->endpoint[inEndpointIndex].bEndpointAddress;
+ const auto outAddress = interface->endpoint[outEndpointIndex].bEndpointAddress;
+ const UsbInterfaceInfo info{interfaceNumber, inAddress, outAddress};
+ return std::make_pair(true, info);
+}
+
+QString getSerialNumber(libusb_device *device, libusb_device_handle *handle)
+{
+ QString serial{"???"};
+
+ libusb_device_descriptor desc;
+ int ret = libusb_get_device_descriptor(device, &desc);
+ if (ret) {
+ qCritical() << "Could not get device descriptor" << libusb_error_name(ret);
+ return serial;
+ }
+ auto serialIndex = desc.iSerialNumber;
+
+ const uint16_t englishUsLangId = 0x409;
+ const int bufferSize = 255; // USB string descriptor size field is a single byte
+ unsigned char buffer[bufferSize];
+ int length = libusb_get_string_descriptor(handle, serialIndex, englishUsLangId, buffer, bufferSize);
+ if (length <= 0) {
+ qWarning() << "Could not get string descriptor of serial number:" << libusb_error_name(length);
+ return serial;
+ }
+ // length is the length in bytes and UTF-16 characters consist of two bytes
+ Q_ASSERT(length % 2 == 0);
+ serial = QString::fromUtf16(reinterpret_cast<unsigned short*>(buffer), length / 2);
+ return serial;
+}
+
+std::vector<UsbDevice> listUsbDevices()
+{
+ if (!libUsbContext()) {
+ qDebug() << "Not initialized libusb in DeviceManager";
+ return std::vector<UsbDevice>{};
+ }
+
+ libusb_device **devicesParam;
+ ssize_t deviceCount = libusb_get_device_list(libUsbContext(), &devicesParam);
+ std::shared_ptr<libusb_device *> devices{devicesParam,
+ [](libusb_device **pointer) {
+ libusb_free_device_list(pointer, 1);
+ }};
+
+ if (deviceCount < 0) {
+ qCritical() << "USB devices could not be listed:" << libusb_error_name(deviceCount);
+ return std::vector<UsbDevice>{};
+ }
+
+ std::vector<UsbDevice> qdbDevices;
+ for (int i = 0; i < deviceCount; ++i) {
+ libusb_device *device = devices.get()[i];
+
+ const auto interfaceResult = findQdbInterface(device);
+ if (!interfaceResult.first) {
+ // No QDB interface found, not a QDB device
+ continue;
+ }
+
+ libusb_device_handle *handle;
+ int ret = libusb_open(device, &handle);
+ if (ret) {
+ qDebug() << "Could not open USB device for checking serial number:" << libusb_error_name(ret);
+ continue;
+ }
+ ScopeGuard deviceGuard = [=]() {
+ libusb_close(handle);
+ };
+ const auto serial = getSerialNumber(device, handle);
+
+ const UsbDevice usbDevice{serial, LibUsbDevice{devices, i}, interfaceResult.second};
+ qdbDevices.push_back(usbDevice);
+ }
+ return qdbDevices;
+}
diff --git a/libqdb/usb/devicemanagement.h b/libqdb/usb/devicemanagement.h
new file mode 100644
index 0000000..52ac688
--- /dev/null
+++ b/libqdb/usb/devicemanagement.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef DEVICEMANAGER_H
+#define DEVICEMANAGER_H
+
+#include "usbdevice.h"
+
+#include <vector>
+
+std::vector<UsbDevice> listUsbDevices();
+
+#endif // DEVICEMANAGER_H
diff --git a/libqdb/usb/libusbcontext.cpp b/libqdb/usb/libusbcontext.cpp
new file mode 100644
index 0000000..6976e4e
--- /dev/null
+++ b/libqdb/usb/libusbcontext.cpp
@@ -0,0 +1,51 @@
+/******************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#include "usbcommon.h"
+
+#include <QtGlobal>
+
+#include <libusb.h>
+
+struct LibUsbContext
+{
+ LibUsbContext()
+ : context{nullptr}
+ {
+ int ret = libusb_init(&context);
+ if (ret) {
+ qCritical("Could not initialize libusb");
+ }
+ }
+
+ ~LibUsbContext()
+ {
+ if (context)
+ libusb_exit(context);
+ }
+
+ libusb_context* context;
+};
+
+libusb_context *libUsbContext()
+{
+ static LibUsbContext context;
+ return context.context;
+}
diff --git a/libqdb/usb/usbcommon.h b/libqdb/usb/usbcommon.h
new file mode 100644
index 0000000..4a6d024
--- /dev/null
+++ b/libqdb/usb/usbcommon.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef USBCOMMON_H
+#define USBCOMMON_H
+
+#include <cstdint>
+
+struct libusb_context;
+
+libusb_context *libUsbContext();
+
+struct UsbInterfaceInfo
+{
+ uint8_t number;
+ uint8_t inAddress;
+ uint8_t outAddress;
+};
+
+#endif // USBCOMMON_H
diff --git a/libqdb/usb/usbconnection.cpp b/libqdb/usb/usbconnection.cpp
index 7564f3e..2a3bf92 100644
--- a/libqdb/usb/usbconnection.cpp
+++ b/libqdb/usb/usbconnection.cpp
@@ -23,6 +23,7 @@
#include "../utils/make_unique.h"
#include "../utils/scopeguard.h"
#include "protocol/protocol.h"
+#include "usbcommon.h"
#include "usbconnectionreader.h"
#include <QtCore/qdebug.h>
@@ -30,23 +31,10 @@
#include <libusb.h>
-static const uint16_t vendorID = 0x18d1; // Google Inc.
-static const uint16_t productID = 0x0d02; // Celkon A88
-static const int inEndpointIndex = 1;
-static const int outEndpointIndex = 0;
-
-bool isQdbInterface(const libusb_interface &interface)
-{
- const libusb_interface_descriptor *descriptor = &interface.altsetting[0];
- return descriptor->bInterfaceClass == qdbUsbClassId && descriptor->bInterfaceSubClass == qdbUsbSubclassId;
-}
-
-UsbConnection::UsbConnection()
- : m_context(nullptr),
- m_handle(nullptr),
- m_interfaceNumber(0),
- m_inAddress(0),
- m_outAddress(0),
+UsbConnection::UsbConnection(const UsbDevice &device)
+ : m_device{device.usbDevice},
+ m_handle{nullptr},
+ m_interfaceInfo(device.interfaceInfo), // uniform initialization with {} fails with GCC 4.9
m_readThread{nullptr},
m_reader{nullptr},
m_reads{}
@@ -60,11 +48,9 @@ UsbConnection::~UsbConnection()
m_readThread->wait();
}
if (m_handle) {
- libusb_release_interface(m_handle, m_interfaceNumber);
+ libusb_release_interface(m_handle, m_interfaceInfo.number);
libusb_close(m_handle);
}
- if (m_context)
- libusb_exit(m_context);
}
bool UsbConnection::open(OpenMode mode)
@@ -72,48 +58,8 @@ bool UsbConnection::open(OpenMode mode)
Q_ASSERT(mode == (QIODevice::ReadWrite | QIODevice::Unbuffered));
QIODevice::open(mode);
- libusb_device *found = NULL;
-
- int ret = libusb_init(&m_context);
- if (ret) {
- qDebug("cannot init libusb: %s\n", libusb_error_name(ret));
- return false;
- }
-
- libusb_device **devices;
- ssize_t deviceCount = libusb_get_device_list(m_context, &devices);
- ScopeGuard deviceListGuard = [&]() {
- libusb_free_device_list(devices, 1);
- };
-
- if (deviceCount <= 0) {
- qDebug("no devices found\n");
- return false;
- }
-
- for (int i = 0; i < deviceCount; ++i) {
- libusb_device *device = devices[i];
- struct libusb_device_descriptor desc;
- ret = libusb_get_device_descriptor(device, &desc);
- if (ret) {
- qDebug("unable to get device descriptor: %s\n",
- libusb_error_name(ret));
- return false;
- }
- if (desc.idVendor == vendorID && desc.idProduct == productID) {
- qDebug("found QDB device");
- found = device;
- break;
- }
- }
-
- if (!found) {
- qDebug("no QDB devices found\n");
- return false;
- }
-
libusb_config_descriptor *config;
- ret = libusb_get_active_config_descriptor(found, &config);
+ int ret = libusb_get_active_config_descriptor(m_device.pointer(), &config);
if (ret) {
qDebug("could not get config descriptor: %s\n",
libusb_error_name(ret));
@@ -123,21 +69,7 @@ bool UsbConnection::open(OpenMode mode)
libusb_free_config_descriptor(config);
};
- auto last = config->interface + config->bNumInterfaces;
- auto qdbInterface = std::find_if(config->interface, last, isQdbInterface);
- if (qdbInterface == last) {
- qDebug("no QDB interface found in device");
- return false;
- }
-
- const libusb_interface_descriptor *interface = &qdbInterface->altsetting[0];
- m_interfaceNumber = interface->bInterfaceNumber;
- m_inAddress = interface->endpoint[inEndpointIndex].bEndpointAddress;
- m_outAddress = interface->endpoint[outEndpointIndex].bEndpointAddress;
-
- qDebug("interface %d is a qdb interface", m_interfaceNumber);
-
- ret = libusb_open(found, &m_handle);
+ ret = libusb_open(m_device.pointer(), &m_handle);
if (ret) {
qDebug("cannot open device: %s\n", libusb_error_name(ret));
return false;
@@ -145,14 +77,14 @@ bool UsbConnection::open(OpenMode mode)
libusb_set_auto_detach_kernel_driver(m_handle, 1);
- ret = libusb_claim_interface(m_handle, m_interfaceNumber);
+ ret = libusb_claim_interface(m_handle, m_interfaceInfo.number);
if (ret) {
qDebug("cannot claim interface: %s", libusb_error_name(ret));
return false;
}
- qDebug("claimed interface %d", m_interfaceNumber);
+ qDebug("claimed interface %d", m_interfaceInfo.number);
- startReader(m_handle, m_inAddress);
+ startReader(m_handle, m_interfaceInfo.inAddress);
return true;
}
@@ -176,7 +108,7 @@ qint64 UsbConnection::writeData(const char *data, qint64 maxSize)
int size = maxSize > qdbHeaderSize ? qdbHeaderSize : maxSize;
int transferred = 0;
- int ret = libusb_bulk_transfer(m_handle, m_outAddress, (unsigned char*)data, size, &transferred, 0);
+ int ret = libusb_bulk_transfer(m_handle, m_interfaceInfo.outAddress, (unsigned char*)data, size, &transferred, 0);
if (ret) {
qDebug() << "writeData error:" << libusb_error_name(ret);
return -1;
@@ -186,7 +118,7 @@ qint64 UsbConnection::writeData(const char *data, qint64 maxSize)
if (size < maxSize) {
int rest = maxSize - size;
- int ret = libusb_bulk_transfer(m_handle, m_outAddress, (unsigned char*)data + size, rest, &transferred, 0);
+ int ret = libusb_bulk_transfer(m_handle, m_interfaceInfo.outAddress, (unsigned char*)data + size, rest, &transferred, 0);
if (ret) {
qDebug() << "writeData error:" << libusb_error_name(ret);
return -1;
diff --git a/libqdb/usb/usbconnection.h b/libqdb/usb/usbconnection.h
index 87c10d5..e050557 100644
--- a/libqdb/usb/usbconnection.h
+++ b/libqdb/usb/usbconnection.h
@@ -22,6 +22,7 @@
#define USBMANAGER_H
#include "libqdb_global.h"
+#include "usbdevice.h"
class UsbConnectionReader;
@@ -34,14 +35,14 @@ QT_END_NAMESPACE
#include <memory>
-struct libusb_context;
+struct libusb_device;
struct libusb_device_handle;
class LIBQDBSHARED_EXPORT UsbConnection : public QIODevice
{
Q_OBJECT
public:
- UsbConnection();
+ UsbConnection(const UsbDevice &device);
~UsbConnection();
bool open(QIODevice::OpenMode mode) override;
@@ -56,11 +57,9 @@ private slots:
private:
void startReader(libusb_device_handle *handle, uint8_t inAddress);
- libusb_context *m_context;
+ LibUsbDevice m_device;
libusb_device_handle *m_handle;
- uint8_t m_interfaceNumber;
- uint8_t m_inAddress;
- uint8_t m_outAddress;
+ UsbInterfaceInfo m_interfaceInfo;
std::unique_ptr<QThread> m_readThread;
std::unique_ptr<UsbConnectionReader> m_reader;
QQueue<QByteArray> m_reads;
diff --git a/libqdb/usb/usbdevice.h b/libqdb/usb/usbdevice.h
new file mode 100644
index 0000000..5e8c1a9
--- /dev/null
+++ b/libqdb/usb/usbdevice.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Debug Bridge.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+******************************************************************************/
+#ifndef USBDEVICE_H
+#define USBDEVICE_H
+
+#include "usbcommon.h"
+
+#include <QtCore/qstring.h>
+
+#include <cstdint>
+#include <memory>
+
+struct libusb_device;
+
+class LibUsbDevice {
+public:
+ LibUsbDevice(std::shared_ptr<libusb_device *> devices, int index)
+ : m_deviceList{devices},
+ m_index{index}
+
+ {
+ }
+
+ libusb_device *pointer()
+ {
+ return m_deviceList.get()[m_index];
+ }
+
+private:
+ std::shared_ptr<libusb_device *> m_deviceList;
+ int m_index;
+
+};
+
+struct UsbDevice
+{
+ QString serial;
+ LibUsbDevice usbDevice;
+ UsbInterfaceInfo interfaceInfo;
+};
+
+#endif // USBDEVICE_H
diff --git a/tests/servicetest.cpp b/tests/servicetest.cpp
index c87d429..099a49f 100644
--- a/tests/servicetest.cpp
+++ b/tests/servicetest.cpp
@@ -24,6 +24,7 @@
#include "../client/processservice.h"
#include "../client/echoservice.h"
#include "../utils/make_unique.h"
+#include "usb/devicemanagement.h"
#include "usb/usbconnection.h"
#include "protocol/qdbtransport.h"
#include "protocol/services.h"
@@ -39,7 +40,7 @@ const int testTimeout = 500; // in milliseconds
struct ConnectionContext
{
ConnectionContext()
- : connection{new QdbTransport{new UsbConnection{}}}
+ : connection{new QdbTransport{new UsbConnection{listUsbDevices()[0]}}}
{
QVERIFY(connection.initialize());
diff --git a/tests/streamtest.cpp b/tests/streamtest.cpp
index df0c814..0d33d10 100644
--- a/tests/streamtest.cpp
+++ b/tests/streamtest.cpp
@@ -19,6 +19,7 @@
**
******************************************************************************/
#include "../utils/make_unique.h"
+#include "usb/devicemanagement.h"
#include "usb/usbconnection.h"
#include "protocol/protocol.h"
#include "protocol/qdbmessage.h"
@@ -44,7 +45,7 @@ public:
public slots:
void run()
{
- m_transport = make_unique<QdbTransport>(new UsbConnection{});
+ m_transport = make_unique<QdbTransport>(new UsbConnection{listUsbDevices()[0]});
if (m_transport->open()) {
qDebug() << "opened transport";
connect(m_transport.get(), &QdbTransport::messageAvailable, this, &TestCase::testPhases);
@@ -209,7 +210,7 @@ public slots:
{
switch (m_phase) {
case 0: {
- QdbMessage cnxn{QdbMessage::Connect, 0, 0};
+ QdbMessage cnxn{QdbMessage::Connect, 0, 0, m_versionBuffer};
QVERIFY(m_transport->send(cnxn));
break;
}