Refactoring: splitting mode logic into different classes

This commit is contained in:
Jan Käberich 2020-09-13 14:44:45 +02:00
parent e266d37b96
commit b7033a029e
32 changed files with 1200 additions and 1563 deletions

Binary file not shown.

View File

@ -13,11 +13,8 @@ HEADERS += \
Device/devicelog.h \ Device/devicelog.h \
Device/firmwareupdatedialog.h \ Device/firmwareupdatedialog.h \
Device/manualcontroldialog.h \ Device/manualcontroldialog.h \
Menu/menu.h \ Generator/generator.h \
Menu/menuaction.h \ Generator/signalgenwidget.h \
Menu/menubool.h \
Menu/menuitem.h \
Menu/menuvalue.h \
Tools/eseries.h \ Tools/eseries.h \
Tools/impedancematchdialog.h \ Tools/impedancematchdialog.h \
Traces/bodeplotaxisdialog.h \ Traces/bodeplotaxisdialog.h \
@ -33,14 +30,14 @@ HEADERS += \
Traces/traceplot.h \ Traces/traceplot.h \
Traces/tracesmithchart.h \ Traces/tracesmithchart.h \
Traces/tracewidget.h \ Traces/tracewidget.h \
VNA/vna.h \
appwindow.h \
averaging.h \ averaging.h \
mode.h \
preferences.h \ preferences.h \
qwtplotpiecewisecurve.h \ qwtplotpiecewisecurve.h \
signalgenerator.h \
touchstone.h \ touchstone.h \
unit.h \ unit.h
valueinput.h \
vna.h
SOURCES += \ SOURCES += \
../VNA_embedded/Application/Communication/Protocol.cpp \ ../VNA_embedded/Application/Communication/Protocol.cpp \
@ -49,6 +46,7 @@ SOURCES += \
Calibration/calkit.cpp \ Calibration/calkit.cpp \
Calibration/calkitdialog.cpp \ Calibration/calkitdialog.cpp \
Calibration/measurementmodel.cpp \ Calibration/measurementmodel.cpp \
CustomWidgets/qwtplotpiecewisecurve.cpp \
CustomWidgets/siunitedit.cpp \ CustomWidgets/siunitedit.cpp \
CustomWidgets/tilewidget.cpp \ CustomWidgets/tilewidget.cpp \
CustomWidgets/toggleswitch.cpp \ CustomWidgets/toggleswitch.cpp \
@ -57,11 +55,8 @@ SOURCES += \
Device/devicelog.cpp \ Device/devicelog.cpp \
Device/firmwareupdatedialog.cpp \ Device/firmwareupdatedialog.cpp \
Device/manualcontroldialog.cpp \ Device/manualcontroldialog.cpp \
Menu/menu.cpp \ Generator/generator.cpp \
Menu/menuaction.cpp \ Generator/signalgenwidget.cpp \
Menu/menubool.cpp \
Menu/menuitem.cpp \
Menu/menuvalue.cpp \
Tools/eseries.cpp \ Tools/eseries.cpp \
Tools/impedancematchdialog.cpp \ Tools/impedancematchdialog.cpp \
Traces/bodeplotaxisdialog.cpp \ Traces/bodeplotaxisdialog.cpp \
@ -77,15 +72,14 @@ SOURCES += \
Traces/traceplot.cpp \ Traces/traceplot.cpp \
Traces/tracesmithchart.cpp \ Traces/tracesmithchart.cpp \
Traces/tracewidget.cpp \ Traces/tracewidget.cpp \
VNA/vna.cpp \
appwindow.cpp \
averaging.cpp \ averaging.cpp \
main.cpp \ main.cpp \
mode.cpp \
preferences.cpp \ preferences.cpp \
qwtplotpiecewisecurve.cpp \
signalgenerator.cpp \
touchstone.cpp \ touchstone.cpp \
unit.cpp \ unit.cpp
valueinput.cpp \
vna.cpp
LIBS += -lusb-1.0 LIBS += -lusb-1.0
unix:INCLUDEPATH += /usr/include/qwt unix:INCLUDEPATH += /usr/include/qwt
@ -103,6 +97,7 @@ FORMS += \
Device/devicelog.ui \ Device/devicelog.ui \
Device/firmwareupdatedialog.ui \ Device/firmwareupdatedialog.ui \
Device/manualcontroldialog.ui \ Device/manualcontroldialog.ui \
Generator/signalgenwidget.ui \
Tools/impedancematchdialog.ui \ Tools/impedancematchdialog.ui \
Traces/bodeplotaxisdialog.ui \ Traces/bodeplotaxisdialog.ui \
Traces/markerwidget.ui \ Traces/markerwidget.ui \
@ -111,8 +106,7 @@ FORMS += \
Traces/traceimportdialog.ui \ Traces/traceimportdialog.ui \
Traces/tracewidget.ui \ Traces/tracewidget.ui \
main.ui \ main.ui \
preferencesdialog.ui \ preferencesdialog.ui
signalgenerator.ui
DISTFILES += DISTFILES +=

View File

