From 9895d4618cb26f55d8e5149dc5d2b01dcf1783ab Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Fri, 16 Sep 2022 08:54:55 +0100 Subject: [PATCH] VISA: Add methods to get available resources. Make I/O logging optional. Check for errors in processCommands. --- sdrbase/util/visa.cpp | 113 +++++++++++++++++++++++++++++++++++++++--- sdrbase/util/visa.h | 25 +++++++++- 2 files changed, 131 insertions(+), 7 deletions(-) diff --git a/sdrbase/util/visa.cpp b/sdrbase/util/visa.cpp index 6cc01935d..bd5a5d982 100644 --- a/sdrbase/util/visa.cpp +++ b/sdrbase/util/visa.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "visa.h" @@ -48,6 +49,8 @@ VISA::VISA() : viClose = (ViStatus (*)(ViObject vi)) libraryFunc(visaLibrary, "viClose"); viPrintf = (ViStatus (*) (ViSession vi, ViString writeFmt, ...)) libraryFunc(visaLibrary, "viPrintf"); viScanf = (ViStatus (*) (ViSession vi, ViString writeFmt, ...)) libraryFunc(visaLibrary, "viScanf"); + viFindRsrc = (ViStatus (*) (ViSession vi, ViString expr, ViPFindList li, ViPUInt32 retCnt, ViChar desc[])) libraryFunc(visaLibrary, "viFindRsrc"); + viFindNext = (ViStatus (*) (ViSession vi, ViChar desc[])) libraryFunc(visaLibrary, "viFindNext"); if (viOpenDefaultRM && viOpen && viClose && viPrintf) { m_available = true; @@ -106,32 +109,130 @@ void VISA::close(ViSession session) } } -QStringList VISA::processCommands(ViSession session, const QString& commands) +QStringList VISA::processCommands(ViSession session, const QString& commands, bool *error) { QStringList list = commands.split("\n"); QStringList results; + ViStatus status; + + if (error) { + *error = false; + } for (int i = 0; i < list.size(); i++) { QString command = list[i].trimmed(); if (!command.isEmpty() && !command.startsWith("#")) // Allow # to comment out lines { - qDebug() << "VISA ->: " << command; + if (m_debugIO) { + qDebug() << "VISA ->: " << command; + } QByteArray bytes = QString("%1\n").arg(command).toLatin1(); char *cmd = bytes.data(); - viPrintf(session, cmd); - if (command.endsWith("?")) + status = viPrintf(session, cmd); + if (error && status) { + *error = true; + } + if (command.contains("?")) { char buf[1024] = ""; char format[] = "%t"; - viScanf(session, format, buf); + status = viScanf(session, format, buf); + if (error && status) { + *error = true; + } results.append(buf); - qDebug() << "VISA <-: " << QString(buf).trimmed(); + if (m_debugIO) { + qDebug() << "VISA <-: " << QString(buf).trimmed(); + } } } } return results; } +QStringList VISA::findResources() +{ + QStringList resources; + ViChar rsrc[VI_FIND_BUFLEN]; + ViFindList list; + ViRsrc matches = rsrc; + ViUInt32 nMatches = 0; + ViChar expr[] = "?*INSTR"; + + if (VI_SUCCESS == viFindRsrc(m_defaultRM, expr, &list, &nMatches, matches)) + { + if (nMatches > 0) + { + resources.append(QString(rsrc)); + while (VI_SUCCESS == viFindNext(list, matches)) + { + resources.append(QString(rsrc)); + } + } + } + return resources; +} + +bool VISA::identification(ViSession session, QString &manufacturer, QString &model, QString &serialNumber, QString &revision) +{ + QStringList result = processCommands(session, "*IDN?"); + if ((result.size() == 1) && (!result[0].isEmpty())) + { + QStringList details = result[0].trimmed().split(','); + manufacturer = details[0]; + // Some serial devices (ASRLn) loop back the the command if not connected + if (manufacturer == "*IDN?") { + return false; + } + if (details.size() >= 2) { + model = details[1]; + } + if (details.size() >= 3) { + serialNumber = details[2]; + } + if (details.size() >= 4) { + revision = details[3]; + } + qDebug() << "VISA::identification: " + << "manufacturer: " << manufacturer + << "model: " << model + << "serialNumber: " << serialNumber + << "revision: " << revision; + return true; + } + return false; +} + +// Filter is a list of resources not to try to open +QList VISA::instruments(QRegularExpression *filter) +{ + QList instruments; + QStringList resourceList = findResources(); + + for (auto const &resource : resourceList) + { + if (filter) + { + if (filter->match(resource).hasMatch()) { + continue; + } + } + ViSession session = open(resource); + if (session) + { + Instrument instrument; + QString manufacturer, model, serialNumber, revision; + if (identification(session, instrument.m_manufacturer, instrument.m_model, instrument.m_serial, instrument.m_revision)) + { + instrument.m_resource = resource; + instruments.append(instrument); + } + close(session); + } + } + return instruments; +} + #ifdef _MSC_VER void *VISA::libraryOpen(const char *filename) diff --git a/sdrbase/util/visa.h b/sdrbase/util/visa.h index b8f60cfae..244b301b5 100644 --- a/sdrbase/util/visa.h +++ b/sdrbase/util/visa.h @@ -23,6 +23,10 @@ #include "export.h" +#include + +class QRegularExpression; + typedef char ViChar; typedef ViChar * ViPChar; typedef signed long ViInt32; @@ -35,17 +39,29 @@ typedef ViObject ViSession; typedef ViSession * ViPSession; typedef ViString ViRsrc; typedef ViUInt32 ViAccessMode; +typedef ViUInt32 * ViPUInt32; +typedef ViObject ViFindList; +typedef ViFindList * ViPFindList; #define VI_SUCCESS 0 #define VI_TRUE 1 #define VI_FALSE 0 #define VI_NULL 0 +#define VI_FIND_BUFLEN 256 // We dynamically load the visa dll, as most users probably do not have it // Note: Can't seem to call viOpenDefaultRM/viClose in constructor / destructor of global instance class SDRBASE_API VISA { public: + struct Instrument { + QString m_resource; + QString m_manufacturer; + QString m_model; + QString m_serial; + QString m_revision; + }; + // Default session ViSession m_defaultRM; // Function pointers to VISA API for direct calls @@ -54,6 +70,8 @@ public: ViStatus (*viClose) (ViObject vi); ViStatus (*viPrintf) (ViSession vi, ViString writeFmt, ...); ViStatus (*viScanf) (ViSession vi, ViString readFmt, ...); + ViStatus (*viFindRsrc) (ViSession vi, ViString expr, ViPFindList li, ViPUInt32 retCnt, ViChar desc[]); + ViStatus (*viFindNext) (ViSession vi, ViChar desc[]); VISA(); @@ -61,7 +79,11 @@ public: void closeDefault(); ViSession open(const QString& device); void close(ViSession session); - QStringList processCommands(ViSession session, const QString& commands); + QStringList processCommands(ViSession session, const QString& commands, bool *error=nullptr); + QStringList findResources(); + bool identification(ViSession session, QString &manufacturer, QString &model, QString &serialNumber, QString &revision); + QList instruments(QRegularExpression *filter); + void setDebugIO(bool debugIO) { m_debugIO = debugIO; } // Is the VISA library available bool isAvailable() const @@ -71,6 +93,7 @@ public: private: bool m_available; + bool m_debugIO; protected: void *visaLibrary;