WIP: synchronization

This commit is contained in:
Jan Käberich 2022-08-08 18:08:40 +02:00
parent 7b3aa6e158
commit 73e26a25c4
41 changed files with 439 additions and 163 deletions

View File

@ -348,9 +348,9 @@ The register contains the number of points per sweep negative one, e.g. set to 1
\rwbits{9}{2}{Window[1:0]}
\rwbits{11}{1}{SCEN}
\rwbits{12}{1}{LCEN}
\robits{13}{2}{reserved}
\robits{13}{1}{reserved}
%\rwbits{13}{1}{EXP2}
%\rwbits{14}{1}{EXP1}
\rwbits{14}{1}{SYM}
\rwbits{15}{1}{PSEN}
\end{tikzpicture}
\end{center}
@ -378,7 +378,7 @@ Setting & Window type\\
\item \textbf{SCEN:}{Source chip enable}
\item \textbf{LCEN:}{LO chip enable}
%\item \textbf{EXP1:}{Excite Port1 during sweep}
%\item \textbf{EXP2:}{Excite Port2 during sweep}
\item \textbf{SYM:}{Sync master, see also section~\ref{synchronization}. If multiple devices are combined, exactly one must have this bit set.}
\item \textbf{PSEN:}{Port switch enable}
\end{itemize}
@ -731,7 +731,7 @@ The FPGA supports synchronization of the sweep across multiple devices. This fea
The synchronization works by delaying sampling until the stimulus signal is present, even when generated by another device. For each sampling stage, performs the following steps:
\begin{itemize}
\item When the device generates the stimulus signal in the current phase:
\item When the device is the synchronization master (SYM bit set):
\begin{itemize}
\item Set up source and 1.LO PLLs
\item If applicable: wait for the "resume sweep" command
@ -741,7 +741,7 @@ The synchronization works by delaying sampling until the stimulus signal is pres
\item Set the trigger output to low
\item Wait for low level on trigger input
\end{itemize}
\item When the device does not generate the stimulus signal in the current phase:
\item When the device is the synchronization slave (SYM bit not set):
\begin{itemize}
\item Set 1.LO PLL
\item If applicable: wait for the "resume sweep" command

View File

@ -52,6 +52,7 @@ entity SPICommands is
NSAMPLES : out STD_LOGIC_VECTOR (12 downto 0);
STAGES : out STD_LOGIC_VECTOR (2 downto 0);
SYNC_ENABLED : out STD_LOGIC;
SYNC_MASTER : out STD_LOGIC;
PORT1_STAGE : out STD_LOGIC_VECTOR (2 downto 0);
PORT2_STAGE : out STD_LOGIC_VECTOR (2 downto 0);
PORT1_EN : out STD_LOGIC;
@ -250,6 +251,7 @@ begin
WINDOW_SETTING <= spi_buf_out(6 downto 5);
SOURCE_CE_EN <= spi_buf_out(4);
LO_CE_EN <= spi_buf_out(3);
SYNC_MASTER <= spi_buf_out(1);
when 4 => ADC_PRESCALER <= spi_buf_out(7 downto 0);
when 5 => ADC_PHASEINC <= spi_buf_out(11 downto 0);
when 6 => STAGES <= spi_buf_out(15 downto 13);

View File

@ -62,9 +62,12 @@ entity Sweep is
SWEEP_RESUME : in STD_LOGIC;
SYNC_ENABLED : in STD_LOGIC;
SYNC_MASTER : in STD_LOGIC;
TRIGGER_IN : in STD_LOGIC;
TRIGGER_OUT : out STD_LOGIC;
NEW_DATA : out STD_LOGIC;
ATTENUATOR : out STD_LOGIC_VECTOR(6 downto 0);
SOURCE_FILTER : out STD_LOGIC_VECTOR(1 downto 0);
@ -85,7 +88,7 @@ end Sweep;
architecture Behavioral of Sweep is
signal point_cnt : unsigned(12 downto 0);
type Point_states is (TriggerSetup, SettingUp, Settling, WaitTriggerHigh, Exciting, WaitTriggerLow, SamplingDone, NextPoint, Done);
type Point_states is (WaitInitialLow, TriggerSetup, SettingUp, Settling, WaitTriggerHigh, Exciting, WaitTriggerLow, SamplingDone, NextPoint, Done);
signal state : Point_states;
signal settling_cnt : unsigned(15 downto 0);
signal settling_time : unsigned(15 downto 0);
@ -153,7 +156,7 @@ begin
if RESET = '1' then
point_cnt <= (others => '0');
stage_cnt <= (others => '0');
state <= WaitTriggerLow;
state <= WaitInitialLow;
START_SAMPLING <= '0';
RELOAD_PLL_REGS <= '0';
SWEEP_HALTED <= '0';
@ -164,19 +167,10 @@ begin
source_active <= '0';
else
case state is
when WaitTriggerLow =>
if SYNC_ENABLED = '1' and (std_logic_vector(stage_cnt) = PORT1_STAGE or std_logic_vector(stage_cnt) = PORT2_STAGE) then
TRIGGER_OUT <= '0';
end if;
when WaitInitialLow =>
TRIGGER_OUT <= '0';
if TRIGGER_IN = '0' or SYNC_ENABLED = '0' then
TRIGGER_OUT <= '0';
if stage_cnt = 0 then
-- first stage in point, need to trigger PLL setup
state <= TriggerSetup;
else
-- PLLs already configured correctly
state <= SettingUp;
end if;
state <= TriggerSetup;
end if;
when TriggerSetup =>
RELOAD_PLL_REGS <= '1';
@ -221,7 +215,7 @@ begin
else
-- need to wait for the trigger
state <= WaitTriggerHigh;
if SYNC_ENABLED = '1' and (std_logic_vector(stage_cnt) = PORT1_STAGE or std_logic_vector(stage_cnt) = PORT2_STAGE) then
if SYNC_MASTER = '1' then
-- this device generates the stimulus signal, it needs start the trigger itself
TRIGGER_OUT <= '1';
end if;
@ -238,14 +232,25 @@ begin
-- wait for sampling to finish
START_SAMPLING <= '0';
if SAMPLING_BUSY = '0' then
NEW_DATA <= '1';
RESULT_INDEX <= std_logic_vector(stage_cnt) & std_logic_vector(point_cnt);
state <= WaitTriggerLow;
end if;
when WaitTriggerLow =>
NEW_DATA <= '0';
if SYNC_MASTER = '1' then
TRIGGER_OUT <= '0';
end if;
if TRIGGER_IN = '0' or SYNC_ENABLED = '0' then
TRIGGER_OUT <= '0';
state <= SamplingDone;
end if;
when SamplingDone =>
NEW_DATA <= '0';
if stage_cnt < unsigned(STAGES) then
stage_cnt <= stage_cnt + 1;
-- can go directly to preperation for next stage
state <= WaitTriggerLow;
state <= Settling;
else
state <= NextPoint;
end if;
@ -254,7 +259,7 @@ begin
if point_cnt < unsigned(NPOINTS) then
point_cnt <= point_cnt + 1;
stage_cnt <= (others => '0');
state <= WaitTriggerLow;
state <= TriggerSetup;
else
point_cnt <= (others => '0');
state <= Done;