@ -8,6 +8,96 @@
using namespace std; using namespace std;
USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) :
buffer_size(buffer_size),
received_size(0),
inCallback(false)
{
buffer = new unsigned char[buffer_size];
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, 64, CallbackTrampoline, this, 100);
libusb_submit_transfer(transfer);
}
USBInBuffer::~USBInBuffer()
{
if(transfer) {
qDebug() << "Start cancellation";
libusb_cancel_transfer(transfer);
// wait for cancellation to complete
mutex mtx;
unique_lock<mutex> lck(mtx);
cv.wait(lck);
qDebug() << "Cancellation complete";
}
delete buffer;
}
void USBInBuffer::removeBytes(int handled_bytes)
{
if(!inCallback) {
throw runtime_error("Removing of bytes is only allowed from within receive callback");
}
if(handled_bytes >= received_size) {
received_size = 0;
} else {
// not removing all bytes, have to move remaining data to the beginning of the buffer
memmove(buffer, &buffer[handled_bytes], received_size - handled_bytes);
received_size -= handled_bytes;
}
}
int USBInBuffer::getReceived() const
{
return received_size;
}
void USBInBuffer::Callback(libusb_transfer *transfer)
{
switch(transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
received_size += transfer->actual_length;
inCallback = true;
emit DataReceived();
inCallback = false;
break;
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_NO_DEVICE:
case LIBUSB_TRANSFER_OVERFLOW:
case LIBUSB_TRANSFER_STALL:
qCritical() << "LIBUSB_TRANSFER_ERROR";
libusb_free_transfer(transfer);
this->transfer = nullptr;
emit TransferError();
return;
break;
case LIBUSB_TRANSFER_TIMED_OUT:
// nothing to do
break;
case LIBUSB_TRANSFER_CANCELLED:
// destructor called, do not resubmit
libusb_free_transfer(transfer);
this->transfer = nullptr;
cv.notify_all();
return;
break;
}
// Resubmit the transfer
transfer->buffer = &buffer[received_size];
libusb_submit_transfer(transfer);
}
void USBInBuffer::CallbackTrampoline(libusb_transfer *transfer)
{
auto usb = (USBInBuffer*) transfer->user_data;
usb->Callback(transfer);
}
uint8_t *USBInBuffer::getBuffer() const
{
return buffer;
}
Device::Device(QString serial) Device::Device(QString serial)
{ {
qDebug() << "Starting device connection..."; qDebug() << "Starting device connection...";
@ -62,6 +152,9 @@ Device::Device(QString serial)
connect(dataBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedData, Qt::DirectConnection); connect(dataBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedData, Qt::DirectConnection);
connect(dataBuffer, &USBInBuffer::TransferError, this, &Device::ConnectionLost); connect(dataBuffer, &USBInBuffer::TransferError, this, &Device::ConnectionLost);
connect(logBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedLog, Qt::DirectConnection); connect(logBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedLog, Qt::DirectConnection);
connect(&transmissionTimer, &QTimer::timeout, this, &Device::transmissionTimeout);
transmissionTimer.setSingleShot(true);
transmissionActive = false;
} }
Device::~Device() Device::~Device()
@ -82,26 +175,17 @@ Device::~Device()
} }
} }
bool Device::SendPacket(Protocol::PacketInfo packet) bool Device::SendPacket(Protocol::PacketInfo packet, std::function<void(TransmissionResult)> cb, unsigned int timeout)
{ {
if(m_connected) { Transmission t;
unsigned char buffer[1024]; t.packet = packet;
unsigned int length = Protocol::EncodePacket(packet, buffer, sizeof(buffer)); t.timeout = timeout;
if(!length) { t.callback = cb;
qCritical() << "Failed to encode packet"; transmissionQueue.enqueue(t);
return false; if(!transmissionActive) {
} startNextTransmission();
int actual_length;
auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0);
if(ret < 0) {
qCritical() << "Error sending data: "
<< libusb_strerror((libusb_error) ret);
return false;
} }
return true; return true;
} else {
return false;
}
} }
bool Device::Configure(Protocol::SweepSettings settings) bool Device::Configure(Protocol::SweepSettings settings)
@ -303,93 +387,38 @@ QString Device::serial() const
return m_serial; return m_serial;
} }
USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) : void Device::startNextTransmission()
buffer_size(buffer_size),
received_size(0),
inCallback(false)
{ {
buffer = new unsigned char[buffer_size]; if(transmissionQueue.empty() || !m_connected) {
transfer = libusb_alloc_transfer(0); // nothing more to transmit
libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, 64, CallbackTrampoline, this, 100); transmissionActive = false;
libusb_submit_transfer(transfer);
}
USBInBuffer::~USBInBuffer()
{
if(transfer) {
qDebug() << "Start cancellation";
libusb_cancel_transfer(transfer);
// wait for cancellation to complete
mutex mtx;
unique_lock<mutex> lck(mtx);
cv.wait(lck);
qDebug() << "Cancellation complete";
}
delete buffer;
}
void USBInBuffer::removeBytes(int handled_bytes)
{
if(!inCallback) {
throw runtime_error("Removing of bytes is only allowed from within receive callback");
}
if(handled_bytes >= received_size) {
received_size = 0;
} else {
// not removing all bytes, have to move remaining data to the beginning of the buffer
memmove(buffer, &buffer[handled_bytes], received_size - handled_bytes);
received_size -= handled_bytes;
}
}
int USBInBuffer::getReceived() const
{
return received_size;
}
void USBInBuffer::Callback(libusb_transfer *transfer)
{
switch(transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
received_size += transfer->actual_length;
inCallback = true;
emit DataReceived();
inCallback = false;
break;
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_NO_DEVICE:
case LIBUSB_TRANSFER_OVERFLOW:
case LIBUSB_TRANSFER_STALL:
qCritical() << "LIBUSB_TRANSFER_ERROR";
libusb_free_transfer(transfer);
this->transfer = nullptr;
emit TransferError();
return; return;
break;
case LIBUSB_TRANSFER_TIMED_OUT:
// nothing to do
break;
case LIBUSB_TRANSFER_CANCELLED:
// destructor called, do not resubmit
libusb_free_transfer(transfer);
this->transfer = nullptr;
cv.notify_all();
return;
break;
} }
// Resubmit the transfer transmissionActive = true;
transfer->buffer = &buffer[received_size]; auto t = transmissionQueue.head();
libusb_submit_transfer(transfer); unsigned char buffer[1024];
unsigned int length = Protocol::EncodePacket(t.packet, buffer, sizeof(buffer));
if(!length) {
qCritical() << "Failed to encode packet";
transmissionFinished(TransmissionResult::InternalError);
}
int actual_length;
auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0);
if(ret < 0) {
qCritical() << "Error sending data: "
<< libusb_strerror((libusb_error) ret);
transmissionFinished(TransmissionResult::InternalError);
}
transmissionTimer.start(t.timeout);
} }
void USBInBuffer::CallbackTrampoline(libusb_transfer *transfer) void Device::transmissionFinished(TransmissionResult result)
{ {
auto usb = (USBInBuffer*) transfer->user_data; transmissionTimer.stop();
usb->Callback(transfer); // remove transmitted packet
auto t = transmissionQueue.dequeue();
if(t.callback) {
t.callback(result);
} }
startNextTransmission();
uint8_t *USBInBuffer::getBuffer() const
{
return buffer;
} }

View File

@ -1,4 +1,4 @@
#ifndef DEVICE_H #ifndef DEVICE_H
#define DEVICE_H #define DEVICE_H
#include "../VNA_embedded/Application/Communication/Protocol.hpp" #include "../VNA_embedded/Application/Communication/Protocol.hpp"
@ -8,6 +8,8 @@
#include <QObject> #include <QObject>
#include <condition_variable> #include <condition_variable>
#include <set> #include <set>
#include <QQueue>
#include <QTimer>
Q_DECLARE_METATYPE(Protocol::Datapoint); Q_DECLARE_METATYPE(Protocol::Datapoint);
Q_DECLARE_METATYPE(Protocol::ManualStatus); Q_DECLARE_METATYPE(Protocol::ManualStatus);
@ -43,10 +45,17 @@ class Device : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum class TransmissionResult {
Ack,
Nack,
Timeout,
InternalError,
};
// connect to a VNA device. If serial is specified only connecting to this device, otherwise to the first one found // connect to a VNA device. If serial is specified only connecting to this device, otherwise to the first one found
Device(QString serial = QString()); Device(QString serial = QString());
~Device(); ~Device();
bool SendPacket(Protocol::PacketInfo packet); bool SendPacket(Protocol::PacketInfo packet, std::function<void(TransmissionResult)> cb = nullptr, unsigned int timeout = 10);
bool Configure(Protocol::SweepSettings settings); bool Configure(Protocol::SweepSettings settings);
bool SetManual(Protocol::ManualControl manual); bool SetManual(Protocol::ManualControl manual);
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
@ -68,6 +77,9 @@ signals:
private slots: private slots:
void ReceivedData(); void ReceivedData();
void ReceivedLog(); void ReceivedLog();
void transmissionTimeout() {
transmissionFinished(TransmissionResult::Timeout);
}
private: private:
static constexpr int VID = 0x0483; static constexpr int VID = 0x0483;
@ -86,6 +98,17 @@ private:
USBInBuffer *dataBuffer; USBInBuffer *dataBuffer;
USBInBuffer *logBuffer; USBInBuffer *logBuffer;
using Transmission = struct {
Protocol::PacketInfo packet;
unsigned int timeout;
std::function<void(TransmissionResult)> callback;
};
QQueue<Transmission> transmissionQueue;
void startNextTransmission();
void transmissionFinished(TransmissionResult result);
QTimer transmissionTimer;
bool transmissionActive;
QString m_serial; QString m_serial;
bool m_connected; bool m_connected;

View File

