Mode switch to signal generator (GUI stubs only)

This commit is contained in:
Jan Käberich 2020-09-11 23:07:15 +02:00
parent 6e82bc42f5
commit f4a6b24a8e
19 changed files with 1132 additions and 311 deletions

Binary file not shown.

View File

@ -34,7 +34,9 @@ HEADERS += \
Traces/tracesmithchart.h \ Traces/tracesmithchart.h \
Traces/tracewidget.h \ Traces/tracewidget.h \
averaging.h \ averaging.h \
preferences.h \
qwtplotpiecewisecurve.h \ qwtplotpiecewisecurve.h \
signalgenerator.h \
touchstone.h \ touchstone.h \
unit.h \ unit.h \
valueinput.h \ valueinput.h \
@ -77,7 +79,9 @@ SOURCES += \
Traces/tracewidget.cpp \ Traces/tracewidget.cpp \
averaging.cpp \ averaging.cpp \
main.cpp \ main.cpp \
preferences.cpp \
qwtplotpiecewisecurve.cpp \ qwtplotpiecewisecurve.cpp \
signalgenerator.cpp \
touchstone.cpp \ touchstone.cpp \
unit.cpp \ unit.cpp \
valueinput.cpp \ valueinput.cpp \
@ -106,7 +110,9 @@ FORMS += \
Traces/traceexportdialog.ui \ Traces/traceexportdialog.ui \
Traces/traceimportdialog.ui \ Traces/traceimportdialog.ui \
Traces/tracewidget.ui \ Traces/tracewidget.ui \
main.ui main.ui \
preferencesdialog.ui \
signalgenerator.ui
DISTFILES += DISTFILES +=

View File

@ -305,17 +305,26 @@ void Device::ReceivedData()
do { do {
handled_len = Protocol::DecodeBuffer(dataBuffer->getBuffer(), dataBuffer->getReceived(), &packet); handled_len = Protocol::DecodeBuffer(dataBuffer->getBuffer(), dataBuffer->getReceived(), &packet);
dataBuffer->removeBytes(handled_len); dataBuffer->removeBytes(handled_len);
if(packet.type == Protocol::PacketType::Datapoint) { switch(packet.type) {
case Protocol::PacketType::Datapoint:
emit DatapointReceived(packet.datapoint); emit DatapointReceived(packet.datapoint);
} else if(packet.type == Protocol::PacketType::Status) { break;
qDebug() << "Got status"; case Protocol::PacketType::Status:
emit ManualStatusReceived(packet.status); emit ManualStatusReceived(packet.status);
} else if(packet.type == Protocol::PacketType::DeviceInfo) { break;
case Protocol::PacketType::DeviceInfo:
lastInfo = packet.info; lastInfo = packet.info;
lastInfoValid = true; lastInfoValid = true;
emit DeviceInfoUpdated(); emit DeviceInfoUpdated();
} else if(packet.type == Protocol::PacketType::Ack) { break;
case Protocol::PacketType::Ack:
emit AckReceived(); emit AckReceived();
break;
case Protocol::PacketType::Nack:
emit NackReceived();
break;
default:
break;
} }
} while (handled_len > 0); } while (handled_len > 0);
} }

View File

@ -62,6 +62,7 @@ signals:
void DeviceInfoUpdated(); void DeviceInfoUpdated();
void ConnectionLost(); void ConnectionLost();
void AckReceived(); void AckReceived();
void NackReceived();
void LogLineReceived(QString line); void LogLineReceived(QString line);
private slots: private slots:
void ReceivedData(); void ReceivedData();

View File

