Merge branch 'master' of github.com:jankae/LibreVNA
This commit is contained in:
commit
4243e64f7f
Binary file not shown.
@ -343,9 +343,10 @@ 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}
|
||||
\rwbits{13}{1}{EXP2}
|
||||
\rwbits{14}{1}{EXP1}
|
||||
\rwbits{15}{1}{PSEN}
|
||||
\robits{13}{3}{reserved}
|
||||
%\rwbits{13}{1}{EXP2}
|
||||
%\rwbits{14}{1}{EXP1}
|
||||
%\rwbits{15}{1}{PSEN}
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
\begin{itemize}
|
||||
@ -371,8 +372,8 @@ Setting & Window type\\
|
||||
\end{center}
|
||||
\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{EXP1:}{Excite Port1 during sweep}
|
||||
%\item \textbf{EXP2:}{Excite Port2 during sweep}
|
||||
\item \textbf{PSEN:}{Port switch enable}
|
||||
\end{itemize}
|
||||
|
||||
@ -407,6 +408,27 @@ $$ PhaseInc = \frac{4096 * f_{IF2}}{SR_{ADC}} $$
|
||||
For the the default IF frequency of $f_{IF2} = \SI{250}{\kilo\hertz}$ this evaluates to 10*Presc (see ADC prescaler register).
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Sweep setup: 0x06}
|
||||
Each point in the sweep is done in stages. Each stage consists of (optionally) routing the source signal to one of the ports and sampling of all ADCs. A "new data" interrupt is triggered after each stage.
|
||||
\label{reg:sweepsetup}
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\bitrect{16}{16-\bit}
|
||||
\rwbits{0}{3}{Stages}
|
||||
\rwbits{3}{1}{IH}
|
||||
\robits{4}{6}{reserved}
|
||||
\rwbits{10}{3}{Port 1 stage}
|
||||
\rwbits{13}{3}{Port 2 stage}
|
||||
\end{tikzpicture}
|
||||
\end{center}
|
||||
\begin{itemize}
|
||||
\item \textbf{Stages} Number of stages per point - 1. Normally the number of stages is equal to the number of ports but it can also be less (e.g. if only S11 is measured).
|
||||
\item \textbf{IH:} Individual halt: Sets the behavior of the "halt sweep" bit (see section~\ref{sweepconfig}). If 1, the sampling is halted before each stage. If 0, the sampling is only halted before the point and all stages are executed without additional halts inbetween.
|
||||
\item \textbf{Port 1 stage} Number of stage during which the source signal is routed to port 1. Must not have the same value as Port 2 stage.
|
||||
\item \textbf{Port 2 stage} Number of stage during which the source signal is routed to port 2. Must not have the same value as Port 1 stage.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\subsection{MAX2871 Default Values Registers: 0x08-0x0F}
|
||||
See datasheet of MAX2871 for bit descriptions. Bits for the fields N, FRAC, M, VCO and DIV\_A are "don't care" as they will be overwritten by the SweepConfig setting.
|
||||
\begin{center}
|
||||
@ -574,12 +596,11 @@ Setting & Selected Power\\
|
||||
|
||||
\section{Sampling Result}
|
||||
\label{result}
|
||||
Each point in the sweep generates two sampling results. The first one contains the measurement when the source was routed to Port 1, the second sampling result was taken when the source was routed to Port 2.
|
||||
Each point in the sweep generates a sampling results for each stage (see section~\ref{reg:sweepsetup}).
|
||||
\begin{center}
|
||||
\begin{tikzpicture}
|
||||
\bitrect{16}{304-\bit}
|
||||
\rwbits{0}{1}{SRC}
|
||||
\robits{1}{2}{reserved}
|
||||
\rwbits{0}{3}{STAGE[2:0]}
|
||||
\rwbits{3}{13}{POINT\_NUMBER[12:0]}
|
||||
\end{tikzpicture}
|
||||
\begin{tikzpicture}
|
||||
|
@ -50,8 +50,10 @@ entity SPICommands is
|
||||
SWEEP_WRITE : out STD_LOGIC_VECTOR (0 downto 0);
|
||||
SWEEP_POINTS : out STD_LOGIC_VECTOR (12 downto 0);
|
||||
NSAMPLES : out STD_LOGIC_VECTOR (12 downto 0);
|
||||
EXCITE_PORT1 : out STD_LOGIC;
|
||||
EXCITE_PORT2 : out STD_LOGIC;
|
||||
STAGES : out STD_LOGIC_VECTOR (2 downto 0);
|
||||
INDIVIDUAL_HALT : 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;
|
||||
PORT2_EN : out STD_LOGIC;
|
||||
REF_EN : out STD_LOGIC;
|
||||
@ -154,8 +156,6 @@ begin
|
||||
SOURCE_CE_EN <= '0';
|
||||
LO_CE_EN <= '0';
|
||||
PORTSWITCH_EN <= '0';
|
||||
EXCITE_PORT1 <= '0';
|
||||
EXCITE_PORT2 <= '0';
|
||||
LEDS <= (others => '1');
|
||||
WINDOW_SETTING <= "00";
|
||||
unread_sampling_data <= '0';
|
||||
@ -243,10 +243,12 @@ begin
|
||||
WINDOW_SETTING <= spi_buf_out(6 downto 5);
|
||||
SOURCE_CE_EN <= spi_buf_out(4);
|
||||
LO_CE_EN <= spi_buf_out(3);
|
||||
EXCITE_PORT1 <= spi_buf_out(1);
|
||||
EXCITE_PORT2 <= spi_buf_out(2);
|
||||
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);
|
||||
INDIVIDUAL_HALT <= spi_buf_out(12);
|
||||
PORT1_STAGE <= spi_buf_out(5 downto 3);
|
||||
PORT2_STAGE <= spi_buf_out(2 downto 0);
|
||||
when 8 => MAX2871_DEF_0(15 downto 0) <= spi_buf_out;
|
||||
when 9 => MAX2871_DEF_0(31 downto 16) <= spi_buf_out;
|
||||
when 10 => MAX2871_DEF_1(15 downto 0) <= spi_buf_out;
|
||||
|
@ -40,7 +40,6 @@ entity Sweep is
|
||||
SAMPLING_BUSY : in STD_LOGIC;
|
||||
SAMPLING_DONE : in STD_LOGIC;
|
||||
START_SAMPLING : out STD_LOGIC;
|
||||
PORT_SELECT : out STD_LOGIC;
|
||||
BAND_SELECT : out STD_LOGIC;
|
||||
-- fixed part of source/LO registers
|
||||
MAX2871_DEF_4 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
@ -67,8 +66,13 @@ entity Sweep is
|
||||
|
||||
--SETTLING_TIME : in STD_LOGIC_VECTOR (15 downto 0);
|
||||
|
||||
EXCITE_PORT1 : in STD_LOGIC;
|
||||
EXCITE_PORT2 : in STD_LOGIC;
|
||||
STAGES : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
INDIVIDUAL_HALT : in STD_LOGIC;
|
||||
PORT1_STAGE : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
PORT2_STAGE : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
|
||||
PORT1_ACTIVE : out STD_LOGIC;
|
||||
PORT2_ACTIVE : out STD_LOGIC;
|
||||
|
||||
-- Debug signals
|
||||
DEBUG_STATUS : out STD_LOGIC_VECTOR (10 downto 0);
|
||||
@ -78,10 +82,11 @@ end Sweep;
|
||||
|
||||
architecture Behavioral of Sweep is
|
||||
signal point_cnt : unsigned(12 downto 0);
|
||||
type Point_states is (TriggerSetup, SettingUp, SettlingPort1, ExcitingPort1, SettlingPort2, ExcitingPort2, NextPoint, Done);
|
||||
type Point_states is (TriggerSetup, SettingUp, Settling, Exciting, NextPoint, Done);
|
||||
signal state : Point_states;
|
||||
signal settling_cnt : unsigned(15 downto 0);
|
||||
signal settling_time : unsigned(15 downto 0);
|
||||
signal stage_cnt : unsigned (2 downto 0);
|
||||
signal config_reg : std_logic_vector(95 downto 0);
|
||||
begin
|
||||
|
||||
@ -121,10 +126,8 @@ begin
|
||||
|
||||
DEBUG_STATUS(10 downto 8) <= "000" when state = TriggerSetup else
|
||||
"001" when state = SettingUp else
|
||||
"010" when state = SettlingPort1 else
|
||||
"011" when state = ExcitingPort1 else
|
||||
"100" when state = SettlingPort2 else
|
||||
"101" when state = ExcitingPort2 else
|
||||
"010" when state = Settling else
|
||||
"011" when state = Exciting else
|
||||
"110" when state = Done else
|
||||
"111";
|
||||
DEBUG_STATUS(7) <= PLL_RELOAD_DONE;
|
||||
@ -139,15 +142,19 @@ begin
|
||||
if rising_edge(CLK) then
|
||||
if RESET = '1' then
|
||||
point_cnt <= (others => '0');
|
||||
stage_cnt <= (others => '0');
|
||||
state <= TriggerSetup;
|
||||
START_SAMPLING <= '0';
|
||||
RELOAD_PLL_REGS <= '0';
|
||||
SWEEP_HALTED <= '0';
|
||||
RESULT_INDEX <= (others => '1');
|
||||
PORT1_ACTIVE <= '0';
|
||||
PORT2_ACTIVE <= '0';
|
||||
else
|
||||
case state is
|
||||
when TriggerSetup =>
|
||||
RELOAD_PLL_REGS <= '1';
|
||||
stage_cnt <= (others => '0');
|
||||
if PLL_RELOAD_DONE = '0' then
|
||||
state <= SettingUp;
|
||||
end if;
|
||||
@ -166,60 +173,52 @@ begin
|
||||
-- check if halted sweep is resumed
|
||||
if config_reg(95) = '0' or SWEEP_RESUME = '1' then
|
||||
SWEEP_HALTED <= '0';
|
||||
if EXCITE_PORT1 = '1' then
|
||||
state <= SettlingPort1;
|
||||
else
|
||||
state <= SettlingPort2;
|
||||
end if;
|
||||
state <= Settling;
|
||||
end if;
|
||||
end if;
|
||||
when SettlingPort1 =>
|
||||
PORT_SELECT <= '1';
|
||||
when Settling =>
|
||||
if std_logic_vector(stage_cnt) = PORT1_STAGE then
|
||||
PORT1_ACTIVE <= '1';
|
||||
else
|
||||
PORT1_ACTIVE <= '0';
|
||||
end if;
|
||||
if std_logic_vector(stage_cnt) = PORT2_STAGE then
|
||||
PORT2_ACTIVE <= '1';
|
||||
else
|
||||
PORT2_ACTIVE <= '0';
|
||||
end if;
|
||||
-- wait for settling time to elapse
|
||||
if settling_cnt > 0 then
|
||||
settling_cnt <= settling_cnt - 1;
|
||||
else
|
||||
START_SAMPLING <= '1';
|
||||
if SAMPLING_BUSY = '1' then
|
||||
state <= ExcitingPort1;
|
||||
state <= Exciting;
|
||||
end if;
|
||||
end if;
|
||||
when ExcitingPort1 =>
|
||||
when Exciting =>
|
||||
-- wait for sampling to finish
|
||||
START_SAMPLING <= '0';
|
||||
if SAMPLING_BUSY = '0' then
|
||||
RESULT_INDEX <= "000" & std_logic_vector(point_cnt);
|
||||
if EXCITE_PORT2 = '1' then
|
||||
state <= SettlingPort2;
|
||||
RESULT_INDEX <= std_logic_vector(stage_cnt) & std_logic_vector(point_cnt);
|
||||
if stage_cnt < unsigned(STAGES) then
|
||||
stage_cnt <= stage_cnt + 1;
|
||||
if INDIVIDUAL_HALT = '1' then
|
||||
-- wait for HALT SWEEP bit again if set
|
||||
state <= SettingUp;
|
||||
else
|
||||
-- no need to halt again, can go directly to settling
|
||||
state <= Settling;
|
||||
end if;
|
||||
else
|
||||
state <= NextPoint;
|
||||
end if;
|
||||
settling_cnt <= settling_time;
|
||||
end if;
|
||||
when SettlingPort2 =>
|
||||
PORT_SELECT <= '0';
|
||||
-- wait for settling time to elapse
|
||||
if settling_cnt > 0 then
|
||||
settling_cnt <= settling_cnt - 1;
|
||||
else
|
||||
START_SAMPLING <= '1';
|
||||
if SAMPLING_BUSY = '1' then
|
||||
state <= ExcitingPort2;
|
||||
end if;
|
||||
end if;
|
||||
when ExcitingPort2 =>
|
||||
-- wait for sampling to finish
|
||||
START_SAMPLING <= '0';
|
||||
RESULT_INDEX <= "100" & std_logic_vector(point_cnt);
|
||||
if SAMPLING_BUSY = '0' then
|
||||
state <= NextPoint;
|
||||
end if;
|
||||
when NextPoint =>
|
||||
if point_cnt < unsigned(NPOINTS) then
|
||||
point_cnt <= point_cnt + 1;
|
||||
state <= TriggerSetup;
|
||||
-- initial port depends on whether port 1 is exited
|
||||
PORT_SELECT <= EXCITE_PORT1;
|
||||
else
|
||||
point_cnt <= (others => '0');
|
||||
state <= Done;
|
||||
|
@ -224,7 +224,7 @@
|
||||
<status xil_pn:value="SuccessfullyRun"/>
|
||||
<status xil_pn:value="ReadyToRun"/>
|
||||
</transform>
|
||||
<transform xil_pn:end_ts="1625850461" xil_pn:in_ck="-4366097307991745463" xil_pn:name="TRAN_regenerateCores" xil_pn:prop_ck="-2723611991789822717" xil_pn:start_ts="1625850460">
|
||||
<transform xil_pn:end_ts="1648844622" xil_pn:in_ck="-4366097307991745463" xil_pn:name="TRAN_regenerateCores" xil_pn:prop_ck="-2723611991789822717" xil_pn:start_ts="1648844621">
|
||||
<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="1625861989" xil_pn:in_ck="2241500006820465658" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1625861965">
|
||||
<transform xil_pn:end_ts="1648846416" xil_pn:in_ck="2241500006820465658" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="3256065936432453276" xil_pn:start_ts="1648846407">
|
||||
<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="1625861996" xil_pn:in_ck="5411862124762956458" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1625861989">
|
||||
<transform xil_pn:end_ts="1648846420" xil_pn:in_ck="5411862124762956458" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="4604875190571501774" xil_pn:start_ts="1648846416">
|
||||
<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="1625862085" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="-4668962392366239264" xil_pn:start_ts="1625861996">
|
||||
<transform xil_pn:end_ts="1648846449" xil_pn:in_ck="8512332261572065657" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="-4668962392366239264" xil_pn:start_ts="1648846420">
|
||||
<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="1625862116" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-1085068593928086116" xil_pn:start_ts="1625862085">
|
||||
<transform xil_pn:end_ts="1648846462" xil_pn:in_ck="1117507038335044978" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-1085068593928086116" xil_pn:start_ts="1648846449">
|
||||
<status xil_pn:value="SuccessfullyRun"/>
|
||||
<status xil_pn:value="ReadyToRun"/>
|
||||
<outfile xil_pn:name="_xmsgs/par.xmsgs"/>
|
||||
@ -312,9 +312,8 @@
|
||||
<outfile xil_pn:name="top_pad.txt"/>
|
||||
<outfile xil_pn:name="top_par.xrpt"/>
|
||||
</transform>
|
||||
<transform xil_pn:end_ts="1625862132" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1625862116">
|
||||
<transform xil_pn:end_ts="1648846469" xil_pn:in_ck="154288912438" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="3274353840855015246" xil_pn:start_ts="1648846462">
|
||||
<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"/>
|
||||
@ -366,7 +365,7 @@
|
||||
<status xil_pn:value="InputChanged"/>
|
||||
<status xil_pn:value="InputRemoved"/>
|
||||
</transform>
|
||||
<transform xil_pn:end_ts="1625862116" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1625862109">
|
||||
<transform xil_pn:end_ts="1648846462" xil_pn:in_ck="8512326635937592693" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416184" xil_pn:start_ts="1648846459">
|
||||
<status xil_pn:value="SuccessfullyRun"/>
|
||||
<status xil_pn:value="ReadyToRun"/>
|
||||
<outfile xil_pn:name="_xmsgs/trce.xmsgs"/>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="top.vhd" xil_pn:type="FILE_VHDL">
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="DSP_SLICE.ngc" xil_pn:type="FILE_NGC">
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="PLL.ucf" xil_pn:type="FILE_UCF">
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="SinCos.ngc" xil_pn:type="FILE_NGC">
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="SweepConfigMem.ngc" xil_pn:type="FILE_NGC">
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
|
||||
</header>
|
||||
|
||||
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
|
||||
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
|
||||
|
||||
<files>
|
||||
<file xil_pn:name="result_bram.ngc" xil_pn:type="FILE_NGC">
|
||||
|
BIN
FPGA/VNA/top.bin
BIN
FPGA/VNA/top.bin
Binary file not shown.
@ -124,7 +124,6 @@ architecture Behavioral of top is
|
||||
PLL_LOCKED : IN std_logic;
|
||||
CONFIG_ADDRESS : OUT std_logic_vector(12 downto 0);
|
||||
START_SAMPLING : OUT std_logic;
|
||||
PORT_SELECT : OUT std_logic;
|
||||
BAND_SELECT : out STD_LOGIC;
|
||||
SOURCE_REG_4 : OUT std_logic_vector(31 downto 0);
|
||||
SOURCE_REG_3 : OUT std_logic_vector(31 downto 0);
|
||||
@ -139,8 +138,13 @@ architecture Behavioral of top is
|
||||
SWEEP_RESUME : in STD_LOGIC;
|
||||
ATTENUATOR : OUT std_logic_vector(6 downto 0);
|
||||
SOURCE_FILTER : OUT std_logic_vector(1 downto 0);
|
||||
EXCITE_PORT1 : in STD_LOGIC;
|
||||
EXCITE_PORT2 : in STD_LOGIC;
|
||||
STAGES : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
INDIVIDUAL_HALT : in STD_LOGIC;
|
||||
PORT1_STAGE : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
PORT2_STAGE : in STD_LOGIC_VECTOR (2 downto 0);
|
||||
|
||||
PORT1_ACTIVE : out STD_LOGIC;
|
||||
PORT2_ACTIVE : out STD_LOGIC;
|
||||
RESULT_INDEX : out STD_LOGIC_VECTOR (15 downto 0);
|
||||
DEBUG_STATUS : out STD_LOGIC_VECTOR (10 downto 0)
|
||||
);
|
||||
@ -243,8 +247,10 @@ architecture Behavioral of top is
|
||||
SWEEP_WRITE : OUT std_logic_vector(0 to 0);
|
||||
SWEEP_POINTS : OUT std_logic_vector(12 downto 0);
|
||||
NSAMPLES : OUT std_logic_vector(12 downto 0);
|
||||
EXCITE_PORT1 : out STD_LOGIC;
|
||||
EXCITE_PORT2 : out STD_LOGIC;
|
||||
STAGES : out STD_LOGIC_VECTOR (2 downto 0);
|
||||
INDIVIDUAL_HALT : 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;
|
||||
PORT2_EN : out STD_LOGIC;
|
||||
REF_EN : out STD_LOGIC;
|
||||
@ -360,10 +366,14 @@ architecture Behavioral of top is
|
||||
|
||||
-- Sweep signals
|
||||
signal sweep_points : std_logic_vector(12 downto 0);
|
||||
signal sweep_stages : STD_LOGIC_VECTOR (2 downto 0);
|
||||
signal sweep_individual_halt : 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);
|
||||
signal sweep_config_address : std_logic_vector(12 downto 0);
|
||||
signal source_filter : std_logic_vector(1 downto 0);
|
||||
signal sweep_port_select : std_logic;
|
||||
signal sweep_band : std_logic;
|
||||
|
||||
signal sweep_config_write_address : std_logic_vector(12 downto 0);
|
||||
signal sweep_config_write_data : std_logic_vector(95 downto 0);
|
||||
@ -376,8 +386,6 @@ architecture Behavioral of top is
|
||||
signal sweep_excite_port1 : std_logic;
|
||||
signal sweep_excite_port2 : std_logic;
|
||||
|
||||
signal sweep_band : std_logic;
|
||||
|
||||
-- Configuration signals
|
||||
signal settling_time : std_logic_vector(15 downto 0);
|
||||
signal def_reg_4 : std_logic_vector(31 downto 0);
|
||||
@ -428,10 +436,10 @@ begin
|
||||
LEDS(2) <= SOURCE_LD;
|
||||
LEDS(3) <= LO1_LD;
|
||||
-- Sweep and active port
|
||||
PORT_SELECT2 <= not sweep_port_select and portswitch_en;
|
||||
PORT2_SELECT <= not sweep_port_select and portswitch_en;
|
||||
PORT_SELECT1 <= sweep_port_select and portswitch_en;
|
||||
PORT1_SELECT <= sweep_port_select and portswitch_en;
|
||||
PORT_SELECT2 <= sweep_excite_port2 and portswitch_en;
|
||||
PORT2_SELECT <= sweep_excite_port2 and portswitch_en;
|
||||
PORT_SELECT1 <= sweep_excite_port1 and portswitch_en;
|
||||
PORT1_SELECT <= sweep_excite_port1 and portswitch_en;
|
||||
BAND_SELECT_HIGH <= not sweep_band;
|
||||
BAND_SELECT_LOW <= sweep_band;
|
||||
PORT1_MIX2_EN <= port1mix_en;
|
||||
@ -440,8 +448,8 @@ begin
|
||||
PORT2_MIX1_EN <= not port2mix_en;
|
||||
REF_MIX2_EN <= refmix_en;
|
||||
REF_MIX1_EN <= not refmix_en;
|
||||
LEDS(4) <= not (not sweep_reset and not sweep_port_select and portswitch_en);
|
||||
LEDS(5) <= not (not sweep_reset and sweep_port_select and portswitch_en);
|
||||
LEDS(4) <= not (not sweep_reset and sweep_excite_port2 and portswitch_en);
|
||||
LEDS(5) <= not (not sweep_reset and sweep_excite_port1 and portswitch_en);
|
||||
-- Uncommitted LEDs
|
||||
LEDS(7 downto 6) <= user_leds(1 downto 0);
|
||||
--LEDS(7) <= '0';
|
||||
@ -649,7 +657,6 @@ begin
|
||||
SAMPLING_BUSY => sampling_busy,
|
||||
SAMPLING_DONE => sampling_done,
|
||||
START_SAMPLING => sampling_start,
|
||||
PORT_SELECT => sweep_port_select,
|
||||
BAND_SELECT => sweep_band,
|
||||
MAX2871_DEF_4 => def_reg_4,
|
||||
MAX2871_DEF_3 => def_reg_3,
|
||||
@ -670,8 +677,13 @@ begin
|
||||
SWEEP_RESUME => sweep_resume,
|
||||
ATTENUATOR => ATTENUATION,
|
||||
SOURCE_FILTER => source_filter,
|
||||
EXCITE_PORT1 => sweep_excite_port1,
|
||||
EXCITE_PORT2 => sweep_excite_port2,
|
||||
STAGES => sweep_stages,
|
||||
INDIVIDUAL_HALT => sweep_individual_halt,
|
||||
PORT1_STAGE => sweep_port1_stage,
|
||||
PORT2_STAGE => sweep_port2_stage,
|
||||
|
||||
PORT1_ACTIVE => sweep_excite_port1,
|
||||
PORT2_ACTIVE => sweep_excite_port2,
|
||||
DEBUG_STATUS => debug,
|
||||
RESULT_INDEX => sampling_result(303 downto 288)
|
||||
);
|
||||
@ -740,8 +752,10 @@ begin
|
||||
RESET_MINMAX => adc_reset_minmax,
|
||||
SWEEP_HALTED => sweep_halted,
|
||||
SWEEP_RESUME => sweep_resume,
|
||||
EXCITE_PORT1 => sweep_excite_port1,
|
||||
EXCITE_PORT2 => sweep_excite_port2,
|
||||
STAGES => sweep_stages,
|
||||
INDIVIDUAL_HALT => sweep_individual_halt,
|
||||
PORT1_STAGE => sweep_port1_stage,
|
||||
PORT2_STAGE => sweep_port2_stage,
|
||||
DFT_BIN1_PHASEINC => dft_bin1_phaseinc,
|
||||
DFT_DIFFBIN_PHASEINC => dft_diffbin_phaseinc,
|
||||
DFT_RESULT_READY => dft_ready,
|
||||
|
@ -253,7 +253,7 @@ void AmplitudeCalDialog::RemoveAllPoints()
|
||||
|
||||
bool AmplitudeCalDialog::AddPoint(AmplitudeCalDialog::CorrectionPoint &p)
|
||||
{
|
||||
if (points.size() >= Device::Info().limits_maxAmplitudePoints) {
|
||||
if (points.size() >= Device::Info(dev).limits_maxAmplitudePoints) {
|
||||
// already at limit
|
||||
return false;
|
||||
}
|
||||
@ -299,8 +299,8 @@ void AmplitudeCalDialog::AddPointDialog()
|
||||
ui->stopFreq->setUnit("Hz");
|
||||
ui->stopFreq->setPrefixes(" kMG");
|
||||
ui->frequency->setValue(1000000000.0);
|
||||
ui->startFreq->setValue(Device::Info().limits_minFreq);
|
||||
ui->stopFreq->setValue(Device::Info().limits_maxFreq);
|
||||
ui->startFreq->setValue(Device::Info(dev).limits_minFreq);
|
||||
ui->stopFreq->setValue(Device::Info(dev).limits_maxFreq);
|
||||
connect(ui->singlePoint, &QRadioButton::toggled, [=](bool single) {
|
||||
ui->stopFreq->setEnabled(!single);
|
||||
ui->startFreq->setEnabled(!single);
|
||||
|
@ -120,16 +120,6 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
|
||||
.FW_minor = 0,
|
||||
.FW_patch = 0,
|
||||
.HW_Revision = '0',
|
||||
.extRefAvailable = 0,
|
||||
.extRefInUse = 0,
|
||||
.FPGA_configured = 0,
|
||||
.source_locked = 0,
|
||||
.LO1_locked = 0,
|
||||
.ADC_overload = 0,
|
||||
.unlevel = 0,
|
||||
.temp_source = 0,
|
||||
.temp_LO1 = 0,
|
||||
.temp_MCU = 0,
|
||||
.limits_minFreq = 0,
|
||||
.limits_maxFreq = 6000000000,
|
||||
.limits_minIFBW = 10,
|
||||
@ -143,14 +133,25 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
|
||||
.limits_maxFreqHarmonic = 18000000000,
|
||||
};
|
||||
|
||||
Protocol::DeviceInfo Device::lastInfo = defaultInfo;
|
||||
static constexpr Protocol::DeviceStatusV1 defaultStatusV1 = {
|
||||
.extRefAvailable = 0,
|
||||
.extRefInUse = 0,
|
||||
.FPGA_configured = 0,
|
||||
.source_locked = 0,
|
||||
.LO1_locked = 0,
|
||||
.ADC_overload = 0,
|
||||
.unlevel = 0,
|
||||
.temp_source = 0,
|
||||
.temp_LO1 = 0,
|
||||
.temp_MCU = 0,
|
||||
};
|
||||
|
||||
Device::Device(QString serial)
|
||||
{
|
||||
lastInfo = defaultInfo;
|
||||
info = defaultInfo;
|
||||
|
||||
m_handle = nullptr;
|
||||
lastInfoValid = false;
|
||||
infoValid = false;
|
||||
libusb_init(&m_context);
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
libusb_set_option(m_context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
|
||||
@ -261,10 +262,10 @@ bool Device::Configure(Protocol::SpectrumAnalyzerSettings settings)
|
||||
return SendPacket(p);
|
||||
}
|
||||
|
||||
bool Device::SetManual(Protocol::ManualControl manual)
|
||||
bool Device::SetManual(Protocol::ManualControlV1 manual)
|
||||
{
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::ManualControl;
|
||||
p.type = Protocol::PacketType::ManualControlV1;
|
||||
p.manual = manual;
|
||||
return SendPacket(p);
|
||||
}
|
||||
@ -393,25 +394,48 @@ void Device::SearchDevices(std::function<bool (libusb_device_handle *, QString)>
|
||||
|
||||
const Protocol::DeviceInfo &Device::Info()
|
||||
{
|
||||
return lastInfo;
|
||||
return info;
|
||||
}
|
||||
|
||||
const Protocol::DeviceInfo &Device::Info(Device *dev)
|
||||
{
|
||||
if(dev) {
|
||||
return dev->Info();
|
||||
} else {
|
||||
return defaultInfo;
|
||||
}
|
||||
}
|
||||
|
||||
Protocol::DeviceStatusV1 &Device::StatusV1()
|
||||
{
|
||||
return status.v1;
|
||||
}
|
||||
|
||||
const Protocol::DeviceStatusV1 &Device::StatusV1(Device *dev)
|
||||
{
|
||||
if(dev) {
|
||||
return dev->StatusV1();
|
||||
} else {
|
||||
return defaultStatusV1;
|
||||
}
|
||||
}
|
||||
|
||||
QString Device::getLastDeviceInfoString()
|
||||
{
|
||||
QString ret;
|
||||
if(!lastInfoValid) {
|
||||
if(!infoValid) {
|
||||
ret.append("No device information available yet");
|
||||
} else {
|
||||
ret.append("HW Rev.");
|
||||
ret.append(lastInfo.HW_Revision);
|
||||
ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor)+"."+QString::number(lastInfo.FW_patch));
|
||||
ret.append(" Temps: "+QString::number(lastInfo.temp_source)+"°C/"+QString::number(lastInfo.temp_LO1)+"°C/"+QString::number(lastInfo.temp_MCU)+"°C");
|
||||
ret.append(info.HW_Revision);
|
||||
ret.append(" FW "+QString::number(info.FW_major)+"."+QString::number(info.FW_minor)+"."+QString::number(info.FW_patch));
|
||||
ret.append(" Temps: "+QString::number(status.v1.temp_source)+"°C/"+QString::number(status.v1.temp_LO1)+"°C/"+QString::number(status.v1.temp_MCU)+"°C");
|
||||
ret.append(" Reference:");
|
||||
if(lastInfo.extRefInUse) {
|
||||
if(status.v1.extRefInUse) {
|
||||
ret.append("External");
|
||||
} else {
|
||||
ret.append("Internal");
|
||||
if(lastInfo.extRefAvailable) {
|
||||
if(status.v1.extRefAvailable) {
|
||||
ret.append(" (External available)");
|
||||
}
|
||||
}
|
||||
@ -431,8 +455,8 @@ void Device::ReceivedData()
|
||||
case Protocol::PacketType::Datapoint:
|
||||
emit DatapointReceived(packet.datapoint);
|
||||
break;
|
||||
case Protocol::PacketType::Status:
|
||||
emit ManualStatusReceived(packet.status);
|
||||
case Protocol::PacketType::ManualStatusV1:
|
||||
emit ManualStatusReceived(packet.manualStatusV1);
|
||||
break;
|
||||
case Protocol::PacketType::SpectrumAnalyzerResult:
|
||||
emit SpectrumResultReceived(packet.spectrumResult);
|
||||
@ -443,15 +467,19 @@ void Device::ReceivedData()
|
||||
break;
|
||||
case Protocol::PacketType::DeviceInfo:
|
||||
if(packet.info.ProtocolVersion != Protocol::Version) {
|
||||
if(!lastInfoValid) {
|
||||
if(!infoValid) {
|
||||
emit NeedsFirmwareUpdate(packet.info.ProtocolVersion, Protocol::Version);
|
||||
}
|
||||
} else {
|
||||
lastInfo = packet.info;
|
||||
info = packet.info;
|
||||
}
|
||||
lastInfoValid = true;
|
||||
infoValid = true;
|
||||
emit DeviceInfoUpdated();
|
||||
break;
|
||||
case Protocol::PacketType::DeviceStatusV1:
|
||||
status.v1 = packet.statusV1;
|
||||
emit DeviceStatusUpdated();
|
||||
break;
|
||||
case Protocol::PacketType::Ack:
|
||||
emit AckReceived();
|
||||
emit receivedAnswer(TransmissionResult::Ack);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <QTimer>
|
||||
|
||||
Q_DECLARE_METATYPE(Protocol::Datapoint);
|
||||
Q_DECLARE_METATYPE(Protocol::ManualStatus);
|
||||
Q_DECLARE_METATYPE(Protocol::ManualStatusV1);
|
||||
Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult);
|
||||
Q_DECLARE_METATYPE(Protocol::AmplitudeCorrectionPoint);
|
||||
|
||||
@ -61,23 +61,27 @@ public:
|
||||
bool SendPacket(const Protocol::PacketInfo& packet, std::function<void(TransmissionResult)> cb = nullptr, unsigned int timeout = 500);
|
||||
bool Configure(Protocol::SweepSettings settings, std::function<void(TransmissionResult)> cb = nullptr);
|
||||
bool Configure(Protocol::SpectrumAnalyzerSettings settings);
|
||||
bool SetManual(Protocol::ManualControl manual);
|
||||
bool SetManual(Protocol::ManualControlV1 manual);
|
||||
bool SetIdle();
|
||||
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
|
||||
bool SendCommandWithoutPayload(Protocol::PacketType type);
|
||||
QString serial() const;
|
||||
static const Protocol::DeviceInfo& Info();
|
||||
const Protocol::DeviceInfo& Info();
|
||||
static const Protocol::DeviceInfo& Info(Device *dev);
|
||||
Protocol::DeviceStatusV1& StatusV1();
|
||||
static const Protocol::DeviceStatusV1& StatusV1(Device *dev);
|
||||
QString getLastDeviceInfoString();
|
||||
|
||||
// Returns serial numbers of all connected devices
|
||||
static std::set<QString> GetDevices();
|
||||
signals:
|
||||
void DatapointReceived(Protocol::Datapoint);
|
||||
void ManualStatusReceived(Protocol::ManualStatus);
|
||||
void ManualStatusReceived(Protocol::ManualStatusV1);
|
||||
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
|
||||
void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint);
|
||||
void FrequencyCorrectionReceived(float ppm);
|
||||
void DeviceInfoUpdated();
|
||||
void DeviceStatusUpdated();
|
||||
void ConnectionLost();
|
||||
void AckReceived();
|
||||
void NackReceived();
|
||||
@ -122,8 +126,11 @@ private:
|
||||
QString m_serial;
|
||||
bool m_connected;
|
||||
std::thread *m_receiveThread;
|
||||
static Protocol::DeviceInfo lastInfo;
|
||||
bool lastInfoValid;
|
||||
Protocol::DeviceInfo info;
|
||||
bool infoValid;
|
||||
union {
|
||||
Protocol::DeviceStatusV1 v1;
|
||||
} status;
|
||||
};
|
||||
|
||||
#endif // DEVICE_H
|
||||
|
@ -580,7 +580,7 @@ double ManualControlDialog::getRefPhase()
|
||||
return ui->refphase->text().toDouble();
|
||||
}
|
||||
|
||||
void ManualControlDialog::NewStatus(Protocol::ManualStatus status)
|
||||
void ManualControlDialog::NewStatus(Protocol::ManualStatusV1 status)
|
||||
{
|
||||
// ADC values
|
||||
ui->port1min->setText(QString::number(status.port1min));
|
||||
@ -616,7 +616,7 @@ void ManualControlDialog::NewStatus(Protocol::ManualStatus status)
|
||||
|
||||
void ManualControlDialog::UpdateDevice()
|
||||
{
|
||||
Protocol::ManualControl m;
|
||||
Protocol::ManualControlV1 m;
|
||||
// Source highband
|
||||
m.SourceHighCE = ui->SourceCE->isChecked();
|
||||
m.SourceHighRFEN = ui->SourceRFEN->isChecked();
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
double getRefPhase();
|
||||
|
||||
public slots:
|
||||
void NewStatus(Protocol::ManualStatus status);
|
||||
void NewStatus(Protocol::ManualStatusV1 status);
|
||||
|
||||
private:
|
||||
void UpdateDevice();
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
Generator::Generator(AppWindow *window)
|
||||
: Mode(window, "Signal Generator")
|
||||
, SCPINode("GENerator")
|
||||
Generator::Generator(AppWindow *window, QString name)
|
||||
: Mode(window, name, "GENerator")
|
||||
{
|
||||
central = new SignalgeneratorWidget(window);
|
||||
central = new SignalgeneratorWidget(window->getDevice(), window);
|
||||
|
||||
auto pref = Preferences::getInstance();
|
||||
|
||||
|
@ -5,13 +5,15 @@
|
||||
#include "signalgenwidget.h"
|
||||
#include "scpi.h"
|
||||
|
||||
class Generator : public Mode, public SCPINode
|
||||
class Generator : public Mode
|
||||
{
|
||||
public:
|
||||
Generator(AppWindow *window);
|
||||
Generator(AppWindow *window, QString name = "Signal Generator");
|
||||
void deactivate() override;
|
||||
void initializeDevice() override;
|
||||
|
||||
virtual Type getType() override { return Type::SG;}
|
||||
|
||||
// Nothing to do for now
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
#include "ui_signalgenwidget.h"
|
||||
|
||||
SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
|
||||
SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::SignalgeneratorWidget)
|
||||
ui(new Ui::SignalgeneratorWidget),
|
||||
dev(dev)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->frequency->setUnit("Hz");
|
||||
@ -31,16 +32,16 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
|
||||
ui->steps->setPrecision(0);
|
||||
|
||||
connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) {
|
||||
if(newval < Device::Info().limits_minFreq) {
|
||||
newval = Device::Info().limits_minFreq;
|
||||
} else if (newval > Device::Info().limits_maxFreq) {
|
||||
newval = Device::Info().limits_maxFreq;
|
||||
if(newval < Device::Info(dev).limits_minFreq) {
|
||||
newval = Device::Info(dev).limits_minFreq;
|
||||
} else if (newval > Device::Info(dev).limits_maxFreq) {
|
||||
newval = Device::Info(dev).limits_maxFreq;
|
||||
}
|
||||
ui->frequency->setValueQuiet(newval);
|
||||
if (newval < ui->span->value()/2)
|
||||
ui->span->setValueQuiet(newval/2);
|
||||
if (newval + ui->span->value()/2 > Device::Info().limits_maxFreq)
|
||||
ui->span->setValueQuiet((Device::Info().limits_maxFreq - newval)*2);
|
||||
if (newval + ui->span->value()/2 > Device::Info(dev).limits_maxFreq)
|
||||
ui->span->setValueQuiet((Device::Info(dev).limits_maxFreq - newval)*2);
|
||||
newval = ui->frequency->value() - ui->span->value()/2;
|
||||
ui->current->setValueQuiet(newval);
|
||||
emit SettingsChanged();
|
||||
@ -49,8 +50,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
|
||||
connect(ui->span, &SIUnitEdit::valueChanged, [=](double newval) {
|
||||
if(newval < 0 ) {
|
||||
newval = 0;
|
||||
} else if (newval > Device::Info().limits_maxFreq - Device::Info().limits_minFreq) {
|
||||
newval = Device::Info().limits_maxFreq - Device::Info().limits_minFreq;
|
||||
} else if (newval > Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq) {
|
||||
newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq;
|
||||
}
|
||||
ui->span->setValueQuiet(newval);
|
||||
|
||||
@ -59,8 +60,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
|
||||
ui->frequency->setValueQuiet(ui->span->value()/2);
|
||||
}
|
||||
newF = ui->frequency->value() + ui->span->value()/2;
|
||||
if (newF > Device::Info().limits_maxFreq) {
|
||||
ui->frequency->setValueQuiet(Device::Info().limits_maxFreq - ui->span->value()/2);
|
||||
if (newF > Device::Info(dev).limits_maxFreq) {
|
||||
ui->frequency->setValueQuiet(Device::Info(dev).limits_maxFreq - ui->span->value()/2);
|
||||
}
|
||||
|
||||
newval = ui->frequency->value() - ui->span->value()/2;
|
||||
@ -71,8 +72,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
|
||||
connect(ui->current, &SIUnitEdit::valueChanged, [=](double newval) {
|
||||
if(newval < 0 ) {
|
||||
newval = 0;
|
||||
} else if (newval > Device::Info().limits_maxFreq - Device::Info().limits_minFreq) {
|
||||
newval = Device::Info().limits_maxFreq - Device::Info().limits_minFreq;
|
||||
} else if (newval > Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq) {
|
||||
newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq;
|
||||
}
|
||||
ui->current->setValueQuiet(newval);
|
||||
emit SettingsChanged();
|
||||
|
@ -15,7 +15,7 @@ class SignalgeneratorWidget : public QWidget, public Savable
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignalgeneratorWidget(QWidget *parent = nullptr);
|
||||
explicit SignalgeneratorWidget(Device*&dev, QWidget *parent = nullptr);
|
||||
~SignalgeneratorWidget();
|
||||
|
||||
Protocol::GeneratorSettings getDeviceStatus();
|
||||
@ -36,6 +36,7 @@ protected:
|
||||
private:
|
||||
Ui::SignalgeneratorWidget *ui;
|
||||
int m_timerId;
|
||||
Device*&dev;
|
||||
};
|
||||
|
||||
#endif // SIGNALGENERATOR_H
|
||||
|
@ -45,9 +45,8 @@
|
||||
#include <fstream>
|
||||
#include <QDateTime>
|
||||
|
||||
SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
||||
: Mode(window, "Spectrum Analyzer"),
|
||||
SCPINode("SA"),
|
||||
SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
|
||||
: Mode(window, name, "SA"),
|
||||
central(new TileWidget(traceModel, window))
|
||||
{
|
||||
averages = 1;
|
||||
@ -422,6 +421,10 @@ using namespace std;
|
||||
|
||||
void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
|
||||
{
|
||||
if(Mode::getActiveMode() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(d.pointNum >= settings.pointNum) {
|
||||
qWarning() << "Ignoring point with too large point number (" << d.pointNum << ")";
|
||||
return;
|
||||
@ -555,14 +558,14 @@ void SpectrumAnalyzer::SetStopFreq(double freq)
|
||||
void SpectrumAnalyzer::SetCenterFreq(double freq)
|
||||
{
|
||||
auto old_span = settings.f_stop - settings.f_start;
|
||||
if (freq - old_span / 2 <= Device::Info().limits_minFreq) {
|
||||
if (freq - old_span / 2 <= Device::Info(window->getDevice()).limits_minFreq) {
|
||||
// would shift start frequency below minimum
|
||||
settings.f_start = 0;
|
||||
settings.f_stop = 2 * freq;
|
||||
} else if(freq + old_span / 2 >= Device::Info().limits_maxFreq) {
|
||||
} else if(freq + old_span / 2 >= Device::Info(window->getDevice()).limits_maxFreq) {
|
||||
// would shift stop frequency above maximum
|
||||
settings.f_start = 2 * freq - Device::Info().limits_maxFreq;
|
||||
settings.f_stop = Device::Info().limits_maxFreq;
|
||||
settings.f_start = 2 * freq - Device::Info(window->getDevice()).limits_maxFreq;
|
||||
settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
} else {
|
||||
settings.f_start = freq - old_span / 2;
|
||||
settings.f_stop = freq + old_span / 2;
|
||||
@ -573,14 +576,14 @@ void SpectrumAnalyzer::SetCenterFreq(double freq)
|
||||
void SpectrumAnalyzer::SetSpan(double span)
|
||||
{
|
||||
auto old_center = (settings.f_start + settings.f_stop) / 2;
|
||||
if(old_center < Device::Info().limits_minFreq + span / 2) {
|
||||
if(old_center < Device::Info(window->getDevice()).limits_minFreq + span / 2) {
|
||||
// would shift start frequency below minimum
|
||||
settings.f_start = Device::Info().limits_minFreq;
|
||||
settings.f_stop = Device::Info().limits_minFreq + span;
|
||||
} else if(old_center > Device::Info().limits_maxFreq - span / 2) {
|
||||
settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
settings.f_stop = Device::Info(window->getDevice()).limits_minFreq + span;
|
||||
} else if(old_center > Device::Info(window->getDevice()).limits_maxFreq - span / 2) {
|
||||
// would shift stop frequency above maximum
|
||||
settings.f_start = Device::Info().limits_maxFreq - span;
|
||||
settings.f_stop = Device::Info().limits_maxFreq;
|
||||
settings.f_start = Device::Info(window->getDevice()).limits_maxFreq - span;
|
||||
settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
} else {
|
||||
settings.f_start = old_center - span / 2;
|
||||
settings.f_stop = settings.f_start + span;
|
||||
@ -590,8 +593,8 @@ void SpectrumAnalyzer::SetSpan(double span)
|
||||
|
||||
void SpectrumAnalyzer::SetFullSpan()
|
||||
{
|
||||
settings.f_start = Device::Info().limits_minFreq;
|
||||
settings.f_stop = Device::Info().limits_maxFreq;
|
||||
settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
@ -619,10 +622,10 @@ void SpectrumAnalyzer::SpanZoomOut()
|
||||
|
||||
void SpectrumAnalyzer::SetRBW(double bandwidth)
|
||||
{
|
||||
if(bandwidth > Device::Info().limits_maxRBW) {
|
||||
bandwidth = Device::Info().limits_maxRBW;
|
||||
} else if(bandwidth < Device::Info().limits_minRBW) {
|
||||
bandwidth = Device::Info().limits_minRBW;
|
||||
if(bandwidth > Device::Info(window->getDevice()).limits_maxRBW) {
|
||||
bandwidth = Device::Info(window->getDevice()).limits_maxRBW;
|
||||
} else if(bandwidth < Device::Info(window->getDevice()).limits_minRBW) {
|
||||
bandwidth = Device::Info(window->getDevice()).limits_minRBW;
|
||||
}
|
||||
settings.RBW = bandwidth;
|
||||
emit RBWChanged(settings.RBW);
|
||||
@ -690,10 +693,10 @@ void SpectrumAnalyzer::SetTGPort(int port)
|
||||
|
||||
void SpectrumAnalyzer::SetTGLevel(double level)
|
||||
{
|
||||
if(level > Device::Info().limits_cdbm_max / 100.0) {
|
||||
level = Device::Info().limits_cdbm_max / 100.0;
|
||||
} else if(level < Device::Info().limits_cdbm_min / 100.0) {
|
||||
level = Device::Info().limits_cdbm_min / 100.0;
|
||||
if(level > Device::Info(window->getDevice()).limits_cdbm_max / 100.0) {
|
||||
level = Device::Info(window->getDevice()).limits_cdbm_max / 100.0;
|
||||
} else if(level < Device::Info(window->getDevice()).limits_cdbm_min / 100.0) {
|
||||
level = Device::Info(window->getDevice()).limits_cdbm_min / 100.0;
|
||||
}
|
||||
emit TGLevelChanged(level);
|
||||
settings.trackingPower = level * 100;
|
||||
@ -1015,24 +1018,24 @@ void SpectrumAnalyzer::UpdateAverageCount()
|
||||
|
||||
void SpectrumAnalyzer::ConstrainAndUpdateFrequencies()
|
||||
{
|
||||
if(settings.f_stop > Device::Info().limits_maxFreq) {
|
||||
settings.f_stop = Device::Info().limits_maxFreq;
|
||||
if(settings.f_stop > Device::Info(window->getDevice()).limits_maxFreq) {
|
||||
settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
}
|
||||
if(settings.f_start > settings.f_stop) {
|
||||
settings.f_start = settings.f_stop;
|
||||
}
|
||||
if(settings.f_start < Device::Info().limits_minFreq) {
|
||||
settings.f_start = Device::Info().limits_minFreq;
|
||||
if(settings.f_start < Device::Info(window->getDevice()).limits_minFreq) {
|
||||
settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
}
|
||||
|
||||
bool trackingOffset_limited = false;
|
||||
if(settings.f_stop + settings.trackingGeneratorOffset > Device::Info().limits_maxFreq) {
|
||||
if(settings.f_stop + settings.trackingGeneratorOffset > Device::Info(window->getDevice()).limits_maxFreq) {
|
||||
trackingOffset_limited = true;
|
||||
settings.trackingGeneratorOffset = Device::Info().limits_maxFreq - settings.f_stop;
|
||||
settings.trackingGeneratorOffset = Device::Info(window->getDevice()).limits_maxFreq - settings.f_stop;
|
||||
}
|
||||
if((long) settings.f_start + settings.trackingGeneratorOffset < (long) Device::Info().limits_minFreq) {
|
||||
if((long) settings.f_start + settings.trackingGeneratorOffset < (long) Device::Info(window->getDevice()).limits_minFreq) {
|
||||
trackingOffset_limited = true;
|
||||
settings.trackingGeneratorOffset = Device::Info().limits_minFreq - settings.f_start;
|
||||
settings.trackingGeneratorOffset = Device::Info(window->getDevice()).limits_minFreq - settings.f_start;
|
||||
}
|
||||
if(trackingOffset_limited) {
|
||||
InformationBox::ShowMessage("Warning", "The selected tracking generator offset is not reachable for all frequencies with the current span. "
|
||||
|
@ -12,15 +12,17 @@
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
class SpectrumAnalyzer : public Mode, public SCPINode
|
||||
class SpectrumAnalyzer : public Mode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpectrumAnalyzer(AppWindow *window);
|
||||
SpectrumAnalyzer(AppWindow *window, QString name = "Spectrum Analyzer");
|
||||
|
||||
void deactivate() override;
|
||||
void initializeDevice() override;
|
||||
|
||||
virtual Type getType() override { return Type::SA;}
|
||||
|
||||
// Only save/load user changeable stuff, no need to save the widgets/mode name etc.
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
@ -51,9 +51,8 @@
|
||||
#include <QErrorMessage>
|
||||
#include <QDebug>
|
||||
|
||||
VNA::VNA(AppWindow *window)
|
||||
: Mode(window, "Vector Network Analyzer"),
|
||||
SCPINode("VNA"),
|
||||
VNA::VNA(AppWindow *window, QString name)
|
||||
: Mode(window, name, "VNA"),
|
||||
deembedding(traceModel),
|
||||
deembedding_active(false),
|
||||
central(new TileWidget(traceModel))
|
||||
@ -790,6 +789,11 @@ using namespace std;
|
||||
|
||||
void VNA::NewDatapoint(Protocol::Datapoint d)
|
||||
{
|
||||
if(Mode::getActiveMode() != this) {
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
|
||||
if(changingSettings) {
|
||||
// already setting new sweep settings, ignore incoming points from old settings
|
||||
return;
|
||||
@ -997,14 +1001,14 @@ void VNA::SetStopFreq(double freq)
|
||||
void VNA::SetCenterFreq(double freq)
|
||||
{
|
||||
auto old_span = settings.Freq.stop - settings.Freq.start;
|
||||
if (freq - old_span / 2 <= Device::Info().limits_minFreq) {
|
||||
if (freq - old_span / 2 <= Device::Info(window->getDevice()).limits_minFreq) {
|
||||
// would shift start frequency below minimum
|
||||
settings.Freq.start = 0;
|
||||
settings.Freq.stop = 2 * freq;
|
||||
} else if(freq + old_span / 2 >= Device::Info().limits_maxFreq) {
|
||||
} else if(freq + old_span / 2 >= Device::Info(window->getDevice()).limits_maxFreq) {
|
||||
// would shift stop frequency above maximum
|
||||
settings.Freq.start = 2 * freq - Device::Info().limits_maxFreq;
|
||||
settings.Freq.stop = Device::Info().limits_maxFreq;
|
||||
settings.Freq.start = 2 * freq - Device::Info(window->getDevice()).limits_maxFreq;
|
||||
settings.Freq.stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
} else {
|
||||
settings.Freq.start = freq - old_span / 2;
|
||||
settings.Freq.stop = freq + old_span / 2;
|
||||
@ -1014,12 +1018,12 @@ void VNA::SetCenterFreq(double freq)
|
||||
|
||||
void VNA::SetSpan(double span)
|
||||
{
|
||||
auto maxFreq = Preferences::getInstance().Acquisition.harmonicMixing ? Device::Info().limits_maxFreqHarmonic : Device::Info().limits_maxFreq;
|
||||
auto maxFreq = Preferences::getInstance().Acquisition.harmonicMixing ? Device::Info(window->getDevice()).limits_maxFreqHarmonic : Device::Info(window->getDevice()).limits_maxFreq;
|
||||
auto old_center = (settings.Freq.start + settings.Freq.stop) / 2;
|
||||
if(old_center < Device::Info().limits_minFreq + span / 2) {
|
||||
if(old_center < Device::Info(window->getDevice()).limits_minFreq + span / 2) {
|
||||
// would shift start frequency below minimum
|
||||
settings.Freq.start = Device::Info().limits_minFreq;
|
||||
settings.Freq.stop = Device::Info().limits_minFreq + span;
|
||||
settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
settings.Freq.stop = Device::Info(window->getDevice()).limits_minFreq + span;
|
||||
} else if(old_center > maxFreq - span / 2) {
|
||||
// would shift stop frequency above maximum
|
||||
settings.Freq.start = maxFreq - span;
|
||||
@ -1033,8 +1037,8 @@ void VNA::SetSpan(double span)
|
||||
|
||||
void VNA::SetFullSpan()
|
||||
{
|
||||
settings.Freq.start = Device::Info().limits_minFreq;
|
||||
settings.Freq.stop = Device::Info().limits_maxFreq;
|
||||
settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
settings.Freq.stop = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
}
|
||||
|
||||
@ -1072,10 +1076,10 @@ void VNA::SetLogSweep(bool log)
|
||||
|
||||
void VNA::SetSourceLevel(double level)
|
||||
{
|
||||
if(level > Device::Info().limits_cdbm_max / 100.0) {
|
||||
level = Device::Info().limits_cdbm_max / 100.0;
|
||||
} else if(level < Device::Info().limits_cdbm_min / 100.0) {
|
||||
level = Device::Info().limits_cdbm_min / 100.0;
|
||||
if(level > Device::Info(window->getDevice()).limits_cdbm_max / 100.0) {
|
||||
level = Device::Info(window->getDevice()).limits_cdbm_max / 100.0;
|
||||
} else if(level < Device::Info(window->getDevice()).limits_cdbm_min / 100.0) {
|
||||
level = Device::Info(window->getDevice()).limits_cdbm_min / 100.0;
|
||||
}
|
||||
emit sourceLevelChanged(level);
|
||||
settings.Freq.excitation_power = level;
|
||||
@ -1105,15 +1109,15 @@ void VNA::SetPowerSweepFrequency(double freq)
|
||||
|
||||
void VNA::SetPoints(unsigned int points)
|
||||
{
|
||||
unsigned int maxPoints = Preferences::getInstance().Acquisition.allowSegmentedSweep ? UINT16_MAX : Device::Info().limits_maxPoints;
|
||||
unsigned int maxPoints = Preferences::getInstance().Acquisition.allowSegmentedSweep ? UINT16_MAX : Device::Info(window->getDevice()).limits_maxPoints;
|
||||
if(points > maxPoints) {
|
||||
points = maxPoints;
|
||||
} else if (points < 2) {
|
||||
points = 2;
|
||||
}
|
||||
if (points > Device::Info().limits_maxPoints) {
|
||||
if (points > Device::Info(window->getDevice()).limits_maxPoints) {
|
||||
// needs segmented sweep
|
||||
settings.segments = ceil((double) points / Device::Info().limits_maxPoints);
|
||||
settings.segments = ceil((double) points / Device::Info(window->getDevice()).limits_maxPoints);
|
||||
settings.activeSegment = 0;
|
||||
} else {
|
||||
// can fit all points into one segment
|
||||
@ -1127,10 +1131,10 @@ void VNA::SetPoints(unsigned int points)
|
||||
|
||||
void VNA::SetIFBandwidth(double bandwidth)
|
||||
{
|
||||
if(bandwidth > Device::Info().limits_maxIFBW) {
|
||||
bandwidth = Device::Info().limits_maxIFBW;
|
||||
} else if(bandwidth < Device::Info().limits_minIFBW) {
|
||||
bandwidth = Device::Info().limits_minIFBW;
|
||||
if(bandwidth > Device::Info(window->getDevice()).limits_maxIFBW) {
|
||||
bandwidth = Device::Info(window->getDevice()).limits_maxIFBW;
|
||||
} else if(bandwidth < Device::Info(window->getDevice()).limits_minIFBW) {
|
||||
bandwidth = Device::Info(window->getDevice()).limits_minIFBW;
|
||||
}
|
||||
settings.bandwidth = bandwidth;
|
||||
emit IFBandwidthChanged(settings.bandwidth);
|
||||
@ -1478,9 +1482,9 @@ void VNA::ConstrainAndUpdateFrequencies()
|
||||
auto pref = Preferences::getInstance();
|
||||
double maxFreq;
|
||||
if(pref.Acquisition.harmonicMixing) {
|
||||
maxFreq = Device::Info().limits_maxFreqHarmonic;
|
||||
maxFreq = Device::Info(window->getDevice()).limits_maxFreqHarmonic;
|
||||
} else {
|
||||
maxFreq = Device::Info().limits_maxFreq;
|
||||
maxFreq = Device::Info(window->getDevice()).limits_maxFreq;
|
||||
}
|
||||
if(settings.Freq.stop > maxFreq) {
|
||||
settings.Freq.stop = maxFreq;
|
||||
@ -1488,8 +1492,8 @@ void VNA::ConstrainAndUpdateFrequencies()
|
||||
if(settings.Freq.start > settings.Freq.stop) {
|
||||
settings.Freq.start = settings.Freq.stop;
|
||||
}
|
||||
if(settings.Freq.start < Device::Info().limits_minFreq) {
|
||||
settings.Freq.start = Device::Info().limits_minFreq;
|
||||
if(settings.Freq.start < Device::Info(window->getDevice()).limits_minFreq) {
|
||||
settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
|
||||
}
|
||||
emit startFreqChanged(settings.Freq.start);
|
||||
emit stopFreqChanged(settings.Freq.stop);
|
||||
|
@ -13,17 +13,19 @@
|
||||
#include <QWidget>
|
||||
#include <functional>
|
||||
|
||||
class VNA : public Mode, public SCPINode
|
||||
class VNA : public Mode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VNA(AppWindow *window);
|
||||
VNA(AppWindow *window, QString name = "Vector Network Analyzer");
|
||||
|
||||
void deactivate() override;
|
||||
void initializeDevice() override;
|
||||
void deviceDisconnected() override;
|
||||
void shutdown() override;
|
||||
|
||||
virtual Type getType() override { return Type::VNA;}
|
||||
|
||||
// Only save/load user changeable stuff, no need to save the widgets/mode name etc.
|
||||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
@ -134,9 +134,9 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
// Create GUI modes
|
||||
central = new QStackedWidget;
|
||||
setCentralWidget(central);
|
||||
vna = new VNA(this);
|
||||
generator = new Generator(this);
|
||||
spectrumAnalyzer = new SpectrumAnalyzer(this);
|
||||
auto vna = new VNA(this);
|
||||
auto generator = new Generator(this);
|
||||
auto spectrumAnalyzer = new SpectrumAnalyzer(this);
|
||||
|
||||
// UI connections
|
||||
connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList);
|
||||
@ -235,7 +235,7 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
vna->activate();
|
||||
|
||||
qRegisterMetaType<Protocol::Datapoint>("Datapoint");
|
||||
qRegisterMetaType<Protocol::ManualStatus>("Manual");
|
||||
qRegisterMetaType<Protocol::ManualStatusV1>("ManualV1");
|
||||
qRegisterMetaType<Protocol::SpectrumAnalyzerResult>("SpectrumAnalyzerResult");
|
||||
qRegisterMetaType<Protocol::AmplitudeCorrectionPoint>("AmplitudeCorrection");
|
||||
|
||||
@ -278,9 +278,9 @@ void AppWindow::closeEvent(QCloseEvent *event)
|
||||
if(pref.Startup.UseSetupFile && pref.Startup.AutosaveSetupFile) {
|
||||
SaveSetup(pref.Startup.SetupFile);
|
||||
}
|
||||
vna->shutdown();
|
||||
generator->shutdown();
|
||||
spectrumAnalyzer->shutdown();
|
||||
for(auto m : Mode::getModes()) {
|
||||
m->shutdown();
|
||||
}
|
||||
delete device;
|
||||
QSettings settings;
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
@ -309,7 +309,7 @@ bool AppWindow::ConnectToDevice(QString serial)
|
||||
UpdateStatusBar(AppWindow::DeviceStatusBar::Connected);
|
||||
connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine);
|
||||
connect(device, &Device::ConnectionLost, this, &AppWindow::DeviceConnectionLost);
|
||||
connect(device, &Device::DeviceInfoUpdated, this, &AppWindow::DeviceInfoUpdated);
|
||||
connect(device, &Device::DeviceStatusUpdated, this, &AppWindow::DeviceStatusUpdated);
|
||||
connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate);
|
||||
ui->actionDisconnect->setEnabled(true);
|
||||
ui->actionManual_Control->setEnabled(true);
|
||||
@ -465,7 +465,7 @@ void AppWindow::SetupSCPI()
|
||||
}
|
||||
return "";
|
||||
}, [=](QStringList) -> QString {
|
||||
switch(Device::Info().extRefInUse) {
|
||||
switch(Device::StatusV1(getDevice()).extRefInUse) {
|
||||
case 0: return "INT";
|
||||
case 1: return "EXT";
|
||||
default: return "ERROR";
|
||||
@ -475,88 +475,89 @@ void AppWindow::SetupSCPI()
|
||||
if (params.size() != 1) {
|
||||
return "ERROR";
|
||||
}
|
||||
Mode *mode = nullptr;
|
||||
if (params[0] == "VNA") {
|
||||
vna->activate();
|
||||
mode = Mode::findFirstOfType(Mode::Type::VNA);
|
||||
} else if(params[0] == "GEN") {
|
||||
generator->activate();
|
||||
mode = Mode::findFirstOfType(Mode::Type::SG);
|
||||
} else if(params[0] == "SA") {
|
||||
spectrumAnalyzer->activate();
|
||||
mode = Mode::findFirstOfType(Mode::Type::SA);
|
||||
} else {
|
||||
return "INVALID MDOE";
|
||||
}
|
||||
return "";
|
||||
}, [=](QStringList) -> QString {
|
||||
auto active = Mode::getActiveMode();
|
||||
if(active == vna) {
|
||||
return "VNA";
|
||||
} else if(active == generator) {
|
||||
return "GEN";
|
||||
} else if(active == spectrumAnalyzer) {
|
||||
return "SA";
|
||||
if(mode) {
|
||||
mode->activate();
|
||||
return "";
|
||||
} else {
|
||||
return "ERROR";
|
||||
}
|
||||
}, [=](QStringList) -> QString {
|
||||
auto active = Mode::getActiveMode();
|
||||
if(active) {
|
||||
switch(active->getType()) {
|
||||
case Mode::Type::VNA: return "VNA";
|
||||
case Mode::Type::SG: return "SG";
|
||||
case Mode::Type::SA: return "SA";
|
||||
}
|
||||
}
|
||||
return "ERROR";
|
||||
}));
|
||||
auto scpi_status = new SCPINode("STAtus");
|
||||
scpi_dev->add(scpi_status);
|
||||
scpi_status->add(new SCPICommand("UNLOcked", nullptr, [=](QStringList){
|
||||
bool locked = Device::Info().source_locked && Device::Info().LO1_locked;
|
||||
bool locked = Device::StatusV1(getDevice()).source_locked && Device::StatusV1(getDevice()).LO1_locked;
|
||||
return locked ? "FALSE" : "TRUE";
|
||||
}));
|
||||
scpi_status->add(new SCPICommand("ADCOVERload", nullptr, [=](QStringList){
|
||||
return Device::Info().ADC_overload ? "TRUE" : "FALSE";
|
||||
return Device::StatusV1(getDevice()).ADC_overload ? "TRUE" : "FALSE";
|
||||
}));
|
||||
scpi_status->add(new SCPICommand("UNLEVel", nullptr, [=](QStringList){
|
||||
return Device::Info().unlevel ? "TRUE" : "FALSE";
|
||||
return Device::StatusV1(getDevice()).unlevel ? "TRUE" : "FALSE";
|
||||
}));
|
||||
auto scpi_info = new SCPINode("INFo");
|
||||
scpi_dev->add(scpi_info);
|
||||
scpi_info->add(new SCPICommand("FWREVision", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().FW_major)+"."+QString::number(Device::Info().FW_minor)+"."+QString::number(Device::Info().FW_patch);
|
||||
return QString::number(Device::Info(getDevice()).FW_major)+"."+QString::number(Device::Info(getDevice()).FW_minor)+"."+QString::number(Device::Info(getDevice()).FW_patch);
|
||||
}));
|
||||
scpi_info->add(new SCPICommand("HWREVision", nullptr, [=](QStringList){
|
||||
return QString(Device::Info().HW_Revision);
|
||||
return QString(Device::Info(getDevice()).HW_Revision);
|
||||
}));
|
||||
scpi_info->add(new SCPICommand("TEMPeratures", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().temp_source)+"/"+QString::number(Device::Info().temp_LO1)+"/"+QString::number(Device::Info().temp_MCU);
|
||||
return QString::number(Device::StatusV1(getDevice()).temp_source)+"/"+QString::number(Device::StatusV1(getDevice()).temp_LO1)+"/"+QString::number(Device::StatusV1(getDevice()).temp_MCU);
|
||||
}));
|
||||
auto scpi_limits = new SCPINode("LIMits");
|
||||
scpi_info->add(scpi_limits);
|
||||
scpi_limits->add(new SCPICommand("MINFrequency", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_minFreq);
|
||||
return QString::number(Device::Info(getDevice()).limits_minFreq);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXFrequency", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_maxFreq);
|
||||
return QString::number(Device::Info(getDevice()).limits_maxFreq);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MINIFBW", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_minIFBW);
|
||||
return QString::number(Device::Info(getDevice()).limits_minIFBW);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXIFBW", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_maxIFBW);
|
||||
return QString::number(Device::Info(getDevice()).limits_maxIFBW);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXPoints", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_maxPoints);
|
||||
return QString::number(Device::Info(getDevice()).limits_maxPoints);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MINPOWer", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_cdbm_min / 100.0);
|
||||
return QString::number(Device::Info(getDevice()).limits_cdbm_min / 100.0);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXPOWer", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_cdbm_max / 100.0);
|
||||
return QString::number(Device::Info(getDevice()).limits_cdbm_max / 100.0);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MINRBW", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_minRBW);
|
||||
return QString::number(Device::Info(getDevice()).limits_minRBW);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXRBW", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_maxRBW);
|
||||
return QString::number(Device::Info(getDevice()).limits_maxRBW);
|
||||
}));
|
||||
scpi_limits->add(new SCPICommand("MAXHARMonicfrequency", nullptr, [=](QStringList){
|
||||
return QString::number(Device::Info().limits_maxFreqHarmonic);
|
||||
return QString::number(Device::Info(getDevice()).limits_maxFreqHarmonic);
|
||||
}));
|
||||
|
||||
scpi.add(vna);
|
||||
scpi.add(generator);
|
||||
scpi.add(spectrumAnalyzer);
|
||||
|
||||
auto scpi_manual = new SCPINode("MANual");
|
||||
scpi_manual->add(new SCPICommand("STArt",[=](QStringList) -> QString {
|
||||
StartManualControl();
|
||||
@ -798,6 +799,11 @@ void AppWindow::StopTCPServer()
|
||||
server = nullptr;
|
||||
}
|
||||
|
||||
SCPI* AppWindow::getSCPI()
|
||||
{
|
||||
return &scpi;
|
||||
}
|
||||
|
||||
int AppWindow::UpdateDeviceList()
|
||||
{
|
||||
deviceActionGroup->setExclusive(true);
|
||||
@ -918,7 +924,7 @@ void AppWindow::DeviceNeedsUpdate(int reported, int expected)
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::DeviceInfoUpdated()
|
||||
void AppWindow::DeviceStatusUpdated()
|
||||
{
|
||||
UpdateStatusBar(DeviceStatusBar::Updated);
|
||||
}
|
||||
@ -963,10 +969,18 @@ void AppWindow::SaveSetup(QString filename)
|
||||
nlohmann::json AppWindow::SaveSetup()
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["activeMode"] = Mode::getActiveMode()->getName().toStdString();
|
||||
j["VNA"] = vna->toJSON();
|
||||
j["Generator"] = generator->toJSON();
|
||||
j["SpectrumAnalyzer"] = spectrumAnalyzer->toJSON();
|
||||
nlohmann::json jm;
|
||||
for(auto m : Mode::getModes()) {
|
||||
nlohmann::json jmode;
|
||||
jmode["type"] = Mode::TypeToName(m->getType()).toStdString();
|
||||
jmode["name"] = m->getName().toStdString();
|
||||
jmode["settings"] = m->toJSON();
|
||||
jm.push_back(jmode);
|
||||
}
|
||||
j["Modes"] = jm;
|
||||
if(Mode::getActiveMode()) {
|
||||
j["activeMode"] = Mode::getActiveMode()->getName().toStdString();
|
||||
}
|
||||
nlohmann::json ref;
|
||||
ref["Mode"] = toolbars.reference.type->currentText().toStdString();
|
||||
ref["Output"] = toolbars.reference.outFreq->currentText().toStdString();
|
||||
@ -1003,20 +1017,36 @@ void AppWindow::LoadSetup(nlohmann::json j)
|
||||
toolbars.reference.type->setCurrentText(QString::fromStdString(j["Reference"].value("Mode", "Int")));
|
||||
toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off")));
|
||||
}
|
||||
while(Mode::getModes().size() > 0) {
|
||||
delete Mode::getModes()[0];
|
||||
}
|
||||
|
||||
// old style VNA/Generator/Spectrum Analyzer settings
|
||||
if(j.contains("VNA")) {
|
||||
auto vna = new VNA(this);
|
||||
vna->fromJSON(j["VNA"]);
|
||||
}
|
||||
if(j.contains("Generator")) {
|
||||
auto generator = new Generator(this);
|
||||
generator->fromJSON(j["Generator"]);
|
||||
}
|
||||
if(j.contains("SpectrumAnalyzer")) {
|
||||
auto spectrumAnalyzer = new SpectrumAnalyzer(this);
|
||||
spectrumAnalyzer->fromJSON(j["SpectrumAnalyzer"]);
|
||||
}
|
||||
if(j.contains("Modes")) {
|
||||
for(auto jm : j["Modes"]) {
|
||||
auto type = Mode::TypeFromName(QString::fromStdString(jm.value("type", "Invalid")));
|
||||
if(type != Mode::Type::Last && jm.contains("settings")) {
|
||||
auto m = Mode::createNew(this, QString::fromStdString(jm.value("name", "")), type);
|
||||
m->fromJSON(jm["settings"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// activate the correct mode
|
||||
QString modeName = QString::fromStdString(j.value("activeMode", ""));
|
||||
std::vector<Mode*> modes = {vna, generator, spectrumAnalyzer};
|
||||
for(auto m : modes) {
|
||||
for(auto m : Mode::getModes()) {
|
||||
if(m->getName() == modeName) {
|
||||
m->activate();
|
||||
break;
|
||||
@ -1024,7 +1054,7 @@ void AppWindow::LoadSetup(nlohmann::json j)
|
||||
}
|
||||
}
|
||||
|
||||
Device *AppWindow::getDevice() const
|
||||
Device *&AppWindow::getDevice()
|
||||
{
|
||||
return device;
|
||||
}
|
||||
@ -1104,14 +1134,12 @@ void AppWindow::UpdateStatusBar(DeviceStatusBar status)
|
||||
break;
|
||||
case DeviceStatusBar::Updated:
|
||||
lDeviceInfo.setText(device->getLastDeviceInfoString());
|
||||
lADCOverload.setVisible(device->Info().ADC_overload);
|
||||
lUnlevel.setVisible(device->Info().unlevel);
|
||||
lUnlock.setVisible(!device->Info().LO1_locked || !device->Info().source_locked);
|
||||
lADCOverload.setVisible(device->StatusV1().ADC_overload);
|
||||
lUnlevel.setVisible(device->StatusV1().unlevel);
|
||||
lUnlock.setVisible(!device->StatusV1().LO1_locked || !device->StatusV1().source_locked);
|
||||
break;
|
||||
default:
|
||||
// invalid status
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -41,13 +41,15 @@ public:
|
||||
|
||||
Ui::MainWindow *getUi() const;
|
||||
QStackedWidget *getCentral() const;
|
||||
Device *getDevice() const;
|
||||
Device*&getDevice();
|
||||
|
||||
const QString& getAppVersion() const;
|
||||
const QString& getAppGitHash() const;
|
||||
|
||||
static bool showGUI();
|
||||
|
||||
SCPI* getSCPI();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
private slots:
|
||||
@ -59,7 +61,7 @@ private slots:
|
||||
void UpdateAcquisitionFrequencies();
|
||||
void StartFirmwareUpdateDialog();
|
||||
void DeviceNeedsUpdate(int reported, int expected);
|
||||
void DeviceInfoUpdated();
|
||||
void DeviceStatusUpdated();
|
||||
void SourceCalibrationDialog();
|
||||
void ReceiverCalibrationDialog();
|
||||
void FrequencyCalibrationDialog();
|
||||
@ -100,11 +102,6 @@ private:
|
||||
|
||||
ManualControlDialog *manual;
|
||||
|
||||
// Modes
|
||||
VNA *vna;
|
||||
Generator *generator;
|
||||
SpectrumAnalyzer *spectrumAnalyzer;
|
||||
|
||||
// Status bar widgets
|
||||
QLabel lConnectionStatus;
|
||||
QLabel lDeviceInfo;
|
||||
|
@ -1,44 +1,115 @@
|
||||
#include "mode.h"
|
||||
|
||||
#include "Generator/generator.h"
|
||||
#include "VNA/vna.h"
|
||||
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
|
||||
#include "ui_main.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
|
||||
std::vector<Mode*> Mode::modes;
|
||||
Mode* Mode::activeMode = nullptr;
|
||||
QTabBar* Mode::tabbar = nullptr;
|
||||
QWidget* Mode::cornerWidget = nullptr;
|
||||
QButtonGroup* Mode::modeButtonGroup = nullptr;
|
||||
//QButtonGroup* Mode::modeButtonGroup = nullptr;
|
||||
|
||||
Mode::Mode(AppWindow *window, QString name)
|
||||
Mode::Mode(AppWindow *window, QString name, QString SCPIname)
|
||||
: QObject(window),
|
||||
SCPINode(SCPIname),
|
||||
window(window),
|
||||
name(name),
|
||||
central(nullptr)
|
||||
{
|
||||
{
|
||||
if(!nameAllowed(name)) {
|
||||
throw std::runtime_error("Unable to create mode, name already taken");
|
||||
}
|
||||
// Create mode switch button
|
||||
auto modeSwitch = new QPushButton(name);
|
||||
modeSwitch->setCheckable(true);
|
||||
modeSwitch->setMaximumHeight(window->menuBar()->height());
|
||||
if(!cornerWidget) {
|
||||
// this is the first created mode, initialize corner widget and set this mode as active
|
||||
modeSwitch->setChecked(true);
|
||||
cornerWidget = new QWidget;
|
||||
cornerWidget = new QWidget();
|
||||
cornerWidget->setLayout(new QHBoxLayout);
|
||||
cornerWidget->layout()->setSpacing(0);
|
||||
cornerWidget->layout()->setMargin(0);
|
||||
cornerWidget->layout()->setContentsMargins(0,0,0,0);
|
||||
window->menuBar()->setCornerWidget(cornerWidget);
|
||||
modeButtonGroup = new QButtonGroup;
|
||||
// window->menuBar()->setMaximumHeight(window->menuBar()->height());
|
||||
}
|
||||
cornerWidget->layout()->addWidget(modeSwitch);
|
||||
modeButtonGroup->addButton(modeSwitch);
|
||||
cornerWidget->setMaximumHeight(window->menuBar()->height());
|
||||
|
||||
connect(modeSwitch, &QPushButton::clicked, [=](){
|
||||
activate();
|
||||
});
|
||||
tabbar = new QTabBar;
|
||||
tabbar->setTabsClosable(true);
|
||||
tabbar->setStyleSheet("QTabBar::tab { height: "+QString::number(window->menuBar()->height())+"px;}");
|
||||
cornerWidget->layout()->addWidget(tabbar);
|
||||
|
||||
auto bAdd = new QPushButton();
|
||||
QIcon icon;
|
||||
QString iconThemeName = QString::fromUtf8("list-add");
|
||||
if (QIcon::hasThemeIcon(iconThemeName)) {
|
||||
icon = QIcon::fromTheme(iconThemeName);
|
||||
} else {
|
||||
icon.addFile(QString::fromUtf8(":/icons/add.png"), QSize(), QIcon::Normal, QIcon::Off);
|
||||
}
|
||||
bAdd->setIcon(icon);
|
||||
|
||||
auto mAdd = new QMenu();
|
||||
for(unsigned int i=0;i<(int) Type::Last;i++) {
|
||||
auto type = (Type) i;
|
||||
auto action = new QAction(TypeToName(type));
|
||||
mAdd->addAction(action);
|
||||
connect(action, &QAction::triggered, [=](){
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(window, "Create new "+TypeToName(type)+" tab",
|
||||
"Name:", QLineEdit::Normal,
|
||||
TypeToName(type), &ok);
|
||||
if(ok) {
|
||||
if(!nameAllowed(text)) {
|
||||
InformationBox::ShowError("Name collision", "Unable to create tab, no duplicate names allowed");
|
||||
} else {
|
||||
auto mode = Mode::createNew(window, text, type);
|
||||
mode->activate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
bAdd->setMenu(mAdd);
|
||||
bAdd->setMaximumHeight(window->menuBar()->height());
|
||||
bAdd->setMaximumWidth(40);
|
||||
cornerWidget->layout()->addWidget(bAdd);
|
||||
|
||||
window->menuBar()->setCornerWidget(cornerWidget);
|
||||
|
||||
connect(tabbar, &QTabBar::currentChanged, [=](int index){
|
||||
modes[index]->activate();
|
||||
});
|
||||
connect(tabbar, &QTabBar::tabCloseRequested, [=](int index){
|
||||
delete modes[index];
|
||||
});
|
||||
}
|
||||
modes.push_back(this);
|
||||
tabbar->blockSignals(true);
|
||||
tabbar->insertTab(tabbar->count(), name);
|
||||
tabbar->blockSignals(false);
|
||||
window->getSCPI()->add(this);
|
||||
}
|
||||
|
||||
Mode::~Mode()
|
||||
{
|
||||
window->getSCPI()->remove(this);
|
||||
if(activeMode == this) {
|
||||
deactivate();
|
||||
}
|
||||
auto index = findTabIndex();
|
||||
tabbar->blockSignals(true);
|
||||
tabbar->removeTab(index);
|
||||
tabbar->blockSignals(false);
|
||||
modes.erase(modes.begin() + index);
|
||||
if(modes.size() > 0) {
|
||||
modes[tabbar->currentIndex()]->activate();
|
||||
}
|
||||
window->getCentral()->removeWidget(central);
|
||||
}
|
||||
|
||||
void Mode::activate()
|
||||
@ -89,14 +160,10 @@ void Mode::activate()
|
||||
}
|
||||
|
||||
activeMode = this;
|
||||
// force activation of correct pushbutton in case the mode switch was done via script/setup load.
|
||||
// This will trigger a second activation of this mode in the signal of the button, but since it is
|
||||
// force activation of correct tab in case the mode switch was done via script/setup load.
|
||||
// This will trigger a second activation of this mode in the signal of the tab bar, but since it is
|
||||
// already the active mode, this function will just return -> no recursion
|
||||
for(auto b : modeButtonGroup->buttons()) {
|
||||
if(b->text() == name) {
|
||||
b->click();
|
||||
}
|
||||
}
|
||||
tabbar->setCurrentIndex(findTabIndex());
|
||||
|
||||
if(window->getDevice()) {
|
||||
initializeDevice();
|
||||
@ -131,6 +198,9 @@ void Mode::deactivate()
|
||||
}
|
||||
|
||||
qDebug() << "Deactivated mode" << name;
|
||||
if(window->getDevice()) {
|
||||
window->getDevice()->SetIdle();
|
||||
}
|
||||
activeMode = nullptr;
|
||||
}
|
||||
|
||||
@ -139,6 +209,26 @@ Mode *Mode::getActiveMode()
|
||||
return activeMode;
|
||||
}
|
||||
|
||||
QString Mode::TypeToName(Mode::Type t)
|
||||
{
|
||||
switch(t) {
|
||||
case Type::VNA: return "Vector Network Analyzer";
|
||||
case Type::SG: return "Signal Generator";
|
||||
case Type::SA: return "Spectrum Analyzer";
|
||||
default: return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
Mode::Type Mode::TypeFromName(QString s)
|
||||
{
|
||||
for(unsigned int i=0;i<(int)Type::Last;i++) {
|
||||
if(s == TypeToName((Type) i)) {
|
||||
return (Type) i;
|
||||
}
|
||||
}
|
||||
return Type::Last;
|
||||
}
|
||||
|
||||
void Mode::saveSreenshot()
|
||||
{
|
||||
auto filename = QFileDialog::getSaveFileName(nullptr, "Save plot image", "", "PNG image files (*.png)", nullptr, QFileDialog::DontUseNativeDialog);
|
||||
@ -153,6 +243,27 @@ void Mode::saveSreenshot()
|
||||
central->grab().save(filename);
|
||||
}
|
||||
|
||||
Mode *Mode::createNew(AppWindow *window, QString name, Mode::Type t)
|
||||
{
|
||||
switch(t) {
|
||||
case Type::VNA: return new VNA(window, name);
|
||||
case Type::SG: return new Generator(window, name);
|
||||
case Type::SA: return new SpectrumAnalyzer(window, name);
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Mode::nameAllowed(QString name)
|
||||
{
|
||||
for(auto m : modes) {
|
||||
if(m->getName() == name) {
|
||||
// name already taken, no duplicates allowed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mode::finalize(QWidget *centralWidget)
|
||||
{
|
||||
central = centralWidget;
|
||||
@ -176,6 +287,27 @@ void Mode::finalize(QWidget *centralWidget)
|
||||
}
|
||||
}
|
||||
|
||||
int Mode::findTabIndex()
|
||||
{
|
||||
auto it = std::find(modes.begin(), modes.end(), this);
|
||||
return it - modes.begin();
|
||||
}
|
||||
|
||||
std::vector<Mode *> Mode::getModes()
|
||||
{
|
||||
return modes;
|
||||
}
|
||||
|
||||
Mode *Mode::findFirstOfType(Mode::Type t)
|
||||
{
|
||||
for(auto m : modes) {
|
||||
if(m->getType() == t) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Mode::setStatusbarMessage(QString msg)
|
||||
{
|
||||
statusbarMsg = msg;
|
||||
@ -188,3 +320,14 @@ QString Mode::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void Mode::setName(const QString &value)
|
||||
{
|
||||
if(!nameAllowed(value)) {
|
||||
// unable to use this name
|
||||
return;
|
||||
}
|
||||
name = value;
|
||||
tabbar->setTabText(findTabIndex(), name);
|
||||
}
|
||||
|
||||
|
@ -3,30 +3,50 @@
|
||||
|
||||
#include "appwindow.h"
|
||||
#include "savable.h"
|
||||
#include "scpi.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#include <QButtonGroup>
|
||||
#include <QToolBar>
|
||||
#include <QTabBar>
|
||||
#include <QDockWidget>
|
||||
#include <set>
|
||||
|
||||
class Mode : public QObject, public Savable
|
||||
class Mode : public QObject, public Savable, public SCPINode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Mode(AppWindow *window, QString name);
|
||||
enum class Type {
|
||||
VNA,
|
||||
SG,
|
||||
SA,
|
||||
Last,
|
||||
};
|
||||
|
||||
Mode(AppWindow *window, QString name, QString SCPIname);
|
||||
~Mode();
|
||||
|
||||
virtual void activate(); // derived classes must call Mode::activate before doing anything
|
||||
virtual void deactivate(); // derived classes must call Mode::deactivate before returning
|
||||
virtual void shutdown(){}; // called when the application is about to exit
|
||||
QString getName() const;
|
||||
void setName(const QString &value);
|
||||
static Mode *getActiveMode();
|
||||
static QString TypeToName(Type t);
|
||||
static Type TypeFromName(QString s);
|
||||
virtual Type getType() = 0;
|
||||
|
||||
virtual void initializeDevice() = 0;
|
||||
virtual void deviceDisconnected(){};
|
||||
|
||||
virtual void saveSreenshot();
|
||||
|
||||
static Mode *createNew(AppWindow *window, QString name, Type t);
|
||||
static bool nameAllowed(QString name);
|
||||
static std::vector<Mode *> getModes();
|
||||
static Mode* findFirstOfType(Type t);
|
||||
|
||||
signals:
|
||||
void statusbarMessage(QString msg);
|
||||
protected:
|
||||
@ -39,10 +59,13 @@ protected:
|
||||
std::set<QDockWidget*> docks;
|
||||
|
||||
private:
|
||||
int findTabIndex();
|
||||
static std::vector<Mode*> modes;
|
||||
static Mode *activeMode;
|
||||
static QTabBar *tabbar;
|
||||
static QWidget *cornerWidget;
|
||||
static QButtonGroup *modeButtonGroup;
|
||||
const QString name;
|
||||
// static QButtonGroup *modeButtonGroup;
|
||||
QString name;
|
||||
QString statusbarMsg;
|
||||
QWidget *central;
|
||||
};
|
||||
|
@ -106,6 +106,17 @@ bool SCPINode::add(SCPINode *node)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SCPINode::remove(SCPINode *node)
|
||||
{
|
||||
auto it = std::find(subnodes.begin(), subnodes.end(), node);
|
||||
if(it != subnodes.end()) {
|
||||
subnodes.erase(it);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SCPINode::add(SCPICommand *cmd)
|
||||
{
|
||||
if(nameCollision(cmd->name())) {
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
name(name){}
|
||||
|
||||
bool add(SCPINode *node);
|
||||
bool remove(SCPINode *node);
|
||||
bool add(SCPICommand *cmd);
|
||||
|
||||
private:
|
||||
|
@ -6,7 +6,7 @@
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
|
||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-1671998965483228530" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1949595105660943601" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
@ -18,7 +18,7 @@
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
|
||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-1671998965483228530" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1949595105660943601" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
|
@ -117,7 +117,7 @@ inline void App_Process() {
|
||||
sweepActive = VNA::Setup(recv_packet.settings);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::ManualControl:
|
||||
case Protocol::PacketType::ManualControlV1:
|
||||
sweepActive = false;
|
||||
last_measure_packet = recv_packet;
|
||||
Manual::Setup(recv_packet.manual);
|
||||
@ -145,12 +145,21 @@ inline void App_Process() {
|
||||
SA::Setup(recv_packet.spectrumSettings);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::RequestDeviceInfo:
|
||||
case Protocol::PacketType::RequestDeviceInfo: {
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::DeviceInfo;
|
||||
HW::fillDeviceInfo(&p.info);
|
||||
p.info = HW::Info;
|
||||
Communication::Send(p);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::RequestDeviceStatus: {
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::DeviceStatusV1;
|
||||
HW::getDeviceStatus(&p.statusV1);
|
||||
Communication::Send(p);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::SetIdle:
|
||||
HW::SetMode(HW::Mode::Idle);
|
||||
|
@ -91,8 +91,9 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
||||
case PacketType::SweepSettings: payload_size = sizeof(packet.settings); break;
|
||||
case PacketType::Reference: payload_size = sizeof(packet.reference); break;
|
||||
case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break;
|
||||
case PacketType::Status: payload_size = sizeof(packet.status); break;
|
||||
case PacketType::ManualControl: payload_size = sizeof(packet.manual); break;
|
||||
case PacketType::DeviceStatusV1: payload_size = sizeof(packet.statusV1); break;
|
||||
case PacketType::ManualStatusV1: payload_size = sizeof(packet.manualStatusV1); break;
|
||||
case PacketType::ManualControlV1: payload_size = sizeof(packet.manual); break;
|
||||
case PacketType::FirmwarePacket: payload_size = sizeof(packet.firmware); break;
|
||||
case PacketType::Generator: payload_size = sizeof(packet.generator); break;
|
||||
case PacketType::SpectrumAnalyzerSettings: payload_size = sizeof(packet.spectrumSettings); break;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
static constexpr uint16_t Version = 9;
|
||||
static constexpr uint16_t Version = 10;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@ -50,17 +50,8 @@ using DeviceInfo = struct _deviceInfo {
|
||||
uint8_t FW_major;
|
||||
uint8_t FW_minor;
|
||||
uint8_t FW_patch;
|
||||
uint8_t hardware_version;
|
||||
char HW_Revision;
|
||||
uint8_t extRefAvailable:1;
|
||||
uint8_t extRefInUse:1;
|
||||
uint8_t FPGA_configured:1;
|
||||
uint8_t source_locked:1;
|
||||
uint8_t LO1_locked:1;
|
||||
uint8_t ADC_overload:1;
|
||||
uint8_t unlevel:1;
|
||||
uint8_t temp_source;
|
||||
uint8_t temp_LO1;
|
||||
uint8_t temp_MCU;
|
||||
uint64_t limits_minFreq;
|
||||
uint64_t limits_maxFreq;
|
||||
uint32_t limits_minIFBW;
|
||||
@ -74,7 +65,21 @@ using DeviceInfo = struct _deviceInfo {
|
||||
uint64_t limits_maxFreqHarmonic;
|
||||
};
|
||||
|
||||
using ManualStatus = struct _manualstatus {
|
||||
using DeviceStatusV1 = struct _deviceStatusV1 {
|
||||
uint8_t extRefAvailable:1;
|
||||
uint8_t extRefInUse:1;
|
||||
uint8_t FPGA_configured:1;
|
||||
uint8_t source_locked:1;
|
||||
uint8_t LO1_locked:1;
|
||||
uint8_t ADC_overload:1;
|
||||
uint8_t unlevel:1;
|
||||
uint8_t temp_source;
|
||||
uint8_t temp_LO1;
|
||||
uint8_t temp_MCU;
|
||||
};
|
||||
|
||||
|
||||
using ManualStatusV1 = struct _manualstatusV1 {
|
||||
int16_t port1min, port1max;
|
||||
int16_t port2min, port2max;
|
||||
int16_t refmin, refmax;
|
||||
@ -87,7 +92,7 @@ using ManualStatus = struct _manualstatus {
|
||||
uint8_t LO_locked :1;
|
||||
};
|
||||
|
||||
using ManualControl = struct _manualControl {
|
||||
using ManualControlV1 = struct _manualControlV1 {
|
||||
// Highband Source
|
||||
uint8_t SourceHighCE :1;
|
||||
uint8_t SourceHighRFEN :1;
|
||||
@ -170,8 +175,8 @@ enum class PacketType : uint8_t {
|
||||
None = 0,
|
||||
Datapoint = 1,
|
||||
SweepSettings = 2,
|
||||
Status = 3,
|
||||
ManualControl = 4,
|
||||
ManualStatusV1 = 3,
|
||||
ManualControlV1 = 4,
|
||||
DeviceInfo = 5,
|
||||
FirmwarePacket = 6,
|
||||
Ack = 7,
|
||||
@ -192,6 +197,8 @@ enum class PacketType : uint8_t {
|
||||
FrequencyCorrection = 22,
|
||||
RequestAcquisitionFrequencySettings = 23,
|
||||
AcquisitionFrequencySettings = 24,
|
||||
DeviceStatusV1 = 25,
|
||||
RequestDeviceStatus = 26,
|
||||
};
|
||||
|
||||
using PacketInfo = struct _packetinfo {
|
||||
@ -201,10 +208,11 @@ using PacketInfo = struct _packetinfo {
|
||||
SweepSettings settings;
|
||||
ReferenceSettings reference;
|
||||
GeneratorSettings generator;
|
||||
DeviceStatusV1 statusV1;
|
||||
DeviceInfo info;
|
||||
ManualControl manual;
|
||||
ManualControlV1 manual;
|
||||
FirmwarePacket firmware;
|
||||
ManualStatus status;
|
||||
ManualStatusV1 manualStatusV1;
|
||||
SpectrumAnalyzerSettings spectrumSettings;
|
||||
SpectrumAnalyzerResult spectrumResult;
|
||||
AmplitudeCorrectionPoint amplitudePoint;
|
||||
|
@ -130,6 +130,17 @@ 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 individual_halt) {
|
||||
uint16_t value = 0x0000;
|
||||
value |= (uint16_t) (stages & 0x07) << 13;
|
||||
if(individual_halt) {
|
||||
value |= 0x1000;
|
||||
}
|
||||
value |= (port1_stage & 0x07) << 3;
|
||||
value |= (port2_stage & 0x07) << 0;
|
||||
WriteRegister(Reg::SweepSetup, value);
|
||||
}
|
||||
|
||||
void FPGA::Enable(Periphery p, bool enable) {
|
||||
if (enable) {
|
||||
SysCtrlReg |= (uint16_t) p;
|
||||
@ -282,7 +293,7 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
result.RefI = assembleSampleResultValue(&raw[8]);
|
||||
result.RefQ = assembleSampleResultValue(&raw[2]);
|
||||
result.pointNum = (uint16_t)(raw[38]&0x1F) << 8 | raw[39];
|
||||
result.activePort = raw[38] & 0x80 ? 1 : 0;
|
||||
result.stageNum = (raw[38] & 0xE0) >> 5;
|
||||
High(CS);
|
||||
busy_reading = false;
|
||||
if ((status & 0x0004) && callback) {
|
||||
|
@ -17,6 +17,7 @@ enum class Reg {
|
||||
SystemControl = 0x03,
|
||||
ADCPrescaler = 0x04,
|
||||
PhaseIncrement = 0x05,
|
||||
SweepSetup = 0x06,
|
||||
MAX2871Def0LSB = 0x08,
|
||||
MAX2871Def0MSB = 0x09,
|
||||
MAX2871Def1LSB = 0x0A,
|
||||
@ -33,8 +34,8 @@ using SamplingResult = struct _samplingresult {
|
||||
int64_t P1I, P1Q;
|
||||
int64_t P2I, P2Q;
|
||||
int64_t RefI, RefQ;
|
||||
uint16_t pointNum :15;
|
||||
uint16_t activePort :1;
|
||||
uint16_t pointNum :13;
|
||||
uint16_t stageNum :3;
|
||||
};
|
||||
|
||||
using DFTResult = struct _dftresult {
|
||||
@ -59,8 +60,7 @@ enum class Periphery {
|
||||
DebugLED = 0x0080,
|
||||
SourceChip = 0x0010,
|
||||
LO1Chip = 0x0008,
|
||||
ExcitePort2 = 0x0004,
|
||||
ExcitePort1 = 0x0002,
|
||||
|
||||
PortSwitch = 0x0001,
|
||||
};
|
||||
|
||||
@ -113,6 +113,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 individual_halt = false);
|
||||
void Enable(Periphery p, bool enable = true);
|
||||
void Disable(Periphery p);
|
||||
bool IsEnabled(Periphery p);
|
||||
|
@ -11,7 +11,7 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
|
||||
HW::SetIdle();
|
||||
return;
|
||||
}
|
||||
Protocol::ManualControl m;
|
||||
Protocol::ManualControlV1 m;
|
||||
// LOs not required
|
||||
m.LO1CE = 0;
|
||||
m.LO1Frequency = 1000000000;
|
||||
|
@ -299,9 +299,7 @@ void HW::SetOutputUnlevel(bool unlev) {
|
||||
unlevel = unlev;
|
||||
}
|
||||
|
||||
void HW::fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy) {
|
||||
// copy constant default values
|
||||
memcpy(info, &HW::Info, sizeof(HW::Info));
|
||||
void HW::getDeviceStatus(Protocol::DeviceStatusV1 *status, bool updateEvenWhenBusy) {
|
||||
if(activeMode == Mode::Idle || updateEvenWhenBusy) {
|
||||
// updating values from FPGA allowed
|
||||
|
||||
@ -318,21 +316,21 @@ void HW::fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy) {
|
||||
if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT
|
||||
|| limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT
|
||||
|| limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) {
|
||||
info->ADC_overload = true;
|
||||
status->ADC_overload = true;
|
||||
} else {
|
||||
info->ADC_overload = false;
|
||||
status->ADC_overload = false;
|
||||
}
|
||||
auto status = FPGA::GetStatus();
|
||||
info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
|
||||
info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
|
||||
info->extRefAvailable = Ref::available();
|
||||
info->extRefInUse = extRefInUse;
|
||||
info->unlevel = unlevel;
|
||||
info->temp_LO1 = tempLO;
|
||||
info->temp_source = tempSource;
|
||||
auto FPGA_status = FPGA::GetStatus();
|
||||
status->LO1_locked = (FPGA_status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
|
||||
status->source_locked = (FPGA_status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
|
||||
status->extRefAvailable = Ref::available();
|
||||
status->extRefInUse = extRefInUse;
|
||||
status->unlevel = unlevel;
|
||||
status->temp_LO1 = tempLO;
|
||||
status->temp_source = tempSource;
|
||||
FPGA::ResetADCLimits();
|
||||
}
|
||||
info->temp_MCU = STM::getTemperature();
|
||||
status->temp_MCU = STM::getTemperature();
|
||||
}
|
||||
|
||||
bool HW::Ref::available() {
|
||||
|
@ -70,17 +70,8 @@ static constexpr Protocol::DeviceInfo Info = {
|
||||
.FW_major = FW_MAJOR,
|
||||
.FW_minor = FW_MINOR,
|
||||
.FW_patch = FW_PATCH,
|
||||
.hardware_version = 1,
|
||||
.HW_Revision = HW_REVISION,
|
||||
.extRefAvailable = 0,
|
||||
.extRefInUse = 0,
|
||||
.FPGA_configured = 0,
|
||||
.source_locked = 0,
|
||||
.LO1_locked = 0,
|
||||
.ADC_overload = 0,
|
||||
.unlevel = 0,
|
||||
.temp_source = 0,
|
||||
.temp_LO1 = 0,
|
||||
.temp_MCU = 0,
|
||||
.limits_minFreq = 0,
|
||||
.limits_maxFreq = 6000000000,
|
||||
.limits_minIFBW = DefaultADCSamplerate / MaxSamples,
|
||||
@ -120,7 +111,7 @@ using AmplitudeSettings = struct _amplitudeSettings {
|
||||
AmplitudeSettings GetAmplitudeSettings(int16_t cdbm, uint64_t freq = 0, bool applyCorrections = false, bool port2 = false);
|
||||
|
||||
bool GetTemps(uint8_t *source, uint8_t *lo);
|
||||
void fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy = false);
|
||||
void getDeviceStatus(Protocol::DeviceStatusV1 *status, bool updateEvenWhenBusy = false);
|
||||
namespace Ref {
|
||||
bool available();
|
||||
bool usingExternal();
|
||||
|
@ -6,11 +6,11 @@
|
||||
|
||||
static bool active = false;
|
||||
static uint32_t samples;
|
||||
static Protocol::ManualStatus status;
|
||||
static Protocol::ManualStatusV1 status;
|
||||
|
||||
using namespace HWHAL;
|
||||
|
||||
void Manual::Setup(Protocol::ManualControl m) {
|
||||
void Manual::Setup(Protocol::ManualControlV1 m) {
|
||||
HW::SetMode(HW::Mode::Manual);
|
||||
samples = m.Samples;
|
||||
FPGA::AbortSweep();
|
||||
@ -69,8 +69,7 @@ void Manual::Setup(Protocol::ManualControl m) {
|
||||
FPGA::Enable(FPGA::Periphery::Port1Mixer, m.Port1EN);
|
||||
FPGA::Enable(FPGA::Periphery::Port2Mixer, m.Port2EN);
|
||||
FPGA::Enable(FPGA::Periphery::RefMixer, m.RefEN);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort1, m.PortSwitch == 0);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort2, m.PortSwitch == 1);
|
||||
FPGA::SetupSweep(0, m.PortSwitch == 1, m.PortSwitch == 0);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch);
|
||||
|
||||
// Enable new data and sweep halt interrupt
|
||||
@ -100,38 +99,38 @@ void Manual::Work() {
|
||||
return;
|
||||
}
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::Status;
|
||||
p.status = status;
|
||||
p.type = Protocol::PacketType::ManualStatusV1;
|
||||
p.manualStatusV1 = status;
|
||||
uint16_t isr_flags = FPGA::GetStatus();
|
||||
if (!(isr_flags & 0x0002)) {
|
||||
p.status.source_locked = 1;
|
||||
p.manualStatusV1.source_locked = 1;
|
||||
} else {
|
||||
p.status.source_locked = 0;
|
||||
p.manualStatusV1.source_locked = 0;
|
||||
}
|
||||
if (!(isr_flags & 0x0001)) {
|
||||
p.status.LO_locked = 1;
|
||||
p.manualStatusV1.LO_locked = 1;
|
||||
} else {
|
||||
p.status.LO_locked = 0;
|
||||
p.manualStatusV1.LO_locked = 0;
|
||||
}
|
||||
auto limits = FPGA::GetADCLimits();
|
||||
FPGA::ResetADCLimits();
|
||||
p.status.port1min = limits.P1min;
|
||||
p.status.port1max = limits.P1max;
|
||||
p.status.port2min = limits.P2min;
|
||||
p.status.port2max = limits.P2max;
|
||||
p.status.refmin = limits.Rmin;
|
||||
p.status.refmax = limits.Rmax;
|
||||
HW::GetTemps(&p.status.temp_source, &p.status.temp_LO);
|
||||
p.manualStatusV1.port1min = limits.P1min;
|
||||
p.manualStatusV1.port1max = limits.P1max;
|
||||
p.manualStatusV1.port2min = limits.P2min;
|
||||
p.manualStatusV1.port2max = limits.P2max;
|
||||
p.manualStatusV1.refmin = limits.Rmin;
|
||||
p.manualStatusV1.refmax = limits.Rmax;
|
||||
HW::GetTemps(&p.manualStatusV1.temp_source, &p.manualStatusV1.temp_LO);
|
||||
Communication::Send(p);
|
||||
HW::Ref::update();
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::DeviceInfo;
|
||||
packet.type = Protocol::PacketType::DeviceStatusV1;
|
||||
// Enable PLL chips for temperature reading
|
||||
bool srcEn = FPGA::IsEnabled(FPGA::Periphery::SourceChip);
|
||||
bool LOEn = FPGA::IsEnabled(FPGA::Periphery::LO1Chip);
|
||||
FPGA::Enable(FPGA::Periphery::SourceChip);
|
||||
FPGA::Enable(FPGA::Periphery::LO1Chip);
|
||||
HW::fillDeviceInfo(&packet.info, true);
|
||||
HW::getDeviceStatus(&packet.statusV1, true);
|
||||
// restore PLL state
|
||||
FPGA::Enable(FPGA::Periphery::SourceChip, srcEn);
|
||||
FPGA::Enable(FPGA::Periphery::LO1Chip, LOEn);
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Manual {
|
||||
|
||||
void Setup(Protocol::ManualControl m);
|
||||
void Setup(Protocol::ManualControlV1 m);
|
||||
bool MeasurementDone(const FPGA::SamplingResult &result);
|
||||
void Work();
|
||||
void Stop();
|
||||
|
@ -209,8 +209,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
||||
FPGA::SetWindow((FPGA::Window) s.WindowType);
|
||||
FPGA::Enable(FPGA::Periphery::LO1Chip);
|
||||
FPGA::Enable(FPGA::Periphery::LO1RF);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.trackingGeneratorPort == 0);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort2, s.trackingGeneratorPort == 1);
|
||||
FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator);
|
||||
FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator);
|
||||
FPGA::Enable(FPGA::Periphery::Port1Mixer);
|
||||
@ -386,8 +385,8 @@ void SA::Work() {
|
||||
// send device info every nth point
|
||||
FPGA::Enable(FPGA::Periphery::SourceChip); // needs to enable the chip to get a valid temperature reading
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::DeviceInfo;
|
||||
HW::fillDeviceInfo(&packet.info, true);
|
||||
packet.type = Protocol::PacketType::DeviceStatusV1;
|
||||
HW::getDeviceStatus(&packet.statusV1, true);
|
||||
FPGA::Disable(FPGA::Periphery::SourceChip);
|
||||
Communication::Send(packet);
|
||||
}
|
||||
|
@ -21,8 +21,9 @@
|
||||
|
||||
static Protocol::SweepSettings settings;
|
||||
static uint16_t pointCnt;
|
||||
static uint8_t stageCnt;
|
||||
static uint8_t stages;
|
||||
static double logMultiplier, logFrequency;
|
||||
static bool excitingPort1;
|
||||
static Protocol::Datapoint data;
|
||||
static bool active = false;
|
||||
static Si5351C::DriveStrength fixedPowerLowband;
|
||||
@ -278,12 +279,22 @@ bool VNA::Setup(Protocol::SweepSettings s) {
|
||||
FPGA::Enable(FPGA::Periphery::SourceRF);
|
||||
FPGA::Enable(FPGA::Periphery::LO1Chip);
|
||||
FPGA::Enable(FPGA::Periphery::LO1RF);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.excitePort1);
|
||||
FPGA::Enable(FPGA::Periphery::ExcitePort2, s.excitePort2);
|
||||
if(s.excitePort1 && s.excitePort2) {
|
||||
// two stages, port 1 first, followed by port 2
|
||||
FPGA::SetupSweep(1, 0, 1);
|
||||
stages = 2;
|
||||
} else if(s.excitePort1) {
|
||||
// one stage, port 1 only
|
||||
FPGA::SetupSweep(0, 0, 1);
|
||||
stages = 1;
|
||||
} else {
|
||||
// one stage, port 2 only
|
||||
FPGA::SetupSweep(0, 1, 0);
|
||||
stages = 1;
|
||||
}
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch);
|
||||
pointCnt = 0;
|
||||
// starting port depends on whether port 1 is active in sweep
|
||||
excitingPort1 = s.excitePort1;
|
||||
stageCnt = 0;
|
||||
IFTableIndexCnt = 0;
|
||||
adcShifted = false;
|
||||
active = true;
|
||||
@ -306,8 +317,8 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
|
||||
if(!active) {
|
||||
return false;
|
||||
}
|
||||
if(result.pointNum != pointCnt || !result.activePort != excitingPort1) {
|
||||
LOG_WARN("Indicated point does not match (%u != %u, %d != %d)", result.pointNum, pointCnt, result.activePort, !excitingPort1);
|
||||
if(result.pointNum != pointCnt || result.stageNum != stageCnt) {
|
||||
LOG_WARN("Indicated point does not match (%u != %u, %d != %d)", result.pointNum, pointCnt, result.stageNum, stageCnt);
|
||||
FPGA::AbortSweep();
|
||||
return false;
|
||||
}
|
||||
@ -320,29 +331,24 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
|
||||
data.pointNum = pointCnt;
|
||||
data.frequency = getPointFrequency(pointCnt);
|
||||
data.cdbm = settings.cdbm_excitation_start + (settings.cdbm_excitation_stop - settings.cdbm_excitation_start) * pointCnt / (settings.points - 1);
|
||||
if(excitingPort1) {
|
||||
if(stageCnt == 0 && settings.excitePort1) {
|
||||
// stimulus is present at port 1
|
||||
data.real_S11 = port1.real();
|
||||
data.imag_S11 = port1.imag();
|
||||
data.real_S21 = port2.real();
|
||||
data.imag_S21 = port2.imag();
|
||||
} else {
|
||||
// stimulus is present at port 2
|
||||
data.real_S12 = port1.real();
|
||||
data.imag_S12 = port1.imag();
|
||||
data.real_S22 = port2.real();
|
||||
data.imag_S22 = port2.imag();
|
||||
}
|
||||
// figure out whether this sweep point is complete and which port gets excited next
|
||||
bool pointComplete = false;
|
||||
if(settings.excitePort1 == 1 && settings.excitePort2 == 1) {
|
||||
// point is complete when port 2 was active
|
||||
pointComplete = !excitingPort1;
|
||||
// next measurement will be from other port
|
||||
excitingPort1 = !excitingPort1;
|
||||
} else {
|
||||
// only one port active, point is complete after every measurement
|
||||
pointComplete = true;
|
||||
}
|
||||
if(pointComplete) {
|
||||
// figure out whether this sweep point is complete
|
||||
stageCnt++;
|
||||
if(stageCnt == stages) {
|
||||
// point is complete
|
||||
stageCnt = 0;
|
||||
STM::DispatchToInterrupt(PassOnData);
|
||||
pointCnt++;
|
||||
if (pointCnt >= settings.points) {
|
||||
@ -361,8 +367,8 @@ void VNA::Work() {
|
||||
HW::Ref::update();
|
||||
// Compile info packet
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::DeviceInfo;
|
||||
HW::fillDeviceInfo(&packet.info, true);
|
||||
packet.type = Protocol::PacketType::DeviceStatusV1;
|
||||
HW::getDeviceStatus(&packet.statusV1, true);
|
||||
Communication::Send(packet);
|
||||
// do not reset unlevel flag here, as it is calculated only once at the setup of the sweep
|
||||
// Start next sweep
|
||||
|
Loading…
Reference in New Issue
Block a user