@ -29,7 +29,8 @@
<string>To File</string> <string>To File</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="document-save"/> <iconset theme="document-save">
<normaloff>.</normaloff>.</iconset>
</property> </property>
</widget> </widget>
</item> </item>
@ -39,7 +40,8 @@
<string>Clear</string> <string>Clear</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="edit-clear"/> <iconset theme="edit-clear">
<normaloff>.</normaloff>.</iconset>
</property> </property>
</widget> </widget>
</item> </item>
@ -48,6 +50,9 @@
<property name="text"> <property name="text">
<string>Autoscroll</string> <string>Autoscroll</string>
</property> </property>
<property name="checked">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -0,0 +1,25 @@
#include "generator.h"
Generator::Generator(AppWindow *window)
: Mode(window, "Signal Generator")
{
central = new SignalgeneratorWidget();
finalize(central);
connect(central, &SignalgeneratorWidget::SettingsChanged, this, &Generator::updateDevice);
}
void Generator::initializeDevice()
{
updateDevice();
}
void Generator::updateDevice()
{
if(!window->getDevice()) {
// can't updat if not connected
return;
}
auto status = central->getDeviceStatus();
// TODO comment in once status is filled with valid values
// window->getDevice()->SetManual(status);
}

View File

@ -0,0 +1,18 @@
#ifndef GENERATOR_H
#define GENERATOR_H
#include "mode.h"
#include "signalgenwidget.h"
class Generator : public Mode
{
public:
Generator(AppWindow *window);
void initializeDevice() override;
private slots:
void updateDevice();
private:
SignalgeneratorWidget *central;
};
#endif // GENERATOR_H

View File

@ -1,9 +1,9 @@
#include "signalgenerator.h" #include "signalgenwidget.h"
#include "ui_signalgenerator.h" #include "ui_signalgenerator.h"
Signalgenerator::Signalgenerator(QWidget *parent) : SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::Signalgenerator) ui(new Ui::SignalgeneratorWidget)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->frequency->setUnit("Hz"); ui->frequency->setUnit("Hz");
@ -17,9 +17,9 @@ Signalgenerator::Signalgenerator(QWidget *parent) :
newval = 6000000000; newval = 6000000000;
} }
ui->frequency->setValueQuiet(newval); ui->frequency->setValueQuiet(newval);
SettingsChanged(); emit SettingsChanged();
}); });
connect(ui->levelSpin, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &Signalgenerator::setLevel); connect(ui->levelSpin, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &SignalgeneratorWidget::setLevel);
connect(ui->levelSlider, &QSlider::valueChanged, [=](int value) { connect(ui->levelSlider, &QSlider::valueChanged, [=](int value) {
setLevel((double) value / 100.0); setLevel((double) value / 100.0);
}); });
@ -27,22 +27,29 @@ Signalgenerator::Signalgenerator(QWidget *parent) :
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) { if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
ui->EnablePort2->setCheckState(Qt::CheckState::Unchecked); ui->EnablePort2->setCheckState(Qt::CheckState::Unchecked);
} }
SettingsChanged(); emit SettingsChanged();
}); });
connect(ui->EnablePort2, &QCheckBox::clicked, [=](){ connect(ui->EnablePort2, &QCheckBox::clicked, [=](){
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) { if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
ui->EnablePort1->setCheckState(Qt::CheckState::Unchecked); ui->EnablePort1->setCheckState(Qt::CheckState::Unchecked);
} }
SettingsChanged(); emit SettingsChanged();
}); });
} }
Signalgenerator::~Signalgenerator() SignalgeneratorWidget::~SignalgeneratorWidget()
{ {
delete ui; delete ui;
} }
void Signalgenerator::setLevel(double level) Protocol::ManualControl SignalgeneratorWidget::getDeviceStatus()
{
// TODO
Protocol::ManualControl s = {};
return s;
}
void SignalgeneratorWidget::setLevel(double level)
{ {
// TODO constrain to frequency dependent levels // TODO constrain to frequency dependent levels
ui->levelSpin->blockSignals(true); ui->levelSpin->blockSignals(true);
@ -54,7 +61,3 @@ void Signalgenerator::setLevel(double level)
SettingsChanged(); SettingsChanged();
} }
void Signalgenerator::SettingsChanged()
{
// TODO compile manual settings packet and send
}

View File

@ -5,25 +5,26 @@
#include "Device/device.h" #include "Device/device.h"
namespace Ui { namespace Ui {
class Signalgenerator; class SignalgeneratorWidget;
} }
class Signalgenerator : public QWidget class SignalgeneratorWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Signalgenerator(QWidget *parent = nullptr); explicit SignalgeneratorWidget(QWidget *parent = nullptr);
~Signalgenerator(); ~SignalgeneratorWidget();
Protocol::ManualControl getDeviceStatus();
signals: signals:
void NewManualState(Protocol::ManualStatus s); void SettingsChanged();
private slots: private slots:
void setLevel(double level); void setLevel(double level);
private: private:
void SettingsChanged(); Ui::SignalgeneratorWidget *ui;
Ui::Signalgenerator *ui;
}; };
#endif // SIGNALGENERATOR_H #endif // SIGNALGENERATOR_H

View File

@ -1,84 +0,0 @@
#include "menu.h"
#include <QKeyEvent>
#include "menuaction.h"
#include <iostream>
using namespace std;
Menu::Menu(QStackedLayout &layout, QString name)
: name(name),
m_containingLayout(layout)
{
m_layout = new QVBoxLayout;
setLayout(m_layout);
m_widgetCount = 0;
setFixedSize(180, 800);
parent = nullptr;
layout.addWidget(this);
if(name.length() > 0) {
auto back = new MenuAction(name, MenuAction::ArrowType::Left);
back->setStyleSheet("background-color:lightblue;");
connect(back, &MenuAction::triggered, this, &Menu::leave);
addItem(back);
}
}
void Menu::addItem(MenuItem *i)
{
if(m_widgetCount >= maxWidgets) {
throw runtime_error("Menu already at maximum capacity");
}
m_layout->addWidget(i, 1);
items.push_back(i);
m_widgetCount++;
}
void Menu::addMenu(Menu *m)
{
auto menuLabel = new MenuAction(m->name, MenuAction::ArrowType::Right);
submenus.push_back(SubmenuEntry(menuLabel, m, m_widgetCount));
connect(menuLabel, &MenuAction::triggered, [=]() {
m->m_containingLayout.setCurrentWidget(m);
});
addItem(menuLabel);
m->parent = this;
}
void Menu::finalize()
{
m_layout->addStretch(maxWidgets - m_widgetCount);
}
void Menu::keyPressEvent(QKeyEvent *event)
{
// check if softkey pressed
int index = -1;
switch(event->key()) {
case Qt::Key_F1: index = 0; break;
case Qt::Key_F2: index = 1; break;
case Qt::Key_F3: index = 2; break;
case Qt::Key_F4: index = 3; break;
case Qt::Key_F5: index = 4; break;
case Qt::Key_F6: index = 5; break;
case Qt::Key_F7: index = 6; break;
case Qt::Key_F8: index = 7; break;
}
if(index >= 0) {
auto w = m_layout->itemAt(index);
w->widget()->setFocus();
items[index]->userSelected();
event->accept();
} else if(event->key() == Qt::Key_Escape) {
leave();
event->accept();
}
}
void Menu::leave()
{
if(parent) {
// got a parent menu
parent->m_containingLayout.setCurrentWidget(parent);
}
}

View File

