176 lines
5.8 KiB
C++
176 lines
5.8 KiB
C++
/**
|
|
* @file TriggerBar.cpp
|
|
*/
|
|
|
|
#include "TriggerBar.h"
|
|
#include "Hub.h"
|
|
#include "Theme.h"
|
|
|
|
#include <QHBoxLayout>
|
|
#include <QComboBox>
|
|
#include <QDoubleSpinBox>
|
|
#include <QSlider>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QRadioButton>
|
|
#include <QButtonGroup>
|
|
#include <cmath>
|
|
|
|
namespace shq {
|
|
|
|
/* Window presets (100 us .. 10 s), mirrors the web UI. */
|
|
static const double kWinVals[] = {1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0};
|
|
static const char* kWinLabels[] = {"100 us", "1 ms", "10 ms", "100 ms", "1 s", "10 s"};
|
|
static const int kNumWins = 6;
|
|
static const char* kEdgeWire[] = {"rising", "falling", "both"};
|
|
|
|
TriggerBar::TriggerBar(Hub* hub, QWidget* parent)
|
|
: QWidget(parent), hub_(hub) {
|
|
auto* lay = new QHBoxLayout(this);
|
|
lay->setContentsMargins(6, 2, 6, 2);
|
|
lay->setSpacing(6);
|
|
|
|
lay->addWidget(new QLabel("Trig:", this));
|
|
|
|
sigCombo_ = new QComboBox(this);
|
|
sigCombo_->setMinimumWidth(150);
|
|
lay->addWidget(sigCombo_);
|
|
|
|
edgeCombo_ = new QComboBox(this);
|
|
edgeCombo_->addItems({"Rising", "Falling", "Both"});
|
|
lay->addWidget(edgeCombo_);
|
|
|
|
lay->addWidget(new QLabel("Thr", this));
|
|
thrSpin_ = new QDoubleSpinBox(this);
|
|
thrSpin_->setRange(-1e12, 1e12);
|
|
thrSpin_->setDecimals(6);
|
|
thrSpin_->setMaximumWidth(100);
|
|
lay->addWidget(thrSpin_);
|
|
|
|
lay->addWidget(new QLabel("Win", this));
|
|
winCombo_ = new QComboBox(this);
|
|
for (int i = 0; i < kNumWins; i++) { winCombo_->addItem(kWinLabels[i]); }
|
|
winCombo_->setCurrentIndex(3); /* 100 ms */
|
|
lay->addWidget(winCombo_);
|
|
|
|
lay->addWidget(new QLabel("Pre", this));
|
|
preSlider_ = new QSlider(Qt::Horizontal, this);
|
|
preSlider_->setRange(0, 100);
|
|
preSlider_->setValue(20);
|
|
preSlider_->setMaximumWidth(90);
|
|
lay->addWidget(preSlider_);
|
|
preLbl_ = new QLabel("20%", this);
|
|
preLbl_->setMinimumWidth(34);
|
|
lay->addWidget(preLbl_);
|
|
|
|
normRadio_ = new QRadioButton("Norm", this);
|
|
singleRadio_ = new QRadioButton("1x", this);
|
|
normRadio_->setChecked(true);
|
|
auto* grp = new QButtonGroup(this);
|
|
grp->addButton(normRadio_);
|
|
grp->addButton(singleRadio_);
|
|
lay->addWidget(normRadio_);
|
|
lay->addWidget(singleRadio_);
|
|
|
|
badge_ = new QLabel("[IDLE]", this);
|
|
badge_->setMinimumWidth(90);
|
|
lay->addWidget(badge_);
|
|
|
|
armBtn_ = new QPushButton("Arm", this);
|
|
disarmBtn_ = new QPushButton("Disarm", this);
|
|
stopBtn_ = new QPushButton("Stop", this);
|
|
lay->addWidget(armBtn_);
|
|
lay->addWidget(disarmBtn_);
|
|
lay->addWidget(stopBtn_);
|
|
|
|
trigTimeLbl_ = new QLabel("", this);
|
|
trigTimeLbl_->setStyleSheet("color:#a6adc8;");
|
|
lay->addWidget(trigTimeLbl_);
|
|
lay->addStretch(1);
|
|
|
|
/* ── Wiring ── */
|
|
auto cfg = [this]() { if (!updating_) { pullFromUi(); sendConfig(); } };
|
|
connect(sigCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|
this, [cfg](int){ cfg(); });
|
|
connect(edgeCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|
this, [cfg](int){ cfg(); });
|
|
connect(thrSpin_, &QDoubleSpinBox::editingFinished, this, cfg);
|
|
connect(winCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|
this, [cfg](int){ cfg(); });
|
|
connect(preSlider_, &QSlider::valueChanged, this, [this](int v) {
|
|
preLbl_->setText(QString("%1%").arg(v));
|
|
});
|
|
connect(preSlider_, &QSlider::sliderReleased, this, cfg);
|
|
connect(normRadio_, &QRadioButton::toggled, this, [cfg](bool){ cfg(); });
|
|
|
|
connect(armBtn_, &QPushButton::clicked, this, [this]() {
|
|
pullFromUi(); sendConfig(); hub_->sendArm();
|
|
});
|
|
connect(disarmBtn_, &QPushButton::clicked, this, [this]() {
|
|
hub_->sendDisarm();
|
|
});
|
|
connect(stopBtn_, &QPushButton::clicked, this, [this]() {
|
|
auto& t = hub_->trigger();
|
|
t.stopped = !t.stopped;
|
|
hub_->sendTrigStop(t.stopped);
|
|
});
|
|
|
|
refreshSignals();
|
|
onTriggerStateChanged();
|
|
}
|
|
|
|
void TriggerBar::pullFromUi() {
|
|
auto& t = hub_->trigger();
|
|
t.signalKey = sigCombo_->currentData().toString().toStdString();
|
|
t.edge = edgeCombo_->currentIndex();
|
|
t.threshold = thrSpin_->value();
|
|
t.windowSec = kWinVals[winCombo_->currentIndex()];
|
|
t.prePercent = preSlider_->value();
|
|
t.single = singleRadio_->isChecked();
|
|
}
|
|
|
|
void TriggerBar::sendConfig() {
|
|
auto& t = hub_->trigger();
|
|
if (t.signalKey.empty()) { return; }
|
|
hub_->sendSetTrigger(t.signalKey, kEdgeWire[t.edge], t.threshold,
|
|
t.windowSec, t.prePercent,
|
|
t.single ? "single" : "normal");
|
|
}
|
|
|
|
void TriggerBar::refreshSignals() {
|
|
updating_ = true;
|
|
QString prev = sigCombo_->currentData().toString();
|
|
sigCombo_->clear();
|
|
for (const auto& src : hub_->sources()) {
|
|
for (const auto& sig : src.signals) {
|
|
QString key = QString::fromStdString(src.id + ":" + sig.meta.name);
|
|
sigCombo_->addItem(key, key);
|
|
}
|
|
}
|
|
int idx = sigCombo_->findData(prev);
|
|
if (idx >= 0) { sigCombo_->setCurrentIndex(idx); }
|
|
updating_ = false;
|
|
}
|
|
|
|
void TriggerBar::onTriggerStateChanged() {
|
|
const auto& t = hub_->trigger();
|
|
QString badge; QColor c;
|
|
if (t.status == "armed") { badge = "[ARMED]"; c = col::yellow(); }
|
|
else if (t.status == "collecting") { badge = "[COLLECTING]"; c = col::blue(); }
|
|
else if (t.status == "triggered") { badge = "[TRIGGERED]"; c = col::green(); }
|
|
else { badge = "[IDLE]"; c = col::overlay0(); }
|
|
badge_->setText(badge);
|
|
badge_->setStyleSheet(QString("color:%1; font-weight:bold;").arg(c.name()));
|
|
|
|
stopBtn_->setVisible(!t.single);
|
|
stopBtn_->setText(t.stopped ? "Run" : "Stop");
|
|
|
|
if (t.hasTrigTime && (t.status == "collecting" || t.status == "triggered")) {
|
|
trigTimeLbl_->setText(QString("t=%1").arg(t.trigTime, 0, 'f', 6));
|
|
} else {
|
|
trigTimeLbl_->clear();
|
|
}
|
|
}
|
|
|
|
} /* namespace shq */
|