New SCPI command: load/save setup files
This commit is contained in:
parent
a697f65de6
commit
94482fe151
Binary file not shown.
@ -251,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}
|
||||||
@ -563,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}
|
||||||
|
|
||||||
|
@ -521,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 {
|
||||||
@ -1185,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 {
|
||||||
@ -1200,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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user