@ -1,41 +0,0 @@
#ifndef MENU_H
#define MENU_H
#include <QWidget>
#include <QStackedLayout>
#include "menuitem.h"
#include "menuaction.h"
class Menu : public QWidget
{
Q_OBJECT
public:
Menu(QStackedLayout &layout, QString name = QString());
void addItem(MenuItem *i);
void addMenu(Menu *m);
void finalize();
signals:
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
void leave();
class SubmenuEntry {
public:
SubmenuEntry(MenuAction *label, Menu *menu, int index) :
label(label), menu(menu), index(index){};
MenuAction *label;
Menu *menu;
int index;
};
static constexpr int maxWidgets = 12;
QVBoxLayout *m_layout;
Menu *parent;
const QString name;
QStackedLayout &m_containingLayout;
std::vector<SubmenuEntry> submenus;
std::vector<MenuItem*> items;
int m_widgetCount;
};
#endif // MENU_H

View File

@ -1,65 +0,0 @@
#include "menuaction.h"
#include <QLabel>
#include <QStyle>
#include <QSizePolicy>
MenuAction::MenuAction(const QString &l, MenuAction::ArrowType arrow)
{
subline = nullptr;
auto label = new QLabel(l, this);
label->setAlignment(Qt::AlignCenter);
auto labelLayout = new QHBoxLayout();
if(arrow == ArrowType::Left) {
auto lIcon = new QLabel(this);
lIcon->setPixmap(style()->standardIcon(QStyle::SP_ArrowLeft).pixmap(16));
lIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
labelLayout->addWidget(lIcon);
}
labelLayout->addWidget(label);
if(arrow == ArrowType::Right) {
auto lIcon = new QLabel(this);
lIcon->setPixmap(style()->standardIcon(QStyle::SP_ArrowRight).pixmap(16));
lIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
labelLayout->addWidget(lIcon);
}
layout.addLayout(labelLayout);
setLayout(&layout);
}
void MenuAction::AddSubline(const QString &l)
{
if(!subline) {
subline = new QLabel(this);
subline->setAlignment(Qt::AlignCenter);
layout.addWidget(subline);
}
QFont f( "Arial", 8);
subline->setFont( f);
subline->setText(l);
}
void MenuAction::RemoveSubline()
{
if(subline) {
layout.removeWidget(subline);
delete subline;
subline = nullptr;
}
}
void MenuAction::userSelected()
{
emit triggered();
}
void MenuAction::mouseReleaseEvent(QMouseEvent *me)
{
setFrameStyle(QFrame::Raised | QFrame::Panel);
MenuItem::mouseReleaseEvent(me);
}
void MenuAction::mousePressEvent(QMouseEvent *)
{
setFrameStyle(QFrame::Sunken | QFrame::Panel);
}

View File

@ -1,33 +0,0 @@
#ifndef MENULABEL_H
#define MENULABEL_H
#include "menuitem.h"
#include <QVBoxLayout>
#include <QLabel>
class MenuAction : public MenuItem
{
Q_OBJECT
public:
enum class ArrowType {
None,
Left,
Right,
};
MenuAction(const QString &l, ArrowType arrow = ArrowType::None);
void AddSubline(const QString &l);
void RemoveSubline();
signals:
void triggered();
public slots:
void userSelected() override;
private:
QVBoxLayout layout;
QLabel *subline;
protected:
void mouseReleaseEvent(QMouseEvent *me) override;
void mousePressEvent(QMouseEvent *me) override;
};
#endif // MENULABEL_H

View File

@ -1,36 +0,0 @@
#include "menubool.h"
#include <QLabel>
MenuBool::MenuBool(QString name, bool defaultValue)
{
auto label = new QLabel(name, this);
label->setAlignment(Qt::AlignCenter);
layout.addWidget(label);
sw = new ToggleSwitch(this, defaultValue);
layout.addWidget(sw);
setLayout(&layout);
connect(sw, &ToggleSwitch::toggled, this, &MenuBool::valueChanged);
sw->setFocusPolicy(Qt::NoFocus);
}
void MenuBool::setValue(bool value)
{
sw->setState(value);
}
void MenuBool::userSelected()
{
sw->toggle();
}
void MenuBool::mouseReleaseEvent(QMouseEvent *me)
{
setFrameStyle(QFrame::Raised | QFrame::Panel);
MenuItem::mouseReleaseEvent(me);
}
void MenuBool::mousePressEvent(QMouseEvent *)
{
setFrameStyle(QFrame::Sunken | QFrame::Panel);
}

View File

@ -1,28 +0,0 @@
#ifndef MENUBOOL_H
#define MENUBOOL_H
#include <QObject>
#include "menuitem.h"
#include <QVBoxLayout>
#include "CustomWidgets/toggleswitch.h"
class MenuBool : public MenuItem
{
Q_OBJECT
public:
MenuBool(QString name, bool defaultValue = false);
signals:
void valueChanged(bool value);
public slots:
void setValue(bool value);
void userSelected() override;
protected:
void mouseReleaseEvent(QMouseEvent *me) override;
void mousePressEvent(QMouseEvent *me) override;
private:
QVBoxLayout layout;
ToggleSwitch *sw;
};
#endif // MENUBOOL_H

View File

@ -1,17 +0,0 @@
#include "menuitem.h"
#include <QMouseEvent>
MenuItem::MenuItem() : QFrame()
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//setStyleSheet("*:focus {background: lightblue}");
setFocusPolicy(Qt::StrongFocus);
setFrameStyle(QFrame::Raised | QFrame::Panel);
}
void MenuItem::mouseReleaseEvent(QMouseEvent *me)
{
userSelected();
me->accept();
}

View File

@ -1,20 +0,0 @@
#ifndef MENUITEM_H
#define MENUITEM_H
#include <QFrame>
class MenuItem : public QFrame
{
Q_OBJECT
public:
MenuItem();
public slots:
virtual void userSelected(){};
protected:
void mouseReleaseEvent(QMouseEvent *me) override;
};
#endif // MENUITEM_H

View File

@ -1,46 +0,0 @@
#include "menuvalue.h"
#include <QVBoxLayout>
#include <math.h>
#include <sstream>
#include <iomanip>
#include "valueinput.h"
#include <QMouseEvent>
#include "unit.h"
#include <QDoubleValidator>
using namespace std;
MenuValue::MenuValue(QString name, double defaultValue, QString unit, QString prefixes, int precision)
: name(name)
{
if(prefixes.indexOf(' ') < 0) {
throw runtime_error("Prefix string must contain space");
}
auto layout = new QVBoxLayout;
auto label = new QLabel(name, this);
label->setAlignment(Qt::AlignCenter);
layout->addWidget(label);
lvalue = new SIUnitEdit(unit, prefixes, precision);
// pass on signal
connect(lvalue, &SIUnitEdit::valueChanged, this, &MenuValue::valueChanged);
layout->addWidget(lvalue);
setValue(defaultValue);
setLayout(layout);
}
void MenuValue::setValue(double value)
{
lvalue->setValue(value);
}
void MenuValue::setValueQuiet(double value)
{
lvalue->setValueQuiet(value);
}
void MenuValue::userSelected()
{
lvalue->setFocus();
//startInputDialog();
}

View File

@ -1,26 +0,0 @@
#ifndef MENUVALUE_H
#define MENUVALUE_H
#include "menuitem.h"
#include <QLabel>
#include <CustomWidgets/siunitedit.h>
class MenuValue : public MenuItem
{
Q_OBJECT
public:
MenuValue(QString name, double defaultValue = 0.0, QString unit = QString(), QString prefixes = " ", int precision = 0);
signals:
void valueChanged(double value);
public slots:
void setValue(double value);
// same as setValue, except that no valueChanged signal is emitted
void setValueQuiet(double value);
void userSelected() override;
private:
SIUnitEdit *lvalue;
const QString name;
};
#endif // MENUVALUE_H

View File

