Merge branch 'master' of github.com:jankae/LibreVNA

This commit is contained in:
Jan Käberich 2022-04-05 14:10:34 +02:00
commit 4243e64f7f
45 changed files with 710 additions and 400 deletions

View File

@ -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{9}{2}{Window[1:0]}
\rwbits{11}{1}{SCEN} \rwbits{11}{1}{SCEN}
\rwbits{12}{1}{LCEN} \rwbits{12}{1}{LCEN}
\rwbits{13}{1}{EXP2} \robits{13}{3}{reserved}
\rwbits{14}{1}{EXP1} %\rwbits{13}{1}{EXP2}
\rwbits{15}{1}{PSEN} %\rwbits{14}{1}{EXP1}
%\rwbits{15}{1}{PSEN}
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\begin{itemize} \begin{itemize}
@ -371,8 +372,8 @@ Setting & Window type\\
\end{center} \end{center}
\item \textbf{SCEN:}{Source chip enable} \item \textbf{SCEN:}{Source chip enable}
\item \textbf{LCEN:}{LO chip enable} \item \textbf{LCEN:}{LO chip enable}
\item \textbf{EXP1:}{Excite Port1 during sweep} %\item \textbf{EXP1:}{Excite Port1 during sweep}
\item \textbf{EXP2:}{Excite Port2 during sweep} %\item \textbf{EXP2:}{Excite Port2 during sweep}
\item \textbf{PSEN:}{Port switch enable} \item \textbf{PSEN:}{Port switch enable}
\end{itemize} \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). For the the default IF frequency of $f_{IF2} = \SI{250}{\kilo\hertz}$ this evaluates to 10*Presc (see ADC prescaler register).
\end{itemize} \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} \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. 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} \begin{center}
@ -574,12 +596,11 @@ Setting & Selected Power\\
\section{Sampling Result} \section{Sampling Result}
\label{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{center}
\begin{tikzpicture} \begin{tikzpicture}
\bitrect{16}{304-\bit} \bitrect{16}{304-\bit}
\rwbits{0}{1}{SRC} \rwbits{0}{3}{STAGE[2:0]}
\robits{1}{2}{reserved}
\rwbits{3}{13}{POINT\_NUMBER[12:0]} \rwbits{3}{13}{POINT\_NUMBER[12:0]}
\end{tikzpicture} \end{tikzpicture}
\begin{tikzpicture} \begin{tikzpicture}

View File

@ -50,8 +50,10 @@ entity SPICommands is
SWEEP_WRITE : out STD_LOGIC_VECTOR (0 downto 0); SWEEP_WRITE : out STD_LOGIC_VECTOR (0 downto 0);
SWEEP_POINTS : out STD_LOGIC_VECTOR (12 downto 0); SWEEP_POINTS : out STD_LOGIC_VECTOR (12 downto 0);
NSAMPLES : out STD_LOGIC_VECTOR (12 downto 0); NSAMPLES : out STD_LOGIC_VECTOR (12 downto 0);
EXCITE_PORT1 : out STD_LOGIC; STAGES : out STD_LOGIC_VECTOR (2 downto 0);
EXCITE_PORT2 : out STD_LOGIC; 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; PORT1_EN : out STD_LOGIC;
PORT2_EN : out STD_LOGIC; PORT2_EN : out STD_LOGIC;
REF_EN : out STD_LOGIC; REF_EN : out STD_LOGIC;
@ -154,8 +156,6 @@ begin
SOURCE_CE_EN <= '0'; SOURCE_CE_EN <= '0';
LO_CE_EN <= '0'; LO_CE_EN <= '0';
PORTSWITCH_EN <= '0'; PORTSWITCH_EN <= '0';
EXCITE_PORT1 <= '0';
EXCITE_PORT2 <= '0';
LEDS <= (others => '1'); LEDS <= (others => '1');
WINDOW_SETTING <= "00"; WINDOW_SETTING <= "00";
unread_sampling_data <= '0'; unread_sampling_data <= '0';
@ -243,10 +243,12 @@ begin
WINDOW_SETTING <= spi_buf_out(6 downto 5); WINDOW_SETTING <= spi_buf_out(6 downto 5);
SOURCE_CE_EN <= spi_buf_out(4); SOURCE_CE_EN <= spi_buf_out(4);
LO_CE_EN <= spi_buf_out(3); 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 4 => ADC_PRESCALER <= spi_buf_out(7 downto 0);
when 5 => ADC_PHASEINC <= spi_buf_out(11 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 8 => MAX2871_DEF_0(15 downto 0) <= spi_buf_out;
when 9 => MAX2871_DEF_0(31 downto 16) <= 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; when 10 => MAX2871_DEF_1(15 downto 0) <= spi_buf_out;

View File

@ -40,7 +40,6 @@ entity Sweep is
SAMPLING_BUSY : in STD_LOGIC; SAMPLING_BUSY : in STD_LOGIC;
SAMPLING_DONE : in STD_LOGIC; SAMPLING_DONE : in STD_LOGIC;
START_SAMPLING : out STD_LOGIC; START_SAMPLING : out STD_LOGIC;
PORT_SELECT : out STD_LOGIC;
BAND_SELECT : out STD_LOGIC; BAND_SELECT : out STD_LOGIC;
-- fixed part of source/LO registers -- fixed part of source/LO registers
MAX2871_DEF_4 : in STD_LOGIC_VECTOR (31 downto 0); 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); --SETTLING_TIME : in STD_LOGIC_VECTOR (15 downto 0);
EXCITE_PORT1 : in STD_LOGIC; STAGES : in STD_LOGIC_VECTOR (2 downto 0);
EXCITE_PORT2 : in STD_LOGIC; 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 signals
DEBUG_STATUS : out STD_LOGIC_VECTOR (10 downto 0); DEBUG_STATUS : out STD_LOGIC_VECTOR (10 downto 0);
@ -78,10 +82,11 @@ end Sweep;
architecture Behavioral of Sweep is architecture Behavioral of Sweep is
signal point_cnt : unsigned(12 downto 0); 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 state : Point_states;
signal settling_cnt : unsigned(15 downto 0); signal settling_cnt : unsigned(15 downto 0);
signal settling_time : 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); signal config_reg : std_logic_vector(95 downto 0);
begin begin
@ -121,10 +126,8 @@ begin
DEBUG_STATUS(10 downto 8) <= "000" when state = TriggerSetup else DEBUG_STATUS(10 downto 8) <= "000" when state = TriggerSetup else
"001" when state = SettingUp else "001" when state = SettingUp else
"010" when state = SettlingPort1 else "010" when state = Settling else
"011" when state = ExcitingPort1 else "011" when state = Exciting else
"100" when state = SettlingPort2 else
"101" when state = ExcitingPort2 else
"110" when state = Done else "110" when state = Done else
"111"; "111";
DEBUG_STATUS(7) <= PLL_RELOAD_DONE; DEBUG_STATUS(7) <= PLL_RELOAD_DONE;
@ -139,15 +142,19 @@ begin
if rising_edge(CLK) then if rising_edge(CLK) then
if RESET = '1' then if RESET = '1' then
point_cnt <= (others => '0'); point_cnt <= (others => '0');
stage_cnt <= (others => '0');
state <= TriggerSetup; state <= TriggerSetup;
START_SAMPLING <= '0'; START_SAMPLING <= '0';
RELOAD_PLL_REGS <= '0'; RELOAD_PLL_REGS <= '0';
SWEEP_HALTED <= '0'; SWEEP_HALTED <= '0';
RESULT_INDEX <= (others => '1'); RESULT_INDEX <= (others => '1');
PORT1_ACTIVE <= '0';
PORT2_ACTIVE <= '0';
else else
case state is case state is
when TriggerSetup => when TriggerSetup =>
RELOAD_PLL_REGS <= '1'; RELOAD_PLL_REGS <= '1';
stage_cnt <= (others => '0');
if PLL_RELOAD_DONE = '0' then if PLL_RELOAD_DONE = '0' then
state <= SettingUp; state <= SettingUp;
end if; end if;
@ -166,60 +173,52 @@ begin
-- check if halted sweep is resumed -- check if halted sweep is resumed
if config_reg(95) = '0' or SWEEP_RESUME = '1' then if config_reg(95) = '0' or SWEEP_RESUME = '1' then
SWEEP_HALTED <= '0'; SWEEP_HALTED <= '0';
if EXCITE_PORT1 = '1' then state <= Settling;
state <= SettlingPort1;
else
state <= SettlingPort2;
end if;
end if; end if;
end if; end if;
when SettlingPort1 => when Settling =>
PORT_SELECT <= '1'; 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 -- wait for settling time to elapse
if settling_cnt > 0 then if settling_cnt > 0 then
settling_cnt <= settling_cnt - 1; settling_cnt <= settling_cnt - 1;
else else
START_SAMPLING <= '1'; START_SAMPLING <= '1';
if SAMPLING_BUSY = '1' then if SAMPLING_BUSY = '1' then
state <= ExcitingPort1; state <= Exciting;
end if; end if;
end if; end if;
when ExcitingPort1 => when Exciting =>
-- wait for sampling to finish -- wait for sampling to finish
START_SAMPLING <= '0'; START_SAMPLING <= '0';
if SAMPLING_BUSY = '0' then if SAMPLING_BUSY = '0' then
RESULT_INDEX <= "000" & std_logic_vector(point_cnt); RESULT_INDEX <= std_logic_vector(stage_cnt) & std_logic_vector(point_cnt);
if EXCITE_PORT2 = '1' then if stage_cnt < unsigned(STAGES) then
state <= SettlingPort2; 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 else
state <= NextPoint; state <= NextPoint;
end if; end if;
settling_cnt <= settling_time; settling_cnt <= settling_time;
end if; 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 => when NextPoint =>
if point_cnt < unsigned(NPOINTS) then if point_cnt < unsigned(NPOINTS) then
point_cnt <= point_cnt + 1; point_cnt <= point_cnt + 1;
state <= TriggerSetup; state <= TriggerSetup;
-- initial port depends on whether port 1 is exited
PORT_SELECT <= EXCITE_PORT1;
else else
point_cnt <= (others => '0'); point_cnt <= (others => '0');
state <= Done; state <= Done;

View File

