From a2389fca135055bf41c1a52dcfe0d397dc7dacc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Sat, 7 Nov 2020 13:22:10 +0100 Subject: [PATCH] Protocol adjustment + exposing settings for DFT --- Software/PC_Application/Device/device.cpp | 66 ++++++++------ Software/PC_Application/Device/device.h | 6 +- .../Generator/signalgenwidget.cpp | 8 +- .../SpectrumAnalyzer/spectrumanalyzer.cpp | 27 +++--- Software/PC_Application/VNA/vna.cpp | 40 +++++---- Software/PC_Application/appwindow.cpp | 32 +++++-- Software/PC_Application/appwindow.h | 3 +- Software/PC_Application/preferences.cpp | 11 +++ Software/PC_Application/preferences.h | 6 +- Software/PC_Application/preferencesdialog.ui | 61 ++++++++++--- Software/VNA_embedded/.cproject | 2 + Software/VNA_embedded/Application/App.cpp | 6 +- .../Application/Communication/Protocol.cpp | 88 ++++++++----------- .../Application/Communication/Protocol.hpp | 42 +++++---- .../VNA_embedded/Application/Hardware.cpp | 59 +++++++------ .../VNA_embedded/Application/Hardware.hpp | 36 +++++--- .../Application/SpectrumAnalyzer.cpp | 22 +++-- Software/VNA_embedded/Application/VNA.cpp | 3 +- Software/VNA_embedded/Makefile | 1 + 19 files changed, 314 insertions(+), 205 deletions(-) diff --git a/Software/PC_Application/Device/device.cpp b/Software/PC_Application/Device/device.cpp index 52c9286..88c598d 100644 --- a/Software/PC_Application/Device/device.cpp +++ b/Software/PC_Application/Device/device.cpp @@ -111,22 +111,40 @@ uint8_t *USBInBuffer::getBuffer() const return buffer; } -static Protocol::DeviceLimits limits = { - .minFreq = 0, - .maxFreq = 6000000000, - .minIFBW = 10, - .maxIFBW = 50000, - .maxPoints = 4501, - .cdbm_min = -4000, - .cdbm_max = 0, - .minRBW = 10, - .maxRBW = 100000, +static constexpr Protocol::DeviceInfo defaultInfo = { + .ProtocolVersion = Protocol::Version, + .FW_major = 0, + .FW_minor = 0, + .FW_patch = 0, + .HW_Revision = '0', + .extRefAvailable = 0, + .extRefInUse = 0, + .FPGA_configured = 0, + .source_locked = 0, + .LO1_locked = 0, + .ADC_overload = 0, + .temp_source = 0, + .temp_LO1 = 0, + .temp_MCU = 0, + .limits_minFreq = 0, + .limits_maxFreq = 6000000000, + .limits_minIFBW = 10, + .limits_maxIFBW = 50000, + .limits_maxPoints = 4501, + .limits_cdbm_min = -4000, + .limits_cdbm_max = 0, + .limits_minRBW = 15, + .limits_maxRBW = 100000, }; +Protocol::DeviceInfo Device::lastInfo = defaultInfo; + Device::Device(QString serial) { qDebug() << "Starting device connection..."; + lastInfo = defaultInfo; + m_handle = nullptr; lastInfoValid = false; libusb_init(&m_context); @@ -182,8 +200,8 @@ Device::Device(QString serial) connect(this, &Device::receivedAnswer, this, &Device::transmissionFinished, Qt::QueuedConnection); transmissionTimer.setSingleShot(true); transmissionActive = false; - // got a new connection, request limits - SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceLimits); + // got a new connection, request info + SendCommandWithoutPayload(Protocol::PacketType::RequestDeviceInfo); } Device::~Device() @@ -282,11 +300,6 @@ std::set Device::GetDevices() return serials; } -Protocol::DeviceLimits Device::Limits() -{ - return limits; -} - void Device::USBHandleThread() { qInfo() << "Receive thread started" << flush; @@ -366,7 +379,7 @@ void Device::SearchDevices(std::function libusb_free_device_list(devList, 1); } -Protocol::DeviceInfo Device::getLastInfo() const +const Protocol::DeviceInfo &Device::Info() { return lastInfo; } @@ -379,8 +392,8 @@ QString Device::getLastDeviceInfoString() } else { ret.append("HW Rev."); ret.append(lastInfo.HW_Revision); - ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor).rightJustified(2, '0')); - ret.append(" Temps: "+QString::number(lastInfo.temperatures.source)+"°C/"+QString::number(lastInfo.temperatures.LO1)+"°C/"+QString::number(lastInfo.temperatures.MCU)+"°C"); + ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor)+"."+QString::number(lastInfo.FW_patch)); + ret.append(" Temps: "+QString::number(lastInfo.temp_source)+"°C/"+QString::number(lastInfo.temp_LO1)+"°C/"+QString::number(lastInfo.temp_MCU)+"°C"); ret.append(" Reference:"); if(lastInfo.extRefInUse) { ret.append("External"); @@ -412,7 +425,13 @@ void Device::ReceivedData() emit SpectrumResultReceived(packet.spectrumResult); break; case Protocol::PacketType::DeviceInfo: - lastInfo = packet.info; + if(packet.info.ProtocolVersion != Protocol::Version) { + if(!lastInfoValid) { + emit NeedsFirmwareUpdate(packet.info.ProtocolVersion, Protocol::Version); + } + } else { + lastInfo = packet.info; + } lastInfoValid = true; emit DeviceInfoUpdated(); break; @@ -424,10 +443,7 @@ void Device::ReceivedData() emit NackReceived(); emit receivedAnswer(TransmissionResult::Nack); break; - case Protocol::PacketType::DeviceLimits: - limits = packet.limits; - break; - default: + default: break; } } while (handled_len > 0); diff --git a/Software/PC_Application/Device/device.h b/Software/PC_Application/Device/device.h index a1905ae..586c496 100644 --- a/Software/PC_Application/Device/device.h +++ b/Software/PC_Application/Device/device.h @@ -65,12 +65,11 @@ public: bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); bool SendCommandWithoutPayload(Protocol::PacketType type); QString serial() const; - Protocol::DeviceInfo getLastInfo() const; + static const Protocol::DeviceInfo& Info(); QString getLastDeviceInfoString(); // Returns serial numbers of all connected devices static std::set GetDevices(); - static Protocol::DeviceLimits Limits(); signals: void DatapointReceived(Protocol::Datapoint); void ManualStatusReceived(Protocol::ManualStatus); @@ -80,6 +79,7 @@ signals: void AckReceived(); void NackReceived(); void LogLineReceived(QString line); + void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol); private slots: void ReceivedData(); void ReceivedLog(); @@ -119,7 +119,7 @@ private: QString m_serial; bool m_connected; std::thread *m_receiveThread; - Protocol::DeviceInfo lastInfo; + static Protocol::DeviceInfo lastInfo; bool lastInfoValid; }; diff --git a/Software/PC_Application/Generator/signalgenwidget.cpp b/Software/PC_Application/Generator/signalgenwidget.cpp index 2ae95de..68735eb 100644 --- a/Software/PC_Application/Generator/signalgenwidget.cpp +++ b/Software/PC_Application/Generator/signalgenwidget.cpp @@ -10,10 +10,10 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) : ui->frequency->setPrefixes(" kMG"); connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) { - if(newval < Device::Limits().minFreq) { - newval = Device::Limits().minFreq; - } else if (newval > Device::Limits().maxFreq) { - newval = Device::Limits().maxFreq; + if(newval < Device::Info().limits_minFreq) { + newval = Device::Info().limits_minFreq; + } else if (newval > Device::Info().limits_maxFreq) { + newval = Device::Info().limits_maxFreq; } ui->frequency->setValueQuiet(newval); emit SettingsChanged(); diff --git a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp index 43c4de3..252cffc 100644 --- a/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp +++ b/Software/PC_Application/SpectrumAnalyzer/spectrumanalyzer.cpp @@ -251,6 +251,13 @@ void SpectrumAnalyzer::SettingsChanged() settings.pointNum = settings.f_stop - settings.f_start + 1; } + auto pref = Preferences::getInstance(); + if(pref.Acquisition.useDFTinSAmode && settings.RBW <= pref.Acquisition.RBWLimitForDFT) { + settings.UseDFT = 1; + } else { + settings.UseDFT = 0; + } + if(window->getDevice()) { window->getDevice()->Configure(settings); } @@ -311,8 +318,8 @@ void SpectrumAnalyzer::SetSpan(double span) void SpectrumAnalyzer::SetFullSpan() { - settings.f_start = Device::Limits().minFreq; - settings.f_stop = Device::Limits().maxFreq; + settings.f_start = Device::Info().limits_minFreq; + settings.f_stop = Device::Info().limits_maxFreq; ConstrainAndUpdateFrequencies(); } @@ -340,10 +347,10 @@ void SpectrumAnalyzer::SpanZoomOut() void SpectrumAnalyzer::SetRBW(double bandwidth) { - if(bandwidth > Device::Limits().maxRBW) { - bandwidth = Device::Limits().maxRBW; - } else if(bandwidth < Device::Limits().minRBW) { - bandwidth = Device::Limits().minRBW; + if(bandwidth > Device::Info().limits_maxRBW) { + bandwidth = Device::Info().limits_maxRBW; + } else if(bandwidth < Device::Info().limits_minRBW) { + bandwidth = Device::Info().limits_minRBW; } settings.RBW = bandwidth; emit RBWChanged(settings.RBW); @@ -365,14 +372,14 @@ void SpectrumAnalyzer::UpdateAverageCount() void SpectrumAnalyzer::ConstrainAndUpdateFrequencies() { - if(settings.f_stop > Device::Limits().maxFreq) { - settings.f_stop = Device::Limits().maxFreq; + if(settings.f_stop > Device::Info().limits_maxFreq) { + settings.f_stop = Device::Info().limits_maxFreq; } if(settings.f_start > settings.f_stop) { settings.f_start = settings.f_stop; } - if(settings.f_start < Device::Limits().minFreq) { - settings.f_start = Device::Limits().minFreq; + if(settings.f_start < Device::Info().limits_minFreq) { + settings.f_start = Device::Info().limits_minFreq; } emit startFreqChanged(settings.f_start); emit stopFreqChanged(settings.f_stop); diff --git a/Software/PC_Application/VNA/vna.cpp b/Software/PC_Application/VNA/vna.cpp index faa07d0..74f91b3 100644 --- a/Software/PC_Application/VNA/vna.cpp +++ b/Software/PC_Application/VNA/vna.cpp @@ -217,7 +217,11 @@ VNA::VNA(AppWindow *window) points->setSingleStep(100); points->setToolTip("Points/sweep"); connect(points, qOverload(&QSpinBox::valueChanged), this, &VNA::SetPoints); - connect(this, &VNA::pointsChanged, points, &QSpinBox::setValue); + connect(this, &VNA::pointsChanged, [=](int p) { + points->blockSignals(true); + points->setValue(p); + points->blockSignals(false); + }); tb_acq->addWidget(new QLabel("Points:")); tb_acq->addWidget(points); @@ -499,8 +503,8 @@ void VNA::SetSpan(double span) void VNA::SetFullSpan() { - settings.f_start = Device::Limits().minFreq; - settings.f_stop = Device::Limits().maxFreq; + settings.f_start = Device::Info().limits_minFreq; + settings.f_stop = Device::Info().limits_maxFreq; ConstrainAndUpdateFrequencies(); } @@ -528,10 +532,10 @@ void VNA::SpanZoomOut() void VNA::SetSourceLevel(double level) { - if(level > Device::Limits().cdbm_max / 100.0) { - level = Device::Limits().cdbm_max / 100.0; - } else if(level < Device::Limits().cdbm_min / 100.0) { - level = Device::Limits().cdbm_min / 100.0; + if(level > Device::Info().limits_cdbm_max / 100.0) { + level = Device::Info().limits_cdbm_max / 100.0; + } else if(level < Device::Info().limits_cdbm_min / 100.0) { + level = Device::Info().limits_cdbm_min / 100.0; } emit sourceLevelChanged(level); settings.cdbm_excitation = level * 100; @@ -540,10 +544,10 @@ void VNA::SetSourceLevel(double level) void VNA::SetPoints(unsigned int points) { - if (points < 2) { + if(points > Device::Info().limits_maxPoints) { + points = Device::Info().limits_maxPoints; + } else if (points < 2) { points = 2; - } else if(points > Device::Limits().maxPoints) { - points = Device::Limits().maxPoints; } emit pointsChanged(points); settings.points = points; @@ -552,10 +556,10 @@ void VNA::SetPoints(unsigned int points) void VNA::SetIFBandwidth(double bandwidth) { - if(bandwidth > Device::Limits().maxIFBW) { - bandwidth = Device::Limits().maxIFBW; - } else if(bandwidth < Device::Limits().minIFBW) { - bandwidth = Device::Limits().minIFBW; + if(bandwidth > Device::Info().limits_maxIFBW) { + bandwidth = Device::Info().limits_maxIFBW; + } else if(bandwidth < Device::Info().limits_minIFBW) { + bandwidth = Device::Info().limits_minIFBW; } settings.if_bandwidth = bandwidth; emit IFBandwidthChanged(bandwidth); @@ -651,14 +655,14 @@ void VNA::StartCalibrationMeasurement(Calibration::Measurement m) void VNA::ConstrainAndUpdateFrequencies() { - if(settings.f_stop > Device::Limits().maxFreq) { - settings.f_stop = Device::Limits().maxFreq; + if(settings.f_stop > Device::Info().limits_maxFreq) { + settings.f_stop = Device::Info().limits_maxFreq; } if(settings.f_start > settings.f_stop) { settings.f_start = settings.f_stop; } - if(settings.f_start < Device::Limits().minFreq) { - settings.f_start = Device::Limits().minFreq; + if(settings.f_start < Device::Info().limits_minFreq) { + settings.f_start = Device::Info().limits_minFreq; } emit startFreqChanged(settings.f_start); emit stopFreqChanged(settings.f_stop); diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp index 15f164b..d421894 100644 --- a/Software/PC_Application/appwindow.cpp +++ b/Software/PC_Application/appwindow.cpp @@ -95,14 +95,7 @@ AppWindow::AppWindow(QWidget *parent) connect(ui->actionDisconnect, &QAction::triggered, this, &AppWindow::DisconnectDevice); connect(ui->actionQuit, &QAction::triggered, this, &AppWindow::close); connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl); - connect(ui->actionFirmware_Update, &QAction::triggered, [=](){ - if(device) { - auto fw_update = new FirmwareUpdateDialog(device); - connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice); - connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice); - fw_update->exec(); - } - }); + connect(ui->actionFirmware_Update, &QAction::triggered, this, &AppWindow::StartFirmwareUpdateDialog); connect(ui->actionPreferences, &QAction::triggered, [=](){ Preferences::getInstance().edit(); // settings might have changed, update necessary stuff @@ -172,6 +165,7 @@ void AppWindow::ConnectToDevice(QString serial) connect(device, &Device::DeviceInfoUpdated, [this]() { lDeviceInfo.setText(device->getLastDeviceInfoString()); }); + connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate); ui->actionDisconnect->setEnabled(true); ui->actionManual_Control->setEnabled(true); ui->actionFirmware_Update->setEnabled(true); @@ -316,6 +310,28 @@ void AppWindow::UpdateReference() device->SendPacket(p); } +void AppWindow::StartFirmwareUpdateDialog() +{ + if(device) { + auto fw_update = new FirmwareUpdateDialog(device); + connect(fw_update, &FirmwareUpdateDialog::DeviceRebooting, this, &AppWindow::DisconnectDevice); + connect(fw_update, &FirmwareUpdateDialog::DeviceRebooted, this, &AppWindow::ConnectToDevice); + fw_update->exec(); + } +} + +void AppWindow::DeviceNeedsUpdate(int reported, int expected) +{ + auto ret = QMessageBox::warning(this, "Warning", + "The device reports are different protocol" + "version (" + QString::number(reported) + ") than expected (" + QString::number(expected) + ").\n" + "A firmware update is strongly suggested. Do you want to update now?", + QMessageBox::Yes | QMessageBox::No); + if (ret == QMessageBox::Yes) { + StartFirmwareUpdateDialog(); + } +} + Device *AppWindow::getDevice() const { return device; diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h index e83c5ff..5d9f42c 100644 --- a/Software/PC_Application/appwindow.h +++ b/Software/PC_Application/appwindow.h @@ -42,7 +42,8 @@ private slots: int UpdateDeviceList(); void StartManualControl(); void UpdateReference(); - + void StartFirmwareUpdateDialog(); + void DeviceNeedsUpdate(int reported, int expected); private: void DeviceConnectionLost(); void CreateToolbars(); diff --git a/Software/PC_Application/preferences.cpp b/Software/PC_Application/preferences.cpp index 59c1bd4..49e03d4 100644 --- a/Software/PC_Application/preferences.cpp +++ b/Software/PC_Application/preferences.cpp @@ -67,6 +67,13 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : ui->StartupSARBW->setUnit("Hz"); ui->StartupSARBW->setPrefixes(" k"); + // Acquisition page + ui->AcquisitionDFTlimitRBW->setUnit("Hz"); + ui->AcquisitionDFTlimitRBW->setPrefixes(" k"); + connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) { + ui->AcquisitionDFTlimitRBW->setEnabled(enabled); + }); + // Page selection connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) { auto name = current->text(0); @@ -107,6 +114,8 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : p->Startup.SA.signalID = ui->StartupSASignalID->isChecked(); p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked(); p->Acquisition.suppressPeaks = ui->AcquisitionSuppressPeaks->isChecked(); + p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked(); + p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value(); p->General.graphColors.background = ui->GeneralGraphBackground->getColor(); p->General.graphColors.axis = ui->GeneralGraphAxis->getColor(); p->General.graphColors.divisions = ui->GeneralGraphDivisions->getColor(); @@ -147,6 +156,8 @@ void PreferencesDialog::setInitialGUIState() ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts); ui->AcquisitionSuppressPeaks->setChecked(p->Acquisition.suppressPeaks); + ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode); + ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT); ui->GeneralGraphBackground->setColor(p->General.graphColors.background); ui->GeneralGraphAxis->setColor(p->General.graphColors.axis); diff --git a/Software/PC_Application/preferences.h b/Software/PC_Application/preferences.h index e1b09a9..5ee9209 100644 --- a/Software/PC_Application/preferences.h +++ b/Software/PC_Application/preferences.h @@ -44,6 +44,8 @@ public: struct { bool alwaysExciteBothPorts; bool suppressPeaks; + bool useDFTinSAmode; + double RBWLimitForDFT; } Acquisition; struct { struct { @@ -60,7 +62,7 @@ private: QString name; QVariant def; }; - const std::array descr = {{ + const std::array descr = {{ {&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true}, {&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false}, {&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0}, @@ -80,6 +82,8 @@ private: {&Startup.SA.signalID, "Startup.SA.signalID", true}, {&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", true}, {&Acquisition.suppressPeaks, "Acquisition.suppressPeaks", true}, + {&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true}, + {&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0}, {&General.graphColors.background, "General.graphColors.background", QColor(Qt::black)}, {&General.graphColors.axis, "General.graphColors.axis", QColor(Qt::white)}, {&General.graphColors.divisions, "General.graphColors.divisions", QColor(Qt::gray)}, diff --git a/Software/PC_Application/preferencesdialog.ui b/Software/PC_Application/preferencesdialog.ui index f9a6e74..873e3d0 100644 --- a/Software/PC_Application/preferencesdialog.ui +++ b/Software/PC_Application/preferencesdialog.ui @@ -73,7 +73,7 @@ - 0 + 1 @@ -454,23 +454,58 @@ - - - <html><head/><body><p>If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.</p></body></html> - - - Always perform full 2-port measurement + + + Vector Network Analyzer + + + + + <html><head/><body><p>If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.</p></body></html> + + + Always perform full 2-port measurement + + + + + + + <html><head/><body><p>Due to limited fractional divider settings, the source and 1.LO PLLs are not able to reach every frequency exactly. At some specific frequencies this causes the final IF to shift. At these frequencies there will be a positive or negative peak in the trace measurement that is not actually there.<br/><br/>Checking this option shifts the 2.LO for points where this could be an issue. This will remove the peaks but slows down the sweep slightly.</p></body></html> + + + Suppress invalid peaks + + + + - - - <html><head/><body><p>Due to limited fractional divider settings, the source and 1.LO PLLs are not able to reach every frequency exactly. At some specific frequencies this causes the final IF to shift. At these frequencies there will be a positive or negative peak in the trace measurement that is not actually there.<br/><br/>Checking this option shifts the 2.LO for points where this could be an issue. This will remove the peaks but slows down the sweep slightly.</p></body></html> - - - Suppress invalid peaks + + + Spectrum Analyzer + + + + + + + <html><head/><body><p>Normally, the spectrum analyzer mode tunes the LO for each point and measures the final IF only at one frequency. When this option is enabled, a DFT of the final IF is calculated instead which covers multiple frequencies with one measurement.</p><p>This can speed up the measurement at low RBWs significantly.</p></body></html> + + + Use DFT when RBW is below + + + + + + + + + diff --git a/Software/VNA_embedded/.cproject b/Software/VNA_embedded/.cproject index fea700d..9e01867 100644 --- a/Software/VNA_embedded/.cproject +++ b/Software/VNA_embedded/.cproject @@ -189,6 +189,8 @@ + + diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index e776d7c..a02424d 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -155,10 +155,10 @@ void App_Start() { SA::Setup(recv_packet.spectrumSettings); Communication::SendWithoutPayload(Protocol::PacketType::Ack); break; - case Protocol::PacketType::RequestDeviceLimits: + case Protocol::PacketType::RequestDeviceInfo: Protocol::PacketInfo p; - p.type = Protocol::PacketType::DeviceLimits; - p.limits = HW::Limits; + p.type = Protocol::PacketType::DeviceInfo; + HW::fillDeviceInfo(&p.info); Communication::Send(p); break; #ifdef HAS_FLASH diff --git a/Software/VNA_embedded/Application/Communication/Protocol.cpp b/Software/VNA_embedded/Application/Communication/Protocol.cpp index 74eec92..758babd 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.cpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.cpp @@ -238,35 +238,58 @@ static int16_t EncodeGeneratorSettings(Protocol::GeneratorSettings d, uint8_t *b static Protocol::DeviceInfo DecodeDeviceInfo(uint8_t *buf) { Protocol::DeviceInfo d; Decoder e(buf); - e.get(d.FW_major); - e.get(d.FW_minor); - e.get(d.HW_Revision); + e.get(d.ProtocolVersion); + e.get(d.FW_major); + e.get(d.FW_minor); + e.get(d.FW_patch); + e.get(d.HW_Revision); d.extRefAvailable = e.getBits(1); d.extRefInUse = e.getBits(1); d.FPGA_configured = e.getBits(1); d.source_locked = e.getBits(1); d.LO1_locked = e.getBits(1); d.ADC_overload = e.getBits(1); - e.get(d.temperatures.source); - e.get(d.temperatures.LO1); - e.get(d.temperatures.MCU); + e.get(d.temp_source); + e.get(d.temp_LO1); + e.get(d.temp_MCU); + e.get(d.limits_minFreq); + e.get(d.limits_maxFreq); + e.get(d.limits_minIFBW); + e.get(d.limits_maxIFBW); + e.get(d.limits_maxPoints); + e.get(d.limits_cdbm_min); + e.get(d.limits_cdbm_max); + e.get(d.limits_minRBW); + e.get(d.limits_maxRBW); return d; } static int16_t EncodeDeviceInfo(Protocol::DeviceInfo d, uint8_t *buf, uint16_t bufSize) { + d.ProtocolVersion = Protocol::Version; Encoder e(buf, bufSize); - e.add(d.FW_major); - e.add(d.FW_minor); - e.add(d.HW_Revision); + e.add(d.ProtocolVersion); + e.add(d.FW_major); + e.add(d.FW_minor); + e.add(d.FW_patch); + e.add(d.HW_Revision); e.addBits(d.extRefAvailable, 1); e.addBits(d.extRefInUse, 1); e.addBits(d.FPGA_configured, 1); e.addBits(d.source_locked, 1); e.addBits(d.LO1_locked, 1); e.addBits(d.ADC_overload, 1); - e.add(d.temperatures.source); - e.add(d.temperatures.LO1); - e.add(d.temperatures.MCU); + e.add(d.temp_source); + e.add(d.temp_LO1); + e.add(d.temp_MCU); + e.add(d.limits_minFreq); + e.add(d.limits_maxFreq); + e.add(d.limits_minIFBW); + e.add(d.limits_maxIFBW); + e.add(d.limits_maxPoints); + e.add(d.limits_cdbm_min); + e.add(d.limits_cdbm_max); + e.add(d.limits_minRBW); + e.add(d.limits_maxRBW); return e.getSize(); } @@ -378,6 +401,7 @@ static Protocol::SpectrumAnalyzerSettings DecodeSpectrumAnalyzerSettings(uint8_t d.WindowType = e.getBits(2); d.SignalID = e.getBits(1); d.Detector = e.getBits(3); + d.UseDFT = e.getBits(1); return d; } static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings d, uint8_t *buf, @@ -390,6 +414,7 @@ static int16_t EncodeSpectrumAnalyzerSettings(Protocol::SpectrumAnalyzerSettings e.addBits(d.WindowType, 2); e.addBits(d.SignalID, 1); e.addBits(d.Detector, 3); + e.addBits(d.UseDFT, 1); return e.getSize(); } @@ -412,35 +437,6 @@ static int16_t EncodeSpectrumAnalyzerResult(Protocol::SpectrumAnalyzerResult d, return e.getSize(); } -static Protocol::DeviceLimits DecodeDeviceLimits(uint8_t *buf) { - Protocol::DeviceLimits d; - Decoder e(buf); - e.get(d.minFreq); - e.get(d.maxFreq); - e.get(d.minIFBW); - e.get(d.maxIFBW); - e.get(d.maxPoints); - e.get(d.cdbm_min); - e.get(d.cdbm_max); - e.get(d.minRBW); - e.get(d.maxRBW); - return d; -} -static int16_t EncodeDeviceLimits(Protocol::DeviceLimits d, uint8_t *buf, - uint16_t bufSize) { - Encoder e(buf, bufSize); - e.add(d.minFreq); - e.add(d.maxFreq); - e.add(d.minIFBW); - e.add(d.maxIFBW); - e.add(d.maxPoints); - e.add(d.cdbm_min); - e.add(d.cdbm_max); - e.add(d.minRBW); - e.add(d.maxRBW); - return e.getSize(); -} - static Protocol::FirmwarePacket DecodeFirmwarePacket(uint8_t *buf) { Protocol::FirmwarePacket d; // simple packet format, memcpy is faster than using the decoder @@ -545,14 +541,11 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) { case PacketType::SpectrumAnalyzerResult: info->spectrumResult = DecodeSpectrumAnalyzerResult(&data[4]); break; - case PacketType::DeviceLimits: - info->limits = DecodeDeviceLimits(&data[4]); - break; case PacketType::Ack: case PacketType::PerformFirmwareUpdate: case PacketType::ClearFlash: case PacketType::Nack: - case PacketType::RequestDeviceLimits: + case PacketType::RequestDeviceInfo: // no payload, nothing to do break; case PacketType::None: @@ -595,14 +588,11 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_ case PacketType::SpectrumAnalyzerResult: payload_size = EncodeSpectrumAnalyzerResult(packet.spectrumResult, &dest[4], destsize - 8); break; - case PacketType::DeviceLimits: - payload_size = EncodeDeviceLimits(packet.limits, &dest[4], destsize - 8); - break; case PacketType::Ack: case PacketType::PerformFirmwareUpdate: case PacketType::ClearFlash: case PacketType::Nack: - case PacketType::RequestDeviceLimits: + case PacketType::RequestDeviceInfo: // no payload, nothing to do break; case PacketType::None: diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index 1f666e7..39e1203 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -4,6 +4,8 @@ namespace Protocol { +static constexpr uint16_t Version = 1; + // When changing/adding/removing variables from these structs also adjust the decode/encode functions in Protocol.cpp using Datapoint = struct _datapoint { @@ -39,8 +41,10 @@ using GeneratorSettings = struct _generatorSettings { }; using DeviceInfo = struct _deviceInfo { - uint16_t FW_major; - uint16_t FW_minor; + uint16_t ProtocolVersion; + uint8_t FW_major; + uint8_t FW_minor; + uint8_t FW_patch; char HW_Revision; uint8_t extRefAvailable:1; uint8_t extRefInUse:1; @@ -48,11 +52,18 @@ using DeviceInfo = struct _deviceInfo { uint8_t source_locked:1; uint8_t LO1_locked:1; uint8_t ADC_overload:1; - struct { - uint8_t source; - uint8_t LO1; - uint8_t MCU; - } temperatures; + uint8_t temp_source; + uint8_t temp_LO1; + uint8_t temp_MCU; + uint64_t limits_minFreq; + uint64_t limits_maxFreq; + uint32_t limits_minIFBW; + uint32_t limits_maxIFBW; + uint16_t limits_maxPoints; + int16_t limits_cdbm_min; + int16_t limits_cdbm_max; + uint32_t limits_minRBW; + uint32_t limits_maxRBW; }; using ManualStatus = struct _manualstatus { @@ -107,6 +118,7 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings { uint8_t WindowType :2; uint8_t SignalID :1; uint8_t Detector :3; + uint8_t UseDFT :1; }; using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { @@ -116,18 +128,6 @@ using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { uint16_t pointNum; }; -using DeviceLimits = struct _deviceLimits { - uint64_t minFreq; - uint64_t maxFreq; - uint32_t minIFBW; - uint32_t maxIFBW; - uint16_t maxPoints; - int16_t cdbm_min; - int16_t cdbm_max; - uint32_t minRBW; - uint32_t maxRBW; -}; - static constexpr uint16_t FirmwareChunkSize = 256; using FirmwarePacket = struct _firmwarePacket { uint32_t address; @@ -150,8 +150,7 @@ enum class PacketType : uint8_t { Generator = 12, SpectrumAnalyzerSettings = 13, SpectrumAnalyzerResult = 14, - RequestDeviceLimits = 15, - DeviceLimits = 16, + RequestDeviceInfo = 15, }; using PacketInfo = struct _packetinfo { @@ -167,7 +166,6 @@ using PacketInfo = struct _packetinfo { ManualStatus status; SpectrumAnalyzerSettings spectrumSettings; SpectrumAnalyzerResult spectrumResult; - DeviceLimits limits; }; }; diff --git a/Software/VNA_embedded/Application/Hardware.cpp b/Software/VNA_embedded/Application/Hardware.cpp index b788a8b..763b832 100644 --- a/Software/VNA_embedded/Application/Hardware.cpp +++ b/Software/VNA_embedded/Application/Hardware.cpp @@ -7,6 +7,7 @@ #include "VNA.hpp" #include "Manual.hpp" #include "SpectrumAnalyzer.hpp" +#include #define LOG_LEVEL LOG_LEVEL_INFO #define LOG_MODULE "HW" @@ -222,33 +223,39 @@ void HW::SetIdle() { FPGA::Enable(FPGA::Periphery::PortSwitch, false); } -void HW::fillDeviceInfo(Protocol::DeviceInfo *info) { - // read PLL temperatures - uint8_t tempSource, tempLO; - GetTemps(&tempSource, &tempLO); - LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO); - // Read ADC min/max - auto limits = FPGA::GetADCLimits(); - LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d", - limits.P1min, limits.P1max, limits.P2min, limits.P2max, - limits.Rmin, limits.Rmax); -#define ADC_LIMIT 30000 - if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT - || limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT - || limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { - info->ADC_overload = true; - } else { - info->ADC_overload = false; +void HW::fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy) { + // copy constant default values + memcpy(info, &HW::Info, sizeof(HW::Info)); + if(activeMode == Mode::Idle || updateEvenWhenBusy) { + // updating values from FPGA allowed + + // read PLL temperatures + uint8_t tempSource, tempLO; + GetTemps(&tempSource, &tempLO); + LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO); + // Read ADC min/max + auto limits = FPGA::GetADCLimits(); + LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d", + limits.P1min, limits.P1max, limits.P2min, limits.P2max, + limits.Rmin, limits.Rmax); + #define ADC_LIMIT 30000 + if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT + || limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT + || limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { + info->ADC_overload = true; + } else { + info->ADC_overload = false; + } + auto status = FPGA::GetStatus(); + info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1; + info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1; + info->extRefAvailable = Ref::available(); + info->extRefInUse = extRefInUse; + info->temp_LO1 = tempLO; + info->temp_source = tempSource; + FPGA::ResetADCLimits(); } - auto status = FPGA::GetStatus(); - info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1; - info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1; - info->extRefAvailable = Ref::available(); - info->extRefInUse = extRefInUse; - info->temperatures.LO1 = tempLO; - info->temperatures.source = tempSource; - info->temperatures.MCU = STM::getTemperature(); - FPGA::ResetADCLimits(); + info->temp_MCU = STM::getTemperature(); } bool HW::Ref::available() { diff --git a/Software/VNA_embedded/Application/Hardware.hpp b/Software/VNA_embedded/Application/Hardware.hpp index 2522051..fca7f24 100644 --- a/Software/VNA_embedded/Application/Hardware.hpp +++ b/Software/VNA_embedded/Application/Hardware.hpp @@ -38,16 +38,30 @@ static_assert(ADCprescaler * ADCSamplerate == FPGA::Clockrate, "ADCSamplerate ca static constexpr uint16_t DFTphaseInc = 4096 * IF2 / ADCSamplerate; static_assert(DFTphaseInc * ADCSamplerate == 4096 * IF2, "DFT can not be computed for 2.IF"); -static constexpr Protocol::DeviceLimits Limits = { - .minFreq = 0, - .maxFreq = 6000000000, - .minIFBW = ADCSamplerate / MaxSamples, - .maxIFBW = ADCSamplerate / MinSamples, - .maxPoints = FPGA::MaxPoints, - .cdbm_min = -4000, - .cdbm_max = 0, - .minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples), - .maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples), +static constexpr Protocol::DeviceInfo Info = { + .ProtocolVersion = Protocol::Version, + .FW_major = FW_MAJOR, + .FW_minor = FW_MINOR, + .FW_patch = FW_PATCH, + .HW_Revision = HW_REVISION, + .extRefAvailable = 0, + .extRefInUse = 0, + .FPGA_configured = 0, + .source_locked = 0, + .LO1_locked = 0, + .ADC_overload = 0, + .temp_source = 0, + .temp_LO1 = 0, + .temp_MCU = 0, + .limits_minFreq = 0, + .limits_maxFreq = 6000000000, + .limits_minIFBW = ADCSamplerate / MaxSamples, + .limits_maxIFBW = ADCSamplerate / MinSamples, + .limits_maxPoints = FPGA::MaxPoints, + .limits_cdbm_min = -4000, + .limits_cdbm_max = 0, + .limits_minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples), + .limits_maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples), }; enum class Mode { @@ -63,7 +77,7 @@ void SetIdle(); void Work(); bool GetTemps(uint8_t *source, uint8_t *lo); -void fillDeviceInfo(Protocol::DeviceInfo *info); +void fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy = false); namespace Ref { bool available(); // reference won't change until update is called diff --git a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp index 9f53e94..1caeb52 100644 --- a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp +++ b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp @@ -23,7 +23,6 @@ static Protocol::PacketInfo p; static bool active = false; static uint32_t lastLO2; static uint32_t actualRBW; -static bool usingDFT; static uint16_t DFTpoints; static bool negativeDFT; // if true, a positive frequency shift at input results in a negative shift at the 2.IF. Handle DFT accordingly @@ -106,7 +105,7 @@ static void StartNextSample() { Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); lastLO2 = LO2freq; } - if (usingDFT) { + if (s.UseDFT) { uint32_t spacing = (s.f_stop - s.f_start) / (points - 1); uint32_t start = HW::IF2; if(negativeDFT) { @@ -166,11 +165,16 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) { FPGA::Enable(FPGA::Periphery::Port1Mixer); FPGA::Enable(FPGA::Periphery::Port2Mixer); - // automatically select DFT mode for lower RBWs - usingDFT = actualRBW <= 1000; - - if (usingDFT) { - DFTpoints = FPGA::DFTbins; // use full DFT in FPGA + if (s.UseDFT) { + uint32_t spacing = (s.f_stop - s.f_start) / (points - 1); + // The DFT can only look at a small bandwidth otherwise the passband of the final ADC filter is visible in the data + // Limit to about 30kHz + uint32_t maxDFTpoints = 30000 / spacing; + // Limit to actual supported number of bins + if(maxDFTpoints > FPGA::DFTbins) { + maxDFTpoints = FPGA::DFTbins; + } + DFTpoints = maxDFTpoints; FPGA::DisableInterrupt(FPGA::Interrupt::NewData); } else { DFTpoints = 1; // can only measure one point at a time @@ -191,7 +195,7 @@ bool SA::MeasurementDone(const FPGA::SamplingResult &result) { for(uint16_t i=0;i