From b647ee2abfb3c3c0a743f9c7810f7b6ebcb96e7c Mon Sep 17 00:00:00 2001 From: Sergey Date: Wed, 26 Oct 2016 20:20:42 +0300 Subject: [PATCH] Qt project for usb relay hid library with simple GUI client (#13) * Added Qt interface to Usb Relay Hid - by sergboec 1) Added Qt based solution to build dynamic linked library 2) Added simple Qt Widgets based client to manage devices * [f] beautifying and changes in pro file for linux build --- qt/QUsbRelay/QUsbRelay.pro | 29 ++++++ qt/QUsbRelayGui/QUsbRelayGui.pro | 38 ++++++++ qt/QUsbRelayGui/device.cpp | 50 ++++++++++ qt/QUsbRelayGui/device.h | 46 +++++++++ qt/QUsbRelayGui/device.ui | 98 +++++++++++++++++++ qt/QUsbRelayGui/device_and_hardware_w.ico | Bin 0 -> 19518 bytes qt/QUsbRelayGui/main.cpp | 36 +++++++ qt/QUsbRelayGui/resources.qrc | 5 + qt/QUsbRelayGui/widget.cpp | 80 ++++++++++++++++ qt/QUsbRelayGui/widget.h | 109 ++++++++++++++++++++++ qt/QUsbRelayGui/widget.ui | 31 ++++++ qt/qusbrelayproject.pro | 5 + 12 files changed, 527 insertions(+) create mode 100644 qt/QUsbRelay/QUsbRelay.pro create mode 100644 qt/QUsbRelayGui/QUsbRelayGui.pro create mode 100644 qt/QUsbRelayGui/device.cpp create mode 100644 qt/QUsbRelayGui/device.h create mode 100644 qt/QUsbRelayGui/device.ui create mode 100644 qt/QUsbRelayGui/device_and_hardware_w.ico create mode 100644 qt/QUsbRelayGui/main.cpp create mode 100644 qt/QUsbRelayGui/resources.qrc create mode 100644 qt/QUsbRelayGui/widget.cpp create mode 100644 qt/QUsbRelayGui/widget.h create mode 100644 qt/QUsbRelayGui/widget.ui create mode 100644 qt/qusbrelayproject.pro diff --git a/qt/QUsbRelay/QUsbRelay.pro b/qt/QUsbRelay/QUsbRelay.pro new file mode 100644 index 0000000..3e473aa --- /dev/null +++ b/qt/QUsbRelay/QUsbRelay.pro @@ -0,0 +1,29 @@ +QT -= core gui + +TARGET = usb_relay_device +TEMPLATE = lib +CONFIG += dll + +SOURCES += ../../lib/usb_relay_lib.c +win32{ + SOURCES += ../../commandline/hiddata_mswin.c +} +unix{ + SOURCES += ../../commandline/hiddata_libusb01.c +} + +HEADERS += ../../lib/usb_relay_device.h \ + ../../lib/usb_relay_hw.h \ + ../../commandline/hiddata.h + +INCLUDEPATH += ../../lib/usb-relay-dll/ +INCLUDEPATH += ../../commandline/ + +win32{ + INCLUDEPATH += C:/Program Files (x86)/Windows Kits/8.0/Include/ +} + +unix:{ +CONFIG += link_pkgconfig +PKGCONFIG += libusb +} diff --git a/qt/QUsbRelayGui/QUsbRelayGui.pro b/qt/QUsbRelayGui/QUsbRelayGui.pro new file mode 100644 index 0000000..d2a2e4b --- /dev/null +++ b/qt/QUsbRelayGui/QUsbRelayGui.pro @@ -0,0 +1,38 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-10-02T19:08:35 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = QUsbRelayGui +TEMPLATE = app + + +SOURCES += main.cpp\ + widget.cpp \ + device.cpp + +HEADERS += widget.h \ + device.h + +FORMS += widget.ui \ + device.ui + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../QUsbRelay/release/ -lusb_relay_device +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../QUsbRelay/debug/ -lusb_relay_device +else:unix: LIBS += -L$$OUT_PWD/../QUsbRelay/ -lusb_relay_device + +INCLUDEPATH += $$PWD/../QUsbRelay +DEPENDPATH += $$PWD/../QUsbRelay + +INCLUDEPATH += $$PWD/../../lib +DEPENDPATH += $$PWD/../../lib + +RESOURCES += \ + resources.qrc + +win32: RC_ICONS = device_and_hardware_w.ico diff --git a/qt/QUsbRelayGui/device.cpp b/qt/QUsbRelayGui/device.cpp new file mode 100644 index 0000000..4125f46 --- /dev/null +++ b/qt/QUsbRelayGui/device.cpp @@ -0,0 +1,50 @@ +#include "device.h" +#include "ui_device.h" + +Device::Device(qint16 index, QWidget *parent, QString name, QString serial, quint16 channelCount, QVector status) : + QWidget(parent), + ui(new Ui::device), + _index(index) +{ + ui->setupUi(this); + + ui->device_channel_count_value->setText(QString::number(channelCount)); + ui->device_name_value->setText(name); + ui->device_serial_value->setText(serial); + + connect(ui->device_close_all,&QPushButton::clicked,[this](){ + changeChannelStatus(false); + emit closeAllSignal(this->_index); + }); + + connect(ui->device_open_all,&QPushButton::clicked,[this](){ + changeChannelStatus(true); + emit openAllSignal(this->_index); + }); + + + QVBoxLayout *vbox = new QVBoxLayout; + for(auto i=1;i_index, state,i); + }); + checkBox->setChecked(status[i-1]); + vbox->addWidget(checkBox); + } + + ui->channels_windget->setLayout(vbox); +} + +Device::~Device() +{ + delete ui; +} + +void Device::changeChannelStatus(bool status) +{ + QList allCButtons = this->ui->channels_windget->findChildren(); + for(const auto& i:allCButtons){ + i->setChecked(status); + } +} diff --git a/qt/QUsbRelayGui/device.h b/qt/QUsbRelayGui/device.h new file mode 100644 index 0000000..61f3602 --- /dev/null +++ b/qt/QUsbRelayGui/device.h @@ -0,0 +1,46 @@ +#ifndef DEVICE_H +#define DEVICE_H + +#include +#include +#include +#include + +namespace Ui { +class device; +} + +class Device : public QWidget +{ + Q_OBJECT +public: + explicit Device(qint16 index, QWidget *parent = 0,QString name="", QString serial="", quint16 channelCount=0, QVector status = {}); + ~Device(); +signals: + /*! + * \brief openAllSignal signaling about opening all channels in device with id passed as parameter + */ + void openAllSignal(qint16); + /*! + * \brief closeAllSignal signaling about closing all channels in device with id passed as parameter + */ + void closeAllSignal(qint16); + /*! + * \brief changeChannelState signaling aboud changing state of one channel in device with id passed as parameter + * \param handle device handle + * \param state state open\closed + * \param channel device channel number + */ + void changeChannelState(qint16 handle,bool state,int channel); + +private: + Ui::device *ui; + qint16 _index; + /*! + * \brief changeChannelStatus heper functions - changes view for all channels at device + * \param status + */ + void changeChannelStatus(bool status); +}; + +#endif // DEVICE_H diff --git a/qt/QUsbRelayGui/device.ui b/qt/QUsbRelayGui/device.ui new file mode 100644 index 0000000..80d6532 --- /dev/null +++ b/qt/QUsbRelayGui/device.ui @@ -0,0 +1,98 @@ + + + device + + + + 0 + 0 + 318 + 227 + + + + Form + + + + + + + + Device Name + + + + + + + + + + + + + + Device Serial Number + + + + + + + + + + + + + + Device Channel Count + + + + + + + + + + + + + + + + Open All + + + + + + + Close All + + + + + + + true + + + + + 0 + 0 + 298 + 90 + + + + + + + + + + diff --git a/qt/QUsbRelayGui/device_and_hardware_w.ico b/qt/QUsbRelayGui/device_and_hardware_w.ico new file mode 100644 index 0000000000000000000000000000000000000000..216154c34130351349d2f89c5860355ef1b74b4e GIT binary patch literal 19518 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 aW%SJSeg{_<&G=OqmnlkZ3M=uyS@<7(P!God literal 0 HcmV?d00001 diff --git a/qt/QUsbRelayGui/main.cpp b/qt/QUsbRelayGui/main.cpp new file mode 100644 index 0000000..3387e67 --- /dev/null +++ b/qt/QUsbRelayGui/main.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include "widget.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + qApp->setStyle(QStyleFactory::create("Fusion")); + + QPalette darkPalette; + darkPalette.setColor(QPalette::Window, QColor(53,53,53)); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(25,25,25)); + darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); + darkPalette.setColor(QPalette::ToolTipBase, Qt::white); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, QColor(53,53,53)); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); + + darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::HighlightedText, Qt::black); + + qApp->setPalette(darkPalette); + + qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"); + + Widget w; + w.show(); + + return a.exec(); +} diff --git a/qt/QUsbRelayGui/resources.qrc b/qt/QUsbRelayGui/resources.qrc new file mode 100644 index 0000000..f56a81d --- /dev/null +++ b/qt/QUsbRelayGui/resources.qrc @@ -0,0 +1,5 @@ + + + device_and_hardware_w.ico + + diff --git a/qt/QUsbRelayGui/widget.cpp b/qt/QUsbRelayGui/widget.cpp new file mode 100644 index 0000000..9df9606 --- /dev/null +++ b/qt/QUsbRelayGui/widget.cpp @@ -0,0 +1,80 @@ +#include "widget.h" +#include "ui_widget.h" + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + + list.searchForDevices(); + + for(auto i=0; i< list.m_devices.size();i++){ + + getRelayStatus(i); + + auto dev = list.m_devices[i]; + + //Device has qobject pointer to this and will be deleated by qt system + Device* k = new Device(i,this,dev.m_name,dev.m_serialNumber,dev.m_channelsNumber,dev.m_channelsStatus); + + connect(k,&Device::closeAllSignal,this,&Widget::onSomeonWantCloseAll); + connect(k,&Device::openAllSignal,this,&Widget::onSomeonWantOpenAll); + connect(k,&Device::changeChannelState,this,&Widget::onSomeoneWantToDoAnythingWithChannel); + + QListWidgetItem* j = new QListWidgetItem(); + j->setSizeHint(k->size()); + + listWidgetsVector.push_back(j); + + ui->listWidget->addItem(j); + ui->listWidget->setItemWidget(j,k); + } +} + +Widget::~Widget() +{ + delete ui; + for(auto& i: listWidgetsVector){ + delete i; + } +} + +void Widget::getRelayStatus(int value) +{ + auto handle = usb_relay_device_open(list.m_devices[value].m_raw_pointer); + unsigned int status; + usb_relay_device_get_status(handle,&status); + QVector tmp; + tmp.resize(list.m_devices[value].m_channelsNumber); + for (int j = 0; j < list.m_devices[value].m_channelsNumber ; ++j){ + tmp[j] = 0 != (status & (1 << j)); + } + list.m_devices[value].m_channelsStatus = tmp; + usb_relay_device_close(handle); +} + +void Widget::onSomeonWantCloseAll(qint16 value) +{ + auto handle = usb_relay_device_open(list.m_devices[value].m_raw_pointer); + usb_relay_device_close_all_relay_channel(handle); + usb_relay_device_close(handle); +} + +void Widget::onSomeonWantOpenAll(qint16 value) +{ + auto handle = usb_relay_device_open(list.m_devices[value].m_raw_pointer); + usb_relay_device_open_all_relay_channel(handle); + usb_relay_device_close(handle); +} + +void Widget::onSomeoneWantToDoAnythingWithChannel(qint16 value, bool state, int channel) +{ + auto handle = usb_relay_device_open(list.m_devices[value].m_raw_pointer); + if(state){ + usb_relay_device_open_one_relay_channel(handle,channel); + }else{ + usb_relay_device_close_one_relay_channel(handle,channel); + } + usb_relay_device_close(handle); +} diff --git a/qt/QUsbRelayGui/widget.h b/qt/QUsbRelayGui/widget.h new file mode 100644 index 0000000..86805f8 --- /dev/null +++ b/qt/QUsbRelayGui/widget.h @@ -0,0 +1,109 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "device.h" + +#include + +/*! + * \brief The DeviceInfo class stores anything we need to know about usb relay device + */ +class DeviceInfo{ +public: + DeviceInfo() = default; + DeviceInfo(QString nm, QString sn, quint16 cn, usb_relay_device_info* rp, QString cun): + m_name(nm), + m_serialNumber(sn), + m_channelsNumber(cn), + m_raw_pointer(rp), + m_customName(cun) + { + } + + QString m_name; + QString m_serialNumber; + quint16 m_channelsNumber; + usb_relay_device_info* m_raw_pointer; + QString m_customName; + QVector m_channelsStatus; +}; + +Q_DECLARE_METATYPE(DeviceInfo) + + +class DeviceList +{ +public: + DeviceList() = default; + + void searchForDevices(){ + auto device = usb_relay_device_enumerate(); + if(device == nullptr){ + m_devices.clear(); + return; + } + bool hasNext = true; + while(hasNext){ + m_devices.push_back(DeviceInfo(device->device_path,device->serial_number,device->type,device,"")); + + if(device->next != nullptr){ + device++; + }else{ + hasNext = false; + } + } + } + + ~DeviceList() = default; + + std::vector m_devices; +}; + + +namespace Ui { + class Widget; +} + +/*! + * \brief The Widget class main idea - share device id as an index in DeviceList vector + */ +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = 0); + ~Widget(); + +private: + Ui::Widget *ui; + DeviceList list; + + QVector listWidgetsVector; + + void getRelayStatus(int); + +private slots: + /*! + * \brief onSomeonWantCloseAll + * \param value device id - see brief of a class + */ + void onSomeonWantCloseAll(qint16 value); + /*! + * \brief onSomeonWantOpenAll + * \param value device id - see brief of a class + */ + void onSomeonWantOpenAll(qint16 value); + void onSomeoneWantToDoAnythingWithChannel(qint16 value,bool state,int channel); + +}; + +#endif // WIDGET_H diff --git a/qt/QUsbRelayGui/widget.ui b/qt/QUsbRelayGui/widget.ui new file mode 100644 index 0000000..b073742 --- /dev/null +++ b/qt/QUsbRelayGui/widget.ui @@ -0,0 +1,31 @@ + + + Widget + + + + 0 + 0 + 400 + 300 + + + + UsbRelayGui + + + + :/images/device_and_hardware_w.ico:/images/device_and_hardware_w.ico + + + + + + + + + + + + + diff --git a/qt/qusbrelayproject.pro b/qt/qusbrelayproject.pro new file mode 100644 index 0000000..fd3a566 --- /dev/null +++ b/qt/qusbrelayproject.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + QUsbRelay \ + QUsbRelayGui -- 2.25.1