mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-01-06 16:49:59 +01:00
Improved electronic calibration
- Added automatic port detection mode - Faster coefficient readout - LibreCAL using asynchronous libusb API
This commit is contained in:
parent
392cb6dc3f
commit
2c639d8080
|
|
@ -336,6 +336,7 @@ void CalDevice::loadCoefficientSetsThreadFast(QStringList names)
|
|||
auto createCoefficient = [&](QString setName, QString paramName) -> CoefficientSet::Coefficient* {
|
||||
CoefficientSet::Coefficient *c = new CoefficientSet::Coefficient();
|
||||
// ask for the whole set at once
|
||||
usb->flushReceived();
|
||||
usb->send(":COEFF:GET? "+setName+" "+paramName);
|
||||
// handle incoming lines
|
||||
if(paramName.endsWith("THROUGH")) {
|
||||
|
|
@ -346,7 +347,7 @@ void CalDevice::loadCoefficientSetsThreadFast(QStringList names)
|
|||
c->t.setFilename("LibreCAL/"+paramName);
|
||||
while(true) {
|
||||
QString line;
|
||||
if(!usb->receive(&line, 100)) {
|
||||
if(!usb->receive(&line)) {
|
||||
// failed to receive something, abort
|
||||
return c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,15 +41,21 @@ LibreCALDialog::LibreCALDialog(Calibration *cal) :
|
|||
connect(device, &CalDevice::updateCoefficientsPercent, ui->progressCoeff, &QProgressBar::setValue);
|
||||
connect(device, &CalDevice::updateCoefficientsDone, this, [=](bool success){
|
||||
busy = false;
|
||||
updateCalibrationStartStatus();
|
||||
if(success) {
|
||||
ui->progressCoeff->setValue(100);
|
||||
ui->lCoefficientStatus->setText("Coefficients loaded.");
|
||||
ui->lCalibrationStatus->setText("Coefficients loaded.");
|
||||
coeffSet = device->getCoefficientSets()[0];
|
||||
|
||||
if(validateCoefficients()) {
|
||||
startCalibration();
|
||||
} else {
|
||||
enableUI();
|
||||
}
|
||||
} else {
|
||||
ui->progressCal->setValue(0);
|
||||
ui->lCoefficientStatus->setText("Failed to load coefficients");
|
||||
ui->lCalibrationStatus->setText("Failed to load coefficients");
|
||||
}
|
||||
updateCalibrationStartStatus();
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
ui->cbCoefficients->clear();
|
||||
|
|
@ -58,6 +64,10 @@ LibreCALDialog::LibreCALDialog(Calibration *cal) :
|
|||
ui->cbCoefficients->addItem(c);
|
||||
}
|
||||
ui->cbCoefficients->setEnabled(true);
|
||||
// select first available coefficient set
|
||||
if(ui->cbCoefficients->count() > 1) {
|
||||
ui->cbCoefficients->setCurrentIndex(1);
|
||||
}
|
||||
} else {
|
||||
ui->cbCoefficients->clear();
|
||||
ui->cbCoefficients->setEnabled(false);
|
||||
|
|
@ -68,19 +78,9 @@ LibreCALDialog::LibreCALDialog(Calibration *cal) :
|
|||
connect(ui->cbCoefficients, &QComboBox::currentTextChanged, [=](){
|
||||
// no coefficient set selected
|
||||
ui->progressCoeff->setValue(0);
|
||||
ui->lCoefficientStatus->setText("No coefficients loaded");
|
||||
coeffSet = CalDevice::CoefficientSet();
|
||||
ui->lCalibrationStatus->setText("No coefficients loaded");
|
||||
updateCalibrationStartStatus();
|
||||
|
||||
if(ui->cbCoefficients->currentIndex() > 0) {
|
||||
if(!device) {
|
||||
qWarning() << "Coefficients selected without connected device";
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
ui->lCoefficientStatus->setText("Loading coefficients...");
|
||||
device->loadCoefficientSets({ui->cbCoefficients->currentText()});
|
||||
}
|
||||
});
|
||||
|
||||
auto deviceList = USBDevice::GetDevices();
|
||||
|
|
@ -88,7 +88,8 @@ LibreCALDialog::LibreCALDialog(Calibration *cal) :
|
|||
ui->cbDevice->addItem(device);
|
||||
}
|
||||
|
||||
connect(ui->start, &QPushButton::clicked, this, &LibreCALDialog::startCalibration);
|
||||
connect(ui->start, &QPushButton::clicked, this, &LibreCALDialog::determineAutoPorts);
|
||||
connect(this, &LibreCALDialog::autoPortComplete, this, &LibreCALDialog::loadCoefficients);
|
||||
|
||||
updateCalibrationStartStatus();
|
||||
updateDeviceStatus();
|
||||
|
|
@ -105,29 +106,28 @@ LibreCALDialog::~LibreCALDialog()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void LibreCALDialog::updateCalibrationStartStatus()
|
||||
bool LibreCALDialog::validatePortSelection(bool autoAllowed)
|
||||
{
|
||||
bool canStart = true;
|
||||
QString status = "Ready to start";
|
||||
if(!device) {
|
||||
status = "Not connected to a LibreCAL device.";
|
||||
canStart = false;
|
||||
}
|
||||
set<int> usedCalPorts;
|
||||
if(canStart) {
|
||||
// Check port mapping for duplicate entries (and at least one used port)
|
||||
for(auto port : portAssignment) {
|
||||
if(port < 1) {
|
||||
// skip unused ports
|
||||
continue;
|
||||
}
|
||||
if(usedCalPorts.count(port)) {
|
||||
status = "LibreCAL port "+QString::number(port)+" is assigned to multiple VNA ports.";
|
||||
canStart = false;
|
||||
break;
|
||||
} else {
|
||||
usedCalPorts.insert(port);
|
||||
}
|
||||
QString status;
|
||||
bool canStart = true;
|
||||
// Check port mapping for duplicate entries (and at least one used port)
|
||||
for(auto port : portAssignment) {
|
||||
if(autoAllowed && port == -1) {
|
||||
// auto port, to be determined later
|
||||
usedCalPorts.insert(port);
|
||||
// skip duplicate selection
|
||||
continue;
|
||||
} else if(port < 1) {
|
||||
// skip unused ports
|
||||
continue;
|
||||
}
|
||||
if(usedCalPorts.count(port)) {
|
||||
status = "LibreCAL port "+QString::number(port)+" is assigned to multiple VNA ports.";
|
||||
canStart = false;
|
||||
break;
|
||||
} else {
|
||||
usedCalPorts.insert(port);
|
||||
}
|
||||
}
|
||||
if(canStart) {
|
||||
|
|
@ -137,68 +137,104 @@ void LibreCALDialog::updateCalibrationStartStatus()
|
|||
canStart = false;
|
||||
}
|
||||
}
|
||||
if(canStart) {
|
||||
// check if coefficients have been loaded
|
||||
if(coeffSet.opens.size() != device->getNumPorts()) {
|
||||
status = "Coefficients not loaded";
|
||||
if(!canStart) {
|
||||
ui->lCalibrationStatus->setText(status);
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
return canStart;
|
||||
}
|
||||
|
||||
bool LibreCALDialog::validateCoefficients()
|
||||
{
|
||||
bool canStart = true;
|
||||
QString status;
|
||||
|
||||
double coeffMinFreq = numeric_limits<double>::max();
|
||||
double coeffMaxFreq = numeric_limits<double>::lowest();
|
||||
|
||||
auto checkCoefficient = [&](CalDevice::CoefficientSet::Coefficient *c) -> bool {
|
||||
if(c->t.points() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if(c->t.minFreq() < coeffMinFreq) {
|
||||
coeffMinFreq = c->t.minFreq();
|
||||
}
|
||||
if(c->t.maxFreq() > coeffMaxFreq) {
|
||||
coeffMaxFreq = c->t.maxFreq();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
set<int> usedCalPorts;
|
||||
// Check port mapping for duplicate entries (and at least one used port)
|
||||
for(auto port : portAssignment) {
|
||||
if(port > 0) {
|
||||
usedCalPorts.insert(port);
|
||||
}
|
||||
}
|
||||
|
||||
// check if coefficients for all ports are available
|
||||
for(auto i : usedCalPorts) {
|
||||
// Check if OSL coefficients are there
|
||||
if(!checkCoefficient(coeffSet.opens[i-1])) {
|
||||
status = "Open coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.shorts[i-1])) {
|
||||
status = "Short coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.loads[i-1])) {
|
||||
status = "Load coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
for(auto j : usedCalPorts) {
|
||||
if(j <= i) {
|
||||
continue;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.getThrough(i,j))) {
|
||||
status = "Through coefficient for LibreCAL port "+QString::number(i)+" to "+QString::number(j)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!canStart) {
|
||||
ui->lCalibrationStatus->setText(status);
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
return canStart;
|
||||
}
|
||||
|
||||
void LibreCALDialog::updateCalibrationStartStatus()
|
||||
{
|
||||
bool canStart = true;
|
||||
if(!device) {
|
||||
canStart = false;
|
||||
ui->lCalibrationStatus->setText("Not connected to a LibreCAL device");
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
|
||||
if(canStart) {
|
||||
double coeffMinFreq = numeric_limits<double>::max();
|
||||
double coeffMaxFreq = numeric_limits<double>::lowest();
|
||||
|
||||
auto checkCoefficient = [&](CalDevice::CoefficientSet::Coefficient *c) -> bool {
|
||||
if(c->t.points() == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if(c->t.minFreq() < coeffMinFreq) {
|
||||
coeffMinFreq = c->t.minFreq();
|
||||
}
|
||||
if(c->t.maxFreq() > coeffMaxFreq) {
|
||||
coeffMaxFreq = c->t.maxFreq();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// check if coefficients for all ports are available
|
||||
for(auto i : usedCalPorts) {
|
||||
// Check if OSL coefficients are there
|
||||
if(!checkCoefficient(coeffSet.opens[i-1])) {
|
||||
status = "Open coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.shorts[i-1])) {
|
||||
status = "Short coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.loads[i-1])) {
|
||||
status = "Load coefficient for LibreCAL port "+QString::number(i)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
for(auto j : usedCalPorts) {
|
||||
if(j <= i) {
|
||||
continue;
|
||||
}
|
||||
if(!checkCoefficient(coeffSet.getThrough(i,j))) {
|
||||
status = "Through coefficient for LibreCAL port "+QString::number(i)+" to "+QString::number(j)+" is missing.";
|
||||
canStart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ui->cbCoefficients->currentIndex() == 0) {
|
||||
canStart = false;
|
||||
ui->lCalibrationStatus->setText("No coefficient set selected");
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
}
|
||||
|
||||
ui->lCalibrationStatus->setText(status);
|
||||
if(canStart) {
|
||||
canStart = validatePortSelection(true);
|
||||
}
|
||||
|
||||
ui->start->setEnabled(canStart);
|
||||
if(canStart) {
|
||||
ui->lCalibrationStatus->setText("Ready to start");
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : black; }");
|
||||
} else {
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : red; }");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +258,153 @@ void LibreCALDialog::updateDeviceStatus()
|
|||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::determineAutoPorts()
|
||||
{
|
||||
ui->progressCal->setValue(0);
|
||||
ui->lCalibrationStatus->setText("Autodetecting port connections...");
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : green; }");
|
||||
|
||||
// check if any ports are set to auto
|
||||
bool usesAuto = false;
|
||||
for(auto port : portAssignment) {
|
||||
if(port == -1) {
|
||||
usesAuto = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(usesAuto) {
|
||||
driver = DeviceDriver::getActiveDriver();
|
||||
emit driver->acquireControl();
|
||||
// Determine ports by setting all ports to open and then switching them to short one at a time while observing the change in the VNA measurement
|
||||
for(unsigned int i=1;i<=device->getNumPorts();i++) {
|
||||
device->setStandard(i, CalDevice::Standard::Type::Open);
|
||||
}
|
||||
autoPortMeasurements.clear();
|
||||
startSweep();
|
||||
} else {
|
||||
// no auto ports
|
||||
emit autoPortComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::loadCoefficients()
|
||||
{
|
||||
// validate ports again, at this point no "auto" selection is allowed anymore
|
||||
if(!validatePortSelection(false)) {
|
||||
enableUI();
|
||||
updateCalibrationStartStatus();
|
||||
} else {
|
||||
// can continue with loading coefficients
|
||||
// they might already be loaded from a previous calibration run, check first
|
||||
// if(!validateCoefficients()) {
|
||||
// TODO only load required coefficients
|
||||
ui->progressCal->setValue(0);
|
||||
ui->lCalibrationStatus->setText("Loading coefficients...");
|
||||
ui->lCalibrationStatus->setStyleSheet("QLabel { color : green; }");
|
||||
|
||||
busy = true;
|
||||
device->loadCoefficientSets({ui->cbCoefficients->currentText()});
|
||||
// } else {
|
||||
// // can proceed with calibration directly
|
||||
// startCalibration();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::handleIncomingMeasurement(DeviceDriver::VNAMeasurement m)
|
||||
{
|
||||
stopSweep();
|
||||
autoPortMeasurements.push_back(m);
|
||||
auto nextPort = autoPortMeasurements.size();
|
||||
// switch LibreCAL to next port
|
||||
if(nextPort <= device->getNumPorts()) {
|
||||
device->setStandard(nextPort, CalDevice::Standard::Type::Short);
|
||||
}
|
||||
if(nextPort > 1) {
|
||||
device->setStandard(nextPort-1, CalDevice::Standard::Type::Open);
|
||||
}
|
||||
if(nextPort > device->getNumPorts()) {
|
||||
// auto port measurements complete
|
||||
|
||||
// reset LibreCAL ports
|
||||
for(unsigned int i=1;i<=device->getNumPorts();i++) {
|
||||
device->setStandard(i, CalDevice::Standard::Type::None);
|
||||
}
|
||||
// evaluate results
|
||||
for(unsigned int p=0;p<portAssignment.size();p++) {
|
||||
auto port = portAssignment[p];
|
||||
if(port != -1) {
|
||||
// not set to auto, ignore
|
||||
continue;
|
||||
}
|
||||
auto param = "S"+QString::number(p+1)+QString::number(p+1);
|
||||
std::vector<std::complex<double>> measurements;
|
||||
for(auto m : autoPortMeasurements) {
|
||||
if(m.measurements.count(param)) {
|
||||
measurements.push_back(m.measurements[param]);
|
||||
}
|
||||
}
|
||||
if(measurements.size() != device->getNumPorts()+1) {
|
||||
// not all measurements available (maybe the port has no stimulus?), set to unused
|
||||
portAssignmentComboBoxes[p]->setCurrentIndex(0);
|
||||
continue;
|
||||
}
|
||||
// got all required measurements, determine which one deviates the most from the baseline
|
||||
double maxDeviation = 0.0;
|
||||
int maxDevIndex = 0;
|
||||
for(unsigned int i=1;i<=device->getNumPorts();i++) {
|
||||
auto diff = abs(measurements[i] - measurements[0]);
|
||||
if (diff > maxDeviation) {
|
||||
maxDeviation = diff;
|
||||
maxDevIndex = i;
|
||||
}
|
||||
}
|
||||
constexpr double minRequiredDeviation = 0.25;
|
||||
if(maxDeviation > minRequiredDeviation) {
|
||||
portAssignmentComboBoxes[p]->setCurrentIndex(maxDevIndex+1);
|
||||
} else {
|
||||
// not enough deviation, probably unused
|
||||
portAssignmentComboBoxes[p]->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
emit driver->releaseControl();
|
||||
emit autoPortComplete();
|
||||
} else {
|
||||
// trigger the next measurement
|
||||
startSweep();
|
||||
}
|
||||
}
|
||||
|
||||
void LibreCALDialog::startSweep()
|
||||
{
|
||||
// set up a sweep with a single measurement point at the start frequency
|
||||
auto info = driver->getInfo();
|
||||
DeviceDriver::VNASettings s = {};
|
||||
s.dBmStart = info.Limits.VNA.maxdBm;
|
||||
s.dBmStop = info.Limits.VNA.maxdBm;
|
||||
|
||||
auto freq = info.Limits.VNA.minFreq == 0 ? 100000 : info.Limits.VNA.minFreq;
|
||||
|
||||
s.freqStart = freq;
|
||||
s.freqStop = freq;
|
||||
s.IFBW = 100;
|
||||
s.logSweep = false;
|
||||
s.points = 1;
|
||||
|
||||
for(unsigned int i=1;i<=info.Limits.VNA.ports;i++) {
|
||||
s.excitedPorts.push_back(i);
|
||||
}
|
||||
driver->setVNA(s, [=](bool){
|
||||
connect(driver, &DeviceDriver::VNAmeasurementReceived, this, &LibreCALDialog::handleIncomingMeasurement, Qt::DirectConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void LibreCALDialog::stopSweep()
|
||||
{
|
||||
disconnect(driver, &DeviceDriver::VNAmeasurementReceived, this, &LibreCALDialog::handleIncomingMeasurement);
|
||||
driver->setIdle();
|
||||
}
|
||||
|
||||
void LibreCALDialog::startCalibration()
|
||||
{
|
||||
disableUI();
|
||||
|
|
@ -441,7 +624,7 @@ void LibreCALDialog::createPortAssignmentUI()
|
|||
if(device) {
|
||||
calPorts = device->getNumPorts();
|
||||
}
|
||||
QStringList choices = {"Unused"};
|
||||
QStringList choices = {"Unused", "Auto"};
|
||||
for(int i=1;i<=calPorts;i++) {
|
||||
choices.push_back("Port "+QString::number(i));
|
||||
}
|
||||
|
|
@ -450,16 +633,16 @@ void LibreCALDialog::createPortAssignmentUI()
|
|||
auto comboBox = new QComboBox();
|
||||
comboBox->addItems(choices);
|
||||
connect(comboBox, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
|
||||
portAssignment[p-1] = comboBox->currentIndex();
|
||||
if(comboBox->currentText().startsWith("Unused")) {
|
||||
portAssignment[p-1] = 0;
|
||||
} else if(comboBox->currentText().startsWith("Auto")) {
|
||||
portAssignment[p-1] = -1;
|
||||
} else if(comboBox->currentText().startsWith("Port")) {
|
||||
portAssignment[p-1] = comboBox->currentText().back().digitValue();
|
||||
}
|
||||
emit portAssignmentChanged();
|
||||
});
|
||||
// try to set the default
|
||||
if(comboBox->count() > (int) p) {
|
||||
comboBox->setCurrentIndex(p);
|
||||
} else {
|
||||
// port not available, set to unused
|
||||
comboBox->setCurrentIndex(0);
|
||||
}
|
||||
comboBox->setCurrentIndex(1);
|
||||
layout->addRow(label, comboBox);
|
||||
portAssignmentComboBoxes.push_back(comboBox);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Calibration/calibration.h"
|
||||
#include "caldevice.h"
|
||||
#include "Device/devicedriver.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
|
|
@ -23,10 +24,20 @@ public:
|
|||
private:
|
||||
signals:
|
||||
void portAssignmentChanged();
|
||||
void autoPortComplete();
|
||||
private slots:
|
||||
bool validatePortSelection(bool autoAllowed);
|
||||
bool validateCoefficients();
|
||||
void updateCalibrationStartStatus();
|
||||
void updateDeviceStatus();
|
||||
void determineAutoPorts();
|
||||
void loadCoefficients();
|
||||
void startCalibration();
|
||||
|
||||
// auto port slots
|
||||
void handleIncomingMeasurement(DeviceDriver::VNAMeasurement m);
|
||||
void startSweep();
|
||||
void stopSweep();
|
||||
private:
|
||||
void disableUI();
|
||||
void enableUI();
|
||||
|
|
@ -37,8 +48,11 @@ private:
|
|||
CalDevice::CoefficientSet coeffSet;
|
||||
QTimer updateTimer;
|
||||
bool busy;
|
||||
// 0 for unused port, -1 for auto port, otherwise the port number
|
||||
std::vector<int> portAssignment;
|
||||
std::vector<QComboBox*> portAssignmentComboBoxes;
|
||||
std::vector<DeviceDriver::VNAMeasurement> autoPortMeasurements;
|
||||
DeviceDriver *driver;
|
||||
|
||||
int measurementsTaken;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>346</width>
|
||||
<height>395</height>
|
||||
<width>399</width>
|
||||
<height>405</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -58,20 +58,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lCoefficientStatus">
|
||||
<property name="text">
|
||||
<string>COEFFICIENT_STATUS_PLACEHOLDER</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCoeff">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -116,10 +102,47 @@
|
|||
<string>Start</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start"/>
|
||||
<iconset theme="media-playback-start">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Coefficients:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCoeff">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Calibration:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCal">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lCalibrationStatus">
|
||||
<property name="text">
|
||||
|
|
@ -127,13 +150,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressCal">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
#include <QDateTime>
|
||||
#include <mutex>
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -21,7 +22,6 @@ static constexpr USBID IDs[] = {
|
|||
|
||||
USBDevice::USBDevice(QString serial)
|
||||
{
|
||||
rx_cnt = 0;
|
||||
m_handle = nullptr;
|
||||
libusb_init(&m_context);
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
|
|
@ -67,18 +67,28 @@ USBDevice::USBDevice(QString serial)
|
|||
throw std::runtime_error(message.toStdString());
|
||||
}
|
||||
qInfo() << "USB connection established" << Qt::flush;
|
||||
|
||||
connected = true;
|
||||
m_receiveThread = new std::thread(&USBDevice::USBHandleThread, this);
|
||||
usbBuffer = new USBInBuffer(m_handle, LIBUSB_ENDPOINT_IN | 0x03, 65536);
|
||||
connect(usbBuffer, &USBInBuffer::DataReceived, this, &USBDevice::ReceivedData, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
USBDevice::~USBDevice()
|
||||
{
|
||||
delete usbBuffer;
|
||||
connected = false;
|
||||
libusb_release_interface(m_handle, 2);
|
||||
libusb_close(m_handle);
|
||||
m_receiveThread->join();
|
||||
libusb_exit(m_context);
|
||||
delete m_receiveThread;
|
||||
}
|
||||
|
||||
bool USBDevice::Cmd(QString cmd)
|
||||
{
|
||||
QString rcv;
|
||||
flushReceived();
|
||||
bool success = send(cmd) && receive(&rcv);
|
||||
if(success && rcv == "") {
|
||||
// empty response expected by commad
|
||||
|
|
@ -92,6 +102,7 @@ bool USBDevice::Cmd(QString cmd)
|
|||
|
||||
QString USBDevice::Query(QString query)
|
||||
{
|
||||
flushReceived();
|
||||
if(send(query)) {
|
||||
QString rcv;
|
||||
if(receive(&rcv)) {
|
||||
|
|
@ -201,7 +212,7 @@ void USBDevice::SearchDevices(std::function<bool (libusb_device_handle *, QStrin
|
|||
|
||||
bool USBDevice::send(const QString &s)
|
||||
{
|
||||
qDebug() << "Send:"<<s;
|
||||
// qDebug() << "Send:"<<s;
|
||||
unsigned char data[s.size()+2];
|
||||
memcpy(data, s.toLatin1().data(), s.size());
|
||||
memcpy(&data[s.size()], "\r\n", 2);
|
||||
|
|
@ -216,67 +227,58 @@ bool USBDevice::send(const QString &s)
|
|||
|
||||
bool USBDevice::receive(QString *s, unsigned int timeout)
|
||||
{
|
||||
auto checkForCompleteLine = [this, s]() -> bool {
|
||||
for(unsigned int i=1;i<rx_cnt;i++) {
|
||||
if(rx_buf[i] == '\n' && rx_buf[i-1] == '\r') {
|
||||
rx_buf[i-1] = '\0';
|
||||
if(s) {
|
||||
*s = QString(rx_buf);
|
||||
// qDebug() << "Receive:"<<*s;
|
||||
}
|
||||
memmove(rx_buf, &rx_buf[i+1], sizeof(rx_buf) - (i+1));
|
||||
rx_cnt -= i+1;
|
||||
rx_buf[rx_cnt] = 0;
|
||||
// qDebug() << "Remaining in buffer:" << QString(rx_buf);
|
||||
return true;
|
||||
}
|
||||
// check if we already have a line queued
|
||||
unique_lock<mutex> lck(mtx);
|
||||
while(lineBuffer.size() == 0) {
|
||||
// needs to wait for an incoming line
|
||||
using namespace std::chrono_literals;
|
||||
if(cv.wait_for(lck, std::chrono::milliseconds(timeout)) == cv_status::timeout) {
|
||||
qWarning() << "Timed out while waiting for received line";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
int res = 0;
|
||||
if(!checkForCompleteLine()) {
|
||||
// needs to receive data
|
||||
int actual;
|
||||
do {
|
||||
res = libusb_bulk_transfer(m_handle, LIBUSB_ENDPOINT_IN | 0x03, (unsigned char*) &rx_buf[rx_cnt], 512, &actual, timeout);
|
||||
rx_cnt += actual;
|
||||
// qDebug() << "received" << actual << "bytes. Total in buffer:" << rx_cnt;
|
||||
if(checkForCompleteLine()) {
|
||||
return true;
|
||||
}
|
||||
} while(res == 0);
|
||||
}
|
||||
return res == 0;
|
||||
// char data[512];
|
||||
// memset(data, 0, sizeof(data));
|
||||
// int actual;
|
||||
// int rcvCnt = 0;
|
||||
// bool endOfLineFound = false;
|
||||
// int res;
|
||||
// do {
|
||||
// res = libusb_bulk_transfer(m_handle, LIBUSB_ENDPOINT_IN | 0x03, (unsigned char*) &data[rcvCnt], sizeof(data) - rcvCnt, &actual, 2000);
|
||||
// for(int i=rcvCnt;i<rcvCnt+actual;i++) {
|
||||
// if(i == 0) {
|
||||
// continue;
|
||||
// }
|
||||
// if(data[i] == '\n' && data[i-1] == '\r') {
|
||||
// endOfLineFound = true;
|
||||
// data[i-1] = '\0';
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// rcvCnt += actual;
|
||||
// } while(res == 0 && !endOfLineFound);
|
||||
// if(res == 0) {
|
||||
// if(s) {
|
||||
// *s = QString(data);
|
||||
//// qDebug() << "Receive:"<<*s;
|
||||
// }
|
||||
// return true;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
*s = lineBuffer.takeFirst();
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBDevice::ReceivedData()
|
||||
{
|
||||
uint16_t handled_len;
|
||||
// qDebug() << "received new data";
|
||||
unique_lock<mutex> lck(mtx);
|
||||
do {
|
||||
handled_len = 0;
|
||||
auto firstLinebreak = (uint8_t*) memchr(usbBuffer->getBuffer(), '\n', usbBuffer->getReceived());
|
||||
if(firstLinebreak) {
|
||||
handled_len = firstLinebreak - usbBuffer->getBuffer();
|
||||
auto line = QString::fromLatin1((const char*) usbBuffer->getBuffer(), handled_len - 1);
|
||||
|
||||
// add received line to buffer
|
||||
lineBuffer.append(line);
|
||||
// qDebug() << "append" << line << "size" << lineBuffer.size();
|
||||
|
||||
usbBuffer->removeBytes(handled_len + 1);
|
||||
}
|
||||
} while(handled_len > 0);
|
||||
if(lineBuffer.size() > 0) {
|
||||
cv.notify_one();
|
||||
}
|
||||
// qDebug() << "notify done";
|
||||
}
|
||||
|
||||
void USBDevice::flushReceived()
|
||||
{
|
||||
unique_lock<mutex> lck(mtx);
|
||||
lineBuffer.clear();
|
||||
}
|
||||
|
||||
void USBDevice::USBHandleThread()
|
||||
{
|
||||
qDebug() << "Receive thread started";
|
||||
while (connected) {
|
||||
libusb_handle_events(m_context);
|
||||
}
|
||||
qDebug() << "Disconnected, receive thread exiting";
|
||||
}
|
||||
|
||||
QString USBDevice::serial() const
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
#ifndef USBDEVICE_H
|
||||
#define USBDEVICE_H
|
||||
|
||||
#include "Util/usbinbuffer.h"
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <QString>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
|
|
@ -25,18 +29,27 @@ public:
|
|||
|
||||
bool send(const QString &s);
|
||||
bool receive(QString *s, unsigned int timeout = 2000);
|
||||
void flushReceived();
|
||||
signals:
|
||||
void communicationFailure();
|
||||
|
||||
private slots:
|
||||
void ReceivedData();
|
||||
private:
|
||||
void USBHandleThread();
|
||||
bool connected;
|
||||
std::thread *m_receiveThread;
|
||||
|
||||
static void SearchDevices(std::function<bool (libusb_device_handle *, QString)> foundCallback, libusb_context *context, bool ignoreOpenError);
|
||||
libusb_device_handle *m_handle;
|
||||
libusb_context *m_context;
|
||||
|
||||
QString m_serial;
|
||||
USBInBuffer *usbBuffer;
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
QStringList lineBuffer;
|
||||
|
||||
char rx_buf[1024];
|
||||
unsigned int rx_cnt;
|
||||
QString m_serial;
|
||||
};
|
||||
|
||||
#endif // DEVICE_H
|
||||
|
|
|
|||
|
|
@ -17,107 +17,6 @@ static constexpr USBID IDs[] = {
|
|||
{0x1209, 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()
|
||||
{
|
||||
if(transfer) {
|
||||
cancelling = true;
|
||||
libusb_cancel_transfer(transfer);
|
||||
// wait for cancellation to complete
|
||||
mutex mtx;
|
||||
unique_lock<mutex> 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;
|
||||
}
|
||||
switch(transfer->status) {
|
||||
case LIBUSB_TRANSFER_COMPLETED:
|
||||
received_size += transfer->actual_length;
|
||||
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;
|
||||
}
|
||||
|
||||
LibreVNAUSBDriver::LibreVNAUSBDriver()
|
||||
: LibreVNADriver()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,40 +2,14 @@
|
|||
#define LIBREVNAUSBDRIVER_H
|
||||
|
||||
#include "librevnadriver.h"
|
||||
#include "Util/usbinbuffer.h"
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class LibreVNAUSBDriver : public LibreVNADriver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ HEADERS += \
|
|||
Traces/tracepolarchart.h \
|
||||
Util/prbs.h \
|
||||
Util/qpointervariant.h \
|
||||
Util/usbinbuffer.h \
|
||||
Util/util.h \
|
||||
Util/app_common.h \
|
||||
VNA/Deembedding/deembedding.h \
|
||||
|
|
@ -280,6 +281,7 @@ SOURCES += \
|
|||
Traces/waterfallaxisdialog.cpp \
|
||||
Traces/xyplotaxisdialog.cpp \
|
||||
Util/prbs.cpp \
|
||||
Util/usbinbuffer.cpp \
|
||||
Util/util.cpp \
|
||||
VNA/Deembedding/deembedding.cpp \
|
||||
VNA/Deembedding/deembeddingdialog.cpp \
|
||||
|
|
|
|||
109
Software/PC_Application/LibreVNA-GUI/Util/usbinbuffer.cpp
Normal file
109
Software/PC_Application/LibreVNA-GUI/Util/usbinbuffer.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#include "usbinbuffer.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace std;
|
||||
|
||||
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<mutex> 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;
|
||||
}
|
||||
switch(transfer->status) {
|
||||
case LIBUSB_TRANSFER_COMPLETED:
|
||||
case LIBUSB_TRANSFER_TIMED_OUT:
|
||||
if(transfer->actual_length > 0) {
|
||||
received_size += transfer->actual_length;
|
||||
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_CANCELLED:
|
||||
// already handled before switch-case
|
||||
break;
|
||||
}
|
||||
// Resubmit the transfer
|
||||
transfer->buffer = &buffer[received_size];
|
||||
transfer->length = buffer_size - received_size;
|
||||
transfer->length = (transfer->length / 512) * 512;
|
||||
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;
|
||||
}
|
||||
35
Software/PC_Application/LibreVNA-GUI/Util/usbinbuffer.h
Normal file
35
Software/PC_Application/LibreVNA-GUI/Util/usbinbuffer.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef USBINBUFFER_H
|
||||
#define USBINBUFFER_H
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif // USBINBUFFER_H
|
||||
|
|
@ -917,6 +917,8 @@ void VNA::NewDatapoint(DeviceDriver::VNAMeasurement m)
|
|||
qDebug() << "Sweep took"<<sweepTime<<"milliseconds";
|
||||
}
|
||||
|
||||
emit newRawDatapoint(m);
|
||||
|
||||
if(singleSweep && average.getLevel() == averages) {
|
||||
Stop();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ public:
|
|||
double firstPointTime; // timestamp of the first point in the sweep, only use when zerospan is used
|
||||
};
|
||||
|
||||
|
||||
signals:
|
||||
void newRawDatapoint(DeviceDriver::VNAMeasurement m);
|
||||
|
||||
public slots:
|
||||
void Run();
|
||||
void Stop();
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ SOURCES += \
|
|||
../LibreVNA-GUI/Traces/xyplotaxisdialog.cpp \
|
||||
../LibreVNA-GUI/Util/prbs.cpp \
|
||||
../LibreVNA-GUI/Util/util.cpp \
|
||||
../LibreVNA-GUI/Util/usbinbuffer.cpp \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembedding.cpp \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.cpp \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingoption.cpp \
|
||||
|
|
@ -317,6 +318,7 @@ HEADERS += \
|
|||
../LibreVNA-GUI/Traces/xyplotaxisdialog.h \
|
||||
../LibreVNA-GUI/Util/prbs.h \
|
||||
../LibreVNA-GUI/Util/util.h \
|
||||
../LibreVNA-GUI/Util/usbinbuffer.h \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembedding.h \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.h \
|
||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingoption.h \
|
||||
|
|
|
|||
Loading…
Reference in a new issue