@ -224,7 +224,7 @@
<status xil_pn:value="SuccessfullyRun"/> <status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="ipcore_dir/DSP_SLICE.ngc"/> <outfile xil_pn:name="ipcore_dir/DSP_SLICE.ngc"/>
@ -253,7 +253,7 @@
<status xil_pn:value="SuccessfullyRun"/> <status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/> <status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
@ -275,7 +275,7 @@
<status xil_pn:value="SuccessfullyRun"/> <status xil_pn:value="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_ngo"/> <outfile xil_pn:name="_ngo"/>
@ -284,7 +284,7 @@
<outfile xil_pn:name="top.ngd"/> <outfile xil_pn:name="top.ngd"/>
<outfile xil_pn:name="top_ngdbuild.xrpt"/> <outfile xil_pn:name="top_ngdbuild.xrpt"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/> <status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
@ -298,7 +298,7 @@
<outfile xil_pn:name="top_summary.xml"/> <outfile xil_pn:name="top_summary.xml"/>
<outfile xil_pn:name="top_usage.xml"/> <outfile xil_pn:name="top_usage.xml"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/par.xmsgs"/> <outfile xil_pn:name="_xmsgs/par.xmsgs"/>
@ -312,9 +312,8 @@
<outfile xil_pn:name="top_pad.txt"/> <outfile xil_pn:name="top_pad.txt"/>
<outfile xil_pn:name="top_par.xrpt"/> <outfile xil_pn:name="top_par.xrpt"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="WarningsGenerated"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/bitgen.xmsgs"/> <outfile xil_pn:name="_xmsgs/bitgen.xmsgs"/>
<outfile xil_pn:name="top.bgn"/> <outfile xil_pn:name="top.bgn"/>
@ -366,7 +365,7 @@
<status xil_pn:value="InputChanged"/> <status xil_pn:value="InputChanged"/>
<status xil_pn:value="InputRemoved"/> <status xil_pn:value="InputRemoved"/>
</transform> </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="SuccessfullyRun"/>
<status xil_pn:value="ReadyToRun"/> <status xil_pn:value="ReadyToRun"/>
<outfile xil_pn:name="_xmsgs/trce.xmsgs"/> <outfile xil_pn:name="_xmsgs/trce.xmsgs"/>

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="top.vhd" xil_pn:type="FILE_VHDL"> <file xil_pn:name="top.vhd" xil_pn:type="FILE_VHDL">

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="DSP_SLICE.ngc" xil_pn:type="FILE_NGC"> <file xil_pn:name="DSP_SLICE.ngc" xil_pn:type="FILE_NGC">

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="PLL.ucf" xil_pn:type="FILE_UCF"> <file xil_pn:name="PLL.ucf" xil_pn:type="FILE_UCF">

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="SinCos.ngc" xil_pn:type="FILE_NGC"> <file xil_pn:name="SinCos.ngc" xil_pn:type="FILE_NGC">

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="SweepConfigMem.ngc" xil_pn:type="FILE_NGC"> <file xil_pn:name="SweepConfigMem.ngc" xil_pn:type="FILE_NGC">

View File

@ -12,7 +12,7 @@
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. --> <!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header> </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> <files>
<file xil_pn:name="result_bram.ngc" xil_pn:type="FILE_NGC"> <file xil_pn:name="result_bram.ngc" xil_pn:type="FILE_NGC">

Binary file not shown.

View File

