Support windows

This commit is contained in:
Carl Philipp Klemm 2025-08-25 17:00:16 +02:00
parent 9e0d7a5d9d
commit 5c5efb5029
8 changed files with 215 additions and 144 deletions

View file

@ -1,36 +1,50 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
# Set the project name project(eismuliplexer-qt)
project(eismultiplexer-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 C++ standard
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find Qt6 find_package(PkgConfig REQUIRED)
pkg_check_modules(EISMULIPLEXER REQUIRED eismuliplexer)
find_package(Qt6 REQUIRED COMPONENTS Widgets) find_package(Qt6 REQUIRED COMPONENTS Widgets)
find_package(Qt6 REQUIRED COMPONENTS Core)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
# Include the libeismultiplexer library add_executable(${PROJECT_NAME}
include_directories(/workspace/libeismultiplexer)
link_directories(/workspace/libeismultiplexer/build)
# Add the application executable
add_executable(eismultiplexer-qt
main.cpp main.cpp
channelwidget.cpp channelwidget.cpp
channelwidget.h channelwidget.h
mainwindow.h mainwindow.h
mainwindow.cpp mainwindow.cpp
mainwindow.ui mainwindow.ui
multiplexer.h
multiplexer.cpp
) )
target_compile_options(eismultiplexer-qt PUBLIC "-Wall") target_compile_options(${PROJECT_NAME} PUBLIC "-Wall")
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Core ${EISMULIPLEXER_LIBRARIES})
# Link Qt Widgets #target_include_directories(${PROJECT_NAME} PUBLIC ${EISMULIPLEXER_INCLUDE_DIRS})
target_link_libraries(eismultiplexer-qt Qt6::Widgets eismultiplexer)
# Include directories
target_include_directories(eismultiplexer-qt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -2,89 +2,96 @@
#include <QDebug> #include <QDebug>
#include <QMessageBox> #include <QMessageBox>
ChannelWidget::ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber, std::shared_ptr<struct eismultiplexer> multiplexer, ChannelWidget::ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber,
std::shared_ptr<struct eismultiplexer> multiplexer,
QWidget *parent) QWidget *parent)
: :
QWidget(parent), QWidget(parent),
deviceSerial(deviceSerial), deviceSerial(deviceSerial),
channelNumber(channelNumber), channelNumber(channelNumber),
multiplexer(multiplexer), multiplexer(multiplexer),
checkbox("Enable"), checkbox("Enable"),
devicelabel(QString::asprintf("Device %04u", deviceSerial)), devicelabel(QString::asprintf("Device %04u", deviceSerial)),
channellabel(QString::asprintf("Channel %u", channelNumber)), channellabel(QString::asprintf("Channel %u", channelNumber)),
ganglabel("Ganged:") ganglabel("Ganged:")
{ {
hlayout.addLayout(&labellayout); hlayout.addLayout(&labellayout);
vlayout.addLayout(&hlayout); vlayout.addLayout(&hlayout);
labellayout.addWidget(&devicelabel); labellayout.addWidget(&devicelabel);
labellayout.addWidget(&channellabel); labellayout.addWidget(&channellabel);
line.setGeometry(QRect(320, 150, 118, 3)); line.setGeometry(QRect(320, 150, 118, 3));
line.setFrameShape(QFrame::HLine); line.setFrameShape(QFrame::HLine);
line.setFrameShadow(QFrame::Sunken); line.setFrameShadow(QFrame::Sunken);
vlayout.addWidget(&line); vlayout.addWidget(&line);
gangcombo.addItem("Unganged"); gangcombo.addItem("Unganged");
hlayout.addStretch(); hlayout.addStretch();
hlayout.addWidget(&ganglabel); hlayout.addWidget(&ganglabel);
hlayout.addWidget(&gangcombo); hlayout.addWidget(&gangcombo);
hlayout.addWidget(&checkbox); hlayout.addWidget(&checkbox);
connect(&checkbox, &QCheckBox::toggled, this, &ChannelWidget::onChannelToggled); connect(&checkbox, &QCheckBox::toggled, this, &ChannelWidget::onChannelToggled);
setFixedHeight(96); setFixedHeight(96);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setLayout(&vlayout); setLayout(&vlayout);
} }
ChannelWidget::~ChannelWidget() ChannelWidget::~ChannelWidget()
{ {
// Nothing to clean up // Nothing to clean up
} }
uint16_t ChannelWidget::getDeviceSerial() const uint16_t ChannelWidget::getDeviceSerial() const
{ {
return deviceSerial; return deviceSerial;
} }
uint16_t ChannelWidget::getChannelNumber() const uint16_t ChannelWidget::getChannelNumber() const
{ {
return channelNumber; return channelNumber;
} }
bool ChannelWidget::isChecked() const bool ChannelWidget::isChecked() const
{ {
return checkbox.isChecked(); return checkbox.isChecked();
} }
void ChannelWidget::onChannelToggled(bool checked) void ChannelWidget::onChannelToggled(bool checked)
{ {
if (checked) { if (checked)
// Emit signal before actually turning on the channel {
emit channelAboutToBeTurnedOn(deviceSerial, channelNumber); // Emit signal before actually turning on the channel
} emit channelAboutToBeTurnedOn(deviceSerial, channelNumber);
}
channel_t channelFlag = static_cast<channel_t>(1 << channelNumber); channel_t channelFlag = static_cast<channel_t>(1 << channelNumber);
if (checked) { if (checked)
if (eismultiplexer_connect_channel(multiplexer.get(), channelFlag) < 0) { {
QMessageBox::warning(this, tr("Connection Failed"), if (eismultiplexer_connect_channel(multiplexer.get(), channelFlag) < 0)
tr("Failed to connect channel %1 on device %2").arg(channelNumber).arg(deviceSerial)); {
qWarning() << "Failed to connect channel" << channelNumber << "on device" << deviceSerial; QMessageBox::warning(this, tr("Connection Failed"),
checkbox.blockSignals(true); tr("Failed to connect channel %1 on device %2").arg(channelNumber).arg(deviceSerial));
checkbox.setChecked(false); qWarning() << "Failed to connect channel" << channelNumber << "on device" << deviceSerial;
setEnabled(false); // Gray out the widget checkbox.blockSignals(true);
} checkbox.setChecked(false);
} else { setEnabled(false); // Gray out the widget
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)); else
qWarning() << "Failed to disconnect channel" << channelNumber << "on device" << deviceSerial; {
checkbox.blockSignals(true); if (eismultiplexer_disconnect_channel(multiplexer.get(), channelFlag) < 0)
checkbox.setChecked(true); {
setEnabled(false); // Gray out the widget 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
}
}
} }

