Qt project for usb relay hid library with simple GUI client (#13)
authorSergey <sergboec@gmail.com>
Wed, 26 Oct 2016 17:20:42 +0000 (20:20 +0300)
committerPavel A <pavel-a@users.noreply.github.com>
Wed, 26 Oct 2016 17:20:42 +0000 (20:20 +0300)
* 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

12 files changed:
qt/QUsbRelay/QUsbRelay.pro [new file with mode: 0644]
qt/QUsbRelayGui/QUsbRelayGui.pro [new file with mode: 0644]
qt/QUsbRelayGui/device.cpp [new file with mode: 0644]
qt/QUsbRelayGui/device.h [new file with mode: 0644]
qt/QUsbRelayGui/device.ui [new file with mode: 0644]
qt/QUsbRelayGui/device_and_hardware_w.ico [new file with mode: 0644]
qt/QUsbRelayGui/main.cpp [new file with mode: 0644]
qt/QUsbRelayGui/resources.qrc [new file with mode: 0644]
qt/QUsbRelayGui/widget.cpp [new file with mode: 0644]
qt/QUsbRelayGui/widget.h [new file with mode: 0644]
qt/QUsbRelayGui/widget.ui [new file with mode: 0644]
qt/qusbrelayproject.pro [new file with mode: 0644]

diff --git a/qt/QUsbRelay/QUsbRelay.pro b/qt/QUsbRelay/QUsbRelay.pro
new file mode 100644 (file)
index 0000000..3e473aa
--- /dev/null
@@ -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 (file)
index 0000000..d2a2e4b
--- /dev/null
@@ -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 (file)
index 0000000..4125f46
--- /dev/null
@@ -0,0 +1,50 @@
+#include "device.h"
+#include "ui_device.h"
+
+Device::Device(qint16 index, QWidget *parent, QString name, QString serial, quint16 channelCount, QVector<bool> 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<channelCount+1;i++){
+        QCheckBox *checkBox = new QCheckBox(QString("Channel %1").arg(i),this);
+        connect(checkBox, &QCheckBox::clicked,[this,i](bool state){
+            emit changeChannelState(this->_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<QCheckBox *> allCButtons = this->ui->channels_windget->findChildren<QCheckBox *>();
+    for(const auto& i:allCButtons){
+        i->setChecked(status);
+    }
+}
diff --git a/qt/QUsbRelayGui/device.h b/qt/QUsbRelayGui/device.h
new file mode 100644 (file)
index 0000000..61f3602
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DEVICE_H
+#define DEVICE_H
+
+#include <QWidget>
+#include <QCheckBox>
+#include <QSignalMapper>
+#include <QDebug>
+
+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<bool> 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 (file)
index 0000000..80d6532
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>device</class>
+ <widget class="QWidget" name="device">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>318</width>
+    <height>227</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="device_name">
+       <property name="text">
+        <string>Device Name</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="device_name_value">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="device_serial_number">
+       <property name="text">
+        <string>Device Serial Number</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLabel" name="device_serial_value">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="device_channel_count">
+       <property name="text">
+        <string>Device Channel Count</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLabel" name="device_channel_count_value">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QPushButton" name="device_open_all">
+     <property name="text">
+      <string>Open All</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="device_close_all">
+     <property name="text">
+      <string>Close All</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QScrollArea" name="scrollArea">
+     <property name="widgetResizable">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="channels_windget">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>298</width>
+        <height>90</height>
+       </rect>
+      </property>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/qt/QUsbRelayGui/device_and_hardware_w.ico b/qt/QUsbRelayGui/device_and_hardware_w.ico
new file mode 100644 (file)
index 0000000..216154c
Binary files /dev/null and b/qt/QUsbRelayGui/device_and_hardware_w.ico differ
diff --git a/qt/QUsbRelayGui/main.cpp b/qt/QUsbRelayGui/main.cpp
new file mode 100644 (file)
index 0000000..3387e67
--- /dev/null
@@ -0,0 +1,36 @@
+#include <QApplication>
+#include <QStyleFactory>
+
+#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 (file)
index 0000000..f56a81d
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/images">
+        <file>device_and_hardware_w.ico</file>
+    </qresource>
+</RCC>
diff --git a/qt/QUsbRelayGui/widget.cpp b/qt/QUsbRelayGui/widget.cpp
new file mode 100644 (file)
index 0000000..9df9606
--- /dev/null
@@ -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<bool> 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 (file)
index 0000000..86805f8
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <QWidget>
+#include <QAbstractListModel>
+#include <QAbstractItemDelegate>
+#include <QPainter>
+#include <QApplication>
+#include <QStyledItemDelegate>
+#include <QSignalMapper>
+#include <QListWidgetItem>
+#include "device.h"
+
+#include <usb_relay_device.h>
+
+/*!
+ * \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<bool> 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<DeviceInfo> 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<QListWidgetItem*> 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 (file)
index 0000000..b073742
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="QWidget" name="Widget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>UsbRelayGui</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="resources.qrc">
+    <normaloff>:/images/device_and_hardware_w.ico</normaloff>:/images/device_and_hardware_w.ico</iconset>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QListWidget" name="listWidget"/>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources>
+  <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/qt/qusbrelayproject.pro b/qt/qusbrelayproject.pro
new file mode 100644 (file)
index 0000000..fd3a566
--- /dev/null
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+SUBDIRS += \
+    QUsbRelay \
+    QUsbRelayGui