@ -58,6 +58,8 @@ void FirmwareUpdateDialog::on_bStart_clicked()
return; return;
} }
state = State::ErasingFLASH; state = State::ErasingFLASH;
connect(dev, &Device::AckReceived, this, &FirmwareUpdateDialog::receivedAck);
connect(dev, &Device::NackReceived, this, &FirmwareUpdateDialog::receivedNack);
addStatus("Erasing device memory..."); addStatus("Erasing device memory...");
dev->SendCommandWithoutPayload(Protocol::PacketType::ClearFlash); dev->SendCommandWithoutPayload(Protocol::PacketType::ClearFlash);
timer.setSingleShot(true); timer.setSingleShot(true);
@ -71,6 +73,9 @@ void FirmwareUpdateDialog::addStatus(QString line)
void FirmwareUpdateDialog::abortWithError(QString error) void FirmwareUpdateDialog::abortWithError(QString error)
{ {
disconnect(dev, &Device::AckReceived, this, &FirmwareUpdateDialog::receivedAck);
disconnect(dev, &Device::NackReceived, this, &FirmwareUpdateDialog::receivedNack);
QTextCharFormat tf; QTextCharFormat tf;
tf = ui->status->currentCharFormat(); tf = ui->status->currentCharFormat();
tf.setForeground(QBrush(Qt::red)); tf.setForeground(QBrush(Qt::red));
@ -94,6 +99,9 @@ void FirmwareUpdateDialog::timerCallback()
dev = new Device(serialnumber); dev = new Device(serialnumber);
addStatus("...device reattached, update complete"); addStatus("...device reattached, update complete");
timer.stop(); timer.stop();
ui->bStart->setEnabled(true);
disconnect(dev, &Device::AckReceived, this, &FirmwareUpdateDialog::receivedAck);
disconnect(dev, &Device::NackReceived, this, &FirmwareUpdateDialog::receivedNack);
} }
} }
} }
@ -139,6 +147,11 @@ void FirmwareUpdateDialog::receivedAck()
} }
} }
void FirmwareUpdateDialog::receivedNack()
{
abortWithError("Nack received, device does not support firmware update");
}
void FirmwareUpdateDialog::sendNextFirmwareChunk() void FirmwareUpdateDialog::sendNextFirmwareChunk()
{ {
Protocol::FirmwarePacket fw; Protocol::FirmwarePacket fw;

View File

@ -29,11 +29,12 @@ private slots:
void on_bFile_clicked(); void on_bFile_clicked();
void on_bStart_clicked(); void on_bStart_clicked();
void timerCallback(); void timerCallback();
void receivedAck();
void receivedNack();
private: private:
void addStatus(QString line); void addStatus(QString line);
void abortWithError(QString error); void abortWithError(QString error);
void receivedAck();
void sendNextFirmwareChunk(); void sendNextFirmwareChunk();
Ui::FirmwareUpdateDialog *ui; Ui::FirmwareUpdateDialog *ui;
Device *&dev; Device *&dev;

View File

@ -396,7 +396,7 @@ bool TraceBodePlot::supported(Trace *t, TraceBodePlot::YAxisType type)
void TraceBodePlot::updateXAxis() void TraceBodePlot::updateXAxis()
{ {
if(XAxis.autorange) { if(XAxis.autorange && sweep_fmax-sweep_fmin > 0) {
QList<double> tickList; QList<double> tickList;
for(double tick = sweep_fmin;tick <= sweep_fmax;tick+= (sweep_fmax-sweep_fmin)/10) { for(double tick = sweep_fmin;tick <= sweep_fmax;tick+= (sweep_fmax-sweep_fmin)/10) {
tickList.append(tick); tickList.append(tick);

View File

@ -47,6 +47,8 @@ void TraceMarkerModel::removeMarker(unsigned int index, bool delete_marker)
if (index < markers.size()) { if (index < markers.size()) {
beginRemoveRows(QModelIndex(), index, index); beginRemoveRows(QModelIndex(), index, index);
if(delete_marker) { if(delete_marker) {
// disconnect from deleted signal prior to deleting the marker. Otherwise a second (possibly non-existent) will be erased from the list
disconnect(markers[index], &TraceMarker::deleted, this, qOverload<TraceMarker*>(&TraceMarkerModel::removeMarker));
delete markers[index]; delete markers[index];
} }
markers.erase(markers.begin() + index); markers.erase(markers.begin() + index);

View File

@ -63,6 +63,9 @@ void TraceSmithChart::mouseMoveEvent(QMouseEvent *event)
auto t = selectedMarker->trace(); auto t = selectedMarker->trace();
auto mouseS = pixelToPlot(event->pos()); auto mouseS = pixelToPlot(event->pos());
auto samples = t->size(); auto samples = t->size();
if(!samples) {
return;
}
double closestDistance = numeric_limits<double>::max(); double closestDistance = numeric_limits<double>::max();
unsigned int closestIndex = 0; unsigned int closestIndex = 0;
for(unsigned int i=0;i<samples;i++) { for(unsigned int i=0;i<samples;i++) {
@ -138,13 +141,16 @@ void TraceSmithChart::draw(QPainter * painter, double width_factor) {
// draw line // draw line
painter->drawLine(std::real(last), -std::imag(last), std::real(now), -std::imag(now)); painter->drawLine(std::real(last), -std::imag(last), std::real(now), -std::imag(now));
} }
auto markers = t.first->getMarkers(); if(trace->size() > 0) {
for(auto m : markers) { // only draw markers if the trace has at least one point
auto coords = m->getData(); auto markers = t.first->getMarkers();
coords *= smithCoordMax; for(auto m : markers) {
auto symbol = m->getSymbol(); auto coords = m->getData();
symbol = symbol.scaled(symbol.width()*width_factor, symbol.height()*width_factor); coords *= smithCoordMax;
painter->drawPixmap(coords.real() - symbol.width()/2, -coords.imag() - symbol.height(), symbol); auto symbol = m->getSymbol();
symbol = symbol.scaled(symbol.width()*width_factor, symbol.height()*width_factor);
painter->drawPixmap(coords.real() - symbol.width()/2, -coords.imag() - symbol.height(), symbol);
}
} }
} }
} }

View File

@ -92,7 +92,8 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="list-add"/> <iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -117,12 +118,19 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="list-remove"/> <iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="bImport"> <widget class="QPushButton" name="bImport">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip"> <property name="toolTip">
<string>Import</string> <string>Import</string>
</property> </property>
@ -137,6 +145,12 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="bExport"> <widget class="QPushButton" name="bExport">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip"> <property name="toolTip">
<string>Export</string> <string>Export</string>
</property> </property>
@ -164,7 +178,8 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="accessories-text-editor"/> <iconset theme="accessories-text-editor">
<normaloff>.</normaloff>.</iconset>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -84,6 +84,7 @@
</widget> </widget>
<addaction name="menuDocks"/> <addaction name="menuDocks"/>
<addaction name="menuToolbars"/> <addaction name="menuToolbars"/>
<addaction name="actionPreferences"/>
</widget> </widget>
<widget class="QMenu" name="menuCalibration"> <widget class="QMenu" name="menuCalibration">
<property name="title"> <property name="title">
@ -206,6 +207,16 @@
<string>Firmware Update</string> <string>Firmware Update</string>
</property> </property>
</action> </action>
<action name="actionPreferences">
<property name="text">
<string>Preferences</string>
</property>
</action>
<action name="actionDummy_4">
<property name="text">
<string>Dummy</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -0,0 +1,128 @@
#include "preferences.h"
#include "ui_preferencesdialog.h"
#include <QSettings>
#include <QPushButton>
#include <QMessageBox>
#include <map>
using namespace std;
PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
QDialog(parent),
ui(new Ui::PreferencesDialog),
p(pref)
{
ui->setupUi(this);
// Setup GUI connections and adjustments
// Startup page
connect(ui->StartupSweepLastUsed, &QPushButton::clicked, [=](){
ui->StartupSweepStart->setEnabled(false);
ui->StartupSweepStop->setEnabled(false);
ui->StartupSweepPoints->setEnabled(false);
ui->StartupSweepLevel->setEnabled(false);
ui->StartupSweepBandwidth->setEnabled(false);
});
connect(ui->StartupSweepDefault, &QPushButton::clicked, [=](){
ui->StartupSweepStart->setEnabled(true);
ui->StartupSweepStop->setEnabled(true);
ui->StartupSweepPoints->setEnabled(true);
ui->StartupSweepLevel->setEnabled(true);
ui->StartupSweepBandwidth->setEnabled(true);
});
ui->StartupSweepStart->setUnit("Hz");
ui->StartupSweepStart->setPrefixes(" kMG");
ui->StartupSweepStop->setUnit("Hz");
ui->StartupSweepStop->setPrefixes(" kMG");
ui->StartupSweepBandwidth->setUnit("Hz");
ui->StartupSweepBandwidth->setPrefixes(" k");
// Page selection
connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) {
auto name = current->text(0);
for(int i=0;i<ui->pageWidget->count();i++) {
auto w = ui->pageWidget->widget(i);
if(name == w->objectName()) {
// found the correct page, set to front
ui->pageWidget->setCurrentWidget(w);
break;
}
}
});
// Reset and OK action
connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, [=](){
if(QMessageBox::question(this, "Restore defaults?", "Do you really want to set all preferences to their default values?") == QMessageBox::StandardButton::Yes) {
p->setDefault();
setInitialGUIState();
}
});
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, [=](){
// apply GUI state to settings
p->Startup.ConnectToFirstDevice = ui->StartupAutoconnect->isChecked();
p->Startup.RememberSweepSettings = ui->StartupSweepLastUsed->isChecked();
p->Startup.DefaultSweep.start = ui->StartupSweepStart->value();
p->Startup.DefaultSweep.stop = ui->StartupSweepStop->value();
p->Startup.DefaultSweep.bandwidth = ui->StartupSweepBandwidth->value();
p->Startup.DefaultSweep.points = ui->StartupSweepPoints->value();
p->Startup.DefaultSweep.excitation = ui->StartupSweepLevel->value();
accept();
});
setInitialGUIState();
}
PreferencesDialog::~PreferencesDialog()
{
delete ui;
}
void PreferencesDialog::setInitialGUIState()
{
ui->StartupAutoconnect->setChecked(p->Startup.ConnectToFirstDevice);
if(p->Startup.RememberSweepSettings) {
ui->StartupSweepLastUsed->click();
} else {
ui->StartupSweepDefault->click();
}
ui->StartupSweepStart->setValueQuiet(p->Startup.DefaultSweep.start);
ui->StartupSweepStop->setValueQuiet(p->Startup.DefaultSweep.stop);
ui->StartupSweepBandwidth->setValueQuiet(p->Startup.DefaultSweep.bandwidth);
ui->StartupSweepPoints->setValue(p->Startup.DefaultSweep.points);
ui->StartupSweepLevel->setValue(p->Startup.DefaultSweep.excitation);
}
void Preferences::load()
{
QSettings settings;
// load settings, using default values if not present
for(auto d : descr) {
try {
d.var.setValue(settings.value(d.name, d.def));
} catch (const exception& e){
d.var.setValue(d.def);
}
}
}
void Preferences::store()
{
QSettings settings;
// store settings
for(auto d : descr) {
settings.setValue(d.name, d.var.value());
}
}
void Preferences::edit()
{
auto dialog = new PreferencesDialog(this);
dialog->exec();
}
void Preferences::setDefault()
{
for(auto d : descr) {
d.var.setValue(d.def);
}
}

View File

@ -0,0 +1,84 @@
#ifndef PREFERENCESDIALOG_H
#define PREFERENCESDIALOG_H
#include <QDialog>
#include <QVariant>
#include <exception>
class QPointerVariant {
public:
template <typename T> QPointerVariant(T *ptr)
: ptr(static_cast<void*>(ptr)),
variant(QVariant(*ptr)){};
void setValue(const QVariant &value) {
auto destType = variant.type();
if(!value.canConvert(destType)) {
throw std::runtime_error("Unable to convert QVariant to requested type");
}
variant = value;
variant.convert(destType);
QMetaType mt(destType);
mt.construct(ptr, variant.constData());
}
QVariant value() {
return QVariant(variant.type(), ptr);
}
private:
void *ptr;
QVariant variant;
};
class Preferences {
public:
void load();
void store();
void edit();
void setDefault();
struct {
bool ConnectToFirstDevice;
bool RememberSweepSettings;
struct {
double start;
double stop;
int points;
double bandwidth;
double excitation;
} DefaultSweep;
} Startup;
private:
using SettingDescription = struct {
QPointerVariant var;
QString name;
QVariant def;
};
const std::array<SettingDescription, 7> descr = {{
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
{&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0},
{&Startup.DefaultSweep.stop, "Startup.DefaultSweep.stop", 6000000000.0},
{&Startup.DefaultSweep.points, "Startup.DefaultSweep.points", 501},
{&Startup.DefaultSweep.bandwidth, "Startup.DefaultSweep.bandwidth", 1000.0},
{&Startup.DefaultSweep.excitation, "Startup.DefaultSweep.excitation", -10.00},
}};
};
namespace Ui {
class PreferencesDialog;
}
class PreferencesDialog : public QDialog
{
Q_OBJECT
public:
explicit PreferencesDialog(Preferences *pref, QWidget *parent = nullptr);
~PreferencesDialog();
private:
void setInitialGUIState();
Ui::PreferencesDialog *ui;
Preferences *p;
};
#endif // PREFERENCESDIALOG_H

View File

@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PreferencesDialog</class>
<widget class="QDialog" name="PreferencesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>646</width>
<height>543</height>
</rect>
</property>
<property name="windowTitle">
<string>Preferences</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>180</width>
<height>16777215</height>
</size>
</property>
<property name="rootIsDecorated">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>1</string>
</property>
</column>
<item>
<property name="text">
<string>Startup</string>
</property>
</item>
<item>
<property name="text">
<string>Acquisition</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="pageWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<widget class="QWidget" name="Startup">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>When starting the application...</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="StartupAutoconnect">
<property name="text">
<string>Autoconnect to the first device available</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Set sweep settings to...</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="StartupSweepLastUsed">
<property name="text">
<string>Last used</string>
</property>
<attribute name="buttonGroup">
<string notr="true">StartupSweepGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="StartupSweepDefault">
<property name="text">
<string>Default values</string>
</property>
<attribute name="buttonGroup">
<string notr="true">StartupSweepGroup</string>
</attribute>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Start:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="StartupSweepStart"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Stop:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="StartupSweepStop"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Level:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="StartupSweepLevel">
<property name="suffix">
<string>dbm</string>
</property>
<property name="minimum">
<double>-42.000000000000000</double>
</property>
<property name="maximum">
<double>-10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Points:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="StartupSweepPoints">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>4501</number>
</property>
<property name="value">
<number>501</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>IF bandwitdh:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="SIUnitEdit" name="StartupSweepBandwidth"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="Acquisition">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="checkBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="StartupSweepGroup"/>
</buttongroups>
</ui>

View File

@ -0,0 +1,60 @@
#include "signalgenerator.h"
#include "ui_signalgenerator.h"
Signalgenerator::Signalgenerator(QWidget *parent) :
QWidget(parent),
ui(new Ui::Signalgenerator)
{
ui->setupUi(this);
ui->frequency->setUnit("Hz");
ui->frequency->setPrefixes(" kMG");
connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) {
// TODO centralize min/max values
if(newval < 9000) {
newval = 9000;
} else if (newval > 6000000000) {
newval = 6000000000;
}
ui->frequency->setValueQuiet(newval);
SettingsChanged();
});
connect(ui->levelSpin, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &Signalgenerator::setLevel);
connect(ui->levelSlider, &QSlider::valueChanged, [=](int value) {
setLevel((double) value / 100.0);
});
connect(ui->EnablePort1, &QCheckBox::clicked, [=](){
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
ui->EnablePort2->setCheckState(Qt::CheckState::Unchecked);
}
SettingsChanged();
});
connect(ui->EnablePort2, &QCheckBox::clicked, [=](){
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
ui->EnablePort1->setCheckState(Qt::CheckState::Unchecked);
}
SettingsChanged();
});
}
Signalgenerator::~Signalgenerator()
{
delete ui;
}
void Signalgenerator::setLevel(double level)
{
// TODO constrain to frequency dependent levels
ui->levelSpin->blockSignals(true);
ui->levelSlider->blockSignals(true);
ui->levelSpin->setValue(level);
ui->levelSlider->setValue(level * 100.0);
ui->levelSpin->blockSignals(false);
ui->levelSlider->blockSignals(false);
SettingsChanged();
}
void Signalgenerator::SettingsChanged()
{
// TODO compile manual settings packet and send
}

