Add macOS USB UART support
This commit is contained in:
+16
-1
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
project(location_plotter VERSION 0.1.0 LANGUAGES CXX)
|
project(location_plotter VERSION 0.2.0 LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -31,6 +31,16 @@ add_executable(location_plotter
|
|||||||
|
|
||||||
target_link_libraries(location_plotter PRIVATE Qt6::Core Qt6::Widgets Qt6::Network ZLIB::ZLIB)
|
target_link_libraries(location_plotter PRIVATE Qt6::Core Qt6::Widgets Qt6::Network ZLIB::ZLIB)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set_target_properties(location_plotter PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "Location Plotter"
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER "com.ankasys.location-plotter"
|
||||||
|
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
|
||||||
|
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
qt_add_resources(location_plotter "app_resources"
|
qt_add_resources(location_plotter "app_resources"
|
||||||
PREFIX "/"
|
PREFIX "/"
|
||||||
FILES resources/ankasys-logo.png resources/land-110m.json
|
FILES resources/ankasys-logo.png resources/land-110m.json
|
||||||
@@ -82,3 +92,8 @@ endif()
|
|||||||
add_test(NAME location_main_window_tests COMMAND location_main_window_tests)
|
add_test(NAME location_main_window_tests COMMAND location_main_window_tests)
|
||||||
set_tests_properties(location_main_window_tests PROPERTIES
|
set_tests_properties(location_main_window_tests PROPERTIES
|
||||||
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;XDG_CACHE_HOME=/tmp/location-plotter-test-cache")
|
ENVIRONMENT "QT_QPA_PLATFORM=offscreen;XDG_CACHE_HOME=/tmp/location-plotter-test-cache")
|
||||||
|
|
||||||
|
install(TARGETS location_plotter
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Location Plotter
|
# Location Plotter
|
||||||
|
|
||||||
Qt6/C++ GUI that listens to `/dev/ttyUSB2`, parses normal debug lines, and plots live
|
Qt6/C++ GUI that listens to a USB UART on Linux or macOS, parses normal debug lines,
|
||||||
locations on a map.
|
and plots live locations on a map.
|
||||||
|
|
||||||
The application also includes an interactive 3D Earth/orbit view. It downloads the current
|
The application also includes an interactive 3D Earth/orbit view. It downloads the current
|
||||||
stream-derived RINEX 3 navigation file from the BKG/IGS archive at startup and every 15
|
stream-derived RINEX 3 navigation file from the BKG/IGS archive at startup and every 15
|
||||||
@@ -95,6 +95,50 @@ make platform_scenario_matrix_test
|
|||||||
Desteklenen senaryolar `stationary`, `pedestrian`, `car`, `aircraft`; GNSS
|
Desteklenen senaryolar `stationary`, `pedestrian`, `car`, `aircraft`; GNSS
|
||||||
periyotları 200/500/1000 ms, IMU periyotları 19/20/200/300 ms'dir.
|
periyotları 200/500/1000 ms, IMU periyotları 19/20/200/300 ms'dir.
|
||||||
|
|
||||||
|
## macOS'ta kurulum (MacBook Air, Apple Silicon veya Intel)
|
||||||
|
|
||||||
|
Guncel macOS surumunde once [Homebrew](https://brew.sh) kurulu olmalidir. Ardindan:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd location_plotter
|
||||||
|
chmod +x setup-macos.sh run.sh
|
||||||
|
./setup-macos.sh
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Betik Homebrew ile guncel `cmake` ve `qt` paketlerini kurar, yerel mimari icin
|
||||||
|
`location_plotter.app` paketini derler, gerekli Qt kutuphanelerini uygulama paketine
|
||||||
|
ekler ve testleri calistirir.
|
||||||
|
|
||||||
|
macOS USB UART aygitlarini genellikle iki adla gosterir:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/dev/cu.usbserial-XXXXXXXX
|
||||||
|
/dev/tty.usbserial-XXXXXXXX
|
||||||
|
```
|
||||||
|
|
||||||
|
veya bir CDC aygitinda:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/dev/cu.usbmodemXXXX
|
||||||
|
/dev/tty.usbmodemXXXX
|
||||||
|
```
|
||||||
|
|
||||||
|
Uygulama her iki bicimi de algilar. Mümkünse `cu.usb...` yolunu secin; macOS'ta
|
||||||
|
disariya baglanti baslatan uygulamalar icin uygun olan aygit budur. UART uygulama
|
||||||
|
acikken takildiysa port alaninin yanindaki `Yenile` dugmesine basin. Otomatik
|
||||||
|
algilanmayan bir yol port alanina elle de yazilabilir.
|
||||||
|
|
||||||
|
Istenen port baslatmadan once ortam degiskeniyle de secilebilir:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LOCATION_PLOTTER_PORT=/dev/cu.usbserial-XXXXXXXX ./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Port hic gorunmuyorsa `ls /dev/cu.usb* /dev/tty.usb*` ile macOS'un aygiti olusturup
|
||||||
|
olusturmadigini kontrol edin. Hic sonuc yoksa kabloyu/veri baglantisini ve UART
|
||||||
|
donaniminizin macOS surucusunu kontrol edin.
|
||||||
|
|
||||||
## Ubuntu'da kurulum
|
## Ubuntu'da kurulum
|
||||||
|
|
||||||
Ubuntu 22.04 ve daha yeni surumlerde gerekli paketleri kurmak, uygulamayi derlemek ve
|
Ubuntu 22.04 ve daha yeni surumlerde gerekli paketleri kurmak, uygulamayi derlemek ve
|
||||||
@@ -140,8 +184,10 @@ Uygulama Qt tabanli bir masaustu arayuzudur; grafik oturumu olan bir Ubuntu maki
|
|||||||
calistirilmalidir. Harita karolari ve guncel RINEX verisi icin internet erisimi gerekir,
|
calistirilmalidir. Harita karolari ve guncel RINEX verisi icin internet erisimi gerekir,
|
||||||
ancak son gecerli RINEX verisi ve harita onbellegiyle cevrimdisi kullanim da desteklenir.
|
ancak son gecerli RINEX verisi ve harita onbellegiyle cevrimdisi kullanim da desteklenir.
|
||||||
|
|
||||||
The port selector lists only detected `/dev/ttyUSB*` devices. The default selection is
|
Port secici Linux'ta `/dev/ttyUSB*` ve `/dev/ttyACM*`; macOS'ta USB ile ilgili
|
||||||
`/dev/ttyUSB2` and the default baud rate is `115200`.
|
`/dev/cu.*` ve `/dev/tty.*` aygitlarini listeler. Hic aygit algilanmazsa Linux'ta
|
||||||
|
`/dev/ttyUSB2`, macOS'ta `/dev/cu.usbserial` duzenlenebilir bir varsayilan yol olarak
|
||||||
|
gosterilir. Varsayilan baud rate `115200`'dur.
|
||||||
|
|
||||||
If the port cannot be opened, make sure the user has serial access:
|
If the port cannot be opened, make sure the user has serial access:
|
||||||
|
|
||||||
|
|||||||
@@ -5,29 +5,46 @@ cd "$(dirname "$0")"
|
|||||||
|
|
||||||
print_qt_install_hint() {
|
print_qt_install_hint() {
|
||||||
echo
|
echo
|
||||||
|
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||||
|
echo "Qt6 bulunamadi. macOS'ta gerekli paketleri kurmak icin:"
|
||||||
|
echo " brew install cmake qt"
|
||||||
|
echo "veya doğrudan: ./setup-macos.sh"
|
||||||
|
else
|
||||||
echo "Qt6 bulunamadi. Ubuntu'da gerekli paketleri kurmak icin:"
|
echo "Qt6 bulunamadi. Ubuntu'da gerekli paketleri kurmak icin:"
|
||||||
echo " sudo apt update"
|
echo " sudo apt update"
|
||||||
echo " sudo apt install build-essential cmake qt6-base-dev"
|
echo " sudo apt install build-essential cmake qt6-base-dev"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
project_dir="$(pwd -P)"
|
project_dir="$(pwd -P)"
|
||||||
|
|
||||||
if [[ -f ./build/CMakeCache.txt ]]; then
|
if [[ -f ./build/CMakeCache.txt ]]; then
|
||||||
cached_source="$(sed -n 's/^CMAKE_HOME_DIRECTORY:INTERNAL=//p' ./build/CMakeCache.txt)"
|
cached_source="$(sed -n 's/^CMAKE_HOME_DIRECTORY:INTERNAL=//p' ./build/CMakeCache.txt)"
|
||||||
if [[ -n "$cached_source" && "$cached_source" != "$project_dir" ]]; then
|
cached_system="$(sed -n 's/^CMAKE_SYSTEM_NAME:INTERNAL=//p' ./build/CMakeCache.txt)"
|
||||||
echo "Build klasoru farkli bir proje yoluna ait, yeniden olusturuluyor:"
|
host_system="$(uname -s)"
|
||||||
echo " $cached_source"
|
if [[ ( -n "$cached_source" && "$cached_source" != "$project_dir" ) \
|
||||||
|
|| ( -n "$cached_system" && "$cached_system" != "$host_system" ) ]]; then
|
||||||
|
echo "Build klasoru farkli bir proje yolu veya sisteme ait, yeniden olusturuluyor."
|
||||||
rm -rf ./build
|
rm -rf ./build
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! cmake -S . -B build; then
|
cmake_args=(-S . -B build)
|
||||||
|
if [[ "$(uname -s)" == "Darwin" ]] && command -v brew >/dev/null 2>&1; then
|
||||||
|
cmake_args+=("-DCMAKE_PREFIX_PATH=$(brew --prefix qt)")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cmake "${cmake_args[@]}"; then
|
||||||
print_qt_install_hint
|
print_qt_install_hint
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
|
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||||||
|
exec ./build/location_plotter.app/Contents/MacOS/location_plotter "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
missing_libs="$(ldd ./build/location_plotter 2>/dev/null | awk '/not found/ { print $1 }' || true)"
|
missing_libs="$(ldd ./build/location_plotter 2>/dev/null | awk '/not found/ { print $1 }' || true)"
|
||||||
if [[ -n "$missing_libs" ]]; then
|
if [[ -n "$missing_libs" ]]; then
|
||||||
echo "Eksik paylasimli kutuphaneler:"
|
echo "Eksik paylasimli kutuphaneler:"
|
||||||
|
|||||||
Executable
+47
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
if [[ "$(uname -s)" != "Darwin" ]]; then
|
||||||
|
echo "Bu kurulum betigi macOS icindir." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v brew >/dev/null 2>&1; then
|
||||||
|
echo "Homebrew bulunamadi. Once https://brew.sh adresindeki Homebrew kurulumunu tamamlayin." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Gerekli macOS paketleri kuruluyor..."
|
||||||
|
brew install cmake qt
|
||||||
|
|
||||||
|
qt_prefix="$(brew --prefix qt)"
|
||||||
|
parallel_jobs="$(sysctl -n hw.logicalcpu 2>/dev/null || echo 4)"
|
||||||
|
|
||||||
|
if [[ -f build/CMakeCache.txt ]]; then
|
||||||
|
cached_system="$(sed -n 's/^CMAKE_SYSTEM_NAME:INTERNAL=//p' build/CMakeCache.txt)"
|
||||||
|
if [[ -n "$cached_system" && "$cached_system" != "Darwin" ]]; then
|
||||||
|
echo "Baska bir sisteme ait build klasoru yeniden olusturuluyor."
|
||||||
|
rm -rf build
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Uygulama derleniyor..."
|
||||||
|
cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_PREFIX_PATH="$qt_prefix"
|
||||||
|
cmake --build build --parallel "$parallel_jobs"
|
||||||
|
|
||||||
|
echo "Testler calistiriliyor..."
|
||||||
|
ctest --test-dir build --output-on-failure
|
||||||
|
|
||||||
|
echo "macOS uygulama paketi hazirlaniyor..."
|
||||||
|
"$qt_prefix/bin/macdeployqt" build/location_plotter.app -always-overwrite
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Kurulum tamamlandi. Uygulamayi baslatmak icin:"
|
||||||
|
echo " ./run.sh"
|
||||||
|
echo
|
||||||
|
echo "USB UART icin port listesinden /dev/cu.usb... aygitini secin."
|
||||||
|
echo "/dev/tty.usb... gorunuyorsa o yol da desteklenir."
|
||||||
+79
-13
@@ -212,6 +212,45 @@ QString optionalDopText(const std::optional<double> &value)
|
|||||||
return QString::number(*value, 'f', 3);
|
return QString::number(*value, 'f', 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList detectedSerialPorts()
|
||||||
|
{
|
||||||
|
const QDir deviceDirectory(QStringLiteral("/dev"));
|
||||||
|
QStringList patterns;
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
// macOS exposes USB UARTs as paired callout (cu.*) and terminal (tty.*)
|
||||||
|
// devices. Prefer cu.* because it does not wait for carrier detect.
|
||||||
|
patterns = {
|
||||||
|
QStringLiteral("cu.usb*"), QStringLiteral("cu.wchusbserial*"),
|
||||||
|
QStringLiteral("cu.SLAB_USBtoUART*"), QStringLiteral("cu.*USB*"),
|
||||||
|
QStringLiteral("tty.usb*"), QStringLiteral("tty.wchusbserial*"),
|
||||||
|
QStringLiteral("tty.SLAB_USBtoUART*"), QStringLiteral("tty.*USB*")};
|
||||||
|
#else
|
||||||
|
patterns = {QStringLiteral("ttyUSB*"), QStringLiteral("ttyACM*")};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QStringList ports;
|
||||||
|
for (const QString &pattern : patterns) {
|
||||||
|
const QStringList names = deviceDirectory.entryList(
|
||||||
|
{pattern}, QDir::System | QDir::Files, QDir::Name);
|
||||||
|
for (const QString &name : names) {
|
||||||
|
const QString path = QStringLiteral("/dev/") + name;
|
||||||
|
if (!ports.contains(path)) {
|
||||||
|
ports.push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fallbackSerialPort()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
return QStringLiteral("/dev/cu.usbserial");
|
||||||
|
#else
|
||||||
|
return QStringLiteral("/dev/ttyUSB2");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void mergeDopValues(DopValues &target, const DopValues &source)
|
void mergeDopValues(DopValues &target, const DopValues &source)
|
||||||
{
|
{
|
||||||
if (source.gdop.has_value()) {
|
if (source.gdop.has_value()) {
|
||||||
@@ -425,6 +464,34 @@ void MainWindow::openTelemetryLog()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshSerialPorts()
|
||||||
|
{
|
||||||
|
const QString previousPort = m_portCombo->currentText().trimmed();
|
||||||
|
const QString configuredPort = qEnvironmentVariable("LOCATION_PLOTTER_PORT").trimmed();
|
||||||
|
const QStringList detectedPorts = detectedSerialPorts();
|
||||||
|
|
||||||
|
m_portCombo->clear();
|
||||||
|
for (const QString &port : detectedPorts) {
|
||||||
|
m_portCombo->addItem(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString selectedPort;
|
||||||
|
if (!configuredPort.isEmpty()) {
|
||||||
|
selectedPort = configuredPort;
|
||||||
|
} else if (!previousPort.isEmpty() && detectedPorts.contains(previousPort)) {
|
||||||
|
selectedPort = previousPort;
|
||||||
|
} else if (!detectedPorts.isEmpty()) {
|
||||||
|
selectedPort = detectedPorts.first();
|
||||||
|
} else {
|
||||||
|
selectedPort = previousPort.isEmpty() ? fallbackSerialPort() : previousPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_portCombo->findText(selectedPort) < 0) {
|
||||||
|
m_portCombo->addItem(selectedPort);
|
||||||
|
}
|
||||||
|
m_portCombo->setCurrentText(selectedPort);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::handleSerialLine(const QString &line)
|
void MainWindow::handleSerialLine(const QString &line)
|
||||||
{
|
{
|
||||||
static const QRegularExpression solveStartRegex(
|
static const QRegularExpression solveStartRegex(
|
||||||
@@ -727,19 +794,16 @@ void MainWindow::buildUi()
|
|||||||
|
|
||||||
m_portCombo = new QComboBox(this);
|
m_portCombo = new QComboBox(this);
|
||||||
m_portCombo->setObjectName(QStringLiteral("portSelector"));
|
m_portCombo->setObjectName(QStringLiteral("portSelector"));
|
||||||
m_portCombo->setMinimumWidth(165);
|
m_portCombo->setMinimumWidth(220);
|
||||||
m_portCombo->setEditable(false);
|
m_portCombo->setEditable(true);
|
||||||
QDir deviceDirectory(QStringLiteral("/dev"));
|
m_portCombo->setToolTip(QStringLiteral(
|
||||||
const QStringList deviceNames = deviceDirectory.entryList(
|
"USB UART portu. macOS'ta /dev/cu.usb... tercih edilir; /dev/tty.usb... da desteklenir."));
|
||||||
{QStringLiteral("ttyUSB*")},
|
refreshSerialPorts();
|
||||||
QDir::System | QDir::Files | QDir::Readable, QDir::Name);
|
|
||||||
for (const QString &deviceName : deviceNames) {
|
auto *refreshPortsButton = new QToolButton(this);
|
||||||
m_portCombo->addItem(QStringLiteral("/dev/") + deviceName);
|
refreshPortsButton->setObjectName(QStringLiteral("refreshPortsButton"));
|
||||||
}
|
refreshPortsButton->setText(QStringLiteral("Yenile"));
|
||||||
if (m_portCombo->findText(QStringLiteral("/dev/ttyUSB2")) < 0) {
|
refreshPortsButton->setToolTip(QStringLiteral("Seri port listesini yenile"));
|
||||||
m_portCombo->addItem(QStringLiteral("/dev/ttyUSB2"));
|
|
||||||
}
|
|
||||||
m_portCombo->setCurrentText(QStringLiteral("/dev/ttyUSB2"));
|
|
||||||
|
|
||||||
m_baudCombo = new QComboBox(this);
|
m_baudCombo = new QComboBox(this);
|
||||||
for (const int baud : {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600}) {
|
for (const int baud : {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600}) {
|
||||||
@@ -773,6 +837,7 @@ void MainWindow::buildUi()
|
|||||||
|
|
||||||
toolbarLayout->addWidget(new QLabel(QStringLiteral("Port"), this));
|
toolbarLayout->addWidget(new QLabel(QStringLiteral("Port"), this));
|
||||||
toolbarLayout->addWidget(m_portCombo);
|
toolbarLayout->addWidget(m_portCombo);
|
||||||
|
toolbarLayout->addWidget(refreshPortsButton);
|
||||||
toolbarLayout->addWidget(new QLabel(QStringLiteral("Baud"), this));
|
toolbarLayout->addWidget(new QLabel(QStringLiteral("Baud"), this));
|
||||||
toolbarLayout->addWidget(m_baudCombo);
|
toolbarLayout->addWidget(m_baudCombo);
|
||||||
toolbarLayout->addWidget(new QLabel(QStringLiteral("Max"), this));
|
toolbarLayout->addWidget(new QLabel(QStringLiteral("Max"), this));
|
||||||
@@ -996,6 +1061,7 @@ void MainWindow::buildUi()
|
|||||||
connect(m_connectButton, &QPushButton::clicked, this, &MainWindow::toggleSerial);
|
connect(m_connectButton, &QPushButton::clicked, this, &MainWindow::toggleSerial);
|
||||||
connect(m_clearButton, &QPushButton::clicked, this, &MainWindow::clearPoints);
|
connect(m_clearButton, &QPushButton::clicked, this, &MainWindow::clearPoints);
|
||||||
connect(m_openLogButton, &QPushButton::clicked, this, &MainWindow::openTelemetryLog);
|
connect(m_openLogButton, &QPushButton::clicked, this, &MainWindow::openTelemetryLog);
|
||||||
|
connect(refreshPortsButton, &QToolButton::clicked, this, &MainWindow::refreshSerialPorts);
|
||||||
connect(m_maxPointsSpin, qOverload<int>(&QSpinBox::valueChanged), this,
|
connect(m_maxPointsSpin, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||||
&MainWindow::trimToMaxPoints);
|
&MainWindow::trimToMaxPoints);
|
||||||
connect(m_autoFollowCheck, &QCheckBox::toggled, m_map, &MapWidget::setAutoFollow);
|
connect(m_autoFollowCheck, &QCheckBox::toggled, m_map, &MapWidget::setAutoFollow);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ private slots:
|
|||||||
void updateReferenceLocation();
|
void updateReferenceLocation();
|
||||||
void flushUiUpdates();
|
void flushUiUpdates();
|
||||||
void openTelemetryLog();
|
void openTelemetryLog();
|
||||||
|
void refreshSerialPorts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildUi();
|
void buildUi();
|
||||||
|
|||||||
+57
-21
@@ -10,38 +10,70 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
#include <IOKit/serial/ioss.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr qsizetype MaxBytesPerReadCycle = 64 * 1024;
|
constexpr qsizetype MaxBytesPerReadCycle = 64 * 1024;
|
||||||
|
|
||||||
speed_t baudToSpeed(int baudRate)
|
bool applyBaudRate(termios &options, int baudRate)
|
||||||
{
|
{
|
||||||
|
speed_t speed = 0;
|
||||||
switch (baudRate) {
|
switch (baudRate) {
|
||||||
case 1200:
|
case 1200:
|
||||||
return B1200;
|
speed = B1200;
|
||||||
|
break;
|
||||||
case 2400:
|
case 2400:
|
||||||
return B2400;
|
speed = B2400;
|
||||||
|
break;
|
||||||
case 4800:
|
case 4800:
|
||||||
return B4800;
|
speed = B4800;
|
||||||
|
break;
|
||||||
case 9600:
|
case 9600:
|
||||||
return B9600;
|
speed = B9600;
|
||||||
|
break;
|
||||||
case 19200:
|
case 19200:
|
||||||
return B19200;
|
speed = B19200;
|
||||||
|
break;
|
||||||
case 38400:
|
case 38400:
|
||||||
return B38400;
|
speed = B38400;
|
||||||
|
break;
|
||||||
case 57600:
|
case 57600:
|
||||||
return B57600;
|
speed = B57600;
|
||||||
|
break;
|
||||||
case 115200:
|
case 115200:
|
||||||
return B115200;
|
speed = B115200;
|
||||||
|
break;
|
||||||
|
#ifdef B230400
|
||||||
case 230400:
|
case 230400:
|
||||||
return B230400;
|
speed = B230400;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B460800
|
||||||
case 460800:
|
case 460800:
|
||||||
return B460800;
|
speed = B460800;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef B921600
|
||||||
case 921600:
|
case 921600:
|
||||||
return B921600;
|
speed = B921600;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
return 0;
|
#ifdef Q_OS_MACOS
|
||||||
|
// IOSSIOSPEED below applies the exact requested rate. A valid termios
|
||||||
|
// placeholder is still required before that ioctl can be issued.
|
||||||
|
speed = B9600;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ::cfsetispeed(&options, speed) == 0
|
||||||
|
&& ::cfsetospeed(&options, speed) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -176,12 +208,6 @@ void SerialReader::flushPartialLine()
|
|||||||
|
|
||||||
bool SerialReader::configurePort(int baudRate)
|
bool SerialReader::configurePort(int baudRate)
|
||||||
{
|
{
|
||||||
const speed_t speed = baudToSpeed(baudRate);
|
|
||||||
if (speed == 0) {
|
|
||||||
emit errorOccurred(QStringLiteral("Desteklenmeyen baud rate: %1").arg(baudRate));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
termios options {};
|
termios options {};
|
||||||
if (::tcgetattr(m_fd, &options) != 0) {
|
if (::tcgetattr(m_fd, &options) != 0) {
|
||||||
emitSystemError(QStringLiteral("Port ayarlari okunamadi"));
|
emitSystemError(QStringLiteral("Port ayarlari okunamadi"));
|
||||||
@@ -189,8 +215,10 @@ bool SerialReader::configurePort(int baudRate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
::cfmakeraw(&options);
|
::cfmakeraw(&options);
|
||||||
::cfsetispeed(&options, speed);
|
if (!applyBaudRate(options, baudRate)) {
|
||||||
::cfsetospeed(&options, speed);
|
emit errorOccurred(QStringLiteral("Bu sistemde desteklenmeyen baud rate: %1").arg(baudRate));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
options.c_cflag |= CLOCAL | CREAD;
|
options.c_cflag |= CLOCAL | CREAD;
|
||||||
options.c_cflag &= ~HUPCL;
|
options.c_cflag &= ~HUPCL;
|
||||||
@@ -206,6 +234,14 @@ bool SerialReader::configurePort(int baudRate)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
speed_t requestedSpeed = static_cast<speed_t>(baudRate);
|
||||||
|
if (::ioctl(m_fd, IOSSIOSPEED, &requestedSpeed) != 0) {
|
||||||
|
emitSystemError(QStringLiteral("macOS baud rate uygulanamadi"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
::tcflush(m_fd, TCIFLUSH);
|
::tcflush(m_fd, TCIFLUSH);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ void flushUpdates(MainWindow &window)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
qputenv("LOCATION_PLOTTER_PORT", "/dev/test-usb-uart");
|
||||||
MainWindow window;
|
MainWindow window;
|
||||||
|
qunsetenv("LOCATION_PLOTTER_PORT");
|
||||||
|
|
||||||
auto *table = window.findChild<QTableView *>();
|
auto *table = window.findChild<QTableView *>();
|
||||||
auto *referenceLatInput = window.findChild<QLineEdit *>(QStringLiteral("referenceLatInput"));
|
auto *referenceLatInput = window.findChild<QLineEdit *>(QStringLiteral("referenceLatInput"));
|
||||||
@@ -67,10 +69,11 @@ int main(int argc, char **argv)
|
|||||||
assert(showRecentPoints != nullptr);
|
assert(showRecentPoints != nullptr);
|
||||||
assert(showAverage != nullptr);
|
assert(showAverage != nullptr);
|
||||||
assert(portSelector != nullptr);
|
assert(portSelector != nullptr);
|
||||||
assert(!portSelector->isEditable());
|
assert(portSelector->isEditable());
|
||||||
assert(portSelector->count() >= 1);
|
assert(portSelector->count() >= 1);
|
||||||
|
assert(portSelector->currentText() == QStringLiteral("/dev/test-usb-uart"));
|
||||||
for (int i = 0; i < portSelector->count(); ++i) {
|
for (int i = 0; i < portSelector->count(); ++i) {
|
||||||
assert(portSelector->itemText(i).startsWith(QStringLiteral("/dev/ttyUSB")));
|
assert(portSelector->itemText(i).startsWith(QStringLiteral("/dev/")));
|
||||||
assert(!portSelector->itemText(i).trimmed().isEmpty());
|
assert(!portSelector->itemText(i).trimmed().isEmpty());
|
||||||
}
|
}
|
||||||
assert(map != nullptr);
|
assert(map != nullptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user