From e87470d14ebe9800acc5e4d63cfe667caa9efbcc Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm Date: Mon, 25 Aug 2025 17:01:34 +0200 Subject: [PATCH] inial commit --- CMakeLists.txt | 50 ++++++++++++++++++++++ channelwidget.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++ channelwidget.h | 49 +++++++++++++++++++++ main.cpp | 10 +++++ mainwindow.cpp | 68 +++++++++++++++++++++++++++++ mainwindow.h | 31 ++++++++++++++ mainwindow.ui | 68 +++++++++++++++++++++++++++++ multiplexer.cpp | 16 +++++++ multiplexer.h | 22 ++++++++++ scripts/release-win.sh | 61 ++++++++++++++++++++++++++ 10 files changed, 472 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 channelwidget.cpp create mode 100644 channelwidget.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 multiplexer.cpp create mode 100644 multiplexer.h create mode 100755 scripts/release-win.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e86a2c3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.14) + +project(eismuliplexer-qt) + +set(CMAKE_PROJECT_VERSION_MAJOR 0) +set(CMAKE_PROJECT_VERSION_MINOR 9) +set(CMAKE_PROJECT_VERSION_PATCH 0) + +add_compile_definitions(VERSION_MAJOR=${CMAKE_PROJECT_VERSION_MAJOR}) +add_compile_definitions(VERSION_MINOR=${CMAKE_PROJECT_VERSION_MINOR}) +add_compile_definitions(VERSION_PATCH=${CMAKE_PROJECT_VERSION_PATCH}) + +if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") + message(FATAL_ERROR "Windows builds have to be cross compiled on UNIX") +endif() + +message("Platform " ${CMAKE_SYSTEM_NAME}) +if(WIN32) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/release-win.sh ${CMAKE_CURRENT_BINARY_DIR}/release.sh @ONLY) + add_custom_target(package + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/release.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Createing release archive" + VERBATIM) +endif(WIN32) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(EISMULIPLEXER REQUIRED eismuliplexer) +find_package(Qt6 REQUIRED COMPONENTS Widgets) +find_package(Qt6 REQUIRED COMPONENTS Core) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) + +add_executable(${PROJECT_NAME} + main.cpp + channelwidget.cpp + channelwidget.h + mainwindow.h + mainwindow.cpp + mainwindow.ui + multiplexer.h + multiplexer.cpp +) +target_compile_options(${PROJECT_NAME} PUBLIC "-Wall") +target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Core ${EISMULIPLEXER_LIBRARIES}) +#target_include_directories(${PROJECT_NAME} PUBLIC ${EISMULIPLEXER_INCLUDE_DIRS}) diff --git a/channelwidget.cpp b/channelwidget.cpp new file mode 100644 index 0000000..ae259fc --- /dev/null +++ b/channelwidget.cpp @@ -0,0 +1,97 @@ +#include "channelwidget.h" +#include +#include + +ChannelWidget::ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber, + std::shared_ptr multiplexer, + QWidget *parent) + : + QWidget(parent), + deviceSerial(deviceSerial), + channelNumber(channelNumber), + multiplexer(multiplexer), + checkbox("Enable"), + devicelabel(QString::asprintf("Device %04u", deviceSerial)), + channellabel(QString::asprintf("Channel %u", channelNumber)), + ganglabel("Ganged:") +{ + hlayout.addLayout(&labellayout); + vlayout.addLayout(&hlayout); + + labellayout.addWidget(&devicelabel); + labellayout.addWidget(&channellabel); + + line.setGeometry(QRect(320, 150, 118, 3)); + line.setFrameShape(QFrame::HLine); + line.setFrameShadow(QFrame::Sunken); + vlayout.addWidget(&line); + + gangcombo.addItem("Unganged"); + + hlayout.addStretch(); + hlayout.addWidget(&ganglabel); + hlayout.addWidget(&gangcombo); + hlayout.addWidget(&checkbox); + connect(&checkbox, &QCheckBox::toggled, this, &ChannelWidget::onChannelToggled); + + setFixedHeight(96); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + setLayout(&vlayout); +} + +ChannelWidget::~ChannelWidget() +{ + // Nothing to clean up +} + +uint16_t ChannelWidget::getDeviceSerial() const +{ + return deviceSerial; +} + +uint16_t ChannelWidget::getChannelNumber() const +{ + return channelNumber; +} + +bool ChannelWidget::isChecked() const +{ + return checkbox.isChecked(); +} + +void ChannelWidget::onChannelToggled(bool checked) +{ + if (checked) + { + // Emit signal before actually turning on the channel + emit channelAboutToBeTurnedOn(deviceSerial, channelNumber); + } + + channel_t channelFlag = static_cast(1 << channelNumber); + if (checked) + { + if (eismultiplexer_connect_channel(multiplexer.get(), channelFlag) < 0) + { + QMessageBox::warning(this, tr("Connection Failed"), + tr("Failed to connect channel %1 on device %2").arg(channelNumber).arg(deviceSerial)); + qWarning() << "Failed to connect channel" << channelNumber << "on device" << deviceSerial; + checkbox.blockSignals(true); + checkbox.setChecked(false); + setEnabled(false); // Gray out the widget + } + } + else + { + if (eismultiplexer_disconnect_channel(multiplexer.get(), channelFlag) < 0) + { + QMessageBox::warning(this, tr("Disconnection Failed"), + tr("Failed to disconnect channel %1 on device %2").arg(channelNumber).arg(deviceSerial)); + qWarning() << "Failed to disconnect channel" << channelNumber << "on device" << deviceSerial; + checkbox.blockSignals(true); + checkbox.setChecked(true); + setEnabled(false); // Gray out the widget + } + } +} + diff --git a/channelwidget.h b/channelwidget.h new file mode 100644 index 0000000..08762a6 --- /dev/null +++ b/channelwidget.h @@ -0,0 +1,49 @@ +#ifndef CHANNELWIDGET_H +#define CHANNELWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + +class ChannelWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber, + std::shared_ptr multiplexer, + QWidget *parent = nullptr); + ~ChannelWidget() override; + + uint16_t getDeviceSerial() const; + uint16_t getChannelNumber() const; + bool isChecked() const; + +signals: + void channelAboutToBeTurnedOn(uint16_t deviceSerial, uint16_t channelNumber); + +private slots: + void onChannelToggled(bool checked); + +private: + uint16_t deviceSerial; + uint16_t channelNumber; + std::shared_ptr multiplexer; + QCheckBox checkbox; + QLabel devicelabel; + QLabel channellabel; + QLabel ganglabel; + QComboBox gangcombo; + QFrame line; + QVBoxLayout vlayout; + QHBoxLayout hlayout; + QVBoxLayout labellayout; +}; + +#endif // CHANNELWIDGET_H + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..fb4d5b4 --- /dev/null +++ b/main.cpp @@ -0,0 +1,10 @@ +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow window; + window.show(); + return app.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..99a5739 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,68 @@ +#include +#include +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + enumerateDevices(); + + connect(ui->actionQuit, &QAction::triggered, this, [this]() + { + close(); + }); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::enumerateDevices() +{ + size_t count = 0; + uint16_t* serials = eismultiplexer_list_available_devices(&count); + + if (!serials || count == 0) + { + QMessageBox::warning(nullptr, tr("No Devices Found"), + tr("No EIS multiplexer devices were found. Please connect a device and try again.")); + qWarning() << "No EIS multiplexer devices found"; + exit(0); + return; + } + + for (size_t i = 0; i < count; i++) + { + uint16_t serial = serials[i]; + std::shared_ptr multiplexer(new struct eismultiplexer); + if (eismultiplexer_connect(multiplexer.get(), serial) >= 0) + { + uint16_t channelCount = 0; + qDebug()<<"Adding channels from device "<= 0) + { + for (uint16_t channel = 0; channel < channelCount; channel++) + { + std::shared_ptr widget(new ChannelWidget(serial, channel, multiplexer)); + qDebug()<<"Added widget from device "<channelLayout->addWidget(widget.get()); + } + } + } + else + { + QMessageBox::warning(this, tr("Connection Failed"), + tr("Failed to connect to device with serial %1").arg(serial)); + qWarning() << "Failed to connect to device with serial" << serial; + } + ui->channelLayout->addStretch(); + } + ui->statusbar->showMessage("Ready"); + + free(serials); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..cb1a19c --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,31 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +#include "channelwidget.h" + +namespace Ui +{ +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + std::vector> channels; + Ui::MainWindow *ui; + +signals: + void channelStateChanged(uint16_t device, uint16_t channel); + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + void enumerateDevices(); +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..53aca8f --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,68 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + EisMultiplexer-Qt + + + + + + + true + + + + + 0 + 0 + 788 + 537 + + + + + + + + + + + + + + + + 0 + 0 + 800 + 29 + + + + + File + + + + + + + + + Quit + + + + + + diff --git a/multiplexer.cpp b/multiplexer.cpp new file mode 100644 index 0000000..3e1c8e0 --- /dev/null +++ b/multiplexer.cpp @@ -0,0 +1,16 @@ +#include "multiplexer.h" + +Multiplexer::Multiplexer(QObject *parent) + : QObject{parent} +{} + +Multiplexer::~Multiplexer() +{ + for(auto& multiplexer : multiplexers) + eismultiplexer_disconnect(multiplexer.get()); +} + +void Multiplexer::probe() +{ + +} diff --git a/multiplexer.h b/multiplexer.h new file mode 100644 index 0000000..32a04ec --- /dev/null +++ b/multiplexer.h @@ -0,0 +1,22 @@ +#ifndef MULTIPLEXER_H +#define MULTIPLEXER_H + +#include +#include "eismultiplexer.h" + +class Multiplexer : public QObject +{ + Q_OBJECT + std::vector> multiplexers; + std::vector channelStates; + +public: + explicit Multiplexer(QObject *parent = nullptr); + ~Multiplexer(); + void probe(); + +signals: + void foundDevice(std::shared_ptr); +}; + +#endif // MULTIPLEXER_H diff --git a/scripts/release-win.sh b/scripts/release-win.sh new file mode 100755 index 0000000..f987f25 --- /dev/null +++ b/scripts/release-win.sh @@ -0,0 +1,61 @@ +#!/bin/bash -e +# +# libkissinference - an inference libary for kiss networks +# Copyright (C) 2024 Carl Philipp Klemm +# +# This file is part of libkissinference. +# +# libkissinference is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libkissinference is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with libkissinference. If not, see . +# + +PROJECTNAME=@PROJECT_NAME@ +SYSTEMPROC=@CMAKE_SYSTEM_PROCESSOR@ +ROOTPATH=@CMAKE_FIND_ROOT_PATH@ +VERSION="@CMAKE_PROJECT_VERSION_MAJOR@.@CMAKE_PROJECT_VERSION_MINOR@.@CMAKE_PROJECT_VERSION_PATCH@" +BINARYDIR="@CMAKE_CURRENT_BINARY_DIR@" +SRCDIR="@CMAKE_CURRENT_SOURCE_DIR@" +RELDIRECTORY="$BINARYDIR/packaged/$VERSION/release" +ZIPNAME=$PROJECTNAME-$SYSTEMPROC-$VERSION + +rm $BINARYDIR/packaged/$ZIPNAME.zip || true +cd $BINARYDIR +install -d $RELDIRECTORY +cp eismuliplexer-qt.exe $RELDIRECTORY +cp $ROOTPATH/bin/libwinpthread-1.dll $RELDIRECTORY +cp $ROOTPATH/bin/libusb-1.0.dll $RELDIRECTORY +cp $ROOTPATH/bin/libssp-0.dll $RELDIRECTORY +cp $ROOTPATH/bin/libgcc_s_seh-1.dll $RELDIRECTORY +cp $ROOTPATH/bin/libstdc++-6.dll $RELDIRECTORY +cp $ROOTPATH/bin/Qt6Core.dll $RELDIRECTORY +cp $ROOTPATH/bin/Qt6Gui.dll $RELDIRECTORY +cp $ROOTPATH/bin/Qt6Widgets.dll $RELDIRECTORY +cp -r $ROOTPATH/lib/qt6/plugins/platforms $RELDIRECTORY +cp $ROOTPATH/lib/libeismultiplexer.dll $RELDIRECTORY +cp $ROOTPATH/bin/libpcre2-*-0.dll $RELDIRECTORY +cp $ROOTPATH/bin/zlib1.dll $RELDIRECTORY +cp $ROOTPATH/bin/libfreetype-6.dll $RELDIRECTORY +cp $ROOTPATH/bin/libpng16-16.dll $RELDIRECTORY +cp $ROOTPATH/bin/libzstd.dll $RELDIRECTORY +cp $ROOTPATH/bin/libharfbuzz-0.dll $RELDIRECTORY +cp $ROOTPATH/bin/libintl-8.dll $RELDIRECTORY +cp $ROOTPATH/bin/libgraphite2.dll $RELDIRECTORY +cp $ROOTPATH/bin/libglib-2.0-0.dll $RELDIRECTORY +cp $ROOTPATH/bin/libbz2-1.dll $RELDIRECTORY +cp $ROOTPATH/bin/libbrotlidec.dll $RELDIRECTORY +cp $ROOTPATH/bin/libbrotlicommon.dll $RELDIRECTORY +cp $ROOTPATH/bin/libiconv-2.dll $RELDIRECTORY +#cp $SRCDIR/README.md $RELDIRECTORY +cd $RELDIRECTORY/.. +rm $BINARYDIR/packaged/$ZIPNAME.zip || true +zip -r $BINARYDIR/packaged/$ZIPNAME.zip release