View File

@ -0,0 +1,29 @@
#ifndef SIGNALGENERATOR_H
#define SIGNALGENERATOR_H
#include <QWidget>
#include "Device/device.h"
namespace Ui {
class Signalgenerator;
}
class Signalgenerator : public QWidget
{
Q_OBJECT
public:
explicit Signalgenerator(QWidget *parent = nullptr);
~Signalgenerator();
signals:
void NewManualState(Protocol::ManualStatus s);
private slots:
void setLevel(double level);
private:
void SettingsChanged();
Ui::Signalgenerator *ui;
};
#endif // SIGNALGENERATOR_H

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Signalgenerator</class>
<widget class="QWidget" name="Signalgenerator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1093</width>
<height>594</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>197</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Generator</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Frequency:</string>
</property>
</widget>
</item>
<item>
<widget class="SIUnitEdit" name="frequency"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Level Control</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QDoubleSpinBox" name="levelSpin">
<property name="suffix">
<string>dbm</string>
</property>
<property name="minimum">
<double>-50.000000000000000</double>
</property>
<property name="maximum">
<double>0.000000000000000</double>
</property>
<property name="singleStep">
<double>0.250000000000000</double>
</property>
<property name="value">
<double>-10.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="levelSlider">
<property name="minimum">
<number>-5000</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="singleStep">
<number>25</number>
</property>
<property name="pageStep">
<number>500</number>
</property>
<property name="value">
<number>-1000</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Enable</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="EnablePort1">
<property name="text">
<string>Port 1</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="EnablePort2">
<property name="text">
<string>Port 2</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>196</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SIUnitEdit</class>
<extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -39,6 +39,10 @@
#include "Calibration/calibrationtracedialog.h" #include "Calibration/calibrationtracedialog.h"
#include "ui_main.h" #include "ui_main.h"
#include "Device/firmwareupdatedialog.h" #include "Device/firmwareupdatedialog.h"
#include "preferences.h"
#include "signalgenerator.h"
#include <QDesktopWidget>
#include <QApplication>
using namespace std; using namespace std;
@ -50,9 +54,10 @@ VNA::VNA(QWidget *parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
QCoreApplication::setOrganizationName("VNA"); QCoreApplication::setOrganizationName("VNA");
QCoreApplication::setOrganizationName("Application"); QCoreApplication::setApplicationName("Application");
pref.load();
settings = defaultSweep;
averages = 1; averages = 1;
calValid = false; calValid = false;
calMeasuring = false; calMeasuring = false;
@ -70,6 +75,48 @@ VNA::VNA(QWidget *parent)
ui->statusbar->addWidget(new QLabel, 1); ui->statusbar->addWidget(new QLabel, 1);
//ui->statusbar->setStyleSheet("QStatusBar::item { border: 1px solid black; };"); //ui->statusbar->setStyleSheet("QStatusBar::item { border: 1px solid black; };");
// Create default traces
auto tS11 = new Trace("S11", Qt::yellow);
tS11->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S11);
traceModel.addTrace(tS11);
auto tS12 = new Trace("S12", Qt::blue);
tS12->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S12);
traceModel.addTrace(tS12);
auto tS21 = new Trace("S21", Qt::green);
tS21->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S21);
traceModel.addTrace(tS21);
auto tS22 = new Trace("S22", Qt::red);
tS22->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S22);
traceModel.addTrace(tS22);
auto tracesmith1 = new TraceSmithChart(traceModel);
tracesmith1->enableTrace(tS11, true);
auto tracesmith2 = new TraceSmithChart(traceModel);
tracesmith2->enableTrace(tS22, true);
auto tracebode1 = new TraceBodePlot(traceModel);
tracebode1->enableTrace(tS12, true);
auto tracebode2 = new TraceBodePlot(traceModel);
tracebode2->enableTrace(tS21, true);
auto tiles = new TileWidget(traceModel);
tiles->splitVertically();
tiles->Child1()->splitHorizontally();
tiles->Child2()->splitHorizontally();
tiles->Child1()->Child1()->setPlot(tracesmith1);
tiles->Child1()->Child2()->setPlot(tracebode1);
tiles->Child2()->Child1()->setPlot(tracebode2);
tiles->Child2()->Child2()->setPlot(tracesmith2);
// Create GUI modes
central = new QStackedWidget;
setCentralWidget(central);
modeVNA = new GUIMode(this, "Vector Network Analyzer", tiles);
auto signalGenWidget = new Signalgenerator;
modeSGen = new GUIMode(this, "Signal Generator", signalGenWidget);
modeSGen->addHiddenElement(ui->menuTools->menuAction());
modeSGen->addHiddenElement(ui->menuCalibration->menuAction());
CreateToolbars(); CreateToolbars();
// UI connections // UI connections
connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &VNA::UpdateDeviceList); connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &VNA::UpdateDeviceList);
@ -113,6 +160,9 @@ VNA::VNA(QWidget *parent)
fw_update->exec(); fw_update->exec();
} }
}); });
connect(ui->actionPreferences, &QAction::triggered, [=](){
pref.edit();
});
setWindowTitle("VNA"); setWindowTitle("VNA");
@ -194,312 +244,73 @@ VNA::VNA(QWidget *parent)
} }
statusLayout->addStretch(); statusLayout->addStretch();
auto tw = new TraceWidget(traceModel);
// Create default traces
auto tS11 = new Trace("S11", Qt::yellow);
tS11->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S11);
traceModel.addTrace(tS11);
auto tS12 = new Trace("S12", Qt::blue);
tS12->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S12);
traceModel.addTrace(tS12);
auto tS21 = new Trace("S21", Qt::green);
tS21->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S21);
traceModel.addTrace(tS21);
auto tS22 = new Trace("S22", Qt::red);
tS22->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S22);
traceModel.addTrace(tS22);
auto tracesmith1 = new TraceSmithChart(traceModel);
tracesmith1->enableTrace(tS11, true);
auto tracesmith2 = new TraceSmithChart(traceModel);
tracesmith2->enableTrace(tS22, true);
auto tracebode1 = new TraceBodePlot(traceModel);
tracebode1->enableTrace(tS12, true);
auto tracebode2 = new TraceBodePlot(traceModel);
tracebode2->enableTrace(tS21, true);
auto tiles = new TileWidget(traceModel);
tiles->splitVertically();
tiles->Child1()->splitHorizontally();
tiles->Child2()->splitHorizontally();
tiles->Child1()->Child1()->setPlot(tracesmith1);
tiles->Child1()->Child2()->setPlot(tracebode1);
tiles->Child2()->Child1()->setPlot(tracebode2);
tiles->Child2()->Child2()->setPlot(tracesmith2);
auto menuLayout = new QStackedLayout;
auto mMain = new Menu(*menuLayout);
auto mFrequency = new Menu(*menuLayout, "Frequency");
auto mCenter = new MenuValue("Center Frequency", (settings.f_start + settings.f_stop)/2, "Hz", " kMG", 6);
mFrequency->addItem(mCenter);
auto mStart = new MenuValue("Start Frequency", settings.f_start, "Hz", " kMG", 6);
mFrequency->addItem(mStart);
auto mStop = new MenuValue("Stop Frequency", settings.f_stop, "Hz", " kMG", 6);
mFrequency->addItem(mStop);
mFrequency->finalize();
mMain->addMenu(mFrequency);
auto mSpan = new Menu(*menuLayout, "Span");
auto mSpanWidth = new MenuValue("Span", settings.f_stop - settings.f_start, "Hz", " kMG", 6);
mSpan->addItem(mSpanWidth);
auto mSpanZoomIn = new MenuAction("Zoom in");
mSpan->addItem(mSpanZoomIn);
auto mSpanZoomOut = new MenuAction("Zoom out");
mSpan->addItem(mSpanZoomOut);
auto mSpanFull = new MenuAction("Full span");
mSpan->addItem(mSpanFull);
mSpan->finalize();
mMain->addMenu(mSpan);
auto mAcquisition = new Menu(*menuLayout, "Acquisition");
auto mdbm = new MenuValue("Source Level", -10, "dbm", " ");
mAcquisition->addItem(mdbm);
auto mPoints = new MenuValue("Points", settings.points, "", " ");
mAcquisition->addItem(mPoints);
auto mBandwidth = new MenuValue("IF Bandwidth", settings.if_bandwidth, "Hz", " k", 3);
mAcquisition->addItem(mBandwidth);
auto mAverages = new MenuValue("Averages", averages);
mAcquisition->addItem(mAverages);
mAcquisition->finalize();
mMain->addMenu(mAcquisition);
auto mCalibration = new Menu(*menuLayout, "Calibration");
auto mCalPort1 = new Menu(*menuLayout, "Port 1");
auto mCalPort1Open = new MenuAction("Port 1 Open");
auto mCalPort1Short = new MenuAction("Port 1 Short");
auto mCalPort1Load = new MenuAction("Port 1 Load");
mCalPort1->addItem(mCalPort1Short);
mCalPort1->addItem(mCalPort1Open);
mCalPort1->addItem(mCalPort1Load);
mCalPort1->finalize();
mCalibration->addMenu(mCalPort1);
auto mCalPort2 = new Menu(*menuLayout, "Port 2");
auto mCalPort2Open = new MenuAction("Port 2 Open");
auto mCalPort2Short = new MenuAction("Port 2 Short");
auto mCalPort2Load = new MenuAction("Port 2 Load");
mCalPort2->addItem(mCalPort2Short);
mCalPort2->addItem(mCalPort2Open);
mCalPort2->addItem(mCalPort2Load);
mCalPort2->finalize();
mCalibration->addMenu(mCalPort2);
auto mCalThrough = new MenuAction("Through");
auto mCalIsolation = new MenuAction("Isolation");
mCalibration->addItem(mCalThrough);
mCalibration->addItem(mCalIsolation);
mCalSOL1 = new MenuAction("Apply Port 1 SOL");
mCalibration->addItem(mCalSOL1);
mCalSOL1->setDisabled(true);
mCalSOL2 = new MenuAction("Apply Port 2 SOL");
mCalibration->addItem(mCalSOL2);
mCalSOL2->setDisabled(true);
mCalFullSOLT = new MenuAction("Apply full SOLT");
mCalibration->addItem(mCalFullSOLT);
mCalFullSOLT->setDisabled(true);
auto mCalSave = new MenuAction("Save to file");
mCalibration->addItem(mCalSave);
auto mCalLoad = new MenuAction("Load from file");
mCalibration->addItem(mCalLoad);
auto mEditKit = new MenuAction("Edit CalKit");
mCalibration->addItem(mEditKit);
mCalibration->finalize();
mMain->addMenu(mCalibration);
auto mSystem = new Menu(*menuLayout, "System");
auto aManual = new MenuAction("Manual Control");
auto aMatchDialog = new MenuAction("Impedance Matching");
mSystem->addItem(aManual);
mSystem->addItem(aMatchDialog);
mSystem->finalize();
mMain->addMenu(mSystem);
mMain->finalize();
// Frequency and span connections
// setting values
connect(mCenter, &MenuValue::valueChanged, this, &VNA::SetCenterFreq);
connect(mStart, &MenuValue::valueChanged, this, &VNA::SetStartFreq);
connect(mStop, &MenuValue::valueChanged, this, &VNA::SetStopFreq);
connect(mSpanWidth, &MenuValue::valueChanged, this, &VNA::SetSpan);
connect(mSpanZoomIn, &MenuAction::triggered, this, &VNA::SpanZoomIn);
connect(mSpanZoomOut, &MenuAction::triggered, this, &VNA::SpanZoomOut);
connect(mSpanFull, &MenuAction::triggered, this, &VNA::SetFullSpan);
// readback and update line edits
connect(this, &VNA::startFreqChanged, mStart, &MenuValue::setValueQuiet);
connect(this, &VNA::stopFreqChanged, mStop, &MenuValue::setValueQuiet);
connect(this, &VNA::centerFreqChanged, mCenter, &MenuValue::setValueQuiet);
connect(this, &VNA::spanChanged, mSpanWidth, &MenuValue::setValueQuiet);
// Acquisition connections
// setting values
connect(mPoints, &MenuValue::valueChanged, [=](double newval){
SetPoints(newval);
});
connect(mdbm, &MenuValue::valueChanged, this, &VNA::SetSourceLevel);
connect(mBandwidth, &MenuValue::valueChanged, this, &VNA::SetIFBandwidth);
connect(mAverages, &MenuValue::valueChanged, [=](double newval){
SetAveraging(newval);
});
// readback and update line edits
connect(this, &VNA::sourceLevelChanged, mdbm, &MenuValue::setValueQuiet);
connect(this, &VNA::pointsChanged, [=](int newval) {
mPoints->setValueQuiet(newval);
});
connect(this, &VNA::IFBandwidthChanged, mBandwidth, &MenuValue::setValueQuiet);
connect(this, &VNA::averagingChanged, [=](int newval) {
mAverages->setValueQuiet(newval);
});
connect(mCalPort1Open, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port1Open);
});
connect(mCalPort1Short, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port1Short);
});
connect(mCalPort1Load, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port1Load);
});
connect(mCalPort2Open, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port2Open);
});
connect(mCalPort2Short, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port2Short);
});
connect(mCalPort2Load, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Port2Load);
});
connect(mCalThrough, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Through);
});
connect(mCalIsolation, &MenuAction::triggered, [=](){
StartCalibrationMeasurement(Calibration::Measurement::Isolation);
});
connect(mCalSOL1, &MenuAction::triggered, [=](){
ApplyCalibration(Calibration::Type::Port1SOL);
});
connect(mCalSOL2, &MenuAction::triggered, [=](){
ApplyCalibration(Calibration::Type::Port2SOL);
});
connect(mCalFullSOLT, &MenuAction::triggered, [=](){
ApplyCalibration(Calibration::Type::FullSOLT);
});
connect(mCalSave, &MenuAction::triggered, [=](){
cal.saveToFile();
});
connect(mCalLoad, &MenuAction::triggered, [=](){
if(cal.openFromFile()) {
// Check if applying calibration is available
if(cal.calculationPossible(Calibration::Type::Port1SOL)) {
mCalSOL1->setEnabled(true);
}
if(cal.calculationPossible(Calibration::Type::Port2SOL)) {
mCalSOL2->setEnabled(true);
}
if(cal.calculationPossible(Calibration::Type::FullSOLT)) {
mCalFullSOLT->setEnabled(true);
}
}
});
connect(mEditKit, &MenuAction::triggered, [=](){
cal.getCalibrationKit().edit();
});
// Manual control trigger
connect(aManual, &MenuAction::triggered, this, &VNA::StartManualControl);
connect(aMatchDialog, &MenuAction::triggered, this, &VNA::StartImpedanceMatching);
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
auto mainWidget = new QWidget;
auto mainLayout = new QHBoxLayout;
mainWidget->setLayout(mainLayout);
auto statusWidget = new QWidget; auto statusWidget = new QWidget;
statusWidget->setLayout(statusLayout); statusWidget->setLayout(statusLayout);
// statusWidget->setFixedWidth(150); // statusWidget->setFixedWidth(150);
auto statusDock = new QDockWidget("Status"); auto statusDock = new QDockWidget("Status");
statusDock->setWidget(statusWidget); statusDock->setWidget(statusWidget);
// statusDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
addDockWidget(Qt::LeftDockWidgetArea, statusDock); addDockWidget(Qt::LeftDockWidgetArea, statusDock);
auto tracesDock = new QDockWidget("Traces"); auto tracesDock = new QDockWidget("Traces");
tracesDock->setWidget(tw); tracesDock->setWidget(new TraceWidget(traceModel));
// tracesDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
addDockWidget(Qt::LeftDockWidgetArea, tracesDock); addDockWidget(Qt::LeftDockWidgetArea, tracesDock);
// mainLayout->addWidget(statusWidget);
mainLayout->addWidget(tiles);
auto menuWidget = new QWidget;
menuWidget->setLayout(menuLayout);
// menuWidget->setFixedWidth(180);
auto menuDock = new QDockWidget("Menu");
menuDock->setWidget(menuWidget);
// menuDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
addDockWidget(Qt::RightDockWidgetArea, menuDock);
// mainLayout->addWidget(menuWidget);
auto markerWidget = new MarkerWidget(*markerModel); auto markerWidget = new MarkerWidget(*markerModel);
auto markerDock = new QDockWidget("Marker"); auto markerDock = new QDockWidget("Marker");
markerDock->setWidget(markerWidget); markerDock->setWidget(markerWidget);
// markerDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
addDockWidget(Qt::BottomDockWidgetArea, markerDock); addDockWidget(Qt::BottomDockWidgetArea, markerDock);
auto logDock = new QDockWidget("Device Log"); auto logDock = new QDockWidget("Device Log");
logDock->setWidget(&deviceLog); logDock->setWidget(&deviceLog);
addDockWidget(Qt::BottomDockWidgetArea, logDock); addDockWidget(Qt::BottomDockWidgetArea, logDock);
setCentralWidget(mainWidget); modeSGen->addHiddenElement(markerDock);
modeSGen->addHiddenElement(tracesDock);
modeSGen->addHiddenElement(statusDock);
// status and menu dock hidden by default // status and menu dock hidden by default
menuDock->close();
statusDock->close(); statusDock->close();
// fill dock/toolbar hide/show menu and set initial state if available {
QSettings settings; QSettings settings;
ui->menuDocks->clear(); restoreGeometry(settings.value("geometry").toByteArray());
for(auto d : findChildren<QDockWidget*>()) {
ui->menuDocks->addAction(d->toggleViewAction());
bool hidden = settings.value("dock_"+d->windowTitle(), d->isHidden()).toBool();
if(hidden) {
d->close();
} else {
d->show();
}
}
ui->menuToolbars->clear();
for(auto t : findChildren<QToolBar*>()) {
ui->menuToolbars->addAction(t->toggleViewAction());
bool hidden = settings.value("toolbar_"+t->windowTitle(), t->isHidden()).toBool();
if(hidden) {
t->close();
} else {
t->show();
}
} }
restoreGeometry(settings.value("geometry").toByteArray()); // Set ObjectName for toolbars and docks
restoreState(settings.value("windowState").toByteArray()); for(auto d : findChildren<QDockWidget*>()) {
d->setObjectName(d->windowTitle());
}
for(auto t : findChildren<QToolBar*>()) {
t->setObjectName(t->windowTitle());
}
// Set default mode
modeVNA->activate();
qRegisterMetaType<Protocol::Datapoint>("Datapoint"); qRegisterMetaType<Protocol::Datapoint>("Datapoint");
ConstrainAndUpdateFrequencies();
// Set initial sweep settings
if(pref.Startup.RememberSweepSettings) {
LoadSweepSettings();
} else {
settings.f_start = pref.Startup.DefaultSweep.start;
settings.f_stop = pref.Startup.DefaultSweep.stop;
ConstrainAndUpdateFrequencies();
SetSourceLevel(pref.Startup.DefaultSweep.excitation);
SetIFBandwidth(pref.Startup.DefaultSweep.bandwidth);
SetPoints(pref.Startup.DefaultSweep.points);
}
// List available devices // List available devices
if(UpdateDeviceList()) { if(UpdateDeviceList() && pref.Startup.ConnectToFirstDevice) {
// at least one device available // at least one device available
ConnectToDevice(); ConnectToDevice();
} }
@ -508,16 +319,11 @@ VNA::VNA(QWidget *parent)
void VNA::closeEvent(QCloseEvent *event) void VNA::closeEvent(QCloseEvent *event)
{ {
QSettings settings; QSettings settings;
// save dock/toolbar visibility
for(auto d : findChildren<QDockWidget*>()) {
settings.setValue("dock_"+d->windowTitle(), d->isHidden());
}
ui->menuToolbars->clear();
for(auto t : findChildren<QToolBar*>()) {
settings.setValue("toolbar_"+t->windowTitle(), t->isHidden());
}
settings.setValue("geometry", saveGeometry()); settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState()); // deactivate currently used mode (stores mode state in settings)
GUIMode::getActiveMode()->deactivate();
StoreSweepSettings();
pref.store();
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);
} }
@ -530,16 +336,6 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
if(d.pointNum == settings.points - 1) { if(d.pointNum == settings.points - 1) {
calMeasuring = false; calMeasuring = false;
emit CalibrationMeasurementComplete(calMeasurement); emit CalibrationMeasurementComplete(calMeasurement);
// Check if applying calibration is available
if(cal.calculationPossible(Calibration::Type::Port1SOL)) {
mCalSOL1->setEnabled(true);
}
if(cal.calculationPossible(Calibration::Type::Port2SOL)) {
mCalSOL2->setEnabled(true);
}
if(cal.calculationPossible(Calibration::Type::FullSOLT)) {
mCalFullSOLT->setEnabled(true);
}
} }
calDialog.setValue(d.pointNum + 1); calDialog.setValue(d.pointNum + 1);
} }
@ -715,6 +511,7 @@ void VNA::CreateToolbars()
tb_sweep->addWidget(bZoomOut); tb_sweep->addWidget(bZoomOut);
addToolBar(tb_sweep); addToolBar(tb_sweep);
modeSGen->addHiddenElement(tb_sweep);
// Acquisition toolbar // Acquisition toolbar
auto tb_acq = new QToolBar("Acquisition", this); auto tb_acq = new QToolBar("Acquisition", this);
@ -751,6 +548,7 @@ void VNA::CreateToolbars()
tb_acq->addWidget(eBandwidth); tb_acq->addWidget(eBandwidth);
addToolBar(tb_acq); addToolBar(tb_acq);
modeSGen->addHiddenElement(tb_acq);
// Reference toolbar // Reference toolbar
auto tb_reference = new QToolBar("Reference", this); auto tb_reference = new QToolBar("Reference", this);
@ -840,6 +638,7 @@ void VNA::CreateToolbars()
tb_cal->addWidget(cbType); tb_cal->addWidget(cbType);
addToolBar(tb_cal); addToolBar(tb_cal);
modeSGen->addHiddenElement(tb_cal);
} }
int VNA::UpdateDeviceList() int VNA::UpdateDeviceList()
@ -1075,3 +874,144 @@ void VNA::ConstrainAndUpdateFrequencies()
emit centerFreqChanged((settings.f_stop + settings.f_start)/2); emit centerFreqChanged((settings.f_stop + settings.f_start)/2);
SettingsChanged(); SettingsChanged();
} }
void VNA::LoadSweepSettings()
{
QSettings s;
settings.f_start = s.value("SweepStart", pref.Startup.DefaultSweep.start).toULongLong();
settings.f_stop = s.value("SweepStop", pref.Startup.DefaultSweep.stop).toULongLong();
ConstrainAndUpdateFrequencies();
SetIFBandwidth(s.value("SweepBandwidth", pref.Startup.DefaultSweep.bandwidth).toUInt());
SetPoints(s.value("SweepPoints", pref.Startup.DefaultSweep.points).toInt());
SetSourceLevel(s.value("SweepLevel", pref.Startup.DefaultSweep.excitation).toDouble());
}
void VNA::StoreSweepSettings()
{
QSettings s;
s.setValue("SweepStart", static_cast<unsigned long long>(settings.f_start));
s.setValue("SweepStop", static_cast<unsigned long long>(settings.f_stop));
s.setValue("SweepBandwidth", settings.if_bandwidth);
s.setValue("SweepPoints", settings.points);
s.setValue("SweepLevel", (double) settings.cdbm_excitation / 100.0);
}
VNA::GUIMode* VNA::GUIMode::activeMode = nullptr;
QWidget* VNA::GUIMode::cornerWidget = nullptr;
QButtonGroup* VNA::GUIMode::modeButtonGroup = nullptr;
VNA::GUIMode::GUIMode(VNA *vna, QString name, QWidget *centralWidget)
: vna(vna),
name(name),
central(centralWidget)
{
vna->central->addWidget(central);
// Create mode switch button
auto modeSwitch = new QPushButton(name);
modeSwitch->setCheckable(true);
modeSwitch->setMaximumHeight(vna->ui->menubar->height());
if(!cornerWidget) {
// this is the first created mode, initialize corner widget and set this mode as active
modeSwitch->setChecked(true);
cornerWidget = new QWidget;
cornerWidget->setLayout(new QHBoxLayout);
cornerWidget->layout()->setSpacing(0);
cornerWidget->layout()->setMargin(0);
cornerWidget->layout()->setContentsMargins(0,0,0,0);
vna->menuBar()->setCornerWidget(cornerWidget);
modeButtonGroup = new QButtonGroup;
vna->ui->menubar->setMaximumHeight(vna->ui->menubar->height());
}
cornerWidget->layout()->addWidget(modeSwitch);
modeButtonGroup->addButton(modeSwitch);
connect(modeSwitch, &QPushButton::clicked, [=](){
activate();
});
}
void VNA::GUIMode::activate()
{
if(activeMode == this) {
// already active;
return;
} else if(activeMode) {
activeMode->deactivate();
}
QSettings settings;
// hide menu actions that are not applicable to this mode
for(auto a : hiddenActions) {
a->setVisible(false);
}
vna->central->setCurrentWidget(central);
// restore dock and toolbar positions
// vna->restoreGeometry(settings.value("geometry_"+name).toByteArray());
vna->restoreState(settings.value("windowState_"+name).toByteArray());
// restore visibility of toolbars and docks
vna->ui->menuDocks->clear();
for(auto d : vna->findChildren<QDockWidget*>()) {
if(hiddenDocks.count(d)) {
// this dock is not applicable for the current state, hide and don't add menu entry
d->hide();
continue;
}
vna->ui->menuDocks->addAction(d->toggleViewAction());
bool hidden = settings.value("dock_"+name+"_"+d->windowTitle(), d->isHidden()).toBool();
if(hidden) {
d->hide();
} else {
d->show();
}
}
vna->ui->menuToolbars->clear();
for(auto t : vna->findChildren<QToolBar*>()) {
if(hiddenToolbars.count(t)) {
// this toolbar is not applicable for the current state, hide and don't add menu entry
t->hide();
continue;
}
vna->ui->menuToolbars->addAction(t->toggleViewAction());
bool hidden = settings.value("toolbar_"+name+"_"+t->windowTitle(), t->isHidden()).toBool();
if(hidden) {
t->hide();
} else {
t->show();
}
}
activeMode = this;
}
void VNA::GUIMode::deactivate()
{
QSettings settings;
// save dock/toolbar visibility
for(auto d : vna->findChildren<QDockWidget*>()) {
settings.setValue("dock_"+name+"_"+d->windowTitle(), d->isHidden());
}
for(auto t : vna->findChildren<QToolBar*>()) {
settings.setValue("toolbar_"+name+"_"+t->windowTitle(), t->isHidden());
}
// settings.setValue("geometry_"+name, vna->saveGeometry());
settings.setValue("windowState_"+name, vna->saveState());
// restore hidden items
for(auto a : hiddenActions) {
a->setVisible(true);
}
activeMode = nullptr;
}
VNA::GUIMode *VNA::GUIMode::getActiveMode()
{
return activeMode;
}
QString VNA::GUIMode::getName() const
{
return name;
}