@ -0,0 +1,89 @@
#ifndef VNA_H
#define VNA_H
#include <QObject>
#include <QWidget>
#include "appwindow.h"
#include "mode.h"
#include "CustomWidgets/tilewidget.h"
class VNA : public Mode
{
Q_OBJECT
public:
VNA(AppWindow *window);
void deactivate() override;
void initializeDevice() override;
private slots:
void NewDatapoint(Protocol::Datapoint d);
void StartImpedanceMatching();
// Sweep control
void SetStartFreq(double freq);
void SetStopFreq(double freq);
void SetCenterFreq(double freq);
void SetSpan(double span);
void SetFullSpan();
void SpanZoomIn();
void SpanZoomOut();
// Acquisition control
void SetSourceLevel(double level);
void SetPoints(unsigned int points);
void SetIFBandwidth(double bandwidth);
void SetAveraging(unsigned int averages);
// Calibration
void DisableCalibration(bool force = false);
void ApplyCalibration(Calibration::Type type);
void StartCalibrationMeasurement(Calibration::Measurement m);
signals:
void CalibrationMeasurementComplete(Calibration::Measurement m);
private:
void UpdateStatusPanel();
void SettingsChanged();
void ConstrainAndUpdateFrequencies();
void LoadSweepSettings();
void StoreSweepSettings();
Preferences pref;
QActionGroup *deviceActionGroup;
Protocol::SweepSettings settings;
unsigned int averages;
TraceModel traceModel;
TraceMarkerModel *markerModel;
Averaging average;
// Calibration
Calibration cal;
bool calValid;
Calibration::Measurement calMeasurement;
bool calMeasuring;
bool calWaitFirst;
QProgressDialog calDialog;
// Status Labels
QLabel *lStart, *lCenter, *lStop, *lSpan, *lPoints, *lBandwidth;
QLabel *lCalibration;
QLabel *lAverages;
TileWidget *central;
signals:
void dataChanged();
void startFreqChanged(double freq);
void stopFreqChanged(double freq);
void centerFreqChanged(double freq);
void spanChanged(double span);
void sourceLevelChanged(double level);
void pointsChanged(unsigned int points);
void IFBandwidthChanged(double bandwidth);
void averagingChanged(unsigned int averages);
void CalibrationDisabled();
void CalibrationApplied(Calibration::Type type);
};
#endif // VNA_H

View File

@ -0,0 +1,316 @@
#include "appwindow.h"
#include <QGridLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <math.h>
#include <QToolBar>
#include <QMenu>
#include <QToolButton>
#include <QActionGroup>
#include <QSpinBox>
#include <QCheckBox>
#include <QComboBox>
#include <QSettings>
#include <algorithm>
#include <QMessageBox>
#include <QFileDialog>
#include <QFile>
#include <iostream>
#include <fstream>
#include <QDateTime>
#include "unit.h"
#include "CustomWidgets/toggleswitch.h"
#include "Device/manualcontroldialog.h"
#include "Traces/tracemodel.h"
#include "Traces/tracewidget.h"
#include "Traces/tracesmithchart.h"
#include "Traces/tracebodeplot.h"
#include "Traces/traceimportdialog.h"
#include "CustomWidgets/tilewidget.h"
#include "CustomWidgets/siunitedit.h"
#include <QDockWidget>
#include "Traces/markerwidget.h"
#include "Tools/impedancematchdialog.h"
#include "Calibration/calibrationtracedialog.h"
#include "ui_main.h"
#include "Device/firmwareupdatedialog.h"
#include "preferences.h"
#include "Generator/signalgenwidget.h"
#include <QDesktopWidget>
#include <QApplication>
#include <QActionGroup>
#include <mode.h>
#include "VNA/vna.h"
#include "Generator/generator.h"
using namespace std;
AppWindow::AppWindow(QWidget *parent)
: QMainWindow(parent)
, deviceActionGroup(new QActionGroup(this))
, ui(new Ui::MainWindow)
{
QCoreApplication::setOrganizationName("VNA");
QCoreApplication::setApplicationName("Application");
pref.load();
device = nullptr;
ui->setupUi(this);
// ui->statusbar->insertPermanentWidget(0, &lDeviceStatus);
// ui->statusbar->insertPermanentWidget(1, new QPushButton("Test"));
ui->statusbar->addWidget(&lConnectionStatus);
auto div1 = new QFrame;
div1->setFrameShape(QFrame::VLine);
ui->statusbar->addWidget(div1);
ui->statusbar->addWidget(&lDeviceInfo);
ui->statusbar->addWidget(new QLabel, 1);
//ui->statusbar->setStyleSheet("QStatusBar::item { border: 1px solid black; };");
CreateToolbars();
auto logDock = new QDockWidget("Device Log");
logDock->setWidget(&deviceLog);
addDockWidget(Qt::BottomDockWidgetArea, logDock);
// fill toolbar/dock menu
ui->menuDocks->clear();
for(auto d : findChildren<QDockWidget*>()) {
ui->menuDocks->addAction(d->toggleViewAction());
}
ui->menuToolbars->clear();
for(auto t : findChildren<QToolBar*>()) {
ui->menuToolbars->addAction(t->toggleViewAction());
}
// Create GUI modes
central = new QStackedWidget;
setCentralWidget(central);
auto vna = new VNA(this);
new Generator(this);
// auto signalGenWidget = new Signalgenerator;
// modeSGen = new GUIMode(this, "Signal Generator", signalGenWidget);
// UI connections
connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList);
connect(ui->actionDisconnect, &QAction::triggered, this, &AppWindow::DisconnectDevice);
connect(ui->actionQuit, &QAction::triggered, this, &AppWindow::close);
connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl);
connect(ui->actionFirmware_Update, &QAction::triggered, [=](){
if(device) {
auto fw_update = new FirmwareUpdateDialog(device);
fw_update->exec();
}
});
connect(ui->actionPreferences, &QAction::triggered, [=](){
pref.edit();
});
setWindowTitle("VNA");
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
{
QSettings settings;
restoreGeometry(settings.value("geometry").toByteArray());
}
// Set ObjectName for toolbars and docks
for(auto d : findChildren<QDockWidget*>()) {
d->setObjectName(d->windowTitle());
}
for(auto t : findChildren<QToolBar*>()) {
t->setObjectName(t->windowTitle());
}
// Set default mode
vna->activate();
qRegisterMetaType<Protocol::Datapoint>("Datapoint");
// List available devices
if(UpdateDeviceList() && pref.Startup.ConnectToFirstDevice) {
// at least one device available
ConnectToDevice();
}
}
void AppWindow::closeEvent(QCloseEvent *event)
{
QSettings settings;
settings.setValue("geometry", saveGeometry());
// deactivate currently used mode (stores mode state in settings)
if(Mode::getActiveMode()) {
Mode::getActiveMode()->deactivate();
}
pref.store();
QMainWindow::closeEvent(event);
}
void AppWindow::ConnectToDevice(QString serial)
{
if(device) {
DisconnectDevice();
}
try {
qDebug() << "Attempting to connect to device...";
device = new Device(serial);
lConnectionStatus.setText("Connected to " + device->serial());
qInfo() << "Connected to " << device->serial();
lDeviceInfo.setText(device->getLastDeviceInfoString());
connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine);
connect(device, &Device::ConnectionLost, this, &AppWindow::DeviceConnectionLost);
connect(device, &Device::DeviceInfoUpdated, [this]() {
lDeviceInfo.setText(device->getLastDeviceInfoString());
});
ui->actionDisconnect->setEnabled(true);
ui->actionManual_Control->setEnabled(true);
ui->menuDefault_Calibration->setEnabled(true);
ui->actionFirmware_Update->setEnabled(true);
Mode::getActiveMode()->initializeDevice();
UpdateReference();
} catch (const runtime_error e) {
DisconnectDevice();
UpdateDeviceList();
}
}
void AppWindow::DisconnectDevice()
{
if(device) {
delete device;
device = nullptr;
}
ui->actionDisconnect->setEnabled(false);
ui->actionManual_Control->setEnabled(false);
ui->menuDefault_Calibration->setEnabled(false);
ui->actionFirmware_Update->setEnabled(false);
if(deviceActionGroup->checkedAction()) {
deviceActionGroup->checkedAction()->setChecked(false);
}
lConnectionStatus.setText("No device connected");
lDeviceInfo.setText("No device information available yet");
}
void AppWindow::DeviceConnectionLost()
{
DisconnectDevice();
QMessageBox::warning(this, "Disconnected", "The USB connection to the device has been lost");
UpdateDeviceList();
}
void AppWindow::CreateToolbars()
{
// Reference toolbar
auto tb_reference = new QToolBar("Reference", this);
tb_reference->addWidget(new QLabel("Ref:"));
toolbars.reference.type = new QComboBox();
toolbars.reference.type->addItem("Int");
toolbars.reference.type->addItem("Ext");
toolbars.reference.automatic = new QCheckBox("Auto");
connect(toolbars.reference.automatic, &QCheckBox::clicked, [this](bool checked) {
toolbars.reference.type->setEnabled(!checked);
UpdateReference();
});
// toolbars.reference.automatic->setChecked(true);
tb_reference->addWidget(toolbars.reference.type);
tb_reference->addWidget(toolbars.reference.automatic);
tb_reference->addSeparator();
tb_reference->addWidget(new QLabel("Ref out:"));
toolbars.reference.outputEnabled = new QCheckBox();
toolbars.reference.outFreq = new QComboBox();
toolbars.reference.outFreq->addItem("10 MHz");
toolbars.reference.outFreq->addItem("100 MHz");
tb_reference->addWidget(toolbars.reference.outputEnabled);
tb_reference->addWidget(toolbars.reference.outFreq);
connect(toolbars.reference.type, qOverload<int>(&QComboBox::currentIndexChanged), this, &AppWindow::UpdateReference);
connect(toolbars.reference.outFreq, qOverload<int>(&QComboBox::currentIndexChanged), this, &AppWindow::UpdateReference);
connect(toolbars.reference.outputEnabled, &QCheckBox::clicked, this, &AppWindow::UpdateReference);
addToolBar(tb_reference);
}
int AppWindow::UpdateDeviceList()
{
ui->menuConnect_to->clear();
auto devices = Device::GetDevices();
if(devices.size()) {
for(auto d : devices) {
auto connectAction = ui->menuConnect_to->addAction(d);
deviceActionGroup->addAction(connectAction);
connectAction->setCheckable(true);
if(device && d == device->serial()) {
connectAction->setChecked(true);
}
connect(connectAction, &QAction::triggered, [this, connectAction, d]() {
ConnectToDevice(d);
if(device) {
// connectAction might have been unchecked if it was a reconnect to the already connected device
connectAction->setChecked(true);
}
});
}
ui->menuConnect_to->setEnabled(true);
} else {
// no devices available, disable connection option
ui->menuConnect_to->setEnabled(false);
}
return devices.size();
}
void AppWindow::StartManualControl()
{
auto control = new ManualControlDialog(*device, this);
connect(control, &QDialog::finished, [=](){
Mode::getActiveMode()->initializeDevice();
});
control->show();
}
void AppWindow::UpdateReference()
{
if(!device) {
// can't update without a device connected
return;
}
Protocol::ReferenceSettings s = {};
if(toolbars.reference.automatic->isChecked()) {
s.AutomaticSwitch = 1;
}
if(toolbars.reference.type->currentText()=="Ext") {
s.UseExternalRef = 1;
}
if(toolbars.reference.outputEnabled->isChecked()) {
switch(toolbars.reference.outFreq->currentIndex()) {
case 0:
s.ExtRefOuputFreq = 10000000;
break;
case 1:
s.ExtRefOuputFreq = 100000000;
break;
}
}
Protocol::PacketInfo p;
p.type = Protocol::PacketType::Reference;
p.reference = s;
device->SendPacket(p);
}
Device *AppWindow::getDevice() const
{
return device;
}
QStackedWidget *AppWindow::getCentral() const
{
return central;
}
Ui::MainWindow *AppWindow::getUi() const
{
return ui;
}

