|
|
|
|
@@ -2,25 +2,25 @@
|
|
|
|
|
// Created by Lenn on 2025/10/14.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QObject>
|
|
|
|
|
#include <QMetaObject>
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
#include <QtCore/Qt>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <qsize.h>
|
|
|
|
|
#include <qsizepolicy.h>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QObject>
|
|
|
|
|
#include <QMetaObject>
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
#include <QtCore/Qt>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <qsize.h>
|
|
|
|
|
#include <qsizepolicy.h>
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include "component.hh"
|
|
|
|
|
#include "cpstream_core.hh"
|
|
|
|
|
#include "modern-qt/utility/theme/theme.hh"
|
|
|
|
|
@@ -42,7 +42,7 @@
|
|
|
|
|
#include <modern-qt/widget/text.hh>
|
|
|
|
|
#include <modern-qt/widget/select.hh>
|
|
|
|
|
#include "components/ffmsep/tactile/tacdec.hh"
|
|
|
|
|
|
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
|
|
|
|
|
using namespace creeper;
|
|
|
|
|
namespace capro = card::pro;
|
|
|
|
|
@@ -98,10 +98,10 @@ public:
|
|
|
|
|
reset_core();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool start(const QString& requested_port, std::uint32_t baudrate) {
|
|
|
|
|
if (is_connected()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool start(const QString& requested_port, std::uint32_t baudrate) {
|
|
|
|
|
if (is_connected()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto ports = ffmsep::CPStreamCore::list_available_ports();
|
|
|
|
|
std::string port_utf8;
|
|
|
|
|
@@ -137,7 +137,7 @@ public:
|
|
|
|
|
cfg.packet_queue_capacity = 128;
|
|
|
|
|
cfg.frame_queue_capacity = 32;
|
|
|
|
|
cfg.slave_request_command.assign(kSlaveRequestCommand.begin(), kSlaveRequestCommand.end());
|
|
|
|
|
cfg.slave_request_interval = std::chrono::milliseconds{200};
|
|
|
|
|
cfg.slave_request_interval = 3ms;
|
|
|
|
|
|
|
|
|
|
reset_core();
|
|
|
|
|
core_ = std::make_unique<ffmsep::CPStreamCore>();
|
|
|
|
|
@@ -161,44 +161,44 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active_port_ = QString::fromStdString(cfg.port);
|
|
|
|
|
last_error_.clear();
|
|
|
|
|
connected_ = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stop() {
|
|
|
|
|
reset_core();
|
|
|
|
|
active_port_.clear();
|
|
|
|
|
if (heatmap_data_ && matrix_context_) {
|
|
|
|
|
heatmap_data_->set(make_flat_points(matrix_context_->get()));
|
|
|
|
|
}
|
|
|
|
|
connected_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool is_running() const noexcept {
|
|
|
|
|
return core_ && core_->is_running();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool is_connected() const noexcept {
|
|
|
|
|
return connected_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] QString active_port() const {
|
|
|
|
|
return active_port_;
|
|
|
|
|
}
|
|
|
|
|
last_error_.clear();
|
|
|
|
|
connected_ = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stop() {
|
|
|
|
|
reset_core();
|
|
|
|
|
active_port_.clear();
|
|
|
|
|
if (heatmap_data_ && matrix_context_) {
|
|
|
|
|
heatmap_data_->set(make_flat_points(matrix_context_->get()));
|
|
|
|
|
}
|
|
|
|
|
connected_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool is_running() const noexcept {
|
|
|
|
|
return core_ && core_->is_running();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool is_connected() const noexcept {
|
|
|
|
|
return connected_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] QString active_port() const {
|
|
|
|
|
return active_port_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] QString last_error() const {
|
|
|
|
|
return last_error_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void reset_core() {
|
|
|
|
|
connected_ = false;
|
|
|
|
|
if (!core_) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
core_->set_frame_callback({});
|
|
|
|
|
if (core_->is_running()) {
|
|
|
|
|
void reset_core() {
|
|
|
|
|
connected_ = false;
|
|
|
|
|
if (!core_) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
core_->set_frame_callback({});
|
|
|
|
|
if (core_->is_running()) {
|
|
|
|
|
core_->stop();
|
|
|
|
|
}
|
|
|
|
|
if (core_->is_open()) {
|
|
|
|
|
@@ -219,46 +219,46 @@ private:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto pressures = frame.tactile_pressures;
|
|
|
|
|
auto size_hint = frame.tactile_matrix_size;
|
|
|
|
|
auto frame_bytes = frame.frame.data;
|
|
|
|
|
std::vector<std::uint8_t> raw_payload;
|
|
|
|
|
if (frame.tactile) {
|
|
|
|
|
raw_payload = frame.tactile->payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QMetaObject::invokeMethod(
|
|
|
|
|
this,
|
|
|
|
|
[this,
|
|
|
|
|
pressures = std::move(pressures),
|
|
|
|
|
size_hint,
|
|
|
|
|
frame_bytes = std::move(frame_bytes),
|
|
|
|
|
raw_payload = std::move(raw_payload)]() {
|
|
|
|
|
const auto format_raw = [](const std::vector<std::uint8_t>& data) -> std::string {
|
|
|
|
|
if (data.empty()) {
|
|
|
|
|
return "[]";
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << '[';
|
|
|
|
|
oss << std::uppercase << std::setfill('0');
|
|
|
|
|
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
|
|
|
|
if (idx != 0U) {
|
|
|
|
|
oss << ' ';
|
|
|
|
|
}
|
|
|
|
|
oss << std::setw(2) << std::hex << static_cast<unsigned int>(data[idx]);
|
|
|
|
|
}
|
|
|
|
|
oss << ']';
|
|
|
|
|
return oss.str();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::cout << "[Sensor] frame=" << format_raw(frame_bytes);
|
|
|
|
|
std::cout << " payload=" << format_raw(raw_payload);
|
|
|
|
|
std::cout << " received " << pressures.size() << " pressure values";
|
|
|
|
|
if (size_hint) {
|
|
|
|
|
std::cout << " matrix=" << int(size_hint->long_edge)
|
|
|
|
|
<< "x" << int(size_hint->short_edge);
|
|
|
|
|
}
|
|
|
|
|
const std::size_t preview = std::min<std::size_t>(pressures.size(), 12);
|
|
|
|
|
auto pressures = frame.tactile_pressures;
|
|
|
|
|
auto size_hint = frame.tactile_matrix_size;
|
|
|
|
|
auto frame_bytes = frame.frame.data;
|
|
|
|
|
std::vector<std::uint8_t> raw_payload;
|
|
|
|
|
if (frame.tactile) {
|
|
|
|
|
raw_payload = frame.tactile->payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QMetaObject::invokeMethod(
|
|
|
|
|
this,
|
|
|
|
|
[this,
|
|
|
|
|
pressures = std::move(pressures),
|
|
|
|
|
size_hint,
|
|
|
|
|
frame_bytes = std::move(frame_bytes),
|
|
|
|
|
raw_payload = std::move(raw_payload)]() {
|
|
|
|
|
const auto format_raw = [](const std::vector<std::uint8_t>& data) -> std::string {
|
|
|
|
|
if (data.empty()) {
|
|
|
|
|
return "[]";
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << '[';
|
|
|
|
|
oss << std::uppercase << std::setfill('0');
|
|
|
|
|
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
|
|
|
|
if (idx != 0U) {
|
|
|
|
|
oss << ' ';
|
|
|
|
|
}
|
|
|
|
|
oss << std::setw(2) << std::hex << static_cast<unsigned int>(data[idx]);
|
|
|
|
|
}
|
|
|
|
|
oss << ']';
|
|
|
|
|
return oss.str();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::cout << "[Sensor] frame=" << format_raw(frame_bytes);
|
|
|
|
|
std::cout << " payload=" << format_raw(raw_payload);
|
|
|
|
|
std::cout << " received " << pressures.size() << " pressure values";
|
|
|
|
|
if (size_hint) {
|
|
|
|
|
std::cout << " matrix=" << int(size_hint->long_edge)
|
|
|
|
|
<< "x" << int(size_hint->short_edge);
|
|
|
|
|
}
|
|
|
|
|
const std::size_t preview = std::min<std::size_t>(pressures.size(), 12);
|
|
|
|
|
if (preview > 0) {
|
|
|
|
|
std::cout << " values=[";
|
|
|
|
|
for (std::size_t idx = 0; idx < preview; ++idx) {
|
|
|
|
|
@@ -305,107 +305,107 @@ private:
|
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] QSize normalize_matrix(QSize candidate, std::size_t value_count) const {
|
|
|
|
|
if (value_count == 0U) {
|
|
|
|
|
return QSize{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto adapt_from = [value_count](const QSize& hint) -> std::optional<QSize> {
|
|
|
|
|
if (hint.width() <= 0 && hint.height() <= 0) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hint.width() > 0 && hint.height() > 0) {
|
|
|
|
|
const auto cells = static_cast<std::size_t>(hint.width()) *
|
|
|
|
|
static_cast<std::size_t>(hint.height());
|
|
|
|
|
if (cells == value_count) {
|
|
|
|
|
return hint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hint.width() > 0) {
|
|
|
|
|
const auto width = static_cast<std::size_t>(hint.width());
|
|
|
|
|
if (width != 0U && (value_count % width) == 0U) {
|
|
|
|
|
const auto height = static_cast<int>(value_count / width);
|
|
|
|
|
return QSize{hint.width(), height};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hint.height() > 0) {
|
|
|
|
|
const auto height = static_cast<std::size_t>(hint.height());
|
|
|
|
|
if (height != 0U && (value_count % height) == 0U) {
|
|
|
|
|
const auto width = static_cast<int>(value_count / height);
|
|
|
|
|
return QSize{width, hint.height()};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (auto adjusted = adapt_from(candidate)) {
|
|
|
|
|
return *adjusted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto adjusted = adapt_from(matrix_context_->get())) {
|
|
|
|
|
return *adjusted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto root = static_cast<int>(std::sqrt(static_cast<double>(value_count)));
|
|
|
|
|
for (int width = root; width >= 1; --width) {
|
|
|
|
|
const auto divisor = static_cast<std::size_t>(width);
|
|
|
|
|
if (divisor == 0U) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ((value_count % divisor) == 0U) {
|
|
|
|
|
const auto height = static_cast<int>(value_count / divisor);
|
|
|
|
|
return QSize{width, height};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QSize{static_cast<int>(value_count), 1};
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] QSize normalize_matrix(QSize candidate, std::size_t value_count) const {
|
|
|
|
|
if (value_count == 0U) {
|
|
|
|
|
return QSize{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<MutableValue<QVector<PointData>>> heatmap_data_;
|
|
|
|
|
std::shared_ptr<MutableValue<QSize>> matrix_context_;
|
|
|
|
|
std::unique_ptr<ffmsep::CPStreamCore> core_;
|
|
|
|
|
QString active_port_;
|
|
|
|
|
QString last_error_;
|
|
|
|
|
bool connected_ = false;
|
|
|
|
|
};
|
|
|
|
|
const auto adapt_from = [value_count](const QSize& hint) -> std::optional<QSize> {
|
|
|
|
|
if (hint.width() <= 0 && hint.height() <= 0) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct SensorUiState {
|
|
|
|
|
std::shared_ptr<MutableValue<QString>> link_icon =
|
|
|
|
|
std::make_shared<MutableValue<QString>>(QString::fromLatin1(material::icon::kAddLink));
|
|
|
|
|
std::shared_ptr<MutableValue<QVector<PointData>>> heatmap_data =
|
|
|
|
|
std::make_shared<MutableValue<QVector<PointData>>>();
|
|
|
|
|
std::shared_ptr<MutableValue<QSize>> heatmap_matrix =
|
|
|
|
|
std::make_shared<MutableValue<QSize>>();
|
|
|
|
|
std::shared_ptr<MutableValue<QStringList>> port_items =
|
|
|
|
|
std::make_shared<MutableValue<QStringList>>();
|
|
|
|
|
QString selected_port;
|
|
|
|
|
std::uint32_t selected_baud = 115200;
|
|
|
|
|
std::unique_ptr<SensorStreamController> controller;
|
|
|
|
|
if (hint.width() > 0 && hint.height() > 0) {
|
|
|
|
|
const auto cells = static_cast<std::size_t>(hint.width()) *
|
|
|
|
|
static_cast<std::size_t>(hint.height());
|
|
|
|
|
if (cells == value_count) {
|
|
|
|
|
return hint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SensorUiState() {
|
|
|
|
|
const QSize size{3, 4};
|
|
|
|
|
heatmap_matrix->set_silent(size);
|
|
|
|
|
heatmap_data->set_silent(make_flat_points(size));
|
|
|
|
|
|
|
|
|
|
// 初始化串口列表
|
|
|
|
|
QStringList ports_list;
|
|
|
|
|
const auto ports = ffmsep::CPStreamCore::list_available_ports();
|
|
|
|
|
ports_list.reserve(static_cast<qsizetype>(ports.size()));
|
|
|
|
|
for (const auto& info : ports) {
|
|
|
|
|
ports_list.emplace_back(QString::fromStdString(info.port));
|
|
|
|
|
}
|
|
|
|
|
port_items->set_silent(ports_list);
|
|
|
|
|
if (selected_port.isEmpty() && !ports_list.isEmpty()) {
|
|
|
|
|
selected_port = ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
controller = std::make_unique<SensorStreamController>(heatmap_data, heatmap_matrix);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if (hint.width() > 0) {
|
|
|
|
|
const auto width = static_cast<std::size_t>(hint.width());
|
|
|
|
|
if (width != 0U && (value_count % width) == 0U) {
|
|
|
|
|
const auto height = static_cast<int>(value_count / width);
|
|
|
|
|
return QSize{hint.width(), height};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hint.height() > 0) {
|
|
|
|
|
const auto height = static_cast<std::size_t>(hint.height());
|
|
|
|
|
if (height != 0U && (value_count % height) == 0U) {
|
|
|
|
|
const auto width = static_cast<int>(value_count / height);
|
|
|
|
|
return QSize{width, hint.height()};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (auto adjusted = adapt_from(candidate)) {
|
|
|
|
|
return *adjusted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto adjusted = adapt_from(matrix_context_->get())) {
|
|
|
|
|
return *adjusted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto root = static_cast<int>(std::sqrt(static_cast<double>(value_count)));
|
|
|
|
|
for (int width = root; width >= 1; --width) {
|
|
|
|
|
const auto divisor = static_cast<std::size_t>(width);
|
|
|
|
|
if (divisor == 0U) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ((value_count % divisor) == 0U) {
|
|
|
|
|
const auto height = static_cast<int>(value_count / divisor);
|
|
|
|
|
return QSize{width, height};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QSize{static_cast<int>(value_count), 1};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<MutableValue<QVector<PointData>>> heatmap_data_;
|
|
|
|
|
std::shared_ptr<MutableValue<QSize>> matrix_context_;
|
|
|
|
|
std::unique_ptr<ffmsep::CPStreamCore> core_;
|
|
|
|
|
QString active_port_;
|
|
|
|
|
QString last_error_;
|
|
|
|
|
bool connected_ = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct SensorUiState {
|
|
|
|
|
std::shared_ptr<MutableValue<QString>> link_icon =
|
|
|
|
|
std::make_shared<MutableValue<QString>>(QString::fromLatin1(material::icon::kAddLink));
|
|
|
|
|
std::shared_ptr<MutableValue<QVector<PointData>>> heatmap_data =
|
|
|
|
|
std::make_shared<MutableValue<QVector<PointData>>>();
|
|
|
|
|
std::shared_ptr<MutableValue<QSize>> heatmap_matrix =
|
|
|
|
|
std::make_shared<MutableValue<QSize>>();
|
|
|
|
|
std::shared_ptr<MutableValue<QStringList>> port_items =
|
|
|
|
|
std::make_shared<MutableValue<QStringList>>();
|
|
|
|
|
QString selected_port;
|
|
|
|
|
std::uint32_t selected_baud = 115200;
|
|
|
|
|
std::unique_ptr<SensorStreamController> controller;
|
|
|
|
|
|
|
|
|
|
SensorUiState() {
|
|
|
|
|
const QSize size{3, 4};
|
|
|
|
|
heatmap_matrix->set_silent(size);
|
|
|
|
|
heatmap_data->set_silent(make_flat_points(size));
|
|
|
|
|
|
|
|
|
|
// 初始化串口列表
|
|
|
|
|
QStringList ports_list;
|
|
|
|
|
const auto ports = ffmsep::CPStreamCore::list_available_ports();
|
|
|
|
|
ports_list.reserve(static_cast<qsizetype>(ports.size()));
|
|
|
|
|
for (const auto& info : ports) {
|
|
|
|
|
ports_list.emplace_back(QString::fromStdString(info.port));
|
|
|
|
|
}
|
|
|
|
|
port_items->set_silent(ports_list);
|
|
|
|
|
if (selected_port.isEmpty() && !ports_list.isEmpty()) {
|
|
|
|
|
selected_port = ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
controller = std::make_unique<SensorStreamController>(heatmap_data, heatmap_matrix);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SensorUiState& sensor_state() {
|
|
|
|
|
static SensorUiState state;
|
|
|
|
|
@@ -418,10 +418,10 @@ static auto ComConfigComponent(ThemeManager& manager) {
|
|
|
|
|
auto& sensor = sensor_state();
|
|
|
|
|
auto link_icon_context = sensor.link_icon;
|
|
|
|
|
|
|
|
|
|
// 串口下拉:改为绑定可变数据源,初始值由 SensorUiState 构造时填充
|
|
|
|
|
if (sensor.selected_port.isEmpty() && !sensor.port_items->get().isEmpty()) {
|
|
|
|
|
sensor.selected_port = sensor.port_items->get().front();
|
|
|
|
|
}
|
|
|
|
|
// 串口下拉:改为绑定可变数据源,初始值由 SensorUiState 构造时填充
|
|
|
|
|
if (sensor.selected_port.isEmpty() && !sensor.port_items->get().isEmpty()) {
|
|
|
|
|
sensor.selected_port = sensor.port_items->get().front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QStringList baud_items{
|
|
|
|
|
QString::fromLatin1("9600"),
|
|
|
|
|
@@ -440,21 +440,21 @@ static auto ComConfigComponent(ThemeManager& manager) {
|
|
|
|
|
// slogen_context,
|
|
|
|
|
// },
|
|
|
|
|
// },
|
|
|
|
|
lnpro::Item<MatSelect> {
|
|
|
|
|
slpro::ThemeManager {manager},
|
|
|
|
|
slpro::LeadingIcon {material::icon::kArrowDropDown, material::regular::font},
|
|
|
|
|
slpro::IndexChanged {[sensor_ptr = &sensor](auto& self){
|
|
|
|
|
const auto text = self.currentText();
|
|
|
|
|
if (!text.isEmpty()) {
|
|
|
|
|
sensor_ptr->selected_port = text;
|
|
|
|
|
}
|
|
|
|
|
}},
|
|
|
|
|
slpro::LeadingText {"COM"},
|
|
|
|
|
MutableForward {
|
|
|
|
|
slpro::SelectItems {},
|
|
|
|
|
sensor.port_items,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
lnpro::Item<MatSelect> {
|
|
|
|
|
slpro::ThemeManager {manager},
|
|
|
|
|
slpro::LeadingIcon {material::icon::kArrowDropDown, material::regular::font},
|
|
|
|
|
slpro::IndexChanged {[sensor_ptr = &sensor](auto& self){
|
|
|
|
|
const auto text = self.currentText();
|
|
|
|
|
if (!text.isEmpty()) {
|
|
|
|
|
sensor_ptr->selected_port = text;
|
|
|
|
|
}
|
|
|
|
|
}},
|
|
|
|
|
slpro::LeadingText {"COM"},
|
|
|
|
|
MutableForward {
|
|
|
|
|
slpro::SelectItems {},
|
|
|
|
|
sensor.port_items,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
lnpro::Item<MatSelect> {
|
|
|
|
|
slpro::ThemeManager {manager },
|
|
|
|
|
slpro::LeadingIcon { material::icon::kArrowDropDown, material::regular::font},
|
|
|
|
|
@@ -484,10 +484,10 @@ static auto ComConfigComponent(ThemeManager& manager) {
|
|
|
|
|
if (!sensor.controller) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (sensor.controller->is_connected()) {
|
|
|
|
|
sensor.controller->stop();
|
|
|
|
|
link_icon_context->set(QString::fromLatin1(material::icon::kAddLink));
|
|
|
|
|
} else {
|
|
|
|
|
if (sensor.controller->is_connected()) {
|
|
|
|
|
sensor.controller->stop();
|
|
|
|
|
link_icon_context->set(QString::fromLatin1(material::icon::kAddLink));
|
|
|
|
|
} else {
|
|
|
|
|
const auto port = sensor.selected_port;
|
|
|
|
|
const auto baud = sensor.selected_baud == 0U ? 115200U : sensor.selected_baud;
|
|
|
|
|
if (sensor.controller->start(port, baud)) {
|
|
|
|
|
@@ -501,34 +501,34 @@ static auto ComConfigComponent(ThemeManager& manager) {
|
|
|
|
|
}
|
|
|
|
|
} }
|
|
|
|
|
},
|
|
|
|
|
lnpro::Item<IconButton> {
|
|
|
|
|
ibpro::ThemeManager { manager },
|
|
|
|
|
ibpro::FixedSize { 40, 40 },
|
|
|
|
|
ibpro::Color { IconButton::Color::TONAL },
|
|
|
|
|
ibpro::Font { material::kRoundSmallFont },
|
|
|
|
|
ibpro::FontIcon { material::icon::kRefresh },
|
|
|
|
|
ibpro::Clickable {[&sensor] {
|
|
|
|
|
// 刷新串口列表
|
|
|
|
|
QStringList ports_list;
|
|
|
|
|
const auto ports = ffmsep::CPStreamCore::list_available_ports();
|
|
|
|
|
ports_list.reserve(static_cast<qsizetype>(ports.size()));
|
|
|
|
|
for (const auto& info : ports) {
|
|
|
|
|
ports_list.emplace_back(QString::fromStdString(info.port));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保持原选择(若仍然存在)
|
|
|
|
|
if (!sensor.selected_port.isEmpty()) {
|
|
|
|
|
const bool exists = ports_list.contains(sensor.selected_port);
|
|
|
|
|
if (!exists) {
|
|
|
|
|
sensor.selected_port = ports_list.isEmpty() ? QString{} : ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
} else if (!ports_list.isEmpty()) {
|
|
|
|
|
sensor.selected_port = ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sensor.port_items->set(std::move(ports_list));
|
|
|
|
|
}},
|
|
|
|
|
},
|
|
|
|
|
lnpro::Item<IconButton> {
|
|
|
|
|
ibpro::ThemeManager { manager },
|
|
|
|
|
ibpro::FixedSize { 40, 40 },
|
|
|
|
|
ibpro::Color { IconButton::Color::TONAL },
|
|
|
|
|
ibpro::Font { material::kRoundSmallFont },
|
|
|
|
|
ibpro::FontIcon { material::icon::kRefresh },
|
|
|
|
|
ibpro::Clickable {[&sensor] {
|
|
|
|
|
// 刷新串口列表
|
|
|
|
|
QStringList ports_list;
|
|
|
|
|
const auto ports = ffmsep::CPStreamCore::list_available_ports();
|
|
|
|
|
ports_list.reserve(static_cast<qsizetype>(ports.size()));
|
|
|
|
|
for (const auto& info : ports) {
|
|
|
|
|
ports_list.emplace_back(QString::fromStdString(info.port));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保持原选择(若仍然存在)
|
|
|
|
|
if (!sensor.selected_port.isEmpty()) {
|
|
|
|
|
const bool exists = ports_list.contains(sensor.selected_port);
|
|
|
|
|
if (!exists) {
|
|
|
|
|
sensor.selected_port = ports_list.isEmpty() ? QString{} : ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
} else if (!ports_list.isEmpty()) {
|
|
|
|
|
sensor.selected_port = ports_list.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sensor.port_items->set(std::move(ports_list));
|
|
|
|
|
}},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
return new Widget {
|
|
|
|
|
|