diff --git a/Software/PC_Application/Application b/Software/PC_Application/Application index 351d308..8109389 100755 Binary files a/Software/PC_Application/Application and b/Software/PC_Application/Application differ diff --git a/Software/PC_Application/Application.pro b/Software/PC_Application/Application.pro index d3be828..4646932 100644 --- a/Software/PC_Application/Application.pro +++ b/Software/PC_Application/Application.pro @@ -13,11 +13,8 @@ HEADERS += \ Device/devicelog.h \ Device/firmwareupdatedialog.h \ Device/manualcontroldialog.h \ - Menu/menu.h \ - Menu/menuaction.h \ - Menu/menubool.h \ - Menu/menuitem.h \ - Menu/menuvalue.h \ + Generator/generator.h \ + Generator/signalgenwidget.h \ Tools/eseries.h \ Tools/impedancematchdialog.h \ Traces/bodeplotaxisdialog.h \ @@ -33,14 +30,14 @@ HEADERS += \ Traces/traceplot.h \ Traces/tracesmithchart.h \ Traces/tracewidget.h \ + VNA/vna.h \ + appwindow.h \ averaging.h \ + mode.h \ preferences.h \ qwtplotpiecewisecurve.h \ - signalgenerator.h \ touchstone.h \ - unit.h \ - valueinput.h \ - vna.h + unit.h SOURCES += \ ../VNA_embedded/Application/Communication/Protocol.cpp \ @@ -49,6 +46,7 @@ SOURCES += \ Calibration/calkit.cpp \ Calibration/calkitdialog.cpp \ Calibration/measurementmodel.cpp \ + CustomWidgets/qwtplotpiecewisecurve.cpp \ CustomWidgets/siunitedit.cpp \ CustomWidgets/tilewidget.cpp \ CustomWidgets/toggleswitch.cpp \ @@ -57,11 +55,8 @@ SOURCES += \ Device/devicelog.cpp \ Device/firmwareupdatedialog.cpp \ Device/manualcontroldialog.cpp \ - Menu/menu.cpp \ - Menu/menuaction.cpp \ - Menu/menubool.cpp \ - Menu/menuitem.cpp \ - Menu/menuvalue.cpp \ + Generator/generator.cpp \ + Generator/signalgenwidget.cpp \ Tools/eseries.cpp \ Tools/impedancematchdialog.cpp \ Traces/bodeplotaxisdialog.cpp \ @@ -77,15 +72,14 @@ SOURCES += \ Traces/traceplot.cpp \ Traces/tracesmithchart.cpp \ Traces/tracewidget.cpp \ + VNA/vna.cpp \ + appwindow.cpp \ averaging.cpp \ main.cpp \ + mode.cpp \ preferences.cpp \ - qwtplotpiecewisecurve.cpp \ - signalgenerator.cpp \ touchstone.cpp \ - unit.cpp \ - valueinput.cpp \ - vna.cpp + unit.cpp LIBS += -lusb-1.0 unix:INCLUDEPATH += /usr/include/qwt @@ -103,6 +97,7 @@ FORMS += \ Device/devicelog.ui \ Device/firmwareupdatedialog.ui \ Device/manualcontroldialog.ui \ + Generator/signalgenwidget.ui \ Tools/impedancematchdialog.ui \ Traces/bodeplotaxisdialog.ui \ Traces/markerwidget.ui \ @@ -111,8 +106,7 @@ FORMS += \ Traces/traceimportdialog.ui \ Traces/tracewidget.ui \ main.ui \ - preferencesdialog.ui \ - signalgenerator.ui + preferencesdialog.ui DISTFILES += diff --git a/Software/PC_Application/qwtplotpiecewisecurve.cpp b/Software/PC_Application/CustomWidgets/qwtplotpiecewisecurve.cpp similarity index 100% rename from Software/PC_Application/qwtplotpiecewisecurve.cpp rename to Software/PC_Application/CustomWidgets/qwtplotpiecewisecurve.cpp diff --git a/Software/PC_Application/Device/device.cpp b/Software/PC_Application/Device/device.cpp index 04b3057..861938c 100644 --- a/Software/PC_Application/Device/device.cpp +++ b/Software/PC_Application/Device/device.cpp @@ -8,6 +8,96 @@ 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 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) { qDebug() << "Starting device connection..."; @@ -62,6 +152,9 @@ Device::Device(QString serial) connect(dataBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedData, Qt::DirectConnection); connect(dataBuffer, &USBInBuffer::TransferError, this, &Device::ConnectionLost); connect(logBuffer, &USBInBuffer::DataReceived, this, &Device::ReceivedLog, Qt::DirectConnection); + connect(&transmissionTimer, &QTimer::timeout, this, &Device::transmissionTimeout); + transmissionTimer.setSingleShot(true); + transmissionActive = false; } Device::~Device() @@ -82,26 +175,17 @@ Device::~Device() } } -bool Device::SendPacket(Protocol::PacketInfo packet) +bool Device::SendPacket(Protocol::PacketInfo packet, std::function cb, unsigned int timeout) { - if(m_connected) { - unsigned char buffer[1024]; - unsigned int length = Protocol::EncodePacket(packet, buffer, sizeof(buffer)); - if(!length) { - qCritical() << "Failed to encode packet"; - return false; - } - 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; - } else { - return false; + Transmission t; + t.packet = packet; + t.timeout = timeout; + t.callback = cb; + transmissionQueue.enqueue(t); + if(!transmissionActive) { + startNextTransmission(); } + return true; } bool Device::Configure(Protocol::SweepSettings settings) @@ -303,93 +387,38 @@ QString Device::serial() const return m_serial; } -USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) : - buffer_size(buffer_size), - received_size(0), - inCallback(false) +void Device::startNextTransmission() { - 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 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(); + if(transmissionQueue.empty() || !m_connected) { + // nothing more to transmit + transmissionActive = false; 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); + transmissionActive = true; + auto t = transmissionQueue.head(); + 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; - usb->Callback(transfer); + transmissionTimer.stop(); + // remove transmitted packet + auto t = transmissionQueue.dequeue(); + if(t.callback) { + t.callback(result); + } + startNextTransmission(); } - -uint8_t *USBInBuffer::getBuffer() const -{ - return buffer; -} - diff --git a/Software/PC_Application/Device/device.h b/Software/PC_Application/Device/device.h index 55fa5c6..28e7438 100644 --- a/Software/PC_Application/Device/device.h +++ b/Software/PC_Application/Device/device.h @@ -1,4 +1,4 @@ -#ifndef DEVICE_H +#ifndef DEVICE_H #define DEVICE_H #include "../VNA_embedded/Application/Communication/Protocol.hpp" @@ -8,6 +8,8 @@ #include #include #include +#include +#include Q_DECLARE_METATYPE(Protocol::Datapoint); Q_DECLARE_METATYPE(Protocol::ManualStatus); @@ -43,10 +45,17 @@ class Device : public QObject { Q_OBJECT 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 Device(QString serial = QString()); ~Device(); - bool SendPacket(Protocol::PacketInfo packet); + bool SendPacket(Protocol::PacketInfo packet, std::function cb = nullptr, unsigned int timeout = 10); bool Configure(Protocol::SweepSettings settings); bool SetManual(Protocol::ManualControl manual); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); @@ -68,6 +77,9 @@ signals: private slots: void ReceivedData(); void ReceivedLog(); + void transmissionTimeout() { + transmissionFinished(TransmissionResult::Timeout); + } private: static constexpr int VID = 0x0483; @@ -86,6 +98,17 @@ private: USBInBuffer *dataBuffer; USBInBuffer *logBuffer; + using Transmission = struct { + Protocol::PacketInfo packet; + unsigned int timeout; + std::function callback; + }; + + QQueue transmissionQueue; + void startNextTransmission(); + void transmissionFinished(TransmissionResult result); + QTimer transmissionTimer; + bool transmissionActive; QString m_serial; bool m_connected; diff --git a/Software/PC_Application/Device/devicelog.ui b/Software/PC_Application/Device/devicelog.ui index e0997b0..9c89375 100644 --- a/Software/PC_Application/Device/devicelog.ui +++ b/Software/PC_Application/Device/devicelog.ui @@ -29,7 +29,8 @@ To File - + + .. @@ -39,7 +40,8 @@ Clear - + + .. @@ -48,6 +50,9 @@ Autoscroll + + true + diff --git a/Software/PC_Application/Generator/generator.cpp b/Software/PC_Application/Generator/generator.cpp new file mode 100644 index 0000000..a1a507b --- /dev/null +++ b/Software/PC_Application/Generator/generator.cpp @@ -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); +} diff --git a/Software/PC_Application/Generator/generator.h b/Software/PC_Application/Generator/generator.h new file mode 100644 index 0000000..fe123d9 --- /dev/null +++ b/Software/PC_Application/Generator/generator.h @@ -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 diff --git a/Software/PC_Application/signalgenerator.cpp b/Software/PC_Application/Generator/signalgenwidget.cpp similarity index 73% rename from Software/PC_Application/signalgenerator.cpp rename to Software/PC_Application/Generator/signalgenwidget.cpp index bb44fac..5b67e8f 100644 --- a/Software/PC_Application/signalgenerator.cpp +++ b/Software/PC_Application/Generator/signalgenwidget.cpp @@ -1,9 +1,9 @@ -#include "signalgenerator.h" +#include "signalgenwidget.h" #include "ui_signalgenerator.h" -Signalgenerator::Signalgenerator(QWidget *parent) : +SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) : QWidget(parent), - ui(new Ui::Signalgenerator) + ui(new Ui::SignalgeneratorWidget) { ui->setupUi(this); ui->frequency->setUnit("Hz"); @@ -17,9 +17,9 @@ Signalgenerator::Signalgenerator(QWidget *parent) : newval = 6000000000; } ui->frequency->setValueQuiet(newval); - SettingsChanged(); + emit SettingsChanged(); }); - connect(ui->levelSpin, qOverload(&QDoubleSpinBox::valueChanged), this, &Signalgenerator::setLevel); + connect(ui->levelSpin, qOverload(&QDoubleSpinBox::valueChanged), this, &SignalgeneratorWidget::setLevel); connect(ui->levelSlider, &QSlider::valueChanged, [=](int value) { setLevel((double) value / 100.0); }); @@ -27,22 +27,29 @@ Signalgenerator::Signalgenerator(QWidget *parent) : if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) { ui->EnablePort2->setCheckState(Qt::CheckState::Unchecked); } - SettingsChanged(); + emit SettingsChanged(); }); connect(ui->EnablePort2, &QCheckBox::clicked, [=](){ if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) { ui->EnablePort1->setCheckState(Qt::CheckState::Unchecked); } - SettingsChanged(); + emit SettingsChanged(); }); } -Signalgenerator::~Signalgenerator() +SignalgeneratorWidget::~SignalgeneratorWidget() { 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 ui->levelSpin->blockSignals(true); @@ -54,7 +61,3 @@ void Signalgenerator::setLevel(double level) SettingsChanged(); } -void Signalgenerator::SettingsChanged() -{ - // TODO compile manual settings packet and send -} diff --git a/Software/PC_Application/signalgenerator.h b/Software/PC_Application/Generator/signalgenwidget.h similarity index 51% rename from Software/PC_Application/signalgenerator.h rename to Software/PC_Application/Generator/signalgenwidget.h index 444ffad..8ef4e05 100644 --- a/Software/PC_Application/signalgenerator.h +++ b/Software/PC_Application/Generator/signalgenwidget.h @@ -5,25 +5,26 @@ #include "Device/device.h" namespace Ui { -class Signalgenerator; +class SignalgeneratorWidget; } -class Signalgenerator : public QWidget +class SignalgeneratorWidget : public QWidget { Q_OBJECT public: - explicit Signalgenerator(QWidget *parent = nullptr); - ~Signalgenerator(); + explicit SignalgeneratorWidget(QWidget *parent = nullptr); + ~SignalgeneratorWidget(); + + Protocol::ManualControl getDeviceStatus(); signals: - void NewManualState(Protocol::ManualStatus s); + void SettingsChanged(); private slots: void setLevel(double level); private: - void SettingsChanged(); - Ui::Signalgenerator *ui; + Ui::SignalgeneratorWidget *ui; }; #endif // SIGNALGENERATOR_H diff --git a/Software/PC_Application/signalgenerator.ui b/Software/PC_Application/Generator/signalgenwidget.ui similarity index 100% rename from Software/PC_Application/signalgenerator.ui rename to Software/PC_Application/Generator/signalgenwidget.ui diff --git a/Software/PC_Application/Menu/menu.cpp b/Software/PC_Application/Menu/menu.cpp deleted file mode 100644 index 818c847..0000000 --- a/Software/PC_Application/Menu/menu.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "menu.h" -#include -#include "menuaction.h" -#include - -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); - } -} - diff --git a/Software/PC_Application/Menu/menu.h b/Software/PC_Application/Menu/menu.h deleted file mode 100644 index 0da8423..0000000 --- a/Software/PC_Application/Menu/menu.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MENU_H -#define MENU_H - -#include -#include -#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 submenus; - std::vector items; - int m_widgetCount; -}; - -#endif // MENU_H diff --git a/Software/PC_Application/Menu/menuaction.cpp b/Software/PC_Application/Menu/menuaction.cpp deleted file mode 100644 index 9a9887d..0000000 --- a/Software/PC_Application/Menu/menuaction.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "menuaction.h" - -#include -#include -#include - -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); -} diff --git a/Software/PC_Application/Menu/menuaction.h b/Software/PC_Application/Menu/menuaction.h deleted file mode 100644 index 6527ebd..0000000 --- a/Software/PC_Application/Menu/menuaction.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MENULABEL_H -#define MENULABEL_H - -#include "menuitem.h" -#include -#include - -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 diff --git a/Software/PC_Application/Menu/menubool.cpp b/Software/PC_Application/Menu/menubool.cpp deleted file mode 100644 index 71b85ce..0000000 --- a/Software/PC_Application/Menu/menubool.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "menubool.h" - -#include - -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); -} diff --git a/Software/PC_Application/Menu/menubool.h b/Software/PC_Application/Menu/menubool.h deleted file mode 100644 index 544d6cc..0000000 --- a/Software/PC_Application/Menu/menubool.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MENUBOOL_H -#define MENUBOOL_H - -#include -#include "menuitem.h" -#include -#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 diff --git a/Software/PC_Application/Menu/menuitem.cpp b/Software/PC_Application/Menu/menuitem.cpp deleted file mode 100644 index 6ab76a6..0000000 --- a/Software/PC_Application/Menu/menuitem.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "menuitem.h" - -#include - -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(); -} diff --git a/Software/PC_Application/Menu/menuitem.h b/Software/PC_Application/Menu/menuitem.h deleted file mode 100644 index 4fe62b8..0000000 --- a/Software/PC_Application/Menu/menuitem.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MENUITEM_H -#define MENUITEM_H - -#include - -class MenuItem : public QFrame -{ - Q_OBJECT -public: - MenuItem(); - -public slots: - virtual void userSelected(){}; - -protected: - void mouseReleaseEvent(QMouseEvent *me) override; - -}; - -#endif // MENUITEM_H diff --git a/Software/PC_Application/Menu/menuvalue.cpp b/Software/PC_Application/Menu/menuvalue.cpp deleted file mode 100644 index c6f52dd..0000000 --- a/Software/PC_Application/Menu/menuvalue.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "menuvalue.h" - -#include -#include -#include -#include -#include "valueinput.h" -#include -#include "unit.h" -#include - -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(); -} diff --git a/Software/PC_Application/Menu/menuvalue.h b/Software/PC_Application/Menu/menuvalue.h deleted file mode 100644 index dcb629f..0000000 --- a/Software/PC_Application/Menu/menuvalue.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MENUVALUE_H -#define MENUVALUE_H - -#include "menuitem.h" -#include -#include - -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 diff --git a/Software/PC_Application/vna.cpp b/Software/PC_Application/VNA/vna.cpp similarity index 52% rename from Software/PC_Application/vna.cpp rename to Software/PC_Application/VNA/vna.cpp index f7aa1f9..0a72c6f 100644 --- a/Software/PC_Application/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -8,16 +8,11 @@ #include #include #include -#include "valueinput.h" #include #include #include #include #include -#include "Menu/menu.h" -#include "Menu/menuaction.h" -#include "Menu/menuvalue.h" -#include "Menu/menubool.h" #include #include #include @@ -33,6 +28,7 @@ #include "Traces/tracebodeplot.h" #include "Traces/traceimportdialog.h" #include "CustomWidgets/tilewidget.h" +#include "CustomWidgets/siunitedit.h" #include #include "Traces/markerwidget.h" #include "Tools/impedancematchdialog.h" @@ -40,18 +36,14 @@ #include "ui_main.h" #include "Device/firmwareupdatedialog.h" #include "preferences.h" -#include "signalgenerator.h" +#include "Generator/signalgenwidget.h" #include #include +#include -using namespace std; - -constexpr Protocol::SweepSettings VNA::defaultSweep; - -VNA::VNA(QWidget *parent) - : QMainWindow(parent) - , deviceActionGroup(new QActionGroup(this)) - , ui(new Ui::MainWindow) +VNA::VNA(AppWindow *window) + : Mode(window, "Vector Network Analyzer"), + central(new TileWidget(traceModel)) { QCoreApplication::setOrganizationName("VNA"); QCoreApplication::setApplicationName("Application"); @@ -61,20 +53,8 @@ VNA::VNA(QWidget *parent) averages = 1; calValid = false; calMeasuring = false; - device = nullptr; calDialog.reset(); - 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; };"); - // Create default traces auto tS11 = new Trace("S11", Qt::yellow); tS11->fromLivedata(Trace::LivedataType::Overwrite, Trace::LiveParameter::S11); @@ -99,374 +79,73 @@ VNA::VNA(QWidget *parent) 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); + central->splitVertically(); + central->Child1()->splitHorizontally(); + central->Child2()->splitHorizontally(); + central->Child1()->Child1()->setPlot(tracesmith1); + central->Child1()->Child2()->setPlot(tracebode1); + central->Child2()->Child1()->setPlot(tracebode2); + central->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()); + // central widget is constructed, mode can be finalized + finalize(central); - CreateToolbars(); - // UI connections - connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &VNA::UpdateDeviceList); - connect(ui->actionDisconnect, &QAction::triggered, this, &VNA::DisconnectDevice); - connect(ui->actionQuit, &QAction::triggered, this, &VNA::close); - connect(ui->actionManual_Control, &QAction::triggered, this, &VNA::StartManualControl); - connect(ui->actionImpedance_Matching, &QAction::triggered, this, &VNA::StartImpedanceMatching); - connect(ui->actionEdit_Calibration_Kit, &QAction::triggered, [=](){ - cal.getCalibrationKit().edit(); - }); - connect(ui->actionImport_error_terms_as_traces, &QAction::triggered, [=](){ - auto import = new TraceImportDialog(traceModel, cal.getErrorTermTraces()); - import->show(); - }); - connect(ui->actionTracedata, &QAction::triggered, [=](){ + // Create menu entries and connections + auto calMenu = new QMenu("Calibration"); + window->menuBar()->insertMenu(window->getUi()->menuWindow->menuAction(), calMenu); + actions.insert(calMenu->menuAction()); + auto calDisable = calMenu->addAction("Disabled"); + calDisable->setCheckable(true); + calDisable->setChecked(true); + calMenu->addSeparator(); + auto calData = calMenu->addAction("Calibration Data"); + connect(calData, &QAction::triggered, [=](){ auto dialog = new CalibrationTraceDialog(&cal); connect(dialog, &CalibrationTraceDialog::triggerMeasurement, this, &VNA::StartCalibrationMeasurement); connect(dialog, &CalibrationTraceDialog::applyCalibration, this, &VNA::ApplyCalibration); connect(this, &VNA::CalibrationMeasurementComplete, dialog, &CalibrationTraceDialog::measurementComplete); dialog->show(); }); - connect(ui->actionAssignDefaultCal, &QAction::triggered, [=](){ - if(device) { - auto key = "DefaultCalibration"+device->serial(); + + auto calImport = calMenu->addAction("Import error terms as traces"); + calImport->setEnabled(false); + connect(calImport, &QAction::triggered, [=](){ + auto import = new TraceImportDialog(traceModel, cal.getErrorTermTraces()); + import->show(); + }); + + auto calEditKit = calMenu->addAction("Edit Calibration Kit"); + connect(calEditKit, &QAction::triggered, [=](){ + cal.getCalibrationKit().edit(); + }); + + // Tools menu + auto toolsMenu = new QMenu("Tools"); + window->menuBar()->insertMenu(window->getUi()->menuWindow->menuAction(), toolsMenu); + actions.insert(toolsMenu->menuAction()); + auto impedanceMatching = toolsMenu->addAction("Impedance Matching"); + connect(impedanceMatching, &QAction::triggered, this, &VNA::StartImpedanceMatching); + + connect(window->getUi()->actionAssignDefaultCal, &QAction::triggered, [=](){ + if(window->getDevice()) { + auto key = "DefaultCalibration"+window->getDevice()->serial(); QSettings settings; auto filename = QFileDialog::getOpenFileName(nullptr, "Load calibration data", settings.value(key).toString(), "Calibration files (*.cal)", nullptr, QFileDialog::DontUseNativeDialog); if(!filename.isEmpty()) { settings.setValue(key, filename); - ui->actionRemoveDefaultCal->setEnabled(true); + window->getUi()->actionRemoveDefaultCal->setEnabled(true); } } }); - connect(ui->actionRemoveDefaultCal, &QAction::triggered, [=](){ + connect(window->getUi()->actionRemoveDefaultCal, &QAction::triggered, [=](){ QSettings settings; - settings.remove("DefaultCalibration"+device->serial()); - ui->actionRemoveDefaultCal->setEnabled(false); - }); - connect(ui->actionFirmware_Update, &QAction::triggered, [=](){ - if(device) { - auto fw_update = new FirmwareUpdateDialog(device); - fw_update->exec(); - } - }); - connect(ui->actionPreferences, &QAction::triggered, [=](){ - pref.edit(); + settings.remove("DefaultCalibration"+window->getDevice()->serial()); + window->getUi()->actionRemoveDefaultCal->setEnabled(false); }); - setWindowTitle("VNA"); - - markerModel = new TraceMarkerModel(traceModel); - - // Create status panel - auto statusLayout = new QVBoxLayout(); - statusLayout->setSpacing(0); - QFont statusFont( "Arial", 8); - { - auto l = new QLabel("Start Frequency:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lStart.setAlignment(Qt::AlignRight); - lStart.setFont(statusFont); - statusLayout->addWidget(&lStart); - - l = new QLabel("Center Frequency:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lCenter.setAlignment(Qt::AlignRight); - lCenter.setFont(statusFont); - statusLayout->addWidget(&lCenter); - - l = new QLabel("Stop Frequency:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lStop.setAlignment(Qt::AlignRight); - lStop.setFont(statusFont); - statusLayout->addWidget(&lStop); - - l = new QLabel("Span:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lSpan.setAlignment(Qt::AlignRight); - lSpan.setFont(statusFont); - statusLayout->addWidget(&lSpan); - - statusLayout->addStretch(); - - l = new QLabel("Points:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lPoints.setAlignment(Qt::AlignRight); - lPoints.setFont(statusFont); - statusLayout->addWidget(&lPoints); - - l = new QLabel("IF Bandwidth:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lBandwidth.setAlignment(Qt::AlignRight); - lBandwidth.setFont(statusFont); - statusLayout->addWidget(&lBandwidth); - - l = new QLabel("Averages:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lAverages.setAlignment(Qt::AlignRight); - lAverages.setFont(statusFont); - statusLayout->addWidget(&lAverages); - - statusLayout->addStretch(); - - l = new QLabel("Calibration:"); - l->setAlignment(Qt::AlignLeft); - l->setFont(statusFont); - statusLayout->addWidget(l); - lCalibration.setAlignment(Qt::AlignRight); - lCalibration.setFont(statusFont); - statusLayout->addWidget(&lCalibration); - } - statusLayout->addStretch(); - - setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); - setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); - setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); - setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - - auto statusWidget = new QWidget; - statusWidget->setLayout(statusLayout); -// statusWidget->setFixedWidth(150); - auto statusDock = new QDockWidget("Status"); - statusDock->setWidget(statusWidget); - addDockWidget(Qt::LeftDockWidgetArea, statusDock); - - auto tracesDock = new QDockWidget("Traces"); - tracesDock->setWidget(new TraceWidget(traceModel)); - addDockWidget(Qt::LeftDockWidgetArea, tracesDock); - - - auto markerWidget = new MarkerWidget(*markerModel); - - auto markerDock = new QDockWidget("Marker"); - markerDock->setWidget(markerWidget); - addDockWidget(Qt::BottomDockWidgetArea, markerDock); - - auto logDock = new QDockWidget("Device Log"); - logDock->setWidget(&deviceLog); - addDockWidget(Qt::BottomDockWidgetArea, logDock); - - modeSGen->addHiddenElement(markerDock); - modeSGen->addHiddenElement(tracesDock); - modeSGen->addHiddenElement(statusDock); - - // status and menu dock hidden by default - statusDock->close(); - - { - QSettings settings; - restoreGeometry(settings.value("geometry").toByteArray()); - } - - // Set ObjectName for toolbars and docks - for(auto d : findChildren()) { - d->setObjectName(d->windowTitle()); - } - for(auto t : findChildren()) { - t->setObjectName(t->windowTitle()); - } - - // Set default mode - modeVNA->activate(); - - qRegisterMetaType("Datapoint"); - - - // 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 - if(UpdateDeviceList() && pref.Startup.ConnectToFirstDevice) { - // at least one device available - ConnectToDevice(); - } -} - -void VNA::closeEvent(QCloseEvent *event) -{ - QSettings settings; - settings.setValue("geometry", saveGeometry()); - // deactivate currently used mode (stores mode state in settings) - GUIMode::getActiveMode()->deactivate(); - StoreSweepSettings(); - pref.store(); - QMainWindow::closeEvent(event); -} - -void VNA::NewDatapoint(Protocol::Datapoint d) -{ - if(calMeasuring) { - if(!calWaitFirst || d.pointNum == 0) { - calWaitFirst = false; - cal.addMeasurement(calMeasurement, d); - if(d.pointNum == settings.points - 1) { - calMeasuring = false; - emit CalibrationMeasurementComplete(calMeasurement); - } - calDialog.setValue(d.pointNum + 1); - } - } - if(calValid) { - cal.correctMeasurement(d); - } - d = average.process(d); - traceModel.addVNAData(d); - emit dataChanged(); - if(d.pointNum == settings.points - 1) { - UpdateStatusPanel(); - } -} - -void VNA::UpdateStatusPanel() -{ - lStart.setText(Unit::ToString(settings.f_start, "Hz", " kMG", 4)); - lCenter.setText(Unit::ToString((settings.f_start + settings.f_stop)/2, "Hz", " kMG", 4)); - lStop.setText(Unit::ToString(settings.f_stop, "Hz", " kMG", 4)); - lSpan.setText(Unit::ToString(settings.f_stop - settings.f_start, "Hz", " kMG", 4)); - lPoints.setText(QString::number(settings.points)); - lBandwidth.setText(Unit::ToString(settings.if_bandwidth, "Hz", " k", 2)); - lAverages.setText(QString::number(average.getLevel()) + "/" + QString::number(averages)); - if(calValid) { - switch(cal.getInterpolation(settings)) { - case Calibration::InterpolationType::Extrapolate: - lCalibration.setText("Enabled/Extrapolating"); - break; - case Calibration::InterpolationType::Interpolate: - lCalibration.setText("Enabled/Interpolating"); - break; - case Calibration::InterpolationType::Exact: - case Calibration::InterpolationType::Unchanged: - lCalibration.setText("Enabled"); - break; - default: - lCalibration.setText("Unknown"); - break; - } - } else { - lCalibration.setText("Off"); - } -} - -void VNA::SettingsChanged() -{ - if(device) { - device->Configure(settings); - } - average.reset(); - traceModel.clearVNAData(); - UpdateStatusPanel(); - TracePlot::UpdateSpan(settings.f_start, settings.f_stop); -} - -void VNA::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::DatapointReceived, this, &VNA::NewDatapoint); - connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine); - connect(device, &Device::ConnectionLost, this, &VNA::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); - { - // Check if default calibration exists and attempt to load it - QSettings settings; - auto key = "DefaultCalibration"+device->serial(); - if (settings.contains(key)) { - auto filename = settings.value(key).toString(); - qDebug() << "Attempting to load default calibration file \"" << filename << "\""; - if(QFile::exists(filename)) { - cal.openFromFile(filename); - ApplyCalibration(cal.getType()); - } - ui->actionRemoveDefaultCal->setEnabled(true); - } else { - qDebug() << "No default calibration file set for this device"; - ui->actionRemoveDefaultCal->setEnabled(false); - } - } - // Configure initial state of device - device->Configure(settings); - UpdateReference(); - } catch (const runtime_error e) { - DisconnectDevice(); - UpdateDeviceList(); - } -} - -void VNA::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 VNA::DeviceConnectionLost() -{ - DisconnectDevice(); - QMessageBox::warning(this, "Disconnected", "The USB connection to the device has been lost"); - UpdateDeviceList(); -} - -void VNA::CreateToolbars() -{ // Sweep toolbar - auto tb_sweep = new QToolBar("Sweep", this); + auto tb_sweep = new QToolBar("Sweep"); auto eStart = new SIUnitEdit("Hz", " kMG", 6); eStart->setFixedWidth(100); eStart->setToolTip("Start frequency"); @@ -514,11 +193,11 @@ void VNA::CreateToolbars() connect(bZoomOut, &QPushButton::clicked, this, &VNA::SpanZoomOut); tb_sweep->addWidget(bZoomOut); - addToolBar(tb_sweep); - modeSGen->addHiddenElement(tb_sweep); + window->addToolBar(tb_sweep); + toolbars.insert(tb_sweep); // Acquisition toolbar - auto tb_acq = new QToolBar("Acquisition", this); + auto tb_acq = new QToolBar("Acquisition"); auto dbm = new QDoubleSpinBox(); dbm->setValue(settings.cdbm_excitation * 100); dbm->setFixedWidth(95); @@ -551,36 +230,8 @@ void VNA::CreateToolbars() tb_acq->addWidget(new QLabel("IF BW:")); tb_acq->addWidget(eBandwidth); - addToolBar(tb_acq); - modeSGen->addHiddenElement(tb_acq); - - // 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(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference); - connect(toolbars.reference.outFreq, qOverload(&QComboBox::currentIndexChanged), this, &VNA::UpdateReference); - connect(toolbars.reference.outputEnabled, &QCheckBox::clicked, this, &VNA::UpdateReference); - - addToolBar(tb_reference); + window->addToolBar(tb_acq); + toolbars.insert(tb_acq); // Calibration toolbar (and populate calibration menu) auto tb_cal = new QToolBar("Calibration"); @@ -589,7 +240,7 @@ void VNA::CreateToolbars() tb_cal->addWidget(cbEnableCal); auto cbType = new QComboBox(); auto calMenuGroup = new QActionGroup(this); - calMenuGroup->addAction(ui->actionCalDisabled); + calMenuGroup->addAction(calDisable); for(auto type : Calibration::Types()) { cbType->addItem(Calibration::TypeToString(type), (int) type); auto menuAction = new QAction(Calibration::TypeToString(type)); @@ -603,7 +254,7 @@ void VNA::CreateToolbars() } }); menuAction->setCheckable(true); - ui->menuCalibration->insertAction(ui->actionCalDisabled, menuAction); + calMenu->insertAction(calDisable, menuAction); } auto calToolbarLambda = [=]() { @@ -621,12 +272,13 @@ void VNA::CreateToolbars() connect(this, &VNA::CalibrationDisabled, [=](){ cbType->blockSignals(true); cbEnableCal->blockSignals(true); - ui->actionCalDisabled->setChecked(true); + calDisable->setChecked(true); cbEnableCal->setCheckState(Qt::CheckState::Unchecked); cbType->blockSignals(false); cbEnableCal->blockSignals(false); + calImport->setEnabled(false); }); - connect(ui->actionCalDisabled, &QAction::triggered, this, &VNA::DisableCalibration); + connect(calDisable, &QAction::triggered, this, &VNA::DisableCalibration); connect(this, &VNA::CalibrationApplied, [=](Calibration::Type applied){ cbType->blockSignals(true); cbEnableCal->blockSignals(true); @@ -639,49 +291,232 @@ void VNA::CreateToolbars() cbEnableCal->setCheckState(Qt::CheckState::Checked); cbType->blockSignals(false); cbEnableCal->blockSignals(false); + calImport->setEnabled(true); }); tb_cal->addWidget(cbType); - addToolBar(tb_cal); - modeSGen->addHiddenElement(tb_cal); -} + window->addToolBar(tb_cal); + toolbars.insert(tb_cal); -int VNA::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); + + markerModel = new TraceMarkerModel(traceModel); + + // Create status panel + auto statusLayout = new QVBoxLayout(); + statusLayout->setSpacing(0); + QFont statusFont( "Arial", 8); + { + auto l = new QLabel("Start Frequency:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lStart = new QLabel; + lStart->setAlignment(Qt::AlignRight); + lStart->setFont(statusFont); + statusLayout->addWidget(lStart); + + l = new QLabel("Center Frequency:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lCenter = new QLabel; + lCenter->setAlignment(Qt::AlignRight); + lCenter->setFont(statusFont); + statusLayout->addWidget(lCenter); + + l = new QLabel("Stop Frequency:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lStop = new QLabel; + lStop->setAlignment(Qt::AlignRight); + lStop->setFont(statusFont); + statusLayout->addWidget(lStop); + + l = new QLabel("Span:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lSpan = new QLabel; + lSpan->setAlignment(Qt::AlignRight); + lSpan->setFont(statusFont); + statusLayout->addWidget(lSpan); + + statusLayout->addStretch(); + + l = new QLabel("Points:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lPoints = new QLabel; + lPoints->setAlignment(Qt::AlignRight); + lPoints->setFont(statusFont); + statusLayout->addWidget(lPoints); + + l = new QLabel("IF Bandwidth:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lBandwidth = new QLabel; + lBandwidth->setAlignment(Qt::AlignRight); + lBandwidth->setFont(statusFont); + statusLayout->addWidget(lBandwidth); + + l = new QLabel("Averages:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lAverages = new QLabel; + lAverages->setAlignment(Qt::AlignRight); + lAverages->setFont(statusFont); + statusLayout->addWidget(lAverages); + + statusLayout->addStretch(); + + l = new QLabel("Calibration:"); + l->setAlignment(Qt::AlignLeft); + l->setFont(statusFont); + statusLayout->addWidget(l); + lCalibration = new QLabel; + lCalibration->setAlignment(Qt::AlignRight); + lCalibration->setFont(statusFont); + statusLayout->addWidget(lCalibration); + } + statusLayout->addStretch(); + + auto statusWidget = new QWidget; + statusWidget->setLayout(statusLayout); +// statusWidget->setFixedWidth(150); + auto statusDock = new QDockWidget("Status"); + statusDock->setWidget(statusWidget); + window->addDockWidget(Qt::LeftDockWidgetArea, statusDock); + docks.insert(statusDock); + + auto tracesDock = new QDockWidget("Traces"); + tracesDock->setWidget(new TraceWidget(traceModel)); + window->addDockWidget(Qt::LeftDockWidgetArea, tracesDock); + docks.insert(tracesDock); + + + auto markerWidget = new MarkerWidget(*markerModel); + + auto markerDock = new QDockWidget("Marker"); + markerDock->setWidget(markerWidget); + window->addDockWidget(Qt::BottomDockWidgetArea, markerDock); + docks.insert(markerDock); + + // status dock hidden by default + statusDock->hide(); + + qRegisterMetaType("Datapoint"); + + // 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); } - return devices.size(); } -void VNA::StartManualControl() +void VNA::deactivate() { - auto control = new ManualControlDialog(*device, this); - connect(control, &QDialog::finished, [this](){ - SettingsChanged(); - }); - control->show(); + StoreSweepSettings(); + Mode::deactivate(); +} + +void VNA::initializeDevice() +{ + connect(window->getDevice(), &Device::DatapointReceived, this, &VNA::NewDatapoint, Qt::UniqueConnection); + // Check if default calibration exists and attempt to load it + QSettings s; + auto key = "DefaultCalibration"+window->getDevice()->serial(); + if (s.contains(key)) { + auto filename = s.value(key).toString(); + qDebug() << "Attempting to load default calibration file \"" << filename << "\""; + if(QFile::exists(filename)) { + cal.openFromFile(filename); + ApplyCalibration(cal.getType()); + } + window->getUi()->actionRemoveDefaultCal->setEnabled(true); + } else { + qDebug() << "No default calibration file set for this device"; + window->getUi()->actionRemoveDefaultCal->setEnabled(false); + } + // Configure initial state of device + window->getDevice()->Configure(settings); +} + +using namespace std; + +void VNA::NewDatapoint(Protocol::Datapoint d) +{ + if(calMeasuring) { + if(!calWaitFirst || d.pointNum == 0) { + calWaitFirst = false; + cal.addMeasurement(calMeasurement, d); + if(d.pointNum == settings.points - 1) { + calMeasuring = false; + emit CalibrationMeasurementComplete(calMeasurement); + } + calDialog.setValue(d.pointNum + 1); + } + } + if(calValid) { + cal.correctMeasurement(d); + } + d = average.process(d); + traceModel.addVNAData(d); + emit dataChanged(); + if(d.pointNum == settings.points - 1) { + UpdateStatusPanel(); + } +} + +void VNA::UpdateStatusPanel() +{ + lStart->setText(Unit::ToString(settings.f_start, "Hz", " kMG", 4)); + lCenter->setText(Unit::ToString((settings.f_start + settings.f_stop)/2, "Hz", " kMG", 4)); + lStop->setText(Unit::ToString(settings.f_stop, "Hz", " kMG", 4)); + lSpan->setText(Unit::ToString(settings.f_stop - settings.f_start, "Hz", " kMG", 4)); + lPoints->setText(QString::number(settings.points)); + lBandwidth->setText(Unit::ToString(settings.if_bandwidth, "Hz", " k", 2)); + lAverages->setText(QString::number(average.getLevel()) + "/" + QString::number(averages)); + if(calValid) { + switch(cal.getInterpolation(settings)) { + case Calibration::InterpolationType::Extrapolate: + lCalibration->setText("Enabled/Extrapolating"); + break; + case Calibration::InterpolationType::Interpolate: + lCalibration->setText("Enabled/Interpolating"); + break; + case Calibration::InterpolationType::Exact: + case Calibration::InterpolationType::Unchanged: + lCalibration->setText("Enabled"); + break; + default: + lCalibration->setText("Unknown"); + break; + } + } else { + lCalibration->setText("Off"); + } +} + +void VNA::SettingsChanged() +{ + if(window->getDevice()) { + window->getDevice()->Configure(settings); + } + average.reset(); + traceModel.clearVNAData(); + UpdateStatusPanel(); + TracePlot::UpdateSpan(settings.f_start, settings.f_stop); } void VNA::StartImpedanceMatching() @@ -736,7 +571,7 @@ void VNA::SetSpan(double span) void VNA::SetFullSpan() { settings.f_start = 0; - settings.f_stop = maxFreq; + settings.f_stop = 6000000000; ConstrainAndUpdateFrequencies(); } @@ -807,7 +642,6 @@ void VNA::DisableCalibration(bool force) { if(calValid || force) { calValid = false; - ui->actionImport_error_terms_as_traces->setEnabled(false); emit CalibrationDisabled(); average.reset(); } @@ -820,7 +654,6 @@ void VNA::ApplyCalibration(Calibration::Type type) cal.constructErrorTerms(type); calValid = true; average.reset(); - ui->actionImport_error_terms_as_traces->setEnabled(true); emit CalibrationApplied(type); } catch (runtime_error e) { QMessageBox::critical(this, "Calibration failure", e.what()); @@ -866,39 +699,11 @@ void VNA::StartCalibrationMeasurement(Calibration::Measurement m) }); } -void VNA::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); -} - void VNA::ConstrainAndUpdateFrequencies() { - if(settings.f_stop > maxFreq) { - settings.f_stop = maxFreq; + // TODO central hardware limits + if(settings.f_stop > 6000000000) { + settings.f_stop = 6000000000; } if(settings.f_start > settings.f_stop) { settings.f_start = settings.f_stop; @@ -930,123 +735,3 @@ void VNA::StoreSweepSettings() 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()) { - 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()) { - 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()) { - settings.setValue("dock_"+name+"_"+d->windowTitle(), d->isHidden()); - } - for(auto t : vna->findChildren()) { - 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; -} diff --git a/Software/PC_Application/VNA/vna.h b/Software/PC_Application/VNA/vna.h new file mode 100644 index 0000000..27066a1 --- /dev/null +++ b/Software/PC_Application/VNA/vna.h @@ -0,0 +1,89 @@ +#ifndef VNA_H +#define VNA_H + +#include +#include +#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 diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp new file mode 100644 index 0000000..c9f46d4 --- /dev/null +++ b/Software/PC_Application/appwindow.cpp @@ -0,0 +1,316 @@ +#include "appwindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#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 +#include +#include +#include +#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()) { + ui->menuDocks->addAction(d->toggleViewAction()); + } + ui->menuToolbars->clear(); + for(auto t : findChildren()) { + 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()) { + d->setObjectName(d->windowTitle()); + } + for(auto t : findChildren()) { + t->setObjectName(t->windowTitle()); + } + + // Set default mode + vna->activate(); + + qRegisterMetaType("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(&QComboBox::currentIndexChanged), this, &AppWindow::UpdateReference); + connect(toolbars.reference.outFreq, qOverload(&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; +} diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h new file mode 100644 index 0000000..7af49b9 --- /dev/null +++ b/Software/PC_Application/appwindow.h @@ -0,0 +1,75 @@ +#ifndef APPWINDOW_H +#define APPWINDOW_H + +#include +#include +#include +#include +#include +#include "Device/device.h" +#include "Traces/traceplot.h" +#include "Calibration/calibration.h" +#include +#include "Traces/tracemodel.h" +#include "Traces/tracemarkermodel.h" +#include "averaging.h" +#include "Device/devicelog.h" +#include "preferences.h" +#include +#include +#include + +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 diff --git a/Software/PC_Application/main.cpp b/Software/PC_Application/main.cpp index c422cb5..373d46a 100644 --- a/Software/PC_Application/main.cpp +++ b/Software/PC_Application/main.cpp @@ -2,12 +2,7 @@ #include #include -#include "vna.h" -#include "valueinput.h" - -#include "Menu/menu.h" -#include "Menu/menuaction.h" -#include "Menu/menuvalue.h" +#include "appwindow.h" #include "Calibration/calkit.h" #include "touchstone.h" @@ -15,7 +10,7 @@ #include int main(int argc, char *argv[]) { QApplication a(argc, argv); - VNA vna; + AppWindow vna; vna.resize(1280, 800); vna.show(); a.exec(); diff --git a/Software/PC_Application/main.ui b/Software/PC_Application/main.ui index 3642195..deacbc8 100644 --- a/Software/PC_Application/main.ui +++ b/Software/PC_Application/main.ui @@ -60,12 +60,6 @@ - - - Tools - - - Window @@ -86,20 +80,8 @@ - - - Calibration - - - - - - - - - @@ -137,11 +119,6 @@ Dummy - - - Impedance Matching - - false @@ -160,32 +137,6 @@ Dummy - - - true - - - Disabled - - - - - Calibration Data - - - - - Edit Calibration Kit - - - - - false - - - Import error terms as traces - - Assign... @@ -212,11 +163,6 @@ Preferences - - - Dummy - - diff --git a/Software/PC_Application/mode.cpp b/Software/PC_Application/mode.cpp new file mode 100644 index 0000000..8e3ae7b --- /dev/null +++ b/Software/PC_Application/mode.cpp @@ -0,0 +1,151 @@ +#include "mode.h" + +#include +#include +#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()) { +// 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()) { +// 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()) { + settings.setValue("dock_"+name+"_"+d->windowTitle(), d->isHidden()); + } + for(auto t : window->findChildren()) { + 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; +} diff --git a/Software/PC_Application/mode.h b/Software/PC_Application/mode.h new file mode 100644 index 0000000..26eecc1 --- /dev/null +++ b/Software/PC_Application/mode.h @@ -0,0 +1,39 @@ +#ifndef MODE_H +#define MODE_H + +#include +#include +#include +#include +#include +#include +#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 actions; + std::set toolbars; + std::set docks; + +private: + static Mode *activeMode; + static QWidget *cornerWidget; + static QButtonGroup *modeButtonGroup; + const QString name; + QWidget *central; +}; + +#endif // MODE_H diff --git a/Software/PC_Application/valueinput.cpp b/Software/PC_Application/valueinput.cpp deleted file mode 100644 index d5507bc..0000000 --- a/Software/PC_Application/valueinput.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "valueinput.h" -#include -#include -#include -#include - -constexpr QSize ValueInput::minButtonSize; - -ValueInput::ValueInput(std::vector 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;isetFont(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(); -} diff --git a/Software/PC_Application/valueinput.h b/Software/PC_Application/valueinput.h deleted file mode 100644 index d8a4c1c..0000000 --- a/Software/PC_Application/valueinput.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef VALUEINPUT_H -#define VALUEINPUT_H - -#include -#include -#include -#include -#include - -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 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 units; -}; - -#endif // VALUEINPUT_H diff --git a/Software/PC_Application/vna.h b/Software/PC_Application/vna.h deleted file mode 100644 index 0ce0380..0000000 --- a/Software/PC_Application/vna.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef VNA_H -#define VNA_H - -#include -#include -#include -#include -#include -#include "Device/device.h" -#include "Traces/traceplot.h" -#include "Calibration/calibration.h" -#include -#include "Menu/menuaction.h" -#include "Traces/tracemodel.h" -#include "Traces/tracemarkermodel.h" -#include "averaging.h" -#include "Device/devicelog.h" -#include "preferences.h" -#include -#include - -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 hiddenActions; - std::set hiddenToolbars; - std::set 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