View File

@ -0,0 +1,75 @@
#ifndef APPWINDOW_H
#define APPWINDOW_H
#include <QWidget>
#include <QMainWindow>
#include <QGridLayout>
#include <QComboBox>
#include <QStackedWidget>
#include "Device/device.h"
#include "Traces/traceplot.h"
#include "Calibration/calibration.h"
#include <QProgressDialog>
#include "Traces/tracemodel.h"
#include "Traces/tracemarkermodel.h"
#include "averaging.h"
#include "Device/devicelog.h"
#include "preferences.h"
#include <QButtonGroup>
#include <QCheckBox>
#include <QLabel>
namespace Ui {
class MainWindow;
}
class AppWindow : public QMainWindow
{
Q_OBJECT
public:
AppWindow(QWidget *parent = nullptr);
Ui::MainWindow *getUi() const;
QStackedWidget *getCentral() const;
Device *getDevice() const;
protected:
void closeEvent(QCloseEvent *event) override;
private slots:
void ConnectToDevice(QString serial = QString());
void DisconnectDevice();
int UpdateDeviceList();
void StartManualControl();
void UpdateReference();
private:
void DeviceConnectionLost();
void CreateToolbars();
QStackedWidget *central;
struct {
struct {
QComboBox *type;
QCheckBox *automatic;
QCheckBox *outputEnabled;
QComboBox *outFreq;
} reference;
} toolbars;
Preferences pref;
Device *device;
DeviceLog deviceLog;
QString deviceSerial;
QActionGroup *deviceActionGroup;
// Status bar widgets
QLabel lConnectionStatus;
QLabel lDeviceInfo;
Ui::MainWindow *ui;
};
#endif // VNA_H

View File

@ -2,12 +2,7 @@
#include <unistd.h> #include <unistd.h>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include "vna.h" #include "appwindow.h"
#include "valueinput.h"
#include "Menu/menu.h"
#include "Menu/menuaction.h"
#include "Menu/menuvalue.h"
#include "Calibration/calkit.h" #include "Calibration/calkit.h"
#include "touchstone.h" #include "touchstone.h"
@ -15,7 +10,7 @@
#include <complex> #include <complex>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QApplication a(argc, argv); QApplication a(argc, argv);
VNA vna; AppWindow vna;
vna.resize(1280, 800); vna.resize(1280, 800);
vna.show(); vna.show();
a.exec(); a.exec();

View File

