Protocol adjustment + exposing settings for DFT

This commit is contained in:
Jan Käberich 2020-11-07 13:22:10 +01:00
parent ce475fa042
commit a2389fca13
19 changed files with 314 additions and 205 deletions

View file

@ -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<QString> 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<bool (libusb_device_handle *, QString)>
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);

View file

@ -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<QString> 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;
};

View file

@ -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();

View file

@ -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);

View file

@ -217,7 +217,11 @@ VNA::VNA(AppWindow *window)
points->setSingleStep(100);
points->setToolTip("Points/sweep");
connect(points, qOverload<int>(&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);

View file

@ -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;

View file

@ -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();

View file

@ -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);

View file

@ -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<SettingDescription, 22> descr = {{
const std::array<SettingDescription, 24> 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)},

View file

@ -73,7 +73,7 @@
</size>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4">
@ -454,23 +454,58 @@
<widget class="QWidget" name="Acquisition">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="AcquisitionAlwaysExciteBoth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Vector Network Analyzer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="AcquisitionAlwaysExciteBoth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AcquisitionSuppressPeaks">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;br/&gt;&lt;br/&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Suppress invalid peaks</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AcquisitionSuppressPeaks">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;br/&gt;&lt;br/&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Suppress invalid peaks</string>
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>Spectrum Analyzer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QFormLayout" name="formLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="AcquisitionUseDFT">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;This can speed up the measurement at low RBWs significantly.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use DFT when RBW is below</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="SIUnitEdit" name="AcquisitionDFTlimitRBW"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>