Merge branch 'master' of github.com:jankae/LibreVNA
This commit is contained in:
commit
175cade3da
Binary file not shown.
@ -212,7 +212,9 @@ Some commands are both events and queries, depending on whether the question mar
|
|||||||
\section{Commands}
|
\section{Commands}
|
||||||
\subsection{General Commands}
|
\subsection{General Commands}
|
||||||
\subsubsection{*IDN}
|
\subsubsection{*IDN}
|
||||||
\query{Returns the identifications string}{*IDN?}{None}{LibreVNA-GUI}
|
\query{Returns the identifications string}{*IDN?}{None}{LibreVNA,LibreVNA-GUI,dummy\_serial,<software version>}
|
||||||
|
\subsubsection{*OPC}
|
||||||
|
\query{Returns a 1 after every previous command has been handled}{*OPC?}{None}{1}
|
||||||
\subsubsection{*LST}
|
\subsubsection{*LST}
|
||||||
\query{Lists all available commands}{*LST?}{None}{List of commands, separated by newline}
|
\query{Lists all available commands}{*LST?}{None}{List of commands, separated by newline}
|
||||||
\subsection{Device Commands}
|
\subsection{Device Commands}
|
||||||
@ -249,6 +251,22 @@ This section contains general device commands, available regardless of the curre
|
|||||||
VNA
|
VNA
|
||||||
\end{example}
|
\end{example}
|
||||||
|
|
||||||
|
\subsubsection{DEVice:SETUP:SAVE}
|
||||||
|
\event{Saves the GUI setup to a file}{DEVice:SETUP:SAVE}{<filename>}
|
||||||
|
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?}{<filename>}{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}
|
\subsubsection{DEVice:REFerence:OUT}
|
||||||
\event{Sets the reference output frequency}{DEVice:REFerence:OUT <freq>}{<freq> in MHz, either 0 (disabled), 10 or 100}
|
\event{Sets the reference output frequency}{DEVice:REFerence:OUT <freq>}{<freq> in MHz, either 0 (disabled), 10 or 100}
|
||||||
\query{Queries the reference output frequency}{DEVice:REFerence:OUT?}{None}{Output frequency in MHz}
|
\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:
|
Important points when saving/loading calibration files through SCPI commands:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Filenames must be either absolute or relative to the location of the GUI application.
|
\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.
|
\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}
|
\end{itemize}
|
||||||
|
|
||||||
|
50
Documentation/UserManual/SCPI_Examples/deembedding_test.py
Normal file
50
Documentation/UserManual/SCPI_Examples/deembedding_test.py
Normal file
@ -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")
|
||||||
|
|
@ -14,6 +14,7 @@ using USBID = struct {
|
|||||||
static constexpr USBID IDs[] = {
|
static constexpr USBID IDs[] = {
|
||||||
{0x0483, 0x564e},
|
{0x0483, 0x564e},
|
||||||
{0x0483, 0x4121},
|
{0x0483, 0x4121},
|
||||||
|
{0x1209, 0x4121},
|
||||||
};
|
};
|
||||||
|
|
||||||
USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) :
|
USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, int buffer_size) :
|
||||||
|
@ -477,7 +477,10 @@ void AppWindow::CreateToolbars()
|
|||||||
void AppWindow::SetupSCPI()
|
void AppWindow::SetupSCPI()
|
||||||
{
|
{
|
||||||
scpi.add(new SCPICommand("*IDN", nullptr, [=](QStringList){
|
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");
|
auto scpi_dev = new SCPINode("DEVice");
|
||||||
scpi.add(scpi_dev);
|
scpi.add(scpi_dev);
|
||||||
@ -518,6 +521,27 @@ void AppWindow::SetupSCPI()
|
|||||||
ret.chop(1);
|
ret.chop(1);
|
||||||
return ret;
|
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");
|
auto scpi_ref = new SCPINode("REFerence");
|
||||||
scpi_dev->add(scpi_ref);
|
scpi_dev->add(scpi_ref);
|
||||||
scpi_ref->add(new SCPICommand("OUT", [=](QStringList params) -> QString {
|
scpi_ref->add(new SCPICommand("OUT", [=](QStringList params) -> QString {
|
||||||
@ -1182,13 +1206,13 @@ nlohmann::json AppWindow::SaveSetup()
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppWindow::LoadSetup(QString filename)
|
bool AppWindow::LoadSetup(QString filename)
|
||||||
{
|
{
|
||||||
ifstream file;
|
ifstream file;
|
||||||
file.open(filename.toStdString());
|
file.open(filename.toStdString());
|
||||||
if(!file.is_open()) {
|
if(!file.is_open()) {
|
||||||
qWarning() << "Unable to open file:" << filename;
|
qWarning() << "Unable to open file:" << filename;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
try {
|
try {
|
||||||
@ -1197,12 +1221,13 @@ void AppWindow::LoadSetup(QString filename)
|
|||||||
InformationBox::ShowError("Error", "Failed to parse the setup file (" + QString(e.what()) + ")");
|
InformationBox::ShowError("Error", "Failed to parse the setup file (" + QString(e.what()) + ")");
|
||||||
qWarning() << "Parsing of setup file failed: " << e.what();
|
qWarning() << "Parsing of setup file failed: " << e.what();
|
||||||
file.close();
|
file.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
LoadSetup(j);
|
LoadSetup(j);
|
||||||
QFileInfo fi(filename);
|
QFileInfo fi(filename);
|
||||||
lSetupName.setText("Setup: "+fi.fileName());
|
lSetupName.setText("Setup: "+fi.fileName());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppWindow::LoadSetup(nlohmann::json j)
|
void AppWindow::LoadSetup(nlohmann::json j)
|
||||||
|
@ -68,7 +68,7 @@ private slots:
|
|||||||
void DeviceFlagsUpdated();
|
void DeviceFlagsUpdated();
|
||||||
void DeviceInfoUpdated();
|
void DeviceInfoUpdated();
|
||||||
void SaveSetup(QString filename);
|
void SaveSetup(QString filename);
|
||||||
void LoadSetup(QString filename);
|
bool LoadSetup(QString filename);
|
||||||
private:
|
private:
|
||||||
nlohmann::json SaveSetup();
|
nlohmann::json SaveSetup();
|
||||||
void LoadSetup(nlohmann::json j);
|
void LoadSetup(nlohmann::json j);
|
||||||
|
@ -105,7 +105,6 @@ void SCPI::input(QString line)
|
|||||||
if(cmd[0] == ':') {
|
if(cmd[0] == ':') {
|
||||||
cmd.remove(0, 1);
|
cmd.remove(0, 1);
|
||||||
}
|
}
|
||||||
cmd = cmd.toUpper();
|
|
||||||
auto response = lastNode->parse(cmd, lastNode);
|
auto response = lastNode->parse(cmd, lastNode);
|
||||||
emit output(response);
|
emit output(response);
|
||||||
}
|
}
|
||||||
@ -274,7 +273,7 @@ QString SCPINode::parse(QString cmd, SCPINode* &lastNode)
|
|||||||
// have not reached a leaf, find next subnode
|
// have not reached a leaf, find next subnode
|
||||||
auto subnode = cmd.left(splitPos);
|
auto subnode = cmd.left(splitPos);
|
||||||
for(auto n : subnodes) {
|
for(auto n : subnodes) {
|
||||||
if(SCPI::match(n->name, subnode)) {
|
if(SCPI::match(n->name, subnode.toUpper())) {
|
||||||
// pass on to next level
|
// pass on to next level
|
||||||
return n->parse(cmd.right(cmd.size() - splitPos - 1), lastNode);
|
return n->parse(cmd.right(cmd.size() - splitPos - 1), lastNode);
|
||||||
}
|
}
|
||||||
@ -292,9 +291,14 @@ QString SCPINode::parse(QString cmd, SCPINode* &lastNode)
|
|||||||
cmd.chop(1);
|
cmd.chop(1);
|
||||||
}
|
}
|
||||||
for(auto c : commands) {
|
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
|
// save current node in case of non-root for the next command
|
||||||
lastNode = this;
|
lastNode = this;
|
||||||
|
if(c->convertToUppercase()) {
|
||||||
|
for(auto &p : params) {
|
||||||
|
p = p.toUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
if(isQuery) {
|
if(isQuery) {
|
||||||
return c->query(params);
|
return c->query(params);
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,20 +8,23 @@
|
|||||||
|
|
||||||
class SCPICommand {
|
class SCPICommand {
|
||||||
public:
|
public:
|
||||||
SCPICommand(QString name, std::function<QString(QStringList)> cmd, std::function<QString(QStringList)> query) :
|
SCPICommand(QString name, std::function<QString(QStringList)> cmd, std::function<QString(QStringList)> query, bool convertToUppercase = true) :
|
||||||
_name(name),
|
_name(name),
|
||||||
fn_cmd(cmd),
|
fn_cmd(cmd),
|
||||||
fn_query(query){}
|
fn_query(query),
|
||||||
|
argAlwaysUppercase(convertToUppercase){}
|
||||||
|
|
||||||
QString execute(QStringList params);
|
QString execute(QStringList params);
|
||||||
QString query(QStringList params);
|
QString query(QStringList params);
|
||||||
QString name() {return _name;}
|
QString name() {return _name;}
|
||||||
bool queryable() { return fn_query != nullptr;}
|
bool queryable() { return fn_query != nullptr;}
|
||||||
bool executable() { return fn_cmd != nullptr;}
|
bool executable() { return fn_cmd != nullptr;}
|
||||||
|
bool convertToUppercase() { return argAlwaysUppercase;}
|
||||||
private:
|
private:
|
||||||
const QString _name;
|
const QString _name;
|
||||||
std::function<QString(QStringList)> fn_cmd;
|
std::function<QString(QStringList)> fn_cmd;
|
||||||
std::function<QString(QStringList)> fn_query;
|
std::function<QString(QStringList)> fn_query;
|
||||||
|
bool argAlwaysUppercase;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SCPINode {
|
class SCPINode {
|
||||||
|
@ -63,10 +63,10 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define USBD_VID 0x0483
|
#define USBD_VID 0x1209
|
||||||
#define USBD_PID_FS 0x4121
|
#define USBD_PID_FS 0x4121
|
||||||
#define USBD_LANGID_STRING 0x0409
|
#define USBD_LANGID_STRING 0x0409
|
||||||
#define USBD_MANUFACTURER_STRING "STMicroelectronics"
|
#define USBD_MANUFACTURER_STRING "LibreVNA"
|
||||||
#define USBD_PRODUCT_STRING_FS "VNA"
|
#define USBD_PRODUCT_STRING_FS "VNA"
|
||||||
#define USBD_CONFIGURATION_STRING_FS "CustomUSBDevice Config"
|
#define USBD_CONFIGURATION_STRING_FS "CustomUSBDevice Config"
|
||||||
#define USBD_INTERFACE_STRING_FS "CustomUSBDevice Interface"
|
#define USBD_INTERFACE_STRING_FS "CustomUSBDevice Interface"
|
||||||
|
Loading…
Reference in New Issue
Block a user