View file

@ -11,36 +11,37 @@
class ChannelWidget : public QWidget class ChannelWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber, std::shared_ptr<struct eismultiplexer> multiplexer, explicit ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber,
QWidget *parent = nullptr); std::shared_ptr<struct eismultiplexer> multiplexer,
~ChannelWidget() override; QWidget *parent = nullptr);
~ChannelWidget() override;
uint16_t getDeviceSerial() const; uint16_t getDeviceSerial() const;
uint16_t getChannelNumber() const; uint16_t getChannelNumber() const;
bool isChecked() const; bool isChecked() const;
signals: signals:
void channelAboutToBeTurnedOn(uint16_t deviceSerial, uint16_t channelNumber); void channelAboutToBeTurnedOn(uint16_t deviceSerial, uint16_t channelNumber);
private slots: private slots:
void onChannelToggled(bool checked); void onChannelToggled(bool checked);
private: private:
uint16_t deviceSerial; uint16_t deviceSerial;
uint16_t channelNumber; uint16_t channelNumber;
std::shared_ptr<struct eismultiplexer> multiplexer; std::shared_ptr<struct eismultiplexer> multiplexer;
QCheckBox checkbox; QCheckBox checkbox;
QLabel devicelabel; QLabel devicelabel;
QLabel channellabel; QLabel channellabel;
QLabel ganglabel; QLabel ganglabel;
QComboBox gangcombo; QComboBox gangcombo;
QFrame line; QFrame line;
QVBoxLayout vlayout; QVBoxLayout vlayout;
QHBoxLayout hlayout; QHBoxLayout hlayout;
QVBoxLayout labellayout; QVBoxLayout labellayout;
}; };
#endif // CHANNELWIDGET_H #endif // CHANNELWIDGET_H

