mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-01-23 09:00:27 +01:00
implementation of OPC/WAI
This commit is contained in:
parent
bb66883de2
commit
5d3ce139b4
|
|
@ -333,6 +333,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window, QString name)
|
|||
|
||||
void SpectrumAnalyzer::deactivate()
|
||||
{
|
||||
setOperationPending(false);
|
||||
StoreSweepSettings();
|
||||
Mode::deactivate();
|
||||
}
|
||||
|
|
@ -503,6 +504,9 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m)
|
|||
}
|
||||
|
||||
auto m_avg = average.process(m);
|
||||
if(average.settled()) {
|
||||
setOperationPending(false);
|
||||
}
|
||||
|
||||
if(settings.freqStart == settings.freqStop) {
|
||||
// keep track of first point time
|
||||
|
|
@ -560,6 +564,7 @@ void SpectrumAnalyzer::NewDatapoint(DeviceDriver::SAMeasurement m)
|
|||
|
||||
void SpectrumAnalyzer::SettingsChanged()
|
||||
{
|
||||
setOperationPending(true);
|
||||
configurationTimer.start(100);
|
||||
ResetLiveTraces();
|
||||
}
|
||||
|
|
@ -703,6 +708,7 @@ void SpectrumAnalyzer::SetAveraging(unsigned int averages)
|
|||
average.setAverages(averages);
|
||||
emit averagingChanged(averages);
|
||||
UpdateAverageCount();
|
||||
setOperationPending(!average.settled());
|
||||
}
|
||||
|
||||
void SpectrumAnalyzer::SetTGEnabled(bool enabled)
|
||||
|
|
@ -887,6 +893,7 @@ void SpectrumAnalyzer::ConfigureDevice()
|
|||
|
||||
void SpectrumAnalyzer::ResetLiveTraces()
|
||||
{
|
||||
setOperationPending(true);
|
||||
average.reset(DeviceDriver::SApoints());
|
||||
traceModel.clearLiveData();
|
||||
UpdateAverageCount();
|
||||
|
|
|
|||
|
|
@ -692,6 +692,7 @@ QString VNA::getCalToolTip()
|
|||
|
||||
void VNA::deactivate()
|
||||
{
|
||||
setOperationPending(false);
|
||||
StoreSweepSettings();
|
||||
Mode::deactivate();
|
||||
}
|
||||
|
|
@ -901,6 +902,9 @@ void VNA::NewDatapoint(DeviceDriver::VNAMeasurement m)
|
|||
}
|
||||
|
||||
m_avg = average.process(m_avg);
|
||||
if(average.settled()) {
|
||||
setOperationPending(false);
|
||||
}
|
||||
|
||||
if(calMeasuring) {
|
||||
if(average.currentSweep() == averages) {
|
||||
|
|
@ -979,6 +983,7 @@ void VNA::UpdateAverageCount()
|
|||
|
||||
void VNA::SettingsChanged(bool resetTraces, int delay)
|
||||
{
|
||||
setOperationPending(true);
|
||||
configurationTimer.start(delay);
|
||||
changingSettings = true;
|
||||
configurationTimerResetTraces = resetTraces;
|
||||
|
|
@ -1218,6 +1223,7 @@ void VNA::SetAveraging(unsigned int averages)
|
|||
average.setAverages(averages);
|
||||
emit averagingChanged(averages);
|
||||
UpdateAverageCount();
|
||||
setOperationPending(!average.settled());
|
||||
}
|
||||
|
||||
void VNA::ExcitationRequired()
|
||||
|
|
@ -1317,7 +1323,6 @@ void VNA::SetupSCPI()
|
|||
if(params.size() >= 1) {
|
||||
if(params[0] == "FREQUENCY") {
|
||||
SetSweepType(SweepType::Frequency);
|
||||
ResetLiveTraces();
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
} else if(params[0] == "POWER") {
|
||||
SetSweepType(SweepType::Power);
|
||||
|
|
@ -1378,7 +1383,6 @@ void VNA::SetupSCPI()
|
|||
scpi_freq->add(new SCPICommand("FULL", [=](QStringList params) -> QString {
|
||||
Q_UNUSED(params)
|
||||
SetFullSpan();
|
||||
ResetLiveTraces();
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
}, nullptr));
|
||||
scpi_freq->add(new SCPICommand("ZERO", [=](QStringList params) -> QString {
|
||||
|
|
@ -1449,7 +1453,7 @@ void VNA::SetupSCPI()
|
|||
return QString::number(average.getLevel());
|
||||
}));
|
||||
scpi_acq->add(new SCPICommand("FINished", nullptr, [=](QStringList) -> QString {
|
||||
return average.getLevel() == averages ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
||||
return average.settled() ? SCPI::getResultName(SCPI::Result::True) : SCPI::getResultName(SCPI::Result::False);
|
||||
}));
|
||||
scpi_acq->add(new SCPICommand("LIMit", nullptr, [=](QStringList) -> QString {
|
||||
return tiles->allLimitsPassing() ? "PASS" : "FAIL";
|
||||
|
|
@ -1855,6 +1859,7 @@ void VNA::ResetLiveTraces()
|
|||
traceModel.clearLiveData();
|
||||
UpdateAverageCount();
|
||||
UpdateCalWidget();
|
||||
setOperationPending(true);
|
||||
}
|
||||
|
||||
bool VNA::LoadCalibration(QString filename)
|
||||
|
|
|
|||
|
|
@ -490,9 +490,6 @@ void AppWindow::SetupSCPI()
|
|||
SetInitialState();
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
}, nullptr));
|
||||
scpi.add(new SCPICommand("*OPC", nullptr, [=](QStringList){
|
||||
return "1";
|
||||
}));
|
||||
auto scpi_dev = new SCPINode("DEVice");
|
||||
scpi.add(scpi_dev);
|
||||
scpi_dev->add(new SCPICommand("DISConnect", [=](QStringList params) -> QString {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ unsigned int Averaging::currentSweep()
|
|||
}
|
||||
}
|
||||
|
||||
bool Averaging::settled()
|
||||
{
|
||||
return getLevel() == averages;
|
||||
}
|
||||
|
||||
Averaging::Mode Averaging::getMode() const
|
||||
{
|
||||
return mode;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public:
|
|||
// Returns the number of the currently active sweep. Value is incremented whenever the the first point of the sweep is added
|
||||
// Returned values are in range 0 (when no data has been added yet) to averages
|
||||
unsigned int currentSweep();
|
||||
// Returns true if all required averages have been taken
|
||||
bool settled();
|
||||
Mode getMode() const;
|
||||
void setMode(const Mode &value);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,40 @@
|
|||
SCPI::SCPI() :
|
||||
SCPINode("")
|
||||
{
|
||||
WAIexecuting = false;
|
||||
OPCQueryScheduled = false;
|
||||
OCAS = false;
|
||||
ESR = 0x00;
|
||||
|
||||
add(new SCPICommand("*OPC", [=](QStringList){
|
||||
// OPC command
|
||||
if(isOperationPending()) {
|
||||
OCAS = true;
|
||||
}
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
}, [=](QStringList) -> QString {
|
||||
// OPC query
|
||||
if(isOperationPending()) {
|
||||
// operation pending
|
||||
OPCQueryScheduled = true;
|
||||
OCAS = true;
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
} else {
|
||||
// no operation, can return immediately
|
||||
OCAS = false;
|
||||
setFlag(Flag::OPC);
|
||||
return "1";
|
||||
}
|
||||
}));
|
||||
|
||||
add(new SCPICommand("*WAI", [=](QStringList){
|
||||
// WAI command
|
||||
if(isOperationPending()) {
|
||||
WAIexecuting = true;
|
||||
}
|
||||
return SCPI::getResultName(SCPI::Result::Empty);
|
||||
}, nullptr));
|
||||
|
||||
add(new SCPICommand("*LST", nullptr, [=](QStringList){
|
||||
QString list;
|
||||
createCommandList("", list);
|
||||
|
|
@ -95,23 +129,68 @@ QString SCPI::getResultName(SCPI::Result r)
|
|||
|
||||
void SCPI::input(QString line)
|
||||
{
|
||||
auto cmds = line.split(";");
|
||||
SCPINode *lastNode = this;
|
||||
for(auto cmd : cmds) {
|
||||
if(cmd.size() > 0) {
|
||||
if(cmd[0] == ':' || cmd[0] == '*') {
|
||||
// reset to root node
|
||||
lastNode = this;
|
||||
cmdQueue.append(line);
|
||||
process();
|
||||
}
|
||||
|
||||
void SCPI::process()
|
||||
{
|
||||
while(!WAIexecuting && !cmdQueue.isEmpty()) {
|
||||
auto cmd = cmdQueue.front();
|
||||
cmdQueue.pop_front();
|
||||
auto cmds = cmd.split(";");
|
||||
SCPINode *lastNode = this;
|
||||
for(auto cmd : cmds) {
|
||||
if(cmd.size() > 0) {
|
||||
if(cmd[0] == ':' || cmd[0] == '*') {
|
||||
// reset to root node
|
||||
lastNode = this;
|
||||
}
|
||||
if(cmd[0] == ':') {
|
||||
cmd.remove(0, 1);
|
||||
}
|
||||
auto response = lastNode->parse(cmd, lastNode);
|
||||
emit output(response);
|
||||
}
|
||||
if(cmd[0] == ':') {
|
||||
cmd.remove(0, 1);
|
||||
}
|
||||
auto response = lastNode->parse(cmd, lastNode);
|
||||
emit output(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SCPI::someOperationCompleted()
|
||||
{
|
||||
if(!isOperationPending()) {
|
||||
// all operations are complete
|
||||
if(OCAS) {
|
||||
OCAS = false;
|
||||
setFlag(Flag::OPC);
|
||||
if(OPCQueryScheduled) {
|
||||
output("1");
|
||||
OPCQueryScheduled = false;
|
||||
}
|
||||
}
|
||||
if(WAIexecuting) {
|
||||
WAIexecuting = false;
|
||||
// process any queued commands
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SCPI::setFlag(Flag flag)
|
||||
{
|
||||
ESR |= ((int) flag);
|
||||
}
|
||||
|
||||
void SCPI::clearFlag(Flag flag)
|
||||
{
|
||||
ESR &= ~((int) flag);
|
||||
}
|
||||
|
||||
bool SCPI::getFlag(Flag flag)
|
||||
{
|
||||
return ESR & (int) flag;
|
||||
}
|
||||
|
||||
SCPINode::~SCPINode()
|
||||
{
|
||||
if(parent) {
|
||||
|
|
@ -235,6 +314,36 @@ bool SCPINode::changeName(QString newname)
|
|||
return true;
|
||||
}
|
||||
|
||||
void SCPINode::setOperationPending(bool pending)
|
||||
{
|
||||
if(operationPending != pending) {
|
||||
operationPending = pending;
|
||||
if(!operationPending) {
|
||||
// operation completed, needs to perform check if all operations are complete
|
||||
auto root = this;
|
||||
while(root->parent) {
|
||||
root = root->parent;
|
||||
}
|
||||
auto scpi = static_cast<SCPI*>(root);
|
||||
scpi->someOperationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SCPINode::isOperationPending()
|
||||
{
|
||||
if(operationPending) {
|
||||
return true;
|
||||
}
|
||||
for(auto node : subnodes) {
|
||||
if(node->isOperationPending()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// no node has any pending operations
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SCPINode::nameCollision(QString name)
|
||||
{
|
||||
for(auto n : subnodes) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class SCPINode {
|
|||
friend class SCPI;
|
||||
public:
|
||||
SCPINode(QString name) :
|
||||
name(name), parent(nullptr){}
|
||||
name(name), parent(nullptr), operationPending(false){}
|
||||
virtual ~SCPINode();
|
||||
|
||||
bool add(SCPINode *node);
|
||||
|
|
@ -44,6 +44,11 @@ public:
|
|||
|
||||
bool changeName(QString newname);
|
||||
|
||||
protected:
|
||||
void setOperationPending(bool pending);
|
||||
|
||||
bool isOperationPending();
|
||||
|
||||
private:
|
||||
QString parse(QString cmd, SCPINode* &lastNode);
|
||||
bool nameCollision(QString name);
|
||||
|
|
@ -52,6 +57,7 @@ private:
|
|||
std::vector<SCPINode*> subnodes;
|
||||
std::vector<SCPICommand*> commands;
|
||||
SCPINode *parent;
|
||||
bool operationPending;
|
||||
};
|
||||
|
||||
class SCPI : public QObject, public SCPINode
|
||||
|
|
@ -77,10 +83,39 @@ public:
|
|||
|
||||
static QString getResultName(SCPI::Result r);
|
||||
|
||||
// call whenever a subnode completes an operation
|
||||
void someOperationCompleted();
|
||||
|
||||
public slots:
|
||||
void input(QString line);
|
||||
void process();
|
||||
signals:
|
||||
void output(QString line);
|
||||
|
||||
private:
|
||||
|
||||
enum class Flag {
|
||||
OPC = 0x01, // Operation complete
|
||||
RQC = 0x02, // device wants to become the controller (of the bus)
|
||||
QYE = 0x04, // query error
|
||||
DDE = 0x08, // device-dependent error
|
||||
EXE = 0x10, // execution error
|
||||
CME = 0x20, // command error
|
||||
URQ = 0x40, // user request
|
||||
PON = 0x80, // power on
|
||||
};
|
||||
|
||||
void setFlag(Flag flag);
|
||||
void clearFlag(Flag flag);
|
||||
bool getFlag(Flag flag);
|
||||
|
||||
unsigned int ESR;
|
||||
|
||||
bool OCAS;
|
||||
bool OPCQueryScheduled;
|
||||
bool WAIexecuting;
|
||||
|
||||
QList<QString> cmdQueue;
|
||||
};
|
||||
|
||||
#endif // SCPI_H
|
||||
|
|
|
|||
Loading…
Reference in a new issue