View File

@ -224,7 +224,7 @@
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
</transform>
<transform xil_pn:end_ts="1659868712" xil_pn:in_ck="-4366097307991745463" xil_pn:name="TRAN_regenerateCores" xil_pn:prop_ck="-2723611991789822717" xil_pn:start_ts="1659868712">
<transform xil_pn:end_ts="1659962405" xil_pn:in_ck="-4366097307991745463" xil_pn:name="TRAN_regenerateCores" xil_pn:prop_ck="-2723611991789822717" xil_pn:start_ts="1659962405">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="ipcore_dir/DSP_SLICE.ngc"/>
@ -253,7 +253,7 @@
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
</transform>
<transform xil_pn:end_ts="1659869263" xil_pn:in_ck="2241500006820465658" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1659869254">
<transform xil_pn:end_ts="1659974081" xil_pn:in_ck="2241500006820465658" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1659974072">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
@ -275,7 +275,7 @@
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
</transform>
<transform xil_pn:end_ts="1659869266" xil_pn:in_ck="5411862124762956458" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1659869263">
<transform xil_pn:end_ts="1659974085" xil_pn:in_ck="5411862124762956458" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1659974081">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_ngo"/>
@ -284,7 +284,7 @@
<outfile xil_pn:name="top.ngd"/>
<outfile xil_pn:name="top_ngdbuild.xrpt"/>
</transform>
<transform xil_pn:end_ts="1659869298" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="-4668962392366239264" xil_pn:start_ts="1659869266">
<transform xil_pn:end_ts="1659974193" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="-4668962392366239264" xil_pn:start_ts="1659974085">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
@ -298,7 +298,7 @@
<outfile xil_pn:name="top_summary.xml"/>
<outfile xil_pn:name="top_usage.xml"/>
</transform>
<transform xil_pn:end_ts="1659869311" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-1085068593928086116" xil_pn:start_ts="1659869298">
<transform xil_pn:end_ts="1659974205" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-1085068593928086116" xil_pn:start_ts="1659974193">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/par.xmsgs"/>
@ -312,8 +312,9 @@
<outfile xil_pn:name="top_pad.txt"/>
<outfile xil_pn:name="top_par.xrpt"/>
</transform>
<transform xil_pn:end_ts="1659869318" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1659869311">
<transform xil_pn:end_ts="1659974213" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1659974205">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/bitgen.xmsgs"/>
<outfile xil_pn:name="top.bgn"/>
@ -365,7 +366,7 @@
<status xil_pn:value="InputChanged"/>
<status xil_pn:value="InputRemoved"/>
</transform>
<transform xil_pn:end_ts="1659869311" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1659869308">
<transform xil_pn:end_ts="1659974205" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1659974202">
<status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/trce.xmsgs"/>

Binary file not shown.

View File

@ -139,8 +139,10 @@ architecture Behavioral of top is
SWEEP_HALTED : out STD_LOGIC;
SWEEP_RESUME : in STD_LOGIC;
SYNC_ENABLED : in STD_LOGIC;
SYNC_MASTER : in STD_LOGIC;
TRIGGER_IN : in STD_LOGIC;
TRIGGER_OUT : out STD_LOGIC;
NEW_DATA : out STD_LOGIC;
ATTENUATOR : OUT std_logic_vector(6 downto 0);
SOURCE_FILTER : OUT std_logic_vector(1 downto 0);
STAGES : in STD_LOGIC_VECTOR (2 downto 0);
@ -253,6 +255,7 @@ architecture Behavioral of top is
NSAMPLES : OUT std_logic_vector(12 downto 0);
STAGES : out STD_LOGIC_VECTOR (2 downto 0);
SYNC_ENABLED : out STD_LOGIC;
SYNC_MASTER : out STD_LOGIC;
PORT1_STAGE : out STD_LOGIC_VECTOR (2 downto 0);
PORT2_STAGE : out STD_LOGIC_VECTOR (2 downto 0);
PORT1_EN : out STD_LOGIC;
@ -376,6 +379,7 @@ architecture Behavioral of top is
signal sweep_points : std_logic_vector(12 downto 0);
signal sweep_stages : STD_LOGIC_VECTOR (2 downto 0);
signal sweep_sync_enabled: STD_LOGIC;
signal sweep_sync_master : STD_LOGIC;
signal sweep_port1_stage : STD_LOGIC_VECTOR (2 downto 0);
signal sweep_port2_stage : STD_LOGIC_VECTOR (2 downto 0);
signal sweep_config_data : std_logic_vector(95 downto 0);
@ -395,6 +399,9 @@ architecture Behavioral of top is
signal sweep_excite_port1 : std_logic;
signal sweep_excite_port2 : std_logic;
signal sweep_trigger_in : std_logic;
signal sweep_trigger_out : std_logic;
-- Configuration signals
signal settling_time : std_logic_vector(15 downto 0);
signal def_reg_4 : std_logic_vector(31 downto 0);
@ -531,7 +538,21 @@ begin
CLK => clk_pll,
SYNC_IN => MCU_NSS,
SYNC_OUT => nss_sync
);
);
Sync_TRIGGER_IN : Synchronizer
GENERIC MAP(stages => 2)
PORT MAP(
CLK => clk_pll,
SYNC_IN => TRIGGER_IN,
SYNC_OUT => sweep_trigger_in
);
Sync_TRIGGER_OUT : Synchronizer
GENERIC MAP(stages => 2)
PORT MAP(
CLK => clk_pll,
SYNC_IN => sweep_trigger_out,
SYNC_OUT => TRIGGER_OUT
);
Source: MAX2871
@ -644,7 +665,7 @@ begin
REF => ref_windowed,
ADC_START => adc_trigger_sample,
NEW_SAMPLE => windowing_ready,
DONE => sampling_done,
DONE => open,
PRE_DONE => open,
START => sampling_start,
SAMPLES => sampling_samples,
@ -689,8 +710,10 @@ begin
SWEEP_HALTED => sweep_halted,
SWEEP_RESUME => sweep_resume,
SYNC_ENABLED => sweep_sync_enabled,
TRIGGER_IN => TRIGGER_IN,
TRIGGER_OUT => TRIGGER_OUT,
SYNC_MASTER => sweep_sync_master,
TRIGGER_IN => sweep_trigger_in,
TRIGGER_OUT => sweep_trigger_out,
NEW_DATA => sampling_done,
ATTENUATOR => sweep_attenuator,
SOURCE_FILTER => sweep_source_filter,
STAGES => sweep_stages,
@ -772,6 +795,7 @@ begin
SWEEP_RESUME => sweep_resume,
STAGES => sweep_stages,
SYNC_ENABLED => sweep_sync_enabled,
SYNC_MASTER => sweep_sync_master,
PORT1_STAGE => sweep_port1_stage,
PORT2_STAGE => sweep_port2_stage,
SPI_OVERWRITE_ENABLED => HW_overwrite_enabled,