View File

@ -5,6 +5,7 @@
#include <QMainWindow> #include <QMainWindow>
#include <QGridLayout> #include <QGridLayout>
#include <QComboBox> #include <QComboBox>
#include <QStackedWidget>
#include "Device/device.h" #include "Device/device.h"
#include "Traces/traceplot.h" #include "Traces/traceplot.h"
#include "Calibration/calibration.h" #include "Calibration/calibration.h"
@ -14,6 +15,8 @@
#include "Traces/tracemarkermodel.h" #include "Traces/tracemarkermodel.h"
#include "averaging.h" #include "averaging.h"
#include "Device/devicelog.h" #include "Device/devicelog.h"
#include "preferences.h"
#include <QButtonGroup>
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -70,11 +73,48 @@ private:
void DeviceConnectionLost(); void DeviceConnectionLost();
void CreateToolbars(); void CreateToolbars();
void ConstrainAndUpdateFrequencies(); void ConstrainAndUpdateFrequencies();
void LoadSweepSettings();
void StoreSweepSettings();
class GUIMode {
friend class VNA;
public:
GUIMode(VNA *vna, QString name, QWidget *centralWidget);;
void addHiddenElement(QAction* a) {
hiddenActions.insert(a);
}
void addHiddenElement(QToolBar* a) {
hiddenToolbars.insert(a);
}
void addHiddenElement(QDockWidget* a) {
hiddenDocks.insert(a);
}
void activate();
void deactivate();
QString getName() const;
static GUIMode *getActiveMode();
private:
static GUIMode *activeMode;
static QWidget *cornerWidget;
static QButtonGroup *modeButtonGroup;
std::set<QAction*> hiddenActions;
std::set<QToolBar*> hiddenToolbars;
std::set<QDockWidget*> hiddenDocks;
VNA *vna;
const QString name;
QWidget *central;
};
GUIMode *modeVNA, *modeSGen;
QStackedWidget *central;
struct { struct {
QComboBox *referenceType; QComboBox *referenceType;
} toolbars; } toolbars;
Preferences pref;
Device *device; Device *device;
DeviceLog deviceLog; DeviceLog deviceLog;
QString deviceSerial; QString deviceSerial;
@ -93,9 +133,6 @@ private:
bool calWaitFirst; bool calWaitFirst;
QProgressDialog calDialog; QProgressDialog calDialog;
// Calibration menu
MenuAction *mCalSOL1, *mCalSOL2, *mCalFullSOLT;
// Status Labels // Status Labels
QLabel lStart, lCenter, lStop, lSpan, lPoints, lBandwidth; QLabel lStart, lCenter, lStop, lSpan, lPoints, lBandwidth;
QLabel lCalibration; QLabel lCalibration;