View file

@ -3,8 +3,8 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
MainWindow window; MainWindow window;
window.show(); window.show();
return app.exec(); return app.exec();
} }

View file

@ -4,55 +4,65 @@
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
enumerateDevices(); enumerateDevices();
connect(ui->actionQuit, &QAction::triggered, this, [this](){close();}); connect(ui->actionQuit, &QAction::triggered, this, [this]()
{
close();
});
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete ui; delete ui;
} }
void MainWindow::enumerateDevices() void MainWindow::enumerateDevices()
{ {
size_t count = 0; size_t count = 0;
uint16_t* serials = eismultiplexer_list_available_devices(&count); uint16_t* serials = eismultiplexer_list_available_devices(&count);
if (!serials || count == 0) { if (!serials || count == 0)
QMessageBox::warning(this, tr("No Devices Found"), {
tr("No EIS multiplexer devices were found. Please connect a device and try again.")); QMessageBox::warning(nullptr, tr("No Devices Found"),
qWarning() << "No EIS multiplexer devices found"; tr("No EIS multiplexer devices were found. Please connect a device and try again."));
close(); qWarning() << "No EIS multiplexer devices found";
return; exit(0);
} return;
}
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++)
uint16_t serial = serials[i]; {
std::shared_ptr<struct eismultiplexer> multiplexer(new struct eismultiplexer); uint16_t serial = serials[i];
if (eismultiplexer_connect(multiplexer.get(), serial) >= 0) { std::shared_ptr<struct eismultiplexer> multiplexer(new struct eismultiplexer);
uint16_t channelCount = 0; if (eismultiplexer_connect(multiplexer.get(), serial) >= 0)
qDebug()<<"Adding channels from device "<<serial; {
if (eismultiplexer_get_channel_count(multiplexer.get(), &channelCount) >= 0) { uint16_t channelCount = 0;
for (uint16_t channel = 0; channel < channelCount; channel++) { qDebug()<<"Adding channels from device "<<serial;
std::shared_ptr<ChannelWidget> widget(new ChannelWidget(serial, channel, multiplexer)); if (eismultiplexer_get_channel_count(multiplexer.get(), &channelCount) >= 0)
qDebug()<<"Added widget from device "<<serial<<" channel "<<channel; {
channels.push_back(widget); for (uint16_t channel = 0; channel < channelCount; channel++)
ui->channelLayout->addWidget(widget.get()); {
} std::shared_ptr<ChannelWidget> widget(new ChannelWidget(serial, channel, multiplexer));
} qDebug()<<"Added widget from device "<<serial<<" channel "<<channel;
} else { channels.push_back(widget);
QMessageBox::warning(this, tr("Connection Failed"), ui->channelLayout->addWidget(widget.get());
tr("Failed to connect to device with serial %1").arg(serial)); }
qWarning() << "Failed to connect to device with serial" << serial; }
} }
ui->channelLayout->addStretch(); else
} {
ui->statusbar->showMessage("Ready"); 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); free(serials);
} }

View file

@ -6,25 +6,26 @@
#include "channelwidget.h" #include "channelwidget.h"
namespace Ui { namespace Ui
{
class MainWindow; class MainWindow;
} }
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
std::vector<std::shared_ptr<ChannelWidget>> channels; std::vector<std::shared_ptr<ChannelWidget>> channels;
Ui::MainWindow *ui; Ui::MainWindow *ui;
signals: signals:
void channelStateChanged(uint16_t device, uint16_t channel); void channelStateChanged(uint16_t device, uint16_t channel);
public: public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
private: private:
void enumerateDevices(); void enumerateDevices();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

16
multiplexer.cpp Normal file
View file

@ -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()
{
}

22
multiplexer.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef MULTIPLEXER_H
#define MULTIPLEXER_H
#include <QObject>
#include "eismultiplexer.h"
class Multiplexer : public QObject
{
Q_OBJECT
std::vector<std::shared_ptr<struct eismultiplexer>> multiplexers;
std::vector<channel_t> channelStates;
public:
explicit Multiplexer(QObject *parent = nullptr);
~Multiplexer();
void probe();
signals:
void foundDevice(std::shared_ptr<struct eismultiplexer>);
};
#endif // MULTIPLEXER_H