View File

@ -423,8 +423,9 @@ void AmplitudeCalDialog::AutomaticMeasurementDialog()
}
}
void AmplitudeCalDialog::ReceivedMeasurement(Protocol::SpectrumAnalyzerResult res)
void AmplitudeCalDialog::ReceivedMeasurement(Device *dev, Protocol::SpectrumAnalyzerResult res)
{
Q_UNUSED(dev)
MeasurementResult m = {.port1 = Util::SparamTodB(res.port1), .port2 = Util::SparamTodB(res.port2)};
sweepMeasurements.push_back(m);
if(res.pointNum == automaticSweepPoints - 1) {
@ -529,8 +530,9 @@ void AmplitudeCalDialog::SetupNextAutomaticPoint(bool isSourceCal)
sweepMeasurements.reserve(automaticSweepPoints);
}
void AmplitudeCalDialog::ReceivedAutomaticMeasurementResult(Protocol::SpectrumAnalyzerResult res)
void AmplitudeCalDialog::ReceivedAutomaticMeasurementResult(Device *dev, Protocol::SpectrumAnalyzerResult res)
{
Q_UNUSED(dev)
if(res.pointNum != automaticSweepPoints - 1) {
// ignore everything except end of sweep
return;

View File

@ -78,7 +78,7 @@ protected slots:
bool AddPoint(double frequency);
void AddPointDialog();
void AutomaticMeasurementDialog();
void ReceivedMeasurement(Protocol::SpectrumAnalyzerResult res);
void ReceivedMeasurement(Device *dev, Protocol::SpectrumAnalyzerResult res);
signals:
void pointsUpdated();
void newPointCreated(CorrectionPoint& p);
@ -108,7 +108,7 @@ protected:
CalibrationMode mode;
void SetupNextAutomaticPoint(bool isSourceCal);
void ReceivedAutomaticMeasurementResult(Protocol::SpectrumAnalyzerResult res);
void ReceivedAutomaticMeasurementResult(Device *dev, Protocol::SpectrumAnalyzerResult res);
struct {
QDialog *dialog;
std::vector<CorrectionPoint> points;

View File

@ -122,6 +122,15 @@ bool TileWidget::allLimitsPassing()
}
}
void TileWidget::setSplitPercentage(int percentage)
{
if(!isSplit) {
return;
}
splitter->setStretchFactor(0, percentage);
splitter->setStretchFactor(1, 100 - percentage);
}
void TileWidget::splitVertically(bool moveContentToSecondChild)
{
if(isSplit) {

View File

@ -32,6 +32,8 @@ public:
// check potential trace limits on graphs, only returns true if all traces in all graphs are within limits
bool allLimitsPassing();
void setSplitPercentage(int percentage);
public slots:
void splitVertically(bool moveContentToSecondChild = false);
void splitHorizontally(bool moveContentToSecondChild = false);

View File

@ -326,7 +326,6 @@ std::set<QString> Device::GetDevices()
void Device::SetTrigger(bool set)
{
qDebug() << "Trigger" << set << "to" << this;
if(set) {
SendCommandWithoutPayload(Protocol::PacketType::SetTrigger);
} else {
@ -479,13 +478,13 @@ void Device::ReceivedData()
dataBuffer->removeBytes(handled_len);
switch(packet.type) {
case Protocol::PacketType::VNADatapoint:
emit DatapointReceived(packet.VNAdatapoint);
emit DatapointReceived(this, packet.VNAdatapoint);
break;
case Protocol::PacketType::ManualStatusV1:
emit ManualStatusReceived(packet.manualStatusV1);
break;
case Protocol::PacketType::SpectrumAnalyzerResult:
emit SpectrumResultReceived(packet.spectrumResult);
emit SpectrumResultReceived(this, packet.spectrumResult);
break;
case Protocol::PacketType::SourceCalPoint:
case Protocol::PacketType::ReceiverCalPoint:
@ -500,11 +499,11 @@ void Device::ReceivedData()
info = packet.info;
}
infoValid = true;
emit DeviceInfoUpdated();
emit DeviceInfoUpdated(this);
break;
case Protocol::PacketType::DeviceStatusV1:
status.v1 = packet.statusV1;
emit DeviceStatusUpdated();
emit DeviceStatusUpdated(this);
break;
case Protocol::PacketType::Ack:
emit AckReceived();
@ -518,11 +517,9 @@ void Device::ReceivedData()
emit FrequencyCorrectionReceived(packet.frequencyCorrection.ppm);
break;
case Protocol::PacketType::SetTrigger:
qDebug() << "Trigger" << true << "from" << this;
emit TriggerReceived(true);
break;
case Protocol::PacketType::ClearTrigger:
qDebug() << "Trigger" << false << "from" << this;
emit TriggerReceived(false);
break;
default:

View File

@ -78,13 +78,13 @@ public:
// Returns serial numbers of all connected devices
static std::set<QString> GetDevices();
signals:
void DatapointReceived(Protocol::VNADatapoint<32>*);
void DatapointReceived(Device*, Protocol::VNADatapoint<32>*);
void ManualStatusReceived(Protocol::ManualStatusV1);
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
void SpectrumResultReceived(Device*, Protocol::SpectrumAnalyzerResult);
void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint);
void FrequencyCorrectionReceived(float ppm);
void DeviceInfoUpdated();
void DeviceStatusUpdated();
void DeviceInfoUpdated(Device*);
void DeviceStatusUpdated(Device*);
void ConnectionLost();
void AckReceived();
void NackReceived();

View File

@ -147,18 +147,10 @@ VirtualDevice::VirtualDevice(QString serial)
connect(dev, &Device::LogLineReceived, [=](QString line){
emit LogLineReceived(line.prepend(dev->serial()+": "));
});
connect(dev, &Device::DeviceInfoUpdated, [=](){
compoundInfoUpdated(dev);
});
connect(dev, &Device::DeviceStatusUpdated, [=](){
compoundStatusUpdated(dev);
});
connect(dev, &Device::DatapointReceived, [=](Protocol::VNADatapoint<32> *data){
compoundDatapointReceivecd(data, dev);
});
connect(dev, &Device::SpectrumResultReceived, [=](Protocol::SpectrumAnalyzerResult res) {
compoundSpectrumResultReceived(res, dev);
});
connect(dev, &Device::DeviceInfoUpdated, this, &VirtualDevice::compoundInfoUpdated, Qt::QueuedConnection);
connect(dev, &Device::DeviceStatusUpdated, this, &VirtualDevice::compoundStatusUpdated, Qt::QueuedConnection);
connect(dev, &Device::DatapointReceived, this, &VirtualDevice::compoundDatapointReceivecd, Qt::QueuedConnection);
connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::compoundSpectrumResultReceived, Qt::QueuedConnection);
}
if(cdev->sync == CompoundDevice::Synchronization::USB) {
// create trigger connections for USB synchronization
@ -283,6 +275,7 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
sd.port1Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 0) - s.excitedPorts.begin();
sd.port2Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 1) - s.excitedPorts.begin();
sd.syncMode = 0;
sd.syncMaster = 0;
return devices[0]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) {
cb(r == Device::TransmissionResult::Ack);
@ -306,6 +299,7 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
for(unsigned int i=0;i<devices.size();i++) {
sd.port1Stage = CompoundDevice::PortMapping::findActiveStage(activeMapping, i, 0);
sd.port2Stage = CompoundDevice::PortMapping::findActiveStage(activeMapping, i, 1);
sd.syncMaster = i == 0 ? 1 : 0;
success &= devices[i]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) {
results[devices[i]] = r;
@ -342,34 +336,65 @@ bool VirtualDevice::setSA(const VirtualDevice::SASettings &s, std::function<void
}
zerospan = s.freqStart == s.freqStop;
auto pref = Preferences::getInstance();
Protocol::SpectrumAnalyzerSettings sd;
sd.f_start = s.freqStart;
sd.f_stop = s.freqStop;
sd.pointNum = s.points;
sd.RBW = s.RBW;
sd.WindowType = (int) s.window;
sd.SignalID = s.signalID ? 1 : 0;
sd.Detector = (int) s.detector;
sd.UseDFT = 0;
if(!s.trackingGenerator && pref.Acquisition.useDFTinSAmode && s.RBW <= pref.Acquisition.RBWLimitForDFT) {
sd.UseDFT = 1;
}
sd.applyReceiverCorrection = 1;
sd.trackingGeneratorOffset = s.trackingOffset;
sd.trackingPower = s.trackingPower;
if(!isCompoundDevice()) {
Protocol::SpectrumAnalyzerSettings sd;
sd.f_start = s.freqStart;
sd.f_stop = s.freqStop;
sd.pointNum = s.points;
sd.RBW = s.RBW;
sd.WindowType = (int) s.window;
sd.SignalID = s.signalID ? 1 : 0;
sd.Detector = (int) s.detector;
sd.UseDFT = 0;
if(!s.trackingGenerator && pref.Acquisition.useDFTinSAmode && s.RBW <= pref.Acquisition.RBWLimitForDFT) {
sd.UseDFT = 1;
}
sd.applyReceiverCorrection = 1;
sd.trackingGenerator = s.trackingGenerator ? 1 : 0;
sd.applySourceCorrection = 1;
sd.trackingGeneratorPort = s.trackingPort;
sd.trackingGeneratorOffset = s.trackingOffset;
sd.trackingPower = s.trackingPower;
sd.syncMode = 0;
sd.syncMaster = 0;
return devices[0]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) {
cb(r == Device::TransmissionResult::Ack);
}
});
} else {
// TODO
return false;
// set the synchronization mode
switch(cdev->sync) {
case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break;
case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break;
case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break;
}
// Configure the devices
results.clear();
bool success = true;
for(unsigned int i=0;i<devices.size();i++) {
if(s.trackingGenerator) {
if(CompoundDevice::PortMapping::findActiveStage(cdev->portMapping, i, 0) == s.trackingPort) {
sd.trackingGenerator = 1;
sd.trackingGeneratorPort = 0;
} else if(CompoundDevice::PortMapping::findActiveStage(cdev->portMapping, i, 1) == s.trackingPort) {
sd.trackingGenerator = 1;
sd.trackingGeneratorPort = 1;
}
} else {
// not used
sd.trackingGenerator = 0;
sd.trackingGeneratorPort = 0;
}
sd.syncMaster = i == 0 ? 1 : 0;
success &= devices[i]->Configure(sd, [=](Device::TransmissionResult r){
if(cb) {
results[devices[i]] = r;
checkIfAllTransmissionsComplete(cb);
}
});
}
return success;
}
}
@ -520,8 +545,9 @@ VirtualDevice *VirtualDevice::getConnected()
return connected;
}
void VirtualDevice::singleDatapointReceived(Protocol::VNADatapoint<32> *res)
void VirtualDevice::singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res)
{
Q_UNUSED(dev)
VNAMeasurement m;
m.pointNum = res->pointNum;
m.Z0 = 50.0;
@ -548,7 +574,7 @@ void VirtualDevice::singleDatapointReceived(Protocol::VNADatapoint<32> *res)
emit VNAmeasurementReceived(m);
}
void VirtualDevice::compoundDatapointReceivecd(Protocol::VNADatapoint<32> *data, Device *dev)
void VirtualDevice::compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data)
{
if(!compoundVNABuffer.count(data->pointNum)) {
compoundVNABuffer[data->pointNum] = std::map<Device*, Protocol::VNADatapoint<32>*>();
@ -600,18 +626,25 @@ void VirtualDevice::compoundDatapointReceivecd(Protocol::VNADatapoint<32> *data,
emit VNAmeasurementReceived(m);
// Clear this and all incomplete older datapoint buffers
for(auto p : compoundVNABuffer) {
for(auto d : p.second) {
delete d.second;
// Clear this and all (incomplete) older datapoint buffers
int pointNum = data->pointNum;
auto it = compoundVNABuffer.begin();
while(it != compoundVNABuffer.end()) {
if(it->first <= pointNum) {
for(auto d : it->second) {
delete d.second;
}
it = compoundVNABuffer.erase(it);
} else {
it++;
}
}
compoundVNABuffer.clear();
}
}
void VirtualDevice::singleSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res)
void VirtualDevice::singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res)
{
Q_UNUSED(dev)
SAMeasurement m;
m.pointNum = res.pointNum;
if(zerospan) {
@ -624,9 +657,47 @@ void VirtualDevice::singleSpectrumResultReceived(Protocol::SpectrumAnalyzerResul
emit SAmeasurementReceived(m);
}
void VirtualDevice::compoundSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res, Device *dev)
void VirtualDevice::compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res)
{
if(!compoundSABuffer.count(res.pointNum)) {
compoundSABuffer[res.pointNum] = std::map<Device*, Protocol::SpectrumAnalyzerResult>();
}
auto &buf = compoundSABuffer[res.pointNum];
buf[dev] = res;
if(buf.size() == devices.size()) {
// Got datapoints from all devices, can create merged VNA result
SAMeasurement m;
m.pointNum = res.pointNum;
if(zerospan) {
m.us = res.us;
} else {
m.frequency = res.frequency;
}
// assemble data
for(unsigned int port=0;port<cdev->portMapping.size();port++) {
auto device = devices[cdev->portMapping[port].device];
auto devicePort = cdev->portMapping[port].port;
QString name = "PORT"+QString::number(port+1);
if(devicePort == 0) {
m.measurements[name] = buf[device].port1;
} else {
m.measurements[name] = buf[device].port2;
}
}
emit SAmeasurementReceived(m);
// Clear this and all (incomplete) older datapoint buffers
auto it = compoundSABuffer.begin();
while(it != compoundSABuffer.end()) {
if(it->first <= res.pointNum) {
it = compoundSABuffer.erase(it);
} else {
it++;
}
}
}
}
void VirtualDevice::compoundInfoUpdated(Device *dev)
@ -778,7 +849,7 @@ VirtualDevice::Info::Info(Device *dev)
Limits.mindBm = (double) info.limits_cdbm_min / 100;
Limits.maxdBm = (double) info.limits_cdbm_max / 100;
Limits.minRBW = info.limits_minRBW;
Limits.maxRBW = info.limits_minRBW;
Limits.maxRBW = info.limits_maxRBW;
}
void VirtualDevice::Info::subset(const VirtualDevice::Info &merge)

