Skip to content

Commit

Permalink
New SCPI command: load/save setup files
Browse files Browse the repository at this point in the history
  • Loading branch information
jankae committed Jul 21, 2023
1 parent a697f65 commit 94482fe
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 10 deletions.
Binary file modified Documentation/UserManual/ProgrammingGuide.pdf
Binary file not shown.
17 changes: 16 additions & 1 deletion Documentation/UserManual/ProgrammingGuide.tex
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,22 @@ \subsubsection{DEVice:MODE}
VNA
\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}
\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}
Expand Down Expand Up @@ -563,7 +579,6 @@ \subsubsection{VNA:CALibration:SAVE}
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}

Expand Down
28 changes: 25 additions & 3 deletions Software/PC_Application/LibreVNA-GUI/appwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,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 {
Expand Down Expand Up @@ -1185,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 {
Expand All @@ -1200,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)
Expand Down
2 changes: 1 addition & 1 deletion Software/PC_Application/LibreVNA-GUI/appwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions Software/PC_Application/LibreVNA-GUI/scpi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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 {
Expand Down
7 changes: 5 additions & 2 deletions Software/PC_Application/LibreVNA-GUI/scpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@

class SCPICommand {
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),
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<QString(QStringList)> fn_cmd;
std::function<QString(QStringList)> fn_query;
bool argAlwaysUppercase;
};

class SCPINode {
Expand Down

0 comments on commit 94482fe

Please sign in to comment.