diff --git a/Software/PC_Application/Device/virtualdevice.cpp b/Software/PC_Application/Device/virtualdevice.cpp new file mode 100644 index 0000000..d4762f5 --- /dev/null +++ b/Software/PC_Application/Device/virtualdevice.cpp @@ -0,0 +1,488 @@ +#include "virtualdevice.h" + +#include "preferences.h" +#include "../VNA_embedded/Application/Communication/Protocol.hpp" + +static VirtualDevice *connected = nullptr; + +using namespace std; + +class Reference +{ +public: + enum class TypeIn { + Internal, + External, + Auto, + None + }; + enum class OutFreq { + MHZ10, + MHZ100, + Off, + None + }; + + static QString OutFreqToLabel(Reference::OutFreq t) + { + switch(t) { + case OutFreq::MHZ10: return "10 MHz"; + case OutFreq::MHZ100: return "100 MHz"; + case OutFreq::Off: return "Off"; + default: return "Invalid"; + } + } + + static QString OutFreqToKey(Reference::OutFreq f) + { + switch(f) { + case OutFreq::MHZ10: return "10 MHz"; + case OutFreq::MHZ100: return "100 MHz"; + case OutFreq::Off: return "Off"; + default: return "Invalid"; + } + } + + static Reference::OutFreq KeyToOutFreq(QString key) + { + for (auto r: Reference::getOutFrequencies()) { + if(OutFreqToKey(r) == key|| OutFreqToLabel(r) == key) { + return r; + } + } + // not found + return Reference::OutFreq::None; + } + + + static QString TypeToLabel(TypeIn t) + { + switch(t) { + case TypeIn::Internal: return "Internal"; + case TypeIn::External: return "External"; + case TypeIn::Auto: return "Auto"; + default: return "Invalid"; + } + } + + static const QString TypeToKey(TypeIn t) + { + switch(t) { + case TypeIn::Internal: return "Int"; + case TypeIn::External: return "Ext"; + case TypeIn::Auto: return "Auto"; + default: return "Invalid"; + } + } + + static TypeIn KeyToType(QString key) + { + for (auto r: Reference::getReferencesIn()) { + if(TypeToKey(r) == key || TypeToLabel(r) == key) { + return r; + } + } + // not found + return TypeIn::None; + } + + static std::vector getReferencesIn() + { + return {TypeIn::Internal, TypeIn::External, TypeIn::Auto}; + } + + static std::vector getOutFrequencies() + { + return {OutFreq::Off, OutFreq::MHZ10, OutFreq::MHZ100}; + } +}; + +static constexpr VirtualDevice::Info defaultInfo = { + .ProtocolVersion = Protocol::Version, + .FW_major = 0, + .FW_minor = 0, + .FW_patch = 0, + .hardware_version = 1, + .HW_Revision = '0', + .ports = 2, + .supportsVNAmode = true, + .supportsSAmode = true, + .supportsSGmode = true, + .Limits = { + .minFreq = 0, + .maxFreq = 6000000000, + .maxFreqHarmonic = 18000000000, + .minIFBW = 10, + .maxIFBW = 1000000, + .maxPoints = 10000, + .mindBm = -100, + .maxdBm = 100, + .minRBW = 1, + .maxRBW = 1000000, + } +}; + +static const VirtualDevice::Status defaultStatus = { + .statusString = "", + .overload = false, + .unlocked = false, + .unlevel = false, +}; + +VirtualDevice::VirtualDevice(QString serial) + : QObject(), + info{} +{ + isCompound = false; + zerospan = false; + auto dev = new Device(serial); + devices.push_back(dev); + + if(!isCompoundDevice()) { + // just acting as a wrapper for device, pass on signals + connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost); + connect(dev, &Device::DeviceInfoUpdated, [&](){ + auto i = dev->Info(); + info.ProtocolVersion = i.ProtocolVersion; + info.FW_major = i.FW_major; + info.FW_minor = i.FW_minor; + info.FW_patch = i.FW_patch; + info.hardware_version = i.hardware_version; + info.HW_Revision = i.HW_Revision; + info.ports = 2; + info.supportsVNAmode = true; + info.supportsSAmode = true; + info.supportsSGmode = true; + info.Limits.minFreq = i.limits_minFreq; + info.Limits.maxFreq = i.limits_maxFreq; + info.Limits.maxFreqHarmonic = i.limits_maxFreqHarmonic; + info.Limits.minIFBW = i.limits_minIFBW; + info.Limits.maxIFBW = i.limits_minIFBW; + info.Limits.maxPoints = i.limits_maxPoints; + info.Limits.mindBm = (double) i.limits_cdbm_min / 100; + info.Limits.maxdBm = (double) i.limits_cdbm_max / 100; + info.Limits.minRBW = i.limits_minRBW; + info.Limits.maxRBW = i.limits_minRBW; + emit InfoUpdated(); + }); + connect(dev, &Device::LogLineReceived, this, &VirtualDevice::LogLineReceived); + connect(dev, &Device::DeviceStatusUpdated, [&](){ + status.statusString = dev->getLastDeviceInfoString(); + status.overload = dev->StatusV1().ADC_overload; + status.unlevel = dev->StatusV1().unlevel; + status.unlocked = !dev->StatusV1().LO1_locked || !dev->StatusV1().source_locked; + emit StatusUpdated(status); + }); + connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate); + + connect(dev, &Device::SpectrumResultReceived, [&](Protocol::SpectrumAnalyzerResult res){ + SAMeasurement m; + m.pointNum = res.pointNum; + if(zerospan) { + m.us = res.us; + } else { + m.frequency = res.frequency; + } + m.measurements["PORT1"] = res.port1; + m.measurements["PORT2"] = res.port2; + emit SAmeasurementReceived(m); + }); + connect(dev, &Device::DatapointReceived, [&](Protocol::Datapoint res){ + VNAMeasurement m; + m.pointNum = res.pointNum; + if(zerospan) { + m.us = res.us; + } else { + m.frequency = res.frequency; + m.dBm = (double) res.cdbm / 100; + } + m.measurements["S11"] = complex(res.real_S11, res.imag_S11); + m.measurements["S21"] = complex(res.real_S21, res.imag_S21); + m.measurements["S12"] = complex(res.real_S12, res.imag_S12); + m.measurements["S22"] = complex(res.real_S22, res.imag_S22); + emit VNAmeasurementReceived(m); + }); + } else { + // TODO + } + connected = this; +} + +VirtualDevice::~VirtualDevice() +{ + connected = nullptr; + for(auto dev : devices) { + delete dev; + } +} + +bool VirtualDevice::isCompoundDevice() const +{ + return isCompound; +} + +Device *VirtualDevice::getDevice() +{ + if(isCompound || devices.size() < 1) { + return nullptr; + } else { + return devices[0]; + } +} + +std::vector VirtualDevice::getDevices() +{ + return devices; +} + +const VirtualDevice::Info &VirtualDevice::getInfo() const +{ + return info; +} + +const VirtualDevice::Info &VirtualDevice::getInfo(VirtualDevice *vdev) +{ + if(vdev) { + return vdev->info; + } else { + return defaultInfo; + } +} + +const VirtualDevice::Status &VirtualDevice::getStatus() const +{ + return status; +} + +const VirtualDevice::Status &VirtualDevice::getStatus(VirtualDevice *vdev) +{ + if(vdev) { + return vdev->status; + } else { + return defaultStatus; + } +} + +QStringList VirtualDevice::availableVNAMeasurements() +{ + QStringList ret; + for(int i=1;i cb) +{ + if(!info.supportsVNAmode) { + return false; + } + zerospan = (s.freqStart == s.freqStop) && (s.dBmStart == s.dBmStop); + auto pref = Preferences::getInstance(); + if(!isCompoundDevice()) { + Protocol::SweepSettings sd; + sd.f_start = s.freqStart; + sd.f_stop = s.freqStop; + sd.points = s.points; + sd.if_bandwidth = s.IFBW; + sd.cdbm_excitation_start = s.dBmStart * 100; + sd.cdbm_excitation_stop = s.dBmStop * 100; + sd.excitePort1 = find(s.excitedPorts.begin(), s.excitedPorts.end(), 1) != s.excitedPorts.end() ? 1 : 0; + sd.excitePort2 = find(s.excitedPorts.begin(), s.excitedPorts.end(), 2) != s.excitedPorts.end() ? 1 : 0; + sd.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0; + sd.fixedPowerSetting = pref.Acquisition.adjustPowerLevel ? 0 : 1; + sd.logSweep = s.logSweep ? 1 : 0; + return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ + if(cb) { + cb(r == Device::TransmissionResult::Ack); + } + }); + } else { + // TODO + return false; +} +} + +QString VirtualDevice::serial() +{ + if(!isCompoundDevice()) { + return devices[0]->serial(); + } else { + // TODO + return ""; + } +} + +QStringList VirtualDevice::availableSAMeasurements() +{ + QStringList ret; + for(int i=1;i cb) +{ + if(!info.supportsSAmode) { + return false; + } + zerospan = s.freqStart == s.freqStop; + auto pref = Preferences::getInstance(); + if(!isCompoundDevice()) { + Protocol::SpectrumAnalyzerSettings sd; + sd.f_start = s.freqStart; + sd.f_stop = s.freqStop; + sd.pointNum = s.points; + sd.RBW = s.RBW; + sd.WindowType = (int) s.window; + sd.SignalID = s.signalID ? 1 : 0; + sd.Detector = (int) s.detector; + sd.UseDFT = 0; + if(!s.trackingGenerator && pref.Acquisition.useDFTinSAmode && s.RBW <= pref.Acquisition.RBWLimitForDFT) { + sd.UseDFT = 1; + } + sd.applyReceiverCorrection = 1; + sd.trackingGenerator = s.trackingGenerator ? 1 : 0; + sd.applySourceCorrection = 1; + sd.trackingGeneratorPort = s.trackingPort; + sd.trackingGeneratorOffset = s.trackingOffset; + sd.trackingPower = s.trackingPower; + return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ + if(cb) { + cb(r == Device::TransmissionResult::Ack); + } + }); + } else { + // TODO + return false; + } +} + +QStringList VirtualDevice::availableSGPorts() +{ + QStringList ret; + for(int i=1;iSendPacket(packet); + } else { + // TODO + return false; + } +} + +bool VirtualDevice::setIdle(std::function cb) +{ + results.clear(); + for(auto dev : devices) { + dev->SetIdle([&](Device::TransmissionResult r){ + if(cb) { + results[dev] = r; + if(results.size() == devices.size()) { + // got all responses + bool success = true; + for(auto res : results) { + if(res.second != Device::TransmissionResult::Ack) { + success = false; + break; + } + } + cb(success); + } + } + }); + } +} + +QStringList VirtualDevice::availableExtRefInSettings() +{ + QStringList ret; + for(auto r : Reference::getReferencesIn()) { + ret.push_back(Reference::TypeToLabel(r)); + } + return ret; +} + +QStringList VirtualDevice::availableExtRefOutSettings() +{ + QStringList ret; + for(auto r : Reference::getOutFrequencies()) { + ret.push_back(Reference::OutFreqToLabel(r)); + } + return ret; +} + +bool VirtualDevice::setExtRef(QString option_in, QString option_out) +{ + if(!info.supportsExtRef) { + return false; + } + auto refIn = Reference::KeyToType(option_in); + if(refIn == Reference::TypeIn::None) { + refIn = Reference::TypeIn::Internal; + } + auto refOut = Reference::KeyToOutFreq(option_out); + if(refOut == Reference::OutFreq::None) { + refOut = Reference::OutFreq::Off; + } + + Protocol::PacketInfo p; + p.type = Protocol::PacketType::Reference; + switch(refIn) { + case Reference::TypeIn::Internal: + p.reference.UseExternalRef = 0; + p.reference.AutomaticSwitch = 0; + break; + case Reference::TypeIn::Auto: + p.reference.UseExternalRef = 0; + p.reference.AutomaticSwitch = 1; + break; + case Reference::TypeIn::External: + p.reference.UseExternalRef = 1; + p.reference.AutomaticSwitch = 0; + break; + } + switch(refOut) { + case Reference::OutFreq::Off: p.reference.ExtRefOuputFreq = 0; break; + case Reference::OutFreq::MHZ10: p.reference.ExtRefOuputFreq = 10000000; break; + case Reference::OutFreq::MHZ100: p.reference.ExtRefOuputFreq = 100000000; break; + } + + bool success = true; + for(auto dev : devices) { + success &= dev->SendPacket(p); + } + return success; +} + +std::set VirtualDevice::GetDevices() +{ + auto ret = Device::GetDevices(); + // TODO check if compound devices are configured and add them if all sub-devices are available + return ret; +} + +VirtualDevice *VirtualDevice::getConnected() +{ + return connected; +} diff --git a/Software/PC_Application/Device/virtualdevice.h b/Software/PC_Application/Device/virtualdevice.h new file mode 100644 index 0000000..638693a --- /dev/null +++ b/Software/PC_Application/Device/virtualdevice.h @@ -0,0 +1,175 @@ +#ifndef VIRTUALDEVICE_H +#define VIRTUALDEVICE_H + +#include "device.h" + +#include +#include + +#include + +class VirtualDevice : public QObject +{ + Q_OBJECT +public: + VirtualDevice(QString serial = ""); + ~VirtualDevice(); + + class Info { + public: + uint16_t ProtocolVersion; + uint8_t FW_major; + uint8_t FW_minor; + uint8_t FW_patch; + uint8_t hardware_version; + char HW_Revision; + int ports; + bool supportsVNAmode; + bool supportsSAmode; + bool supportsSGmode; + bool supportsExtRef; + struct { + double minFreq, maxFreq, maxFreqHarmonic; + double minIFBW, maxIFBW; + int maxPoints; + double mindBm; + double maxdBm; + double minRBW, maxRBW; + } Limits; + }; + + class Status { + public: + QString statusString; + bool overload; + bool unlocked; + bool unlevel; + }; + + bool isCompoundDevice() const; + Device *getDevice(); + std::vector getDevices(); + const Info& getInfo() const; + static const VirtualDevice::Info &getInfo(VirtualDevice *vdev); + const Status &getStatus() const; + static const VirtualDevice::Status &getStatus(VirtualDevice *vdev); + + class VNASettings { + public: + double freqStart, freqStop; + double dBmStart, dBmStop; + double IFBW; + int points; + bool logSweep; + std::vector excitedPorts; + }; + class VNAMeasurement { + public: + int pointNum; + union { + struct { + // for non-zero span + double frequency; + double dBm; + }; + struct { + // for zero span + double us; // time in us since first datapoint + }; + }; + std::map> measurements; + }; + + QStringList availableVNAMeasurements(); + bool setVNA(const VNASettings &s, std::function cb = nullptr); + QString serial(); + + class SASettings { + public: + enum class Window { + None = 0, + Kaiser = 1, + Hann = 2, + FlatTop = 3, + Last + }; + enum class Detector { + PPeak = 0, + NPeak = 1, + Sample = 2, + Normal = 3, + Average = 4, + Last + }; + + double freqStart, freqStop; + double RBW; + int points; + Window window; + Detector detector; + bool signalID; + bool trackingGenerator; + int trackingPort; + double trackingOffset; + double trackingPower; + }; + class SAMeasurement { + public: + int pointNum; + union { + struct { + // for non-zero span + double frequency; + double cdbm; + }; + struct { + // for zero span + double us; // time in us since first datapoint + }; + }; + std::map measurements; + }; + + QStringList availableSAMeasurements(); + bool setSA(const SASettings &s, std::function cb = nullptr); + + class SGSettings { + public: + double freq; + double dBm; + int port; + }; + + QStringList availableSGPorts(); + bool setSG(const SGSettings &s); + + bool setIdle(std::function cb = nullptr); + + QStringList availableExtRefInSettings(); + QStringList availableExtRefOutSettings(); + + bool setExtRef(QString option_in, QString option_out); + + static std::set GetDevices(); + static VirtualDevice* getConnected(); + +signals: + void VNAmeasurementReceived(const VNAMeasurement &m); + void SAmeasurementReceived(const SAMeasurement &m); + void ConnectionLost(); + void InfoUpdated(); + void StatusUpdated(const Status &status); + void LogLineReceived(QString line); + void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol); +private: + Info info; + Status status; + bool isCompound; + std::vector devices; + std::vector portMapping; + bool zerospan; + + std::map results; +}; + +#endif // VIRTUALDEVICE_H diff --git a/Software/PC_Application/Generator/generator.cpp b/Software/PC_Application/Generator/generator.cpp index 6a52878..a2d1127 100644 --- a/Software/PC_Application/Generator/generator.cpp +++ b/Software/PC_Application/Generator/generator.cpp @@ -30,8 +30,8 @@ void Generator::deactivate() // store current settings QSettings s; auto settings = central->getDeviceStatus(); - s.setValue("GeneratorFrequency", static_cast(settings.frequency)); - s.setValue("GeneratorLevel", static_cast((double) settings.cdbm_level / 100.0)); + s.setValue("GeneratorFrequency", static_cast(settings.freq)); + s.setValue("GeneratorLevel", static_cast((double) settings.dBm)); Mode::deactivate(); } @@ -59,10 +59,7 @@ void Generator::updateDevice() // can't update if not connected return; } - Protocol::PacketInfo p; - p.type = Protocol::PacketType::Generator; - p.generator = central->getDeviceStatus(); - window->getDevice()->SendPacket(p); + window->getDevice()->setSG(central->getDeviceStatus()); } void Generator::setupSCPI() @@ -76,7 +73,7 @@ void Generator::setupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(central->getDeviceStatus().frequency); + return QString::number(central->getDeviceStatus().freq); })); add(new SCPICommand("LVL", [=](QStringList params) -> QString { double newval; @@ -88,7 +85,7 @@ void Generator::setupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(central->getDeviceStatus().cdbm_level / 100.0); + return QString::number(central->getDeviceStatus().dBm); })); add(new SCPICommand("PORT", [=](QStringList params) -> QString { unsigned long long newval; @@ -99,6 +96,6 @@ void Generator::setupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(central->getDeviceStatus().activePort); + return QString::number(central->getDeviceStatus().port); })); } diff --git a/Software/PC_Application/Generator/signalgenwidget.cpp b/Software/PC_Application/Generator/signalgenwidget.cpp index 3347804..7cf8d2a 100644 --- a/Software/PC_Application/Generator/signalgenwidget.cpp +++ b/Software/PC_Application/Generator/signalgenwidget.cpp @@ -2,7 +2,7 @@ #include "ui_signalgenwidget.h" -SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) : +SignalgeneratorWidget::SignalgeneratorWidget(VirtualDevice *dev, QWidget *parent) : QWidget(parent), ui(new Ui::SignalgeneratorWidget), dev(dev) @@ -32,16 +32,16 @@ SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) : ui->steps->setPrecision(0); connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) { - if(newval < Device::Info(dev).limits_minFreq) { - newval = Device::Info(dev).limits_minFreq; - } else if (newval > Device::Info(dev).limits_maxFreq) { - newval = Device::Info(dev).limits_maxFreq; + if(newval < VirtualDevice::getInfo(dev).Limits.minFreq) { + newval = VirtualDevice::getInfo(dev).Limits.minFreq; + } else if (newval > VirtualDevice::getInfo(dev).Limits.maxFreq) { + newval = VirtualDevice::getInfo(dev).Limits.maxFreq; } ui->frequency->setValueQuiet(newval); if (newval < ui->span->value()/2) ui->span->setValueQuiet(newval/2); - if (newval + ui->span->value()/2 > Device::Info(dev).limits_maxFreq) - ui->span->setValueQuiet((Device::Info(dev).limits_maxFreq - newval)*2); + if (newval + ui->span->value()/2 > VirtualDevice::getInfo(dev).Limits.maxFreq) + ui->span->setValueQuiet((VirtualDevice::getInfo(dev).Limits.maxFreq - newval)*2); newval = ui->frequency->value() - ui->span->value()/2; ui->current->setValueQuiet(newval); emit SettingsChanged(); @@ -50,8 +50,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) : connect(ui->span, &SIUnitEdit::valueChanged, [=](double newval) { if(newval < 0 ) { newval = 0; - } else if (newval > Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq) { - newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq; + } else if (newval > VirtualDevice::getInfo(dev).Limits.maxFreq - VirtualDevice::getInfo(dev).Limits.minFreq) { + newval = VirtualDevice::getInfo(dev).Limits.maxFreq - VirtualDevice::getInfo(dev).Limits.minFreq; } ui->span->setValueQuiet(newval); @@ -60,8 +60,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) : ui->frequency->setValueQuiet(ui->span->value()/2); } newF = ui->frequency->value() + ui->span->value()/2; - if (newF > Device::Info(dev).limits_maxFreq) { - ui->frequency->setValueQuiet(Device::Info(dev).limits_maxFreq - ui->span->value()/2); + if (newF > VirtualDevice::getInfo(dev).Limits.maxFreq) { + ui->frequency->setValueQuiet(VirtualDevice::getInfo(dev).Limits.maxFreq - ui->span->value()/2); } newval = ui->frequency->value() - ui->span->value()/2; @@ -72,8 +72,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) : connect(ui->current, &SIUnitEdit::valueChanged, [=](double newval) { if(newval < 0 ) { newval = 0; - } else if (newval > Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq) { - newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq; + } else if (newval > VirtualDevice::getInfo(dev).Limits.maxFreq - VirtualDevice::getInfo(dev).Limits.minFreq) { + newval = VirtualDevice::getInfo(dev).Limits.maxFreq - VirtualDevice::getInfo(dev).Limits.minFreq; } ui->current->setValueQuiet(newval); emit SettingsChanged(); @@ -140,22 +140,21 @@ void SignalgeneratorWidget::timerEvent(QTimerEvent *event) } } -Protocol::GeneratorSettings SignalgeneratorWidget::getDeviceStatus() +VirtualDevice::SGSettings SignalgeneratorWidget::getDeviceStatus() { - Protocol::GeneratorSettings s = {}; + VirtualDevice::SGSettings s = {}; if (ui->EnabledSweep->isChecked()) - s.frequency = ui->current->value(); + s.freq = ui->current->value(); else - s.frequency = ui->frequency->value(); - s.cdbm_level = ui->levelSpin->value() * 100.0; + s.freq = ui->frequency->value(); + s.dBm = ui->levelSpin->value(); if(ui->EnablePort1->isChecked()) { - s.activePort = 1; + s.port = 1; } else if(ui->EnablePort2->isChecked()) { - s.activePort = 2; + s.port = 2; } else { - s.activePort = 0; + s.port = 0; } - s.applyAmplitudeCorrection = 1; return s; } diff --git a/Software/PC_Application/Generator/signalgenwidget.h b/Software/PC_Application/Generator/signalgenwidget.h index 6573140..acf63ec 100644 --- a/Software/PC_Application/Generator/signalgenwidget.h +++ b/Software/PC_Application/Generator/signalgenwidget.h @@ -1,7 +1,7 @@ #ifndef SIGNALGENERATOR_H #define SIGNALGENERATOR_H -#include "Device/device.h" +#include "Device/virtualdevice.h".h" #include "savable.h" #include @@ -15,10 +15,10 @@ class SignalgeneratorWidget : public QWidget, public Savable Q_OBJECT public: - explicit SignalgeneratorWidget(Device*&dev, QWidget *parent = nullptr); + explicit SignalgeneratorWidget(VirtualDevice *dev, QWidget *parent = nullptr); ~SignalgeneratorWidget(); - Protocol::GeneratorSettings getDeviceStatus(); + VirtualDevice::SGSettings getDeviceStatus(); virtual nlohmann::json toJSON() override; virtual void fromJSON(nlohmann::json j) override; @@ -36,7 +36,7 @@ protected: private: Ui::SignalgeneratorWidget *ui; int m_timerId; - Device*&dev; + VirtualDevice *dev; }; #endif // SIGNALGENERATOR_H diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index b12ef96..7d2a041 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -22,6 +22,7 @@ HEADERS += \ Device/devicelog.h \ Device/firmwareupdatedialog.h \ Device/manualcontroldialog.h \ + Device/virtualdevice.h \ Generator/generator.h \ Generator/signalgenwidget.h \ SpectrumAnalyzer/spectrumanalyzer.h \ @@ -157,6 +158,7 @@ SOURCES += \ Device/devicelog.cpp \ Device/firmwareupdatedialog.cpp \ Device/manualcontroldialog.cpp \ + Device/virtualdevice.cpp \ Generator/generator.cpp \ Generator/signalgenwidget.cpp \ SpectrumAnalyzer/spectrumanalyzer.cpp \ diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index 12d8d94..923f4b3 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -14,7 +14,7 @@ #include "Tools/impedancematchdialog.h" #include "Calibration/calibrationtracedialog.h" #include "ui_main.h" -#include "Device/firmwareupdatedialog.h" +#include "Device/virtualdevice.h".h" #include "preferences.h" #include "Generator/signalgenwidget.h" @@ -164,7 +164,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name) cbWindowType->addItem("Flat Top"); cbWindowType->setCurrentIndex(1); connect(cbWindowType, qOverload(&QComboBox::currentIndexChanged), [=](int index) { - SetWindow((Window) index); + SetWindow((VirtualDevice::SASettings::Window) index); }); tb_acq->addWidget(cbWindowType); @@ -177,7 +177,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name) cbDetector->addItem("Average"); cbDetector->setCurrentIndex(0); connect(cbDetector, qOverload(&QComboBox::currentIndexChanged), [=](int index) { - SetDetector((Detector) index); + SetDetector((VirtualDevice::SASettings::Detector) index); }); tb_acq->addWidget(cbDetector); @@ -286,14 +286,14 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name) if(pref.Startup.RememberSweepSettings) { LoadSweepSettings(); } else { - settings.f_start = pref.Startup.SA.start; - settings.f_stop = pref.Startup.SA.stop; + settings.freqStart = pref.Startup.SA.start; + settings.freqStop = pref.Startup.SA.stop; ConstrainAndUpdateFrequencies(); SetRBW(pref.Startup.SA.RBW); SetAveraging(pref.Startup.SA.averaging); - settings.pointNum = 1001; - SetWindow((Window) pref.Startup.SA.window); - SetDetector((Detector) pref.Startup.SA.detector); + settings.points = 1001; + SetWindow((VirtualDevice::SASettings::Window) pref.Startup.SA.window); + SetDetector((VirtualDevice::SASettings::Detector) pref.Startup.SA.detector); SetSignalID(pref.Startup.SA.signalID); } @@ -308,7 +308,7 @@ void SpectrumAnalyzer::deactivate() void SpectrumAnalyzer::initializeDevice() { - connect(window->getDevice(), &Device::SpectrumResultReceived, this, &SpectrumAnalyzer::NewDatapoint, Qt::UniqueConnection); + connect(window->getDevice(), &VirtualDevice::SAmeasurementReceived, this, &SpectrumAnalyzer::NewDatapoint, Qt::UniqueConnection); // Configure initial state of device SettingsChanged(); @@ -320,20 +320,20 @@ nlohmann::json SpectrumAnalyzer::toJSON() // save current sweep/acquisition settings nlohmann::json sweep; nlohmann::json freq; - freq["start"] = settings.f_start; - freq["stop"] = settings.f_stop; + freq["start"] = settings.freqStart; + freq["stop"] = settings.freqStop; sweep["frequency"] = freq; sweep["single"] = singleSweep; nlohmann::json acq; acq["RBW"] = settings.RBW; - acq["window"] = WindowToString((Window) settings.WindowType).toStdString(); - acq["detector"] = DetectorToString((Detector) settings.Detector).toStdString(); - acq["signal ID"] = settings.SignalID ? true : false; + acq["window"] = WindowToString((VirtualDevice::SASettings::Window) settings.window).toStdString(); + acq["detector"] = DetectorToString((VirtualDevice::SASettings::Detector) settings.detector).toStdString(); + acq["signal ID"] = settings.signalID ? true : false; sweep["acquisition"] = acq; nlohmann::json tracking; tracking["enabled"] = settings.trackingGenerator ? true : false; - tracking["port"] = settings.trackingGeneratorPort ? 2 : 1; - tracking["offset"] = settings.trackingGeneratorOffset; + tracking["port"] = settings.trackingPort ? 2 : 1; + tracking["offset"] = settings.trackingOffset; tracking["power"] = (double) settings.trackingPower / 100.0; // convert to dBm sweep["trackingGenerator"] = tracking; @@ -343,8 +343,11 @@ nlohmann::json SpectrumAnalyzer::toJSON() norm["stop"] = normalize.f_stop; norm["points"] = normalize.points; norm["level"] = normalize.Level->value(); - norm["port1"] = normalize.port1Correction; - norm["port2"] = normalize.port2Correction; + nlohmann::json jCorr; + for(auto m : normalize.portCorrection) { + jCorr[m.first.toStdString()] = m.second; + } + norm["corrections"] = jCorr; sweep["normalization"] = norm; } j["sweep"] = sweep; @@ -374,25 +377,25 @@ void SpectrumAnalyzer::fromJSON(nlohmann::json j) auto sweep = j["sweep"]; if(sweep.contains("frequency")) { auto freq = sweep["frequency"]; - SetStartFreq(freq.value("start", settings.f_start)); - SetStopFreq(freq.value("stop", settings.f_start)); + SetStartFreq(freq.value("start", settings.freqStart)); + SetStopFreq(freq.value("stop", settings.freqStop)); } if(sweep.contains("acquisition")) { auto acq = sweep["acquisition"]; SetRBW(acq.value("RBW", settings.RBW)); auto w = WindowFromString(QString::fromStdString(acq.value("window", ""))); - if(w == Window::Last) { + if(w == VirtualDevice::SASettings::Window::Last) { // invalid, keep current value - w = (Window) settings.WindowType; + w = (VirtualDevice::SASettings::Window) settings.window; } SetWindow(w); auto d = DetectorFromString(QString::fromStdString(acq.value("detector", ""))); - if(d == Detector::Last) { + if(d == VirtualDevice::SASettings::Detector::Last) { // invalid, keep current value - d = (Detector) settings.Detector; + d = (VirtualDevice::SASettings::Detector) settings.detector; } SetDetector(d); - SetSignalID(acq.value("signal ID", settings.SignalID ? true : false)); + SetSignalID(acq.value("signal ID", settings.signalID ? true : false)); } if(sweep.contains("trackingGenerator")) { auto tracking = sweep["trackingGenerator"]; @@ -401,29 +404,33 @@ void SpectrumAnalyzer::fromJSON(nlohmann::json j) // Function expects 0 for port1, 1 for port2 SetTGPort(port - 1); SetTGLevel(tracking.value("power", settings.trackingPower)); - SetTGOffset(tracking.value("offset", settings.trackingGeneratorOffset)); + SetTGOffset(tracking.value("offset", settings.trackingOffset)); } if(sweep.contains("normalization")) { auto norm = sweep["normalization"]; // restore normalization data - normalize.port1Correction.clear(); - for(double p1 : norm["port1"]) { - normalize.port1Correction.push_back(p1); - } - normalize.port2Correction.clear(); - for(double p2 : norm["port2"]) { - normalize.port2Correction.push_back(p2); + normalize.portCorrection.clear(); + if(norm.contains("corrections")) { + for(auto& el : norm["corrections"].items()) { + normalize.portCorrection[QString::fromStdString(el.key())] = {}; + for(auto p : el.value()) { + normalize.portCorrection[QString::fromStdString(el.key())].push_back(p); + } + } } normalize.f_start = norm.value("start", normalize.f_start); normalize.f_stop = norm.value("stop", normalize.f_stop); normalize.points = norm.value("points", normalize.points); normalize.Level->setValue(norm.value("level", normalize.Level->value())); - if((normalize.port1Correction.size() == normalize.points) && (normalize.port1Correction.size() == normalize.points)) { - // got the correct number of points - EnableNormalization(true); - } else { - EnableNormalization(false); + // check correction vector size + bool correctSize = true; + for(auto c : normalize.portCorrection) { + if(c.second.size() != normalize.points) { + correctSize = false; + break; + } } + EnableNormalization(correctSize); } SetSingleSweep(sweep.value("single", singleSweep)); } @@ -431,7 +438,7 @@ void SpectrumAnalyzer::fromJSON(nlohmann::json j) using namespace std; -void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) +void SpectrumAnalyzer::NewDatapoint(const VirtualDevice::SAMeasurement &m) { if(isActive != true) { return; @@ -445,115 +452,100 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) if(singleSweep && average.getLevel() == averages) { changingSettings = true; // single sweep finished - window->getDevice()->SetIdle([=](Device::TransmissionResult){ + window->getDevice()->setIdle([=](bool){ changingSettings = false; }); } - if(d.pointNum >= settings.pointNum) { - qWarning() << "Ignoring point with too large point number (" << d.pointNum << ")"; + if(m.pointNum >= settings.points) { + qWarning() << "Ignoring point with too large point number (" << m.pointNum << ")"; return; } - d = average.process(d); + auto m_avg = average.process(m); - if(settings.f_start == settings.f_stop) { + if(settings.freqStart == settings.freqStop) { // keep track of first point time - if(d.pointNum == 0) { - firstPointTime = d.us; - d.us = 0; + if(m_avg.pointNum == 0) { + firstPointTime = m_avg.us; + m_avg.us = 0; } else { - d.us -= firstPointTime; + m_avg.us -= firstPointTime; } } if(normalize.measuring) { if(average.currentSweep() == averages) { // this is the last averaging sweep, use values for normalization - if(normalize.port1Correction.size() > 0 || d.pointNum == 0) { + if(normalize.portCorrection[0].size() > 0 || m_avg.pointNum == 0) { // add measurement - normalize.port1Correction.push_back(d.port1); - normalize.port2Correction.push_back(d.port2); - if(d.pointNum == settings.pointNum - 1) { + for(auto m : m_avg.measurements) { + normalize.portCorrection[m.first].push_back(m.second); + } + if(m_avg.pointNum == settings.points - 1) { // this was the last point normalize.measuring = false; - normalize.f_start = settings.f_start; - normalize.f_stop = settings.f_stop; - normalize.points = settings.pointNum; + normalize.f_start = settings.freqStart; + normalize.f_stop = settings.freqStop; + normalize.points = settings.points; EnableNormalization(true); qDebug() << "Normalization measurement complete"; } } } - int percentage = (((average.currentSweep() - 1) * 100) + (d.pointNum + 1) * 100 / settings.pointNum) / averages; + int percentage = (((average.currentSweep() - 1) * 100) + (m_avg.pointNum + 1) * 100 / settings.points) / averages; normalize.dialog.setValue(percentage); } if(normalize.active) { - d.port1 /= normalize.port1Correction[d.pointNum]; - d.port2 /= normalize.port2Correction[d.pointNum]; double corr = pow(10.0, normalize.Level->value() / 20.0); - d.port1 *= corr; - d.port2 *= corr; + for(auto &m : m_avg.measurements) { + m.second /= normalize.portCorrection[m.first][m_avg.pointNum]; + m.second *= corr; + } } - traceModel.addSAData(d, settings); + traceModel.addSAData(m_avg, settings); emit dataChanged(); - if(d.pointNum == settings.pointNum - 1) { + if(m_avg.pointNum == settings.points - 1) { UpdateAverageCount(); markerModel->updateMarkers(); } static unsigned int lastPoint = 0; - if(d.pointNum > 0 && d.pointNum != lastPoint + 1) { - qWarning() << "Got point" << d.pointNum << "but last received point was" << lastPoint << "("<<(d.pointNum-lastPoint-1)<<"missed points)"; + if(m_avg.pointNum > 0 && m_avg.pointNum != lastPoint + 1) { + qWarning() << "Got point" << m_avg.pointNum << "but last received point was" << lastPoint << "("<<(m_avg.pointNum-lastPoint-1)<<"missed points)"; } - lastPoint = d.pointNum; + lastPoint = m_avg.pointNum; } void SpectrumAnalyzer::SettingsChanged() { changingSettings = true; - if(settings.f_stop - settings.f_start >= 1000 || settings.f_stop - settings.f_start <= 0) { - settings.pointNum = 1001; + if(settings.freqStop - settings.freqStart >= 1000 || settings.freqStop - settings.freqStart <= 0) { + settings.points = 1001; } else { - settings.pointNum = settings.f_stop - settings.f_start + 1; - } - settings.applyReceiverCorrection = 1; - settings.applySourceCorrection = 1; - - auto pref = Preferences::getInstance(); - if(settings.f_stop > settings.f_start) { - // non-zerospan, check usability of DFT - if(!settings.trackingGenerator && pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) { - // Enable DFT if below RBW threshold and TG is not enabled - settings.UseDFT = 1; - } else { - settings.UseDFT = 0; - } - } else { - // zerospan, DFT not usable - settings.UseDFT = 0; + settings.points = settings.freqStop - settings.freqStart + 1; } - if(settings.trackingGenerator && settings.f_stop >= 25000000) { + if(settings.trackingGenerator && settings.freqStop >= 25000000) { // Check point spacing. // The highband PLL used as the tracking generator is not able to reach every frequency exactly. This // could lead to sharp drops in the spectrum at certain frequencies. If the span is wide enough with // respect to the point number, it is ensured that every displayed point has at least one sample with // a reachable PLL frequency in it. Display a warning message if this is not the case with the current // settings. - auto pointSpacing = (settings.f_stop - settings.f_start) / (settings.pointNum - 1); + auto pointSpacing = (settings.freqStop - settings.freqStart) / (settings.points - 1); // The frequency resolution of the PLL is frequency dependent (due to PLL divider). // This code assumes some knowledge of the actual hardware and probably should be moved // onto the device at some point double minSpacing = 25000; - auto stop = settings.f_stop; + auto stop = settings.freqStop; while(stop <= 3000000000) { minSpacing /= 2; stop *= 2; } if(pointSpacing < minSpacing) { - auto requiredMinSpan = minSpacing * (settings.pointNum - 1); + auto requiredMinSpan = minSpacing * (settings.points - 1); auto message = QString() + "Due to PLL limitations, the tracking generator can not reach every frequency exactly. " "With your current span, this could result in the signal not being detected at some bands. A minimum" " span of " + Unit::ToString(requiredMinSpan, "Hz", " kMG") + " is recommended at this stop frequency."; @@ -563,7 +555,7 @@ void SpectrumAnalyzer::SettingsChanged() if(normalize.active) { // check if normalization is still valid - if(normalize.f_start != settings.f_start || normalize.f_stop != settings.f_stop || normalize.points != settings.pointNum) { + if(normalize.f_start != settings.freqStart || normalize.f_stop != settings.freqStop || normalize.points != settings.points) { // normalization was taken at different settings, disable EnableNormalization(false); InformationBox::ShowMessage("Information", "Normalization was disabled because the span has been changed"); @@ -571,104 +563,104 @@ void SpectrumAnalyzer::SettingsChanged() } if(window->getDevice() && isActive) { - window->getDevice()->Configure(settings, [=](Device::TransmissionResult res){ + window->getDevice()->setSA(settings, [=](bool){ // device received command changingSettings = false; }); } - average.reset(settings.pointNum); + average.reset(settings.points); UpdateAverageCount(); traceModel.clearLiveData(); - emit traceModel.SpanChanged(settings.f_start, settings.f_stop); + emit traceModel.SpanChanged(settings.freqStart, settings.freqStop); } void SpectrumAnalyzer::SetStartFreq(double freq) { - settings.f_start = freq; - if(settings.f_stop < freq) { - settings.f_stop = freq; + settings.freqStart = freq; + if(settings.freqStop < freq) { + settings.freqStop = freq; } ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SetStopFreq(double freq) { - settings.f_stop = freq; - if(settings.f_start > freq) { - settings.f_start = freq; + settings.freqStop = freq; + if(settings.freqStart > freq) { + settings.freqStart = freq; } ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SetCenterFreq(double freq) { - auto old_span = settings.f_stop - settings.f_start; - if (freq - old_span / 2 <= Device::Info(window->getDevice()).limits_minFreq) { + auto old_span = settings.freqStop - settings.freqStart; + if (freq - old_span / 2 <= VirtualDevice::getInfo(window->getDevice()).Limits.minFreq) { // would shift start frequency below minimum - settings.f_start = 0; - settings.f_stop = 2 * freq; - } else if(freq + old_span / 2 >= Device::Info(window->getDevice()).limits_maxFreq) { + settings.freqStart = 0; + settings.freqStop = 2 * freq; + } else if(freq + old_span / 2 >= VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq) { // would shift stop frequency above maximum - settings.f_start = 2 * freq - Device::Info(window->getDevice()).limits_maxFreq; - settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq; + settings.freqStart = 2 * freq - VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq; + settings.freqStop = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq; } else { - settings.f_start = freq - old_span / 2; - settings.f_stop = freq + old_span / 2; + settings.freqStart = freq - old_span / 2; + settings.freqStop = freq + old_span / 2; } ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SetSpan(double span) { - auto old_center = (settings.f_start + settings.f_stop) / 2; - if(old_center < Device::Info(window->getDevice()).limits_minFreq + span / 2) { + auto old_center = (settings.freqStart + settings.freqStop) / 2; + if(old_center < VirtualDevice::getInfo(window->getDevice()).Limits.minFreq + span / 2) { // would shift start frequency below minimum - settings.f_start = Device::Info(window->getDevice()).limits_minFreq; - settings.f_stop = Device::Info(window->getDevice()).limits_minFreq + span; - } else if(old_center > Device::Info(window->getDevice()).limits_maxFreq - span / 2) { + settings.freqStart = VirtualDevice::getInfo(window->getDevice()).Limits.minFreq; + settings.freqStop = VirtualDevice::getInfo(window->getDevice()).Limits.minFreq + span; + } else if(old_center > VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq - span / 2) { // would shift stop frequency above maximum - settings.f_start = Device::Info(window->getDevice()).limits_maxFreq - span; - settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq; + settings.freqStart = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq - span; + settings.freqStop = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq; } else { - settings.f_start = old_center - span / 2; - settings.f_stop = settings.f_start + span; + settings.freqStart = old_center - span / 2; + settings.freqStop = settings.freqStart + span; } ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SetFullSpan() { - settings.f_start = Device::Info(window->getDevice()).limits_minFreq; - settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq; + settings.freqStart = VirtualDevice::getInfo(window->getDevice()).Limits.minFreq; + settings.freqStop = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq; ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SetZeroSpan() { - auto center = (settings.f_start + settings.f_stop) / 2; + auto center = (settings.freqStart + settings.freqStop) / 2; SetStartFreq(center); SetStopFreq(center); } void SpectrumAnalyzer::SpanZoomIn() { - auto center = (settings.f_start + settings.f_stop) / 2; - auto old_span = settings.f_stop - settings.f_start; - settings.f_start = center - old_span / 4; - settings.f_stop = center + old_span / 4; + auto center = (settings.freqStart + settings.freqStop) / 2; + auto old_span = settings.freqStop - settings.freqStart; + settings.freqStart = center - old_span / 4; + settings.freqStop = center + old_span / 4; ConstrainAndUpdateFrequencies(); } void SpectrumAnalyzer::SpanZoomOut() { - auto center = (settings.f_start + settings.f_stop) / 2; - auto old_span = settings.f_stop - settings.f_start; + auto center = (settings.freqStart + settings.freqStop) / 2; + auto old_span = settings.freqStop - settings.freqStart; if(center > old_span) { - settings.f_start = center - old_span; + settings.freqStart = center - old_span; } else { - settings.f_start = 0; + settings.freqStart = 0; } - settings.f_stop = center + old_span; + settings.freqStop = center + old_span; ConstrainAndUpdateFrequencies(); } @@ -683,26 +675,26 @@ void SpectrumAnalyzer::SetSingleSweep(bool single) void SpectrumAnalyzer::SetRBW(double bandwidth) { - if(bandwidth > Device::Info(window->getDevice()).limits_maxRBW) { - bandwidth = Device::Info(window->getDevice()).limits_maxRBW; - } else if(bandwidth < Device::Info(window->getDevice()).limits_minRBW) { - bandwidth = Device::Info(window->getDevice()).limits_minRBW; + if(bandwidth > VirtualDevice::getInfo(window->getDevice()).Limits.maxRBW) { + bandwidth = VirtualDevice::getInfo(window->getDevice()).Limits.maxRBW; + } else if(bandwidth < VirtualDevice::getInfo(window->getDevice()).Limits.minRBW) { + bandwidth = VirtualDevice::getInfo(window->getDevice()).Limits.minRBW; } settings.RBW = bandwidth; emit RBWChanged(settings.RBW); SettingsChanged(); } -void SpectrumAnalyzer::SetWindow(SpectrumAnalyzer::Window w) +void SpectrumAnalyzer::SetWindow(VirtualDevice::SASettings::Window w) { - settings.WindowType = (int) w; + settings.window = w; cbWindowType->setCurrentIndex((int) w); SettingsChanged(); } -void SpectrumAnalyzer::SetDetector(SpectrumAnalyzer::Detector d) +void SpectrumAnalyzer::SetDetector(VirtualDevice::SASettings::Detector d) { - settings.Detector = (int) d; + settings.detector = d; cbDetector->setCurrentIndex((int) d); SettingsChanged(); } @@ -717,7 +709,7 @@ void SpectrumAnalyzer::SetAveraging(unsigned int averages) void SpectrumAnalyzer::SetSignalID(bool enabled) { - settings.SignalID = enabled ? 1 : 0; + settings.signalID = enabled ? 1 : 0; cbSignalID->setChecked(enabled); SettingsChanged(); } @@ -743,8 +735,8 @@ void SpectrumAnalyzer::SetTGPort(int port) if(port < 0 || port > 1) { return; } - if(port != settings.trackingGeneratorPort) { - settings.trackingGeneratorPort = port; + if(port != settings.trackingPort) { + settings.trackingPort = port; emit TGPortChanged(port); if(settings.trackingGenerator) { SettingsChanged(); @@ -754,10 +746,10 @@ void SpectrumAnalyzer::SetTGPort(int port) void SpectrumAnalyzer::SetTGLevel(double level) { - if(level > Device::Info(window->getDevice()).limits_cdbm_max / 100.0) { - level = Device::Info(window->getDevice()).limits_cdbm_max / 100.0; - } else if(level < Device::Info(window->getDevice()).limits_cdbm_min / 100.0) { - level = Device::Info(window->getDevice()).limits_cdbm_min / 100.0; + if(level > VirtualDevice::getInfo(window->getDevice()).Limits.maxdBm / 100.0) { + level = VirtualDevice::getInfo(window->getDevice()).Limits.maxdBm / 100.0; + } else if(level < VirtualDevice::getInfo(window->getDevice()).Limits.mindBm / 100.0) { + level = VirtualDevice::getInfo(window->getDevice()).Limits.mindBm / 100.0; } emit TGLevelChanged(level); settings.trackingPower = level * 100; @@ -768,7 +760,7 @@ void SpectrumAnalyzer::SetTGLevel(double level) void SpectrumAnalyzer::SetTGOffset(double offset) { - settings.trackingGeneratorOffset = offset; + settings.trackingOffset = offset; ConstrainAndUpdateFrequencies(); if(settings.trackingGenerator) { @@ -778,9 +770,14 @@ void SpectrumAnalyzer::SetTGOffset(double offset) void SpectrumAnalyzer::MeasureNormalization() { + if(!window->getDevice()) { + return; + } normalize.active = false; - normalize.port1Correction.clear(); - normalize.port2Correction.clear(); + normalize.portCorrection.clear(); + for(auto m : window->getDevice()->availableSAMeasurements()) { + normalize.portCorrection[m] = {}; + } normalize.measuring = true; normalize.dialog.setLabelText("Taking normalization measurement..."); normalize.dialog.setCancelButtonText("Abort"); @@ -807,7 +804,7 @@ void SpectrumAnalyzer::EnableNormalization(bool enabled) if(enabled != normalize.active) { if(enabled) { // check if measurements already taken - if(normalize.f_start == settings.f_start && normalize.f_stop == settings.f_stop && normalize.points == settings.pointNum) { + if(normalize.f_start == settings.freqStart && normalize.f_stop == settings.freqStop && normalize.points == settings.points) { // same settings as with normalization measurement, can enable normalize.active = true; } else { @@ -843,7 +840,7 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(settings.f_stop - settings.f_start, 'f', 0); + return QString::number(settings.freqStop - settings.freqStart, 'f', 0); })); scpi_freq->add(new SCPICommand("START", [=](QStringList params) -> QString { unsigned long long newval; @@ -854,7 +851,7 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(settings.f_start, 'f', 0); + return QString::number(settings.freqStart, 'f', 0); })); scpi_freq->add(new SCPICommand("CENTer", [=](QStringList params) -> QString { unsigned long long newval; @@ -865,7 +862,7 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number((settings.f_start + settings.f_stop)/2, 'f', 0); + return QString::number((settings.freqStart + settings.freqStop)/2, 'f', 0); })); scpi_freq->add(new SCPICommand("STOP", [=](QStringList params) -> QString { unsigned long long newval; @@ -876,7 +873,7 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(settings.f_stop, 'f', 0); + return QString::number(settings.freqStop, 'f', 0); })); scpi_freq->add(new SCPICommand("FULL", [=](QStringList params) -> QString { Q_UNUSED(params) @@ -906,23 +903,23 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Error); } if (params[0] == "NONE") { - SetWindow(Window::None); + SetWindow(VirtualDevice::SASettings::Window::None); } else if(params[0] == "KAISER") { - SetWindow(Window::Kaiser); + SetWindow(VirtualDevice::SASettings::Window::Kaiser); } else if(params[0] == "HANN") { - SetWindow(Window::Hann); + SetWindow(VirtualDevice::SASettings::Window::Hann); } else if(params[0] == "FLATTOP") { - SetWindow(Window::FlatTop); + SetWindow(VirtualDevice::SASettings::Window::FlatTop); } else { return "INVALID WINDOW"; } return SCPI::getResultName(SCPI::Result::Empty); }, [=](QStringList) -> QString { - switch((Window) settings.WindowType) { - case Window::None: return "NONE"; - case Window::Kaiser: return "KAISER"; - case Window::Hann: return "HANN"; - case Window::FlatTop: return "FLATTOP"; + switch((VirtualDevice::SASettings::Window) settings.window) { + case VirtualDevice::SASettings::Window::None: return "NONE"; + case VirtualDevice::SASettings::Window::Kaiser: return "KAISER"; + case VirtualDevice::SASettings::Window::Hann: return "HANN"; + case VirtualDevice::SASettings::Window::FlatTop: return "FLATTOP"; default: return SCPI::getResultName(SCPI::Result::Error); } })); @@ -931,26 +928,26 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Error); } if (params[0] == "+PEAK") { - SetDetector(Detector::PPeak); + SetDetector(VirtualDevice::SASettings::Detector::PPeak); } else if(params[0] == "-PEAK") { - SetDetector(Detector::NPeak); + SetDetector(VirtualDevice::SASettings::Detector::NPeak); } else if(params[0] == "NORMAL") { - SetDetector(Detector::Normal); + SetDetector(VirtualDevice::SASettings::Detector::Normal); } else if(params[0] == "SAMPLE") { - SetDetector(Detector::Sample); + SetDetector(VirtualDevice::SASettings::Detector::Sample); } else if(params[0] == "AVERAGE") { - SetDetector(Detector::Average); + SetDetector(VirtualDevice::SASettings::Detector::Average); } else { return "INVALID MDOE"; } return SCPI::getResultName(SCPI::Result::Empty); }, [=](QStringList) -> QString { - switch((Detector) settings.Detector) { - case Detector::PPeak: return "+PEAK"; - case Detector::NPeak: return "-PEAK"; - case Detector::Normal: return "NORMAL"; - case Detector::Sample: return "SAMPLE"; - case Detector::Average: return "AVERAGE"; + switch((VirtualDevice::SASettings::Detector) settings.detector) { + case VirtualDevice::SASettings::Detector::PPeak: return "+PEAK"; + case VirtualDevice::SASettings::Detector::NPeak: return "-PEAK"; + case VirtualDevice::SASettings::Detector::Normal: return "NORMAL"; + case VirtualDevice::SASettings::Detector::Sample: return "SAMPLE"; + case VirtualDevice::SASettings::Detector::Average: return "AVERAGE"; default: return SCPI::getResultName(SCPI::Result::Error); } })); @@ -987,7 +984,7 @@ void SpectrumAnalyzer::SetupSCPI() } return SCPI::getResultName(SCPI::Result::Empty); }, [=](QStringList) -> QString { - return settings.SignalID ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False); + return settings.signalID ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False); })); scpi_acq->add(new SCPICommand("SINGLE", [=](QStringList params) -> QString { bool single; @@ -1030,7 +1027,7 @@ void SpectrumAnalyzer::SetupSCPI() } return SCPI::getResultName(SCPI::Result::Empty); }, [=](QStringList) -> QString { - return settings.trackingGeneratorPort ? "2" : "1"; + return QString::number(settings.trackingPort); })); scpi_tg->add(new SCPICommand("LVL", [=](QStringList params) -> QString { double newval; @@ -1053,7 +1050,7 @@ void SpectrumAnalyzer::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - return QString::number(settings.trackingGeneratorOffset); + return QString::number(settings.trackingOffset); })); auto scpi_norm = new SCPINode("NORMalize"); scpi_tg->add(scpi_norm); @@ -1098,34 +1095,34 @@ void SpectrumAnalyzer::UpdateAverageCount() void SpectrumAnalyzer::ConstrainAndUpdateFrequencies() { - if(settings.f_stop > Device::Info(window->getDevice()).limits_maxFreq) { - settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq; + if(settings.freqStop > VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq) { + settings.freqStop = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq; } - if(settings.f_start > settings.f_stop) { - settings.f_start = settings.f_stop; + if(settings.freqStart > settings.freqStop) { + settings.freqStart = settings.freqStop; } - if(settings.f_start < Device::Info(window->getDevice()).limits_minFreq) { - settings.f_start = Device::Info(window->getDevice()).limits_minFreq; + if(settings.freqStart < VirtualDevice::getInfo(window->getDevice()).Limits.minFreq) { + settings.freqStart = VirtualDevice::getInfo(window->getDevice()).Limits.minFreq; } bool trackingOffset_limited = false; - if(settings.f_stop + settings.trackingGeneratorOffset > Device::Info(window->getDevice()).limits_maxFreq) { + if(settings.freqStop + settings.trackingOffset > VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq) { trackingOffset_limited = true; - settings.trackingGeneratorOffset = Device::Info(window->getDevice()).limits_maxFreq - settings.f_stop; + settings.trackingOffset = VirtualDevice::getInfo(window->getDevice()).Limits.maxFreq - settings.freqStop; } - if(settings.f_start + settings.trackingGeneratorOffset < Device::Info(window->getDevice()).limits_minFreq) { + if(settings.freqStart + settings.trackingOffset < VirtualDevice::getInfo(window->getDevice()).Limits.minFreq) { trackingOffset_limited = true; - settings.trackingGeneratorOffset = Device::Info(window->getDevice()).limits_minFreq - settings.f_start; + settings.trackingOffset = VirtualDevice::getInfo(window->getDevice()).Limits.minFreq - settings.freqStart; } if(trackingOffset_limited) { InformationBox::ShowMessage("Warning", "The selected tracking generator offset is not reachable for all frequencies with the current span. " "The tracking generator offset has been constrained according to the selected start and stop frequencies"); } - emit startFreqChanged(settings.f_start); - emit stopFreqChanged(settings.f_stop); - emit spanChanged(settings.f_stop - settings.f_start); - emit centerFreqChanged((settings.f_stop + settings.f_start)/2); - emit TGOffsetChanged(settings.trackingGeneratorOffset); + emit startFreqChanged(settings.freqStart); + emit stopFreqChanged(settings.freqStop); + emit spanChanged(settings.freqStop - settings.freqStart); + emit centerFreqChanged((settings.freqStop + settings.freqStart)/2); + emit TGOffsetChanged(settings.trackingOffset); SettingsChanged(); } @@ -1133,13 +1130,13 @@ void SpectrumAnalyzer::LoadSweepSettings() { QSettings s; auto pref = Preferences::getInstance(); - settings.f_start = s.value("SAStart", pref.Startup.SA.start).toULongLong(); - settings.f_stop = s.value("SAStop", pref.Startup.SA.stop).toULongLong(); + settings.freqStart = s.value("SAStart", pref.Startup.SA.start).toULongLong(); + settings.freqStop = s.value("SAStop", pref.Startup.SA.stop).toULongLong(); ConstrainAndUpdateFrequencies(); SetRBW(s.value("SARBW", pref.Startup.SA.RBW).toUInt()); - settings.pointNum = 1001; - SetWindow((Window) s.value("SAWindow", pref.Startup.SA.window).toInt()); - SetDetector((Detector) s.value("SADetector", pref.Startup.SA.detector).toInt()); + settings.points = 1001; + SetWindow((VirtualDevice::SASettings::Window) s.value("SAWindow", pref.Startup.SA.window).toInt()); + SetDetector((VirtualDevice::SASettings::Detector) s.value("SADetector", pref.Startup.SA.detector).toInt()); SetSignalID(s.value("SASignalID", pref.Startup.SA.signalID).toBool()); SetAveraging(s.value("SAAveraging", pref.Startup.SA.averaging).toInt()); } @@ -1147,13 +1144,13 @@ void SpectrumAnalyzer::LoadSweepSettings() void SpectrumAnalyzer::StoreSweepSettings() { QSettings s; - s.setValue("SAStart", static_cast(settings.f_start)); - s.setValue("SAStop", static_cast(settings.f_stop)); + s.setValue("SAStart", static_cast(settings.freqStart)); + s.setValue("SAStop", static_cast(settings.freqStop)); s.setValue("SARBW", settings.RBW); - s.setValue("SAWindow", settings.WindowType); - s.setValue("SADetector", settings.Detector); + s.setValue("SAWindow", (int) settings.window); + s.setValue("SADetector", (int) settings.detector); s.setValue("SAAveraging", averages); - s.setValue("SASignalID", static_cast(settings.SignalID)); + s.setValue("SASignalID", static_cast(settings.signalID)); } void SpectrumAnalyzer::setAveragingMode(Averaging::Mode mode) @@ -1161,47 +1158,47 @@ void SpectrumAnalyzer::setAveragingMode(Averaging::Mode mode) average.setMode(mode); } -QString SpectrumAnalyzer::WindowToString(SpectrumAnalyzer::Window w) +QString SpectrumAnalyzer::WindowToString(VirtualDevice::SASettings::Window w) { switch(w) { - case Window::None: return "None"; - case Window::Kaiser: return "Kaiser"; - case Window::Hann: return "Hann"; - case Window::FlatTop: return "FlatTop"; + case VirtualDevice::SASettings::Window::None: return "None"; + case VirtualDevice::SASettings::Window::Kaiser: return "Kaiser"; + case VirtualDevice::SASettings::Window::Hann: return "Hann"; + case VirtualDevice::SASettings::Window::FlatTop: return "FlatTop"; default: return "Unknown"; } } -SpectrumAnalyzer::Window SpectrumAnalyzer::WindowFromString(QString s) +VirtualDevice::SASettings::Window SpectrumAnalyzer::WindowFromString(QString s) { - for(int i=0;i<(int)Window::Last;i++) { - if(WindowToString((Window) i) == s) { - return (Window) i; + for(int i=0;i<(int)VirtualDevice::SASettings::Window::Last;i++) { + if(WindowToString((VirtualDevice::SASettings::Window) i) == s) { + return (VirtualDevice::SASettings::Window) i; } } // not found - return Window::Last; + return VirtualDevice::SASettings::Window::Last; } -QString SpectrumAnalyzer::DetectorToString(SpectrumAnalyzer::Detector d) +QString SpectrumAnalyzer::DetectorToString(VirtualDevice::SASettings::Detector d) { switch(d) { - case Detector::PPeak: return "+Peak"; - case Detector::NPeak: return "-Peak"; - case Detector::Sample: return "Sample"; - case Detector::Normal: return "Normal"; - case Detector::Average: return "Average"; + case VirtualDevice::SASettings::Detector::PPeak: return "+Peak"; + case VirtualDevice::SASettings::Detector::NPeak: return "-Peak"; + case VirtualDevice::SASettings::Detector::Sample: return "Sample"; + case VirtualDevice::SASettings::Detector::Normal: return "Normal"; + case VirtualDevice::SASettings::Detector::Average: return "Average"; default: return "Unknown"; } } -SpectrumAnalyzer::Detector SpectrumAnalyzer::DetectorFromString(QString s) +VirtualDevice::SASettings::Detector SpectrumAnalyzer::DetectorFromString(QString s) { - for(int i=0;i<(int)Detector::Last;i++) { - if(DetectorToString((Detector) i) == s) { - return (Detector) i; + for(int i=0;i<(int)VirtualDevice::SASettings::Detector::Last;i++) { + if(DetectorToString((VirtualDevice::SASettings::Detector) i) == s) { + return (VirtualDevice::SASettings::Detector) i; } } // not found - return Detector::Last; + return VirtualDevice::SASettings::Detector::Last; } diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h index fcec0da..7963222 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.h @@ -6,6 +6,7 @@ #include "CustomWidgets/tilewidget.h" #include "scpi.h" #include "Traces/tracewidget.h" +#include "Device/virtualdevice.h" #include #include @@ -32,29 +33,13 @@ public: private: - enum class Window { - None = 0, - Kaiser = 1, - Hann = 2, - FlatTop = 3, - Last - }; - enum class Detector { - PPeak = 0, - NPeak = 1, - Sample = 2, - Normal = 3, - Average = 4, - Last - }; - - static QString WindowToString(Window w); - static Window WindowFromString(QString s); - static QString DetectorToString(Detector d); - static Detector DetectorFromString(QString s); + static QString WindowToString(VirtualDevice::SASettings::Window w); + static VirtualDevice::SASettings::Window WindowFromString(QString s); + static QString DetectorToString(VirtualDevice::SASettings::Detector d); + static VirtualDevice::SASettings::Detector DetectorFromString(QString s); private slots: - void NewDatapoint(Protocol::SpectrumAnalyzerResult d); + void NewDatapoint(const VirtualDevice::SAMeasurement &m); // Sweep control void SetStartFreq(double freq); void SetStopFreq(double freq); @@ -67,8 +52,8 @@ private slots: void SetSingleSweep(bool single); // Acquisition control void SetRBW(double bandwidth); - void SetWindow(Window w); - void SetDetector(Detector d); + void SetWindow(VirtualDevice::SASettings::Window w); + void SetDetector(VirtualDevice::SASettings::Detector d); void SetAveraging(unsigned int averages); void SetSignalID(bool enabled); // TG control @@ -89,7 +74,7 @@ private: void LoadSweepSettings(); void StoreSweepSettings(); - Protocol::SpectrumAnalyzerSettings settings; + VirtualDevice::SASettings settings; bool changingSettings; unsigned int averages; bool singleSweep; @@ -110,8 +95,7 @@ private: // settings when normalize was measured double f_start, f_stop, points; // correction values to get the ports to 0dBm - std::vector port1Correction; - std::vector port2Correction; + std::map> portCorrection; // level to normalize to (additional correction factor) SIUnitEdit *Level; diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp index ced60da..ba94dc4 100644 --- a/Software/PC_Application/appwindow.cpp +++ b/Software/PC_Application/appwindow.cpp @@ -68,99 +68,6 @@ static const QString APP_GIT_HASH = QString(GITHASH); static bool noGUIset = false; - -class Reference -{ -public: - - enum class TypeIn { - Internal, - External, - Auto, - None - }; - - enum class OutFreq { - MHZ10, - MHZ100, - Off, - None - }; - - static QString OutFreqToLabel(Reference::OutFreq t) - { - switch(t) { - case OutFreq::MHZ10: return "10 MHz"; - case OutFreq::MHZ100: return "100 MHz"; - case OutFreq::Off: return "Off"; - default: return "Invalid"; - } - } - - static QString OutFreqToKey(Reference::OutFreq f) - { - switch(f) { - case OutFreq::MHZ10: return "10 MHz"; - case OutFreq::MHZ100: return "100 MHz"; - case OutFreq::Off: return "Off"; - default: return "Invalid"; - } - } - - static Reference::OutFreq KeyToOutFreq(QString key) - { - for (auto r: Reference::getOutFrequencies()) { - if(OutFreqToKey((Reference::OutFreq) r) == key) { - return (Reference::OutFreq) r; - } - } - // not found - return Reference::OutFreq::None; - } - - - static QString TypeToLabel(TypeIn t) - { - switch(t) { - case TypeIn::Internal: return "Internal"; - case TypeIn::External: return "External"; - case TypeIn::Auto: return "Auto"; - default: return "Invalid"; - } - } - - static const QString TypeToKey(TypeIn t) - { - switch(t) { - case TypeIn::Internal: return "Int"; - case TypeIn::External: return "Ext"; - case TypeIn::Auto: return "Auto"; - default: return "Invalid"; - } - } - - static TypeIn KeyToType(QString key) - { - for (auto r: Reference::getReferencesIn()) { - if(TypeToKey((TypeIn) r) == key) { - return (TypeIn) r; - } - } - // not found - return TypeIn::None; - } - - static std::vector getReferencesIn() - { - return {TypeIn::Internal, TypeIn::External, TypeIn::Auto}; - } - - static std::vector getOutFrequencies() - { - return {OutFreq::Off, OutFreq::MHZ10, OutFreq::MHZ100}; - } -}; - AppWindow::AppWindow(QWidget *parent) : QMainWindow(parent) , deviceActionGroup(new QActionGroup(this)) @@ -193,7 +100,7 @@ AppWindow::AppWindow(QWidget *parent) } else { Preferences::getInstance().load(); } - device = nullptr; + vdevice = nullptr; modeHandler = nullptr; if(parser.isSet("port")) { @@ -370,7 +277,7 @@ void AppWindow::SetupMenu() { active->updateGraphColors(); - if(device) { + if(vdevice) { active->initializeDevice(); } } @@ -396,7 +303,7 @@ void AppWindow::closeEvent(QCloseEvent *event) if(modeHandler->getActiveMode()) { modeHandler->deactivate(modeHandler->getActiveMode()); } - delete device; + delete vdevice; delete modeHandler; modeHandler = nullptr; pref.store(); @@ -410,33 +317,36 @@ bool AppWindow::ConnectToDevice(QString serial) } else { qDebug() << "Trying to connect to" << serial; } - if(device) { + if(vdevice) { qDebug() << "Already connected to a device, disconnecting first..."; DisconnectDevice(); } try { qDebug() << "Attempting to connect to device..."; - device = new Device(serial); + vdevice = new VirtualDevice(serial); UpdateStatusBar(AppWindow::DeviceStatusBar::Connected); - connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine); - connect(device, &Device::ConnectionLost, this, &AppWindow::DeviceConnectionLost); - connect(device, &Device::DeviceStatusUpdated, this, &AppWindow::DeviceStatusUpdated); - connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate); + connect(vdevice, &VirtualDevice::LogLineReceived, &deviceLog, &DeviceLog::addLine); + connect(vdevice, &VirtualDevice::ConnectionLost, this, &AppWindow::DeviceConnectionLost); + connect(vdevice, &VirtualDevice::StatusUpdated, this, &AppWindow::DeviceStatusUpdated); + connect(vdevice, &VirtualDevice::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate); ui->actionDisconnect->setEnabled(true); - ui->actionManual_Control->setEnabled(true); - ui->actionFirmware_Update->setEnabled(true); - ui->actionSource_Calibration->setEnabled(true); - ui->actionReceiver_Calibration->setEnabled(true); - ui->actionFrequency_Calibration->setEnabled(true); + if(!vdevice->isCompoundDevice()) { + ui->actionManual_Control->setEnabled(true); + ui->actionFirmware_Update->setEnabled(true); + ui->actionSource_Calibration->setEnabled(true); + ui->actionReceiver_Calibration->setEnabled(true); + ui->actionFrequency_Calibration->setEnabled(true); + } UpdateAcquisitionFrequencies(); if (modeHandler->getActiveMode()) { modeHandler->getActiveMode()->initializeDevice(); } + UpdateReferenceToolbar(); UpdateReference(); for(auto d : deviceActionGroup->actions()) { - if(d->text() == device->serial()) { + if(d->text() == vdevice->serial()) { d->blockSignals(true); d->setChecked(true); d->blockSignals(false); @@ -454,8 +364,8 @@ bool AppWindow::ConnectToDevice(QString serial) void AppWindow::DisconnectDevice() { - delete device; - device = nullptr; + delete vdevice; + vdevice = nullptr; ui->actionDisconnect->setEnabled(false); ui->actionManual_Control->setEnabled(false); ui->actionFirmware_Update->setEnabled(false); @@ -488,17 +398,10 @@ void AppWindow::CreateToolbars() auto tb_reference = new QToolBar("Reference", this); tb_reference->addWidget(new QLabel("Ref in:")); toolbars.reference.type = new QComboBox(); - for (auto r: Reference::getReferencesIn()) { - toolbars.reference.type->addItem(Reference::TypeToLabel(r), (int)r); - } tb_reference->addWidget(toolbars.reference.type); tb_reference->addSeparator(); tb_reference->addWidget(new QLabel("Ref out:")); toolbars.reference.outFreq = new QComboBox(); - for (auto f: Reference::getOutFrequencies()) { - - toolbars.reference.outFreq->addItem(Reference::OutFreqToLabel(f), (int)f); - } 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); @@ -529,8 +432,8 @@ void AppWindow::SetupSCPI() return SCPI::getResultName(SCPI::Result::Empty); } }, [=](QStringList) -> QString { - if(device) { - return device->serial(); + if(vdevice) { + return vdevice->serial(); } else { return "Not connected"; } @@ -629,57 +532,64 @@ void AppWindow::SetupSCPI() auto scpi_status = new SCPINode("STAtus"); scpi_dev->add(scpi_status); scpi_status->add(new SCPICommand("UNLOcked", nullptr, [=](QStringList){ - bool locked = Device::StatusV1(getDevice()).source_locked && Device::StatusV1(getDevice()).LO1_locked; - return locked ? "FALSE" : "TRUE"; + return VirtualDevice::getStatus(getDevice()).unlocked ? "TRUE" : "FALSE"; })); scpi_status->add(new SCPICommand("ADCOVERload", nullptr, [=](QStringList){ - return Device::StatusV1(getDevice()).ADC_overload ? "TRUE" : "FALSE"; + return VirtualDevice::getStatus(getDevice()).overload ? "TRUE" : "FALSE"; })); scpi_status->add(new SCPICommand("UNLEVel", nullptr, [=](QStringList){ - return Device::StatusV1(getDevice()).unlevel ? "TRUE" : "FALSE"; + return VirtualDevice::getStatus(getDevice()).unlevel ? "TRUE" : "FALSE"; })); auto scpi_info = new SCPINode("INFo"); scpi_dev->add(scpi_info); scpi_info->add(new SCPICommand("FWREVision", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).FW_major)+"."+QString::number(Device::Info(getDevice()).FW_minor)+"."+QString::number(Device::Info(getDevice()).FW_patch); + return QString::number(VirtualDevice::getInfo(getDevice()).FW_major)+"."+QString::number(VirtualDevice::getInfo(getDevice()).FW_minor)+"."+QString::number(VirtualDevice::getInfo(getDevice()).FW_patch); })); scpi_info->add(new SCPICommand("HWREVision", nullptr, [=](QStringList){ - return QString(Device::Info(getDevice()).HW_Revision); + return QString(VirtualDevice::getInfo(getDevice()).HW_Revision); })); scpi_info->add(new SCPICommand("TEMPeratures", nullptr, [=](QStringList){ - return QString::number(Device::StatusV1(getDevice()).temp_source)+"/"+QString::number(Device::StatusV1(getDevice()).temp_LO1)+"/"+QString::number(Device::StatusV1(getDevice()).temp_MCU); + if(!vdevice) { + return QString("0/0/0"); + } else if(vdevice->isCompoundDevice()) { + // TODO + return QString(); + } else { + auto dev = vdevice->getDevice(); + return QString::number(dev->StatusV1().temp_source)+"/"+QString::number(dev->StatusV1().temp_LO1)+"/"+QString::number(dev->StatusV1().temp_MCU); + } })); auto scpi_limits = new SCPINode("LIMits"); scpi_info->add(scpi_limits); scpi_limits->add(new SCPICommand("MINFrequency", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_minFreq); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.minFreq); })); scpi_limits->add(new SCPICommand("MAXFrequency", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_maxFreq); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxFreq); })); scpi_limits->add(new SCPICommand("MINIFBW", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_minIFBW); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.minIFBW); })); scpi_limits->add(new SCPICommand("MAXIFBW", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_maxIFBW); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxIFBW); })); scpi_limits->add(new SCPICommand("MAXPoints", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_maxPoints); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxPoints); })); scpi_limits->add(new SCPICommand("MINPOWer", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_cdbm_min / 100.0); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.mindBm); })); scpi_limits->add(new SCPICommand("MAXPOWer", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_cdbm_max / 100.0); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxdBm); })); scpi_limits->add(new SCPICommand("MINRBW", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_minRBW); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.minRBW); })); scpi_limits->add(new SCPICommand("MAXRBW", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_maxRBW); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxRBW); })); scpi_limits->add(new SCPICommand("MAXHARMonicfrequency", nullptr, [=](QStringList){ - return QString::number(Device::Info(getDevice()).limits_maxFreqHarmonic); + return QString::number(VirtualDevice::getInfo(getDevice()).Limits.maxFreqHarmonic); })); auto scpi_manual = new SCPINode("MANual"); @@ -938,8 +848,8 @@ int AppWindow::UpdateDeviceList() deviceActionGroup->setExclusive(true); ui->menuConnect_to->clear(); auto devices = Device::GetDevices(); - if(device) { - devices.insert(device->serial()); + if(vdevice) { + devices.insert(vdevice->serial()); } int available = 0; bool found = false; @@ -952,7 +862,7 @@ int AppWindow::UpdateDeviceList() auto connectAction = ui->menuConnect_to->addAction(d); connectAction->setCheckable(true); connectAction->setActionGroup(deviceActionGroup); - if(device && d == device->serial()) { + if(vdevice && d == vdevice->serial()) { connectAction->setChecked(true); } connect(connectAction, &QAction::triggered, [this, d]() { @@ -969,14 +879,17 @@ int AppWindow::UpdateDeviceList() void AppWindow::StartManualControl() { + if(!vdevice || vdevice->isCompoundDevice()) { + return; + } if(manual) { // dialog already active, nothing to do return; } - manual = new ManualControlDialog(*device, this); + manual = new ManualControlDialog(*vdevice->getDevice(), this); connect(manual, &QDialog::finished, [=](){ manual = nullptr; - if(device) { + if(vdevice) { modeHandler->getActiveMode()->initializeDevice(); } }); @@ -985,37 +898,48 @@ void AppWindow::StartManualControl() } } +void AppWindow::UpdateReferenceToolbar() +{ + if(!vdevice || !vdevice->getInfo().supportsExtRef) { + toolbars.reference.type->setEnabled(false); + toolbars.reference.outFreq->setEnabled(false); + } + // save current setting + auto refInBuf = toolbars.reference.type->currentText(); + auto refOutBuf = toolbars.reference.outFreq->currentText(); + toolbars.reference.type->clear(); + for(auto in : vdevice->availableExtRefInSettings()) { + toolbars.reference.type->addItem(in); + } + toolbars.reference.outFreq->clear(); + for(auto out : vdevice->availableExtRefOutSettings()) { + toolbars.reference.outFreq->addItem(in); + } + // restore previous setting if still available + if(toolbars.reference.type->findText(refInBuf) >= 0) { + toolbars.reference.type->setCurrentText(refInBuf); + } else { + toolbars.reference.type->setCurrentIndex(0); + } + if(toolbars.reference.outFreq->findText(refOutBuf) >= 0) { + toolbars.reference.outFreq->setCurrentText(refOutBuf); + } else { + toolbars.reference.outFreq->setCurrentIndex(0); + } +} + void AppWindow::UpdateReference() { - if(!device) { + if(!vdevice) { // can't update without a device connected return; } - Protocol::ReferenceSettings s = {}; - - Reference::TypeIn t = static_cast(toolbars.reference.type->currentData().toInt()); - switch (t) { - case Reference::TypeIn::External: s.UseExternalRef = 1; break; - case Reference::TypeIn::Auto: s.AutomaticSwitch = 1; break; - default: break; - } - - Reference::OutFreq f = static_cast(toolbars.reference.outFreq->currentData().toInt()); - switch(f) { - case Reference::OutFreq::MHZ10: s.ExtRefOuputFreq = 10000000; break; - case Reference::OutFreq::MHZ100: s.ExtRefOuputFreq = 100000000; break; - default: break; - } - - Protocol::PacketInfo p; - p.type = Protocol::PacketType::Reference; - p.reference = s; - device->SendPacket(p); + vdevice->setExtRef(toolbars.reference.type->currentText(), toolbars.reference.outFreq->currentText()); } void AppWindow::UpdateAcquisitionFrequencies() { - if(!device) { + if(!vdevice) { return; } Protocol::PacketInfo p; @@ -1024,18 +948,21 @@ void AppWindow::UpdateAcquisitionFrequencies() p.acquisitionFrequencySettings.IF1 = pref.Acquisition.IF1; p.acquisitionFrequencySettings.ADCprescaler = pref.Acquisition.ADCprescaler; p.acquisitionFrequencySettings.DFTphaseInc = pref.Acquisition.DFTPhaseInc; - device->SendPacket(p); + for(auto dev : vdevice->getDevices()) { + dev->SendPacket(p); + } } void AppWindow::StartFirmwareUpdateDialog() { - if(device) { - auto fw_update = new FirmwareUpdateDialog(device); - connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice); - connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice); - if(AppWindow::showGUI()) { - fw_update->exec(); - } + if(!vdevice || vdevice->isCompoundDevice()) { + return; + } + auto fw_update = new FirmwareUpdateDialog(vdevice->getDevice()); + connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice); + connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice); + if(AppWindow::showGUI()) { + fw_update->exec(); } } @@ -1046,18 +973,29 @@ void AppWindow::DeviceNeedsUpdate(int reported, int expected) "version (" + QString::number(reported) + ") than expected (" + QString::number(expected) + ").\n" "A firmware update is strongly recommended. Do you want to update now?", false); if (ret) { + if (vdevice->isCompoundDevice()) { + InformationBox::ShowError("Unable to update the firmware", "The connected device is a compound device, direct firmware" + " update is not supported. Connect to each LibreVNA individually for the update."); + return; + } StartFirmwareUpdateDialog(); } } -void AppWindow::DeviceStatusUpdated() +void AppWindow::DeviceStatusUpdated(VirtualDevice::Status &status) { - UpdateStatusBar(DeviceStatusBar::Updated); + lDeviceInfo.setText(status.statusString); + lADCOverload.setVisible(status.overload); + lUnlevel.setVisible(status.unlevel); + lUnlock.setVisible(status.unlocked); } void AppWindow::SourceCalibrationDialog() { - auto d = new SourceCalDialog(device, modeHandler); + if(!vdevice || vdevice->isCompoundDevice()) { + return; + } + auto d = new SourceCalDialog(vdevice->getDevice(), modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1065,7 +1003,10 @@ void AppWindow::SourceCalibrationDialog() void AppWindow::ReceiverCalibrationDialog() { - auto d = new ReceiverCalDialog(device, modeHandler); + if(!vdevice || vdevice->isCompoundDevice()) { + return; + } + auto d = new ReceiverCalDialog(vdevice->getDevice(), modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1073,7 +1014,10 @@ void AppWindow::ReceiverCalibrationDialog() void AppWindow::FrequencyCalibrationDialog() { - auto d = new FrequencyCalDialog(device, modeHandler); + if(!vdevice || vdevice->isCompoundDevice()) { + return; + } + auto d = new FrequencyCalDialog(vdevice->getDevice(), modeHandler); if(AppWindow::showGUI()) { d->exec(); } @@ -1109,10 +1053,8 @@ nlohmann::json AppWindow::SaveSetup() } nlohmann::json ref; - Reference::TypeIn t = static_cast(toolbars.reference.type->currentData().toInt()); - ref["Mode"] = Reference::TypeToKey(t).toStdString(); - Reference::OutFreq f = static_cast(toolbars.reference.outFreq->currentData().toInt()); - ref["Output"] = Reference::OutFreqToKey(f).toStdString(); + ref["Mode"] = toolbars.reference.type->currentText().toStdString(); + ref["Output"] = toolbars.reference.outFreq->currentText().toStdString(); j["Reference"] = ref; j["version"] = qlibrevnaApp->applicationVersion().toStdString(); return j; @@ -1146,10 +1088,7 @@ void AppWindow::LoadSetup(nlohmann::json j) // auto d = new JSONPickerDialog(j); // d->exec(); if(j.contains("Reference")) { - QString fallback = Reference::TypeToKey(Reference::TypeIn::Internal); - auto mode = QString::fromStdString(j["Reference"].value("Mode",fallback.toStdString())); - auto index = toolbars.reference.type->findData((int)Reference::KeyToType(mode)); - toolbars.reference.type->setCurrentIndex(index); + toolbars.reference.type->setCurrentText(QString::fromStdString(j["Reference"].value("Mode", "Internal"))); toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off"))); } @@ -1198,9 +1137,9 @@ void AppWindow::LoadSetup(nlohmann::json j) } } -Device *&AppWindow::getDevice() +VirtualDevice *AppWindow::getDevice() { - return device; + return vdevice; } QStackedWidget *AppWindow::getCentral() const @@ -1274,19 +1213,19 @@ void AppWindow::UpdateStatusBar(DeviceStatusBar status) { switch(status) { case DeviceStatusBar::Connected: - lConnectionStatus.setText("Connected to " + device->serial()); - qInfo() << "Connected to" << device->serial(); - lDeviceInfo.setText(device->getLastDeviceInfoString()); + lConnectionStatus.setText("Connected to " + vdevice->serial()); + qInfo() << "Connected to" << vdevice->serial(); +// lDeviceInfo.setText(vdevice->getLastDeviceInfoString()); break; case DeviceStatusBar::Disconnected: lConnectionStatus.setText("No device connected"); lDeviceInfo.setText("No device information available yet"); break; case DeviceStatusBar::Updated: - lDeviceInfo.setText(device->getLastDeviceInfoString()); - lADCOverload.setVisible(device->StatusV1().ADC_overload); - lUnlevel.setVisible(device->StatusV1().unlevel); - lUnlock.setVisible(!device->StatusV1().LO1_locked || !device->StatusV1().source_locked); +// lDeviceInfo.setText(vdevice->getLastDeviceInfoString()); +// lADCOverload.setVisible(vdevice->StatusV1().ADC_overload); +// lUnlevel.setVisible(vdevice->StatusV1().unlevel); +// lUnlock.setVisible(!vdevice->StatusV1().LO1_locked || !vdevice->StatusV1().source_locked); break; default: // invalid status diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h index 289e2dd..0fa05a4 100644 --- a/Software/PC_Application/appwindow.h +++ b/Software/PC_Application/appwindow.h @@ -1,7 +1,7 @@ #ifndef APPWINDOW_H #define APPWINDOW_H -#include "Device/device.h" +#include "Device/virtualdevice.h".h" #include "Traces/traceplot.h" #include "Calibration/calibration.h" #include "Traces/tracemodel.h" @@ -43,7 +43,7 @@ public: Ui::MainWindow *getUi() const; QStackedWidget *getCentral() const; ModeHandler* getModeHandler() const; - Device*&getDevice(); + VirtualDevice *getDevice(); const QString& getAppVersion() const; const QString& getAppGitHash() const; @@ -62,11 +62,12 @@ private slots: void DisconnectDevice(); int UpdateDeviceList(); void StartManualControl(); + void UpdateReferenceToolbar(); void UpdateReference(); void UpdateAcquisitionFrequencies(); void StartFirmwareUpdateDialog(); void DeviceNeedsUpdate(int reported, int expected); - void DeviceStatusUpdated(); + void DeviceStatusUpdated(VirtualDevice::Status &status); void SourceCalibrationDialog(); void ReceiverCalibrationDialog(); void FrequencyCalibrationDialog(); @@ -102,7 +103,7 @@ private: } toolbars; ModeHandler *modeHandler; - Device *device; + VirtualDevice *vdevice; DeviceLog deviceLog; QString deviceSerial; QActionGroup *deviceActionGroup; diff --git a/Software/PC_Application/averaging.cpp b/Software/PC_Application/averaging.cpp index 5705b46..4a4324a 100644 --- a/Software/PC_Application/averaging.cpp +++ b/Software/PC_Application/averaging.cpp @@ -104,11 +104,15 @@ VNAData Averaging::process(VNAData d) return d; } -Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerResult d) +VirtualDevice::SAMeasurement Averaging::process(VirtualDevice::SAMeasurement d) { + if(d.measurements.size() != numMeasurements) { + reset(avg.size()); + } + if (d.pointNum == avg.size()) { // add moving average entry - deque, 4>> deque; + deque>> deque; avg.push_back(deque); } @@ -117,46 +121,61 @@ Protocol::SpectrumAnalyzerResult Averaging::process(Protocol::SpectrumAnalyzerRe // get correct queue auto deque = &avg[d.pointNum]; // add newest sample to queue - array, 4> sample = {d.port1, d.port2, 0, 0}; + vector> sample; + for(auto m : d.measurements) { + sample.push_back(m.second); + } deque->push_back(sample); if(deque->size() > averages) { deque->pop_front(); } + deque averagedResults; + switch(mode) { case Mode::Mean: { // calculate average - complex sum[2]; + complex sum[numMeasurements]; for(auto s : *deque) { - sum[0] += s[0]; - sum[1] += s[1]; + for(int i=0;isize()))); } - d.port1 = abs(sum[0] / (double) (deque->size())); - d.port2 = abs(sum[1] / (double) (deque->size())); } break; case Mode::Median: { auto size = deque->size(); - // create sorted arrays - std::vector port1, port2; - port1.reserve(size); - port2.reserve(size); + // create sorted vectors + array, numMeasurements> vectors; + for(auto &v : vectors) { + v.reserve(size); + } for(auto d : *deque) { - port1.insert(upper_bound(port1.begin(), port1.end(), abs(d[0])), abs(d[0])); - port2.insert(upper_bound(port2.begin(), port2.end(), abs(d[0])), abs(d[0])); + for(auto &v : vectors) { + v.insert(upper_bound(v.begin(), v.end(), abs(d[0])), abs(d[0])); + } } if(size & 0x01) { // odd number of samples - d.port1 = port1[size / 2]; - d.port2 = port1[size / 2]; + for(auto v : vectors) { + averagedResults.push_back(v[size / 2]); + } } else { // even number, use average of middle samples - d.port1 = (port1[size / 2 - 1] + port1[size / 2]) / 2; - d.port2 = (port2[size / 2 - 1] + port2[size / 2]) / 2; + for(auto v : vectors) { + averagedResults.push_back((v[size / 2 - 1] + v[size / 2]) / 2); + } } } break; } + + for(auto &m : d.measurements) { + m.second = averagedResults.pop_front(); + } } return d; diff --git a/Software/PC_Application/averaging.h b/Software/PC_Application/averaging.h index ffea038..6cc377b 100644 --- a/Software/PC_Application/averaging.h +++ b/Software/PC_Application/averaging.h @@ -1,7 +1,7 @@ #ifndef AVERAGING_H #define AVERAGING_H -#include "Device/device.h" +#include "Device/virtualdevice.h".h" #include "VNA/vnadata.h" #include @@ -20,7 +20,7 @@ public: void reset(unsigned int points); void setAverages(unsigned int a); VNAData process(VNAData d); - Protocol::SpectrumAnalyzerResult process(Protocol::SpectrumAnalyzerResult d); + VirtualDevice::SAMeasurement process(VirtualDevice::SAMeasurement d); // Returns the number of averaged sweeps. Value is incremented whenever the last point of the sweep is added. // Returned values are in range 0 to averages unsigned int getLevel(); @@ -31,8 +31,9 @@ public: void setMode(const Mode &value); private: - std::vector, 4>>> avg; + std::vector>>> avg; int maxPoints; + int numMeasurements; unsigned int averages; Mode mode; }; diff --git a/Software/PC_Application/mode.cpp b/Software/PC_Application/mode.cpp index ec31fb1..60fd833 100644 --- a/Software/PC_Application/mode.cpp +++ b/Software/PC_Application/mode.cpp @@ -115,7 +115,7 @@ void Mode::deactivate() qDebug() << "Deactivated mode" << name; if(window->getDevice()) { - window->getDevice()->SetIdle(); + window->getDevice()->setIdle(); } }