View File

@ -141,7 +141,6 @@ public:
struct {
// for non-zero span
double frequency;
double cdbm;
};
struct {
// for zero span
@ -184,10 +183,10 @@ signals:
void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol);
private slots:
void singleDatapointReceived(Protocol::VNADatapoint<32> *res);
void compoundDatapointReceivecd(Protocol::VNADatapoint<32> *data, Device *dev);
void singleSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res);
void compoundSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res, Device *dev);
void singleDatapointReceived(Device *dev, Protocol::VNADatapoint<32> *res);
void compoundDatapointReceivecd(Device *dev, Protocol::VNADatapoint<32> *data);
void singleSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res);
void compoundSpectrumResultReceived(Device *dev, Protocol::SpectrumAnalyzerResult res);
void compoundInfoUpdated(Device *dev);
void compoundStatusUpdated(Device *dev);
private:

View File

@ -53,6 +53,11 @@ void Generator::fromJSON(nlohmann::json j)
central->fromJSON(j);
}
void Generator::preset()
{
}
void Generator::updateDevice()
{
if(!window->getDevice() || isActive != true) {

View File

@ -21,6 +21,8 @@ public:
void setAveragingMode(Averaging::Mode mode) override {Q_UNUSED(mode)}
void preset() override;
private slots:
void updateDevice();

View File

@ -60,20 +60,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
traceModel.setSource(TraceModel::DataSource::SA);
// Create default traces
auto tPort1 = new Trace("Port1", Qt::yellow);
tPort1->fromLivedata(Trace::LivedataType::Overwrite, "PORT1");
traceModel.addTrace(tPort1);
auto tPort2 = new Trace("Port2", Qt::blue);
tPort2->fromLivedata(Trace::LivedataType::Overwrite, "PORT2");
traceModel.addTrace(tPort2);
auto traceXY = new TraceXYPlot(traceModel);
traceXY->enableTrace(tPort1, true);
traceXY->enableTrace(tPort2, true);
traceXY->setYAxis(0, YAxis::Type::Magnitude, false, false, -120,0,10);
traceXY->setYAxis(1, YAxis::Type::Disabled, false, true, 0,0,1);
central->setPlot(traceXY);
preset();
// Create menu entries and connections
// Sweep toolbar
@ -1153,11 +1140,42 @@ void SpectrumAnalyzer::StoreSweepSettings()
s.setValue("SASignalID", static_cast<bool>(settings.signalID));
}
void SpectrumAnalyzer::createDefaultTracesAndGraphs(int ports)
{
central->clear();
auto traceXY = new TraceXYPlot(traceModel);
traceXY->setYAxis(0, YAxis::Type::Magnitude, false, false, -120,0,10);
traceXY->setYAxis(1, YAxis::Type::Disabled, false, true, 0,0,1);
traceXY->updateSpan(settings.freqStart, settings.freqStop);
central->setPlot(traceXY);
QColor defaultColors[] = {Qt::yellow, Qt::blue, Qt::red, Qt::green, Qt::gray, Qt::cyan, Qt::magenta, Qt::white};
for(int i=0;i<ports;i++) {
QString param = "PORT"+QString::number(i+1);
auto trace = new Trace(param, defaultColors[i], param);
traceModel.addTrace(trace);
traceXY->enableTrace(trace, true);
}
}
void SpectrumAnalyzer::setAveragingMode(Averaging::Mode mode)
{
average.setMode(mode);
}
void SpectrumAnalyzer::preset()
{
for(auto t : traceModel.getTraces()) {
if(Trace::isSAParameter(t->name())) {
traceModel.removeTrace(t);
}
}
// Create default traces
createDefaultTracesAndGraphs(VirtualDevice::getInfo(window->getDevice()).ports);
}
QString SpectrumAnalyzer::WindowToString(VirtualDevice::SASettings::Window w)
{
switch(w) {

View File

@ -31,6 +31,7 @@ public:
void updateGraphColors();
void setAveragingMode(Averaging::Mode mode) override;
void preset() override;
private:
static QString WindowToString(VirtualDevice::SASettings::Window w);
@ -74,6 +75,8 @@ private:
void LoadSweepSettings();
void StoreSweepSettings();
void createDefaultTracesAndGraphs(int ports);
VirtualDevice::SASettings settings;
bool changingSettings;
unsigned int averages;

View File

@ -48,11 +48,29 @@ void TraceModel::removeTrace(unsigned int index)
}
}
void TraceModel::removeTrace(Trace *t)
{
auto index = findIndex(t);
if(index >= 0) {
removeTrace(index);
}
}
Trace *TraceModel::trace(unsigned int index)
{
return traces.at(index);
}
int TraceModel::findIndex(Trace *t)
{
for(int i=0;i<traces.size();i++) {
if(traces[i] == t) {
return i;
}
}
return -1;
}
void TraceModel::toggleVisibility(unsigned int index)
{
if (index < traces.size()) {
@ -184,7 +202,7 @@ void TraceModel::fromJSON(nlohmann::json j)
{
// clear old traces
while(traces.size()) {
removeTrace(0);
removeTrace((int) 0);
}
for(auto jt : j) {
auto trace = new Trace();

View File

@ -33,7 +33,9 @@ public:
void addTrace(Trace *t);
void removeTrace(unsigned int index);
void removeTrace(Trace *t);
Trace *trace(unsigned int index);
int findIndex(Trace *t);
void toggleVisibility(unsigned int index);
void togglePause(unsigned int index);
void toggleMath(unsigned int index);

View File

@ -105,7 +105,7 @@ class TraceSmithChart : public TracePlot
public:
TraceSmithChart(TraceModel &model, QWidget *parent = 0);
virtual Type getType() override { return Type::SmithChart;};
virtual Type getType() override { return Type::SmithChart;}
virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override;

View File

@ -21,6 +21,7 @@ public:
QVariant value() {
return QVariant(variant.type(), ptr);
}
void* getPtr(){return ptr;}
private:
void *ptr;
QVariant variant;

View File

@ -71,40 +71,10 @@ VNA::VNA(AppWindow *window, QString name)
traceModel.setSource(TraceModel::DataSource::VNA);
// Create default traces
auto tS11 = new Trace("S11", Qt::yellow);
tS11->fromLivedata(Trace::LivedataType::Overwrite, "S11");
traceModel.addTrace(tS11);
auto tS12 = new Trace("S12", Qt::blue);
tS12->fromLivedata(Trace::LivedataType::Overwrite, "S12");
traceModel.addTrace(tS12);
auto tS21 = new Trace("S21", Qt::green);
tS21->fromLivedata(Trace::LivedataType::Overwrite, "S21");
traceModel.addTrace(tS21);
auto tS22 = new Trace("S22", Qt::red);
tS22->fromLivedata(Trace::LivedataType::Overwrite, "S22");
traceModel.addTrace(tS22);
auto tracesmith1 = new TraceSmithChart(traceModel);
tracesmith1->enableTrace(tS11, true);
auto tracesmith2 = new TraceSmithChart(traceModel);
tracesmith2->enableTrace(tS22, true);
auto traceXY1 = new TraceXYPlot(traceModel);
traceXY1->enableTrace(tS12, true);
auto traceXY2 = new TraceXYPlot(traceModel);
traceXY2->enableTrace(tS21, true);
createDefaultTracesAndGraphs(2);
connect(&traceModel, &TraceModel::requiredExcitation, this, &VNA::ExcitationRequired);
central->splitVertically();
central->Child1()->splitHorizontally();
central->Child2()->splitHorizontally();
central->Child1()->Child1()->setPlot(tracesmith1);
central->Child1()->Child2()->setPlot(traceXY1);
central->Child2()->Child1()->setPlot(traceXY2);
central->Child2()->Child2()->setPlot(tracesmith2);
// Create menu entries and connections
auto calMenu = new QMenu("Calibration", window);
window->menuBar()->insertMenu(window->getUi()->menuWindow->menuAction(), calMenu);
@ -924,7 +894,7 @@ void VNA::SettingsChanged(bool resetTraces, std::function<void (bool)> cb)
// assemble VNA protocol settings
VirtualDevice::VNASettings s = {};
s.IFBW = settings.bandwidth;
if(Preferences::getInstance().Acquisition.alwaysExciteBothPorts) {
if(Preferences::getInstance().Acquisition.alwaysExciteAllPorts) {
for(int i=0;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
s.excitedPorts.push_back(i);
}
@ -1183,7 +1153,7 @@ void VNA::SetAveraging(unsigned int averages)
void VNA::ExcitationRequired()
{
if(!Preferences::getInstance().Acquisition.alwaysExciteBothPorts) {
if(!Preferences::getInstance().Acquisition.alwaysExciteAllPorts) {
for(int i=1;i<VirtualDevice::getInfo(window->getDevice()).ports;i++) {
auto required = traceModel.PortExcitationRequired(i);
auto set = find(settings.excitedPorts.begin(), settings.excitedPorts.end(), i) != settings.excitedPorts.end();
@ -1624,6 +1594,92 @@ void VNA::UpdateCalWidget()
calLabel->setToolTip(getCalToolTip());
}
void VNA::createDefaultTracesAndGraphs(int ports)
{
auto getDefaultColor = [](int ports, int i, int j)->QColor {
// Default colors for up to four ports, ensures that e.g. S21 always has the same color
const array<vector<QColor>, 4> defaultColors = {{
{Qt::yellow},
{Qt::yellow, Qt::blue, Qt::green, Qt::red},
{Qt::yellow, Qt::blue, Qt::cyan, Qt::green, Qt::red, Qt::darkGreen, Qt::darkBlue, Qt::darkYellow, Qt::magenta},
{Qt::yellow, Qt::blue, Qt::cyan, Qt::darkCyan, Qt::green, Qt::red, Qt::darkGreen, Qt::gray, Qt::darkBlue, Qt::darkYellow, Qt::magenta, Qt::darkMagenta, Qt::cyan, Qt::darkGray, Qt::lightGray, Qt::darkRed},
}};
if(ports >= 1 && ports <= 4) {
return defaultColors[ports-1][i*ports+j];
} else {
// not enough predefined colors available for all ports, just cycle through list
const array<QColor, 16> list = {{
Qt::yellow, Qt::blue, Qt::green, Qt::red, Qt::cyan, Qt::magenta, Qt::yellow, Qt::darkRed, Qt::darkGreen, Qt::darkBlue, Qt::gray, Qt::darkCyan, Qt::darkMagenta, Qt::darkYellow, Qt::darkGray, Qt::lightGray
}};
auto index = (i*ports+j) % list.size();
return list[index];
}
};
vector<vector<TracePlot*>> plots;
for(int i=0;i<ports;i++) {
plots.push_back(vector<TracePlot*>());
for(int j=0;j<ports;j++) {
QString param = "S"+QString::number(i+1)+QString::number(j+1);
auto trace = new Trace(param, getDefaultColor(ports, i, j), param);
traceModel.addTrace(trace);
TracePlot *plot;
if(i == j) {
plot = new TraceSmithChart(traceModel);
} else {
plot = new TraceXYPlot(traceModel);
}
plot->updateSpan(settings.Freq.start, settings.Freq.stop);
plot->enableTrace(trace, true);
plots[i].push_back(plot);
}
}
// Add created graphs to tiles
central->clear();
TileWidget *tile = central;
for(int i=0;i<ports;i++) {
TileWidget *row;
if(i != ports - 1) {
// this is not the last row, split tile
tile->splitVertically();
row = tile->Child1();
tile = tile->Child2();
} else {
row = tile;
}
for(int j=0;j<ports;j++) {
TileWidget *graphTile;
if(j != ports - 1) {
row->splitHorizontally();
graphTile = row->Child1();
row = row->Child2();
} else {
graphTile = row;
}
graphTile->setPlot(plots[i][j]);
}
}
if(ports >= 3) {
// default split at the middle does not result in all plots being the same size, adjust
tile = central;
for(int i=0;i<ports;i++) {
TileWidget *rowTile;
if(i < ports - 1) {
tile->setSplitPercentage(100 / (ports - i));
rowTile = tile->Child1();
} else {
rowTile = tile;
}
for(int j=0;j<ports-1;j++) {
rowTile->setSplitPercentage(100 / (ports - j));
rowTile = rowTile->Child2();
}
tile = tile->Child2();
}
}
}
void VNA::EnableDeembedding(bool enable)
{
deembedding_active = enable;
@ -1637,6 +1693,17 @@ void VNA::setAveragingMode(Averaging::Mode mode)
average.setMode(mode);
}
void VNA::preset()
{
for(auto t : traceModel.getTraces()) {
if(Trace::isVNAParameter(t->name())) {
traceModel.removeTrace(t);
}
}
// Create default traces
createDefaultTracesAndGraphs(VirtualDevice::getInfo(window->getDevice()).ports);
}
QString VNA::SweepTypeToString(VNA::SweepType sw)
{
switch(sw) {

View File

@ -33,6 +33,8 @@ public:
void updateGraphColors();
void setAveragingMode(Averaging::Mode mode) override;
void preset() override;
enum class SweepType {
Frequency = 0,
Power = 1,
@ -121,6 +123,8 @@ private:
void StopSweep();
void StartCalibrationDialog(Calibration::Type type = Calibration::Type::None);
void UpdateCalWidget();
void createDefaultTracesAndGraphs(int ports);
private slots:
void EnableDeembedding(bool enable);
void UpdateStatusbar();

View File

@ -236,6 +236,11 @@ void AppWindow::SetupMenu()
connect(ui->actionSource_Calibration, &QAction::triggered, this, &AppWindow::SourceCalibrationDialog);
connect(ui->actionReceiver_Calibration, &QAction::triggered, this, &AppWindow::ReceiverCalibrationDialog);
connect(ui->actionFrequency_Calibration, &QAction::triggered, this, &AppWindow::FrequencyCalibrationDialog);
connect(ui->actionPreset, &QAction::triggered, [=](){
modeHandler->getActiveMode()->preset();
});
connect(ui->actionPreferences, &QAction::triggered, [=](){
// save previous SCPI settings in case they change
auto &p = Preferences::getInstance();
@ -338,6 +343,7 @@ bool AppWindow::ConnectToDevice(QString serial)
ui->actionReceiver_Calibration->setEnabled(true);
ui->actionFrequency_Calibration->setEnabled(true);
}
ui->actionPreset->setEnabled(true);
UpdateAcquisitionFrequencies();
@ -368,6 +374,7 @@ void AppWindow::DisconnectDevice()
ui->actionSource_Calibration->setEnabled(false);
ui->actionReceiver_Calibration->setEnabled(false);
ui->actionFrequency_Calibration->setEnabled(false);
ui->actionPreset->setEnabled(false);
for(auto a : deviceActionGroup->actions()) {
a->setChecked(false);
}

View File

@ -82,8 +82,15 @@
</property>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionPreset"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuDevice"/>
<addaction name="menuView"/>
<addaction name="menuWindow"/>
<addaction name="menuHelp"/>
</widget>
@ -209,6 +216,14 @@
<string>Frequency Calibration</string>
</property>
</action>
<action name="actionPreset">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Preset</string>
</property>
</action>
</widget>
<resources>
<include location="icons.qrc"/>

View File

@ -43,6 +43,8 @@ public:
virtual void setAveragingMode(Averaging::Mode mode) = 0;
virtual void preset() = 0;
signals:
void statusbarMessage(QString msg);
protected:

View File

@ -138,6 +138,10 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
auto index = ui->compoundList->currentRow();
if(index >= 0 && index < p->compoundDevices.size()) {
auto d = new CompoundDeviceEditDialog(p->compoundDevices[index]);
connect(d, &QDialog::accepted, [=](){
ui->compoundList->item(index)->setText(p->compoundDevices[index]->getDesription());
p->nonTrivialWriting();
});
d->show();
}
});
@ -276,7 +280,7 @@ void PreferencesDialog::setInitialGUIState()
ui->StartupSAAveraging->setValue(p->Startup.SA.averaging);
ui->StartupSASignalID->setChecked(p->Startup.SA.signalID);
ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts);
ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteAllPorts);
ui->AcquisitionSuppressPeaks->setChecked(p->Acquisition.suppressPeaks);
ui->AcquisitionAdjustPowerLevel->setChecked(p->Acquisition.adjustPowerLevel);
ui->AcquisitionUseHarmonic->setChecked(p->Acquisition.harmonicMixing);
@ -346,7 +350,7 @@ void PreferencesDialog::updateFromGUI()
p->Startup.SA.detector = ui->StartupSADetector->currentIndex();
p->Startup.SA.signalID = ui->StartupSASignalID->isChecked();
p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked();
p->Acquisition.alwaysExciteAllPorts = ui->AcquisitionAlwaysExciteBoth->isChecked();
p->Acquisition.suppressPeaks = ui->AcquisitionSuppressPeaks->isChecked();
p->Acquisition.adjustPowerLevel = ui->AcquisitionAdjustPowerLevel->isChecked();
p->Acquisition.harmonicMixing = ui->AcquisitionUseHarmonic->isChecked();
@ -379,6 +383,8 @@ void PreferencesDialog::updateFromGUI()
p->SCPIServer.enabled = ui->SCPIServerEnabled->isChecked();
p->SCPIServer.port = ui->SCPIServerPort->value();
p->nonTrivialWriting();
}
void Preferences::load()

View File

@ -83,7 +83,7 @@ public:
} SA;
} Startup;
struct {
bool alwaysExciteBothPorts;
bool alwaysExciteAllPorts;
bool suppressPeaks;
bool adjustPowerLevel;
bool harmonicMixing;
@ -145,7 +145,9 @@ public:
private:
Preferences() :
TCPoverride(false) {}
TCPoverride(false) {
qDebug() << "Pref constructor: " << &compoundDeviceJSON;
}
static Preferences instance;
const std::vector<Savable::SettingDescription> descr = {{
@ -174,7 +176,7 @@ private:
{&Startup.SA.detector, "Startup.SA.detector", 0},
{&Startup.SA.averaging, "Startup.SA.averaging", 1},
{&Startup.SA.signalID, "Startup.SA.signalID", true},
{&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", true},
{&Acquisition.alwaysExciteAllPorts, "Acquisition.alwaysExciteBothPorts", true},
{&Acquisition.suppressPeaks, "Acquisition.suppressPeaks", true},
{&Acquisition.adjustPowerLevel, "Acquisition.adjustPowerLevel", false},
{&Acquisition.harmonicMixing, "Acquisition.harmonicMixing", false},

View File

@ -84,7 +84,7 @@
<x>0</x>
<y>0</y>
<width>687</width>
<height>884</height>
<height>938</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
@ -103,7 +103,7 @@
</size>
</property>
<property name="currentIndex">
<number>5</number>
<number>1</number>
</property>
<widget class="QWidget" name="Startup">
<layout class="QHBoxLayout" name="horizontalLayout_4">
@ -714,7 +714,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If only S11/S21 or S22/S12 are enabled, faster sweeps are possible by only exciting one port. Checking this option forces the device to always excite both ports even when the measurements from one port will not be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always perform full 2-port measurement</string>
<string>Always create the stimulus signal at all ports</string>
</property>
</widget>
</item>

View File

@ -305,10 +305,6 @@ inline void App_Process() {
}
}
if(HW::TimedOut()) {
vTaskDelay(1000);
LOG_WARN("Timed out, FPGA status: 0x%04x", FPGA::GetStatus());
vTaskDelay(1000);
LOG_WARN("Trigger out: %d (last reported: %d), in: %d", (uint8_t) Trigger::GetOutput(), (uint8_t) lastReportedTrigger, (uint8_t) Trigger::GetInput());
HW::SetMode(HW::Mode::Idle);
// insert the last received packet (restarts the timed out operation)
Communication::BlockNextAck();

View File

@ -130,7 +130,8 @@ using SweepSettings = struct _sweepSettings {
uint16_t points;
uint32_t if_bandwidth;
int16_t cdbm_excitation_start; // in 1/100 dbm
uint16_t unused:2;
uint16_t unused:1;
uint16_t syncMaster:1;
uint16_t suppressPeaks:1;
uint16_t fixedPowerSetting:1; // if set the attenuator and source PLL power will not be changed across the sweep
uint16_t logSweep:1;
@ -258,6 +259,7 @@ using SpectrumAnalyzerSettings = struct _spectrumAnalyzerSettings {
* 3: Trigger synchronization (not supported yet by hardware)
*/
uint8_t syncMode :2;
uint8_t syncMaster :1;
int64_t trackingGeneratorOffset;
int16_t trackingPower;
};

View File

@ -130,7 +130,7 @@ void FPGA::SetSamplesPerPoint(uint32_t nsamples) {
WriteRegister(Reg::SamplesPerPoint, nsamples);
}
void FPGA::SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize) {
void FPGA::SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize, bool syncMaster) {
uint16_t value = 0x0000;
value |= (uint16_t) (stages & 0x07) << 13;
if(synchronize) {
@ -139,6 +139,7 @@ void FPGA::SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage,
value |= (port1_stage & 0x07) << 3;
value |= (port2_stage & 0x07) << 0;
WriteRegister(Reg::SweepSetup, value);
Enable(Periphery::SyncMaster, syncMaster);
}
void FPGA::Enable(Periphery p, bool enable) {

View File

@ -61,7 +61,7 @@ enum class Periphery {
DebugLED = 0x0080,
SourceChip = 0x0010,
LO1Chip = 0x0008,
SyncMaster = 0x0002,
PortSwitch = 0x0001,
};
@ -114,7 +114,7 @@ bool Init(HaltedCallback cb = nullptr);
void WriteRegister(FPGA::Reg reg, uint16_t value);
void SetNumberOfPoints(uint16_t npoints);
void SetSamplesPerPoint(uint32_t nsamples);
void SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize = false);
void SetupSweep(uint8_t stages, uint8_t port1_stage, uint8_t port2_stage, bool synchronize = false, bool syncMaster = false);
void Enable(Periphery p, bool enable = true);
void Disable(Periphery p);
bool IsEnabled(Periphery p);

View File

@ -9,6 +9,7 @@
#include "delay.hpp"
#include "SpectrumAnalyzer.hpp"
#include "Communication.h"
#include "Trigger.hpp"
#include <cstring>
#define LOG_LEVEL LOG_LEVEL_INFO
@ -230,6 +231,7 @@ bool HW::GetTemps(uint8_t *source, uint8_t *lo) {
void HW::SetIdle() {
unlevel = false;
Trigger::SetInput(false);
FPGA::AbortSweep();
FPGA::SetMode(FPGA::Mode::FPGA);
FPGA::DisableHardwareOverwrite();

View File

@ -87,8 +87,8 @@ void LED::Init() {
#if HW_REVISION == 'B'
led_ncnt = 0;
mode = Mode::Off;
HAL_TIM_Base_Start(&htim2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
// HAL_TIM_Base_Start(&htim2);
// HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
LedStatusHandle = xTaskCreateStatic(LedStatus, "LedStatusTask", LED_STATUS_TASK_STACK_SIZE_WORDS,
NULL, 6, LedStatusStack, &LedStatusCB);
@ -132,3 +132,11 @@ void LED::Error(uint8_t code) {
vTaskResume(LedStatusHandle);
#endif
}
void LED::On() {
GPIOA->BSRR = GPIO_PIN_15;
}
void LED::Toggle() {
GPIOA->ODR ^= GPIO_PIN_15;
}

View File

@ -9,4 +9,7 @@ void Pulsating();
void Off();
void Error(uint8_t code);
void On();
void Toggle();
}

View File

@ -225,7 +225,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
FPGA::SetWindow((FPGA::Window) s.WindowType);
FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0, s.syncMode != 0);
FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0, s.syncMode != 0, s.syncMaster);
FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Port1Mixer);

View File

@ -279,7 +279,7 @@ bool VNA::Setup(Protocol::SweepSettings s) {
FPGA::Enable(FPGA::Periphery::SourceRF);
FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::SetupSweep(s.stages, s.port1Stage, s.port2Stage, s.syncMode != 0);
FPGA::SetupSweep(s.stages, s.port1Stage, s.port2Stage, s.syncMode != 0, s.syncMaster);
Trigger::SetMode((Trigger::Mode) s.syncMode);
FPGA::Enable(FPGA::Periphery::PortSwitch);
pointCnt = 0;

View File

@ -405,7 +405,7 @@ SPI2.VirtualType=VM_MASTER
TIM1.IPParameters=Prescaler
TIM1.Prescaler=159
TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM2.IPParameters=Channel-PWM Generation1 CH1,Prescaler,PeriodNoDither,OCMode_PWM-PWM Generation1 CH1
TIM2.IPParameters=Prescaler,PeriodNoDither,Channel-PWM Generation1 CH1,OCMode_PWM-PWM Generation1 CH1
TIM2.OCMode_PWM-PWM\ Generation1\ CH1=TIM_OCMODE_PWM2
TIM2.PeriodNoDither=99
TIM2.Prescaler=143