diff --git a/.github/workflows/cppcmake.yml b/.github/workflows/cppcmake.yml
index dc682dd..35ef562 100644
--- a/.github/workflows/cppcmake.yml
+++ b/.github/workflows/cppcmake.yml
@@ -55,16 +55,6 @@ jobs:
with:
version: ${{ matrix.config.qt_ver }}
arch: ${{ matrix.config.qt_arch }}
-
- - name: Install boost
- uses: MarkusJx/install-boost@v2.4.1
- id: install-boost
- with:
- # REQUIRED: Specify the required boost version
- # A list of supported versions can be found here:
- # https://github.com/Markus
- boost_version: 1.80.0
- toolset: msvc
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
@@ -77,8 +67,6 @@ jobs:
-DCPACK_PACKAGE_DIRECTORY=${PWD}/package \
-DLSL_INSTALL_ROOT=${PWD}/LSL/ \
${{ matrix.config.cmake_extra }}
- env:
- BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }}
- name: make
run: cmake --build build --config ${{env.BUILD_TYPE}} -j --target install
@@ -91,6 +79,7 @@ jobs:
- name: Upload Artifacts
uses: actions/upload-artifact@v3
+ if: ${{ ! startsWith(github.ref, 'refs/tags/v') }}
with:
name: pkg-${{ matrix.config.name }}
path: package
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3fdc019..75e72e4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.12)
-project(SerialPortLSL
+project(SerialPort
DESCRIPTION "Read byte stream from COM port and emit as an LSL stream"
HOMEPAGE_URL "https://github.com/labstreaminglayer/App-SerialPort/"
LANGUAGES CXX
@@ -30,9 +30,6 @@ set(CMAKE_AUTOUIC ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets)
-## Boost
-find_package(Boost REQUIRED)
-
## Threads
find_package(Threads REQUIRED)
@@ -44,7 +41,7 @@ add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME} PRIVATE
main.cpp
mainwindow.cpp
- mainwindow.h
+ mainwindow.hpp
mainwindow.ui
)
@@ -52,7 +49,6 @@ target_link_libraries(${PROJECT_NAME}
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Widgets
- Boost::headers
Threads::Threads
LSL::lsl
)
diff --git a/README.md b/README.md
index 11a4d85..746eba6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ The program reads a byte stream from a given COM port and emits it as an LSL str
# Usage
* Start the SerialPort app. You should see a window like the following.
- ![serialport.png](serialport.png)
+> ![serialport.png](serialport.png)
* Make sure that your device is plugged in and that you know its COM port (you can usually check this in the Device Manager).
@@ -14,4 +14,4 @@ The program reads a byte stream from a given COM port and emits it as an LSL str
* Click the "Link" button. If all goes well you should now have a stream on your lab network that has the name that you entered under Stream Name and type "Raw". Note that you cannot close the app while it is linked.
- * For subsequent uses you can save the settings in the GUI via File / Save Configuration. If the app is frequently used with different settings you might can also make a shortcut on the desktop that points to the app and appends to the Target field the snippet `-c name_of_config.cfg`.
+ * For subsequent uses you can save the settings in the GUI via File / Save Configuration. If the app is frequently used with different settings you might can also make a shortcut on the desktop that points to the app and appends to the Target field the snippet `name_of_config.cfg`.
diff --git a/SerialPort.cfg b/SerialPort.cfg
new file mode 100644
index 0000000..19beb35
--- /dev/null
+++ b/SerialPort.cfg
@@ -0,0 +1,2 @@
+
+157600032SerialPort4005005010
\ No newline at end of file
diff --git a/SerialPortLSL.cfg b/SerialPortLSL.cfg
deleted file mode 100644
index 27209e3..0000000
--- a/SerialPortLSL.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- 1
- 57600
-
-
- 0
- 32
- SerialPort
-
-
- 4
- 0
- 0
-
-
- 500
- 50
- 10
-
diff --git a/main.cpp b/main.cpp
index bf9ed41..d730ed4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,20 +1,9 @@
+#include "mainwindow.hpp"
#include
-#include "mainwindow.h"
-#include
-
-
-int main(int argc, char *argv[])
-{
- // determine the startup config file...
- std::string config_file = "SerialPortLSL.cfg";
- for (int k=1;k 1 ? argv[1] : nullptr);
w.show();
-
-
return a.exec();
-}
+}
\ No newline at end of file
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 795954f..38850ab 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -1,221 +1,247 @@
-#include "mainwindow.h"
+#include "mainwindow.hpp"
#include "ui_mainwindow.h"
-#include
-#include
-
-
-MainWindow::MainWindow(QWidget *parent, const std::string &config_file) :
-QMainWindow(parent),
-ui(new Ui::MainWindow)
-{
- ui->setupUi(this);
-
- // parse startup config file
- load_config(config_file);
-
- // make GUI connections
- QObject::connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
- QObject::connect(ui->linkButton, SIGNAL(clicked()), this, SLOT(on_link()));
- QObject::connect(ui->actionLoad_Configuration, SIGNAL(triggered()), this, SLOT(load_config_dialog()));
- QObject::connect(ui->actionSave_Configuration, SIGNAL(triggered()), this, SLOT(save_config_dialog()));
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+MainWindow::MainWindow(QWidget *parent, const char *config_file)
+ : QMainWindow(parent), ui(new Ui::MainWindow) {
+ ui->setupUi(this);
+ connect(ui->actionLoad_Configuration, &QAction::triggered, [this]() {
+ load_config(QFileDialog::getOpenFileName(
+ this, "Load Configuration File", "", "Configuration Files (*.cfg)"));
+ });
+ connect(ui->actionSave_Configuration, &QAction::triggered, [this]() {
+ save_config(QFileDialog::getSaveFileName(
+ this, "Save Configuration File", "", "Configuration Files (*.cfg)"));
+ });
+ connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::close);
+ connect(ui->actionAbout, &QAction::triggered, [this]() {
+ QString infostr = QStringLiteral("LSL library version: ") +
+ QString::number(lsl::library_version()) +
+ "\nLSL library info:" + lsl::library_info();
+ QMessageBox::about(this, "About this app", infostr);
+ });
+ connect(ui->linkButton, &QPushButton::clicked, this, &MainWindow::toggleRecording);
+
+
+ //: At the end of the constructor, we load the supplied config file or find it
+ //: in one of the default paths
+ QString cfgfilepath = find_config_file(config_file);
+ load_config(cfgfilepath);
}
-
-void MainWindow::load_config_dialog() {
- QString sel = QFileDialog::getOpenFileName(this,"Load Configuration File","","Configuration Files (*.cfg)");
- if (!sel.isEmpty())
- load_config(sel.toStdString());
+void MainWindow::load_config(const QString &filename) {
+ QSettings settings(filename, QSettings::Format::IniFormat);
+ ui->comPort->setValue(settings.value("coresettings.comport", 1).toInt());
+ ui->baudRate->setValue(settings.value("coresettings.baudrate", 57600).toInt());
+ ui->samplingRate->setValue(settings.value("streamsettings.samplingrate", 0).toInt());
+ ui->chunkSize->setValue(settings.value("streamsettings.chunksize", 32).toInt());
+ ui->input_name->setText(settings.value("streamsettings.streamname", "SerialPort").toString());
+ ui->dataBits->setCurrentIndex(settings.value("miscsettings.databits", 4).toInt());
+ ui->parity->setCurrentIndex(settings.value("miscsettings.parity", 0).toInt());
+ ui->stopBits->setCurrentIndex(settings.value("miscsettings.stopbits", 0).toInt());
+ ui->readIntervalTimeout->setValue(
+ settings.value("timeoutsettings.readintervaltimeout", 500).toInt());
+ ui->readTotalTimeoutConstant->setValue(
+ settings.value("timeoutsettings.readtotaltimeoutconstant", 50).toInt());
+ ui->readTotalTimeoutMultiplier->setValue(
+ settings.value("timeoutsettings.readtotaltimeoutmultiplier", 10).toInt());
}
-void MainWindow::save_config_dialog() {
- QString sel = QFileDialog::getSaveFileName(this,"Save Configuration File","","Configuration Files (*.cfg)");
- if (!sel.isEmpty())
- save_config(sel.toStdString());
+//: Save function, same as above
+void MainWindow::save_config(const QString &filename) {
+ QSettings settings(filename, QSettings::Format::IniFormat);
+ settings.beginGroup("coresettings");
+ settings.setValue("comport", ui->comPort->value());
+ settings.setValue("baudrate", ui->baudRate->value());
+ settings.endGroup();
+ settings.beginGroup("streamsettings");
+ settings.setValue("samplingrate", ui->samplingRate->value());
+ settings.setValue("chunksize", ui->chunkSize->value());
+ settings.setValue("streamname", ui->input_name->text());
+ settings.endGroup();
+ settings.beginGroup("miscsettings");
+ settings.setValue("databits", ui->dataBits->currentIndex());
+ settings.setValue("parity", ui->parity->currentIndex());
+ settings.setValue("stopbits", ui->stopBits->currentIndex());
+ settings.endGroup();
+ settings.beginGroup("timeoutsettings");
+ settings.setValue("readintervaltimeout", ui->readIntervalTimeout->value());
+ settings.setValue("readtotaltimeoutconstant", ui->readTotalTimeoutConstant->value());
+ settings.setValue("readtotaltimeoutmultiplier", ui->readTotalTimeoutMultiplier->value());
+ settings.sync();
}
void MainWindow::closeEvent(QCloseEvent *ev) {
- if (reader_thread_)
- ev->ignore();
+ if (reader) {
+ QMessageBox::warning(this, "Recording still running", "Can't quit while recording");
+ ev->ignore();
+ }
}
-void MainWindow::load_config(const std::string &filename) {
- using boost::property_tree::ptree;
- ptree pt;
-
- // parse file
- try {
- read_xml(filename, pt);
- } catch(std::exception &e) {
- QMessageBox::information(this,"Error",(std::string("Cannot read config file: ")+= e.what()).c_str(),QMessageBox::Ok);
- return;
- }
-
- // get config values
- try {
- ui->comPort->setValue(pt.get("coresettings.comport",1));
- ui->baudRate->setValue(pt.get("coresettings.baudrate",57600));
- ui->samplingRate->setValue(pt.get("streamsettings.samplingrate",0));
- ui->chunkSize->setValue(pt.get("streamsettings.chunksize",32));
- ui->streamName->setText(pt.get("streamsettings.streamname","SerialPort").c_str());
- ui->dataBits->setCurrentIndex(pt.get("miscsettings.databits",4));
- ui->parity->setCurrentIndex(pt.get("miscsettings.parity",0));
- ui->stopBits->setCurrentIndex(pt.get("miscsettings.stopbits",0));
- ui->readIntervalTimeout->setValue(pt.get("timeoutsettings.readintervaltimeout",500));
- ui->readTotalTimeoutConstant->setValue(pt.get("timeoutsettings.readtotaltimeoutconstant",50));
- ui->readTotalTimeoutMultiplier->setValue(pt.get("timeoutsettings.readtotaltimeoutmultiplier",10));
- } catch(std::exception &) {
- QMessageBox::information(this,"Error in Config File","Could not read out config parameters.",QMessageBox::Ok);
- return;
- }
-}
-void MainWindow::save_config(const std::string &filename) {
- using boost::property_tree::ptree;
- ptree pt;
-
- // transfer UI content into property tree
- try {
- pt.put("coresettings.comport",ui->comPort->value());
- pt.put("coresettings.baudrate",ui->baudRate->value());
- pt.put("streamsettings.samplingrate",ui->samplingRate->value());
- pt.put("streamsettings.chunksize",ui->chunkSize->value());
- pt.put("streamsettings.streamname",ui->streamName->text().toStdString());
- pt.put("miscsettings.databits",ui->dataBits->currentIndex());
- pt.put("miscsettings.parity",ui->parity->currentIndex());
- pt.put("miscsettings.stopbits",ui->stopBits->currentIndex());
- pt.put("timeoutsettings.readintervaltimeout",ui->readIntervalTimeout->value());
- pt.put("timeoutsettings.readtotaltimeoutconstant",ui->readTotalTimeoutConstant->value());
- pt.put("timeoutsettings.readtotaltimeoutmultiplier",ui->readTotalTimeoutMultiplier->value());
- } catch(std::exception &e) {
- QMessageBox::critical(this,"Error",(std::string("Could not prepare settings for saving: ")+=e.what()).c_str(),QMessageBox::Ok);
- }
-
- // write to disk
- try {
- write_xml(filename, pt);
- } catch(std::exception &e) {
- QMessageBox::critical(this,"Error",(std::string("Could not write to config file: ")+=e.what()).c_str(),QMessageBox::Ok);
- }
+// background data reader thread
+void read_thread(HANDLE hPort, int comPort, int baudRate, int samplingRate, int chunkSize,
+ const std::string streamName, std::atomic &shutdown) {
+ try {
+
+ // create streaminfo
+ lsl::stream_info info(streamName,"Raw",1,samplingRate,lsl::cf_int16,std::string("SerialPort_") + streamName);
+ // append some meta-data
+ lsl::xml_element channels = info.desc().append_child("channels");
+ channels.append_child("channel")
+ .append_child_value("label","Channel1")
+ .append_child_value("type","Raw")
+ .append_child_value("unit","integer");
+ info.desc().append_child("acquisition")
+ .append_child("hardware")
+ .append_child_value("com_port", std::to_string(comPort))
+ .append_child_value("baud_rate",std::to_string(baudRate));
+
+ // make a new outlet
+ lsl::stream_outlet outlet(info,chunkSize);
+
+ // enter transmission loop
+ unsigned char byte;
+ short sample;
+ unsigned long bytes_read;
+ while (!shutdown) {
+ // get a sample
+ ReadFile(hPort,&byte,1,&bytes_read,NULL); sample = byte;
+ // transmit it
+ if (bytes_read)
+ outlet.push_sample(&sample);
+ }
+ }
+ catch(std::exception &e) {
+ // any other error
+// QMessageBox::critical(this,"Error",(std::string("Error during processing: ")+=e.what()).c_str(),QMessageBox::Ok);
+ }
+ CloseHandle(hPort);
}
-
-// start/stop the cognionics connection
-void MainWindow::on_link() {
- if (reader_thread_) {
- // === perform unlink action ===
- try {
- shutdown_ = true;
- reader_thread_->join();
- reader_thread_.reset();
- } catch(std::exception &e) {
- QMessageBox::critical(this,"Error",(std::string("Could not stop the background processing: ")+=e.what()).c_str(),QMessageBox::Ok);
- return;
- }
-
- // indicate that we are now successfully unlinked
- ui->linkButton->setText("Link");
- } else {
- // === perform link action ===
- HANDLE hPort = NULL;
-
- try {
- // get the UI parameters...
- int comPort = ui->comPort->value();
- int baudRate = ui->baudRate->value();
- int samplingRate = ui->samplingRate->value();
- int chunkSize = ui->chunkSize->value();
- std::string streamName = ui->streamName->text().toStdString();
- int dataBits = ui->dataBits->currentIndex()+4;
- int parity = ui->parity->currentIndex();
- int stopBits = ui->stopBits->currentIndex();
- int readIntervalTimeout = ui->readIntervalTimeout->value();
- int readTotalTimeoutConstant = ui->readTotalTimeoutConstant->value();
- int readTotalTimeoutMultiplier = ui->readTotalTimeoutMultiplier->value();
-
- // try to open the serial port
- std::string fname = "\\\\.\\COM" + std::to_string(comPort);
- hPort = CreateFileA(fname.c_str(),GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
- if (hPort == INVALID_HANDLE_VALUE)
- throw std::runtime_error("Could not open serial port. Please make sure that you are using the right COM port and that the device is ready.");
-
- // try to set up serial port parameters
- DCB dcbSerialParams = {0};
- if (!GetCommState(hPort, &dcbSerialParams))
- QMessageBox::critical(this,"Error","Could not get COM port state.",QMessageBox::Ok);
- dcbSerialParams.BaudRate=baudRate;
- dcbSerialParams.ByteSize=dataBits;
- dcbSerialParams.StopBits=stopBits;
- dcbSerialParams.Parity=parity;
- if(!SetCommState(hPort, &dcbSerialParams))
- QMessageBox::critical(this,"Error","Could not set baud rate.",QMessageBox::Ok);
-
- // try to set timeouts
- COMMTIMEOUTS timeouts = {0};
- if (!GetCommTimeouts(hPort,&timeouts))
- QMessageBox::critical(this,"Error","Could not get COM port timeouts.",QMessageBox::Ok);
- timeouts.ReadIntervalTimeout = readIntervalTimeout;
- timeouts.ReadTotalTimeoutConstant = readTotalTimeoutConstant;
- timeouts.ReadTotalTimeoutMultiplier = readTotalTimeoutMultiplier;
- if (!SetCommTimeouts(hPort,&timeouts))
- QMessageBox::critical(this,"Error","Could not set COM port timeouts.",QMessageBox::Ok);
-
- // start reading
- shutdown_ = false;
- reader_thread_ = std::make_unique(&MainWindow::read_thread, this, hPort, comPort, baudRate, samplingRate, chunkSize, streamName);
-
- }
- catch(std::exception &e) {
- if (hPort != INVALID_HANDLE_VALUE)
- CloseHandle(hPort);
- QMessageBox::critical(this,"Error",(std::string("Error during initialization: ")+=e.what()).c_str(),QMessageBox::Ok);
- return;
- }
-
- // done, all successful
- ui->linkButton->setText("Unlink");
- }
+//: ## Toggling the recording state
+//: Our record button has two functions: start a recording and
+//: stop it if a recording is running already.
+void MainWindow::toggleRecording() {
+ /*: the `std::unique_ptr` evaluates to false if it doesn't point to an object,
+ * so we need to start a recording.
+ * First, we load the configuration from the UI fields, set the shutdown flag
+ * to false so the recording thread doesn't quit immediately and create the
+ * recording thread. */
+ if (!reader) {
+ HANDLE hPort = NULL;
+ try {
+
+ // get the UI parameters...
+ int comPort = ui->comPort->value();
+ int baudRate = ui->baudRate->value();
+ int samplingRate = ui->samplingRate->value();
+ int chunkSize = ui->chunkSize->value();
+ std::string streamName = ui->input_name->text().toStdString();
+ int dataBits = ui->dataBits->currentIndex() + 4;
+ int parity = ui->parity->currentIndex();
+ int stopBits = ui->stopBits->currentIndex();
+ int readIntervalTimeout = ui->readIntervalTimeout->value();
+ int readTotalTimeoutConstant = ui->readTotalTimeoutConstant->value();
+ int readTotalTimeoutMultiplier = ui->readTotalTimeoutMultiplier->value();
+
+ // try to open the serial port
+ std::string fname = "\\\\.\\COM" + std::to_string(comPort);
+ hPort = CreateFileA(fname.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if (hPort == INVALID_HANDLE_VALUE)
+ throw std::runtime_error(
+ "Could not open serial port. Please make sure that you are using the right COM "
+ "port and that the device is ready.");
+
+ // try to set up serial port parameters
+ DCB dcbSerialParams = {0};
+ if (!GetCommState(hPort, &dcbSerialParams))
+ QMessageBox::critical(
+ this, "Error", "Could not get COM port state.", QMessageBox::Ok);
+ dcbSerialParams.BaudRate = baudRate;
+ dcbSerialParams.ByteSize = dataBits;
+ dcbSerialParams.StopBits = stopBits;
+ dcbSerialParams.Parity = parity;
+ if (!SetCommState(hPort, &dcbSerialParams))
+ QMessageBox::critical(this, "Error", "Could not set baud rate.", QMessageBox::Ok);
+
+ // try to set timeouts
+ COMMTIMEOUTS timeouts = {0};
+ if (!GetCommTimeouts(hPort, &timeouts))
+ QMessageBox::critical(
+ this, "Error", "Could not get COM port timeouts.", QMessageBox::Ok);
+ timeouts.ReadIntervalTimeout = readIntervalTimeout;
+ timeouts.ReadTotalTimeoutConstant = readTotalTimeoutConstant;
+ timeouts.ReadTotalTimeoutMultiplier = readTotalTimeoutMultiplier;
+ if (!SetCommTimeouts(hPort, &timeouts))
+ QMessageBox::critical(
+ this, "Error", "Could not set COM port timeouts.", QMessageBox::Ok);
+ reader = std::make_unique([&]() {
+ read_thread(
+ hPort, comPort, baudRate, samplingRate, chunkSize, streamName, shutdown);
+ });
+
+ } catch (std::exception &e) {
+ if (hPort != INVALID_HANDLE_VALUE) CloseHandle(hPort);
+ QMessageBox::critical(this, "Error",
+ QStringLiteral("Error during initialization: ") + e.what(), QMessageBox::Ok);
+ return;
+ }
+ ui->linkButton->setText("Unlink");
+ } else {
+ shutdown = true;
+ reader->join();
+ reader.reset();
+ ui->linkButton->setText("Link");
+ }
}
-// background data reader thread
-void MainWindow::read_thread(HANDLE hPort, int comPort, int baudRate, int samplingRate, int chunkSize, const std::string &streamName) {
- try {
-
- // create streaminfo
- lsl::stream_info info(streamName,"Raw",1,samplingRate,lsl::cf_int16,std::string("SerialPort_") + streamName);
- // append some meta-data
- lsl::xml_element channels = info.desc().append_child("channels");
- channels.append_child("channel")
- .append_child_value("label","Channel1")
- .append_child_value("type","Raw")
- .append_child_value("unit","integer");
- info.desc().append_child("acquisition")
- .append_child("hardware")
- .append_child_value("com_port", std::to_string(comPort))
- .append_child_value("baud_rate",std::to_string(baudRate));
-
- // make a new outlet
- lsl::stream_outlet outlet(info,chunkSize);
-
- // enter transmission loop
- unsigned char byte;
- short sample;
- unsigned long bytes_read;
- while (!shutdown_) {
- // get a sample
- ReadFile(hPort,&byte,1,&bytes_read,NULL); sample = byte;
- // transmit it
- if (bytes_read)
- outlet.push_sample(&sample);
- }
- }
- catch(std::exception &e) {
- // any other error
- QMessageBox::critical(this,"Error",(std::string("Error during processing: ")+=e.what()).c_str(),QMessageBox::Ok);
- }
- CloseHandle(hPort);
+/**
+ * Find a config file to load. This is (in descending order or preference):
+ * - a file supplied on the command line
+ * - [executablename].cfg in one the the following folders:
+ * - the current working directory
+ * - the default config folder, e.g. '~/Library/Preferences' on OS X
+ * - the executable folder
+ * @param filename Optional file name supplied e.g. as command line parameter
+ * @return Path to a found config file
+ */
+QString MainWindow::find_config_file(const char *filename) {
+ if (filename) {
+ QString qfilename(filename);
+ if (!QFileInfo::exists(qfilename))
+ QMessageBox(QMessageBox::Warning, "Config file not found",
+ QStringLiteral("The file '%1' doesn't exist").arg(qfilename), QMessageBox::Ok,
+ this);
+ else
+ return qfilename;
+ }
+ QFileInfo exeInfo(QCoreApplication::applicationFilePath());
+ QString defaultCfgFilename(exeInfo.completeBaseName() + ".cfg");
+ QStringList cfgpaths;
+ cfgpaths << QDir::currentPath()
+ << QStandardPaths::standardLocations(QStandardPaths::ConfigLocation) << exeInfo.path();
+ for (auto path : cfgpaths) {
+ QString cfgfilepath = path + QDir::separator() + defaultCfgFilename;
+ if (QFileInfo::exists(cfgfilepath)) return cfgfilepath;
+ }
+ QMessageBox(QMessageBox::Warning, "No config file not found",
+ QStringLiteral("No default config file could be found"), QMessageBox::Ok, this);
+ return "";
}
-MainWindow::~MainWindow() {
- delete ui;
-}
+
+//: Tell the compiler to put the default destructor in this object file
+MainWindow::~MainWindow() noexcept = default;
\ No newline at end of file
diff --git a/mainwindow.h b/mainwindow.h
deleted file mode 100644
index a8e6161..0000000
--- a/mainwindow.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-// LSL API
-#include
-
-#define WIN32_LEAN_AND_MEAN
-#include "windows.h"
-
-namespace Ui {
-class MainWindow;
-}
-
-class MainWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- explicit MainWindow(QWidget *parent, const std::string &config_file);
- ~MainWindow();
-
-private slots:
- // config file dialog ops (from main menu)
- void load_config_dialog();
- void save_config_dialog();
-
- // start the cognionics connection
- void on_link();
-
- // close event (potentially disabled)
- void closeEvent(QCloseEvent *ev);
-private:
- // background data reader thread
- void read_thread(HANDLE hPort, int comPort, int baudRate, int samplingRate, int chunkSize, const std::string &streamName);
-
- // raw config file IO
- void load_config(const std::string &filename);
- void save_config(const std::string &filename);
-
- std::unique_ptr reader_thread_{nullptr}; // our reader thread
- std::atomic shutdown_{false}; // flag indicating whether the streaming thread should quit
-
- Ui::MainWindow *ui;
-};
-
-#endif // MAINWINDOW_H
diff --git a/mainwindow.hpp b/mainwindow.hpp
new file mode 100644
index 0000000..d455f49
--- /dev/null
+++ b/mainwindow.hpp
@@ -0,0 +1,37 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include //for std::unique_ptr
+#include
+
+
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+
+namespace Ui {
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow {
+Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent, const char *config_file);
+ ~MainWindow() noexcept override;
+
+private slots:
+ void closeEvent(QCloseEvent *ev) override;
+ void toggleRecording();
+
+private:
+ QString find_config_file(const char *filename);
+ void load_config(const QString &filename);
+ void save_config(const QString &filename);
+ std::unique_ptr reader{nullptr};
+
+ std::unique_ptr ui; // window pointer
+ std::atomic shutdown{false}; // flag indicating whether the recording thread should quit
+};
+
+#endif // MAINWINDOW_H
\ No newline at end of file
diff --git a/mainwindow.ui b/mainwindow.ui
index a09e1a9..5d8d014 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -9,8 +9,8 @@
0
0
- 415
- 333
+ 502
+ 433
@@ -26,9 +26,6 @@
Core Port Settings
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
@@ -78,9 +75,6 @@
Stream Settings
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
@@ -93,6 +87,9 @@
Set this to a non-zero value if you know the sampling rate.
+
+ Hz
+
0
@@ -112,7 +109,7 @@
-
-
+
The name of the stream within LSL.
@@ -294,8 +291,8 @@
-
-
- Maximum time that may pass between two bytes
+
+ ms
10000000
@@ -394,44 +391,60 @@
0
0
- 415
- 18
+ 502
+ 30
+
+
- Load Configuration
+ &Load Configuration
+
+
+ Ctrl+L
- Save Configuration
+ &Save Configuration
+
+
+ Ctrl+S
- Quit
+ &Quit
+
+
+ Ctrl+Q
-
+
- Quit
+ &About
-
+
\ No newline at end of file