diff --git a/Documentation/UserManual/ProgrammingGuide.pdf b/Documentation/UserManual/ProgrammingGuide.pdf index 7eff4fb..97b6444 100644 Binary files a/Documentation/UserManual/ProgrammingGuide.pdf and b/Documentation/UserManual/ProgrammingGuide.pdf differ diff --git a/Documentation/UserManual/ProgrammingGuide.tex b/Documentation/UserManual/ProgrammingGuide.tex index a3d502a..3f4b66b 100644 --- a/Documentation/UserManual/ProgrammingGuide.tex +++ b/Documentation/UserManual/ProgrammingGuide.tex @@ -212,7 +212,9 @@ Some commands are both events and queries, depending on whether the question mar \section{Commands} \subsection{General Commands} \subsubsection{*IDN} -\query{Returns the identifications string}{*IDN?}{None}{LibreVNA-GUI} +\query{Returns the identifications string}{*IDN?}{None}{LibreVNA,LibreVNA-GUI,dummy\_serial,} +\subsubsection{*OPC} +\query{Returns a 1 after every previous command has been handled}{*OPC?}{None}{1} \subsubsection{*LST} \query{Lists all available commands}{*LST?}{None}{List of commands, separated by newline} \subsection{Device Commands} @@ -249,6 +251,22 @@ This section contains general device commands, available regardless of the curre VNA \end{example} +\subsubsection{DEVice:SETUP:SAVE} +\event{Saves the GUI setup to a file}{DEVice:SETUP:SAVE}{} +Important points when saving/loading setup files through SCPI commands: +\begin{itemize} +\item Filenames must be either absolute or relative to the location of the GUI application. +\item If the LibreVNA-GUI (and thus also the SCPI server) is running on a different machine than the SCPI client, the setup files will be saved/loaded from the machine that runs the GUI. +\item If no (or a wrong) file ending is specified, ``.setup'' is automatically added to the filename. +\end{itemize} + +\subsubsection{DEVice:SETUP:LOAD} +\query{Loads a setup file}{DEVice:SETUP:LOAD?}{}{TRUE or FALSE} +\begin{itemize} +\item Filenames must be either absolute or relative to the location of the GUI application. +\item The filename must include the file ending ``.setup''. +\end{itemize} + \subsubsection{DEVice:REFerence:OUT} \event{Sets the reference output frequency}{DEVice:REFerence:OUT }{ in MHz, either 0 (disabled), 10 or 100} \query{Queries the reference output frequency}{DEVice:REFerence:OUT?}{None}{Output frequency in MHz} @@ -561,7 +579,6 @@ Any number of measurements can be specified (by their number). These measurement Important points when saving/loading calibration files through SCPI commands: \begin{itemize} \item Filenames must be either absolute or relative to the location of the GUI application. -\item SCPI parsing implicitly capitalizes all commands, the file will be saved using only uppercase letters. Similarly, it is not possible to load a file whose filename contains lowercase characters. \item If the LibreVNA-GUI (and thus also the SCPI server) is running on a different machine than the SCPI client, the calibration files will be saved/loaded from the machine that runs the GUI. \end{itemize} diff --git a/Documentation/UserManual/SCPI_Examples/deembedding_test.py b/Documentation/UserManual/SCPI_Examples/deembedding_test.py new file mode 100644 index 0000000..8e748a5 --- /dev/null +++ b/Documentation/UserManual/SCPI_Examples/deembedding_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +import time +from libreVNA import libreVNA + +# Create the control instance +vna = libreVNA('localhost', 19542) + +# Quick connection check (should print "LibreVNA-GUI") +print(vna.query("*IDN?")) + +vna.cmd(":VNA:DEEMB:CLEAR") +vna.cmd(":VNA:DEEMB:NEW PORT_EXTENSION") +vna.cmd(":VNA:DEEMB:NEW 2XTHRU") +vna.cmd(":VNA:DEEMB:NEW MATCHING_NETWORK") +vna.cmd(":VNA:DEEMB:NEW IMPEDANCE_RENORMALIZATION") + +print("Number of total deembedding options:") +num_options = int(vna.query(":VNA:DEEMB:NUM?")) +print(num_options) + +for i in range(1, num_options+1): + option_name = vna.query(":VNA:DEEMB:TYPE? "+str(i)) + print("Option "+str(i)+": "+option_name) + +# edit port extension +vna.cmd(":VNA:DEEMB:1:PORT 2") +vna.cmd(":VNA:DEEMB:1:DELAY 0.00002") +vna.cmd(":VNA:DEEMB:1:DCLOSS 1") +vna.cmd(":VNA:DEEMB:1:LOSS 3") +vna.cmd(":VNA:DEEMB:1:FREQUENCY 5000000000") + +vna.cmd(":VNA:DEEMB:3:PORT 3") +vna.cmd(":VNA:DEEMB:3:CLEAR") +vna.cmd(":VNA:DEEMB:3:ADD FALSE") +vna.cmd(":VNA:DEEMB:3:NEW ParallelC") +vna.cmd(":VNA:DEEMB:3:NEW SeriesR") +vna.cmd(":VNA:DEEMB:3:NEW ParallelL") +vna.cmd(":VNA:DEEMB:3:NEW SeriesL") +vna.cmd(":VNA:DEEMB:3:NEW touchstone_shunt") + +vna.cmd(":VNA:DEEMB:3:1:VALUE 0.0001") +vna.cmd(":VNA:DEEMB:3:2:VALUE 0.00002") +vna.cmd(":VNA:DEEMB:3:3:VALUE 0.000003") +vna.cmd(":VNA:DEEMB:3:4:VALUE 0.000004") + +vna.cmd(":VNA:DEEMB:3:5:FILE TEST.S2P") + +vna.cmd(":VNA:DEEMB:4:IMPedance 75") + diff --git a/Software/PC_Application/LibreVNA-GUI/Device/LibreVNA/librevnausbdriver.cpp b/Software/PC_Application/LibreVNA-GUI/Device/LibreVNA/librevnausbdriver.cpp index d3d7dd8..7a9c33a 100644 --- a/Software/PC_Application/LibreVNA-GUI/Device/LibreVNA/librevnausbdriver.cpp +++ b/Software/PC_Application/LibreVNA-GUI/Device/LibreVNA/librevnausbdriver.cpp @@ -14,6 +14,7 @@ using USBID = struct { static constexpr USBID IDs[] = { {0x0483, 0x564e}, {0x0483, 0x4121}, + {0x1209, 0x4121}, }; USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) : diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp index fc27de9..720ceef 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.cpp +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.cpp @@ -477,7 +477,10 @@ void AppWindow::CreateToolbars() void AppWindow::SetupSCPI() { scpi.add(new SCPICommand("*IDN", nullptr, [=](QStringList){ - return "LibreVNA-GUI"; + return "LibreVNA,LibreVNA-GUI,dummy_serial,"+appVersion; + })); + scpi.add(new SCPICommand("*OPC", nullptr, [=](QStringList){ + return "1"; })); auto scpi_dev = new SCPINode("DEVice"); scpi.add(scpi_dev); @@ -518,6 +521,27 @@ void AppWindow::SetupSCPI() ret.chop(1); return ret; })); + auto scpi_setup = new SCPINode("SETUP"); + scpi_dev->add(scpi_setup); + scpi_setup->add(new SCPICommand("SAVE", [=](QStringList params) -> QString { + if(params.size() != 1) { + // no filename given + return SCPI::getResultName(SCPI::Result::Error); + } + SaveSetup(params[0]); + return SCPI::getResultName(SCPI::Result::Empty); + }, nullptr, false)); + scpi_setup->add(new SCPICommand("LOAD", nullptr, [=](QStringList params) -> QString { + if(params.size() != 1) { + // no filename given + return SCPI::getResultName(SCPI::Result::False); + } + if(!LoadSetup(params[0])) { + // some error when loading the setup file + return SCPI::getResultName(SCPI::Result::False); + } + return SCPI::getResultName(SCPI::Result::True); + }, false)); auto scpi_ref = new SCPINode("REFerence"); scpi_dev->add(scpi_ref); scpi_ref->add(new SCPICommand("OUT", [=](QStringList params) -> QString { @@ -1182,13 +1206,13 @@ nlohmann::json AppWindow::SaveSetup() return j; } -void AppWindow::LoadSetup(QString filename) +bool AppWindow::LoadSetup(QString filename) { ifstream file; file.open(filename.toStdString()); if(!file.is_open()) { qWarning() << "Unable to open file:" << filename; - return; + return false; } nlohmann::json j; try { @@ -1197,12 +1221,13 @@ void AppWindow::LoadSetup(QString filename) InformationBox::ShowError("Error", "Failed to parse the setup file (" + QString(e.what()) + ")"); qWarning() << "Parsing of setup file failed: " << e.what(); file.close(); - return; + return false; } file.close(); LoadSetup(j); QFileInfo fi(filename); lSetupName.setText("Setup: "+fi.fileName()); + return true; } void AppWindow::LoadSetup(nlohmann::json j) diff --git a/Software/PC_Application/LibreVNA-GUI/appwindow.h b/Software/PC_Application/LibreVNA-GUI/appwindow.h index 1db476a..e47376e 100644 --- a/Software/PC_Application/LibreVNA-GUI/appwindow.h +++ b/Software/PC_Application/LibreVNA-GUI/appwindow.h @@ -68,7 +68,7 @@ private slots: void DeviceFlagsUpdated(); void DeviceInfoUpdated(); void SaveSetup(QString filename); - void LoadSetup(QString filename); + bool LoadSetup(QString filename); private: nlohmann::json SaveSetup(); void LoadSetup(nlohmann::json j); diff --git a/Software/PC_Application/LibreVNA-GUI/scpi.cpp b/Software/PC_Application/LibreVNA-GUI/scpi.cpp index cc78f69..4684033 100644 --- a/Software/PC_Application/LibreVNA-GUI/scpi.cpp +++ b/Software/PC_Application/LibreVNA-GUI/scpi.cpp @@ -105,7 +105,6 @@ void SCPI::input(QString line) if(cmd[0] == ':') { cmd.remove(0, 1); } - cmd = cmd.toUpper(); auto response = lastNode->parse(cmd, lastNode); emit output(response); } @@ -274,7 +273,7 @@ QString SCPINode::parse(QString cmd, SCPINode* &lastNode) // have not reached a leaf, find next subnode auto subnode = cmd.left(splitPos); for(auto n : subnodes) { - if(SCPI::match(n->name, subnode)) { + if(SCPI::match(n->name, subnode.toUpper())) { // pass on to next level return n->parse(cmd.right(cmd.size() - splitPos - 1), lastNode); } @@ -292,9 +291,14 @@ QString SCPINode::parse(QString cmd, SCPINode* &lastNode) cmd.chop(1); } for(auto c : commands) { - if(SCPI::match(c->name(), cmd)) { + if(SCPI::match(c->name(), cmd.toUpper())) { // save current node in case of non-root for the next command lastNode = this; + if(c->convertToUppercase()) { + for(auto &p : params) { + p = p.toUpper(); + } + } if(isQuery) { return c->query(params); } else { diff --git a/Software/PC_Application/LibreVNA-GUI/scpi.h b/Software/PC_Application/LibreVNA-GUI/scpi.h index 8a7f37d..f56f92e 100644 --- a/Software/PC_Application/LibreVNA-GUI/scpi.h +++ b/Software/PC_Application/LibreVNA-GUI/scpi.h @@ -8,20 +8,23 @@ class SCPICommand { public: - SCPICommand(QString name, std::function cmd, std::function query) : + SCPICommand(QString name, std::function cmd, std::function query, bool convertToUppercase = true) : _name(name), fn_cmd(cmd), - fn_query(query){} + fn_query(query), + argAlwaysUppercase(convertToUppercase){} QString execute(QStringList params); QString query(QStringList params); QString name() {return _name;} bool queryable() { return fn_query != nullptr;} bool executable() { return fn_cmd != nullptr;} + bool convertToUppercase() { return argAlwaysUppercase;} private: const QString _name; std::function fn_cmd; std::function fn_query; + bool argAlwaysUppercase; }; class SCPINode { diff --git a/Software/VNA_embedded/Application/Drivers/USB/Core/Src/usbd_desc.c b/Software/VNA_embedded/Application/Drivers/USB/Core/Src/usbd_desc.c index 7535574..72c129b 100644 --- a/Software/VNA_embedded/Application/Drivers/USB/Core/Src/usbd_desc.c +++ b/Software/VNA_embedded/Application/Drivers/USB/Core/Src/usbd_desc.c @@ -63,10 +63,10 @@ * @{ */ -#define USBD_VID 0x0483 +#define USBD_VID 0x1209 #define USBD_PID_FS 0x4121 #define USBD_LANGID_STRING 0x0409 -#define USBD_MANUFACTURER_STRING "STMicroelectronics" +#define USBD_MANUFACTURER_STRING "LibreVNA" #define USBD_PRODUCT_STRING_FS "VNA" #define USBD_CONFIGURATION_STRING_FS "CustomUSBDevice Config" #define USBD_INTERFACE_STRING_FS "CustomUSBDevice Interface"