c++visa

NI VISA and viWrite not detecting command errors


I'm testing out the vanilla viWrite() function and have realised that it does not return an error code when I pass in an invalid command string. I find this a little strange... surely the implementation ought to detect this event.

Here is a small test case I used to demonstrate this... (it's just test code so it won't be perfect :))

#include <visa.h>
#include <cstring>
#include <iostream>

#define VIBUF_LEN 255

static ViChar viBuf[VIBUF_LEN];

void MyWrite(ViSession sess, char const *cmd)
{
    ViStatus status;
    ViUInt32 rcount;

    strncpy_s(viBuf, cmd, VIBUF_LEN);
    status = viWrite(sess, (ViBuf)viBuf, strlen(viBuf), &rcount);
    if (status < VI_SUCCESS)
    {
        std::cout << "Failed to write!\n";
        exit(-1);
    }
}

std::string MyRead(ViSession sess)
{
    ViStatus status;
    ViUInt32 rcount;

    status = viRead(sess, (ViBuf)viBuf, VIBUF_LEN, &rcount);
    if (status < VI_SUCCESS)
    {
        std::cout << "Failed to read 1!\n";
        exit(-1);
    }
    else if (rcount >= VIBUF_LEN)
    {
        std::cout << "Failed to read 2!\n";
        exit(-1);
    }
    else if (!rcount)
    {
        std::cout << "Failed to read 3!\n";
        exit(-1);
    }

    viBuf[rcount] = NULL;
    return std::string(viBuf);
}

int _tmain(int argc, _TCHAR* argv[])
{
    ViStatus status;
    ViSession mVisaDefaultRM;
    ViSession mVisaInst;

    status = viOpenDefaultRM(&mVisaDefaultRM);
    if (status == VI_SUCCESS)
    {
        strncpy_s(viBuf, "GPIB0::1::INSTR", VIBUF_LEN);
        status = viOpen(mVisaDefaultRM, viBuf, VI_NULL, VI_NULL, &mVisaInst);
    }

    if (status < VI_SUCCESS)
    {
        std::cout << "Failed to initialise!\n";
        exit(-1);
    }

    viClear(mVisaInst);
    MyWrite(mVisaInst, "*CLS;");
    MyWrite(mVisaInst, "*RST;");
    MyWrite(mVisaInst, "*SRE 0;");
    MyWrite(mVisaInst, "*ESE 0;");
    MyWrite(mVisaInst, "CRAP;");   /* Wow really!? */
    MyWrite(mVisaInst, "*ESR?;");
    std::string str = MyRead(mVisaInst);
    std::cout << "ESR is " << str.c_str() << "\n";

    std::cout << "END\n";
    getchar();

    return 0;
}

The program outputs the following:

ESR is +32
END

So, the write of the SCPI command "CRAP;" is definitely being flagged up as an error by the device.

This made me think, ah... I haven't enabled the ESE bit to enable this bit to get flagged in the STB. So I do this:

MyWrite(mVisaInst, "*ESE 255;");
//                       ^^^
//                       A bit of a sledge hammer but should do the job

The bad command is still not detected.

Okay, so maybe need to enable SRQs... perhaps the VISA library needs both these enabled to handle this...

So I do this:

MyWrite(mVisaInst, "*SRE 255;");
//                       ^^^
//                       A bit of a sledge hammer but should do the job

Nope, no difference. It still does not detect the bad command.

Is this standard VISA? Should it be working like this? Does this mean that if I want to detect these errors I always have to enable the event VI_EVENT_SERVICE_REQ and so a viWaitOnEvent() after a write? I would have thought the vanilla viWrite() would detect this for me??


Solution

  • viWrite just takes care of writing (see Ni Visa Programmers Reference), meaning it only returns an error when there's a true communication failure (like a timeout, or someone unplugging the cable, etc.). This is standard for low-level I/O functions (sockets, serial ports, ... all work this way).

    Which means in order to figure out if there is a remote device error you'll have to query that somehow. I'm not familiar with VISA, so I'm not sure what the best way is too achieve this. It's either something in the style you talk about (events) or maybe you can query the device directly? (maybe you can viWrite a command that says "give me your status" and then viRead the response?)