Commit 4a1617f43c5bf752d800c4d5fb75d1ec995f3c70
Committed by
David Gräff
1 parent
3ccfb5b2
Rework device selection
* Use own QDialog class SelectDevice and clean up main.cpp. * USBDevice: Introduce a unique usb id for a connected device * USBDevice: Introduce iteration field, to remember in which find round a device was found
Showing
15 changed files
with
434 additions
and
154 deletions
cmake/CPackInfos.cmake
| @@ -44,13 +44,17 @@ else() | @@ -44,13 +44,17 @@ else() | ||
| 44 | ) | 44 | ) |
| 45 | 45 | ||
| 46 | set(ENV{LANG} "en_US") | 46 | set(ENV{LANG} "en_US") |
| 47 | - execute_process( | ||
| 48 | - COMMAND ${GIT_EXECUTABLE} log -n 10 "--date=format:%a %b %d %Y" "--pretty=format:* %ad %aN <%aE> %h - %s" | ||
| 49 | - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||
| 50 | - RESULT_VARIABLE CMD_RESULT | ||
| 51 | - OUTPUT_VARIABLE CHANGELOG | ||
| 52 | - OUTPUT_STRIP_TRAILING_WHITESPACE | ||
| 53 | - ) | 47 | + if(GIT_VERSION_STRING VERSION_LESS 2.6) |
| 48 | + set(CHANGELOG "") | ||
| 49 | + else() | ||
| 50 | + execute_process( | ||
| 51 | + COMMAND ${GIT_EXECUTABLE} log -n 10 "--date=format:%a %b %d %Y" "--pretty=format:* %ad %aN <%aE> %h - %s" | ||
| 52 | + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||
| 53 | + RESULT_VARIABLE CMD_RESULT | ||
| 54 | + OUTPUT_VARIABLE CHANGELOG | ||
| 55 | + OUTPUT_STRIP_TRAILING_WHITESPACE | ||
| 56 | + ) | ||
| 57 | + endif() | ||
| 54 | file(WRITE "${CMAKE_BINARY_DIR}/changelog" "${CHANGELOG}") | 58 | file(WRITE "${CMAKE_BINARY_DIR}/changelog" "${CHANGELOG}") |
| 55 | endif() | 59 | endif() |
| 56 | 60 |
openhantek/res/application.qrc
| 1 | <RCC> | 1 | <RCC> |
| 2 | <qresource prefix="/"> | 2 | <qresource prefix="/"> |
| 3 | <file alias="openhantek.png">images/openhantek.png</file> | 3 | <file alias="openhantek.png">images/openhantek.png</file> |
| 4 | + <file alias="switch.png">images/switch.png</file> | ||
| 4 | </qresource> | 5 | </qresource> |
| 5 | <qresource prefix="/actions"> | 6 | <qresource prefix="/actions"> |
| 6 | <file alias="open.png">images/actions/open.png</file> | 7 | <file alias="open.png">images/actions/open.png</file> |
openhantek/res/images/switch.png
0 → 100644
120 KB
openhantek/src/main.cpp
| 1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | 2 | ||
| 3 | -#include <QApplication> | ||
| 4 | #include <QDebug> | 3 | #include <QDebug> |
| 5 | -#include <QDesktopWidget> | 4 | +#include <QApplication> |
| 6 | #include <QLibraryInfo> | 5 | #include <QLibraryInfo> |
| 7 | -#include <QListWidget> | ||
| 8 | #include <QLocale> | 6 | #include <QLocale> |
| 9 | -#include <QMessageBox> | ||
| 10 | -#include <QPushButton> | ||
| 11 | -#include <QTimer> | ||
| 12 | #include <QTranslator> | 7 | #include <QTranslator> |
| 13 | -#include <QVBoxLayout> | 8 | + |
| 14 | #include <iostream> | 9 | #include <iostream> |
| 15 | #include <memory> | 10 | #include <memory> |
| 16 | - | ||
| 17 | #include <libusb-1.0/libusb.h> | 11 | #include <libusb-1.0/libusb.h> |
| 18 | 12 | ||
| 19 | #include "analyse/dataanalyzer.h" | 13 | #include "analyse/dataanalyzer.h" |
| 20 | #include "hantekdsocontrol.h" | 14 | #include "hantekdsocontrol.h" |
| 21 | #include "mainwindow.h" | 15 | #include "mainwindow.h" |
| 22 | #include "settings.h" | 16 | #include "settings.h" |
| 23 | -#include "usb/finddevices.h" | ||
| 24 | -#include "usb/uploadFirmware.h" | ||
| 25 | #include "usb/usbdevice.h" | 17 | #include "usb/usbdevice.h" |
| 26 | #include "dsomodel.h" | 18 | #include "dsomodel.h" |
| 19 | +#include "selectdevice/selectdevice.h" | ||
| 27 | 20 | ||
| 28 | using namespace Hantek; | 21 | using namespace Hantek; |
| 29 | 22 | ||
| 30 | -void showMessage(const QString &message) { | ||
| 31 | - QMessageBox::information(nullptr, QCoreApplication::translate("", "No connection established!"), message); | ||
| 32 | -} | ||
| 33 | - | ||
| 34 | /// \brief Initialize resources and translations and show the main window. | 23 | /// \brief Initialize resources and translations and show the main window. |
| 35 | int main(int argc, char *argv[]) { | 24 | int main(int argc, char *argv[]) { |
| 36 | //////// Set application information //////// | 25 | //////// Set application information //////// |
| @@ -53,97 +42,17 @@ int main(int argc, char *argv[]) { | @@ -53,97 +42,17 @@ int main(int argc, char *argv[]) { | ||
| 53 | } | 42 | } |
| 54 | 43 | ||
| 55 | //////// Find matching usb devices //////// | 44 | //////// Find matching usb devices //////// |
| 56 | - libusb_context *context; | 45 | + libusb_context *context = nullptr; |
| 57 | int error = libusb_init(&context); | 46 | int error = libusb_init(&context); |
| 58 | - | ||
| 59 | if (error) { | 47 | if (error) { |
| 60 | - showMessage(QCoreApplication::translate("", "Can't initalize USB: %1").arg(libUsbErrorString(error))); | 48 | + SelectDevice().showLibUSBFailedDialogModel(error); |
| 61 | return -1; | 49 | return -1; |
| 62 | } | 50 | } |
| 51 | + std::unique_ptr<USBDevice> device = SelectDevice().showSelectDeviceModal(context); | ||
| 63 | 52 | ||
| 64 | - FindDevices findDevices; | ||
| 65 | - std::list<std::unique_ptr<USBDevice>> devices = findDevices.findDevices(); | ||
| 66 | - | ||
| 67 | - if (devices.empty()) { | ||
| 68 | - showMessage(QCoreApplication::translate("", "No Hantek oscilloscope found. Please check if your " | ||
| 69 | - "device is supported by this software, is connected, " | ||
| 70 | - "in the right mode (oscilloscope mode) and if the " | ||
| 71 | - "driver is correctly installed. Refer to the <a " | ||
| 72 | - "href='https://github.com/OpenHantek/openhantek/" | ||
| 73 | - "'>website</a> for help: %1") | ||
| 74 | - .arg(findDevices.getErrorMessage())); | ||
| 75 | - return -1; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - //////// Upload firmwares for all connected devices //////// | ||
| 79 | - for (const auto &i : devices) { | ||
| 80 | - QString modelName = QString::fromStdString(i->getModel()->name); | ||
| 81 | - if (i->needsFirmware()) { | ||
| 82 | - UploadFirmware uf; | ||
| 83 | - uf.startUpload(i.get()); | ||
| 84 | - } | ||
| 85 | - } | ||
| 86 | - devices.clear(); | ||
| 87 | - | ||
| 88 | -#define TR(str) QCoreApplication::translate("Firmware upload dialog", str) | ||
| 89 | - | ||
| 90 | - //////// Select device - Autoselect if only one device is ready //////// | ||
| 91 | - std::unique_ptr<QDialog> dialog = std::unique_ptr<QDialog>(new QDialog); | ||
| 92 | - QListWidget *w = new QListWidget(dialog.get()); | ||
| 93 | - | ||
| 94 | - devices = findDevices.findDevices(); | ||
| 95 | - for (auto &i : devices) { | ||
| 96 | - QString modelName = QString::fromStdString(i->getModel()->name); | ||
| 97 | - | ||
| 98 | - if (i->needsFirmware()) { | ||
| 99 | - if (UploadFirmware().startUpload(&*i)) { | ||
| 100 | - w->addItem(TR("%1: Upload failed").arg(modelName)); | ||
| 101 | - } else { | ||
| 102 | - w->addItem(TR("%1: Upload failed").arg(modelName)); | ||
| 103 | - | ||
| 104 | - } | ||
| 105 | - continue; | ||
| 106 | - } | ||
| 107 | - QString errorMessage; | ||
| 108 | - if (i->connectDevice(errorMessage)) { | ||
| 109 | - w->addItem(TR("%1: Ready").arg(modelName)); | ||
| 110 | - w->setCurrentRow(w->count() - 1); | ||
| 111 | - } else { | ||
| 112 | - w->addItem(TR("%1: %2").arg(modelName).arg(findDevices.getErrorMessage())); | ||
| 113 | - } | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - if (w->currentRow() == -1 || devices.size() > 1) { | ||
| 117 | - QPushButton *btn = new QPushButton(QCoreApplication::translate("", "Connect to first device"), dialog.get()); | ||
| 118 | - dialog->move(QApplication::desktop()->screen()->rect().center() - w->rect().center()); | ||
| 119 | - dialog->setWindowTitle(QCoreApplication::translate("", "Firmware upload")); | ||
| 120 | - dialog->setLayout(new QVBoxLayout()); | ||
| 121 | - dialog->layout()->addWidget(w); | ||
| 122 | - dialog->layout()->addWidget(btn); | ||
| 123 | - btn->connect(btn, &QPushButton::clicked, QCoreApplication::instance(), &QCoreApplication::quit); | ||
| 124 | - dialog->show(); | ||
| 125 | - openHantekApplication.exec(); | ||
| 126 | - dialog->close(); | ||
| 127 | - } | ||
| 128 | - int selectedDevice = w->currentRow(); | ||
| 129 | - dialog.reset(nullptr); | ||
| 130 | - | ||
| 131 | - std::unique_ptr<USBDevice> device; | ||
| 132 | - int indexCounter = 0; | ||
| 133 | - for (auto &i : devices) { | ||
| 134 | - if (indexCounter == selectedDevice) { | ||
| 135 | - device = std::move(i); | ||
| 136 | - break; | ||
| 137 | - } | ||
| 138 | - } | ||
| 139 | - devices.clear(); | ||
| 140 | - | ||
| 141 | - if (device == nullptr || device->needsFirmware() || !device->isConnected()) { | ||
| 142 | - showMessage(QCoreApplication::translate("", "A device was found, but the " | ||
| 143 | - "firmware upload seem to have " | ||
| 144 | - "failed or the connection " | ||
| 145 | - "could not be established: %1") | ||
| 146 | - .arg(findDevices.getErrorMessage())); | 53 | + QString errorMessage; |
| 54 | + if (device == nullptr || !device->connectDevice(errorMessage)) { | ||
| 55 | + libusb_exit(context); | ||
| 147 | return -1; | 56 | return -1; |
| 148 | } | 57 | } |
| 149 | 58 |
openhantek/src/selectdevice/devicelistentry.h
0 → 100644
| 1 | +#pragma once | ||
| 2 | + | ||
| 3 | +#include <QString> | ||
| 4 | +#include "usb/usbdevice.h" | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Represents an entry in the {@link DevicesListModel}. | ||
| 8 | + */ | ||
| 9 | +struct DeviceListEntry { | ||
| 10 | + UniqueUSBid id; | ||
| 11 | + QString name; | ||
| 12 | + bool canConnect; | ||
| 13 | + bool needFirmware; | ||
| 14 | + QString errorMessage; | ||
| 15 | + QString getStatus() const { | ||
| 16 | + return errorMessage.size()? errorMessage : (canConnect?"Ready":(needFirmware?"Firmware upload":"Cannot connect")); | ||
| 17 | + } | ||
| 18 | +}; |
openhantek/src/selectdevice/deviceslistmodel.cpp
0 → 100644
| 1 | +#include "deviceslistmodel.h" | ||
| 2 | +#include "usb/finddevices.h" | ||
| 3 | +#include "usb/uploadFirmware.h" | ||
| 4 | +#include "dsomodel.h" | ||
| 5 | +#include <QColor> | ||
| 6 | + | ||
| 7 | +DevicesListModel::DevicesListModel(FindDevices *findDevices) :findDevices(findDevices) {} | ||
| 8 | + | ||
| 9 | +int DevicesListModel::rowCount(const QModelIndex &) const | ||
| 10 | +{ | ||
| 11 | + return entries.size(); | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +int DevicesListModel::columnCount(const QModelIndex &parent) const | ||
| 15 | +{ | ||
| 16 | + return 2; | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +QVariant DevicesListModel::headerData(int section, Qt::Orientation orientation, int role) const | ||
| 20 | +{ | ||
| 21 | + if (orientation == Qt::Vertical) | ||
| 22 | + return QAbstractTableModel::headerData(section, orientation, role); | ||
| 23 | + if (role == Qt::DisplayRole) { | ||
| 24 | + switch(section) { | ||
| 25 | + case 0: return tr("Devicename"); | ||
| 26 | + case 1: return tr("Status"); | ||
| 27 | + default: return QVariant(); | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + return QAbstractTableModel::headerData(section, orientation, role); | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +QVariant DevicesListModel::data(const QModelIndex &index, int role) const | ||
| 34 | +{ | ||
| 35 | + if (!index.isValid()) return QVariant(); | ||
| 36 | + if (role==Qt::UserRole) return QVariant::fromValue(entries[index.row()].id); | ||
| 37 | + else if (role==Qt::UserRole+1) return QVariant::fromValue(entries[index.row()].canConnect); | ||
| 38 | + else if (role==Qt::UserRole+2) return QVariant::fromValue(entries[index.row()].needFirmware); | ||
| 39 | + | ||
| 40 | + if (role == Qt::DisplayRole) { | ||
| 41 | + if (index.column() == 0) { | ||
| 42 | + return entries[index.row()].name; | ||
| 43 | + } else if (index.column() == 1) { | ||
| 44 | + return entries[index.row()].getStatus(); | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + if (role == Qt::BackgroundRole) { | ||
| 49 | + if (entries[index.row()].canConnect) return QColor(Qt::darkGreen).lighter(); | ||
| 50 | + else if (entries[index.row()].needFirmware) return QColor(Qt::yellow).lighter(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + return QVariant(); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +void DevicesListModel::updateDeviceList() | ||
| 57 | +{ | ||
| 58 | + beginResetModel(); | ||
| 59 | + entries.clear(); | ||
| 60 | + endResetModel(); | ||
| 61 | + const FindDevices::DeviceList* devices = findDevices->getDevices(); | ||
| 62 | + beginInsertRows(QModelIndex(),0,devices->size()); | ||
| 63 | + for (auto &i : *devices) { | ||
| 64 | + DeviceListEntry entry; | ||
| 65 | + entry.name= QString::fromStdString(i.second->getModel()->name); | ||
| 66 | + entry.id = i.first; | ||
| 67 | + if (i.second->needsFirmware()) { | ||
| 68 | + UploadFirmware uf; | ||
| 69 | + if (!uf.startUpload(i.second.get())) { | ||
| 70 | + entry.errorMessage = uf.getErrorMessage(); | ||
| 71 | + } | ||
| 72 | + entry.needFirmware = true; | ||
| 73 | + } else if (i.second->connectDevice(entry.errorMessage)) { | ||
| 74 | + entry.canConnect = true; | ||
| 75 | + i.second->disconnectFromDevice(); | ||
| 76 | + } else { | ||
| 77 | + entry.canConnect = false; | ||
| 78 | + } | ||
| 79 | + entries.push_back(entry); | ||
| 80 | + } | ||
| 81 | + endInsertRows(); | ||
| 82 | +} |
openhantek/src/selectdevice/deviceslistmodel.h
0 → 100644
| 1 | +#pragma once | ||
| 2 | + | ||
| 3 | +#include <QAbstractTableModel> | ||
| 4 | +#include "devicelistentry.h" | ||
| 5 | + | ||
| 6 | +class FindDevices; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Provides a Model for the Qt Model/View concept. The {@see FindDevices} is required | ||
| 10 | + * to update the list of available devices. | ||
| 11 | + */ | ||
| 12 | +class DevicesListModel: public QAbstractTableModel { | ||
| 13 | +public: | ||
| 14 | + DevicesListModel(FindDevices* findDevices); | ||
| 15 | + // QAbstractItemModel interface | ||
| 16 | + virtual int rowCount(const QModelIndex &parent) const override; | ||
| 17 | + virtual int columnCount(const QModelIndex &parent) const override; | ||
| 18 | + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; | ||
| 19 | + virtual QVariant data(const QModelIndex &index, int role) const override; | ||
| 20 | + void updateDeviceList(); | ||
| 21 | +private: | ||
| 22 | + std::vector<DeviceListEntry> entries; | ||
| 23 | + FindDevices* findDevices; | ||
| 24 | +}; |
openhantek/src/selectdevice/selectdevice.cpp
0 → 100644
| 1 | +#include <libusb-1.0/libusb.h> | ||
| 2 | + | ||
| 3 | +#include "utils/printutils.h" | ||
| 4 | +#include "selectdevice.h" | ||
| 5 | +#include "usb/uploadFirmware.h" | ||
| 6 | +#include "usb/finddevices.h" | ||
| 7 | +#include "dsomodel.h" | ||
| 8 | +#include <QApplication> | ||
| 9 | +#include <QTimer> | ||
| 10 | +#include <QAbstractTableModel> | ||
| 11 | +#include <QHeaderView> | ||
| 12 | +#include <QFile> | ||
| 13 | + | ||
| 14 | +#include "devicelistentry.h" | ||
| 15 | +#include "deviceslistmodel.h" | ||
| 16 | + | ||
| 17 | +SelectDevice::SelectDevice() { | ||
| 18 | + btn = new QPushButton(this); | ||
| 19 | + w = new QTableView(this); | ||
| 20 | + label = new QLabel(); | ||
| 21 | + label->setWordWrap(true); | ||
| 22 | + move(QApplication::desktop()->screen()->rect().center() - w->rect().center()); | ||
| 23 | + setWindowTitle(tr("Select device")); | ||
| 24 | + setLayout(new QVBoxLayout()); | ||
| 25 | + layout()->addWidget(w); | ||
| 26 | + layout()->addWidget(label); | ||
| 27 | + layout()->addWidget(btn); | ||
| 28 | + qRegisterMetaType<UniqueUSBid>(); | ||
| 29 | + connect(btn, &QPushButton::clicked, [this]() { | ||
| 30 | + if (w->currentIndex().isValid()) { | ||
| 31 | + selectedDevice = w->currentIndex().data(Qt::UserRole).value<UniqueUSBid>(); | ||
| 32 | + } | ||
| 33 | + QCoreApplication::instance()->quit(); | ||
| 34 | + }); | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +std::unique_ptr<USBDevice> SelectDevice::showSelectDeviceModal(libusb_context *&context) | ||
| 38 | +{ | ||
| 39 | + | ||
| 40 | + std::unique_ptr<FindDevices> findDevices = std::unique_ptr<FindDevices>(new FindDevices(context)); | ||
| 41 | + std::unique_ptr<DevicesListModel> model = std::unique_ptr<DevicesListModel>(new DevicesListModel(findDevices.get())); | ||
| 42 | + w->setModel(model.get()); | ||
| 43 | + w->verticalHeader()->hide(); | ||
| 44 | + w->horizontalHeader()->hide(); | ||
| 45 | + w->setSelectionBehavior(QAbstractItemView::SelectRows); | ||
| 46 | + // w->setColumnWidth(1,60); | ||
| 47 | + w->horizontalHeader()->setStretchLastSection(true); | ||
| 48 | + connect(w->selectionModel(), &QItemSelectionModel::currentChanged, this, &SelectDevice::currentChanged); | ||
| 49 | + | ||
| 50 | + QTimer timer; | ||
| 51 | + timer.setInterval(1000); | ||
| 52 | + connect(&timer, &QTimer::timeout, [this, &model, &findDevices]() { | ||
| 53 | + if (findDevices->updateDeviceList()) | ||
| 54 | + model->updateDeviceList(); | ||
| 55 | + if (model->rowCount(QModelIndex())) { | ||
| 56 | + w->setVisible(true); | ||
| 57 | + label->setVisible(false); | ||
| 58 | + currentChanged(w->currentIndex(),QModelIndex()); | ||
| 59 | + } else { | ||
| 60 | + QString generalMessage = tr("<p>OpenHantek did not find any compatible devices.</p>" | ||
| 61 | + "<p><img align='right' height='150' src='qrc:///switch.png'>" | ||
| 62 | + "Don't forget to switch your device into oscilloscope mode if it has multiple modes.</p>" | ||
| 63 | + ); | ||
| 64 | +#if defined(Q_OS_WIN) | ||
| 65 | + generalMessage = generalMessage.arg("Please make sure you have installed the windows usb driver correctly"); | ||
| 66 | +#elif defined(Q_OS_LINUX) | ||
| 67 | + QFile file("/lib/udev/rules.d/60-hantek.rules"); | ||
| 68 | + if (!file.exists()) { | ||
| 69 | + generalMessage += tr("<p>Please make sure you have copied the udev rules file to <b>%1</b> for correct USB access permissions.</p>").arg(file.fileName()); | ||
| 70 | + } | ||
| 71 | +#else | ||
| 72 | +#endif | ||
| 73 | + generalMessage += tr("<p>Visit the build and run instruction " | ||
| 74 | + "<a href='https://github.com/OpenHantek/openhantek/blob/master/docs/build.md'>website</a> for help.</p>"); | ||
| 75 | + makeErrorDialog(generalMessage); | ||
| 76 | + } | ||
| 77 | + if (!w->currentIndex().isValid()) { | ||
| 78 | + currentChanged(QModelIndex(),QModelIndex()); | ||
| 79 | + } | ||
| 80 | + }); | ||
| 81 | + timer.start(); | ||
| 82 | + QCoreApplication::sendEvent(&timer, new QTimerEvent(timer.timerId())); // immediate timer event | ||
| 83 | + | ||
| 84 | + show(); | ||
| 85 | + QCoreApplication::instance()->exec(); | ||
| 86 | + timer.stop(); | ||
| 87 | + close(); | ||
| 88 | + | ||
| 89 | + return findDevices->takeDevice(selectedDevice); | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +void SelectDevice::showLibUSBFailedDialogModel(int error) | ||
| 93 | +{ | ||
| 94 | + makeErrorDialog(tr("Can't initalize USB: %1").arg(libUsbErrorString(error))); | ||
| 95 | + show(); | ||
| 96 | + QCoreApplication::instance()->exec(); | ||
| 97 | + close(); | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +void SelectDevice::makeErrorDialog(const QString &message) | ||
| 101 | +{ | ||
| 102 | + w->setVisible(false); | ||
| 103 | + label->setText(message); | ||
| 104 | + label->setVisible(true); | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +void SelectDevice::currentChanged(const QModelIndex ¤t, const QModelIndex &) | ||
| 108 | +{ | ||
| 109 | + if (!current.isValid()) { | ||
| 110 | + btn->setText(tr("Quit application")); | ||
| 111 | + btn->setEnabled(true); | ||
| 112 | + return; | ||
| 113 | + } | ||
| 114 | + if (current.data(Qt::UserRole+1).toBool()) { | ||
| 115 | + btn->setText(tr("Use device %1").arg(current.sibling(current.row(),0).data(Qt::DisplayRole).toString())); | ||
| 116 | + btn->setEnabled(true); | ||
| 117 | + } else { | ||
| 118 | + btn->setEnabled(false); | ||
| 119 | + if (current.data(Qt::UserRole+2).toBool()) { | ||
| 120 | + btn->setText(tr("Upload in progress...")); | ||
| 121 | + } else { | ||
| 122 | + btn->setText(tr("Connection failed!")); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | +} |
openhantek/src/selectdevice/selectdevice.h
0 → 100644
| 1 | +#pragma once | ||
| 2 | + | ||
| 3 | +#include <QTableView> | ||
| 4 | +#include <QPushButton> | ||
| 5 | +#include <QVBoxLayout> | ||
| 6 | +#include <QDesktopWidget> | ||
| 7 | +#include <QDialog> | ||
| 8 | +#include <QLabel> | ||
| 9 | +#include <memory> | ||
| 10 | +#include "usb/usbdevice.h" | ||
| 11 | + | ||
| 12 | +struct libusb_context; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * Offers the user a selection dialog. If you call any of the -Modal methods, | ||
| 16 | + * the method will block and show a dialog for selection or for a usb error | ||
| 17 | + * message. The method returns as soon as the user closes the dialog. | ||
| 18 | + * | ||
| 19 | + * An example to get a device: | ||
| 20 | + * std::unique_ptr<USBDevice> device = SelectDevice().showSelectDeviceModal(context); | ||
| 21 | + */ | ||
| 22 | +class SelectDevice: public QDialog { | ||
| 23 | +public: | ||
| 24 | + SelectDevice(); | ||
| 25 | + std::unique_ptr<USBDevice> showSelectDeviceModal(libusb_context *&context); | ||
| 26 | + void showLibUSBFailedDialogModel(int error); | ||
| 27 | +private: | ||
| 28 | + void makeErrorDialog(const QString& message); | ||
| 29 | + void updateDeviceList(); | ||
| 30 | + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); | ||
| 31 | + QTableView *w; | ||
| 32 | + QLabel *label; | ||
| 33 | + QPushButton *btn; | ||
| 34 | + UniqueUSBid selectedDevice = 0; | ||
| 35 | +}; |
openhantek/src/usb/finddevices.cpp
| @@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
| 7 | #include <QList> | 7 | #include <QList> |
| 8 | #include <QTemporaryFile> | 8 | #include <QTemporaryFile> |
| 9 | 9 | ||
| 10 | +#include <algorithm> | ||
| 10 | #include "ezusb.h" | 11 | #include "ezusb.h" |
| 11 | #include "utils/printutils.h" | 12 | #include "utils/printutils.h" |
| 12 | #include <libusb-1.0/libusb.h> | 13 | #include <libusb-1.0/libusb.h> |
| @@ -16,50 +17,64 @@ | @@ -16,50 +17,64 @@ | ||
| 16 | FindDevices::FindDevices(libusb_context *context) : context(context) {} | 17 | FindDevices::FindDevices(libusb_context *context) : context(context) {} |
| 17 | 18 | ||
| 18 | // Iterate through all usb devices | 19 | // Iterate through all usb devices |
| 19 | -std::list<std::unique_ptr<USBDevice>> FindDevices::findDevices() { | ||
| 20 | - std::list<std::unique_ptr<USBDevice>> devices; | ||
| 21 | - | 20 | +int FindDevices::updateDeviceList() { |
| 22 | libusb_device **deviceList; | 21 | libusb_device **deviceList; |
| 23 | ssize_t deviceCount = libusb_get_device_list(context, &deviceList); | 22 | ssize_t deviceCount = libusb_get_device_list(context, &deviceList); |
| 24 | if (deviceCount < 0) { | 23 | if (deviceCount < 0) { |
| 25 | - errorMessage = QCoreApplication::translate("", "Failed to get device list"); | ||
| 26 | - return devices; | 24 | + return (int) deviceCount; |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | - noAccessDevices = false; | ||
| 30 | - int noAccessDeviceCount = 0; | 27 | + ++findIteration; |
| 28 | + int changes = 0; | ||
| 31 | 29 | ||
| 32 | for (ssize_t deviceIterator = 0; deviceIterator < deviceCount; ++deviceIterator) { | 30 | for (ssize_t deviceIterator = 0; deviceIterator < deviceCount; ++deviceIterator) { |
| 33 | libusb_device *device = deviceList[deviceIterator]; | 31 | libusb_device *device = deviceList[deviceIterator]; |
| 34 | // Get device descriptor | 32 | // Get device descriptor |
| 35 | struct libusb_device_descriptor descriptor; | 33 | struct libusb_device_descriptor descriptor; |
| 36 | - if (libusb_get_device_descriptor(device, &descriptor) < 0) continue; | 34 | + libusb_get_device_descriptor(device, &descriptor); |
| 35 | + | ||
| 36 | + DeviceList::const_iterator inList = devices.find(USBDevice::computeUSBdeviceID(device)); | ||
| 37 | + | ||
| 38 | + if (inList != devices.end()) { | ||
| 39 | + inList->second->setFindIteration(findIteration); | ||
| 40 | + continue; | ||
| 41 | + } | ||
| 37 | 42 | ||
| 38 | for (DSOModel* model : supportedModels) { | 43 | for (DSOModel* model : supportedModels) { |
| 39 | // Check VID and PID for firmware flashed devices | 44 | // Check VID and PID for firmware flashed devices |
| 40 | - if (descriptor.idVendor == model->vendorID && descriptor.idProduct == model->productID) { | ||
| 41 | - devices.push_back(std::unique_ptr<USBDevice>(new USBDevice(model, device))); | ||
| 42 | - break; | ||
| 43 | - } | 45 | + bool supported = descriptor.idVendor == model->vendorID && descriptor.idProduct == model->productID; |
| 44 | // Devices without firmware have different VID/PIDs | 46 | // Devices without firmware have different VID/PIDs |
| 45 | - if (descriptor.idVendor == model->vendorIDnoFirmware && descriptor.idProduct == model->productIDnoFirmware) { | ||
| 46 | - devices.push_back(std::unique_ptr<USBDevice>(new USBDevice(model, device))); | ||
| 47 | - break; | 47 | + supported |= descriptor.idVendor == model->vendorIDnoFirmware && descriptor.idProduct == model->productIDnoFirmware; |
| 48 | + if (supported) { | ||
| 49 | + ++changes; | ||
| 50 | + devices[USBDevice::computeUSBdeviceID(device)] = std::unique_ptr<USBDevice>(new USBDevice(model, device, findIteration)); | ||
| 48 | } | 51 | } |
| 49 | } | 52 | } |
| 50 | } | 53 | } |
| 51 | 54 | ||
| 52 | - if (noAccessDeviceCount == deviceCount) { | ||
| 53 | - noAccessDevices = true; | ||
| 54 | - errorMessage = | ||
| 55 | - QCoreApplication::translate("", "Please make sure to have read/write access to your usb device. On " | ||
| 56 | - "linux you need to install the correct udev file for example."); | 55 | + // Remove non existing devices |
| 56 | + for (DeviceList::iterator it=devices.begin();it!=devices.end();) { | ||
| 57 | + if (it->second->getFindIteration() != findIteration) { | ||
| 58 | + ++changes; | ||
| 59 | + it = devices.erase(it); | ||
| 60 | + } else { | ||
| 61 | + ++it; | ||
| 62 | + } | ||
| 57 | } | 63 | } |
| 58 | 64 | ||
| 59 | libusb_free_device_list(deviceList, true); | 65 | libusb_free_device_list(deviceList, true); |
| 60 | - return devices; | 66 | + |
| 67 | + return changes; | ||
| 61 | } | 68 | } |
| 62 | 69 | ||
| 63 | -const QString &FindDevices::getErrorMessage() const { return errorMessage; } | 70 | +const FindDevices::DeviceList* FindDevices::getDevices() |
| 71 | +{ | ||
| 72 | + return &devices; | ||
| 73 | +} | ||
| 64 | 74 | ||
| 65 | -bool FindDevices::allDevicesNoAccessError() const { return noAccessDevices; } | 75 | +std::unique_ptr<USBDevice> FindDevices::takeDevice(UniqueUSBid id) |
| 76 | +{ | ||
| 77 | + DeviceList::iterator i = devices.find(id); | ||
| 78 | + if (i==devices.end()) return nullptr; | ||
| 79 | + return std::move(i->second); | ||
| 80 | +} |
openhantek/src/usb/finddevices.h
| @@ -4,6 +4,8 @@ | @@ -4,6 +4,8 @@ | ||
| 4 | 4 | ||
| 5 | #include <QString> | 5 | #include <QString> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | +#include <map> | ||
| 8 | +#include <list> | ||
| 7 | 9 | ||
| 8 | #include "definitions.h" | 10 | #include "definitions.h" |
| 9 | #include "usbdevice.h" | 11 | #include "usbdevice.h" |
| @@ -11,19 +13,30 @@ | @@ -11,19 +13,30 @@ | ||
| 11 | struct libusb_context; | 13 | struct libusb_context; |
| 12 | 14 | ||
| 13 | /** | 15 | /** |
| 14 | - * @brief Search for Hantek devices and connect to the selected one. | 16 | + * @brief Search for Hantek devices. |
| 17 | + * Use usually want to call `updateDeviceList` and then retrieve the list via `getDevices`. | ||
| 18 | + * You can call `updateDeviceList` as often as you want. | ||
| 19 | + * If you have found your favorite device, you want to call `takeDevice`. The device will | ||
| 20 | + * not be available in `getDevices` anymore and this will not change with calls to `updateDeviceList`. | ||
| 15 | * | 21 | * |
| 16 | - * At the moment this class connects to the first found devic automatically. | 22 | + * Do not close the given usb context before this class object is destroyed. |
| 17 | */ | 23 | */ |
| 18 | -class FindDevices { | 24 | +class FindDevices{ |
| 19 | public: | 25 | public: |
| 20 | - FindDevices(libusb_context *context = nullptr); | ||
| 21 | - std::list<std::unique_ptr<USBDevice>> findDevices(); | ||
| 22 | - const QString &getErrorMessage() const; | ||
| 23 | - bool allDevicesNoAccessError() const; | ||
| 24 | - | 26 | + typedef std::map<UniqueUSBid, std::unique_ptr<USBDevice>> DeviceList; |
| 27 | + FindDevices(libusb_context *context); | ||
| 28 | + /// Updates the device list. To clear the list, just dispose this object | ||
| 29 | + /// \return If negative it represents a libusb error code otherwise the amount of updates | ||
| 30 | + int updateDeviceList(); | ||
| 31 | + const DeviceList *getDevices(); | ||
| 32 | + /** | ||
| 33 | + * @brief takeDevice | ||
| 34 | + * @param id The unique usb id for the current bus layout | ||
| 35 | + * @return A shared reference to the | ||
| 36 | + */ | ||
| 37 | + std::unique_ptr<USBDevice> takeDevice(UniqueUSBid id); | ||
| 25 | private: | 38 | private: |
| 26 | libusb_context *context; ///< The usb context used for this device | 39 | libusb_context *context; ///< The usb context used for this device |
| 27 | - QString errorMessage; | ||
| 28 | - bool noAccessDevices = false; | 40 | + DeviceList devices; |
| 41 | + unsigned findIteration = 0; | ||
| 29 | }; | 42 | }; |
openhantek/src/usb/uploadFirmware.cpp
| @@ -14,6 +14,8 @@ | @@ -14,6 +14,8 @@ | ||
| 14 | 14 | ||
| 15 | #include "dsomodel.h" | 15 | #include "dsomodel.h" |
| 16 | 16 | ||
| 17 | +#define TR(str) QCoreApplication::translate("UploadFirmware", str) | ||
| 18 | + | ||
| 17 | bool UploadFirmware::startUpload(USBDevice *device) { | 19 | bool UploadFirmware::startUpload(USBDevice *device) { |
| 18 | if (device->isConnected() || !device->needsFirmware()) return false; | 20 | if (device->isConnected() || !device->needsFirmware()) return false; |
| 19 | 21 | ||
| @@ -22,7 +24,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | @@ -22,7 +24,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | ||
| 22 | int errorCode = libusb_open(device->getRawDevice(), &handle); | 24 | int errorCode = libusb_open(device->getRawDevice(), &handle); |
| 23 | if (errorCode != LIBUSB_SUCCESS) { | 25 | if (errorCode != LIBUSB_SUCCESS) { |
| 24 | handle = nullptr; | 26 | handle = nullptr; |
| 25 | - errorMessage = QCoreApplication::translate("", "Couldn't open device: %1").arg(libUsbErrorString(errorCode)); | 27 | + errorMessage = TR("Couldn't open device: %1").arg(libUsbErrorString(errorCode)); |
| 26 | return false; | 28 | return false; |
| 27 | } | 29 | } |
| 28 | 30 | ||
| @@ -41,7 +43,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | @@ -41,7 +43,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | ||
| 41 | libusb_set_auto_detach_kernel_driver(handle, 1); | 43 | libusb_set_auto_detach_kernel_driver(handle, 1); |
| 42 | int status = libusb_claim_interface(handle, 0); | 44 | int status = libusb_claim_interface(handle, 0); |
| 43 | if (status != LIBUSB_SUCCESS) { | 45 | if (status != LIBUSB_SUCCESS) { |
| 44 | - errorMessage = QString("libusb_claim_interface() failed: %1").arg(libusb_error_name(status)); | 46 | + errorMessage = TR("libusb_claim_interface() failed: %1").arg(libusb_error_name(status)); |
| 45 | libusb_close(handle); | 47 | libusb_close(handle); |
| 46 | return false; | 48 | return false; |
| 47 | } | 49 | } |
| @@ -50,7 +52,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | @@ -50,7 +52,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | ||
| 50 | status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 0); | 52 | status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 0); |
| 51 | 53 | ||
| 52 | if (status != LIBUSB_SUCCESS) { | 54 | if (status != LIBUSB_SUCCESS) { |
| 53 | - errorMessage = QString("ezusb_load_ram(loader_path) failed: %1").arg(libusb_error_name(status)); | 55 | + errorMessage = TR("Writing the loader firmware failed: %1").arg(libusb_error_name(status)); |
| 54 | libusb_release_interface(handle, 0); | 56 | libusb_release_interface(handle, 0); |
| 55 | libusb_close(handle); | 57 | libusb_close(handle); |
| 56 | return false; | 58 | return false; |
| @@ -60,7 +62,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | @@ -60,7 +62,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { | ||
| 60 | status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 1); | 62 | status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 1); |
| 61 | 63 | ||
| 62 | if (status != LIBUSB_SUCCESS) { | 64 | if (status != LIBUSB_SUCCESS) { |
| 63 | - errorMessage = QString("ezusb_load_ram(firmware_path) failed: %1").arg(libusb_error_name(status)); | 65 | + errorMessage = TR("Writing the main firmware failed: %1").arg(libusb_error_name(status)); |
| 64 | libusb_release_interface(handle, 0); | 66 | libusb_release_interface(handle, 0); |
| 65 | libusb_close(handle); | 67 | libusb_close(handle); |
| 66 | return false; | 68 | return false; |
| @@ -72,3 +74,4 @@ bool UploadFirmware::startUpload(USBDevice *device) { | @@ -72,3 +74,4 @@ bool UploadFirmware::startUpload(USBDevice *device) { | ||
| 72 | } | 74 | } |
| 73 | 75 | ||
| 74 | const QString &UploadFirmware::getErrorMessage() const { return errorMessage; } | 76 | const QString &UploadFirmware::getErrorMessage() const { return errorMessage; } |
| 77 | + |
openhantek/src/usb/uploadFirmware.h
| @@ -14,7 +14,6 @@ class UploadFirmware { | @@ -14,7 +14,6 @@ class UploadFirmware { | ||
| 14 | public: | 14 | public: |
| 15 | bool startUpload(USBDevice *device); | 15 | bool startUpload(USBDevice *device); |
| 16 | const QString &getErrorMessage() const; | 16 | const QString &getErrorMessage() const; |
| 17 | - | ||
| 18 | private: | 17 | private: |
| 19 | QString errorMessage; | 18 | QString errorMessage; |
| 20 | }; | 19 | }; |
openhantek/src/usb/usbdevice.cpp
| @@ -11,8 +11,14 @@ | @@ -11,8 +11,14 @@ | ||
| 11 | #include "models.h" | 11 | #include "models.h" |
| 12 | #include "utils/printutils.h" | 12 | #include "utils/printutils.h" |
| 13 | 13 | ||
| 14 | +UniqueUSBid USBDevice::computeUSBdeviceID(libusb_device *device) { | ||
| 15 | + UniqueUSBid v=0; | ||
| 16 | + libusb_get_port_numbers(device, (uint8_t*)&v, sizeof(v)); | ||
| 17 | + return v; | ||
| 18 | +} | ||
| 14 | 19 | ||
| 15 | -USBDevice::USBDevice(DSOModel *model, libusb_device *device) : model(model), device(device) { | 20 | +USBDevice::USBDevice(DSOModel *model, libusb_device *device, unsigned findIteration) : |
| 21 | + model(model), device(device), findIteration(findIteration), uniqueUSBdeviceID(computeUSBdeviceID(device)) { | ||
| 16 | libusb_ref_device(device); | 22 | libusb_ref_device(device); |
| 17 | libusb_get_device_descriptor(device, &descriptor); | 23 | libusb_get_device_descriptor(device, &descriptor); |
| 18 | } | 24 | } |
| @@ -59,7 +65,10 @@ bool USBDevice::connectDevice(QString &errorMessage) { | @@ -59,7 +65,10 @@ bool USBDevice::connectDevice(QString &errorMessage) { | ||
| 59 | return true; | 65 | return true; |
| 60 | } | 66 | } |
| 61 | 67 | ||
| 62 | -USBDevice::~USBDevice() { connectionLost(); } | 68 | +USBDevice::~USBDevice() { |
| 69 | + disconnectFromDevice(); | ||
| 70 | + device = nullptr; | ||
| 71 | +} | ||
| 63 | 72 | ||
| 64 | int USBDevice::claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn) { | 73 | int USBDevice::claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn) { |
| 65 | int errorCode = libusb_claim_interface(this->handle, interfaceDescriptor->bInterfaceNumber); | 74 | int errorCode = libusb_claim_interface(this->handle, interfaceDescriptor->bInterfaceNumber); |
| @@ -82,7 +91,8 @@ int USBDevice::claimInterface(const libusb_interface_descriptor *interfaceDescri | @@ -82,7 +91,8 @@ int USBDevice::claimInterface(const libusb_interface_descriptor *interfaceDescri | ||
| 82 | return LIBUSB_SUCCESS; | 91 | return LIBUSB_SUCCESS; |
| 83 | } | 92 | } |
| 84 | 93 | ||
| 85 | -void USBDevice::connectionLost() { | 94 | +void USBDevice::disconnectFromDevice() { |
| 95 | + if (!device) return; | ||
| 86 | libusb_unref_device(device); | 96 | libusb_unref_device(device); |
| 87 | 97 | ||
| 88 | if (!this->handle) return; | 98 | if (!this->handle) return; |
| @@ -93,7 +103,7 @@ void USBDevice::connectionLost() { | @@ -93,7 +103,7 @@ void USBDevice::connectionLost() { | ||
| 93 | 103 | ||
| 94 | // Close device handle | 104 | // Close device handle |
| 95 | libusb_close(this->handle); | 105 | libusb_close(this->handle); |
| 96 | - this->handle = 0; | 106 | + this->handle = nullptr; |
| 97 | 107 | ||
| 98 | emit deviceDisconnected(); | 108 | emit deviceDisconnected(); |
| 99 | } | 109 | } |
| @@ -104,6 +114,16 @@ bool USBDevice::needsFirmware() { | @@ -104,6 +114,16 @@ bool USBDevice::needsFirmware() { | ||
| 104 | return this->descriptor.idProduct != model->productID || this->descriptor.idVendor != model->vendorID; | 114 | return this->descriptor.idProduct != model->productID || this->descriptor.idVendor != model->vendorID; |
| 105 | } | 115 | } |
| 106 | 116 | ||
| 117 | +void USBDevice::setFindIteration(unsigned iteration) | ||
| 118 | +{ | ||
| 119 | + findIteration = iteration; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +unsigned USBDevice::getFindIteration() const | ||
| 123 | +{ | ||
| 124 | + return findIteration; | ||
| 125 | +} | ||
| 126 | + | ||
| 107 | int USBDevice::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts, | 127 | int USBDevice::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts, |
| 108 | unsigned int timeout) { | 128 | unsigned int timeout) { |
| 109 | if (!this->handle) return LIBUSB_ERROR_NO_DEVICE; | 129 | if (!this->handle) return LIBUSB_ERROR_NO_DEVICE; |
| @@ -113,7 +133,7 @@ int USBDevice::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigne | @@ -113,7 +133,7 @@ int USBDevice::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigne | ||
| 113 | for (int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt) | 133 | for (int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt) |
| 114 | errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, timeout); | 134 | errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, timeout); |
| 115 | 135 | ||
| 116 | - if (errorCode == LIBUSB_ERROR_NO_DEVICE) connectionLost(); | 136 | + if (errorCode == LIBUSB_ERROR_NO_DEVICE) disconnectFromDevice(); |
| 117 | if (errorCode < 0) | 137 | if (errorCode < 0) |
| 118 | return errorCode; | 138 | return errorCode; |
| 119 | else | 139 | else |
| @@ -211,7 +231,7 @@ int USBDevice::controlTransfer(unsigned char type, unsigned char request, unsign | @@ -211,7 +231,7 @@ int USBDevice::controlTransfer(unsigned char type, unsigned char request, unsign | ||
| 211 | for (int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt) | 231 | for (int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt) |
| 212 | errorCode = libusb_control_transfer(this->handle, type, request, value, index, data, length, HANTEK_TIMEOUT); | 232 | errorCode = libusb_control_transfer(this->handle, type, request, value, index, data, length, HANTEK_TIMEOUT); |
| 213 | 233 | ||
| 214 | - if (errorCode == LIBUSB_ERROR_NO_DEVICE) connectionLost(); | 234 | + if (errorCode == LIBUSB_ERROR_NO_DEVICE) disconnectFromDevice(); |
| 215 | return errorCode; | 235 | return errorCode; |
| 216 | } | 236 | } |
| 217 | 237 | ||
| @@ -276,6 +296,11 @@ int USBDevice::getPacketSize() { | @@ -276,6 +296,11 @@ int USBDevice::getPacketSize() { | ||
| 276 | 296 | ||
| 277 | libusb_device *USBDevice::getRawDevice() const { return device; } | 297 | libusb_device *USBDevice::getRawDevice() const { return device; } |
| 278 | 298 | ||
| 299 | +unsigned long USBDevice::getUniqueUSBDeviceID() const | ||
| 300 | +{ | ||
| 301 | + return uniqueUSBdeviceID; | ||
| 302 | +} | ||
| 303 | + | ||
| 279 | const DSOModel* USBDevice::getModel() const { return model; } | 304 | const DSOModel* USBDevice::getModel() const { return model; } |
| 280 | 305 | ||
| 281 | void USBDevice::setEnableBulkTransfer(bool enable) { allowBulkTransfer = enable; } | 306 | void USBDevice::setEnableBulkTransfer(bool enable) { allowBulkTransfer = enable; } |
openhantek/src/usb/usbdevice.h
| @@ -14,21 +14,31 @@ | @@ -14,21 +14,31 @@ | ||
| 14 | 14 | ||
| 15 | class DSOModel; | 15 | class DSOModel; |
| 16 | 16 | ||
| 17 | +typedef unsigned long UniqueUSBid; | ||
| 18 | + | ||
| 17 | /// \brief This class handles the USB communication with an usb device that has | 19 | /// \brief This class handles the USB communication with an usb device that has |
| 18 | /// one in and one out endpoint. | 20 | /// one in and one out endpoint. |
| 19 | class USBDevice : public QObject { | 21 | class USBDevice : public QObject { |
| 20 | Q_OBJECT | 22 | Q_OBJECT |
| 21 | 23 | ||
| 22 | public: | 24 | public: |
| 23 | - USBDevice(DSOModel* model, libusb_device *device); | 25 | + USBDevice(DSOModel* model, libusb_device *device, unsigned findIteration = 0); |
| 24 | ~USBDevice(); | 26 | ~USBDevice(); |
| 25 | bool connectDevice(QString &errorMessage); | 27 | bool connectDevice(QString &errorMessage); |
| 28 | + void disconnectFromDevice(); | ||
| 26 | 29 | ||
| 27 | /// \brief Check if the oscilloscope is connected. | 30 | /// \brief Check if the oscilloscope is connected. |
| 28 | /// \return true, if a connection is up. | 31 | /// \return true, if a connection is up. |
| 29 | bool isConnected(); | 32 | bool isConnected(); |
| 30 | bool needsFirmware(); | 33 | bool needsFirmware(); |
| 31 | 34 | ||
| 35 | + /** | ||
| 36 | + * Keep track of the find iteration on which this device was found | ||
| 37 | + * @param iteration The new iteration value | ||
| 38 | + */ | ||
| 39 | + void setFindIteration(unsigned iteration); | ||
| 40 | + unsigned getFindIteration() const; | ||
| 41 | + | ||
| 32 | // Various methods to handle USB transfers | 42 | // Various methods to handle USB transfers |
| 33 | 43 | ||
| 34 | /// \brief Bulk transfer to/from the oscilloscope. | 44 | /// \brief Bulk transfer to/from the oscilloscope. |
| @@ -57,16 +67,31 @@ class USBDevice : public QObject { | @@ -57,16 +67,31 @@ class USBDevice : public QObject { | ||
| 57 | int getConnectionSpeed(); | 67 | int getConnectionSpeed(); |
| 58 | int getPacketSize(); | 68 | int getPacketSize(); |
| 59 | 69 | ||
| 70 | + /** | ||
| 71 | + * @return Returns the raw libusb device | ||
| 72 | + */ | ||
| 60 | libusb_device *getRawDevice() const; | 73 | libusb_device *getRawDevice() const; |
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * @return Return the unique usb device id {@link USBDevice::computeUSBdeviceID()}. | ||
| 77 | + */ | ||
| 78 | + unsigned long getUniqueUSBDeviceID() const; | ||
| 79 | + /** | ||
| 80 | + * The USB bus is organised in a tree hierarchy. A device is connected to a port on a bus device, | ||
| 81 | + * which is connected to a port on another bus device etc up to the root usb device. | ||
| 82 | + * | ||
| 83 | + * The USB 3.0 standard allows up to 7 levels with 256 devices on each level (1 Byte). We generate | ||
| 84 | + * a unique number for the connected device. | ||
| 85 | + */ | ||
| 86 | + static UniqueUSBid computeUSBdeviceID(libusb_device *device); | ||
| 87 | + | ||
| 61 | /// \brief Get the oscilloscope model. | 88 | /// \brief Get the oscilloscope model. |
| 62 | /// \return The ::Model of the connected Hantek DSO. | 89 | /// \return The ::Model of the connected Hantek DSO. |
| 63 | const DSOModel *getModel() const; | 90 | const DSOModel *getModel() const; |
| 64 | void setEnableBulkTransfer(bool enable); | 91 | void setEnableBulkTransfer(bool enable); |
| 65 | void overwriteInPacketLength(int len); | 92 | void overwriteInPacketLength(int len); |
| 66 | - | ||
| 67 | protected: | 93 | protected: |
| 68 | int claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn); | 94 | int claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn); |
| 69 | - void connectionLost(); | ||
| 70 | 95 | ||
| 71 | // Command buffers | 96 | // Command buffers |
| 72 | ControlBeginCommand beginCommandControl; | 97 | ControlBeginCommand beginCommandControl; |
| @@ -76,6 +101,8 @@ class USBDevice : public QObject { | @@ -76,6 +101,8 @@ class USBDevice : public QObject { | ||
| 76 | struct libusb_device_descriptor descriptor; | 101 | struct libusb_device_descriptor descriptor; |
| 77 | libusb_device *device; ///< The USB handle for the oscilloscope | 102 | libusb_device *device; ///< The USB handle for the oscilloscope |
| 78 | libusb_device_handle *handle = nullptr; | 103 | libusb_device_handle *handle = nullptr; |
| 104 | + unsigned findIteration; | ||
| 105 | + const unsigned long uniqueUSBdeviceID; | ||
| 79 | int interface; | 106 | int interface; |
| 80 | int outPacketLength; ///< Packet length for the OUT endpoint | 107 | int outPacketLength; ///< Packet length for the OUT endpoint |
| 81 | int inPacketLength; ///< Packet length for the IN endpoint | 108 | int inPacketLength; ///< Packet length for the IN endpoint |