@ -60,12 +60,6 @@
<addaction name="menuDefault_Calibration"/> <addaction name="menuDefault_Calibration"/>
<addaction name="actionFirmware_Update"/> <addaction name="actionFirmware_Update"/>
</widget> </widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionImpedance_Matching"/>
</widget>
<widget class="QMenu" name="menuWindow"> <widget class="QMenu" name="menuWindow">
<property name="title"> <property name="title">
<string>Window</string> <string>Window</string>
@ -86,20 +80,8 @@
<addaction name="menuToolbars"/> <addaction name="menuToolbars"/>
<addaction name="actionPreferences"/> <addaction name="actionPreferences"/>
</widget> </widget>
<widget class="QMenu" name="menuCalibration">
<property name="title">
<string>Calibration</string>
</property>
<addaction name="actionCalDisabled"/>
<addaction name="separator"/>
<addaction name="actionTracedata"/>
<addaction name="actionImport_error_terms_as_traces"/>
<addaction name="actionEdit_Calibration_Kit"/>
</widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuDevice"/> <addaction name="menuDevice"/>
<addaction name="menuCalibration"/>
<addaction name="menuTools"/>
<addaction name="menuWindow"/> <addaction name="menuWindow"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
@ -137,11 +119,6 @@
<string>Dummy</string> <string>Dummy</string>
</property> </property>
</action> </action>
<action name="actionImpedance_Matching">
<property name="text">
<string>Impedance Matching</string>
</property>
</action>
<action name="actionManual_Control"> <action name="actionManual_Control">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@ -160,32 +137,6 @@
<string>Dummy</string> <string>Dummy</string>
</property> </property>
</action> </action>
<action name="actionCalDisabled">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Disabled</string>
</property>
</action>
<action name="actionTracedata">
<property name="text">
<string>Calibration Data</string>
</property>
</action>
<action name="actionEdit_Calibration_Kit">
<property name="text">
<string>Edit Calibration Kit</string>
</property>
</action>
<action name="actionImport_error_terms_as_traces">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Import error terms as traces</string>
</property>
</action>
<action name="actionAssignDefaultCal"> <action name="actionAssignDefaultCal">
<property name="text"> <property name="text">
<string>Assign...</string> <string>Assign...</string>
@ -212,11 +163,6 @@
<string>Preferences</string> <string>Preferences</string>
</property> </property>
</action> </action>
<action name="actionDummy_4">
<property name="text">
<string>Dummy</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -0,0 +1,151 @@
#include "mode.h"
#include <QPushButton>
#include <QSettings>
#include "ui_main.h"
Mode* Mode::activeMode = nullptr;
QWidget* Mode::cornerWidget = nullptr;
QButtonGroup* Mode::modeButtonGroup = nullptr;
Mode::Mode(AppWindow *window, QString name)
: window(window),
name(name),
central(nullptr)
{
// Create mode switch button
auto modeSwitch = new QPushButton(name);
modeSwitch->setCheckable(true);
modeSwitch->setMaximumHeight(window->getUi()->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);
window->menuBar()->setCornerWidget(cornerWidget);
modeButtonGroup = new QButtonGroup;
window->getUi()->menubar->setMaximumHeight(window->getUi()->menubar->height());
}
cornerWidget->layout()->addWidget(modeSwitch);
modeButtonGroup->addButton(modeSwitch);
connect(modeSwitch, &QPushButton::clicked, [=](){
activate();
});
}
void Mode::activate()
{
if(activeMode == this) {
// already active;
return;
} else if(activeMode) {
activeMode->deactivate();
}
// show all mode specific GUI elements
for(auto t : toolbars) {
t->show();
window->getUi()->menuToolbars->addAction(t->toggleViewAction());
}
for(auto d : docks) {
d->show();
window->getUi()->menuDocks->addAction(d->toggleViewAction());
}
for(auto a : actions) {
a->setVisible(true);
}
QSettings settings;
window->getCentral()->setCurrentWidget(central);
// restore dock and toolbar positions
// window->restoreGeometry(settings.value("geometry_"+name).toByteArray());
window->restoreState(settings.value("windowState_"+name).toByteArray());
// restore visibility of toolbars and docks
// window->getUi()->menuDocks->clear();
for(auto d : window->findChildren<QDockWidget*>()) {
// window->getUi()->menuDocks->addAction(d->toggleViewAction());
bool hidden = settings.value("dock_"+name+"_"+d->windowTitle(), d->isHidden()).toBool();
if(hidden) {
d->hide();
} else {
d->show();
}
}
// window->getUi()->menuToolbars->clear();
for(auto t : window->findChildren<QToolBar*>()) {
// window->getUi()->menuToolbars->addAction(t->toggleViewAction());
bool hidden = settings.value("toolbar_"+name+"_"+t->windowTitle(), t->isHidden()).toBool();
if(hidden) {
t->hide();
} else {
t->show();
}
}
activeMode = this;
if(window->getDevice()) {
initializeDevice();
}
}
void Mode::deactivate()
{
QSettings settings;
// save dock/toolbar visibility
for(auto d : window->findChildren<QDockWidget*>()) {
settings.setValue("dock_"+name+"_"+d->windowTitle(), d->isHidden());
}
for(auto t : window->findChildren<QToolBar*>()) {
settings.setValue("toolbar_"+name+"_"+t->windowTitle(), t->isHidden());
}
// settings.setValue("geometry_"+name, window->saveGeometry());
settings.setValue("windowState_"+name, window->saveState());
// hide all mode specific GUI elements
for(auto t : toolbars) {
t->hide();
window->getUi()->menuToolbars->removeAction(t->toggleViewAction());
}
for(auto d : docks) {
d->hide();
window->getUi()->menuDocks->removeAction(d->toggleViewAction());
}
for(auto a : actions) {
a->setVisible(false);
}
activeMode = nullptr;
}
Mode *Mode::getActiveMode()
{
return activeMode;
}
void Mode::finalize(QWidget *centralWidget)
{
central = centralWidget;
window->getCentral()->addWidget(central);
// hide all mode specific GUI elements
for(auto t : toolbars) {
t->hide();
}
for(auto d : docks) {
d->hide();
}
for(auto a : actions) {
a->setVisible(false);
}
}
QString Mode::getName() const
{
return name;
}

View File

@ -0,0 +1,39 @@
#ifndef MODE_H
#define MODE_H
#include <QString>
#include <QWidget>
#include <QButtonGroup>
#include <QToolBar>
#include <QDockWidget>
#include <set>
#include "appwindow.h"
class Mode : public QWidget
{
public:
Mode(AppWindow *window, QString name);
virtual void activate();
virtual void deactivate();
QString getName() const;
static Mode *getActiveMode();
virtual void initializeDevice() = 0;
protected:
// call once the derived class is fully initialized
void finalize(QWidget *centralWidget);
AppWindow *window;
std::set<QAction*> actions;
std::set<QToolBar*> toolbars;
std::set<QDockWidget*> docks;
private:
static Mode *activeMode;
static QWidget *cornerWidget;
static QButtonGroup *modeButtonGroup;
const QString name;
QWidget *central;
};
#endif // MODE_H

View File