@ -124,7 +124,6 @@ architecture Behavioral of top is
PLL_LOCKED : IN std_logic; PLL_LOCKED : IN std_logic;
CONFIG_ADDRESS : OUT std_logic_vector(12 downto 0); CONFIG_ADDRESS : OUT std_logic_vector(12 downto 0);
START_SAMPLING : OUT std_logic; START_SAMPLING : OUT std_logic;
PORT_SELECT : OUT std_logic;
BAND_SELECT : out STD_LOGIC; BAND_SELECT : out STD_LOGIC;
SOURCE_REG_4 : OUT std_logic_vector(31 downto 0); SOURCE_REG_4 : OUT std_logic_vector(31 downto 0);
SOURCE_REG_3 : 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; SWEEP_RESUME : in STD_LOGIC;
ATTENUATOR : OUT std_logic_vector(6 downto 0); ATTENUATOR : OUT std_logic_vector(6 downto 0);
SOURCE_FILTER : OUT std_logic_vector(1 downto 0); SOURCE_FILTER : OUT std_logic_vector(1 downto 0);
EXCITE_PORT1 : in STD_LOGIC; STAGES : in STD_LOGIC_VECTOR (2 downto 0);
EXCITE_PORT2 : in STD_LOGIC; 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); RESULT_INDEX : out STD_LOGIC_VECTOR (15 downto 0);
DEBUG_STATUS : out STD_LOGIC_VECTOR (10 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_WRITE : OUT std_logic_vector(0 to 0);
SWEEP_POINTS : OUT std_logic_vector(12 downto 0); SWEEP_POINTS : OUT std_logic_vector(12 downto 0);
NSAMPLES : OUT std_logic_vector(12 downto 0); NSAMPLES : OUT std_logic_vector(12 downto 0);
EXCITE_PORT1 : out STD_LOGIC; STAGES : out STD_LOGIC_VECTOR (2 downto 0);
EXCITE_PORT2 : out STD_LOGIC; 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; PORT1_EN : out STD_LOGIC;
PORT2_EN : out STD_LOGIC; PORT2_EN : out STD_LOGIC;
REF_EN : out STD_LOGIC; REF_EN : out STD_LOGIC;
@ -360,10 +366,14 @@ architecture Behavioral of top is
-- Sweep signals -- Sweep signals
signal sweep_points : std_logic_vector(12 downto 0); 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_data : std_logic_vector(95 downto 0);
signal sweep_config_address : std_logic_vector(12 downto 0); signal sweep_config_address : std_logic_vector(12 downto 0);
signal source_filter : std_logic_vector(1 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_address : std_logic_vector(12 downto 0);
signal sweep_config_write_data : std_logic_vector(95 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_port1 : std_logic;
signal sweep_excite_port2 : std_logic; signal sweep_excite_port2 : std_logic;
signal sweep_band : std_logic;
-- Configuration signals -- Configuration signals
signal settling_time : std_logic_vector(15 downto 0); signal settling_time : std_logic_vector(15 downto 0);
signal def_reg_4 : std_logic_vector(31 downto 0); signal def_reg_4 : std_logic_vector(31 downto 0);
@ -428,10 +436,10 @@ begin
LEDS(2) <= SOURCE_LD; LEDS(2) <= SOURCE_LD;
LEDS(3) <= LO1_LD; LEDS(3) <= LO1_LD;
-- Sweep and active port -- Sweep and active port
PORT_SELECT2 <= not sweep_port_select and portswitch_en; PORT_SELECT2 <= sweep_excite_port2 and portswitch_en;
PORT2_SELECT <= not sweep_port_select and portswitch_en; PORT2_SELECT <= sweep_excite_port2 and portswitch_en;
PORT_SELECT1 <= sweep_port_select and portswitch_en; PORT_SELECT1 <= sweep_excite_port1 and portswitch_en;
PORT1_SELECT <= sweep_port_select and portswitch_en; PORT1_SELECT <= sweep_excite_port1 and portswitch_en;
BAND_SELECT_HIGH <= not sweep_band; BAND_SELECT_HIGH <= not sweep_band;
BAND_SELECT_LOW <= sweep_band; BAND_SELECT_LOW <= sweep_band;
PORT1_MIX2_EN <= port1mix_en; PORT1_MIX2_EN <= port1mix_en;
@ -440,8 +448,8 @@ begin
PORT2_MIX1_EN <= not port2mix_en; PORT2_MIX1_EN <= not port2mix_en;
REF_MIX2_EN <= refmix_en; REF_MIX2_EN <= refmix_en;
REF_MIX1_EN <= not refmix_en; REF_MIX1_EN <= not refmix_en;
LEDS(4) <= not (not sweep_reset and not 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_port_select and portswitch_en); LEDS(5) <= not (not sweep_reset and sweep_excite_port1 and portswitch_en);
-- Uncommitted LEDs -- Uncommitted LEDs
LEDS(7 downto 6) <= user_leds(1 downto 0); LEDS(7 downto 6) <= user_leds(1 downto 0);
--LEDS(7) <= '0'; --LEDS(7) <= '0';
@ -649,7 +657,6 @@ begin
SAMPLING_BUSY => sampling_busy, SAMPLING_BUSY => sampling_busy,
SAMPLING_DONE => sampling_done, SAMPLING_DONE => sampling_done,
START_SAMPLING => sampling_start, START_SAMPLING => sampling_start,
PORT_SELECT => sweep_port_select,
BAND_SELECT => sweep_band, BAND_SELECT => sweep_band,
MAX2871_DEF_4 => def_reg_4, MAX2871_DEF_4 => def_reg_4,
MAX2871_DEF_3 => def_reg_3, MAX2871_DEF_3 => def_reg_3,
@ -670,8 +677,13 @@ begin
SWEEP_RESUME => sweep_resume, SWEEP_RESUME => sweep_resume,
ATTENUATOR => ATTENUATION, ATTENUATOR => ATTENUATION,
SOURCE_FILTER => source_filter, SOURCE_FILTER => source_filter,
EXCITE_PORT1 => sweep_excite_port1, STAGES => sweep_stages,
EXCITE_PORT2 => sweep_excite_port2, 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, DEBUG_STATUS => debug,
RESULT_INDEX => sampling_result(303 downto 288) RESULT_INDEX => sampling_result(303 downto 288)
); );
@ -740,8 +752,10 @@ begin
RESET_MINMAX => adc_reset_minmax, RESET_MINMAX => adc_reset_minmax,
SWEEP_HALTED => sweep_halted, SWEEP_HALTED => sweep_halted,
SWEEP_RESUME => sweep_resume, SWEEP_RESUME => sweep_resume,
EXCITE_PORT1 => sweep_excite_port1, STAGES => sweep_stages,
EXCITE_PORT2 => sweep_excite_port2, INDIVIDUAL_HALT => sweep_individual_halt,
PORT1_STAGE => sweep_port1_stage,
PORT2_STAGE => sweep_port2_stage,
DFT_BIN1_PHASEINC => dft_bin1_phaseinc, DFT_BIN1_PHASEINC => dft_bin1_phaseinc,
DFT_DIFFBIN_PHASEINC => dft_diffbin_phaseinc, DFT_DIFFBIN_PHASEINC => dft_diffbin_phaseinc,
DFT_RESULT_READY => dft_ready, DFT_RESULT_READY => dft_ready,

View File

@ -253,7 +253,7 @@ void AmplitudeCalDialog::RemoveAllPoints()
bool AmplitudeCalDialog::AddPoint(AmplitudeCalDialog::CorrectionPoint &p) bool AmplitudeCalDialog::AddPoint(AmplitudeCalDialog::CorrectionPoint &p)
{ {
if (points.size() >= Device::Info().limits_maxAmplitudePoints) { if (points.size() >= Device::Info(dev).limits_maxAmplitudePoints) {
// already at limit // already at limit
return false; return false;
} }
@ -299,8 +299,8 @@ void AmplitudeCalDialog::AddPointDialog()
ui->stopFreq->setUnit("Hz"); ui->stopFreq->setUnit("Hz");
ui->stopFreq->setPrefixes(" kMG"); ui->stopFreq->setPrefixes(" kMG");
ui->frequency->setValue(1000000000.0); ui->frequency->setValue(1000000000.0);
ui->startFreq->setValue(Device::Info().limits_minFreq); ui->startFreq->setValue(Device::Info(dev).limits_minFreq);
ui->stopFreq->setValue(Device::Info().limits_maxFreq); ui->stopFreq->setValue(Device::Info(dev).limits_maxFreq);
connect(ui->singlePoint, &QRadioButton::toggled, [=](bool single) { connect(ui->singlePoint, &QRadioButton::toggled, [=](bool single) {
ui->stopFreq->setEnabled(!single); ui->stopFreq->setEnabled(!single);
ui->startFreq->setEnabled(!single); ui->startFreq->setEnabled(!single);

View File

@ -120,16 +120,6 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
.FW_minor = 0, .FW_minor = 0,
.FW_patch = 0, .FW_patch = 0,
.HW_Revision = '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_minFreq = 0,
.limits_maxFreq = 6000000000, .limits_maxFreq = 6000000000,
.limits_minIFBW = 10, .limits_minIFBW = 10,
@ -143,14 +133,25 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
.limits_maxFreqHarmonic = 18000000000, .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) Device::Device(QString serial)
{ {
lastInfo = defaultInfo; info = defaultInfo;
m_handle = nullptr; m_handle = nullptr;
lastInfoValid = false; infoValid = false;
libusb_init(&m_context); libusb_init(&m_context);
#if LIBUSB_API_VERSION >= 0x01000106 #if LIBUSB_API_VERSION >= 0x01000106
libusb_set_option(m_context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); 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); return SendPacket(p);
} }
bool Device::SetManual(Protocol::ManualControl manual) bool Device::SetManual(Protocol::ManualControlV1 manual)
{ {
Protocol::PacketInfo p; Protocol::PacketInfo p;
p.type = Protocol::PacketType::ManualControl; p.type = Protocol::PacketType::ManualControlV1;
p.manual = manual; p.manual = manual;
return SendPacket(p); return SendPacket(p);
} }
@ -393,25 +394,48 @@ void Device::SearchDevices(std::function<bool (libusb_device_handle *, QString)>
const Protocol::DeviceInfo &Device::Info() 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 Device::getLastDeviceInfoString()
{ {
QString ret; QString ret;
if(!lastInfoValid) { if(!infoValid) {
ret.append("No device information available yet"); ret.append("No device information available yet");
} else { } else {
ret.append("HW Rev."); ret.append("HW Rev.");
ret.append(lastInfo.HW_Revision); ret.append(info.HW_Revision);
ret.append(" FW "+QString::number(lastInfo.FW_major)+"."+QString::number(lastInfo.FW_minor)+"."+QString::number(lastInfo.FW_patch)); ret.append(" FW "+QString::number(info.FW_major)+"."+QString::number(info.FW_minor)+"."+QString::number(info.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(" 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:"); ret.append(" Reference:");
if(lastInfo.extRefInUse) { if(status.v1.extRefInUse) {
ret.append("External"); ret.append("External");
} else { } else {
ret.append("Internal"); ret.append("Internal");
if(lastInfo.extRefAvailable) { if(status.v1.extRefAvailable) {
ret.append(" (External available)"); ret.append(" (External available)");
} }
} }
@ -431,8 +455,8 @@ void Device::ReceivedData()
case Protocol::PacketType::Datapoint: case Protocol::PacketType::Datapoint:
emit DatapointReceived(packet.datapoint); emit DatapointReceived(packet.datapoint);
break; break;
case Protocol::PacketType::Status: case Protocol::PacketType::ManualStatusV1:
emit ManualStatusReceived(packet.status); emit ManualStatusReceived(packet.manualStatusV1);
break; break;
case Protocol::PacketType::SpectrumAnalyzerResult: case Protocol::PacketType::SpectrumAnalyzerResult:
emit SpectrumResultReceived(packet.spectrumResult); emit SpectrumResultReceived(packet.spectrumResult);
@ -443,15 +467,19 @@ void Device::ReceivedData()
break; break;
case Protocol::PacketType::DeviceInfo: case Protocol::PacketType::DeviceInfo:
if(packet.info.ProtocolVersion != Protocol::Version) { if(packet.info.ProtocolVersion != Protocol::Version) {
if(!lastInfoValid) { if(!infoValid) {
emit NeedsFirmwareUpdate(packet.info.ProtocolVersion, Protocol::Version); emit NeedsFirmwareUpdate(packet.info.ProtocolVersion, Protocol::Version);
} }
} else { } else {
lastInfo = packet.info; info = packet.info;
} }
lastInfoValid = true; infoValid = true;
emit DeviceInfoUpdated(); emit DeviceInfoUpdated();
break; break;
case Protocol::PacketType::DeviceStatusV1:
status.v1 = packet.statusV1;
emit DeviceStatusUpdated();
break;
case Protocol::PacketType::Ack: case Protocol::PacketType::Ack:
emit AckReceived(); emit AckReceived();
emit receivedAnswer(TransmissionResult::Ack); emit receivedAnswer(TransmissionResult::Ack);

View File

@ -13,7 +13,7 @@
#include <QTimer> #include <QTimer>
Q_DECLARE_METATYPE(Protocol::Datapoint); Q_DECLARE_METATYPE(Protocol::Datapoint);
Q_DECLARE_METATYPE(Protocol::ManualStatus); Q_DECLARE_METATYPE(Protocol::ManualStatusV1);
Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult); Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult);
Q_DECLARE_METATYPE(Protocol::AmplitudeCorrectionPoint); 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 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::SweepSettings settings, std::function<void(TransmissionResult)> cb = nullptr);
bool Configure(Protocol::SpectrumAnalyzerSettings settings); bool Configure(Protocol::SpectrumAnalyzerSettings settings);
bool SetManual(Protocol::ManualControl manual); bool SetManual(Protocol::ManualControlV1 manual);
bool SetIdle(); bool SetIdle();
bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw);
bool SendCommandWithoutPayload(Protocol::PacketType type); bool SendCommandWithoutPayload(Protocol::PacketType type);
QString serial() const; 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(); QString getLastDeviceInfoString();
// Returns serial numbers of all connected devices // Returns serial numbers of all connected devices
static std::set<QString> GetDevices(); static std::set<QString> GetDevices();
signals: signals:
void DatapointReceived(Protocol::Datapoint); void DatapointReceived(Protocol::Datapoint);
void ManualStatusReceived(Protocol::ManualStatus); void ManualStatusReceived(Protocol::ManualStatusV1);
void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult); void SpectrumResultReceived(Protocol::SpectrumAnalyzerResult);
void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint); void AmplitudeCorrectionPointReceived(Protocol::AmplitudeCorrectionPoint);
void FrequencyCorrectionReceived(float ppm); void FrequencyCorrectionReceived(float ppm);
void DeviceInfoUpdated(); void DeviceInfoUpdated();
void DeviceStatusUpdated();
void ConnectionLost(); void ConnectionLost();
void AckReceived(); void AckReceived();
void NackReceived(); void NackReceived();
@ -122,8 +126,11 @@ private:
QString m_serial; QString m_serial;
bool m_connected; bool m_connected;
std::thread *m_receiveThread; std::thread *m_receiveThread;
static Protocol::DeviceInfo lastInfo; Protocol::DeviceInfo info;
bool lastInfoValid; bool infoValid;
union {
Protocol::DeviceStatusV1 v1;
} status;
}; };
#endif // DEVICE_H #endif // DEVICE_H

View File

@ -580,7 +580,7 @@ double ManualControlDialog::getRefPhase()
return ui->refphase->text().toDouble(); return ui->refphase->text().toDouble();
} }
void ManualControlDialog::NewStatus(Protocol::ManualStatus status) void ManualControlDialog::NewStatus(Protocol::ManualStatusV1 status)
{ {
// ADC values // ADC values
ui->port1min->setText(QString::number(status.port1min)); ui->port1min->setText(QString::number(status.port1min));
@ -616,7 +616,7 @@ void ManualControlDialog::NewStatus(Protocol::ManualStatus status)
void ManualControlDialog::UpdateDevice() void ManualControlDialog::UpdateDevice()
{ {
Protocol::ManualControl m; Protocol::ManualControlV1 m;
// Source highband // Source highband
m.SourceHighCE = ui->SourceCE->isChecked(); m.SourceHighCE = ui->SourceCE->isChecked();
m.SourceHighRFEN = ui->SourceRFEN->isChecked(); m.SourceHighRFEN = ui->SourceRFEN->isChecked();

View File

@ -103,7 +103,7 @@ public:
double getRefPhase(); double getRefPhase();
public slots: public slots:
void NewStatus(Protocol::ManualStatus status); void NewStatus(Protocol::ManualStatusV1 status);
private: private:
void UpdateDevice(); void UpdateDevice();

View File

@ -2,11 +2,10 @@
#include <QSettings> #include <QSettings>
Generator::Generator(AppWindow *window) Generator::Generator(AppWindow *window, QString name)
: Mode(window, "Signal Generator") : Mode(window, name, "GENerator")
, SCPINode("GENerator")
{ {
central = new SignalgeneratorWidget(window); central = new SignalgeneratorWidget(window->getDevice(), window);
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();

View File

@ -5,13 +5,15 @@
#include "signalgenwidget.h" #include "signalgenwidget.h"
#include "scpi.h" #include "scpi.h"
class Generator : public Mode, public SCPINode class Generator : public Mode
{ {
public: public:
Generator(AppWindow *window); Generator(AppWindow *window, QString name = "Signal Generator");
void deactivate() override; void deactivate() override;
void initializeDevice() override; void initializeDevice() override;
virtual Type getType() override { return Type::SG;}
// Nothing to do for now // Nothing to do for now
virtual nlohmann::json toJSON() override; virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override; virtual void fromJSON(nlohmann::json j) override;

View File

@ -2,9 +2,10 @@
#include "ui_signalgenwidget.h" #include "ui_signalgenwidget.h"
SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) : SignalgeneratorWidget::SignalgeneratorWidget(Device *&dev, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::SignalgeneratorWidget) ui(new Ui::SignalgeneratorWidget),
dev(dev)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->frequency->setUnit("Hz"); ui->frequency->setUnit("Hz");
@ -31,16 +32,16 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
ui->steps->setPrecision(0); ui->steps->setPrecision(0);
connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) { connect(ui->frequency, &SIUnitEdit::valueChanged, [=](double newval) {
if(newval < Device::Info().limits_minFreq) { if(newval < Device::Info(dev).limits_minFreq) {
newval = Device::Info().limits_minFreq; newval = Device::Info(dev).limits_minFreq;
} else if (newval > Device::Info().limits_maxFreq) { } else if (newval > Device::Info(dev).limits_maxFreq) {
newval = Device::Info().limits_maxFreq; newval = Device::Info(dev).limits_maxFreq;
} }
ui->frequency->setValueQuiet(newval); ui->frequency->setValueQuiet(newval);
if (newval < ui->span->value()/2) if (newval < ui->span->value()/2)
ui->span->setValueQuiet(newval/2); ui->span->setValueQuiet(newval/2);
if (newval + ui->span->value()/2 > Device::Info().limits_maxFreq) if (newval + ui->span->value()/2 > Device::Info(dev).limits_maxFreq)
ui->span->setValueQuiet((Device::Info().limits_maxFreq - newval)*2); ui->span->setValueQuiet((Device::Info(dev).limits_maxFreq - newval)*2);
newval = ui->frequency->value() - ui->span->value()/2; newval = ui->frequency->value() - ui->span->value()/2;
ui->current->setValueQuiet(newval); ui->current->setValueQuiet(newval);
emit SettingsChanged(); emit SettingsChanged();
@ -49,8 +50,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
connect(ui->span, &SIUnitEdit::valueChanged, [=](double newval) { connect(ui->span, &SIUnitEdit::valueChanged, [=](double newval) {
if(newval < 0 ) { if(newval < 0 ) {
newval = 0; newval = 0;
} else if (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().limits_maxFreq - Device::Info().limits_minFreq; newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq;
} }
ui->span->setValueQuiet(newval); ui->span->setValueQuiet(newval);
@ -59,8 +60,8 @@ SignalgeneratorWidget::SignalgeneratorWidget(QWidget *parent) :
ui->frequency->setValueQuiet(ui->span->value()/2); ui->frequency->setValueQuiet(ui->span->value()/2);
} }
newF = ui->frequency->value() + ui->span->value()/2; newF = ui->frequency->value() + ui->span->value()/2;
if (newF > Device::Info().limits_maxFreq) { if (newF > Device::Info(dev).limits_maxFreq) {
ui->frequency->setValueQuiet(Device::Info().limits_maxFreq - ui->span->value()/2); ui->frequency->setValueQuiet(Device::Info(dev).limits_maxFreq - ui->span->value()/2);
} }
newval = ui->frequency->value() - 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) { connect(ui->current, &SIUnitEdit::valueChanged, [=](double newval) {
if(newval < 0 ) { if(newval < 0 ) {
newval = 0; newval = 0;
} else if (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().limits_maxFreq - Device::Info().limits_minFreq; newval = Device::Info(dev).limits_maxFreq - Device::Info(dev).limits_minFreq;
} }
ui->current->setValueQuiet(newval); ui->current->setValueQuiet(newval);
emit SettingsChanged(); emit SettingsChanged();

View File

@ -15,7 +15,7 @@ class SignalgeneratorWidget : public QWidget, public Savable
Q_OBJECT Q_OBJECT
public: public:
explicit SignalgeneratorWidget(QWidget *parent = nullptr); explicit SignalgeneratorWidget(Device*&dev, QWidget *parent = nullptr);
~SignalgeneratorWidget(); ~SignalgeneratorWidget();
Protocol::GeneratorSettings getDeviceStatus(); Protocol::GeneratorSettings getDeviceStatus();
@ -36,6 +36,7 @@ protected:
private: private:
Ui::SignalgeneratorWidget *ui; Ui::SignalgeneratorWidget *ui;
int m_timerId; int m_timerId;
Device*&dev;
}; };
#endif // SIGNALGENERATOR_H #endif // SIGNALGENERATOR_H

View File

@ -45,9 +45,8 @@
#include <fstream> #include <fstream>
#include <QDateTime> #include <QDateTime>
SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window) SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
: Mode(window, "Spectrum Analyzer"), : Mode(window, name, "SA"),
SCPINode("SA"),
central(new TileWidget(traceModel, window)) central(new TileWidget(traceModel, window))
{ {
averages = 1; averages = 1;
@ -422,6 +421,10 @@ using namespace std;
void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d) void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
{ {
if(Mode::getActiveMode() != this) {
return;
}
if(d.pointNum >= settings.pointNum) { if(d.pointNum >= settings.pointNum) {
qWarning() << "Ignoring point with too large point number (" << d.pointNum << ")"; qWarning() << "Ignoring point with too large point number (" << d.pointNum << ")";
return; return;
@ -555,14 +558,14 @@ void SpectrumAnalyzer::SetStopFreq(double freq)
void SpectrumAnalyzer::SetCenterFreq(double freq) void SpectrumAnalyzer::SetCenterFreq(double freq)
{ {
auto old_span = settings.f_stop - settings.f_start; 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 // would shift start frequency below minimum
settings.f_start = 0; settings.f_start = 0;
settings.f_stop = 2 * freq; 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 // would shift stop frequency above maximum
settings.f_start = 2 * freq - Device::Info().limits_maxFreq; settings.f_start = 2 * freq - Device::Info(window->getDevice()).limits_maxFreq;
settings.f_stop = Device::Info().limits_maxFreq; settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
} else { } else {
settings.f_start = freq - old_span / 2; settings.f_start = freq - old_span / 2;
settings.f_stop = 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) void SpectrumAnalyzer::SetSpan(double span)
{ {
auto old_center = (settings.f_start + settings.f_stop) / 2; 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 // would shift start frequency below minimum
settings.f_start = Device::Info().limits_minFreq; settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
settings.f_stop = Device::Info().limits_minFreq + span; settings.f_stop = Device::Info(window->getDevice()).limits_minFreq + span;
} else if(old_center > Device::Info().limits_maxFreq - span / 2) { } else if(old_center > Device::Info(window->getDevice()).limits_maxFreq - span / 2) {
// would shift stop frequency above maximum // would shift stop frequency above maximum
settings.f_start = Device::Info().limits_maxFreq - span; settings.f_start = Device::Info(window->getDevice()).limits_maxFreq - span;
settings.f_stop = Device::Info().limits_maxFreq; settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
} else { } else {
settings.f_start = old_center - span / 2; settings.f_start = old_center - span / 2;
settings.f_stop = settings.f_start + span; settings.f_stop = settings.f_start + span;
@ -590,8 +593,8 @@ void SpectrumAnalyzer::SetSpan(double span)
void SpectrumAnalyzer::SetFullSpan() void SpectrumAnalyzer::SetFullSpan()
{ {
settings.f_start = Device::Info().limits_minFreq; settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
settings.f_stop = Device::Info().limits_maxFreq; settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
ConstrainAndUpdateFrequencies(); ConstrainAndUpdateFrequencies();
} }
@ -619,10 +622,10 @@ void SpectrumAnalyzer::SpanZoomOut()
void SpectrumAnalyzer::SetRBW(double bandwidth) void SpectrumAnalyzer::SetRBW(double bandwidth)
{ {
if(bandwidth > Device::Info().limits_maxRBW) { if(bandwidth > Device::Info(window->getDevice()).limits_maxRBW) {
bandwidth = Device::Info().limits_maxRBW; bandwidth = Device::Info(window->getDevice()).limits_maxRBW;
} else if(bandwidth < Device::Info().limits_minRBW) { } else if(bandwidth < Device::Info(window->getDevice()).limits_minRBW) {
bandwidth = Device::Info().limits_minRBW; bandwidth = Device::Info(window->getDevice()).limits_minRBW;
} }
settings.RBW = bandwidth; settings.RBW = bandwidth;
emit RBWChanged(settings.RBW); emit RBWChanged(settings.RBW);
@ -690,10 +693,10 @@ void SpectrumAnalyzer::SetTGPort(int port)
void SpectrumAnalyzer::SetTGLevel(double level) void SpectrumAnalyzer::SetTGLevel(double level)
{ {
if(level > Device::Info().limits_cdbm_max / 100.0) { if(level > Device::Info(window->getDevice()).limits_cdbm_max / 100.0) {
level = Device::Info().limits_cdbm_max / 100.0; level = Device::Info(window->getDevice()).limits_cdbm_max / 100.0;
} else if(level < Device::Info().limits_cdbm_min / 100.0) { } else if(level < Device::Info(window->getDevice()).limits_cdbm_min / 100.0) {
level = Device::Info().limits_cdbm_min / 100.0; level = Device::Info(window->getDevice()).limits_cdbm_min / 100.0;
} }
emit TGLevelChanged(level); emit TGLevelChanged(level);
settings.trackingPower = level * 100; settings.trackingPower = level * 100;
@ -1015,24 +1018,24 @@ void SpectrumAnalyzer::UpdateAverageCount()
void SpectrumAnalyzer::ConstrainAndUpdateFrequencies() void SpectrumAnalyzer::ConstrainAndUpdateFrequencies()
{ {
if(settings.f_stop > Device::Info().limits_maxFreq) { if(settings.f_stop > Device::Info(window->getDevice()).limits_maxFreq) {
settings.f_stop = Device::Info().limits_maxFreq; settings.f_stop = Device::Info(window->getDevice()).limits_maxFreq;
} }
if(settings.f_start > settings.f_stop) { if(settings.f_start > settings.f_stop) {
settings.f_start = settings.f_stop; settings.f_start = settings.f_stop;
} }
if(settings.f_start < Device::Info().limits_minFreq) { if(settings.f_start < Device::Info(window->getDevice()).limits_minFreq) {
settings.f_start = Device::Info().limits_minFreq; settings.f_start = Device::Info(window->getDevice()).limits_minFreq;
} }
bool trackingOffset_limited = false; 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; 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; 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) { if(trackingOffset_limited) {
InformationBox::ShowMessage("Warning", "The selected tracking generator offset is not reachable for all frequencies with the current span. " InformationBox::ShowMessage("Warning", "The selected tracking generator offset is not reachable for all frequencies with the current span. "

View File

@ -12,15 +12,17 @@
#include <QComboBox> #include <QComboBox>
#include <QCheckBox> #include <QCheckBox>
class SpectrumAnalyzer : public Mode, public SCPINode class SpectrumAnalyzer : public Mode
{ {
Q_OBJECT Q_OBJECT
public: public:
SpectrumAnalyzer(AppWindow *window); SpectrumAnalyzer(AppWindow *window, QString name = "Spectrum Analyzer");
void deactivate() override; void deactivate() override;
void initializeDevice() 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. // Only save/load user changeable stuff, no need to save the widgets/mode name etc.
virtual nlohmann::json toJSON() override; virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override; virtual void fromJSON(nlohmann::json j) override;

View File

@ -51,9 +51,8 @@
#include <QErrorMessage> #include <QErrorMessage>
#include <QDebug> #include <QDebug>
VNA::VNA(AppWindow *window) VNA::VNA(AppWindow *window, QString name)
: Mode(window, "Vector Network Analyzer"), : Mode(window, name, "VNA"),
SCPINode("VNA"),
deembedding(traceModel), deembedding(traceModel),
deembedding_active(false), deembedding_active(false),
central(new TileWidget(traceModel)) central(new TileWidget(traceModel))
@ -790,6 +789,11 @@ using namespace std;
void VNA::NewDatapoint(Protocol::Datapoint d) void VNA::NewDatapoint(Protocol::Datapoint d)
{ {
if(Mode::getActiveMode() != this) {
// ignore
return;
}
if(changingSettings) { if(changingSettings) {
// already setting new sweep settings, ignore incoming points from old settings // already setting new sweep settings, ignore incoming points from old settings
return; return;
@ -997,14 +1001,14 @@ void VNA::SetStopFreq(double freq)
void VNA::SetCenterFreq(double freq) void VNA::SetCenterFreq(double freq)
{ {
auto old_span = settings.Freq.stop - settings.Freq.start; 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 // would shift start frequency below minimum
settings.Freq.start = 0; settings.Freq.start = 0;
settings.Freq.stop = 2 * freq; 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 // would shift stop frequency above maximum
settings.Freq.start = 2 * freq - Device::Info().limits_maxFreq; settings.Freq.start = 2 * freq - Device::Info(window->getDevice()).limits_maxFreq;
settings.Freq.stop = Device::Info().limits_maxFreq; settings.Freq.stop = Device::Info(window->getDevice()).limits_maxFreq;
} else { } else {
settings.Freq.start = freq - old_span / 2; settings.Freq.start = freq - old_span / 2;
settings.Freq.stop = 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) 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; 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 // would shift start frequency below minimum
settings.Freq.start = Device::Info().limits_minFreq; settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
settings.Freq.stop = Device::Info().limits_minFreq + span; settings.Freq.stop = Device::Info(window->getDevice()).limits_minFreq + span;
} else if(old_center > maxFreq - span / 2) { } else if(old_center > maxFreq - span / 2) {
// would shift stop frequency above maximum // would shift stop frequency above maximum
settings.Freq.start = maxFreq - span; settings.Freq.start = maxFreq - span;
@ -1033,8 +1037,8 @@ void VNA::SetSpan(double span)
void VNA::SetFullSpan() void VNA::SetFullSpan()
{ {
settings.Freq.start = Device::Info().limits_minFreq; settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
settings.Freq.stop = Device::Info().limits_maxFreq; settings.Freq.stop = Device::Info(window->getDevice()).limits_maxFreq;
ConstrainAndUpdateFrequencies(); ConstrainAndUpdateFrequencies();
} }
@ -1072,10 +1076,10 @@ void VNA::SetLogSweep(bool log)
void VNA::SetSourceLevel(double level) void VNA::SetSourceLevel(double level)
{ {
if(level > Device::Info().limits_cdbm_max / 100.0) { if(level > Device::Info(window->getDevice()).limits_cdbm_max / 100.0) {
level = Device::Info().limits_cdbm_max / 100.0; level = Device::Info(window->getDevice()).limits_cdbm_max / 100.0;
} else if(level < Device::Info().limits_cdbm_min / 100.0) { } else if(level < Device::Info(window->getDevice()).limits_cdbm_min / 100.0) {
level = Device::Info().limits_cdbm_min / 100.0; level = Device::Info(window->getDevice()).limits_cdbm_min / 100.0;
} }
emit sourceLevelChanged(level); emit sourceLevelChanged(level);
settings.Freq.excitation_power = level; settings.Freq.excitation_power = level;
@ -1105,15 +1109,15 @@ void VNA::SetPowerSweepFrequency(double freq)
void VNA::SetPoints(unsigned int points) 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) { if(points > maxPoints) {
points = maxPoints; points = maxPoints;
} else if (points < 2) { } else if (points < 2) {
points = 2; points = 2;
} }
if (points > Device::Info().limits_maxPoints) { if (points > Device::Info(window->getDevice()).limits_maxPoints) {
// needs segmented sweep // 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; settings.activeSegment = 0;
} else { } else {
// can fit all points into one segment // can fit all points into one segment
@ -1127,10 +1131,10 @@ void VNA::SetPoints(unsigned int points)
void VNA::SetIFBandwidth(double bandwidth) void VNA::SetIFBandwidth(double bandwidth)
{ {
if(bandwidth > Device::Info().limits_maxIFBW) { if(bandwidth > Device::Info(window->getDevice()).limits_maxIFBW) {
bandwidth = Device::Info().limits_maxIFBW; bandwidth = Device::Info(window->getDevice()).limits_maxIFBW;
} else if(bandwidth < Device::Info().limits_minIFBW) { } else if(bandwidth < Device::Info(window->getDevice()).limits_minIFBW) {
bandwidth = Device::Info().limits_minIFBW; bandwidth = Device::Info(window->getDevice()).limits_minIFBW;
} }
settings.bandwidth = bandwidth; settings.bandwidth = bandwidth;
emit IFBandwidthChanged(settings.bandwidth); emit IFBandwidthChanged(settings.bandwidth);
@ -1478,9 +1482,9 @@ void VNA::ConstrainAndUpdateFrequencies()
auto pref = Preferences::getInstance(); auto pref = Preferences::getInstance();
double maxFreq; double maxFreq;
if(pref.Acquisition.harmonicMixing) { if(pref.Acquisition.harmonicMixing) {
maxFreq = Device::Info().limits_maxFreqHarmonic; maxFreq = Device::Info(window->getDevice()).limits_maxFreqHarmonic;
} else { } else {
maxFreq = Device::Info().limits_maxFreq; maxFreq = Device::Info(window->getDevice()).limits_maxFreq;
} }
if(settings.Freq.stop > maxFreq) { if(settings.Freq.stop > maxFreq) {
settings.Freq.stop = maxFreq; settings.Freq.stop = maxFreq;
@ -1488,8 +1492,8 @@ void VNA::ConstrainAndUpdateFrequencies()
if(settings.Freq.start > settings.Freq.stop) { if(settings.Freq.start > settings.Freq.stop) {
settings.Freq.start = settings.Freq.stop; settings.Freq.start = settings.Freq.stop;
} }
if(settings.Freq.start < Device::Info().limits_minFreq) { if(settings.Freq.start < Device::Info(window->getDevice()).limits_minFreq) {
settings.Freq.start = Device::Info().limits_minFreq; settings.Freq.start = Device::Info(window->getDevice()).limits_minFreq;
} }
emit startFreqChanged(settings.Freq.start); emit startFreqChanged(settings.Freq.start);
emit stopFreqChanged(settings.Freq.stop); emit stopFreqChanged(settings.Freq.stop);

View File

@ -13,17 +13,19 @@
#include <QWidget> #include <QWidget>
#include <functional> #include <functional>
class VNA : public Mode, public SCPINode class VNA : public Mode
{ {
Q_OBJECT Q_OBJECT
public: public:
VNA(AppWindow *window); VNA(AppWindow *window, QString name = "Vector Network Analyzer");
void deactivate() override; void deactivate() override;
void initializeDevice() override; void initializeDevice() override;
void deviceDisconnected() override; void deviceDisconnected() override;
void shutdown() 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. // Only save/load user changeable stuff, no need to save the widgets/mode name etc.
virtual nlohmann::json toJSON() override; virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override; virtual void fromJSON(nlohmann::json j) override;

View File

@ -134,9 +134,9 @@ AppWindow::AppWindow(QWidget *parent)
// Create GUI modes // Create GUI modes
central = new QStackedWidget; central = new QStackedWidget;
setCentralWidget(central); setCentralWidget(central);
vna = new VNA(this); auto vna = new VNA(this);
generator = new Generator(this); auto generator = new Generator(this);
spectrumAnalyzer = new SpectrumAnalyzer(this); auto spectrumAnalyzer = new SpectrumAnalyzer(this);
// UI connections // UI connections
connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList); connect(ui->actionUpdate_Device_List, &QAction::triggered, this, &AppWindow::UpdateDeviceList);
@ -235,7 +235,7 @@ AppWindow::AppWindow(QWidget *parent)
vna->activate(); vna->activate();
qRegisterMetaType<Protocol::Datapoint>("Datapoint"); qRegisterMetaType<Protocol::Datapoint>("Datapoint");
qRegisterMetaType<Protocol::ManualStatus>("Manual"); qRegisterMetaType<Protocol::ManualStatusV1>("ManualV1");
qRegisterMetaType<Protocol::SpectrumAnalyzerResult>("SpectrumAnalyzerResult"); qRegisterMetaType<Protocol::SpectrumAnalyzerResult>("SpectrumAnalyzerResult");
qRegisterMetaType<Protocol::AmplitudeCorrectionPoint>("AmplitudeCorrection"); qRegisterMetaType<Protocol::AmplitudeCorrectionPoint>("AmplitudeCorrection");
@ -278,9 +278,9 @@ void AppWindow::closeEvent(QCloseEvent *event)
if(pref.Startup.UseSetupFile && pref.Startup.AutosaveSetupFile) { if(pref.Startup.UseSetupFile && pref.Startup.AutosaveSetupFile) {
SaveSetup(pref.Startup.SetupFile); SaveSetup(pref.Startup.SetupFile);
} }
vna->shutdown(); for(auto m : Mode::getModes()) {
generator->shutdown(); m->shutdown();
spectrumAnalyzer->shutdown(); }
delete device; delete device;
QSettings settings; QSettings settings;
settings.setValue("geometry", saveGeometry()); settings.setValue("geometry", saveGeometry());
@ -309,7 +309,7 @@ bool AppWindow::ConnectToDevice(QString serial)
UpdateStatusBar(AppWindow::DeviceStatusBar::Connected); UpdateStatusBar(AppWindow::DeviceStatusBar::Connected);
connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine); connect(device, &Device::LogLineReceived, &deviceLog, &DeviceLog::addLine);
connect(device, &Device::ConnectionLost, this, &AppWindow::DeviceConnectionLost); 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); connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate);
ui->actionDisconnect->setEnabled(true); ui->actionDisconnect->setEnabled(true);
ui->actionManual_Control->setEnabled(true); ui->actionManual_Control->setEnabled(true);
@ -465,7 +465,7 @@ void AppWindow::SetupSCPI()
} }
return ""; return "";
}, [=](QStringList) -> QString { }, [=](QStringList) -> QString {
switch(Device::Info().extRefInUse) { switch(Device::StatusV1(getDevice()).extRefInUse) {
case 0: return "INT"; case 0: return "INT";
case 1: return "EXT"; case 1: return "EXT";
default: return "ERROR"; default: return "ERROR";
@ -475,88 +475,89 @@ void AppWindow::SetupSCPI()
if (params.size() != 1) { if (params.size() != 1) {
return "ERROR"; return "ERROR";
} }
Mode *mode = nullptr;
if (params[0] == "VNA") { if (params[0] == "VNA") {
vna->activate(); mode = Mode::findFirstOfType(Mode::Type::VNA);
} else if(params[0] == "GEN") { } else if(params[0] == "GEN") {
generator->activate(); mode = Mode::findFirstOfType(Mode::Type::SG);
} else if(params[0] == "SA") { } else if(params[0] == "SA") {
spectrumAnalyzer->activate(); mode = Mode::findFirstOfType(Mode::Type::SA);
} else { } else {
return "INVALID MDOE"; return "INVALID MDOE";
} }
return ""; if(mode) {
}, [=](QStringList) -> QString { mode->activate();
auto active = Mode::getActiveMode(); return "";
if(active == vna) {
return "VNA";
} else if(active == generator) {
return "GEN";
} else if(active == spectrumAnalyzer) {
return "SA";
} else { } else {
return "ERROR"; 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"); auto scpi_status = new SCPINode("STAtus");
scpi_dev->add(scpi_status); scpi_dev->add(scpi_status);
scpi_status->add(new SCPICommand("UNLOcked", nullptr, [=](QStringList){ 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"; return locked ? "FALSE" : "TRUE";
})); }));
scpi_status->add(new SCPICommand("ADCOVERload", nullptr, [=](QStringList){ 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){ 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"); auto scpi_info = new SCPINode("INFo");
scpi_dev->add(scpi_info); scpi_dev->add(scpi_info);
scpi_info->add(new SCPICommand("FWREVision", nullptr, [=](QStringList){ 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){ 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){ 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"); auto scpi_limits = new SCPINode("LIMits");
scpi_info->add(scpi_limits); scpi_info->add(scpi_limits);
scpi_limits->add(new SCPICommand("MINFrequency", nullptr, [=](QStringList){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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"); auto scpi_manual = new SCPINode("MANual");
scpi_manual->add(new SCPICommand("STArt",[=](QStringList) -> QString { scpi_manual->add(new SCPICommand("STArt",[=](QStringList) -> QString {
StartManualControl(); StartManualControl();
@ -798,6 +799,11 @@ void AppWindow::StopTCPServer()
server = nullptr; server = nullptr;
} }
SCPI* AppWindow::getSCPI()
{
return &scpi;
}
int AppWindow::UpdateDeviceList() int AppWindow::UpdateDeviceList()
{ {
deviceActionGroup->setExclusive(true); deviceActionGroup->setExclusive(true);
@ -918,7 +924,7 @@ void AppWindow::DeviceNeedsUpdate(int reported, int expected)
} }
} }
void AppWindow::DeviceInfoUpdated() void AppWindow::DeviceStatusUpdated()
{ {
UpdateStatusBar(DeviceStatusBar::Updated); UpdateStatusBar(DeviceStatusBar::Updated);
} }
@ -963,10 +969,18 @@ void AppWindow::SaveSetup(QString filename)
nlohmann::json AppWindow::SaveSetup() nlohmann::json AppWindow::SaveSetup()
{ {
nlohmann::json j; nlohmann::json j;
j["activeMode"] = Mode::getActiveMode()->getName().toStdString(); nlohmann::json jm;
j["VNA"] = vna->toJSON(); for(auto m : Mode::getModes()) {
j["Generator"] = generator->toJSON(); nlohmann::json jmode;
j["SpectrumAnalyzer"] = spectrumAnalyzer->toJSON(); 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; nlohmann::json ref;
ref["Mode"] = toolbars.reference.type->currentText().toStdString(); ref["Mode"] = toolbars.reference.type->currentText().toStdString();
ref["Output"] = toolbars.reference.outFreq->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.type->setCurrentText(QString::fromStdString(j["Reference"].value("Mode", "Int")));
toolbars.reference.outFreq->setCurrentText(QString::fromStdString(j["Reference"].value("Output", "Off"))); 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")) { if(j.contains("VNA")) {
auto vna = new VNA(this);
vna->fromJSON(j["VNA"]); vna->fromJSON(j["VNA"]);
} }
if(j.contains("Generator")) { if(j.contains("Generator")) {
auto generator = new Generator(this);
generator->fromJSON(j["Generator"]); generator->fromJSON(j["Generator"]);
} }
if(j.contains("SpectrumAnalyzer")) { if(j.contains("SpectrumAnalyzer")) {
auto spectrumAnalyzer = new SpectrumAnalyzer(this);
spectrumAnalyzer->fromJSON(j["SpectrumAnalyzer"]); 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 // activate the correct mode
QString modeName = QString::fromStdString(j.value("activeMode", "")); QString modeName = QString::fromStdString(j.value("activeMode", ""));
std::vector<Mode*> modes = {vna, generator, spectrumAnalyzer}; for(auto m : Mode::getModes()) {
for(auto m : modes) {
if(m->getName() == modeName) { if(m->getName() == modeName) {
m->activate(); m->activate();
break; break;
@ -1024,7 +1054,7 @@ void AppWindow::LoadSetup(nlohmann::json j)
} }
} }
Device *AppWindow::getDevice() const Device *&AppWindow::getDevice()
{ {
return device; return device;
} }
@ -1104,14 +1134,12 @@ void AppWindow::UpdateStatusBar(DeviceStatusBar status)
break; break;
case DeviceStatusBar::Updated: case DeviceStatusBar::Updated:
lDeviceInfo.setText(device->getLastDeviceInfoString()); lDeviceInfo.setText(device->getLastDeviceInfoString());
lADCOverload.setVisible(device->Info().ADC_overload); lADCOverload.setVisible(device->StatusV1().ADC_overload);
lUnlevel.setVisible(device->Info().unlevel); lUnlevel.setVisible(device->StatusV1().unlevel);
lUnlock.setVisible(!device->Info().LO1_locked || !device->Info().source_locked); lUnlock.setVisible(!device->StatusV1().LO1_locked || !device->StatusV1().source_locked);
break; break;
default: default:
// invalid status // invalid status
break; break;
} }
} }

View File

@ -41,13 +41,15 @@ public:
Ui::MainWindow *getUi() const; Ui::MainWindow *getUi() const;
QStackedWidget *getCentral() const; QStackedWidget *getCentral() const;
Device *getDevice() const; Device*&getDevice();
const QString& getAppVersion() const; const QString& getAppVersion() const;
const QString& getAppGitHash() const; const QString& getAppGitHash() const;
static bool showGUI(); static bool showGUI();
SCPI* getSCPI();
protected: protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
private slots: private slots:
@ -59,7 +61,7 @@ private slots:
void UpdateAcquisitionFrequencies(); void UpdateAcquisitionFrequencies();
void StartFirmwareUpdateDialog(); void StartFirmwareUpdateDialog();
void DeviceNeedsUpdate(int reported, int expected); void DeviceNeedsUpdate(int reported, int expected);
void DeviceInfoUpdated(); void DeviceStatusUpdated();
void SourceCalibrationDialog(); void SourceCalibrationDialog();
void ReceiverCalibrationDialog(); void ReceiverCalibrationDialog();
void FrequencyCalibrationDialog(); void FrequencyCalibrationDialog();
@ -100,11 +102,6 @@ private:
ManualControlDialog *manual; ManualControlDialog *manual;
// Modes
VNA *vna;
Generator *generator;
SpectrumAnalyzer *spectrumAnalyzer;
// Status bar widgets // Status bar widgets
QLabel lConnectionStatus; QLabel lConnectionStatus;
QLabel lDeviceInfo; QLabel lDeviceInfo;

View File

@ -1,44 +1,115 @@
#include "mode.h" #include "mode.h"
#include "Generator/generator.h"
#include "VNA/vna.h"
#include "SpectrumAnalyzer/spectrumanalyzer.h"
#include "CustomWidgets/informationbox.h"
#include "ui_main.h" #include "ui_main.h"
#include <QPushButton> #include <QPushButton>
#include <QSettings> #include <QSettings>
#include <QDebug> #include <QDebug>
#include <QFileDialog> #include <QFileDialog>
#include <QInputDialog>
std::vector<Mode*> Mode::modes;
Mode* Mode::activeMode = nullptr; Mode* Mode::activeMode = nullptr;
QTabBar* Mode::tabbar = nullptr;
QWidget* Mode::cornerWidget = 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), : QObject(window),
SCPINode(SCPIname),
window(window), window(window),
name(name), name(name),
central(nullptr) central(nullptr)
{ {
if(!nameAllowed(name)) {
throw std::runtime_error("Unable to create mode, name already taken");
}
// Create mode switch button // Create mode switch button
auto modeSwitch = new QPushButton(name);
modeSwitch->setCheckable(true);
modeSwitch->setMaximumHeight(window->menuBar()->height());
if(!cornerWidget) { if(!cornerWidget) {
// this is the first created mode, initialize corner widget and set this mode as active // 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->setLayout(new QHBoxLayout);
cornerWidget->layout()->setSpacing(0); cornerWidget->layout()->setSpacing(0);
cornerWidget->layout()->setMargin(0); cornerWidget->layout()->setMargin(0);
cornerWidget->layout()->setContentsMargins(0,0,0,0); cornerWidget->layout()->setContentsMargins(0,0,0,0);
window->menuBar()->setCornerWidget(cornerWidget); cornerWidget->setMaximumHeight(window->menuBar()->height());
modeButtonGroup = new QButtonGroup;
// window->menuBar()->setMaximumHeight(window->menuBar()->height());
}
cornerWidget->layout()->addWidget(modeSwitch);
modeButtonGroup->addButton(modeSwitch);
connect(modeSwitch, &QPushButton::clicked, [=](){ tabbar = new QTabBar;
activate(); 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() void Mode::activate()
@ -89,14 +160,10 @@ void Mode::activate()
} }
activeMode = this; activeMode = this;
// force activation of correct pushbutton in case the mode switch was done via script/setup load. // 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 button, but since it is // 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 // already the active mode, this function will just return -> no recursion
for(auto b : modeButtonGroup->buttons()) { tabbar->setCurrentIndex(findTabIndex());
if(b->text() == name) {
b->click();
}
}
if(window->getDevice()) { if(window->getDevice()) {
initializeDevice(); initializeDevice();
@ -131,6 +198,9 @@ void Mode::deactivate()
} }
qDebug() << "Deactivated mode" << name; qDebug() << "Deactivated mode" << name;
if(window->getDevice()) {
window->getDevice()->SetIdle();
}
activeMode = nullptr; activeMode = nullptr;
} }
@ -139,6 +209,26 @@ Mode *Mode::getActiveMode()
return activeMode; 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() void Mode::saveSreenshot()
{ {
auto filename = QFileDialog::getSaveFileName(nullptr, "Save plot image", "", "PNG image files (*.png)", nullptr, QFileDialog::DontUseNativeDialog); 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); 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) void Mode::finalize(QWidget *centralWidget)
{ {
central = 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) void Mode::setStatusbarMessage(QString msg)
{ {
statusbarMsg = msg; statusbarMsg = msg;
@ -188,3 +320,14 @@ QString Mode::getName() const
{ {
return name; return name;
} }
void Mode::setName(const QString &value)
{
if(!nameAllowed(value)) {
// unable to use this name
return;
}
name = value;
tabbar->setTabText(findTabIndex(), name);
}

View File

@ -3,30 +3,50 @@
#include "appwindow.h" #include "appwindow.h"
#include "savable.h" #include "savable.h"
#include "scpi.h"
#include <QString> #include <QString>
#include <QWidget> #include <QWidget>
#include <QButtonGroup> #include <QButtonGroup>
#include <QToolBar> #include <QToolBar>
#include <QTabBar>
#include <QDockWidget> #include <QDockWidget>
#include <set> #include <set>
class Mode : public QObject, public Savable class Mode : public QObject, public Savable, public SCPINode
{ {
Q_OBJECT Q_OBJECT
public: 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 activate(); // derived classes must call Mode::activate before doing anything
virtual void deactivate(); // derived classes must call Mode::deactivate before returning virtual void deactivate(); // derived classes must call Mode::deactivate before returning
virtual void shutdown(){}; // called when the application is about to exit virtual void shutdown(){}; // called when the application is about to exit
QString getName() const; QString getName() const;
void setName(const QString &value);
static Mode *getActiveMode(); static Mode *getActiveMode();
static QString TypeToName(Type t);
static Type TypeFromName(QString s);
virtual Type getType() = 0;
virtual void initializeDevice() = 0; virtual void initializeDevice() = 0;
virtual void deviceDisconnected(){}; virtual void deviceDisconnected(){};
virtual void saveSreenshot(); 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: signals:
void statusbarMessage(QString msg); void statusbarMessage(QString msg);
protected: protected:
@ -39,10 +59,13 @@ protected:
std::set<QDockWidget*> docks; std::set<QDockWidget*> docks;
private: private:
int findTabIndex();
static std::vector<Mode*> modes;
static Mode *activeMode; static Mode *activeMode;
static QTabBar *tabbar;
static QWidget *cornerWidget; static QWidget *cornerWidget;
static QButtonGroup *modeButtonGroup; // static QButtonGroup *modeButtonGroup;
const QString name; QString name;
QString statusbarMsg; QString statusbarMsg;
QWidget *central; QWidget *central;
}; };

View File

@ -106,6 +106,17 @@ bool SCPINode::add(SCPINode *node)
return true; 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) bool SCPINode::add(SCPICommand *cmd)
{ {
if(nameCollision(cmd->name())) { if(nameCollision(cmd->name())) {

View File

@ -31,6 +31,7 @@ public:
name(name){} name(name){}
bool add(SCPINode *node); bool add(SCPINode *node);
bool remove(SCPINode *node);
bool add(SCPICommand *cmd); bool add(SCPICommand *cmd);
private: private:

View File

@ -6,7 +6,7 @@
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" 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 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 &quot;${INPUTS}&quot;" 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 &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/> <language-scope id="org.eclipse.cdt.core.g++"/>
</provider> </provider>
@ -18,7 +18,7 @@
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" 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 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 &quot;${INPUTS}&quot;" 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 &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/> <language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/> <language-scope id="org.eclipse.cdt.core.g++"/>
</provider> </provider>

View File

@ -117,7 +117,7 @@ inline void App_Process() {
sweepActive = VNA::Setup(recv_packet.settings); sweepActive = VNA::Setup(recv_packet.settings);
Communication::SendWithoutPayload(Protocol::PacketType::Ack); Communication::SendWithoutPayload(Protocol::PacketType::Ack);
break; break;
case Protocol::PacketType::ManualControl: case Protocol::PacketType::ManualControlV1:
sweepActive = false; sweepActive = false;
last_measure_packet = recv_packet; last_measure_packet = recv_packet;
Manual::Setup(recv_packet.manual); Manual::Setup(recv_packet.manual);
@ -145,12 +145,21 @@ inline void App_Process() {
SA::Setup(recv_packet.spectrumSettings); SA::Setup(recv_packet.spectrumSettings);
Communication::SendWithoutPayload(Protocol::PacketType::Ack); Communication::SendWithoutPayload(Protocol::PacketType::Ack);
break; break;
case Protocol::PacketType::RequestDeviceInfo: case Protocol::PacketType::RequestDeviceInfo: {
Communication::SendWithoutPayload(Protocol::PacketType::Ack); Communication::SendWithoutPayload(Protocol::PacketType::Ack);
Protocol::PacketInfo p; Protocol::PacketInfo p;
p.type = Protocol::PacketType::DeviceInfo; p.type = Protocol::PacketType::DeviceInfo;
HW::fillDeviceInfo(&p.info); p.info = HW::Info;
Communication::Send(p); 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; break;
case Protocol::PacketType::SetIdle: case Protocol::PacketType::SetIdle:
HW::SetMode(HW::Mode::Idle); HW::SetMode(HW::Mode::Idle);

View File

@ -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::SweepSettings: payload_size = sizeof(packet.settings); break;
case PacketType::Reference: payload_size = sizeof(packet.reference); break; case PacketType::Reference: payload_size = sizeof(packet.reference); break;
case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break; case PacketType::DeviceInfo: payload_size = sizeof(packet.info); break;
case PacketType::Status: payload_size = sizeof(packet.status); break; case PacketType::DeviceStatusV1: payload_size = sizeof(packet.statusV1); break;
case PacketType::ManualControl: payload_size = sizeof(packet.manual); 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::FirmwarePacket: payload_size = sizeof(packet.firmware); break;
case PacketType::Generator: payload_size = sizeof(packet.generator); break; case PacketType::Generator: payload_size = sizeof(packet.generator); break;
case PacketType::SpectrumAnalyzerSettings: payload_size = sizeof(packet.spectrumSettings); break; case PacketType::SpectrumAnalyzerSettings: payload_size = sizeof(packet.spectrumSettings); break;

View File

@ -4,7 +4,7 @@
namespace Protocol { namespace Protocol {
static constexpr uint16_t Version = 9; static constexpr uint16_t Version = 10;
#pragma pack(push, 1) #pragma pack(push, 1)
@ -50,17 +50,8 @@ using DeviceInfo = struct _deviceInfo {
uint8_t FW_major; uint8_t FW_major;
uint8_t FW_minor; uint8_t FW_minor;
uint8_t FW_patch; uint8_t FW_patch;
uint8_t hardware_version;
char HW_Revision; 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_minFreq;
uint64_t limits_maxFreq; uint64_t limits_maxFreq;
uint32_t limits_minIFBW; uint32_t limits_minIFBW;
@ -74,7 +65,21 @@ using DeviceInfo = struct _deviceInfo {
uint64_t limits_maxFreqHarmonic; 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 port1min, port1max;
int16_t port2min, port2max; int16_t port2min, port2max;
int16_t refmin, refmax; int16_t refmin, refmax;
@ -87,7 +92,7 @@ using ManualStatus = struct _manualstatus {
uint8_t LO_locked :1; uint8_t LO_locked :1;
}; };
using ManualControl = struct _manualControl { using ManualControlV1 = struct _manualControlV1 {
// Highband Source // Highband Source
uint8_t SourceHighCE :1; uint8_t SourceHighCE :1;
uint8_t SourceHighRFEN :1; uint8_t SourceHighRFEN :1;
@ -170,8 +175,8 @@ enum class PacketType : uint8_t {
None = 0, None = 0,
Datapoint = 1, Datapoint = 1,
SweepSettings = 2, SweepSettings = 2,
Status = 3, ManualStatusV1 = 3,
ManualControl = 4, ManualControlV1 = 4,
DeviceInfo = 5, DeviceInfo = 5,
FirmwarePacket = 6, FirmwarePacket = 6,
Ack = 7, Ack = 7,
@ -192,6 +197,8 @@ enum class PacketType : uint8_t {
FrequencyCorrection = 22, FrequencyCorrection = 22,
RequestAcquisitionFrequencySettings = 23, RequestAcquisitionFrequencySettings = 23,
AcquisitionFrequencySettings = 24, AcquisitionFrequencySettings = 24,
DeviceStatusV1 = 25,
RequestDeviceStatus = 26,
}; };
using PacketInfo = struct _packetinfo { using PacketInfo = struct _packetinfo {
@ -201,10 +208,11 @@ using PacketInfo = struct _packetinfo {
SweepSettings settings; SweepSettings settings;
ReferenceSettings reference; ReferenceSettings reference;
GeneratorSettings generator; GeneratorSettings generator;
DeviceStatusV1 statusV1;
DeviceInfo info; DeviceInfo info;
ManualControl manual; ManualControlV1 manual;
FirmwarePacket firmware; FirmwarePacket firmware;
ManualStatus status; ManualStatusV1 manualStatusV1;
SpectrumAnalyzerSettings spectrumSettings; SpectrumAnalyzerSettings spectrumSettings;
SpectrumAnalyzerResult spectrumResult; SpectrumAnalyzerResult spectrumResult;
AmplitudeCorrectionPoint amplitudePoint; AmplitudeCorrectionPoint amplitudePoint;

View File

@ -130,6 +130,17 @@ void FPGA::SetSamplesPerPoint(uint32_t nsamples) {
WriteRegister(Reg::SamplesPerPoint, 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) { void FPGA::Enable(Periphery p, bool enable) {
if (enable) { if (enable) {
SysCtrlReg |= (uint16_t) p; SysCtrlReg |= (uint16_t) p;
@ -282,7 +293,7 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
result.RefI = assembleSampleResultValue(&raw[8]); result.RefI = assembleSampleResultValue(&raw[8]);
result.RefQ = assembleSampleResultValue(&raw[2]); result.RefQ = assembleSampleResultValue(&raw[2]);
result.pointNum = (uint16_t)(raw[38]&0x1F) << 8 | raw[39]; 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); High(CS);
busy_reading = false; busy_reading = false;
if ((status & 0x0004) && callback) { if ((status & 0x0004) && callback) {

View File

@ -17,6 +17,7 @@ enum class Reg {
SystemControl = 0x03, SystemControl = 0x03,
ADCPrescaler = 0x04, ADCPrescaler = 0x04,
PhaseIncrement = 0x05, PhaseIncrement = 0x05,
SweepSetup = 0x06,
MAX2871Def0LSB = 0x08, MAX2871Def0LSB = 0x08,
MAX2871Def0MSB = 0x09, MAX2871Def0MSB = 0x09,
MAX2871Def1LSB = 0x0A, MAX2871Def1LSB = 0x0A,
@ -33,8 +34,8 @@ using SamplingResult = struct _samplingresult {
int64_t P1I, P1Q; int64_t P1I, P1Q;
int64_t P2I, P2Q; int64_t P2I, P2Q;
int64_t RefI, RefQ; int64_t RefI, RefQ;
uint16_t pointNum :15; uint16_t pointNum :13;
uint16_t activePort :1; uint16_t stageNum :3;
}; };
using DFTResult = struct _dftresult { using DFTResult = struct _dftresult {
@ -59,8 +60,7 @@ enum class Periphery {
DebugLED = 0x0080, DebugLED = 0x0080,
SourceChip = 0x0010, SourceChip = 0x0010,
LO1Chip = 0x0008, LO1Chip = 0x0008,
ExcitePort2 = 0x0004,
ExcitePort1 = 0x0002,
PortSwitch = 0x0001, PortSwitch = 0x0001,
}; };
@ -113,6 +113,7 @@ bool Init(HaltedCallback cb = nullptr);
void WriteRegister(FPGA::Reg reg, uint16_t value); void WriteRegister(FPGA::Reg reg, uint16_t value);
void SetNumberOfPoints(uint16_t npoints); void SetNumberOfPoints(uint16_t npoints);
void SetSamplesPerPoint(uint32_t nsamples); 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 Enable(Periphery p, bool enable = true);
void Disable(Periphery p); void Disable(Periphery p);
bool IsEnabled(Periphery p); bool IsEnabled(Periphery p);

View File

@ -11,7 +11,7 @@ void Generator::Setup(Protocol::GeneratorSettings g) {
HW::SetIdle(); HW::SetIdle();
return; return;
} }
Protocol::ManualControl m; Protocol::ManualControlV1 m;
// LOs not required // LOs not required
m.LO1CE = 0; m.LO1CE = 0;
m.LO1Frequency = 1000000000; m.LO1Frequency = 1000000000;

View File

@ -299,9 +299,7 @@ void HW::SetOutputUnlevel(bool unlev) {
unlevel = unlev; unlevel = unlev;
} }
void HW::fillDeviceInfo(Protocol::DeviceInfo *info, bool updateEvenWhenBusy) { void HW::getDeviceStatus(Protocol::DeviceStatusV1 *status, bool updateEvenWhenBusy) {
// copy constant default values
memcpy(info, &HW::Info, sizeof(HW::Info));
if(activeMode == Mode::Idle || updateEvenWhenBusy) { if(activeMode == Mode::Idle || updateEvenWhenBusy) {
// updating values from FPGA allowed // 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 if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT
|| limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT || limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT
|| limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { || limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) {
info->ADC_overload = true; status->ADC_overload = true;
} else { } else {
info->ADC_overload = false; status->ADC_overload = false;
} }
auto status = FPGA::GetStatus(); auto FPGA_status = FPGA::GetStatus();
info->LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1; status->LO1_locked = (FPGA_status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1;
info->source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1; status->source_locked = (FPGA_status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1;
info->extRefAvailable = Ref::available(); status->extRefAvailable = Ref::available();
info->extRefInUse = extRefInUse; status->extRefInUse = extRefInUse;
info->unlevel = unlevel; status->unlevel = unlevel;
info->temp_LO1 = tempLO; status->temp_LO1 = tempLO;
info->temp_source = tempSource; status->temp_source = tempSource;
FPGA::ResetADCLimits(); FPGA::ResetADCLimits();
} }
info->temp_MCU = STM::getTemperature(); status->temp_MCU = STM::getTemperature();
} }
bool HW::Ref::available() { bool HW::Ref::available() {

View File

@ -70,17 +70,8 @@ static constexpr Protocol::DeviceInfo Info = {
.FW_major = FW_MAJOR, .FW_major = FW_MAJOR,
.FW_minor = FW_MINOR, .FW_minor = FW_MINOR,
.FW_patch = FW_PATCH, .FW_patch = FW_PATCH,
.hardware_version = 1,
.HW_Revision = HW_REVISION, .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_minFreq = 0,
.limits_maxFreq = 6000000000, .limits_maxFreq = 6000000000,
.limits_minIFBW = DefaultADCSamplerate / MaxSamples, .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); AmplitudeSettings GetAmplitudeSettings(int16_t cdbm, uint64_t freq = 0, bool applyCorrections = false, bool port2 = false);
bool GetTemps(uint8_t *source, uint8_t *lo); 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 { namespace Ref {
bool available(); bool available();
bool usingExternal(); bool usingExternal();

View File

@ -6,11 +6,11 @@
static bool active = false; static bool active = false;
static uint32_t samples; static uint32_t samples;
static Protocol::ManualStatus status; static Protocol::ManualStatusV1 status;
using namespace HWHAL; using namespace HWHAL;
void Manual::Setup(Protocol::ManualControl m) { void Manual::Setup(Protocol::ManualControlV1 m) {
HW::SetMode(HW::Mode::Manual); HW::SetMode(HW::Mode::Manual);
samples = m.Samples; samples = m.Samples;
FPGA::AbortSweep(); FPGA::AbortSweep();
@ -69,8 +69,7 @@ void Manual::Setup(Protocol::ManualControl m) {
FPGA::Enable(FPGA::Periphery::Port1Mixer, m.Port1EN); FPGA::Enable(FPGA::Periphery::Port1Mixer, m.Port1EN);
FPGA::Enable(FPGA::Periphery::Port2Mixer, m.Port2EN); FPGA::Enable(FPGA::Periphery::Port2Mixer, m.Port2EN);
FPGA::Enable(FPGA::Periphery::RefMixer, m.RefEN); FPGA::Enable(FPGA::Periphery::RefMixer, m.RefEN);
FPGA::Enable(FPGA::Periphery::ExcitePort1, m.PortSwitch == 0); FPGA::SetupSweep(0, m.PortSwitch == 1, m.PortSwitch == 0);
FPGA::Enable(FPGA::Periphery::ExcitePort2, m.PortSwitch == 1);
FPGA::Enable(FPGA::Periphery::PortSwitch); FPGA::Enable(FPGA::Periphery::PortSwitch);
// Enable new data and sweep halt interrupt // Enable new data and sweep halt interrupt
@ -100,38 +99,38 @@ void Manual::Work() {
return; return;
} }
Protocol::PacketInfo p; Protocol::PacketInfo p;
p.type = Protocol::PacketType::Status; p.type = Protocol::PacketType::ManualStatusV1;
p.status = status; p.manualStatusV1 = status;
uint16_t isr_flags = FPGA::GetStatus(); uint16_t isr_flags = FPGA::GetStatus();
if (!(isr_flags & 0x0002)) { if (!(isr_flags & 0x0002)) {
p.status.source_locked = 1; p.manualStatusV1.source_locked = 1;
} else { } else {
p.status.source_locked = 0; p.manualStatusV1.source_locked = 0;
} }
if (!(isr_flags & 0x0001)) { if (!(isr_flags & 0x0001)) {
p.status.LO_locked = 1; p.manualStatusV1.LO_locked = 1;
} else { } else {
p.status.LO_locked = 0; p.manualStatusV1.LO_locked = 0;
} }
auto limits = FPGA::GetADCLimits(); auto limits = FPGA::GetADCLimits();
FPGA::ResetADCLimits(); FPGA::ResetADCLimits();
p.status.port1min = limits.P1min; p.manualStatusV1.port1min = limits.P1min;
p.status.port1max = limits.P1max; p.manualStatusV1.port1max = limits.P1max;
p.status.port2min = limits.P2min; p.manualStatusV1.port2min = limits.P2min;
p.status.port2max = limits.P2max; p.manualStatusV1.port2max = limits.P2max;
p.status.refmin = limits.Rmin; p.manualStatusV1.refmin = limits.Rmin;
p.status.refmax = limits.Rmax; p.manualStatusV1.refmax = limits.Rmax;
HW::GetTemps(&p.status.temp_source, &p.status.temp_LO); HW::GetTemps(&p.manualStatusV1.temp_source, &p.manualStatusV1.temp_LO);
Communication::Send(p); Communication::Send(p);
HW::Ref::update(); HW::Ref::update();
Protocol::PacketInfo packet; Protocol::PacketInfo packet;
packet.type = Protocol::PacketType::DeviceInfo; packet.type = Protocol::PacketType::DeviceStatusV1;
// Enable PLL chips for temperature reading // Enable PLL chips for temperature reading
bool srcEn = FPGA::IsEnabled(FPGA::Periphery::SourceChip); bool srcEn = FPGA::IsEnabled(FPGA::Periphery::SourceChip);
bool LOEn = FPGA::IsEnabled(FPGA::Periphery::LO1Chip); bool LOEn = FPGA::IsEnabled(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::SourceChip); FPGA::Enable(FPGA::Periphery::SourceChip);
FPGA::Enable(FPGA::Periphery::LO1Chip); FPGA::Enable(FPGA::Periphery::LO1Chip);
HW::fillDeviceInfo(&packet.info, true); HW::getDeviceStatus(&packet.statusV1, true);
// restore PLL state // restore PLL state
FPGA::Enable(FPGA::Periphery::SourceChip, srcEn); FPGA::Enable(FPGA::Periphery::SourceChip, srcEn);
FPGA::Enable(FPGA::Periphery::LO1Chip, LOEn); FPGA::Enable(FPGA::Periphery::LO1Chip, LOEn);

View File

@ -5,7 +5,7 @@
namespace Manual { namespace Manual {
void Setup(Protocol::ManualControl m); void Setup(Protocol::ManualControlV1 m);
bool MeasurementDone(const FPGA::SamplingResult &result); bool MeasurementDone(const FPGA::SamplingResult &result);
void Work(); void Work();
void Stop(); void Stop();

View File

@ -209,8 +209,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
FPGA::SetWindow((FPGA::Window) s.WindowType); FPGA::SetWindow((FPGA::Window) s.WindowType);
FPGA::Enable(FPGA::Periphery::LO1Chip); FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF); FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.trackingGeneratorPort == 0); FPGA::SetupSweep(0, s.trackingGeneratorPort == 1, s.trackingGeneratorPort == 0);
FPGA::Enable(FPGA::Periphery::ExcitePort2, s.trackingGeneratorPort == 1);
FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator); FPGA::Enable(FPGA::Periphery::PortSwitch, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator); FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator);
FPGA::Enable(FPGA::Periphery::Port1Mixer); FPGA::Enable(FPGA::Periphery::Port1Mixer);
@ -386,8 +385,8 @@ void SA::Work() {
// send device info every nth point // send device info every nth point
FPGA::Enable(FPGA::Periphery::SourceChip); // needs to enable the chip to get a valid temperature reading FPGA::Enable(FPGA::Periphery::SourceChip); // needs to enable the chip to get a valid temperature reading
Protocol::PacketInfo packet; Protocol::PacketInfo packet;
packet.type = Protocol::PacketType::DeviceInfo; packet.type = Protocol::PacketType::DeviceStatusV1;
HW::fillDeviceInfo(&packet.info, true); HW::getDeviceStatus(&packet.statusV1, true);
FPGA::Disable(FPGA::Periphery::SourceChip); FPGA::Disable(FPGA::Periphery::SourceChip);
Communication::Send(packet); Communication::Send(packet);
} }

View File

@ -21,8 +21,9 @@
static Protocol::SweepSettings settings; static Protocol::SweepSettings settings;
static uint16_t pointCnt; static uint16_t pointCnt;
static uint8_t stageCnt;
static uint8_t stages;
static double logMultiplier, logFrequency; static double logMultiplier, logFrequency;
static bool excitingPort1;
static Protocol::Datapoint data; static Protocol::Datapoint data;
static bool active = false; static bool active = false;
static Si5351C::DriveStrength fixedPowerLowband; static Si5351C::DriveStrength fixedPowerLowband;
@ -278,12 +279,22 @@ bool VNA::Setup(Protocol::SweepSettings s) {
FPGA::Enable(FPGA::Periphery::SourceRF); FPGA::Enable(FPGA::Periphery::SourceRF);
FPGA::Enable(FPGA::Periphery::LO1Chip); FPGA::Enable(FPGA::Periphery::LO1Chip);
FPGA::Enable(FPGA::Periphery::LO1RF); FPGA::Enable(FPGA::Periphery::LO1RF);
FPGA::Enable(FPGA::Periphery::ExcitePort1, s.excitePort1); if(s.excitePort1 && s.excitePort2) {
FPGA::Enable(FPGA::Periphery::ExcitePort2, 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); FPGA::Enable(FPGA::Periphery::PortSwitch);
pointCnt = 0; pointCnt = 0;
// starting port depends on whether port 1 is active in sweep stageCnt = 0;
excitingPort1 = s.excitePort1;
IFTableIndexCnt = 0; IFTableIndexCnt = 0;
adcShifted = false; adcShifted = false;
active = true; active = true;
@ -306,8 +317,8 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
if(!active) { if(!active) {
return false; return false;
} }
if(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.activePort, !excitingPort1); LOG_WARN("Indicated point does not match (%u != %u, %d != %d)", result.pointNum, pointCnt, result.stageNum, stageCnt);
FPGA::AbortSweep(); FPGA::AbortSweep();
return false; return false;
} }
@ -320,29 +331,24 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
data.pointNum = pointCnt; data.pointNum = pointCnt;
data.frequency = getPointFrequency(pointCnt); data.frequency = getPointFrequency(pointCnt);
data.cdbm = settings.cdbm_excitation_start + (settings.cdbm_excitation_stop - settings.cdbm_excitation_start) * pointCnt / (settings.points - 1); 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.real_S11 = port1.real();
data.imag_S11 = port1.imag(); data.imag_S11 = port1.imag();
data.real_S21 = port2.real(); data.real_S21 = port2.real();
data.imag_S21 = port2.imag(); data.imag_S21 = port2.imag();
} else { } else {
// stimulus is present at port 2
data.real_S12 = port1.real(); data.real_S12 = port1.real();
data.imag_S12 = port1.imag(); data.imag_S12 = port1.imag();
data.real_S22 = port2.real(); data.real_S22 = port2.real();
data.imag_S22 = port2.imag(); data.imag_S22 = port2.imag();
} }
// figure out whether this sweep point is complete and which port gets excited next // figure out whether this sweep point is complete
bool pointComplete = false; stageCnt++;
if(settings.excitePort1 == 1 && settings.excitePort2 == 1) { if(stageCnt == stages) {
// point is complete when port 2 was active // point is complete
pointComplete = !excitingPort1; stageCnt = 0;
// next measurement will be from other port
excitingPort1 = !excitingPort1;
} else {
// only one port active, point is complete after every measurement
pointComplete = true;
}
if(pointComplete) {
STM::DispatchToInterrupt(PassOnData); STM::DispatchToInterrupt(PassOnData);
pointCnt++; pointCnt++;
if (pointCnt >= settings.points) { if (pointCnt >= settings.points) {
@ -361,8 +367,8 @@ void VNA::Work() {
HW::Ref::update(); HW::Ref::update();
// Compile info packet // Compile info packet
Protocol::PacketInfo packet; Protocol::PacketInfo packet;
packet.type = Protocol::PacketType::DeviceInfo; packet.type = Protocol::PacketType::DeviceStatusV1;
HW::fillDeviceInfo(&packet.info, true); HW::getDeviceStatus(&packet.statusV1, true);
Communication::Send(packet); Communication::Send(packet);
// do not reset unlevel flag here, as it is calculated only once at the setup of the sweep // do not reset unlevel flag here, as it is calculated only once at the setup of the sweep
// Start next sweep // Start next sweep