Hello everyone,
I'm developing an application that needs to communicate with the multimeter Keithley 2110.
I installed the latest Keithely IO Library (KIOL-850C07), which bundles the NIVISA run-time version 5.2.
Everything works as expected: I can connect to the device, retrieve its ID, read voltage measurements and so on. However, once in a while voltage reading method gets stuck in the call to viReadSTB for about 120s before returning a VI_ERROR_SYSTEM_ERROR. I tried to read the timeout value:
ViUInt32attrValue;
status = viGetAttribute(vi, VI_ATTR_TMO_VALUE, (void *)&attrValue);
which correctly returns the default value of 2000ms (much smaller than the actual wait time of 120000ms).
Trying to set a different timeout:
ViUInt32attrValue = 1000;
status = viSetAttribute(vi, VI_ATTR_TMO_VALUE, attrValue);
does not make any difference.
I tried so to update the nivisa runtime to the latest available version (17.0). I did not update the visa.h and visa32.lib since visa.h has only minimal changes, while .lib is byte-to-byte unchanged.
Interestingly, all the above is true on a win10 machine, but if I run the very same application with the same libraries, drivers and device on a win7 machine (tried 2 of them) the hanging time reduces to 10s. Also in the latter case this time is unaffected by timeout setting.
I wanted to know what is causing the hang and if I can do anything to reduce the waiting time or get rid of it if possible.
I'm building the application using gcc 5.3.0.
Here below is the code snippet I'm using to communicate with the multimeter.
DMM.h
#ifndef DMM_H #define DMM_H #include <QObject> #include <QThread> #include "visa.h" #define MANUFACTURER_ID 0x05E6 //Keithley #define DMM_MODEL 0x2110 //Keithley 2110 5 1/2 Digit Multimeter class Dmm : public QObject { Q_OBJECT public: Dmm(); ~Dmm(); bool openConnection(int SerialNumber); bool closeConnection(); bool identify(QString &identificationString); bool measureVoltage(double &value); bool clearErrors(); private: ViSession defaultRM, vi; //these are pointers char buf [256] = {0}; ViStatus error = VI_SUCCESS; ViUInt16 status = 0; signals: void errorMessage(QString); public slots: bool initialize(); }; #endif // DMM_H
DMM.cpp
#include <stdio.h> #include "DMM.h" #include <windows.h> Dmm::Dmm() { } Dmm::~Dmm() { } bool Dmm::openConnection(int SerialNumber) { char AddressString[60]; int ManufacturerID = MANUFACTURER_ID; int DMMmodel = DMM_MODEL; sprintf(AddressString, "USB0::0x%x::0x%x::%d::INSTR", ManufacturerID, DMMmodel, SerialNumber); /*! Open session to USB device*/ if ((error = viOpenDefaultRM(&defaultRM)) != VI_SUCCESS) { emit errorMessage("DMM: viOpenDefaultRM(&defaultRM) failed"); return false; } if ((error = viOpen(defaultRM, AddressString, VI_NULL, VI_NULL, &vi)) != VI_SUCCESS) { emit errorMessage("DMM: viOpen(defaultRM, " + QString::fromUtf8(AddressString) + ", VI_NULL,VI_NULL, &vi) failed"); return false; } return true; } bool Dmm::closeConnection() { /*! Restore DMM manual mode *! if ((error = viPrintf(vi, ":SYSTem:LOCal\n")) != VI_SUCCESS) { emit errorMessage("DMM: viPrintf(vi, \":SYSTem:LOCal\\n\")) failed"); return false; } /* Close session */ if ((error = viClose(vi)) != VI_SUCCESS) { emit errorMessage("DMM: DMM viClose(vi) failed"); return false; } if ((error = viClose(defaultRM)) != VI_SUCCESS) { emit errorMessage("DMM: DMM viClose(defaultRM) failed"); return false; } return true; } bool Dmm::clearErrors() { /*! Clears tester errors */ if ((error = viPrintf(vi, "*CLS\n")) != VI_SUCCESS) { emit errorMessage("DMM: viPrintf(vi, \"*CLS\\n\") failed"); return false; } return true; } bool Dmm::initialize() { /*! Resets the device to power on configuration */ if ((error = viPrintf(vi, "*RST\n")) != VI_SUCCESS) { emit errorMessage("DMM: viPrintf(vi, \"*RST\\n\") failed"); return false; } /*! Modify timeout */ ViUInt32 attrValue = 1000; status = viSetAttribute(vi, VI_ATTR_TMO_VALUE, attrValue); /*! Clear error queue */ return this->clearErrors(); } bool Dmm::identify(QString &identificationString) { /*! Send an *IDN? string to the device */ if ((error = viPrintf(vi, "*IDN?\n")) != VI_SUCCESS) { emit errorMessage("DMM: viPrintf(vi, \"*IDN?\\n\") failed"); return false; } do { if ((error = viReadSTB(vi, &status)) != VI_SUCCESS) { emit errorMessage("DMM: viReadSTB(vi, &status) failed"); return false; } } while (status == 0); //waits for 0x10, Message available (?) /*! Read results */ if ((error = viScanf(vi, "%t", &buf)) != VI_SUCCESS) { emit errorMessage("DMM: viScanf(vi, \"%t\", &buf) failed"); return false; } identificationString = QString::fromUtf8(buf); return true; } bool Dmm::measureVoltage(double &value) { if ((error = viPrintf(vi, ":MEASure:VoltAge:DC?\n")) != VI_SUCCESS) { emit errorMessage("DMM: viPrintf(vi, \":MEASure:VoltAge:DC?\\n\") failed"); return false; } /*! Wait 100ms to avoid too frequent calls */ QThread::msleep(100); do { if ((error = viReadSTB(vi, &status)) != VI_SUCCESS) { emit errorMessage("DMM: viReadSTB(vi, &status) failed"); this->initialize(); return false; } } while (status == 0); //waits for 0x10, Message available (?) /*! Check that the data available bit is set, otherwise reset device and return */ if (!(status & 0x10)) { this->initialize(); return false; } /*! Read results */ if ((error = viScanf(vi, "%t", &buf)) != VI_SUCCESS) { emit errorMessage("DMM: viScanf(vi, \"%t\", &buf) failed"); return false; } sscanf(buf, "%lf", &value); /*!< returns a measure in volts */ return true; }
Thank you in advance for any help.
Best regards