@ -1,148 +0,0 @@
#include "valueinput.h"
#include <QGridLayout>
#include <QKeyEvent>
#include <QApplication>
#include <QDesktopWidget>
constexpr QSize ValueInput::minButtonSize;
ValueInput::ValueInput(std::vector<Unit> units, QString name, QString initialValue)
{
auto fontButton = QFont("Arial", 12);
auto fontLabel = QFont("Arial", 30);
input = initialValue;
// always use dots instead of comma
input.replace(',', '.');
this->units = units;
setWindowTitle(name);
// Create layout
auto layout = new QGridLayout();
// Add Label
label = new QLabel();
layout->addWidget(label, 0, 0, 2, 4);
label->setText(input);
label->setAlignment(Qt::AlignCenter);
label->setFont(fontLabel);
// Create buttons and add to layout
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
int number = i+1 + j*3;
auto name = QString::number(number);
auto button = new QPushButton(name);
button->setFont(fontButton);
button->setMinimumSize(minButtonSize);
connect(button, &QPushButton::clicked, [=]() {this->AddToInput(name);});
layout->addWidget(button, j+2, i);
}
}
bDot = new QPushButton(".");
bDot->setFont(fontButton);
bDot->setMinimumSize(minButtonSize);
if(input.contains('.')) {
bDot->setDisabled(true);
}
layout->addWidget(bDot, 5, 0);
connect(bDot, &QPushButton::clicked, [=]() {this->AddToInput(".");});
auto bZero = new QPushButton("0");
bZero->setFont(fontButton);
bZero->setMinimumSize(minButtonSize);
connect(bZero, &QPushButton::clicked, [=]() {this->AddToInput("0");});
layout->addWidget(bZero, 5, 1);
auto bSign = new QPushButton("+/-");
bSign->setFont(fontButton);
bSign->setMinimumSize(minButtonSize);
layout->addWidget(bSign, 5, 2);
connect(bSign, SIGNAL(clicked()), this, SLOT(ChangeSign()));
auto bDel = new QPushButton("Backspace");
bDel->setMinimumSize(minButtonSize);
layout->addWidget(bDel, 6, 0, 1, 3);
connect(bDel, SIGNAL(clicked()), this, SLOT(Backspace()));
auto bAbort = new QPushButton("Abort");
bAbort->setMinimumSize(minButtonSize);
layout->addWidget(bAbort, 6, 3);
connect(bAbort, SIGNAL(clicked()), this, SLOT(Abort()));
// Add unit inputs
if(units.size() > 4) {
units.resize(4);
}
for(unsigned int i=0;i<units.size();i++) {
auto bUnit = new QPushButton(units[i].name);
bUnit->setFont(fontButton);
bUnit->setMinimumSize(minButtonSize);
connect(bUnit, &QPushButton::clicked, [=](){this->UnitPressed(units[i].factor);});
layout->addWidget(bUnit, i+2, 3);
}
setLayout(layout);
setWindowModality(Qt::ApplicationModal);
show();
}
void ValueInput::keyPressEvent(QKeyEvent *event) {
auto key = event->key();
if(key >= '0' && key <= '9') {
AddToInput((QChar) key);
event->accept();
} else if((key == '.' || key == ',') && bDot->isEnabled()) {
AddToInput(".");
event->accept();
} else if(key == Qt::Key_Escape) {
Abort();
event->accept();
} else if(key == Qt::Key_Backspace) {
Backspace();
event->accept();
} else if(key == '-') {
ChangeSign();
event->accept();
}
}
void ValueInput::AddToInput(QString a)
{
input.append(a);
label->setText(input);
if(a == '.') {
bDot->setDisabled(true);
}
}
void ValueInput::ChangeSign()
{
if(input.at(0) == '-') {
input.remove(0, 1);
} else {
input.prepend('-');
}
label->setText(input);
}
void ValueInput::Backspace()
{
if(input.size() > 0) {
if(input.at(input.size()-1) == '.') {
bDot->setEnabled(true);
}
input.chop(1);
label->setText(input);
}
}
void ValueInput::Abort()
{
close();
}
void ValueInput::UnitPressed(double factor)
{
double value = input.toDouble() * factor;
emit ValueChanged(value);
close();
}

View File

@ -1,44 +0,0 @@
#ifndef VALUEINPUT_H
#define VALUEINPUT_H
#include <QWidget>
#include <vector>
#include <QPushButton>
#include <QLabel>
#include <QSignalMapper>
class ValueInput : public QWidget
{
Q_OBJECT
public:
class Unit {
public:
Unit(){};
Unit(QString name, double factor):
name(name), factor(factor){};
QString name;
double factor;
};
ValueInput(std::vector<Unit> units, QString name = "Value input", QString initialValue = QString());
signals:
void ValueChanged(double value);
protected:
void keyPressEvent(QKeyEvent *event) override;
private slots:
void AddToInput(QString a);
void ChangeSign();
void Backspace();
void Abort();
void UnitPressed(double factor);
private:
static constexpr QSize minButtonSize = QSize(50, 50);
QString input;
QLabel *label;
QPushButton *bDot;
std::vector<Unit> units;
};
#endif // VALUEINPUT_H

View File

@ -1,169 +0,0 @@
#ifndef VNA_H
#define VNA_H
#include <QWidget>
#include <QMainWindow>
#include <QGridLayout>
#include <QComboBox>
#include <QStackedWidget>
#include "Device/device.h"
#include "Traces/traceplot.h"
#include "Calibration/calibration.h"
#include <QProgressDialog>
#include "Menu/menuaction.h"
#include "Traces/tracemodel.h"
#include "Traces/tracemarkermodel.h"
#include "averaging.h"
#include "Device/devicelog.h"
#include "preferences.h"
#include <QButtonGroup>
#include <QCheckBox>
namespace Ui {
class MainWindow;
}
class VNA : public QMainWindow
{
Q_OBJECT
public:
VNA(QWidget *parent = nullptr);
protected:
void closeEvent(QCloseEvent *event) override;
private:
static constexpr double minFreq = 0;
static constexpr double maxFreq = 6000000000;
static constexpr Protocol::SweepSettings defaultSweep = {
.f_start = 1000000,
.f_stop = (uint64_t) maxFreq,
.points = 501,
.if_bandwidth = 1000,
.cdbm_excitation = 0,
};
private slots:
void NewDatapoint(Protocol::Datapoint d);
void ConnectToDevice(QString serial = QString());
void DisconnectDevice();
int UpdateDeviceList();
void StartManualControl();
void StartImpedanceMatching();
// Sweep control
void SetStartFreq(double freq);
void SetStopFreq(double freq);
void SetCenterFreq(double freq);
void SetSpan(double span);
void SetFullSpan();
void SpanZoomIn();
void SpanZoomOut();
// Acquisition control
void SetSourceLevel(double level);
void SetPoints(unsigned int points);
void SetIFBandwidth(double bandwidth);
void SetAveraging(unsigned int averages);
// Calibration
void DisableCalibration(bool force = false);
void ApplyCalibration(Calibration::Type type);
void StartCalibrationMeasurement(Calibration::Measurement m);
void UpdateReference();
signals:
void CalibrationMeasurementComplete(Calibration::Measurement m);
private:
void UpdateStatusPanel();
void SettingsChanged();
void DeviceConnectionLost();
void CreateToolbars();
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 *type;
QCheckBox *automatic;
QCheckBox *outputEnabled;
QComboBox *outFreq;
} reference;
} toolbars;
Preferences pref;
Device *device;
DeviceLog deviceLog;
QString deviceSerial;
QActionGroup *deviceActionGroup;
Protocol::SweepSettings settings;
unsigned int averages;
TraceModel traceModel;
TraceMarkerModel *markerModel;
Averaging average;
// Calibration
Calibration cal;
bool calValid;
Calibration::Measurement calMeasurement;
bool calMeasuring;
bool calWaitFirst;
QProgressDialog calDialog;
// Status Labels
QLabel lStart, lCenter, lStop, lSpan, lPoints, lBandwidth;
QLabel lCalibration;
QLabel lAverages;
// Status bar widgets
QLabel lConnectionStatus;
QLabel lDeviceInfo;
Ui::MainWindow *ui;
signals:
void dataChanged();
void startFreqChanged(double freq);
void stopFreqChanged(double freq);
void centerFreqChanged(double freq);
void spanChanged(double span);
void sourceLevelChanged(double level);
void pointsChanged(unsigned int points);
void IFBandwidthChanged(double bandwidth);
void averagingChanged(unsigned int averages);
void CalibrationDisabled();
void CalibrationApplied(Calibration::Type type);
};
#endif // VNA_H