Initial serial port dialog work

This commit is contained in:
Dan Paulat 2024-05-14 00:33:57 -05:00
parent 523c26ed47
commit 230c96e450
5 changed files with 333 additions and 1 deletions

View file

@ -34,7 +34,7 @@ Supercell Wx uses code from the following dependencies:
| [MapLibre Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) | | [MapLibre Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native | | [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native |
| [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) | | [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) |
| [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Multimedia, Qt Network, Qt OpenGL, Qt Positioning, Qt SQL, Qt SVG, Qt Widgets<br/>Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html | | [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Multimedia, Qt Network, Qt OpenGL, Qt Positioning, Qt Serial Port, Qt SQL, Qt SVG, Qt Widgets<br/>Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html |
| [re2](https://github.com/google/re2) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) | | [re2](https://github.com/google/re2) | [BSD 3-Clause "New" or "Revised" License](https://spdx.org/licenses/BSD-3-Clause.html) |
| [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) | | [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [SQLite](https://www.sqlite.org/) | Public Domain | | [SQLite](https://www.sqlite.org/) | Public Domain |

View file

@ -28,6 +28,7 @@ find_package(QT NAMES Qt6
OpenGL OpenGL
OpenGLWidgets OpenGLWidgets
Positioning Positioning
SerialPort
Svg Svg
Widgets REQUIRED) Widgets REQUIRED)
@ -39,6 +40,7 @@ find_package(Qt${QT_VERSION_MAJOR}
OpenGL OpenGL
OpenGLWidgets OpenGLWidgets
Positioning Positioning
SerialPort
Svg Svg
Widgets Widgets
REQUIRED) REQUIRED)
@ -248,6 +250,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
source/scwx/qt/ui/placefile_settings_widget.hpp source/scwx/qt/ui/placefile_settings_widget.hpp
source/scwx/qt/ui/progress_dialog.hpp source/scwx/qt/ui/progress_dialog.hpp
source/scwx/qt/ui/radar_site_dialog.hpp source/scwx/qt/ui/radar_site_dialog.hpp
source/scwx/qt/ui/serial_port_dialog.hpp
source/scwx/qt/ui/settings_dialog.hpp source/scwx/qt/ui/settings_dialog.hpp
source/scwx/qt/ui/update_dialog.hpp) source/scwx/qt/ui/update_dialog.hpp)
set(SRC_UI source/scwx/qt/ui/about_dialog.cpp set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
@ -272,6 +275,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
source/scwx/qt/ui/progress_dialog.cpp source/scwx/qt/ui/progress_dialog.cpp
source/scwx/qt/ui/radar_site_dialog.cpp source/scwx/qt/ui/radar_site_dialog.cpp
source/scwx/qt/ui/settings_dialog.cpp source/scwx/qt/ui/settings_dialog.cpp
source/scwx/qt/ui/serial_port_dialog.cpp
source/scwx/qt/ui/update_dialog.cpp) source/scwx/qt/ui/update_dialog.cpp)
set(UI_UI source/scwx/qt/ui/about_dialog.ui set(UI_UI source/scwx/qt/ui/about_dialog.ui
source/scwx/qt/ui/alert_dialog.ui source/scwx/qt/ui/alert_dialog.ui
@ -287,6 +291,7 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui
source/scwx/qt/ui/progress_dialog.ui source/scwx/qt/ui/progress_dialog.ui
source/scwx/qt/ui/radar_site_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui
source/scwx/qt/ui/settings_dialog.ui source/scwx/qt/ui/settings_dialog.ui
source/scwx/qt/ui/serial_port_dialog.ui
source/scwx/qt/ui/update_dialog.ui) source/scwx/qt/ui/update_dialog.ui)
set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp
source/scwx/qt/ui/settings/settings_page_widget.hpp source/scwx/qt/ui/settings/settings_page_widget.hpp
@ -597,6 +602,7 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::OpenGLWidgets Qt${QT_VERSION_MAJOR}::OpenGLWidgets
Qt${QT_VERSION_MAJOR}::Multimedia Qt${QT_VERSION_MAJOR}::Multimedia
Qt${QT_VERSION_MAJOR}::Positioning Qt${QT_VERSION_MAJOR}::Positioning
Qt${QT_VERSION_MAJOR}::SerialPort
Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Svg
Boost::json Boost::json
Boost::timer Boost::timer

View file

@ -0,0 +1,199 @@
#define __STDC_WANT_LIB_EXT1__ 1
#include "serial_port_dialog.hpp"
#include "ui_serial_port_dialog.h"
#include <scwx/util/logger.hpp>
#include <QPushButton>
#include <QSerialPortInfo>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#if defined(_WIN32)
# include <Windows.h>
# include <cstdlib>
# include <tchar.h>
#endif
namespace scwx
{
namespace qt
{
namespace ui
{
static const std::string logPrefix_ = "scwx::qt::ui::serial_port_dialog";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
class SerialPortDialog::Impl
{
public:
explicit Impl(SerialPortDialog* self) :
self_ {self}, model_ {new QStandardItemModel(self)}
{
}
~Impl() = default;
void LogSerialPortInfo(const QSerialPortInfo& info);
void ReadComPortSettings();
void RefreshSerialDevices();
SerialPortDialog* self_;
QStandardItemModel* model_;
std::string selectedSerialPort_ {"?"};
};
SerialPortDialog::SerialPortDialog(QWidget* parent) :
QDialog(parent),
p {std::make_unique<Impl>(this)},
ui(new Ui::SerialPortDialog)
{
ui->setupUi(this);
connect(ui->refreshButton,
&QAbstractButton::clicked,
this,
[this]() { p->RefreshSerialDevices(); });
}
SerialPortDialog::~SerialPortDialog()
{
delete ui;
}
std::string SerialPortDialog::serial_port()
{
return p->selectedSerialPort_;
}
void SerialPortDialog::Impl::LogSerialPortInfo(const QSerialPortInfo& info)
{
logger_->debug("Serial Port: {}", info.portName().toStdString());
logger_->debug(" Description: {}", info.description().toStdString());
logger_->debug(" System Loc: {}", info.systemLocation().toStdString());
logger_->debug(" Manufacturer: {}", info.manufacturer().toStdString());
logger_->debug(" Vendor ID: {}", info.vendorIdentifier());
logger_->debug(" Product ID: {}", info.productIdentifier());
logger_->debug(" Serial No: {}", info.serialNumber().toStdString());
}
void SerialPortDialog::Impl::RefreshSerialDevices()
{
QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
for (auto& port : availablePorts)
{
LogSerialPortInfo(port);
}
ReadComPortSettings();
}
void SerialPortDialog::Impl::ReadComPortSettings()
{
#if defined(_WIN32)
const LPCTSTR lpSubKey =
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports");
DWORD ulOptions = 0;
REGSAM samDesired = KEY_READ;
HKEY hkResult;
LSTATUS status;
// Open Port Settings Key
status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE, lpSubKey, ulOptions, samDesired, &hkResult);
if (status == ERROR_SUCCESS)
{
DWORD dwIndex = 0;
TCHAR valueName[MAX_PATH];
LPDWORD lpReserved = nullptr;
DWORD type;
TCHAR valueData[64];
char buffer[MAX_PATH]; // Buffer for string conversion
// Number of characters, not including terminating null
static constexpr DWORD maxValueNameSize =
sizeof(valueName) / sizeof(TCHAR) - 1;
DWORD valueNameSize = maxValueNameSize;
// Number of bytes
DWORD valueDataSize = sizeof(valueData);
static constexpr std::size_t bufferSize = sizeof(buffer);
// Enumerate each port value
while ((status = RegEnumValue(hkResult,
dwIndex,
valueName,
&valueNameSize,
lpReserved,
&type,
(LPBYTE) &valueData,
&valueDataSize)) == ERROR_SUCCESS ||
status == ERROR_MORE_DATA)
{
// Validate port value
if (status == ERROR_SUCCESS && //
type == REG_SZ && //
valueNameSize >= 5 && // COM#:
valueNameSize < sizeof(buffer) - 1 && // Strip off :
valueDataSize > sizeof(TCHAR) && // Null character
_tcsncmp(valueName, TEXT("COM"), 3) == 0)
{
errno_t error;
std::size_t returnValue;
// Get port name
if ((error = wcstombs_s(&returnValue,
buffer,
sizeof(buffer),
valueName,
valueNameSize - 1)) != 0)
{
logger_->error(
"Error converting registry value name to string: {}",
returnValue);
continue;
}
std::string portName = buffer;
// Get port data
if ((error = wcstombs_s(&returnValue,
buffer,
sizeof(buffer),
valueData,
sizeof(buffer) - 1)) != 0)
{
logger_->error(
"Error converting registry value data to string: {}",
returnValue);
continue;
}
std::string portData = buffer;
logger_->debug("Port {} has data \"{}\"", portName, portData);
}
valueNameSize = maxValueNameSize;
valueDataSize = sizeof(valueData);
++dwIndex;
}
RegCloseKey(hkResult);
}
else
{
logger_->warn("Could not open COM port settings registry key: {}",
status);
}
#endif
}
} // namespace ui
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,35 @@
#pragma once
#include <QDialog>
namespace Ui
{
class SerialPortDialog;
}
namespace scwx
{
namespace qt
{
namespace ui
{
class SerialPortDialog : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(SerialPortDialog)
public:
explicit SerialPortDialog(QWidget* parent = nullptr);
~SerialPortDialog();
std::string serial_port();
private:
class Impl;
std::unique_ptr<Impl> p;
Ui::SerialPortDialog* ui;
};
} // namespace ui
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SerialPortDialog</class>
<widget class="QDialog" name="SerialPortDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Serial Port</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="serialPortView"/>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="refreshButton">
<property name="text">
<string>&amp;Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SerialPortDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SerialPortDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>