From cde564299c3a5309bbad75bbae7fdef7c3ebf35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Tue, 17 Jan 2023 00:25:58 +0100 Subject: [PATCH] WIP: device driver abstraction --- .../Calibration/LibreCAL/librecaldialog.cpp | 4 +- .../LibreVNA-GUI/Device/device.cpp | 233 +-- .../LibreVNA-GUI/Device/device.h | 46 +- .../LibreVNA-GUI/Device/devicedriver.cpp | 82 + .../LibreVNA-GUI/Device/devicedriver.h | 18 +- .../LibreVNA-GUI/Device/librevnadriver.cpp | 148 ++ .../LibreVNA-GUI/Device/librevnausbdriver.cpp | 35 + .../LibreVNA-GUI/Device/librevnausbdriver.h | 16 +- .../LibreVNA-GUI/Device/virtualdevice.cpp | 1856 ++++++++--------- .../LibreVNA-GUI/Device/virtualdevice.h | 370 ++-- .../SpectrumAnalyzer/spectrumanalyzer.cpp | 17 +- .../LibreVNA-GUI/Traces/traceeditdialog.cpp | 7 +- .../PC_Application/LibreVNA-GUI/VNA/vna.cpp | 4 +- .../PC_Application/LibreVNA-GUI/appwindow.cpp | 144 +- .../PC_Application/LibreVNA-GUI/appwindow.h | 21 +- Software/PC_Application/LibreVNA-GUI/main.cpp | 1 - .../LibreVNA-GUI/preferences.cpp | 64 +- .../PC_Application/LibreVNA-GUI/preferences.h | 2 + .../LibreVNA-Test/LibreVNA-Test.pro | 6 + 19 files changed, 1729 insertions(+), 1345 deletions(-) diff --git a/Software/PC_Application/LibreVNA-GUI/Calibration/LibreCAL/librecaldialog.cpp b/Software/PC_Application/LibreVNA-GUI/Calibration/LibreCAL/librecaldialog.cpp index e04af2e..ccd3f3c 100644 --- a/Software/PC_Application/LibreVNA-GUI/Calibration/LibreCAL/librecaldialog.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Calibration/LibreCAL/librecaldialog.cpp @@ -277,7 +277,7 @@ void LibreCALDialog::startCalibration() } ui->lCalibrationStatus->setText("Creating calibration measurements..."); cal->reset(); - auto vnaPorts = VirtualDevice::getInfo(VirtualDevice::getConnected()).ports; + auto vnaPorts = DeviceDriver::getInfo(DeviceDriver::getActiveDriver()).Limits.VNA.ports; set openMeasurements; set shortMeasurements; set loadMeasurements; @@ -432,7 +432,7 @@ void LibreCALDialog::createPortAssignmentUI() while(layout->rowCount() > 1) { layout->removeRow(1); } - auto vnaPorts = VirtualDevice::getInfo(VirtualDevice::getConnected()).ports; + auto vnaPorts = DeviceDriver::getInfo(DeviceDriver::getActiveDriver()).Limits.VNA.ports; portAssignment.resize(vnaPorts, 0); auto calPorts = 0; if(device) { diff --git a/Software/PC_Application/LibreVNA-GUI/Device/device.cpp b/Software/PC_Application/LibreVNA-GUI/Device/device.cpp index dc47e54..0a1b0d9 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/device.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/device.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "devicedriver.h" using namespace std; @@ -20,126 +21,126 @@ static constexpr USBID IDs[] = { {0x0483, 0x4121}, }; -USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) : - buffer_size(buffer_size), - received_size(0), - inCallback(false), - cancelling(false) -{ - buffer = new unsigned char[buffer_size]; - memset(buffer, 0, buffer_size); - transfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, buffer_size, CallbackTrampoline, this, 0); - libusb_submit_transfer(transfer); -} +//USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) : +// buffer_size(buffer_size), +// received_size(0), +// inCallback(false), +// cancelling(false) +//{ +// buffer = new unsigned char[buffer_size]; +// memset(buffer, 0, buffer_size); +// transfer = libusb_alloc_transfer(0); +// libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, buffer_size, CallbackTrampoline, this, 0); +// libusb_submit_transfer(transfer); +//} -USBInBuffer::~USBInBuffer() -{ - if(transfer) { - cancelling = true; - libusb_cancel_transfer(transfer); - // wait for cancellation to complete - mutex mtx; - unique_lock lck(mtx); - using namespace std::chrono_literals; - if(cv.wait_for(lck, 100ms) == cv_status::timeout) { - qWarning() << "Timed out waiting for mutex acquisition during disconnect"; - } - } - 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) -{ - if(cancelling || (transfer->status == LIBUSB_TRANSFER_CANCELLED)) { - // destructor called, do not resubmit - libusb_free_transfer(transfer); - this->transfer = nullptr; - cv.notify_all(); - return; - } -// qDebug() << libusb_error_name(transfer->status); - switch(transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - received_size += transfer->actual_length; - // Change/insert/delete random data to check the data handling for robustness -// srand((unsigned)time(0)); -// for(unsigned int i=0;i lck(mtx); +// using namespace std::chrono_literals; +// if(cv.wait_for(lck, 100ms) == cv_status::timeout) { +// qWarning() << "Timed out waiting for mutex acquisition during disconnect"; // } -// qDebug() << transfer->actual_length <<"total:" << received_size; - inCallback = true; - emit DataReceived(); - inCallback = false; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - qCritical() << "LIBUSB_TRANSFER_NO_DEVICE"; - libusb_free_transfer(transfer); - return; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_OVERFLOW: - case LIBUSB_TRANSFER_STALL: - qCritical() << "LIBUSB_ERROR" << transfer->status; - libusb_free_transfer(transfer); - this->transfer = nullptr; - emit TransferError(); - return; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - // nothing to do - break; - case LIBUSB_TRANSFER_CANCELLED: - // already handled before switch-case - break; - } - // Resubmit the transfer - transfer->buffer = &buffer[received_size]; - transfer->length = buffer_size - received_size; - libusb_submit_transfer(transfer); -} +// } +// delete[] buffer; +//} -void USBInBuffer::CallbackTrampoline(libusb_transfer *transfer) -{ - auto usb = (USBInBuffer*) transfer->user_data; - usb->Callback(transfer); -} +//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; +// } +//} -uint8_t *USBInBuffer::getBuffer() const -{ - return buffer; -} +//int USBInBuffer::getReceived() const +//{ +// return received_size; +//} + +//void USBInBuffer::Callback(libusb_transfer *transfer) +//{ +// if(cancelling || (transfer->status == LIBUSB_TRANSFER_CANCELLED)) { +// // destructor called, do not resubmit +// libusb_free_transfer(transfer); +// this->transfer = nullptr; +// cv.notify_all(); +// return; +// } +//// qDebug() << libusb_error_name(transfer->status); +// switch(transfer->status) { +// case LIBUSB_TRANSFER_COMPLETED: +// received_size += transfer->actual_length; +// // Change/insert/delete random data to check the data handling for robustness +//// srand((unsigned)time(0)); +//// for(unsigned int i=0;iactual_length <<"total:" << received_size; +// inCallback = true; +// emit DataReceived(); +// inCallback = false; +// break; +// case LIBUSB_TRANSFER_NO_DEVICE: +// qCritical() << "LIBUSB_TRANSFER_NO_DEVICE"; +// libusb_free_transfer(transfer); +// return; +// case LIBUSB_TRANSFER_ERROR: +// case LIBUSB_TRANSFER_OVERFLOW: +// case LIBUSB_TRANSFER_STALL: +// qCritical() << "LIBUSB_ERROR" << transfer->status; +// libusb_free_transfer(transfer); +// this->transfer = nullptr; +// emit TransferError(); +// return; +// break; +// case LIBUSB_TRANSFER_TIMED_OUT: +// // nothing to do +// break; +// case LIBUSB_TRANSFER_CANCELLED: +// // already handled before switch-case +// break; +// } +// // Resubmit the transfer +// transfer->buffer = &buffer[received_size]; +// transfer->length = buffer_size - 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; +//} static constexpr Protocol::DeviceInfo defaultInfo = { .ProtocolVersion = Protocol::Version, diff --git a/Software/PC_Application/LibreVNA-GUI/Device/device.h b/Software/PC_Application/LibreVNA-GUI/Device/device.h index 2e29bc9..b59acee 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/device.h +++ b/Software/PC_Application/LibreVNA-GUI/Device/device.h @@ -3,6 +3,8 @@ #include "../../VNA_embedded/Application/Communication/Protocol.hpp" +#include "librevnausbdriver.h" + #include #include #include @@ -18,31 +20,31 @@ Q_DECLARE_METATYPE(Protocol::ManualStatusV1) Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult) Q_DECLARE_METATYPE(Protocol::AmplitudeCorrectionPoint) -class USBInBuffer : public QObject { - Q_OBJECT -public: - USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size); - ~USBInBuffer(); +//class USBInBuffer : public QObject { +// Q_OBJECT +//public: +// USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size); +// ~USBInBuffer(); - void removeBytes(int handled_bytes); - int getReceived() const; - uint8_t *getBuffer() const; +// void removeBytes(int handled_bytes); +// int getReceived() const; +// uint8_t *getBuffer() const; -signals: - void DataReceived(); - void TransferError(); +//signals: +// void DataReceived(); +// void TransferError(); -private: - void Callback(libusb_transfer *transfer); - static void LIBUSB_CALL CallbackTrampoline(libusb_transfer *transfer); - libusb_transfer *transfer; - unsigned char *buffer; - int buffer_size; - int received_size; - bool inCallback; - bool cancelling; - std::condition_variable cv; -}; +//private: +// void Callback(libusb_transfer *transfer); +// static void LIBUSB_CALL CallbackTrampoline(libusb_transfer *transfer); +// libusb_transfer *transfer; +// unsigned char *buffer; +// int buffer_size; +// int received_size; +// bool inCallback; +// bool cancelling; +// std::condition_variable cv; +//}; class Device : public QObject diff --git a/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.cpp b/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.cpp index a730b00..265c13d 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.cpp @@ -20,3 +20,85 @@ void DeviceDriver::disconnectDevice() disconnect(); activeDriver = nullptr; } + +unsigned int DeviceDriver::SApoints() { + if(activeDriver) { + return activeDriver->getSApoints(); + } else { + // return default value instead + return 1001; + } +} + +Sparam DeviceDriver::VNAMeasurement::toSparam(int port1, int port2) const +{ + Sparam S; + S.m11 = measurements.at("S"+QString::number(port1)+QString::number(port1)); + S.m12 = measurements.at("S"+QString::number(port1)+QString::number(port2)); + S.m21 = measurements.at("S"+QString::number(port2)+QString::number(port1)); + S.m22 = measurements.at("S"+QString::number(port2)+QString::number(port2)); + return S; +} + +void DeviceDriver::VNAMeasurement::fromSparam(Sparam S, int port1, int port2) +{ + QString s11 = "S"+QString::number(port1)+QString::number(port1); + QString s12 = "S"+QString::number(port1)+QString::number(port2); + QString s21 = "S"+QString::number(port2)+QString::number(port1); + QString s22 = "S"+QString::number(port2)+QString::number(port2); + if(measurements.count(s11)) { + measurements[s11] = S.m11; + } + if(measurements.count(s12)) { + measurements[s12] = S.m12; + } + if(measurements.count(s21)) { + measurements[s21] = S.m21; + } + if(measurements.count(s22)) { + measurements[s22] = S.m22; + } +} + +DeviceDriver::VNAMeasurement DeviceDriver::VNAMeasurement::interpolateTo(const DeviceDriver::VNAMeasurement &to, double a) +{ + VNAMeasurement ret; + ret.frequency = frequency * (1.0 - a) + to.frequency * a; + ret.dBm = dBm * (1.0 - a) + to.dBm * a; + ret.Z0 = Z0 * (1.0 - a) + to.Z0 * a; + for(auto m : measurements) { + if(to.measurements.count(m.first) == 0) { + throw std::runtime_error("Nothing to interpolate to, expected measurement +\""+m.first.toStdString()+"\""); + } + ret.measurements[m.first] = measurements[m.first] * (1.0 - a) + to.measurements.at(m.first) * a; + } + return ret; +} + +DeviceDriver::Info::Info() +{ + firmware_version = "missing"; + hardware_version = "missing"; + Limits.VNA.ports = 2; + Limits.VNA.minFreq = 0; + Limits.VNA.maxFreq = 6000000000; + Limits.VNA.mindBm = -100; + Limits.VNA.maxdBm = 30; + Limits.VNA.minIFBW = 1; + Limits.VNA.maxIFBW = 1000000; + Limits.VNA.maxPoints = 65535; + + Limits.Generator.ports = 2; + Limits.Generator.minFreq = 0; + Limits.Generator.maxFreq = 6000000000; + Limits.Generator.mindBm = -100; + Limits.Generator.maxdBm = 30; + + Limits.SA.ports = 2; + Limits.SA.minFreq = 0; + Limits.SA.maxFreq = 6000000000; + Limits.SA.mindBm = -100; + Limits.SA.maxdBm = 30; + Limits.SA.minRBW = 1; + Limits.SA.maxRBW = 1000000; +} diff --git a/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.h b/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.h index cefda78..43df4b0 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.h +++ b/Software/PC_Application/LibreVNA-GUI/Device/devicedriver.h @@ -78,7 +78,7 @@ public: class Info { public: - // TODO create constructor with default values + Info(); QString firmware_version; QString hardware_version; std::set supportedFeatures; @@ -161,6 +161,13 @@ public: */ virtual std::set getFlags() = 0; +signals: + /** + * @brief Emit this signal whenever a flag changes + */ + void FlagsUpdated(); +public: + /** * @brief Checks whether a specific flag is asserted * @param f Flag to check @@ -428,6 +435,14 @@ public: } } + /** + * @brief Registers metatypes within the Qt Framework. + * + * If the device driver uses a queued signal/slot connection with custom data types, these types must be registered before emitting the signal. + * Register them within this function with qRegisterMetaType("Name"); + */ + virtual void registerTypes() {} + signals: /** * @brief Emit this signal when the device connection has been lost unexpectedly @@ -445,6 +460,7 @@ public: bool connectDevice(QString serial); void disconnectDevice(); static DeviceDriver* getActiveDriver() {return activeDriver;} + static unsigned int SApoints(); private: static DeviceDriver *activeDriver; diff --git a/Software/PC_Application/LibreVNA-GUI/Device/librevnadriver.cpp b/Software/PC_Application/LibreVNA-GUI/Device/librevnadriver.cpp index c57638e..db1cb42 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/librevnadriver.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/librevnadriver.cpp @@ -2,6 +2,96 @@ 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}; + } +}; + LibreVNADriver::LibreVNADriver() { connected = false; @@ -142,6 +232,7 @@ bool LibreVNADriver::setSA(const DeviceDriver::SASettings &s, std::function cb) }); } +QStringList LibreVNADriver::availableExtRefInSettings() +{ + QStringList ret; + for(auto r : Reference::getReferencesIn()) { + ret.push_back(Reference::TypeToLabel(r)); + } + return ret; +} + +QStringList LibreVNADriver::availableExtRefOutSettings() +{ + QStringList ret; + for(auto r : Reference::getOutFrequencies()) { + ret.push_back(Reference::OutFreqToLabel(r)); + } + return ret; +} + +bool LibreVNADriver::setExtRef(QString option_in, QString option_out) +{ + 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: + case Reference::TypeIn::None: + 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::None: + 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; + } + + return SendPacket(p); +} + void LibreVNADriver::handleReceivedPacket(const Protocol::PacketInfo &packet) { emit passOnReceivedPacket(packet); @@ -253,6 +400,7 @@ void LibreVNADriver::handleReceivedPacket(const Protocol::PacketInfo &packet) case Protocol::PacketType::DeviceStatusV1: lastStatus = packet.statusV1; emit StatusUpdated(); + emit FlagsUpdated(); break; case Protocol::PacketType::VNADatapoint: { VNAMeasurement m; diff --git a/Software/PC_Application/LibreVNA-GUI/Device/librevnausbdriver.cpp b/Software/PC_Application/LibreVNA-GUI/Device/librevnausbdriver.cpp index dd70592..eb3aa6d 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/librevnausbdriver.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/librevnausbdriver.cpp @@ -249,6 +249,12 @@ void LibreVNAUSBDriver::disconnect() } } +void LibreVNAUSBDriver::registerTypes() +{ + qRegisterMetaType("LibreVNAUSBPacket"); + qRegisterMetaType("LibreVNAUSBResult"); +} + void LibreVNAUSBDriver::ReceivedData() { Protocol::PacketInfo packet; @@ -429,3 +435,32 @@ void LibreVNAUSBDriver::SearchDevices(std::function #include +Q_DECLARE_METATYPE(Protocol::PacketInfo) +Q_DECLARE_METATYPE(LibreVNADriver::TransmissionResult) + class USBInBuffer : public QObject { Q_OBJECT public: @@ -63,6 +66,14 @@ public: */ virtual void disconnect() override; + /** + * @brief Registers metatypes within the Qt Framework. + * + * If the device driver uses a queued signal/slot connection with custom data types, these types must be registered before emitting the signal. + * Register them within this function with qRegisterMetaType("Name"); + */ + virtual void registerTypes(); + private slots: void ReceivedData(); void ReceivedLog(); @@ -101,11 +112,6 @@ private: bool transmissionActive; std::thread *m_receiveThread; - Protocol::DeviceInfo info; - bool infoValid; - union { - Protocol::DeviceStatusV1 v1; - } status; std::mutex accessMutex; }; diff --git a/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.cpp b/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.cpp index 6d7f742..a54c727 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.cpp @@ -1,928 +1,928 @@ -#include "virtualdevice.h" - -#include "preferences.h" -#include "CustomWidgets/informationbox.h" -#include "../../VNA_embedded/Application/Communication/Protocol.hpp" - -#include - -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}; - } -}; - -VirtualDevice::VirtualDevice(QString serial) - : QObject(), - info{}, - status{} -{ - cdev = nullptr; - zerospan = false; - - // Check if this is a compound device - auto& pref = Preferences::getInstance(); - for(auto cd : pref.compoundDevices) { - if(cd->name == serial) { - // connect request to this compound device - cdev = cd; - break; - } - } - - if(!isCompoundDevice()) { - // just acting as a wrapper for device, pass on signals - auto dev = new Device(serial); - devices.push_back(dev); - connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost, Qt::QueuedConnection); - connect(dev, &Device::DeviceInfoUpdated, this, [=](){ - info = Info(devices[0]); - emit InfoUpdated(); - }, Qt::QueuedConnection); - connect(dev, &Device::LogLineReceived, this, &VirtualDevice::LogLineReceived, Qt::QueuedConnection); - connect(dev, &Device::DeviceStatusUpdated, this, [=](){ - status = Status(devices[0]); - emit StatusUpdated(status); - }, Qt::QueuedConnection); - connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate, Qt::QueuedConnection); - connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::singleSpectrumResultReceived, Qt::QueuedConnection); - connect(dev, &Device::DatapointReceived, this, &VirtualDevice::singleDatapointReceived, Qt::QueuedConnection); - } else { - // Connect to the actual devices - for(auto devSerial : cdev->deviceSerials) { - auto dev = new Device(devSerial, true); - devices.push_back(dev); - // Create device connections - connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost, Qt::QueuedConnection); - connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate, Qt::QueuedConnection); - connect(dev, &Device::LogLineReceived, this, [=](QString line){ - emit LogLineReceived(line.prepend(dev->serial()+": ")); - }, Qt::QueuedConnection); - connect(dev, &Device::DeviceInfoUpdated, this, &VirtualDevice::compoundInfoUpdated, Qt::QueuedConnection); - connect(dev, &Device::DeviceStatusUpdated, this, &VirtualDevice::compoundStatusUpdated, Qt::QueuedConnection); - connect(dev, &Device::DatapointReceived, this, &VirtualDevice::compoundDatapointReceivecd, Qt::QueuedConnection); - connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::compoundSpectrumResultReceived, Qt::QueuedConnection); - } - if(cdev->sync == CompoundDevice::Synchronization::USB) { - // create trigger connections for USB synchronization - for(unsigned int i=0;i("Status"); - qRegisterMetaType("VNAMeasurement"); - qRegisterMetaType("SAMeasurement"); -} - -void VirtualDevice::initialize() -{ - for(auto dev : devices) { - dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceInfo); - dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceStatus); - } -} - -bool VirtualDevice::isCompoundDevice() const -{ - return cdev != nullptr; -} - -Device *VirtualDevice::getDevice() -{ - if(isCompoundDevice() || devices.size() < 1) { - return nullptr; - } else { - return devices[0]; - } -} - -CompoundDevice *VirtualDevice::getCompoundDevice() -{ - return cdev; -} - -std::vector VirtualDevice::getDevices() -{ - return devices; -} - -const VirtualDevice::Info &VirtualDevice::getInfo() const -{ - return info; -} - -VirtualDevice::Info VirtualDevice::getInfo(VirtualDevice *vdev) -{ - if(vdev) { - return vdev->info; - } else { - return Info(); - } -} - -const VirtualDevice::Status &VirtualDevice::getStatus() const -{ - return status; -} - -VirtualDevice::Status VirtualDevice::getStatus(VirtualDevice *vdev) -{ - if(vdev) { - return vdev->status; - } else { - return Status(); - } -} - -QStringList VirtualDevice::availableVNAMeasurements() -{ - QStringList ret; - for(unsigned int i=1;i<=info.ports;i++) { - for(unsigned int j=1;j<=info.ports;j++) { - ret.push_back("S"+QString::number(i)+QString::number(j)); - } - } - auto &pref = Preferences::getInstance(); - if(pref.Debug.makeRawReceiverValuesAvailable) { - for(unsigned int i=1;i<=info.ports;i++) { - for(unsigned int j=0;j cb) -{ - if(!info.supportsVNAmode) { - return false; - } - if(s.excitedPorts.size() == 0) { - return setIdle(cb); - } - - // create port->stage mapping - portStageMapping.clear(); - for(unsigned int i=0;iConfigure(sd, [=](Device::TransmissionResult r){ - if(cb) { - cb(r == Device::TransmissionResult::Ack); - } - }); - } else { - // set the synchronization mode - switch(cdev->sync) { - case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break; - case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break; - case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break; - case CompoundDevice::Synchronization::Last: sd.syncMode = 1; break; // should never get here - } - // create vector of currently used stimulus ports - vector activeMapping; - for(auto p : s.excitedPorts) { - activeMapping.push_back(cdev->portMapping[p]); - } - // Configure the devices - results.clear(); - bool success = true; - for(unsigned int i=0;iConfigure(sd, [=](Device::TransmissionResult r){ - if(cb) { - results[devices[i]] = r; - checkIfAllTransmissionsComplete(cb); - } - }); - } - return success; - } -} - -QString VirtualDevice::serial() -{ - if(!isCompoundDevice()) { - return devices[0]->serial(); - } else { - return cdev->name; - } -} - -QStringList VirtualDevice::availableSAMeasurements() -{ - QStringList ret; - for(unsigned int i=1;i<=info.ports;i++) { - ret.push_back("PORT"+QString::number(i)); - } - return ret; -} - -bool VirtualDevice::setSA(const VirtualDevice::SASettings &s, std::function cb) -{ - if(!info.supportsSAmode) { - return false; - } - zerospan = s.freqStart == s.freqStop; - auto& pref = Preferences::getInstance(); - 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.trackingGeneratorOffset = s.trackingOffset; - sd.trackingPower = s.trackingPower; - - if(!isCompoundDevice()) { - sd.trackingGenerator = s.trackingGenerator ? 1 : 0; - sd.trackingGeneratorPort = s.trackingPort; - sd.syncMode = 0; - sd.syncMaster = 0; - return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ - if(cb) { - cb(r == Device::TransmissionResult::Ack); - } - }); - } else { - // set the synchronization mode - switch(cdev->sync) { - case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break; - case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break; - case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break; - case CompoundDevice::Synchronization::Last: sd.syncMode = 1; break; // should never get here - } - // Configure the devices - results.clear(); - bool success = true; - for(unsigned int i=0;iportMapping, i, 0) == s.trackingPort) { - sd.trackingGenerator = 1; - sd.trackingGeneratorPort = 0; - } else if(CompoundDevice::PortMapping::findActiveStage(cdev->portMapping, i, 1) == s.trackingPort) { - sd.trackingGenerator = 1; - sd.trackingGeneratorPort = 1; - } - } - sd.syncMaster = i == 0 ? 1 : 0; - success &= devices[i]->Configure(sd, [=](Device::TransmissionResult r){ - if(cb) { - results[devices[i]] = r; - checkIfAllTransmissionsComplete(cb); - } - }); - } - return success; - } -} - -QStringList VirtualDevice::availableSGPorts() -{ - QStringList ret; - for(unsigned int i=1;iSendPacket(packet); - } else { - // configure all devices - bool success = true; - for(unsigned int i=0;i 0) { - if(cdev->portMapping[s.port-1].device == i) { - // this device has the active port - sd.activePort = cdev->portMapping[s.port-1].port+1; - } - } - success &= devices[i]->SendPacket(packet); - } - return success; - } -} - -bool VirtualDevice::setIdle(std::function cb) -{ - auto success = true; - results.clear(); - for(auto dev : devices) { - success &= dev->SetIdle([=](Device::TransmissionResult r){ - if(cb) { - results[dev] = r; - checkIfAllTransmissionsComplete(cb); - } - }); - } - return 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: - case Reference::TypeIn::None: - 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::None: - 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::GetAvailableVirtualDevices() -{ - auto& pref = Preferences::getInstance(); - auto ret = Device::GetDevices(); - // Add compound devices as well - for(auto vdev : pref.compoundDevices) { - // check if all serial number required for this compound device are available - bool serialMissing = false; - for(auto s : vdev->deviceSerials) { - if(ret.count(s) == 0) { - serialMissing = true; - break; - } - } - if(!serialMissing) { - // this compound device is available - ret.insert(vdev->name); - } - } - return ret; -} - -VirtualDevice *VirtualDevice::getConnected() -{ - return connected; -} - -void VirtualDevice::singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res) -{ - Q_UNUSED(dev) - auto &pref = Preferences::getInstance(); - VNAMeasurement m; - m.pointNum = res->pointNum; - m.Z0 = 50.0; - if(zerospan) { - m.us = res->us; - } else { - m.frequency = res->frequency; - m.dBm = (double) res->cdBm / 100; - } - for(auto map : portStageMapping) { - // map.first is the port (starts at zero) - // map.second is the stage at which this port had the stimulus (starts at zero) - complex ref = res->getValue(map.second, map.first, true); - for(unsigned int i=0;i input = res->getValue(map.second, i, false); - if(!std::isnan(ref.real()) && !std::isnan(input.real())) { - // got both required measurements - QString name = "S"+QString::number(i+1)+QString::number(map.first+1); - m.measurements[name] = input / ref; - } - if(pref.Debug.makeRawReceiverValuesAvailable) { - QString name = "RawPort"+QString::number(i+1)+"Stage"+QString::number(map.first); - m.measurements[name] = input; - name = "RawPort"+QString::number(i+1)+"Stage"+QString::number(map.first)+"Ref"; - m.measurements[name] = res->getValue(map.second, i, true); - } - } - } - delete res; - emit VNAmeasurementReceived(m); -} - -void VirtualDevice::compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data) -{ - if(!compoundVNABuffer.count(data->pointNum)) { - compoundVNABuffer[data->pointNum] = std::map*>(); - } - auto &buf = compoundVNABuffer[data->pointNum]; - buf[dev] = data; - if(buf.size() == devices.size()) { - // Got datapoints from all devices, can create merged VNA result - VNAMeasurement m; - m.pointNum = data->pointNum; - m.Z0 = 50.0; - if(zerospan) { - m.us = data->us; - } else { - m.frequency = data->frequency; - m.dBm = (double) data->cdBm / 100; - } - // assemble data - for(auto map : portStageMapping) { - // map.first is the port (starts at zero) - // map.second is the stage at which this port had the stimulus (starts at zero) - - // figure out which device had the stimulus for the port... - auto stimulusDev = devices[cdev->portMapping[map.first].device]; - // ...and which device port was used for the stimulus... - auto stimulusDevPort = cdev->portMapping[map.first].port; - // ...grab the reference receiver data - complex ref = buf[stimulusDev]->getValue(map.second, stimulusDevPort, true); - - // for all ports of the compound device... - for(unsigned int i=0;iportMapping.size();i++) { - // ...figure out which physical device and port was used for this input... - auto inputDevice = devices[cdev->portMapping[i].device]; - // ...and grab the data - auto inputPort = cdev->portMapping[i].port; - complex input = buf[inputDevice]->getValue(map.second, inputPort, false); - if(!std::isnan(ref.real()) && !std::isnan(input.real())) { - // got both required measurements - QString name = "S"+QString::number(i+1)+QString::number(map.first+1); - auto S = input / ref; - if(inputDevice != stimulusDev) { - // can't use phase information when measuring across devices - S = abs(S); - } - m.measurements[name] = S; - } - } - } - - emit VNAmeasurementReceived(m); - - // Clear this and all (incomplete) older datapoint buffers - int pointNum = data->pointNum; - auto it = compoundVNABuffer.begin(); - while(it != compoundVNABuffer.end()) { - if(it->first <= pointNum) { - for(auto d : it->second) { - delete d.second; - } - it = compoundVNABuffer.erase(it); - } else { - it++; - } - } - } -} - -void VirtualDevice::singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res) -{ - Q_UNUSED(dev) - 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); -} - -void VirtualDevice::compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res) -{ - if(!compoundSABuffer.count(res.pointNum)) { - compoundSABuffer[res.pointNum] = std::map(); - } - auto &buf = compoundSABuffer[res.pointNum]; - buf[dev] = res; - if(buf.size() == devices.size()) { - // Got datapoints from all devices, can create merged VNA result - SAMeasurement m; - m.pointNum = res.pointNum; - if(zerospan) { - m.us = res.us; - } else { - m.frequency = res.frequency; - } - // assemble data - for(unsigned int port=0;portportMapping.size();port++) { - auto device = devices[cdev->portMapping[port].device]; - auto devicePort = cdev->portMapping[port].port; - - QString name = "PORT"+QString::number(port+1); - if(devicePort == 0) { - m.measurements[name] = buf[device].port1; - } else { - m.measurements[name] = buf[device].port2; - } - } - - emit SAmeasurementReceived(m); - - // Clear this and all (incomplete) older datapoint buffers - auto it = compoundSABuffer.begin(); - while(it != compoundSABuffer.end()) { - if(it->first <= res.pointNum) { - it = compoundSABuffer.erase(it); - } else { - it++; - } - } - } -} - -void VirtualDevice::compoundInfoUpdated(Device *dev) -{ - compoundInfoBuffer[dev] = dev->Info(); - if(compoundInfoBuffer.size() == devices.size()) { - // got information of all devices - info = Info(devices[0]); - for(unsigned int i=1;isync == CompoundDevice::Synchronization::ExtRef) { - // can't use the external reference if it is used for synchronization - info.supportsExtRef = false; - } - info.ports = cdev->portMapping.size(); - emit InfoUpdated(); - } -} - -void VirtualDevice::compoundStatusUpdated(Device *dev) -{ - compoundStatusBuffer[dev] = dev->StatusV1(); - if(compoundStatusBuffer.size() == devices.size()) { - // got status of all devices - status = Status(devices[0]); - for(unsigned int i=1;i cb) -{ - if(results.size() == devices.size()) { - // got all responses - bool success = true; - for(auto res : results) { - if(res.second != Device::TransmissionResult::Ack) { - success = false; - break; - } - } - if(cb) { - cb(success); - } - } -} - -Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2) const -{ - Sparam S; - S.m11 = measurements.at("S"+QString::number(port1)+QString::number(port1)); - S.m12 = measurements.at("S"+QString::number(port1)+QString::number(port2)); - S.m21 = measurements.at("S"+QString::number(port2)+QString::number(port1)); - S.m22 = measurements.at("S"+QString::number(port2)+QString::number(port2)); - return S; -} - -void VirtualDevice::VNAMeasurement::fromSparam(Sparam S, int port1, int port2) -{ - QString s11 = "S"+QString::number(port1)+QString::number(port1); - QString s12 = "S"+QString::number(port1)+QString::number(port2); - QString s21 = "S"+QString::number(port2)+QString::number(port1); - QString s22 = "S"+QString::number(port2)+QString::number(port2); - if(measurements.count(s11)) { - measurements[s11] = S.m11; - } - if(measurements.count(s12)) { - measurements[s12] = S.m12; - } - if(measurements.count(s21)) { - measurements[s21] = S.m21; - } - if(measurements.count(s22)) { - measurements[s22] = S.m22; - } -} - -VirtualDevice::VNAMeasurement VirtualDevice::VNAMeasurement::interpolateTo(const VirtualDevice::VNAMeasurement &to, double a) -{ - VNAMeasurement ret; - ret.frequency = frequency * (1.0 - a) + to.frequency * a; - ret.dBm = dBm * (1.0 - a) + to.dBm * a; - ret.Z0 = Z0 * (1.0 - a) + to.Z0 * a; - for(auto m : measurements) { - if(to.measurements.count(m.first) == 0) { - throw runtime_error("Nothing to interpolate to, expected measurement +\""+m.first.toStdString()+"\""); - } - ret.measurements[m.first] = measurements[m.first] * (1.0 - a) + to.measurements.at(m.first) * a; - } - return ret; -} - -VirtualDevice::Info::Info() -{ - 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; - supportsExtRef = true; - Limits = { - .minFreq = 0, - .maxFreq = 6000000000, - .maxFreqHarmonic = 18000000000, - .minIFBW = 10, - .maxIFBW = 1000000, - .maxPoints = 10000, - .mindBm = -100, - .maxdBm = 30, - .minRBW = 1, - .maxRBW = 1000000, - }; -} - -VirtualDevice::Info::Info(Device *dev) -{ - auto info = dev->Info(); - ProtocolVersion = info.ProtocolVersion; - FW_major = info.FW_major; - FW_minor = info.FW_minor; - FW_patch = info.FW_patch; - hardware_version = info.hardware_version; - HW_Revision = info.HW_Revision; - ports = 2; - supportsVNAmode = true; - supportsSAmode = true; - supportsSGmode = true; - supportsExtRef = true; - Limits.minFreq = info.limits_minFreq; - Limits.maxFreq = info.limits_maxFreq; - Limits.maxFreqHarmonic = info.limits_maxFreqHarmonic; - Limits.minIFBW = info.limits_minIFBW; - Limits.maxIFBW = info.limits_maxIFBW; - Limits.maxPoints = info.limits_maxPoints; - Limits.mindBm = (double) info.limits_cdbm_min / 100; - Limits.maxdBm = (double) info.limits_cdbm_max / 100; - Limits.minRBW = info.limits_minRBW; - Limits.maxRBW = info.limits_maxRBW; -} - -void VirtualDevice::Info::subset(const VirtualDevice::Info &merge) -{ - if((merge.ProtocolVersion != ProtocolVersion) - || (merge.FW_major != FW_major) - || (merge.FW_minor != FW_minor) - || (merge.FW_patch != FW_patch)) { - throw runtime_error("Incompatible device, unable to create compound device. All devices must run the same firmware version."); - } - ports += merge.ports; - supportsVNAmode &= merge.supportsVNAmode; - supportsSGmode &= merge.supportsSGmode; - supportsSAmode &= merge.supportsSAmode; - supportsExtRef &= merge.supportsExtRef; - Limits.minFreq = max(Limits.minFreq, merge.Limits.minFreq); - Limits.maxFreq = min(Limits.maxFreq, merge.Limits.maxFreq); - Limits.maxFreqHarmonic = min(Limits.maxFreqHarmonic, merge.Limits.maxFreqHarmonic); - Limits.minIFBW = max(Limits.minIFBW, merge.Limits.minIFBW); - Limits.maxIFBW = min(Limits.maxIFBW, merge.Limits.maxIFBW); - Limits.maxPoints = min(Limits.maxPoints, merge.Limits.maxPoints); - Limits.mindBm = max(Limits.mindBm, merge.Limits.mindBm); - Limits.maxdBm = min(Limits.maxdBm, merge.Limits.maxdBm); - Limits.minRBW = max(Limits.minRBW, merge.Limits.minRBW); - Limits.maxRBW = min(Limits.maxRBW, merge.Limits.maxRBW); -} - -VirtualDevice::Status::Status() -{ - statusString = ""; - overload = false; - unlocked = false; - unlevel = false; - extRef = false; -} - -VirtualDevice::Status::Status(Device *dev) -{ - auto status = dev->StatusV1(); - statusString = dev->getLastDeviceInfoString(); - overload = status.ADC_overload; - unlevel = status.unlevel; - unlocked = !status.LO1_locked || !status.source_locked; - extRef = status.extRefInUse; -} - -void VirtualDevice::Status::merge(const VirtualDevice::Status &merge) -{ - statusString += " / "+merge.statusString; - overload |= merge.overload; - unlevel |= merge.unlevel; - unlocked |= merge.unlocked; - extRef &= merge.extRef; -} +//#include "virtualdevice.h" + +//#include "preferences.h" +//#include "CustomWidgets/informationbox.h" +//#include "../../VNA_embedded/Application/Communication/Protocol.hpp" + +//#include + +//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}; +// } +//}; + +//VirtualDevice::VirtualDevice(QString serial) +// : QObject(), +// info{}, +// status{} +//{ +// cdev = nullptr; +// zerospan = false; + +// // Check if this is a compound device +// auto& pref = Preferences::getInstance(); +// for(auto cd : pref.compoundDevices) { +// if(cd->name == serial) { +// // connect request to this compound device +// cdev = cd; +// break; +// } +// } + +// if(!isCompoundDevice()) { +// // just acting as a wrapper for device, pass on signals +// auto dev = new Device(serial); +// devices.push_back(dev); +// connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost, Qt::QueuedConnection); +// connect(dev, &Device::DeviceInfoUpdated, this, [=](){ +// info = Info(devices[0]); +// emit InfoUpdated(); +// }, Qt::QueuedConnection); +// connect(dev, &Device::LogLineReceived, this, &VirtualDevice::LogLineReceived, Qt::QueuedConnection); +// connect(dev, &Device::DeviceStatusUpdated, this, [=](){ +// status = Status(devices[0]); +// emit StatusUpdated(status); +// }, Qt::QueuedConnection); +// connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate, Qt::QueuedConnection); +// connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::singleSpectrumResultReceived, Qt::QueuedConnection); +// connect(dev, &Device::DatapointReceived, this, &VirtualDevice::singleDatapointReceived, Qt::QueuedConnection); +// } else { +// // Connect to the actual devices +// for(auto devSerial : cdev->deviceSerials) { +// auto dev = new Device(devSerial, true); +// devices.push_back(dev); +// // Create device connections +// connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost, Qt::QueuedConnection); +// connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate, Qt::QueuedConnection); +// connect(dev, &Device::LogLineReceived, this, [=](QString line){ +// emit LogLineReceived(line.prepend(dev->serial()+": ")); +// }, Qt::QueuedConnection); +// connect(dev, &Device::DeviceInfoUpdated, this, &VirtualDevice::compoundInfoUpdated, Qt::QueuedConnection); +// connect(dev, &Device::DeviceStatusUpdated, this, &VirtualDevice::compoundStatusUpdated, Qt::QueuedConnection); +// connect(dev, &Device::DatapointReceived, this, &VirtualDevice::compoundDatapointReceivecd, Qt::QueuedConnection); +// connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::compoundSpectrumResultReceived, Qt::QueuedConnection); +// } +// if(cdev->sync == CompoundDevice::Synchronization::USB) { +// // create trigger connections for USB synchronization +// for(unsigned int i=0;i("Status"); +// qRegisterMetaType("VNAMeasurement"); +// qRegisterMetaType("SAMeasurement"); +//} + +//void VirtualDevice::initialize() +//{ +// for(auto dev : devices) { +// dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceInfo); +// dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceStatus); +// } +//} + +//bool VirtualDevice::isCompoundDevice() const +//{ +// return cdev != nullptr; +//} + +//Device *VirtualDevice::getDevice() +//{ +// if(isCompoundDevice() || devices.size() < 1) { +// return nullptr; +// } else { +// return devices[0]; +// } +//} + +//CompoundDevice *VirtualDevice::getCompoundDevice() +//{ +// return cdev; +//} + +//std::vector VirtualDevice::getDevices() +//{ +// return devices; +//} + +//const VirtualDevice::Info &VirtualDevice::getInfo() const +//{ +// return info; +//} + +//VirtualDevice::Info VirtualDevice::getInfo(VirtualDevice *vdev) +//{ +// if(vdev) { +// return vdev->info; +// } else { +// return Info(); +// } +//} + +//const VirtualDevice::Status &VirtualDevice::getStatus() const +//{ +// return status; +//} + +//VirtualDevice::Status VirtualDevice::getStatus(VirtualDevice *vdev) +//{ +// if(vdev) { +// return vdev->status; +// } else { +// return Status(); +// } +//} + +//QStringList VirtualDevice::availableVNAMeasurements() +//{ +// QStringList ret; +// for(unsigned int i=1;i<=info.ports;i++) { +// for(unsigned int j=1;j<=info.ports;j++) { +// ret.push_back("S"+QString::number(i)+QString::number(j)); +// } +// } +// auto &pref = Preferences::getInstance(); +// if(pref.Debug.makeRawReceiverValuesAvailable) { +// for(unsigned int i=1;i<=info.ports;i++) { +// for(unsigned int j=0;j cb) +//{ +// if(!info.supportsVNAmode) { +// return false; +// } +// if(s.excitedPorts.size() == 0) { +// return setIdle(cb); +// } + +// // create port->stage mapping +// portStageMapping.clear(); +// for(unsigned int i=0;iConfigure(sd, [=](Device::TransmissionResult r){ +// if(cb) { +// cb(r == Device::TransmissionResult::Ack); +// } +// }); +// } else { +// // set the synchronization mode +// switch(cdev->sync) { +// case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break; +// case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break; +// case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break; +// case CompoundDevice::Synchronization::Last: sd.syncMode = 1; break; // should never get here +// } +// // create vector of currently used stimulus ports +// vector activeMapping; +// for(auto p : s.excitedPorts) { +// activeMapping.push_back(cdev->portMapping[p]); +// } +// // Configure the devices +// results.clear(); +// bool success = true; +// for(unsigned int i=0;iConfigure(sd, [=](Device::TransmissionResult r){ +// if(cb) { +// results[devices[i]] = r; +// checkIfAllTransmissionsComplete(cb); +// } +// }); +// } +// return success; +// } +//} + +//QString VirtualDevice::serial() +//{ +// if(!isCompoundDevice()) { +// return devices[0]->serial(); +// } else { +// return cdev->name; +// } +//} + +//QStringList VirtualDevice::availableSAMeasurements() +//{ +// QStringList ret; +// for(unsigned int i=1;i<=info.ports;i++) { +// ret.push_back("PORT"+QString::number(i)); +// } +// return ret; +//} + +//bool VirtualDevice::setSA(const VirtualDevice::SASettings &s, std::function cb) +//{ +// if(!info.supportsSAmode) { +// return false; +// } +// zerospan = s.freqStart == s.freqStop; +// auto& pref = Preferences::getInstance(); +// 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.trackingGeneratorOffset = s.trackingOffset; +// sd.trackingPower = s.trackingPower; + +// if(!isCompoundDevice()) { +// sd.trackingGenerator = s.trackingGenerator ? 1 : 0; +// sd.trackingGeneratorPort = s.trackingPort; +// sd.syncMode = 0; +// sd.syncMaster = 0; +// return devices[0]->Configure(sd, [=](Device::TransmissionResult r){ +// if(cb) { +// cb(r == Device::TransmissionResult::Ack); +// } +// }); +// } else { +// // set the synchronization mode +// switch(cdev->sync) { +// case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break; +// case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break; +// case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break; +// case CompoundDevice::Synchronization::Last: sd.syncMode = 1; break; // should never get here +// } +// // Configure the devices +// results.clear(); +// bool success = true; +// for(unsigned int i=0;iportMapping, i, 0) == s.trackingPort) { +// sd.trackingGenerator = 1; +// sd.trackingGeneratorPort = 0; +// } else if(CompoundDevice::PortMapping::findActiveStage(cdev->portMapping, i, 1) == s.trackingPort) { +// sd.trackingGenerator = 1; +// sd.trackingGeneratorPort = 1; +// } +// } +// sd.syncMaster = i == 0 ? 1 : 0; +// success &= devices[i]->Configure(sd, [=](Device::TransmissionResult r){ +// if(cb) { +// results[devices[i]] = r; +// checkIfAllTransmissionsComplete(cb); +// } +// }); +// } +// return success; +// } +//} + +//QStringList VirtualDevice::availableSGPorts() +//{ +// QStringList ret; +// for(unsigned int i=1;iSendPacket(packet); +// } else { +// // configure all devices +// bool success = true; +// for(unsigned int i=0;i 0) { +// if(cdev->portMapping[s.port-1].device == i) { +// // this device has the active port +// sd.activePort = cdev->portMapping[s.port-1].port+1; +// } +// } +// success &= devices[i]->SendPacket(packet); +// } +// return success; +// } +//} + +//bool VirtualDevice::setIdle(std::function cb) +//{ +// auto success = true; +// results.clear(); +// for(auto dev : devices) { +// success &= dev->SetIdle([=](Device::TransmissionResult r){ +// if(cb) { +// results[dev] = r; +// checkIfAllTransmissionsComplete(cb); +// } +// }); +// } +// return 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: +// case Reference::TypeIn::None: +// 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::None: +// 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::GetAvailableVirtualDevices() +//{ +// auto& pref = Preferences::getInstance(); +// auto ret = Device::GetDevices(); +// // Add compound devices as well +// for(auto vdev : pref.compoundDevices) { +// // check if all serial number required for this compound device are available +// bool serialMissing = false; +// for(auto s : vdev->deviceSerials) { +// if(ret.count(s) == 0) { +// serialMissing = true; +// break; +// } +// } +// if(!serialMissing) { +// // this compound device is available +// ret.insert(vdev->name); +// } +// } +// return ret; +//} + +//VirtualDevice *VirtualDevice::getConnected() +//{ +// return connected; +//} + +//void VirtualDevice::singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res) +//{ +// Q_UNUSED(dev) +// auto &pref = Preferences::getInstance(); +// VNAMeasurement m; +// m.pointNum = res->pointNum; +// m.Z0 = 50.0; +// if(zerospan) { +// m.us = res->us; +// } else { +// m.frequency = res->frequency; +// m.dBm = (double) res->cdBm / 100; +// } +// for(auto map : portStageMapping) { +// // map.first is the port (starts at zero) +// // map.second is the stage at which this port had the stimulus (starts at zero) +// complex ref = res->getValue(map.second, map.first, true); +// for(unsigned int i=0;i input = res->getValue(map.second, i, false); +// if(!std::isnan(ref.real()) && !std::isnan(input.real())) { +// // got both required measurements +// QString name = "S"+QString::number(i+1)+QString::number(map.first+1); +// m.measurements[name] = input / ref; +// } +// if(pref.Debug.makeRawReceiverValuesAvailable) { +// QString name = "RawPort"+QString::number(i+1)+"Stage"+QString::number(map.first); +// m.measurements[name] = input; +// name = "RawPort"+QString::number(i+1)+"Stage"+QString::number(map.first)+"Ref"; +// m.measurements[name] = res->getValue(map.second, i, true); +// } +// } +// } +// delete res; +// emit VNAmeasurementReceived(m); +//} + +//void VirtualDevice::compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data) +//{ +// if(!compoundVNABuffer.count(data->pointNum)) { +// compoundVNABuffer[data->pointNum] = std::map*>(); +// } +// auto &buf = compoundVNABuffer[data->pointNum]; +// buf[dev] = data; +// if(buf.size() == devices.size()) { +// // Got datapoints from all devices, can create merged VNA result +// VNAMeasurement m; +// m.pointNum = data->pointNum; +// m.Z0 = 50.0; +// if(zerospan) { +// m.us = data->us; +// } else { +// m.frequency = data->frequency; +// m.dBm = (double) data->cdBm / 100; +// } +// // assemble data +// for(auto map : portStageMapping) { +// // map.first is the port (starts at zero) +// // map.second is the stage at which this port had the stimulus (starts at zero) + +// // figure out which device had the stimulus for the port... +// auto stimulusDev = devices[cdev->portMapping[map.first].device]; +// // ...and which device port was used for the stimulus... +// auto stimulusDevPort = cdev->portMapping[map.first].port; +// // ...grab the reference receiver data +// complex ref = buf[stimulusDev]->getValue(map.second, stimulusDevPort, true); + +// // for all ports of the compound device... +// for(unsigned int i=0;iportMapping.size();i++) { +// // ...figure out which physical device and port was used for this input... +// auto inputDevice = devices[cdev->portMapping[i].device]; +// // ...and grab the data +// auto inputPort = cdev->portMapping[i].port; +// complex input = buf[inputDevice]->getValue(map.second, inputPort, false); +// if(!std::isnan(ref.real()) && !std::isnan(input.real())) { +// // got both required measurements +// QString name = "S"+QString::number(i+1)+QString::number(map.first+1); +// auto S = input / ref; +// if(inputDevice != stimulusDev) { +// // can't use phase information when measuring across devices +// S = abs(S); +// } +// m.measurements[name] = S; +// } +// } +// } + +// emit VNAmeasurementReceived(m); + +// // Clear this and all (incomplete) older datapoint buffers +// int pointNum = data->pointNum; +// auto it = compoundVNABuffer.begin(); +// while(it != compoundVNABuffer.end()) { +// if(it->first <= pointNum) { +// for(auto d : it->second) { +// delete d.second; +// } +// it = compoundVNABuffer.erase(it); +// } else { +// it++; +// } +// } +// } +//} + +//void VirtualDevice::singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res) +//{ +// Q_UNUSED(dev) +// 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); +//} + +//void VirtualDevice::compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res) +//{ +// if(!compoundSABuffer.count(res.pointNum)) { +// compoundSABuffer[res.pointNum] = std::map(); +// } +// auto &buf = compoundSABuffer[res.pointNum]; +// buf[dev] = res; +// if(buf.size() == devices.size()) { +// // Got datapoints from all devices, can create merged VNA result +// SAMeasurement m; +// m.pointNum = res.pointNum; +// if(zerospan) { +// m.us = res.us; +// } else { +// m.frequency = res.frequency; +// } +// // assemble data +// for(unsigned int port=0;portportMapping.size();port++) { +// auto device = devices[cdev->portMapping[port].device]; +// auto devicePort = cdev->portMapping[port].port; + +// QString name = "PORT"+QString::number(port+1); +// if(devicePort == 0) { +// m.measurements[name] = buf[device].port1; +// } else { +// m.measurements[name] = buf[device].port2; +// } +// } + +// emit SAmeasurementReceived(m); + +// // Clear this and all (incomplete) older datapoint buffers +// auto it = compoundSABuffer.begin(); +// while(it != compoundSABuffer.end()) { +// if(it->first <= res.pointNum) { +// it = compoundSABuffer.erase(it); +// } else { +// it++; +// } +// } +// } +//} + +//void VirtualDevice::compoundInfoUpdated(Device *dev) +//{ +// compoundInfoBuffer[dev] = dev->Info(); +// if(compoundInfoBuffer.size() == devices.size()) { +// // got information of all devices +// info = Info(devices[0]); +// for(unsigned int i=1;isync == CompoundDevice::Synchronization::ExtRef) { +// // can't use the external reference if it is used for synchronization +// info.supportsExtRef = false; +// } +// info.ports = cdev->portMapping.size(); +// emit InfoUpdated(); +// } +//} + +//void VirtualDevice::compoundStatusUpdated(Device *dev) +//{ +// compoundStatusBuffer[dev] = dev->StatusV1(); +// if(compoundStatusBuffer.size() == devices.size()) { +// // got status of all devices +// status = Status(devices[0]); +// for(unsigned int i=1;i cb) +//{ +// if(results.size() == devices.size()) { +// // got all responses +// bool success = true; +// for(auto res : results) { +// if(res.second != Device::TransmissionResult::Ack) { +// success = false; +// break; +// } +// } +// if(cb) { +// cb(success); +// } +// } +//} + +//Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2) const +//{ +// Sparam S; +// S.m11 = measurements.at("S"+QString::number(port1)+QString::number(port1)); +// S.m12 = measurements.at("S"+QString::number(port1)+QString::number(port2)); +// S.m21 = measurements.at("S"+QString::number(port2)+QString::number(port1)); +// S.m22 = measurements.at("S"+QString::number(port2)+QString::number(port2)); +// return S; +//} + +//void VirtualDevice::VNAMeasurement::fromSparam(Sparam S, int port1, int port2) +//{ +// QString s11 = "S"+QString::number(port1)+QString::number(port1); +// QString s12 = "S"+QString::number(port1)+QString::number(port2); +// QString s21 = "S"+QString::number(port2)+QString::number(port1); +// QString s22 = "S"+QString::number(port2)+QString::number(port2); +// if(measurements.count(s11)) { +// measurements[s11] = S.m11; +// } +// if(measurements.count(s12)) { +// measurements[s12] = S.m12; +// } +// if(measurements.count(s21)) { +// measurements[s21] = S.m21; +// } +// if(measurements.count(s22)) { +// measurements[s22] = S.m22; +// } +//} + +//VirtualDevice::VNAMeasurement VirtualDevice::VNAMeasurement::interpolateTo(const VirtualDevice::VNAMeasurement &to, double a) +//{ +// VNAMeasurement ret; +// ret.frequency = frequency * (1.0 - a) + to.frequency * a; +// ret.dBm = dBm * (1.0 - a) + to.dBm * a; +// ret.Z0 = Z0 * (1.0 - a) + to.Z0 * a; +// for(auto m : measurements) { +// if(to.measurements.count(m.first) == 0) { +// throw runtime_error("Nothing to interpolate to, expected measurement +\""+m.first.toStdString()+"\""); +// } +// ret.measurements[m.first] = measurements[m.first] * (1.0 - a) + to.measurements.at(m.first) * a; +// } +// return ret; +//} + +//VirtualDevice::Info::Info() +//{ +// 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; +// supportsExtRef = true; +// Limits = { +// .minFreq = 0, +// .maxFreq = 6000000000, +// .maxFreqHarmonic = 18000000000, +// .minIFBW = 10, +// .maxIFBW = 1000000, +// .maxPoints = 10000, +// .mindBm = -100, +// .maxdBm = 30, +// .minRBW = 1, +// .maxRBW = 1000000, +// }; +//} + +//VirtualDevice::Info::Info(Device *dev) +//{ +// auto info = dev->Info(); +// ProtocolVersion = info.ProtocolVersion; +// FW_major = info.FW_major; +// FW_minor = info.FW_minor; +// FW_patch = info.FW_patch; +// hardware_version = info.hardware_version; +// HW_Revision = info.HW_Revision; +// ports = 2; +// supportsVNAmode = true; +// supportsSAmode = true; +// supportsSGmode = true; +// supportsExtRef = true; +// Limits.minFreq = info.limits_minFreq; +// Limits.maxFreq = info.limits_maxFreq; +// Limits.maxFreqHarmonic = info.limits_maxFreqHarmonic; +// Limits.minIFBW = info.limits_minIFBW; +// Limits.maxIFBW = info.limits_maxIFBW; +// Limits.maxPoints = info.limits_maxPoints; +// Limits.mindBm = (double) info.limits_cdbm_min / 100; +// Limits.maxdBm = (double) info.limits_cdbm_max / 100; +// Limits.minRBW = info.limits_minRBW; +// Limits.maxRBW = info.limits_maxRBW; +//} + +//void VirtualDevice::Info::subset(const VirtualDevice::Info &merge) +//{ +// if((merge.ProtocolVersion != ProtocolVersion) +// || (merge.FW_major != FW_major) +// || (merge.FW_minor != FW_minor) +// || (merge.FW_patch != FW_patch)) { +// throw runtime_error("Incompatible device, unable to create compound device. All devices must run the same firmware version."); +// } +// ports += merge.ports; +// supportsVNAmode &= merge.supportsVNAmode; +// supportsSGmode &= merge.supportsSGmode; +// supportsSAmode &= merge.supportsSAmode; +// supportsExtRef &= merge.supportsExtRef; +// Limits.minFreq = max(Limits.minFreq, merge.Limits.minFreq); +// Limits.maxFreq = min(Limits.maxFreq, merge.Limits.maxFreq); +// Limits.maxFreqHarmonic = min(Limits.maxFreqHarmonic, merge.Limits.maxFreqHarmonic); +// Limits.minIFBW = max(Limits.minIFBW, merge.Limits.minIFBW); +// Limits.maxIFBW = min(Limits.maxIFBW, merge.Limits.maxIFBW); +// Limits.maxPoints = min(Limits.maxPoints, merge.Limits.maxPoints); +// Limits.mindBm = max(Limits.mindBm, merge.Limits.mindBm); +// Limits.maxdBm = min(Limits.maxdBm, merge.Limits.maxdBm); +// Limits.minRBW = max(Limits.minRBW, merge.Limits.minRBW); +// Limits.maxRBW = min(Limits.maxRBW, merge.Limits.maxRBW); +//} + +//VirtualDevice::Status::Status() +//{ +// statusString = ""; +// overload = false; +// unlocked = false; +// unlevel = false; +// extRef = false; +//} + +//VirtualDevice::Status::Status(Device *dev) +//{ +// auto status = dev->StatusV1(); +// statusString = dev->getLastDeviceInfoString(); +// overload = status.ADC_overload; +// unlevel = status.unlevel; +// unlocked = !status.LO1_locked || !status.source_locked; +// extRef = status.extRefInUse; +//} + +//void VirtualDevice::Status::merge(const VirtualDevice::Status &merge) +//{ +// statusString += " / "+merge.statusString; +// overload |= merge.overload; +// unlevel |= merge.unlevel; +// unlocked |= merge.unlocked; +// extRef &= merge.extRef; +//} diff --git a/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.h b/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.h index 4fc9ee8..5ec2a3a 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.h +++ b/Software/PC_Application/LibreVNA-GUI/Device/virtualdevice.h @@ -1,220 +1,220 @@ -#ifndef VIRTUALDEVICE_H -#define VIRTUALDEVICE_H +//#ifndef VIRTUALDEVICE_H +//#define VIRTUALDEVICE_H -#include "device.h" -#include "Tools/parameters.h" -#include "compounddevice.h" +//#include "device.h" +//#include "Tools/parameters.h" +//#include "compounddevice.h" -#include -#include +//#include +//#include -#include +//#include -class VirtualDevice : public QObject -{ - Q_OBJECT -public: - VirtualDevice(QString serial = ""); - ~VirtualDevice(); +//class VirtualDevice : public QObject +//{ +// Q_OBJECT +//public: +// VirtualDevice(QString serial = ""); +// ~VirtualDevice(); - class Info { - public: - Info(); - Info(Device *dev); +// class Info { +// public: +// Info(); +// Info(Device *dev); - void subset(const Info &merge); +// void subset(const Info &merge); - uint16_t ProtocolVersion; - uint8_t FW_major; - uint8_t FW_minor; - uint8_t FW_patch; - uint8_t hardware_version; - char HW_Revision; - unsigned int ports; - bool supportsVNAmode; - bool supportsSAmode; - bool supportsSGmode; - bool supportsExtRef; - struct { - double minFreq, maxFreq, maxFreqHarmonic; - double minIFBW, maxIFBW; - unsigned int maxPoints; - double mindBm; - double maxdBm; - double minRBW, maxRBW; - } Limits; - }; +// uint16_t ProtocolVersion; +// uint8_t FW_major; +// uint8_t FW_minor; +// uint8_t FW_patch; +// uint8_t hardware_version; +// char HW_Revision; +// unsigned int ports; +// bool supportsVNAmode; +// bool supportsSAmode; +// bool supportsSGmode; +// bool supportsExtRef; +// struct { +// double minFreq, maxFreq, maxFreqHarmonic; +// double minIFBW, maxIFBW; +// unsigned int maxPoints; +// double mindBm; +// double maxdBm; +// double minRBW, maxRBW; +// } Limits; +// }; - class Status { - public: - Status(); - Status(Device *dev); +// class Status { +// public: +// Status(); +// Status(Device *dev); - void merge(const Status &merge); +// void merge(const Status &merge); - QString statusString; - bool overload; - bool unlocked; - bool unlevel; - bool extRef; - }; +// QString statusString; +// bool overload; +// bool unlocked; +// bool unlevel; +// bool extRef; +// }; - static void RegisterTypes(); +// static void RegisterTypes(); - void initialize(); // call this after creating the virtual device and all connections to signals have been made +// void initialize(); // call this after creating the virtual device and all connections to signals have been made - bool isCompoundDevice() const; - Device *getDevice(); - CompoundDevice *getCompoundDevice(); - std::vector getDevices(); - const Info& getInfo() const; - static VirtualDevice::Info getInfo(VirtualDevice *vdev); - const Status &getStatus() const; - static VirtualDevice::Status getStatus(VirtualDevice *vdev); +// bool isCompoundDevice() const; +// Device *getDevice(); +// CompoundDevice *getCompoundDevice(); +// std::vector getDevices(); +// const Info& getInfo() const; +// static VirtualDevice::Info getInfo(VirtualDevice *vdev); +// const Status &getStatus() const; +// static VirtualDevice::Status getStatus(VirtualDevice *vdev); - class VNASettings { - public: - double freqStart, freqStop; - double dBmStart, dBmStop; - double IFBW; - int points; - bool logSweep; - std::vector excitedPorts; // port count starts at one - }; - class VNAMeasurement { - public: - unsigned int pointNum; - double Z0; - 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; +// class VNASettings { +// public: +// double freqStart, freqStop; +// double dBmStart, dBmStop; +// double IFBW; +// int points; +// bool logSweep; +// std::vector excitedPorts; // port count starts at one +// }; +// class VNAMeasurement { +// public: +// unsigned int pointNum; +// double Z0; +// 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; - Sparam toSparam(int port1, int port2) const; - void fromSparam(Sparam S, int port1, int port2); - VNAMeasurement interpolateTo(const VNAMeasurement &to, double a); - }; +// Sparam toSparam(int port1, int port2) const; +// void fromSparam(Sparam S, int port1, int port2); +// VNAMeasurement interpolateTo(const VNAMeasurement &to, double a); +// }; - QStringList availableVNAMeasurements(); - bool setVNA(const VNASettings &s, std::function cb = nullptr); - QString serial(); +// 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 - }; +// 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; // counting starts at zero - double trackingOffset; - double trackingPower; - }; - class SAMeasurement { - public: - int pointNum; - union { - struct { - // for non-zero span - double frequency; - }; - struct { - // for zero span - double us; // time in us since first datapoint - }; - }; - std::map measurements; - }; +// double freqStart, freqStop; +// double RBW; +// int points; +// Window window; +// Detector detector; +// bool signalID; +// bool trackingGenerator; +// int trackingPort; // counting starts at zero +// double trackingOffset; +// double trackingPower; +// }; +// class SAMeasurement { +// public: +// int pointNum; +// union { +// struct { +// // for non-zero span +// double frequency; +// }; +// 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); +// QStringList availableSAMeasurements(); +// bool setSA(const SASettings &s, std::function cb = nullptr); - class SGSettings { - public: - double freq; - double dBm; - int port; // starts at one, set to zero to disable all ports - }; +// class SGSettings { +// public: +// double freq; +// double dBm; +// int port; // starts at one, set to zero to disable all ports +// }; - QStringList availableSGPorts(); - bool setSG(const SGSettings &s); +// QStringList availableSGPorts(); +// bool setSG(const SGSettings &s); - bool setIdle(std::function cb = nullptr); +// bool setIdle(std::function cb = nullptr); - QStringList availableExtRefInSettings(); - QStringList availableExtRefOutSettings(); +// QStringList availableExtRefInSettings(); +// QStringList availableExtRefOutSettings(); - bool setExtRef(QString option_in, QString option_out); +// bool setExtRef(QString option_in, QString option_out); - static std::set GetAvailableVirtualDevices(); - static VirtualDevice* getConnected(); +// static std::set GetAvailableVirtualDevices(); +// static VirtualDevice* getConnected(); - static constexpr unsigned int maximumSupportedPorts = 8; +// static constexpr unsigned int maximumSupportedPorts = 8; -signals: - void VNAmeasurementReceived(VNAMeasurement m); - void SAmeasurementReceived(SAMeasurement m); - void ConnectionLost(); - void InfoUpdated(); - void StatusUpdated(Status status); - void LogLineReceived(QString line); - void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol); +//signals: +// void VNAmeasurementReceived(VNAMeasurement m); +// void SAmeasurementReceived(SAMeasurement m); +// void ConnectionLost(); +// void InfoUpdated(); +// void StatusUpdated(Status status); +// void LogLineReceived(QString line); +// void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol); -private slots: - void singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res); - void compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data); - void singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res); - void compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res); - void compoundInfoUpdated(Device *dev); - void compoundStatusUpdated(Device *dev); -private: - void checkIfAllTransmissionsComplete(std::function cb = nullptr); +//private slots: +// void singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res); +// void compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data); +// void singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res); +// void compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res); +// void compoundInfoUpdated(Device *dev); +// void compoundStatusUpdated(Device *dev); +//private: +// void checkIfAllTransmissionsComplete(std::function cb = nullptr); - Info info; - Status status; - std::vector devices; - bool zerospan; +// Info info; +// Status status; +// std::vector devices; +// bool zerospan; - std::map results; +// std::map results; - CompoundDevice *cdev; +// CompoundDevice *cdev; - std::map*>> compoundVNABuffer; - std::map> compoundSABuffer; - std::map compoundInfoBuffer; - std::map compoundStatusBuffer; +// std::map*>> compoundVNABuffer; +// std::map> compoundSABuffer; +// std::map compoundInfoBuffer; +// std::map compoundStatusBuffer; - std::map portStageMapping; // maps from excitedPort (count starts at zero) to stage (count starts at zero) -}; +// std::map portStageMapping; // maps from excitedPort (count starts at zero) to stage (count starts at zero) +//}; -Q_DECLARE_METATYPE(VirtualDevice::Status) -Q_DECLARE_METATYPE(VirtualDevice::VNAMeasurement) -Q_DECLARE_METATYPE(VirtualDevice::SAMeasurement) +//Q_DECLARE_METATYPE(VirtualDevice::Status) +//Q_DECLARE_METATYPE(VirtualDevice::VNAMeasurement) +//Q_DECLARE_METATYPE(VirtualDevice::SAMeasurement) -#endif // VIRTUALDEVICE_H +//#endif // VIRTUALDEVICE_H diff --git a/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp index 8df6a96..a495ad5 100644 --- a/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -499,18 +499,18 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m) for(auto m : m_avg.measurements) { normalize.portCorrection[m.first].push_back(m.second); } - if(m_avg.pointNum == DeviceDriver::getActiveDriver()->getSApoints() - 1) { + if(m_avg.pointNum == DeviceDriver::SApoints() - 1) { // this was the last point normalize.measuring = false; normalize.f_start = settings.freqStart; normalize.f_stop = settings.freqStop; - normalize.points = DeviceDriver::getActiveDriver()->getSApoints(); + normalize.points = DeviceDriver::SApoints(); EnableNormalization(true); qDebug() << "Normalization measurement complete"; } } } - int percentage = (((average.currentSweep() - 1) * 100) + (m_avg.pointNum + 1) * 100 / DeviceDriver::getActiveDriver()->getSApoints()) / averages; + int percentage = (((average.currentSweep() - 1) * 100) + (m_avg.pointNum + 1) * 100 / DeviceDriver::SApoints()) / averages; normalize.dialog.setValue(percentage); } @@ -524,7 +524,7 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m) traceModel.addSAData(m_avg, settings); emit dataChanged(); - if(m_avg.pointNum == DeviceDriver::getActiveDriver()->getSApoints() - 1) { + if(m_avg.pointNum == DeviceDriver::SApoints() - 1) { UpdateAverageCount(); markerModel->updateMarkers(); } @@ -771,7 +771,8 @@ void SpectrumAnalyzer::EnableNormalization(bool enabled) if(enabled != normalize.active) { if(enabled) { // check if measurements already taken - if(normalize.f_start == settings.freqStart && normalize.f_stop == settings.freqStop && normalize.points == settings.points) { + if(normalize.f_start == settings.freqStart && normalize.f_stop == settings.freqStop + && normalize.points == DeviceDriver::SApoints()) { // same settings as with normalization measurement, can enable normalize.active = true; } else { @@ -856,7 +857,7 @@ void SpectrumAnalyzer::ConfigureDevice() if(normalize.active) { // check if normalization is still valid - if(normalize.f_start != settings.freqStart || normalize.f_stop != settings.freqStop || normalize.points != DeviceDriver::getActiveDriver()->getSApoints()) { + if(normalize.f_start != settings.freqStart || normalize.f_stop != settings.freqStop || normalize.points != DeviceDriver::SApoints()) { // normalization was taken at different settings, disable EnableNormalization(false); InformationBox::ShowMessage("Information", "Normalization was disabled because the span has been changed"); @@ -869,7 +870,7 @@ void SpectrumAnalyzer::ConfigureDevice() emit sweepStopped(); changingSettings = false; } - average.reset(DeviceDriver::getActiveDriver()->getSApoints()); + average.reset(DeviceDriver::SApoints()); UpdateAverageCount(); traceModel.clearLiveData(); emit traceModel.SpanChanged(settings.freqStart, settings.freqStop); @@ -890,7 +891,7 @@ void SpectrumAnalyzer::ConfigureDevice() void SpectrumAnalyzer::ResetLiveTraces() { - average.reset(DeviceDriver::getActiveDriver()->getSApoints()); + average.reset(DeviceDriver::SApoints()); traceModel.clearLiveData(); UpdateAverageCount(); } diff --git a/Software/PC_Application/LibreVNA-GUI/Traces/traceeditdialog.cpp b/Software/PC_Application/LibreVNA-GUI/Traces/traceeditdialog.cpp index 455ab50..a5cc70c 100644 --- a/Software/PC_Application/LibreVNA-GUI/Traces/traceeditdialog.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Traces/traceeditdialog.cpp @@ -125,12 +125,11 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : } VNAtrace = Trace::isVNAParameter(t.liveParameter()); - if(VirtualDevice::getConnected()) { - qDebug() << VirtualDevice::getConnected(); + if(DeviceDriver::getActiveDriver()) { if(VNAtrace) { - ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableVNAMeasurements()); + ui->CLiveParam->addItems(DeviceDriver::getActiveDriver()->availableVNAMeasurements()); } else { - ui->CLiveParam->addItems(VirtualDevice::getConnected()->availableSAMeasurements()); + ui->CLiveParam->addItems(DeviceDriver::getActiveDriver()->availableSAMeasurements()); } } diff --git a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp index 2cf0f43..784db25 100644 --- a/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp +++ b/Software/PC_Application/LibreVNA-GUI/VNA/vna.cpp @@ -1430,8 +1430,8 @@ void VNA::SetupSCPI() void VNA::ConstrainAndUpdateFrequencies() { - if(settings.Freq.stop > DeviceDriver::getInfo(window->getDevice()).Limits.VNA.minFreq) { - settings.Freq.stop = DeviceDriver::getInfo(window->getDevice()).Limits.VNA.minFreq; + if(settings.Freq.stop > DeviceDriver::getInfo(window->getDevice()).Limits.VNA.maxFreq) { + settings.Freq.stop = DeviceDriver::getInfo(window->getDevice()).Limits.VNA.maxFreq; } if(settings.Freq.start > settings.Freq.stop) { settings.Freq.start = settings.Freq.stop; diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp index b6bb043..280a384 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp @@ -60,6 +60,7 @@ #include #include #include +#include using namespace std; @@ -84,9 +85,6 @@ AppWindow::AppWindow(QWidget *parent) // qDebug().setVerbosity(0); qDebug() << "Application start"; - // Register device drivers - deviceDrivers.push_back(new LibreVNAUSBDriver()); - this->setWindowIcon(QIcon(":/app/logo.png")); parser.setApplicationDescription(qlibrevnaApp->applicationName()); @@ -106,6 +104,15 @@ AppWindow::AppWindow(QWidget *parent) } else { Preferences::getInstance().load(); } + + // Register device drivers + deviceDrivers.push_back(new LibreVNAUSBDriver()); + + for(auto driver : deviceDrivers) { + driver->registerTypes(); + Preferences::getInstance().load(driver->driverSpecificSettings()); + } + device = nullptr; // vdevice = nullptr; modeHandler = nullptr; @@ -184,9 +191,9 @@ AppWindow::AppWindow(QWidget *parent) } // List available devices UpdateDeviceList(); - if(pref.Startup.ConnectToFirstDevice) { + if(pref.Startup.ConnectToFirstDevice && deviceList.size() > 0) { // at least one device available - ConnectToDevice(); + ConnectToDevice(deviceList[0].serial); } if(parser.isSet("setup")) { @@ -325,10 +332,13 @@ void AppWindow::closeEvent(QCloseEvent *event) delete modeHandler; modeHandler = nullptr; pref.store(); + for(auto driver : deviceDrivers) { + Preferences::getInstance().store(driver->driverSpecificSettings()); + } QMainWindow::closeEvent(event); } -bool AppWindow::ConnectToDevice(QString serial) +bool AppWindow::ConnectToDevice(QString serial, DeviceDriver *driver) { if(serial.isEmpty()) { qDebug() << "Trying to connect to any device"; @@ -341,17 +351,25 @@ bool AppWindow::ConnectToDevice(QString serial) } try { qDebug() << "Attempting to connect to device..."; - for(auto driver : deviceDrivers) { - if(driver->GetAvailableDevices().count(serial)) { + for(auto d : deviceDrivers) { + if(driver && driver != d) { + // not the specified driver + continue; + } + if(d->GetAvailableDevices().count(serial)) { // this driver can connect to the device - if(driver->connectDevice(serial)) { - device = driver; + if(d->connectDevice(serial)) { + device = d; } else { - // failed to connect - // TODO show error message + break; } } } + if(!device) { + // failed to connect + InformationBox::ShowError("Failed to connect", "Could not connect to "+serial); + return false; + } UpdateStatusBar(AppWindow::DeviceStatusBar::Connected); connect(device, &DeviceDriver::InfoUpdated, this, &AppWindow::DeviceInfoUpdated); connect(device, &DeviceDriver::LogLineReceived, &deviceLog, &DeviceLog::addLine); @@ -368,8 +386,11 @@ bool AppWindow::ConnectToDevice(QString serial) // } ui->actionPreset->setEnabled(true); + DeviceEntry e; + e.serial = device->getSerial(); + e.driver = device; for(auto d : deviceActionGroup->actions()) { - if(d->text() == device->getSerial()) { + if(d->text() == e.toString()) { d->blockSignals(true); d->setChecked(true); d->blockSignals(false); @@ -476,8 +497,10 @@ void AppWindow::SetupSCPI() })); scpi_dev->add(new SCPICommand("LIST", nullptr, [=](QStringList) -> QString { QString ret; - for(auto d : VirtualDevice::GetAvailableVirtualDevices()) { - ret += d + ","; + for(auto driver : deviceDrivers) { + for(auto d : driver->GetAvailableDevices()) { + ret += d + ","; + } } // remove last comma ret.chop(1); @@ -933,33 +956,42 @@ int AppWindow::UpdateDeviceList() { deviceActionGroup->setExclusive(true); ui->menuConnect_to->clear(); - std::set devices; + deviceList.clear(); for(auto driver : deviceDrivers) { - devices.merge(driver->GetAvailableDevices()); + for(auto serial : driver->GetAvailableDevices()) { + DeviceEntry e; + e.driver = driver; + e.serial = serial; + deviceList.push_back(e); + } } if(device) { - devices.insert(device->getSerial()); + DeviceEntry e; + e.driver = device; + e.serial = device->getSerial(); + if(std::find(deviceList.begin(), deviceList.end(), e) == deviceList.end()) { + // connected device is not in list (this may happen if the driver does not detect a connected device as "available") + deviceList.push_back(e); + } } int available = 0; bool found = false; - if(devices.size()) { - for(auto d : devices) { - if(!parser.value("device").isEmpty() && parser.value("device") != d) { - // specified device does not match, ignore - continue; - } - auto connectAction = ui->menuConnect_to->addAction(d); - connectAction->setCheckable(true); - connectAction->setActionGroup(deviceActionGroup); - if(device && d == device->getSerial()) { - connectAction->setChecked(true); - } - connect(connectAction, &QAction::triggered, [this, d]() { - ConnectToDevice(d); - }); - found = true; - available++; + for(auto d : deviceList) { + if(!parser.value("device").isEmpty() && parser.value("device") != d.serial) { + // specified device does not match, ignore + continue; } + auto connectAction = ui->menuConnect_to->addAction(d.toString()); + connectAction->setCheckable(true); + connectAction->setActionGroup(deviceActionGroup); + if(device && d.serial == device->getSerial()) { + connectAction->setChecked(true); + } + connect(connectAction, &QAction::triggered, [this, d]() { + ConnectToDevice(d.serial, d.driver); + }); + found = true; + available++; } ui->menuConnect_to->setEnabled(found); qDebug() << "Updated device list, found" << available; @@ -1055,12 +1087,16 @@ void AppWindow::ShowUSBLog() // } //} -void AppWindow::DeviceStatusUpdated(VirtualDevice::Status status) +void AppWindow::DeviceStatusUpdated() { - lDeviceInfo.setText(status.statusString); - lADCOverload.setVisible(status.overload); - lUnlevel.setVisible(status.unlevel); - lUnlock.setVisible(status.unlocked); + lDeviceInfo.setText(device->getStatus()); +} + +void AppWindow::DeviceFlagsUpdated() +{ + lADCOverload.setVisible(device->asserted(DeviceDriver::Flag::Overload)); + lUnlevel.setVisible(device->asserted(DeviceDriver::Flag::Unlevel)); + lUnlock.setVisible(device->asserted(DeviceDriver::Flag::Unlocked)); } void AppWindow::DeviceInfoUpdated() @@ -1320,3 +1356,31 @@ void AppWindow::UpdateStatusBar(DeviceStatusBar status) } } + +QString AppWindow::DeviceEntry::toString() +{ + return serial + " (" + driver->getDriverName()+")"; +} + +AppWindow::DeviceEntry AppWindow::DeviceEntry::fromString(QString s, std::vector drivers) +{ + DeviceEntry e; + QStringList parts = s.split(" "); + if(parts.size() < 2) { + // invalid string + e.serial = ""; + e.driver = nullptr; + } else { + e.serial = parts[0]; + e.driver = nullptr; + parts[1].chop(1); + auto driverName = parts[1].mid(1); + for(auto d : drivers) { + if(d->getDriverName() == driverName) { + e.driver = d; + break; + } + } + } + return e; +} diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.h b/Software/PC_Application/LibreVNA-GUI/appwindow.h index a1bab00..de63452 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.h +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.h @@ -58,7 +58,7 @@ public slots: protected: void closeEvent(QCloseEvent *event) override; private slots: - bool ConnectToDevice(QString serial = QString()); + bool ConnectToDevice(QString serial = QString(), DeviceDriver *driver = nullptr); void DisconnectDevice(); int UpdateDeviceList(); // void StartManualControl(); @@ -67,8 +67,9 @@ private slots: // void UpdateAcquisitionFrequencies(); void ShowUSBLog(); // void StartFirmwareUpdateDialog(); - void DeviceNeedsUpdate(int reported, int expected); - void DeviceStatusUpdated(VirtualDevice::Status status); +// void DeviceNeedsUpdate(int reported, int expected); + void DeviceStatusUpdated(); + void DeviceFlagsUpdated(); void DeviceInfoUpdated(); // void SourceCalibrationDialog(); // void ReceiverCalibrationDialog(); @@ -109,6 +110,20 @@ private: std::vector deviceDrivers; DeviceDriver *device; + class DeviceEntry { + public: + QString toString(); + static DeviceEntry fromString(QString s, std::vector drivers); + bool operator==(const DeviceEntry& rhs) { + return serial == rhs.serial && driver == rhs.driver; + } + + QString serial; + DeviceDriver *driver; + }; + + std::vector deviceList; + DeviceLog deviceLog; QString deviceSerial; QActionGroup *deviceActionGroup; diff --git a/Software/PC_Application/LibreVNA-GUI/main.cpp b/Software/PC_Application/LibreVNA-GUI/main.cpp index 5b24c01..ecd9ff9 100644 --- a/Software/PC_Application/LibreVNA-GUI/main.cpp +++ b/Software/PC_Application/LibreVNA-GUI/main.cpp @@ -21,7 +21,6 @@ int main(int argc, char *argv[]) { qSetMessagePattern("%{time process}: [%{type}] %{message}"); Device::RegisterTypes(); - VirtualDevice::RegisterTypes(); app = new QApplication(argc, argv); QCoreApplication::setOrganizationName("LibreVNA"); diff --git a/Software/PC_Application/LibreVNA-GUI/preferences.cpp b/Software/PC_Application/LibreVNA-GUI/preferences.cpp index 90fc33e..9ce617d 100644 --- a/Software/PC_Application/LibreVNA-GUI/preferences.cpp +++ b/Software/PC_Application/LibreVNA-GUI/preferences.cpp @@ -163,14 +163,14 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : }); // Compound device page - connect(ui->compoundList, &QListWidget::currentRowChanged, [=](){ - if(VirtualDevice::getConnected() && VirtualDevice::getConnected()->getCompoundDevice() == p->compoundDevices[ui->compoundList->currentRow()]) { - // can't remove the device we are connected to - ui->compoundDelete->setEnabled(false); - } else { - ui->compoundDelete->setEnabled(true); - } - }); +// connect(ui->compoundList, &QListWidget::currentRowChanged, [=](){ +// if(VirtualDevice::getConnected() && VirtualDevice::getConnected()->getCompoundDevice() == p->compoundDevices[ui->compoundList->currentRow()]) { +// // can't remove the device we are connected to +// ui->compoundDelete->setEnabled(false); +// } else { +// ui->compoundDelete->setEnabled(true); +// } +// }); connect(ui->compoundList, &QListWidget::doubleClicked, [=](){ auto index = ui->compoundList->currentRow(); if(index >= 0 && index < (int) p->compoundDevices.size()) { @@ -195,22 +195,22 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : }); d->show(); }); - connect(ui->compoundDelete, &QPushButton::clicked, [=](){ - auto index = ui->compoundList->currentRow(); - if(index >= 0 && index < (int) p->compoundDevices.size()) { - // delete the actual compound device - if(VirtualDevice::getConnected() && VirtualDevice::getConnected()->getCompoundDevice() == p->compoundDevices[index]) { - // can't remove the device we are currently connected to - return; - } - delete p->compoundDevices[index]; - // delete the line in the GUI list - delete ui->compoundList->takeItem(index); - // remove compound device from list - p->compoundDevices.erase(p->compoundDevices.begin() + index); - p->nonTrivialWriting(); - } - }); +// connect(ui->compoundDelete, &QPushButton::clicked, [=](){ +// auto index = ui->compoundList->currentRow(); +// if(index >= 0 && index < (int) p->compoundDevices.size()) { +// // delete the actual compound device +// if(VirtualDevice::getConnected() && VirtualDevice::getConnected()->getCompoundDevice() == p->compoundDevices[index]) { +// // can't remove the device we are currently connected to +// return; +// } +// delete p->compoundDevices[index]; +// // delete the line in the GUI list +// delete ui->compoundList->takeItem(index); +// // remove compound device from list +// p->compoundDevices.erase(p->compoundDevices.begin() + index); +// p->nonTrivialWriting(); +// } +// }); // Debug page ui->DebugMaxUSBlogSize->setUnit("B"); @@ -514,24 +514,32 @@ Preferences::~Preferences() void Preferences::load() { - QSettings settings; // load settings, using default values if not present qInfo() << "Loading preferences"; + load(descr); + nonTrivialParsing(); +} + +void Preferences::load(std::vector descr) +{ + QSettings settings; for(auto d : descr) { try { d.var.setValue(settings.value(d.name, d.def)); -// qDebug() << "Setting" << d.name << "is set to" << d.var.value(); } catch (const exception& e){ d.var.setValue(d.def); -// qDebug() << "Setting" << d.name << "reset to default:" << d.def; } } - nonTrivialParsing(); } void Preferences::store() { nonTrivialWriting(); + store(descr); +} + +void Preferences::store(std::vector descr) +{ QSettings settings; // store settings for(auto d : descr) { diff --git a/Software/PC_Application/LibreVNA-GUI/preferences.h b/Software/PC_Application/LibreVNA-GUI/preferences.h index 34cb523..68e8171 100644 --- a/Software/PC_Application/LibreVNA-GUI/preferences.h +++ b/Software/PC_Application/LibreVNA-GUI/preferences.h @@ -51,7 +51,9 @@ public: Preferences(const Preferences&) = delete; ~Preferences(); void load(); + void load(std::vector descr); void store(); + void store(std::vector descr); void edit(); void setDefault(); diff --git a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro index c543912..f131c66 100644 --- a/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro +++ b/Software/PC_Application/LibreVNA-Test/LibreVNA-Test.pro @@ -32,10 +32,13 @@ SOURCES += \ ../LibreVNA-GUI/Device/compounddevice.cpp \ ../LibreVNA-GUI/Device/compounddeviceeditdialog.cpp \ ../LibreVNA-GUI/Device/device.cpp \ + ../LibreVNA-GUI/Device/devicedriver.cpp \ ../LibreVNA-GUI/Device/devicelog.cpp \ ../LibreVNA-GUI/Device/deviceusblog.cpp \ ../LibreVNA-GUI/Device/deviceusblogview.cpp \ ../LibreVNA-GUI/Device/firmwareupdatedialog.cpp \ + ../LibreVNA-GUI/Device/librevnadriver.cpp \ + ../LibreVNA-GUI/Device/librevnausbdriver.cpp \ ../LibreVNA-GUI/Device/manualcontroldialog.cpp \ ../LibreVNA-GUI/Device/virtualdevice.cpp \ ../LibreVNA-GUI/Generator/generator.cpp \ @@ -199,10 +202,13 @@ HEADERS += \ ../LibreVNA-GUI/Device/compounddevice.h \ ../LibreVNA-GUI/Device/compounddeviceeditdialog.h \ ../LibreVNA-GUI/Device/device.h \ + ../LibreVNA-GUI/Device/devicedriver.h \ ../LibreVNA-GUI/Device/devicelog.h \ ../LibreVNA-GUI/Device/deviceusblog.h \ ../LibreVNA-GUI/Device/deviceusblogview.h \ ../LibreVNA-GUI/Device/firmwareupdatedialog.h \ + ../LibreVNA-GUI/Device/librevnadriver.h \ + ../LibreVNA-GUI/Device/librevnausbdriver.h \ ../LibreVNA-GUI/Device/manualcontroldialog.h \ ../LibreVNA-GUI/Device/virtualdevice.h \ ../LibreVNA-GUI/Generator/generator.h \