WIP: ADC spectrum

This commit is contained in:
Jan Käberich 2025-05-19 16:50:24 +02:00
parent f76e3a209d
commit be7cf38e05
9 changed files with 861 additions and 575 deletions

View file

@ -146,7 +146,7 @@ LibreVNADriver::LibreVNADriver()
break; break;
} }
if(manualControlDialog) { if(manualControlDialog) {
manualControlDialog->show(); manualControlDialog->showMaximized();
connect(manualControlDialog, &QDialog::finished, this, [=](){ connect(manualControlDialog, &QDialog::finished, this, [=](){
manualControlDialog = nullptr; manualControlDialog = nullptr;
}); });

View file

@ -6,6 +6,7 @@
#include <QComboBox> #include <QComboBox>
#include <QDebug> #include <QDebug>
#include <QButtonGroup> #include <QButtonGroup>
#include <QValueAxis>
#include <complex> #include <complex>
@ -18,6 +19,7 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
{ {
ui->setupUi(this); ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
setWindowFlags(Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
emit dev.acquireControl(); emit dev.acquireControl();
@ -44,6 +46,8 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
ui->DACAmplitudeA->setValue(2047); ui->DACAmplitudeA->setValue(2047);
ui->DACAmplitudeB->setValue(2047); ui->DACAmplitudeB->setValue(2047);
ui->ADCSamples->setValue(1024);
auto updateVariableAtt = [=](unsigned int value){ auto updateVariableAtt = [=](unsigned int value){
ui->SourceVariableAttSlider->setValue(value); ui->SourceVariableAttSlider->setValue(value);
ui->SourceVariableAttEntry->setValueQuiet(value); ui->SourceVariableAttEntry->setValueQuiet(value);
@ -64,11 +68,38 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
MakeReadOnly(ui->SourceLocked); MakeReadOnly(ui->SourceLocked);
MakeReadOnly(ui->LOLocked); MakeReadOnly(ui->LOLocked);
// connect(&dev, &LibreVNADriver::receivedPacket, this, [=](const Protocol::PacketInfo &p){ // ADC spectrum charts
// if(p.type == Protocol::PacketType::ManualStatus) { for(int i=0;i<4;i++) {
// NewStatus(p.manualStatus); charts[i] = new QChart();
// } spectrumSeries[i] = new QLineSeries;
// }, Qt::QueuedConnection);
auto pen = spectrumSeries[i]->pen();
pen.setWidth(2);
pen.setBrush(QBrush("blue"));
spectrumSeries[i]->setPen(pen);
auto xAxis = new QValueAxis;
xAxis->setTitleText("Frequency [MHz]");
xAxis->setRange(0,12.5);
auto yAxis = new QValueAxis;
yAxis->setTitleText("Amplitude [dBFS]");
yAxis->setRange(-120, 0);
charts[i]->legend()->hide();
charts[i]->addSeries(spectrumSeries[i]);
charts[i]->addAxis(xAxis, Qt::AlignBottom);
charts[i]->addAxis(yAxis, Qt::AlignLeft);
spectrumSeries[i]->attachAxis(xAxis);
spectrumSeries[i]->attachAxis(yAxis);
}
ui->spectrumA->setChart(charts[0]);
charts[0]->setTitle("ADC A Spectrum");
ui->spectrumB->setChart(charts[1]);
charts[1]->setTitle("ADC B Spectrum");
ui->spectrumC->setChart(charts[2]);
charts[2]->setTitle("ADC C Spectrum");
ui->spectrumD->setChart(charts[3]);
charts[3]->setTitle("ADC D Spectrum");
connect(ui->SourceCE, &QCheckBox::toggled, [=](bool) { UpdateDevice(); }); connect(ui->SourceCE, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
connect(ui->SourceRFEN, &QCheckBox::toggled, [=](bool) { UpdateDevice(); }); connect(ui->SourceRFEN, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
@ -79,11 +110,13 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
connect(ui->SourceAmp2En, &QCheckBox::toggled, [=](bool) { UpdateDevice(); }); connect(ui->SourceAmp2En, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
connect(ui->LOAmpEn, &QCheckBox::toggled, [=](bool) { UpdateDevice(); }); connect(ui->LOAmpEn, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
connect(ui->DACEnable, &QCheckBox::toggled, [=](bool) { UpdateDevice(); }); connect(ui->DACEnable, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
connect(ui->ADCEnable, &QCheckBox::toggled, [=](bool) { UpdateDevice(); });
connect(ui->SourceFilter, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); }); connect(ui->SourceFilter, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); });
connect(ui->SourceBandsel, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); }); connect(ui->SourceBandsel, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); });
connect(ui->SourcePortSel, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); }); connect(ui->SourcePortSel, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); });
connect(ui->LOMode, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); }); connect(ui->LOMode, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); });
connect(ui->ADCTestPattern, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) { UpdateDevice(); });
connect(ui->SourceFrequency, &SIUnitEdit::valueChanged, [=](double) { UpdateDevice(); }); connect(ui->SourceFrequency, &SIUnitEdit::valueChanged, [=](double) { UpdateDevice(); });
connect(ui->LOFrequency, &SIUnitEdit::valueChanged, [=](double) { UpdateDevice(); }); connect(ui->LOFrequency, &SIUnitEdit::valueChanged, [=](double) { UpdateDevice(); });
@ -93,6 +126,7 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
connect(ui->SourceStepAtt, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); }); connect(ui->SourceStepAtt, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); });
connect(ui->DACAmplitudeA, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); }); connect(ui->DACAmplitudeA, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); });
connect(ui->DACAmplitudeB, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); }); connect(ui->DACAmplitudeB, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); });
connect(ui->ADCSamples, qOverload<int>(&QSpinBox::valueChanged), [=](int) { UpdateDevice(); });
// Create the SCPI commands // Create the SCPI commands
@ -333,6 +367,47 @@ ManualControlDialogVFD::ManualControlDialogVFD(LibreVNADriver &dev, QWidget *par
addDoubleManualSetting("MANual:DACB_FREQ", &ManualControlDialogVFD::setDACBFrequency, &ManualControlDialogVFD::getDACBFrequency); addDoubleManualSetting("MANual:DACB_FREQ", &ManualControlDialogVFD::setDACBFrequency, &ManualControlDialogVFD::getDACBFrequency);
addIntegerManualSetting("MANual:DACB_AMPlitude", &ManualControlDialogVFD::setDACBAmplitude, &ManualControlDialogVFD::getDACBAmplitude); addIntegerManualSetting("MANual:DACB_AMPlitude", &ManualControlDialogVFD::setDACBAmplitude, &ManualControlDialogVFD::getDACBAmplitude);
addBooleanManualSetting("MANual:ADC_EN", &ManualControlDialogVFD::setADCEnable, &ManualControlDialogVFD::getADCEnable);
addIntegerManualSetting("MANual:ADC_SAMPLES", &ManualControlDialogVFD::setADCSamples, &ManualControlDialogVFD::getADCSamples);
addIntegerManualSetting("MANual:ADC_TESTPATTERN", &ManualControlDialogVFD::setADCTestPattern, &ManualControlDialogVFD::getADCTestPattern);
connect(&dev, &LibreVNADriver::receivedPacket, this, [=](const Protocol::PacketInfo &p){
if(p.type == Protocol::PacketType::ArrayData) {
// incoming spectrum data
const Protocol::ArrayData data = p.arrayData;
int index = 0;
auto series = spectrumSeries[data.id];
auto chart = charts[data.id];
chart->removeSeries(series);
// qDebug() << "Incoming spectrum data";
for(unsigned int i=0;i<data.values/2;i++) {
auto freq = data.xbegin + (data.xend - data.xbegin) * i / (data.values/2);
freq /= 1000000; // convert to MHz
auto d = std::complex<double>(data.data[i*2], data.data[i*2+1]);
auto dB = 20*log10(abs(d));
auto point = QPointF(freq, dB);
// get index at which this point should be inserted
while(index < series->count() && series->at(index).x() < freq) {
index++;
}
// qDebug() << "point at" << freq <<": " << dB << "(index:" << index << ")";
if(index >= series->count()) {
// append at the end
series->append(point);
} else if(freq == series->at(index).x()) {
// replace existing point
series->replace(index, point);
} else {
// insert at position
series->insert(index, point);
}
}
chart->addSeries(series);
series->attachAxis(chart->axes(Qt::Horizontal)[0]);
series->attachAxis(chart->axes(Qt::Vertical)[0]);
}
}, Qt::QueuedConnection);
for(auto c : commands) { for(auto c : commands) {
emit dev.addSCPICommand(c); emit dev.addSCPICommand(c);
} }
@ -627,6 +702,36 @@ int ManualControlDialogVFD::getDACBAmplitude()
return ui->DACAmplitudeB->value(); return ui->DACAmplitudeB->value();
} }
void ManualControlDialogVFD::setADCEnable(bool enable)
{
ui->ADCEnable->setChecked(enable);
}
bool ManualControlDialogVFD::getADCEnable()
{
return ui->ADCEnable->isChecked();
}
void ManualControlDialogVFD::setADCSamples(int samples)
{
ui->ADCSamples->setValue(samples);
}
int ManualControlDialogVFD::getADCSamples()
{
return ui->ADCSamples->value();
}
void ManualControlDialogVFD::setADCTestPattern(int tp)
{
ui->ADCTestPattern->setCurrentIndex(tp);
}
int ManualControlDialogVFD::getADCTestPattern()
{
return ui->ADCTestPattern->currentIndex();
}
void ManualControlDialogVFD::UpdateDevice() void ManualControlDialogVFD::UpdateDevice()
{ {
Protocol::PacketInfo p; Protocol::PacketInfo p;
@ -659,6 +764,11 @@ void ManualControlDialogVFD::UpdateDevice()
m.DACAmpB = ui->DACAmplitudeB->value(); m.DACAmpB = ui->DACAmplitudeB->value();
m.DACEn = ui->DACEnable->isChecked(); m.DACEn = ui->DACEnable->isChecked();
// ADC
m.ADCEn = ui->ADCEnable->isChecked();
m.ADCSamples = ui->ADCSamples->value();
m.ADCTestPattern = ui->ADCTestPattern->currentIndex();
qDebug() << "Updating manual control state"; qDebug() << "Updating manual control state";
dev.SendPacket(p); dev.SendPacket(p);

View file

@ -4,6 +4,8 @@
#include "librevnadriver.h" #include "librevnadriver.h"
#include <QDialog> #include <QDialog>
#include <QChart>
#include <QLineSeries>
#include <complex> #include <complex>
namespace Ui { namespace Ui {
@ -106,12 +108,24 @@ public:
void setDACBAmplitude(int a); void setDACBAmplitude(int a);
int getDACBAmplitude(); int getDACBAmplitude();
void setADCEnable(bool enable);
bool getADCEnable();
void setADCSamples(int samples);
int getADCSamples();
void setADCTestPattern(int tp);
int getADCTestPattern();
private: private:
void UpdateDevice(); void UpdateDevice();
Ui::ManualControlDialogVFD *ui; Ui::ManualControlDialogVFD *ui;
LibreVNADriver &dev; LibreVNADriver &dev;
std::vector<SCPICommand*> commands; std::vector<SCPICommand*> commands;
std::array<QChart*, 4> charts;
std::array<QLineSeries*, 4> spectrumSeries;
}; };
#endif // MANUALCONTROLDIALOGV1_H #endif // MANUALCONTROLDIALOGV1_H

View file

@ -9,20 +9,20 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>640</width> <width>1270</width>
<height>453</height> <height>827</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Manual Control</string> <string>Manual Control</string>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<item> <item>
<widget class="QGroupBox" name="groupBox_10"> <widget class="QGroupBox" name="groupBox_10">
<property name="title"> <property name="title">
<string>Signal Generation</string> <string>Signal Generation</string>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QGroupBox" name="groupBox_3"> <widget class="QGroupBox" name="groupBox_3">
<property name="title"> <property name="title">
@ -265,162 +265,292 @@
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <widget class="QGroupBox" name="groupBox">
<item> <property name="title">
<widget class="QGroupBox" name="groupBox_2"> <string>DAC</string>
<property name="title"> </property>
<string>LO PLL</string> <layout class="QFormLayout" name="formLayout_2">
</property> <item row="0" column="0">
<layout class="QFormLayout" name="formLayout"> <widget class="QLabel" name="label_4">
<item row="3" column="0"> <property name="text">
<widget class="QLabel" name="label_5"> <string>Enabled:</string>
<property name="text"> </property>
<string>Frequency:</string> </widget>
</property> </item>
</widget> <item row="0" column="1">
<widget class="QCheckBox" name="DACEnable">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Output A Frequency:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="SIUnitEdit" name="DACFrequencyA"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Output A Amplitude:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="DACAmplitudeA">
<property name="maximum">
<number>2047</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Output A Frequency:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="SIUnitEdit" name="DACFrequencyB"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Output A Amplitude:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="DACAmplitudeB">
<property name="maximum">
<number>2047</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>LO PLL</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Frequency:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="SIUnitEdit" name="LOFrequency"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Mode:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="LOMode">
<item>
<property name="text">
<string>Internal - HF</string>
</property>
</item> </item>
<item row="3" column="1"> <item>
<widget class="SIUnitEdit" name="LOFrequency"/> <property name="text">
<string>Internal -LF</string>
</property>
</item> </item>
<item row="4" column="0"> <item>
<widget class="QLabel" name="label"> <property name="text">
<property name="text"> <string>External</string>
<string>Mode:</string> </property>
</property>
</widget>
</item> </item>
<item row="4" column="1"> </widget>
<widget class="QComboBox" name="LOMode"> </item>
<item> <item row="2" column="1">
<property name="text"> <widget class="QCheckBox" name="LOLocked">
<string>Internal - HF</string> <property name="enabled">
</property> <bool>true</bool>
</item> </property>
<item> <property name="text">
<property name="text"> <string>Locked</string>
<string>Internal -LF</string> </property>
</property> </widget>
</item> </item>
<item> <item row="1" column="1">
<property name="text"> <widget class="QCheckBox" name="LORFEN">
<string>External</string> <property name="text">
</property> <string>RF Enable</string>
</item> </property>
</widget> </widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="LOCE">
<property name="text">
<string>Chip Enable</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Amplifier:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="LOAmpEn">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Data Acquisition</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Spectrum View</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QChartView" name="spectrumA"/>
</item>
<item row="0" column="1">
<widget class="QChartView" name="spectrumB"/>
</item>
<item row="1" column="0">
<widget class="QChartView" name="spectrumC"/>
</item>
<item row="1" column="1">
<widget class="QChartView" name="spectrumD"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Settings</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>ADC Enable:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="ADCEnable">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Samples:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="ADCSamples">
<property name="minimum">
<number>16</number>
</property>
<property name="maximum">
<number>131072</number>
</property>
<property name="singleStep">
<number>16</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Testpattern:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="ADCTestPattern">
<item>
<property name="text">
<string>Off</string>
</property>
</item> </item>
<item row="2" column="1"> <item>
<widget class="QCheckBox" name="LOLocked"> <property name="text">
<property name="enabled"> <string>Zeros</string>
<bool>true</bool> </property>
</property>
<property name="text">
<string>Locked</string>
</property>
</widget>
</item> </item>
<item row="1" column="1"> <item>
<widget class="QCheckBox" name="LORFEN"> <property name="text">
<property name="text"> <string>Ones</string>
<string>RF Enable</string> </property>
</property>
</widget>
</item> </item>
<item row="0" column="1"> <item>
<widget class="QCheckBox" name="LOCE"> <property name="text">
<property name="text"> <string>Toggle</string>
<string>Chip Enable</string> </property>
</property>
</widget>
</item> </item>
<item row="5" column="0"> <item>
<widget class="QLabel" name="label_15"> <property name="text">
<property name="text"> <string>Ramp</string>
<string>Amplifier:</string> </property>
</property>
</widget>
</item> </item>
<item row="5" column="1"> <item>
<widget class="QCheckBox" name="LOAmpEn"> <property name="text">
<property name="text"> <string>Custom</string>
<string/> </property>
</property>
</widget>
</item> </item>
</layout> <item>
</widget> <property name="text">
</item> <string>Deskew</string>
<item> </property>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>DAC</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Enabled:</string>
</property>
</widget>
</item> </item>
<item row="0" column="1"> <item>
<widget class="QCheckBox" name="DACEnable"> <property name="text">
<property name="text"> <string>Reserved</string>
<string/> </property>
</property>
</widget>
</item> </item>
<item row="1" column="0"> <item>
<widget class="QLabel" name="label_6"> <property name="text">
<property name="text"> <string>PRBS</string>
<string>Output A Frequency:</string> </property>
</property>
</widget>
</item> </item>
<item row="1" column="1"> <item>
<widget class="SIUnitEdit" name="DACFrequencyA"/> <property name="text">
<string>Sine</string>
</property>
</item> </item>
<item row="2" column="0"> </widget>
<widget class="QLabel" name="label_7"> </item>
<property name="text"> </layout>
<string>Output A Amplitude:</string> </widget>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="DACAmplitudeA">
<property name="maximum">
<number>2047</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Output A Frequency:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="SIUnitEdit" name="DACFrequencyB"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Output A Amplitude:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="DACAmplitudeB">
<property name="maximum">
<number>2047</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -433,6 +563,11 @@
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>CustomWidgets/siunitedit.h</header> <header>CustomWidgets/siunitedit.h</header>
</customwidget> </customwidget>
<customwidget>
<class>QChartView</class>
<extends>QGraphicsView</extends>
<header>QtCharts</header>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View file

@ -330,7 +330,7 @@ mac{
PKGCONFIG += libusb-1.0 PKGCONFIG += libusb-1.0
} }
QT += widgets network QT += widgets network charts
FORMS += \ FORMS += \
Calibration/CalStandardLineEditDialog.ui \ Calibration/CalStandardLineEditDialog.ui \

View file

@ -1,4 +1,4 @@
QT += testlib widgets network QT += testlib widgets network charts
CONFIG += qt console warn_on depend_includepath testcase CONFIG += qt console warn_on depend_includepath testcase
CONFIG -= app_bundle CONFIG -= app_bundle

View file

@ -5,45 +5,48 @@
namespace PacketConstants { namespace PacketConstants {
// USB protocol packet field constants // USB protocol packet field constants
static constexpr uint8_t PCKT_HEADER_DATA = 0x5A; static constexpr uint8_t PCKT_HEADER_DATA = 0x5A;
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// General packet structure field sizes and offsets in bytes // General packet structure field sizes and offsets in bytes
static constexpr uint8_t PCKT_HEADER_OFFSET = 0; static constexpr uint8_t PCKT_HEADER_OFFSET = 0;
static constexpr uint8_t PCKT_HEADER_LEN = 1; static constexpr uint8_t PCKT_HEADER_LEN = 1;
static constexpr uint8_t PCKT_LENGTH_OFFSET = PCKT_HEADER_OFFSET + PCKT_HEADER_LEN; // offset one byte static constexpr uint8_t PCKT_LENGTH_OFFSET = PCKT_HEADER_OFFSET + PCKT_HEADER_LEN; // offset one byte
static constexpr uint8_t PCKT_LENGTH_LEN = 2; static constexpr uint8_t PCKT_LENGTH_LEN = 2;
static constexpr uint8_t PCKT_TYPE_OFFSET = PCKT_LENGTH_OFFSET + PCKT_LENGTH_LEN; // offset three bytes static constexpr uint8_t PCKT_TYPE_OFFSET = PCKT_LENGTH_OFFSET + PCKT_LENGTH_LEN; // offset three bytes
static constexpr uint8_t PCKT_TYPE_LEN = 1; static constexpr uint8_t PCKT_TYPE_LEN = 1;
static constexpr uint8_t PCKT_PAYLOAD_OFFSET = PCKT_TYPE_OFFSET + PCKT_TYPE_LEN; // offset four bytes static constexpr uint8_t PCKT_PAYLOAD_OFFSET = PCKT_TYPE_OFFSET + PCKT_TYPE_LEN; // offset four bytes
static constexpr uint8_t PCKT_CRC_LEN = 4; static constexpr uint8_t PCKT_CRC_LEN = 4;
static constexpr uint8_t PCKT_COMBINED_HEADER_LEN = PCKT_HEADER_LEN + PCKT_LENGTH_LEN + PCKT_TYPE_LEN; // combined length of fields preceding payload static constexpr uint8_t PCKT_COMBINED_HEADER_LEN = PCKT_HEADER_LEN + PCKT_LENGTH_LEN + PCKT_TYPE_LEN; // combined length of fields preceding payload
static constexpr uint8_t PCKT_EXCL_PAYLOAD_LEN = PCKT_COMBINED_HEADER_LEN + PCKT_CRC_LEN; // combined length of all packet fields, excluding payload static constexpr uint8_t PCKT_EXCL_PAYLOAD_LEN = PCKT_COMBINED_HEADER_LEN + PCKT_CRC_LEN; // combined length of all packet fields, excluding payload
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// Payload content // Payload content
// Firmware packets // Firmware packets
static constexpr uint16_t FW_CHUNK_SIZE = 256; static constexpr uint16_t FW_CHUNK_SIZE = 256;
// VNADataPoint payload fields in bytes // VNADataPoint payload fields in bytes
static constexpr uint8_t DPNT_FREQ_LEN = 8; static constexpr uint8_t DPNT_FREQ_LEN = 8;
static constexpr uint8_t DPNT_POW_LVL_LEN = 2; static constexpr uint8_t DPNT_POW_LVL_LEN = 2;
static constexpr uint8_t DPNT_PNT_NUM_LEN = 2; static constexpr uint8_t DPNT_PNT_NUM_LEN = 2;
static constexpr uint8_t DPNT_REAL_PART_LEN = 4; static constexpr uint8_t DPNT_REAL_PART_LEN = 4;
static constexpr uint8_t DPNT_IMAG_PART_LEN = 4; static constexpr uint8_t DPNT_IMAG_PART_LEN = 4;
static constexpr uint8_t DPNT_DESC_LEN = 1; static constexpr uint8_t DPNT_DESC_LEN = 1;
// VNADataPoint configuration bitmask offsets in bits // VNADataPoint configuration bitmask offsets in bits
static constexpr uint8_t DPNT_CONF_P1_OFFSET = 0; static constexpr uint8_t DPNT_CONF_P1_OFFSET = 0;
static constexpr uint8_t DPNT_CONF_P2_OFFSET = 1; static constexpr uint8_t DPNT_CONF_P2_OFFSET = 1;
static constexpr uint8_t DPNT_CONF_P3_OFFSET = 2; static constexpr uint8_t DPNT_CONF_P3_OFFSET = 2;
static constexpr uint8_t DPNT_CONF_P4_OFFSET = 3; static constexpr uint8_t DPNT_CONF_P4_OFFSET = 3;
static constexpr uint8_t DPNT_CONF_REF_OFFSET = 4; static constexpr uint8_t DPNT_CONF_REF_OFFSET = 4;
static constexpr uint8_t DPNT_CONF_STAGE_OFFSET = 5; static constexpr uint8_t DPNT_CONF_STAGE_OFFSET = 5;
// DataArray packets
static constexpr uint16_t ARRAY_PCKT_MAX_NUM = 62;
} }

View file

@ -13,42 +13,42 @@
#define CRC32_POLYGON 0xEDB88320 #define CRC32_POLYGON 0xEDB88320
uint32_t Protocol::CRC32(uint32_t crc, const void *data, uint32_t len) { uint32_t Protocol::CRC32(uint32_t crc, const void *data, uint32_t len) {
uint8_t *u8buf = (uint8_t*) data; uint8_t *u8buf = (uint8_t*) data;
int k; int k;
crc = ~crc; crc = ~crc;
while (len--) { while (len--) {
crc ^= *u8buf++; crc ^= *u8buf++;
for (k = 0; k < 8; k++) for (k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ CRC32_POLYGON : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ CRC32_POLYGON : crc >> 1;
} }
return ~crc; return ~crc;
} }
uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) { uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
if (!info || !len) { if (!info || !len) {
info->type = PacketType::None; info->type = PacketType::None;
return 0; return 0;
} }
uint8_t *data = buf; uint8_t *data = buf;
/* Remove any out-of-order bytes in front of the frame */ /* Remove any out-of-order bytes in front of the frame */
while (*data != PCKT_HEADER_DATA) { while (*data != PCKT_HEADER_DATA) {
data++; data++;
if(--len == 0) { if(--len == 0) {
/* Reached end of data */ /* Reached end of data */
/* No frame contained in data */ /* No frame contained in data */
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
} }
/* At this point, data points to the beginning of the frame */ /* At this point, data points to the beginning of the frame */
if(len < PCKT_COMBINED_HEADER_LEN) { if(len < PCKT_COMBINED_HEADER_LEN) {
/* the frame header has not been completely received */ /* the frame header has not been completely received */
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
/* Evaluate frame size */ /* Evaluate frame size */
uint16_t length = data[PCKT_LENGTH_OFFSET] | ((uint16_t) data[2] << 8); uint16_t length = data[PCKT_LENGTH_OFFSET] | ((uint16_t) data[2] << 8);
if(length > sizeof(PacketInfo) * 2 || length < PCKT_EXCL_PAYLOAD_LEN) { if(length > sizeof(PacketInfo) * 2 || length < PCKT_EXCL_PAYLOAD_LEN) {
@ -58,46 +58,46 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) {
} }
if(len < length) { if(len < length) {
/* The frame payload has not been completely received */ /* The frame payload has not been completely received */
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
/* The complete frame has been received, check checksum */ /* The complete frame has been received, check checksum */
auto type = (PacketType) data[PCKT_TYPE_OFFSET]; auto type = (PacketType) data[PCKT_TYPE_OFFSET];
uint32_t crc = (uint32_t) data[length-4] | ((uint32_t) data[length-3] << 8) | ((uint32_t) data[length-2] << 16) | ((uint32_t) data[length-1] << 24); uint32_t crc = (uint32_t) data[length-4] | ((uint32_t) data[length-3] << 8) | ((uint32_t) data[length-2] << 16) | ((uint32_t) data[length-1] << 24);
if(type != PacketType::VNADatapoint) { if(type != PacketType::VNADatapoint) {
uint32_t compare = CRC32(0, data, length - PCKT_CRC_LEN); uint32_t compare = CRC32(0, data, length - PCKT_CRC_LEN);
if(crc != compare) { if(crc != compare) {
// CRC mismatch, remove header // CRC mismatch, remove header
data += 1; data += 1;
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
// Valid packet, copy packet type and payload // Valid packet, copy packet type and payload
memcpy(info, &data[PCKT_TYPE_OFFSET], length - 7); memcpy(info, &data[PCKT_TYPE_OFFSET], length - 7);
} else { } else {
// Datapoint has the CRC set to zero // Datapoint has the CRC set to zero
if(crc != 0x00000000) { if(crc != 0x00000000) {
data += 1; data += 1;
info->type = PacketType::None; info->type = PacketType::None;
return data - buf; return data - buf;
} }
// Create the datapoint // Create the datapoint
info->type = (PacketType) data[PCKT_TYPE_OFFSET]; info->type = (PacketType) data[PCKT_TYPE_OFFSET];
info->VNAdatapoint = new VNADatapoint<32>; info->VNAdatapoint = new VNADatapoint<32>;
info->VNAdatapoint->decode(&data[PCKT_PAYLOAD_OFFSET], length - PCKT_EXCL_PAYLOAD_LEN); info->VNAdatapoint->decode(&data[PCKT_PAYLOAD_OFFSET], length - PCKT_EXCL_PAYLOAD_LEN);
} }
return data - buf + length; return data - buf + length;
} }
uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize) { uint16_t Protocol::GetRequiredSize(const PacketInfo &packet) {
int16_t payload_size = 0; int16_t payload_size = 0;
switch (packet.type) { switch (packet.type) {
// case PacketType::Datapoint: payload_size = sizeof(packet.datapoint); break; // case PacketType::Datapoint: payload_size = sizeof(packet.datapoint); break;
case PacketType::SweepSettings: payload_size = sizeof(packet.settings); break; case PacketType::SweepSettings: payload_size = sizeof(packet.settings); break;
case PacketType::Reference: payload_size = sizeof(packet.reference); break; case PacketType::Reference: payload_size = sizeof(packet.reference); break;
case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break; case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break;
case PacketType::DeviceStatus: payload_size = sizeof(packet.status); break; case PacketType::DeviceStatus: payload_size = sizeof(packet.status); break;
case PacketType::ManualStatus: payload_size = sizeof(packet.manualStatus); break; case PacketType::ManualStatus: payload_size = sizeof(packet.manualStatus); break;
@ -129,32 +129,38 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
// no payload // no payload
break; break;
case PacketType::VNADatapoint: payload_size = packet.VNAdatapoint->requiredBufferSize(); break; case PacketType::VNADatapoint: payload_size = packet.VNAdatapoint->requiredBufferSize(); break;
case PacketType::ArrayData: payload_size = 12 + packet.arrayData.values * 4; break;
case PacketType::None: case PacketType::None:
break; break;
} }
if (payload_size < 0 || payload_size + PCKT_EXCL_PAYLOAD_LEN > destsize) {
// encoding failed, buffer too small return payload_size + PCKT_EXCL_PAYLOAD_LEN;
return 0; }
}
// Write header uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize) {
dest[PCKT_HEADER_OFFSET] = PCKT_HEADER_DATA; uint16_t overall_size = GetRequiredSize(packet);
uint16_t overall_size = payload_size + PCKT_EXCL_PAYLOAD_LEN; if(overall_size > destsize) {
memcpy(&dest[PCKT_LENGTH_OFFSET], &overall_size, PCKT_LENGTH_LEN); // encoding faile, buffer too small
// Further encoding uses a special case for VNADatapoint packettype return 0;
uint32_t crc = 0x00000000; }
if(packet.type == PacketType::VNADatapoint) { // Write header
// CRC calculation takes about 18us which is the bulk of the time required to encode and transmit a datapoint. dest[PCKT_HEADER_OFFSET] = PCKT_HEADER_DATA;
// Skip CRC for data points to optimize throughput memcpy(&dest[PCKT_LENGTH_OFFSET], &overall_size, PCKT_LENGTH_LEN);
dest[PCKT_TYPE_OFFSET] = (uint8_t) packet.type; // Further encoding uses a special case for VNADatapoint packettype
packet.VNAdatapoint->encode(&dest[PCKT_PAYLOAD_OFFSET], destsize - PCKT_EXCL_PAYLOAD_LEN); uint32_t crc = 0x00000000;
crc = 0x00000000; if(packet.type == PacketType::VNADatapoint) {
} else { // CRC calculation takes about 18us which is the bulk of the time required to encode and transmit a datapoint.
// Copy rest of the packet // Skip CRC for data points to optimize throughput
memcpy(&dest[PCKT_TYPE_OFFSET], &packet, payload_size + PCKT_TYPE_LEN); // one additional byte for the packet type dest[PCKT_TYPE_OFFSET] = (uint8_t) packet.type;
// Calculate the CRC packet.VNAdatapoint->encode(&dest[PCKT_PAYLOAD_OFFSET], destsize - PCKT_EXCL_PAYLOAD_LEN);
crc = CRC32(0, dest, overall_size - PCKT_CRC_LEN); crc = 0x00000000;
} } else {
memcpy(&dest[overall_size - PCKT_CRC_LEN], &crc, PCKT_CRC_LEN); // Copy rest of the packet
return overall_size; memcpy(&dest[PCKT_TYPE_OFFSET], &packet, overall_size - PCKT_EXCL_PAYLOAD_LEN + PCKT_TYPE_LEN); // one additional byte for the packet type
// Calculate the CRC
crc = CRC32(0, dest, overall_size - PCKT_CRC_LEN);
}
memcpy(&dest[overall_size - PCKT_CRC_LEN], &crc, PCKT_CRC_LEN);
return overall_size;
} }

View file

@ -15,56 +15,56 @@ static constexpr uint16_t Version = 14;
#pragma pack(push, 1) #pragma pack(push, 1)
enum class Source : uint8_t { enum class Source : uint8_t {
Port1 = 0x01, Port1 = 0x01,
Port2 = 0x02, Port2 = 0x02,
Port3 = 0x04, Port3 = 0x04,
Port4 = 0x08, Port4 = 0x08,
Reference = 0x10, Reference = 0x10,
}; };
template<int s> class VNADatapoint { template<int s> class VNADatapoint {
public: public:
VNADatapoint() { VNADatapoint() {
clear(); clear();
} }
void clear() { void clear() {
num_values = 0; num_values = 0;
pointNum = 0; pointNum = 0;
cdBm = 0; cdBm = 0;
frequency = 0; frequency = 0;
} }
bool addValue(float real, float imag, uint8_t stage, int sourceMask) { bool addValue(float real, float imag, uint8_t stage, int sourceMask) {
if(num_values >= s) { if(num_values >= s) {
return false; return false;
} }
real_values[num_values] = real; real_values[num_values] = real;
imag_values[num_values] = imag; imag_values[num_values] = imag;
descr_values[num_values] = stage << DPNT_CONF_STAGE_OFFSET | sourceMask; descr_values[num_values] = stage << DPNT_CONF_STAGE_OFFSET | sourceMask;
num_values++; num_values++;
return true; return true;
} }
bool encode(uint8_t *dest, uint16_t destSize) { bool encode(uint8_t *dest, uint16_t destSize) {
if(requiredBufferSize() > destSize) { if(requiredBufferSize() > destSize) {
return false; return false;
} }
memcpy(dest, &frequency, DPNT_FREQ_LEN); memcpy(dest, &frequency, DPNT_FREQ_LEN);
dest += DPNT_FREQ_LEN; dest += DPNT_FREQ_LEN;
memcpy(dest, &cdBm, DPNT_POW_LVL_LEN); memcpy(dest, &cdBm, DPNT_POW_LVL_LEN);
dest += DPNT_POW_LVL_LEN; dest += DPNT_POW_LVL_LEN;
memcpy(dest, &pointNum, DPNT_PNT_NUM_LEN); memcpy(dest, &pointNum, DPNT_PNT_NUM_LEN);
dest += DPNT_PNT_NUM_LEN; dest += DPNT_PNT_NUM_LEN;
memcpy(dest, real_values, num_values * DPNT_REAL_PART_LEN); memcpy(dest, real_values, num_values * DPNT_REAL_PART_LEN);
dest += num_values * DPNT_REAL_PART_LEN; dest += num_values * DPNT_REAL_PART_LEN;
memcpy(dest, imag_values, num_values * DPNT_IMAG_PART_LEN); memcpy(dest, imag_values, num_values * DPNT_IMAG_PART_LEN);
dest += num_values * DPNT_IMAG_PART_LEN; dest += num_values * DPNT_IMAG_PART_LEN;
memcpy(dest, descr_values, num_values); memcpy(dest, descr_values, num_values);
return true; return true;
} }
void decode(const uint8_t *buffer, uint16_t size) { void decode(const uint8_t *buffer, uint16_t size) {
num_values = (size - (DPNT_FREQ_LEN + DPNT_POW_LVL_LEN + DPNT_PNT_NUM_LEN)) / num_values = (size - (DPNT_FREQ_LEN + DPNT_POW_LVL_LEN + DPNT_PNT_NUM_LEN)) /
(DPNT_REAL_PART_LEN + DPNT_IMAG_PART_LEN + DPNT_DESC_LEN); (DPNT_REAL_PART_LEN + DPNT_IMAG_PART_LEN + DPNT_DESC_LEN);
memcpy(&frequency, buffer, DPNT_FREQ_LEN); memcpy(&frequency, buffer, DPNT_FREQ_LEN);
buffer += DPNT_FREQ_LEN; buffer += DPNT_FREQ_LEN;
memcpy(&cdBm, buffer, DPNT_POW_LVL_LEN); memcpy(&cdBm, buffer, DPNT_POW_LVL_LEN);
@ -76,25 +76,25 @@ public:
memcpy(imag_values, buffer, num_values * DPNT_IMAG_PART_LEN); memcpy(imag_values, buffer, num_values * DPNT_IMAG_PART_LEN);
buffer += num_values * DPNT_IMAG_PART_LEN; buffer += num_values * DPNT_IMAG_PART_LEN;
memcpy(descr_values, buffer, num_values); memcpy(descr_values, buffer, num_values);
} }
std::complex<double> getValue(uint8_t stage, uint8_t port, bool reference) { std::complex<double> getValue(uint8_t stage, uint8_t port, bool reference) {
uint8_t sourceMask = 0; uint8_t sourceMask = 0;
sourceMask |= 0x01 << port; sourceMask |= 0x01 << port;
if(reference) { if(reference) {
sourceMask |= (int) Source::Reference; sourceMask |= (int) Source::Reference;
} }
for(int i=0;i<num_values;i++) { for(int i=0;i<num_values;i++) {
if(descr_values[i] >> DPNT_CONF_STAGE_OFFSET != stage) { if(descr_values[i] >> DPNT_CONF_STAGE_OFFSET != stage) {
continue; continue;
} }
if((descr_values[i] & sourceMask) != sourceMask) { if((descr_values[i] & sourceMask) != sourceMask) {
continue; continue;
} }
return std::complex<double>(real_values[i], imag_values[i]); return std::complex<double>(real_values[i], imag_values[i]);
} }
return std::numeric_limits<std::complex<double>>::quiet_NaN(); return std::numeric_limits<std::complex<double>>::quiet_NaN();
} }
class Value { class Value {
public: public:
@ -115,104 +115,104 @@ public:
return num_values; return num_values;
} }
uint16_t requiredBufferSize() { uint16_t requiredBufferSize() {
return DPNT_FREQ_LEN + DPNT_POW_LVL_LEN + DPNT_PNT_NUM_LEN + return DPNT_FREQ_LEN + DPNT_POW_LVL_LEN + DPNT_PNT_NUM_LEN +
num_values * (DPNT_REAL_PART_LEN + DPNT_IMAG_PART_LEN + DPNT_DESC_LEN); num_values * (DPNT_REAL_PART_LEN + DPNT_IMAG_PART_LEN + DPNT_DESC_LEN);
} }
union { union {
uint64_t frequency; uint64_t frequency;
uint64_t us; uint64_t us;
}; };
int16_t cdBm; int16_t cdBm;
uint16_t pointNum; uint16_t pointNum;
private: private:
float real_values[s]; float real_values[s];
float imag_values[s]; float imag_values[s];
uint8_t descr_values[s]; uint8_t descr_values[s];
uint8_t num_values; uint8_t num_values;
}; };
using Datapoint = struct _datapoint { using Datapoint = struct _datapoint {
float real_S11, imag_S11; float real_S11, imag_S11;
float real_S21, imag_S21; float real_S21, imag_S21;
float real_S12, imag_S12; float real_S12, imag_S12;
float real_S22, imag_S22; float real_S22, imag_S22;
union { union {
struct { struct {
// for non-zero span // for non-zero span
uint64_t frequency; uint64_t frequency;
int16_t cdbm; int16_t cdbm;
}; };
struct { struct {
// for zero span // for zero span
uint64_t us; // time in us since first datapoint uint64_t us; // time in us since first datapoint
}; };
}; };
uint16_t pointNum; uint16_t pointNum;
}; };
using SweepSettings = struct _sweepSettings { using SweepSettings = struct _sweepSettings {
uint64_t f_start; uint64_t f_start;
uint64_t f_stop; uint64_t f_stop;
uint16_t points; uint16_t points;
uint32_t if_bandwidth; uint32_t if_bandwidth;
int16_t cdbm_excitation_start; // in 1/100 dbm int16_t cdbm_excitation_start; // in 1/100 dbm
uint8_t standby:1; uint8_t standby:1;
uint8_t syncMaster:1; uint8_t syncMaster:1;
uint8_t suppressPeaks:1; uint8_t suppressPeaks:1;
uint8_t fixedPowerSetting:1; // if set the attenuator and source PLL power will not be changed across the sweep uint8_t fixedPowerSetting:1; // if set the attenuator and source PLL power will not be changed across the sweep
uint8_t logSweep:1; uint8_t logSweep:1;
/* /*
* 0: no synchronization * 0: no synchronization
* 1: USB synchronization * 1: USB synchronization
* 2: External reference synchronization * 2: External reference synchronization
* 3: Trigger synchronization (not supported yet by hardware) * 3: Trigger synchronization (not supported yet by hardware)
*/ */
uint8_t syncMode:2; uint8_t syncMode:2;
uint8_t unused1:1; uint8_t unused1:1;
uint16_t stages:3; uint16_t stages:3;
uint16_t port1Stage:3; uint16_t port1Stage:3;
uint16_t port2Stage:3; uint16_t port2Stage:3;
uint16_t port3Stage:3; uint16_t port3Stage:3;
uint16_t port4Stage:3; uint16_t port4Stage:3;
uint16_t unused2:1; uint16_t unused2:1;
int16_t cdbm_excitation_stop; // in 1/100 dbm int16_t cdbm_excitation_stop; // in 1/100 dbm
uint16_t dwell_time; // in us uint16_t dwell_time; // in us
}; };
using ReferenceSettings = struct _referenceSettings { using ReferenceSettings = struct _referenceSettings {
uint32_t ExtRefOuputFreq; uint32_t ExtRefOuputFreq;
uint8_t AutomaticSwitch:1; uint8_t AutomaticSwitch:1;
uint8_t UseExternalRef:1; uint8_t UseExternalRef:1;
}; };
using GeneratorSettings = struct _generatorSettings { using GeneratorSettings = struct _generatorSettings {
uint64_t frequency; uint64_t frequency;
int16_t cdbm_level; int16_t cdbm_level;
uint8_t activePort :3; uint8_t activePort :3;
uint8_t applyAmplitudeCorrection :1; uint8_t applyAmplitudeCorrection :1;
uint8_t unused :4; uint8_t unused :4;
}; };
using DeviceInfo = struct _deviceInfo { using DeviceInfo = struct _deviceInfo {
uint16_t ProtocolVersion; uint16_t ProtocolVersion;
uint8_t FW_major; uint8_t FW_major;
uint8_t FW_minor; uint8_t FW_minor;
uint8_t FW_patch; uint8_t FW_patch;
uint8_t hardware_version; uint8_t hardware_version;
char HW_Revision; char HW_Revision;
uint64_t limits_minFreq; uint64_t limits_minFreq;
uint64_t limits_maxFreq; uint64_t limits_maxFreq;
uint32_t limits_minIFBW; uint32_t limits_minIFBW;
uint32_t limits_maxIFBW; uint32_t limits_maxIFBW;
uint16_t limits_maxPoints; uint16_t limits_maxPoints;
int16_t limits_cdbm_min; int16_t limits_cdbm_min;
int16_t limits_cdbm_max; int16_t limits_cdbm_max;
uint32_t limits_minRBW; uint32_t limits_minRBW;
uint32_t limits_maxRBW; uint32_t limits_maxRBW;
uint8_t limits_maxAmplitudePoints; uint8_t limits_maxAmplitudePoints;
uint64_t limits_maxFreqHarmonic; uint64_t limits_maxFreqHarmonic;
uint8_t num_ports; uint8_t num_ports;
@ -220,26 +220,26 @@ using DeviceInfo = struct _deviceInfo {
}; };
using DeviceStatus = struct _deviceStatus { using DeviceStatus = struct _deviceStatus {
union { union {
struct { struct {
uint8_t extRefAvailable:1; uint8_t extRefAvailable:1;
uint8_t extRefInUse:1; uint8_t extRefInUse:1;
uint8_t FPGA_configured:1; uint8_t FPGA_configured:1;
uint8_t source_locked:1; uint8_t source_locked:1;
uint8_t LO1_locked:1; uint8_t LO1_locked:1;
uint8_t ADC_overload:1; uint8_t ADC_overload:1;
uint8_t unlevel:1; uint8_t unlevel:1;
uint8_t temp_source; uint8_t temp_source;
uint8_t temp_LO1; uint8_t temp_LO1;
uint8_t temp_MCU; uint8_t temp_MCU;
} V1; } V1;
struct { struct {
uint8_t source_locked:1; uint8_t source_locked:1;
uint8_t LO_locked:1; uint8_t LO_locked:1;
uint8_t ADC_overload:1; uint8_t ADC_overload:1;
uint8_t unlevel:1; uint8_t unlevel:1;
uint8_t temp_MCU; uint8_t temp_MCU;
} VFF; } VFF;
struct { struct {
uint8_t source_locked:1; uint8_t source_locked:1;
uint8_t LO_locked:1; uint8_t LO_locked:1;
@ -249,32 +249,32 @@ using DeviceStatus = struct _deviceStatus {
uint16_t temp_eCal; // in 1/100 °C uint16_t temp_eCal; // in 1/100 °C
uint16_t power_heater; // in mW uint16_t power_heater; // in mW
} VFE; } VFE;
}; };
}; };
using ManualStatus = struct _manualstatus { using ManualStatus = struct _manualstatus {
union { union {
struct { struct {
int16_t port1min, port1max; int16_t port1min, port1max;
int16_t port2min, port2max; int16_t port2min, port2max;
int16_t refmin, refmax; int16_t refmin, refmax;
float port1real, port1imag; float port1real, port1imag;
float port2real, port2imag; float port2real, port2imag;
float refreal, refimag; float refreal, refimag;
uint8_t temp_source; uint8_t temp_source;
uint8_t temp_LO; uint8_t temp_LO;
uint8_t source_locked :1; uint8_t source_locked :1;
uint8_t LO_locked :1; uint8_t LO_locked :1;
} V1; } V1;
struct { struct {
int16_t portmin, portmax; int16_t portmin, portmax;
int16_t refmin, refmax; int16_t refmin, refmax;
float portreal, portimag; float portreal, portimag;
float refreal, refimag; float refreal, refimag;
uint8_t source_locked :1; uint8_t source_locked :1;
uint8_t LO_locked :1; uint8_t LO_locked :1;
} VFF; } VFF;
struct { struct {
int16_t portmin, portmax; int16_t portmin, portmax;
int16_t refmin, refmax; int16_t refmin, refmax;
@ -285,41 +285,41 @@ using ManualStatus = struct _manualstatus {
uint16_t temp_eCal; // in 1/100 °C uint16_t temp_eCal; // in 1/100 °C
uint16_t power_heater; // in mW uint16_t power_heater; // in mW
} VFE; } VFE;
}; };
}; };
using ManualControl = struct _manualControl { using ManualControl = struct _manualControl {
union { union {
struct { struct {
// Highband Source // Highband Source
uint8_t SourceHighCE :1; uint8_t SourceHighCE :1;
uint8_t SourceHighRFEN :1; uint8_t SourceHighRFEN :1;
uint8_t SourceHighPower :2; uint8_t SourceHighPower :2;
uint8_t SourceHighLowpass :2; uint8_t SourceHighLowpass :2;
uint64_t SourceHighFrequency; uint64_t SourceHighFrequency;
// Lowband Source // Lowband Source
uint8_t SourceLowEN :1; uint8_t SourceLowEN :1;
uint8_t SourceLowPower :2; uint8_t SourceLowPower :2;
uint32_t SourceLowFrequency; uint32_t SourceLowFrequency;
// Source signal path // Source signal path
uint8_t attenuator :7; uint8_t attenuator :7;
uint8_t SourceHighband :1; uint8_t SourceHighband :1;
uint8_t AmplifierEN :1; uint8_t AmplifierEN :1;
uint8_t PortSwitch :1; uint8_t PortSwitch :1;
// LO1 // LO1
uint8_t LO1CE :1; uint8_t LO1CE :1;
uint8_t LO1RFEN :1; uint8_t LO1RFEN :1;
uint64_t LO1Frequency; uint64_t LO1Frequency;
// LO2 // LO2
uint8_t LO2EN :1; uint8_t LO2EN :1;
uint32_t LO2Frequency; uint32_t LO2Frequency;
// Acquisition // Acquisition
uint8_t Port1EN :1; uint8_t Port1EN :1;
uint8_t Port2EN :1; uint8_t Port2EN :1;
uint8_t RefEN :1; uint8_t RefEN :1;
uint32_t Samples; uint32_t Samples;
uint8_t WindowType :2; uint8_t WindowType :2;
} V1; } V1;
struct { struct {
uint64_t SourceFrequency; uint64_t SourceFrequency;
@ -351,30 +351,35 @@ using ManualControl = struct _manualControl {
uint32_t DACFreqB; uint32_t DACFreqB;
uint16_t DACAmpA; uint16_t DACAmpA;
uint16_t DACAmpB; uint16_t DACAmpB;
// ADC
uint8_t ADCTestPattern :4;
uint8_t ADCEn :1;
uint32_t ADCSamples;
} VFD; } VFD;
struct { struct {
// Source // Source
uint8_t SourceCE :1; uint8_t SourceCE :1;
uint8_t SourceRFEN :1; uint8_t SourceRFEN :1;
uint8_t SourcePower :3; uint8_t SourcePower :3;
uint64_t SourceFrequency; uint64_t SourceFrequency;
// Source signal path // Source signal path
uint8_t attenuator :7; uint8_t attenuator :7;
uint8_t SourceAmplifierEN :1; uint8_t SourceAmplifierEN :1;
// LO // LO
uint8_t LOCE :1; uint8_t LOCE :1;
uint8_t LORFEN :1; uint8_t LORFEN :1;
uint8_t LOAmplifierEN :1; uint8_t LOAmplifierEN :1;
uint8_t LOexternal :1; uint8_t LOexternal :1;
uint64_t LOFrequency; uint64_t LOFrequency;
// Acquisition // Acquisition
uint16_t PortEN :1; uint16_t PortEN :1;
uint16_t RefEN :1; uint16_t RefEN :1;
uint16_t WindowType :2; uint16_t WindowType :2;
uint16_t PortGain :4; uint16_t PortGain :4;
uint16_t RefGain :4; uint16_t RefGain :4;
uint16_t Samples; uint16_t Samples;
} VFF; } VFF;
struct { struct {
// Source // Source
uint8_t SourceCE :1; uint8_t SourceCE :1;
@ -399,28 +404,28 @@ using ManualControl = struct _manualControl {
uint8_t eCal_state :2; uint8_t eCal_state :2;
uint16_t eCal_target; // in 1/100 °C uint16_t eCal_target; // in 1/100 °C
} VFE; } VFE;
}; };
}; };
using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings { using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
uint64_t f_start; uint64_t f_start;
uint64_t f_stop; uint64_t f_stop;
uint32_t RBW; uint32_t RBW;
uint16_t pointNum; uint16_t pointNum;
uint8_t WindowType :2; uint8_t WindowType :2;
uint8_t SignalID :1; uint8_t SignalID :1;
uint8_t Detector :3; uint8_t Detector :3;
uint8_t UseDFT :1; uint8_t UseDFT :1;
uint8_t applyReceiverCorrection :1; uint8_t applyReceiverCorrection :1;
uint8_t trackingGenerator :1; uint8_t trackingGenerator :1;
uint8_t applySourceCorrection :1; uint8_t applySourceCorrection :1;
uint8_t trackingGeneratorPort :2; // port count starts at zero uint8_t trackingGeneratorPort :2; // port count starts at zero
/* /*
* 0: no synchronization * 0: no synchronization
* 1: Protocol synchronization (via SetTrigger and ClearTrigger packets) * 1: Protocol synchronization (via SetTrigger and ClearTrigger packets)
* 2: Reserved * 2: Reserved
* 3: Trigger synchronization (not supported yet by hardware) * 3: Trigger synchronization (not supported yet by hardware)
*/ */
uint8_t syncMode :2; uint8_t syncMode :2;
uint8_t syncMaster :1; uint8_t syncMaster :1;
int64_t trackingGeneratorOffset; int64_t trackingGeneratorOffset;
@ -428,21 +433,21 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
}; };
using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult { using SpectrumAnalyzerResult = struct _spectrumAnalyzerResult {
float port1; float port1;
float port2; float port2;
float port3; float port3;
float port4; float port4;
union { union {
struct { struct {
// for non-zero span // for non-zero span
uint64_t frequency; uint64_t frequency;
}; };
struct { struct {
// for zero span // for zero span
uint64_t us; // time in us since first datapoint uint64_t us; // time in us since first datapoint
}; };
}; };
uint16_t pointNum; uint16_t pointNum;
}; };
@ -452,89 +457,100 @@ using FirmwarePacket = struct _firmwarePacket {
}; };
using AmplitudeCorrectionPoint = struct _amplitudecorrectionpoint { using AmplitudeCorrectionPoint = struct _amplitudecorrectionpoint {
uint8_t totalPoints; uint8_t totalPoints;
uint8_t pointNum; uint8_t pointNum;
uint32_t freq; uint32_t freq;
int16_t port1; int16_t port1;
int16_t port2; int16_t port2;
int16_t port3; int16_t port3;
int16_t port4; int16_t port4;
}; };
using FrequencyCorrection = struct _frequencycorrection { using FrequencyCorrection = struct _frequencycorrection {
float ppm; float ppm;
}; };
using DeviceConfig = struct _deviceconfig { using DeviceConfig = struct _deviceconfig {
union { union {
struct { struct {
uint32_t IF1; uint32_t IF1;
uint8_t ADCprescaler; uint8_t ADCprescaler;
uint16_t DFTphaseInc; uint16_t DFTphaseInc;
uint8_t PLLSettlingDelay; uint8_t PLLSettlingDelay;
} V1; } V1;
struct { struct {
uint32_t ip; uint32_t ip;
uint32_t mask; uint32_t mask;
uint32_t gw; uint32_t gw;
uint8_t dhcp :1; uint8_t dhcp :1;
uint8_t unused :7; uint8_t unused :7;
uint16_t autogain :1; uint16_t autogain :1;
uint16_t portGain :4; uint16_t portGain :4;
uint16_t refGain :4; uint16_t refGain :4;
} VFF; } VFF;
struct { struct {
uint16_t autogain :1; uint16_t autogain :1;
uint16_t portGain :4; uint16_t portGain :4;
uint16_t refGain :4; uint16_t refGain :4;
} VFE; } VFE;
}; };
};
#define PROTOCOL_
using ArrayData = struct _arraydata {
uint16_t id;
uint16_t values;
float xbegin;
float xend;
float data[ARRAY_PCKT_MAX_NUM];
}; };
enum class PacketType : uint8_t { enum class PacketType : uint8_t {
None = 0, None = 0,
//Datapoint = 1, // Deprecated, replaced by VNADatapoint //Datapoint = 1, // Deprecated, replaced by VNADatapoint
SweepSettings = 2, SweepSettings = 2,
ManualStatus = 3, ManualStatus = 3,
ManualControl = 4, ManualControl = 4,
DeviceInfo = 5, DeviceInfo = 5,
FirmwarePacket = 6, FirmwarePacket = 6,
Ack = 7, Ack = 7,
ClearFlash = 8, ClearFlash = 8,
PerformFirmwareUpdate = 9, PerformFirmwareUpdate = 9,
Nack = 10, Nack = 10,
Reference = 11, Reference = 11,
Generator = 12, Generator = 12,
SpectrumAnalyzerSettings = 13, SpectrumAnalyzerSettings = 13,
SpectrumAnalyzerResult = 14, SpectrumAnalyzerResult = 14,
RequestDeviceInfo = 15, RequestDeviceInfo = 15,
RequestSourceCal = 16, RequestSourceCal = 16,
RequestReceiverCal = 17, RequestReceiverCal = 17,
SourceCalPoint = 18, SourceCalPoint = 18,
ReceiverCalPoint = 19, ReceiverCalPoint = 19,
SetIdle = 20, SetIdle = 20,
RequestFrequencyCorrection = 21, RequestFrequencyCorrection = 21,
FrequencyCorrection = 22, FrequencyCorrection = 22,
RequestDeviceConfiguration = 23, RequestDeviceConfiguration = 23,
DeviceConfiguration = 24, DeviceConfiguration = 24,
DeviceStatus = 25, DeviceStatus = 25,
RequestDeviceStatus = 26, RequestDeviceStatus = 26,
VNADatapoint = 27, VNADatapoint = 27,
SetTrigger = 28, SetTrigger = 28,
ClearTrigger = 29, ClearTrigger = 29,
StopStatusUpdates = 30, StopStatusUpdates = 30,
StartStatusUpdates = 31, StartStatusUpdates = 31,
InitiateSweep = 32 InitiateSweep = 32,
ArrayData = 33,
}; };
using PacketInfo = struct _packetinfo { using PacketInfo = struct _packetinfo {
PacketType type; PacketType type;
union { union {
// Datapoint datapoint; // Deprecated, use VNADatapoint instead // Datapoint datapoint; // Deprecated, use VNADatapoint instead
SweepSettings settings; SweepSettings settings;
ReferenceSettings reference; ReferenceSettings reference;
GeneratorSettings generator; GeneratorSettings generator;
DeviceStatus status; DeviceStatus status;
DeviceInfo info; DeviceInfo info;
ManualControl manual; ManualControl manual;
FirmwarePacket firmware; FirmwarePacket firmware;
@ -549,13 +565,15 @@ using PacketInfo = struct _packetinfo {
* When decoding: VNADatapoint is created on heap by DecodeBuffer, freeing is up to the caller * When decoding: VNADatapoint is created on heap by DecodeBuffer, freeing is up to the caller
*/ */
VNADatapoint<32> *VNAdatapoint; VNADatapoint<32> *VNAdatapoint;
}; ArrayData arrayData;
};
}; };
#pragma pack(pop) #pragma pack(pop)
uint32_t CRC32(uint32_t crc, const void *data, uint32_t len); uint32_t CRC32(uint32_t crc, const void *data, uint32_t len);
uint16_t DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info); uint16_t DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info);
uint16_t GetRequiredSize(const PacketInfo &packet);
uint16_t EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize); uint16_t EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_t destsize);
} }