Instrument Control (GPIB, Serial, VISA, IVI)

cancel
Showing results for 
Search instead for 
Did you mean: 

Error "pure virtual function call"

Hi,

 

Windows7, PCI-GPIB, NI-488.2 Version 3.1.1, Visual Studio 2010 C++ Application.

 

Randomly between 10 minuntes and 4 hours I get the error "pure virtual function call"

 

With the debbuger attached to the process in error I identified NI4882.dll as the source of the error.

 

Then I deinstalled NI-488.2 Version 3.1.1 and installed NI488.2 July 2000. Then my application runs without any error!

 

I tried to attach the source files which represents the interface between my application and the NI-4882 driver but it did not work for the C++ file.

 

Any help appreciated.

 

Best Regards

Walter

 

 

 

0 Kudos
Message 1 of 7
(5,764 Views)

Hello Walter,

 

I could not find anything related to the ni4882.dll and a pure virtual function call but does this article might help understand what is happening:

http://forums.ni.com/t5/NI-TestStand/Pure-Virtual-Function-Call-Error/td-p/101802

Did you try installing the recent NI 488.2 3.1.2 driver (http://www.ni.com/download/labview-real-time-module-2012/3080/en/ )?
Could you post your C++ source code?

 

Best regards
AndGar

Andreas Gareis
Senior Applications Engineer, NI
Certified LabVIEW Developer & TestStand Architect
0 Kudos
Message 2 of 7
(5,724 Views)

Hi AndGar,

 

After the first time when I got the error  "pure virtual function call" I installed with _set_purecall_handler (myHandler) my own handler and this handler creates a minidump. When I forced a pure virtual call within my application then my own handler was called and a minidump was written.

 

When I got the error  "pure virtual function call" from the ni4882.dll, then the original  "pure virtual function call" Message Box was displayed. And when I attached the debugger, the ni4882.dll was the bottom module of the callstack.

 

Here my code (I had to delete most of the comments and split to 2 messages because of the limits of this forum)

 

1. The Interface declaration

#ifndef MC_IGPIB_H
#define MC_IGPIB_H

#include "Interfaces/_Interface.h"

namespace MC {
// Default for one GPIB
const Tstring kGPIB = _T("GPIB0");
// use GPIB1, GPIB2 up to GPIB9 for multiple cards.

struct SGpibDevInfo
{
  Int     mGpibAdr;     
  bool    mRemote;      
  HANDLE  mSRQEvent;    
  Tstring mVendorName;  
  Tstring mModelName;   
  char    mSerialPoll;  
  Int     mIbsta1;      
  Int     mIbsta2;      
  Int     mIberr;       
  Int     mIbcntl;      
};

// Get the interface IGpib with MC::IApplication::AppObject (kGPIB).
struct IGpib : public IInterface
{
 virtual  bool         Reset() = 0;
 virtual  Int          Open(UShort adr, ULong timeoutMs) = 0;
 virtual  bool         Close(Int ud) = 0;
 virtual  bool         SetTimeout(Int ud, ULong timeoutMs) = 0;
 virtual  ULong        Timeout() = 0;
 virtual  bool         EnableSRQ(Int ud, HANDLE srqEvent) = 0;
 virtual  bool         DisableSRQ(Int ud) = 0;
 virtual  bool         Remote(Int ud)  = 0;
 virtual  bool         Local(Int ud) = 0;
 virtual  char         SerialPoll(Int ud) = 0;
 virtual  bool         DeviceClear(Int ud) = 0;
 virtual  bool         Trigger(Int ud) = 0;
 virtual  bool         Send(Int ud, const std::string& data) = 0;
 virtual  bool         SendNoEOI (Int ud, const std::string& data) = 0;
 virtual  std::string  Enter(Int ud) = 0;
 virtual  std::string  EnterNoTimeout(Int ud, ULong timeoutMs) = 0;
 virtual  SGpibDevInfo DeviceInfo(Int ud) = 0;
 virtual  Int          ibask(Int ud, Int option, Int* value) = 0;
 virtual  Int          ibcmd(Int ud, void* cmdbuf, Long count) = 0;
};

}    //    namespace MC
#endif    //    MC_IGPIB_H

 2. The implementation header

#ifndef MC_GPIB_H
#define MC_GPIB_H

#include "CORE/_Model.h"
#include "Interfaces/_IGPIB.h"

namespace MC {
typedef std::map<Int, SGpibDevInfo>    GPIBDevMap;

class TGpib : public VModel, public IGpib
{
public:
               TGpib (const Tstring& devName = kGPIB);
               ~TGpib ();
  bool         Reset ();
  Int          Open (UShort adr, ULong timeoutMs);
  bool         Close (Int ud);
  bool         SetTimeout (Int ud, ULong timeoutMs);
  ULong        Timeout ();
  bool         EnableSRQ (Int ud, HANDLE srqEvent);
  bool         DisableSRQ (Int ud);
  bool         Remote (Int ud);
  bool         Local (Int ud);
  char         SerialPoll (Int ud);
  bool         DeviceClear (Int ud);
  bool         Trigger (Int ud);
  bool         Send (Int ud, const std::string& data);
  bool         SendNoEOI (Int ud, const std::string& data);
  std::string  Enter (Int ud);
  std::string  EnterNoTimeout (Int ud, ULong timeoutMs);
  SGpibDevInfo DeviceInfo (Int ud);
  Int          ibask (Int ud, Int option, Int* value);
  Int          ibcmd (Int ud, void* cmdbuf, long count);

private:
  void       GPIBError       (Int ud, const Tstring& ctx, bool fatal = false);
  static Int __stdcall  GpibSRQ(Int ud, unsigned long ibsta, unsigned long iberr, unsigned long ibcntl, void* ptr);
  
  UInt        mBoardID;
  GPIBDevMap  mDevices;
  ULong       mTimeout;
};
}    //    namespace MC
#endif    //    MC_GPIB_H

  

0 Kudos
Message 3 of 7
(5,702 Views)

And here part 1 of the implementation:

 

 

#include "StdAfx.h"
#include "R:\MCLIB\ThirdParty\National\ni4882.h"
#include "COMMON/_ErrorHandling.h"
#include "COMMON/_Tracing.h"
#include "COMMON/_Makros.h"
#include "COMMON/_MC_Strings.h"
#include "System/_GPIB.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using namespace std;

namespace MC {
const   char    MTA0            = 64;    // My Talk Address
const   Char*   ErrorMnemonic[] = {_T("EDVR"), _T("ECIC"), _T("ENOL"), _T("EADR"), 
                                   _T("EARG"), _T("ESAC"), _T("EABO"), _T("ENEB"),
                                   _T("EDMA"), _T("---9"), _T("EOIP"), _T("ECAP"),
                                   _T("EFSO"), _T("--13"), _T("EBUS"), _T("ESTB"),
                                   _T("ESRQ"), _T("--17"), _T("--18"), _T("--19"),
                                   _T("ETAB"), _T("ELCK"), _T("EARM"), _T("EHDL"),
                                   _T("ECFG"), _T("--25"), _T("EWIP"), _T("ERST"),
                                   _T("EPWR"), _T("OOPS")
                                 };
const   UShort  kErrorMnemonics = sizeof (ErrorMnemonic) / sizeof (ErrorMnemonic[0]);
const   ULong   TimeoutTime[]   = { 1, 3, 10, 30, 100, 300, 1000, 3000, 10000,
                                    30000, 100000, 300000, 1000000
                                  };
const   UShort  kTimeoutTimes   = sizeof (TimeoutTime) / sizeof (ULong);

Int TimeoutCode (ULong millisec)
{
    if (millisec > 0)
    {
        for (UShort i = 0; i < kTimeoutTimes; ++i)
        {
            if (millisec <= TimeoutTime[i])
                return i + T1ms;
        }
    }
    return TNONE;
}

class TGpib_TimeoutSetter
{
public:
            TGpib_TimeoutSetter     (TGpib* drv, Int ud, ULong timeoutTime);
            ~TGpib_TimeoutSetter    ();

private:
    TGpib*  mDriver;
    Int     mUd;
    ULong   mOldTimeoutTime;
};

TGpib_TimeoutSetter::TGpib_TimeoutSetter (TGpib* drv, Int ud, ULong timeoutTime)
{
    mDriver = drv;
    mUd = ud;
    mOldTimeoutTime = mDriver->Timeout ();
    mDriver->SetTimeout (mUd, timeoutTime);
}

TGpib_TimeoutSetter::~TGpib_TimeoutSetter ()
{
    mDriver->SetTimeout (mUd, mOldTimeoutTime);
}

struct SDevInfo : public SGpibDevInfo
{
    SDevInfo::SDevInfo () : SGpibDevInfo ()
    {
        mGpibAdr    = -1;
        mRemote     = false;
        mSRQEvent   = NULL;

        mIbsta1     = 0;
        mIbsta2     = 0;
        mIberr      = 0;
        mIbcntl     = 0;
        mVendorName = _T("");
        mModelName  = _T("");
    }
};

TGpib::TGpib (const Tstring& devName)
:    VModel    (devName)
{
    mBoardID = devName[4] - _T('0');

    SendIFC (mBoardID);
    ibconfig (mBoardID, IbcAUTOPOLL, 0);
    ibsre (mBoardID, 1);
}

TGpib::~TGpib ()
{
    ibsre (mBoardID, 0);
    ibonl (mBoardID, 0);
}

bool TGpib::Reset ()
{
    GPIBDevMap::iterator it = mDevices.begin ();
    for (; it != mDevices.end (); ++it)
        Close (it->first);
    mDevices.clear ();

    Int stat = ibonl (mBoardID, 0);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("Board offline failed"));
        GPIBError (-1, FCTX, true);
        return false;
    }

    SendIFC (mBoardID);
    stat = ThreadIbsta ();
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("send IFC failed"));
        GPIBError (-1, FCTX, true);
        return false;
    }

    stat = ibconfig (mBoardID, IbcAUTOPOLL, 0);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("send IbcAUTOPOLL failed"));
        GPIBError (-1, FCTX, true);
        return false;
    }

    stat = ibsre (mBoardID, 1);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("Set REN failed"));
        GPIBError (-1, FCTX, true);
        return false;
    }

    return true;
}

 

0 Kudos
Message 4 of 7
(5,701 Views)

Part 2:

Int TGpib::Open (UShort adr, ULong timeoutMs)
{
    if (mDevices.empty ())
        Reset ();

    Int ud = ibdev (mBoardID, adr, 0, TimeoutCode (timeoutMs), 1, 0);
    if (ud < 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("open device '%d' failed"), adr);
        GPIBError (-1, FCTX, true);
        return -1;
    }

    SDevInfo devInf;
    devInf.mGpibAdr = adr;
    mDevices[ud] = devInf;
    
    if (!DeviceClear (ud))
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("no device on address '%d'"), adr);
        GPIBError (ud, FCTX, true);
        Close (ud);
        return -1;
    }

    if (Send (ud, "*IDN?"))
    {
        Tstring s = String2Tstring (Enter (ud));
        StringList l = Split (s, _T(','));
        if (l.size () == 4)
        {
            mDevices[ud].mVendorName = l[0];
            mDevices[ud].mModelName = l[1];
        }
    }
    else
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("no device on address '%d'"), adr);
        GPIBError (ud, FCTX, true);
        Close (ud);
        return -1;
    }
    Local (ud);
    return ud;
}

bool TGpib::Close (Int ud)
{
    GPIBDevMap::iterator it = mDevices.find (ud);
    if (it != mDevices.end ())
    {
        Local (ud);
        Int stat = ibonl (ud, 0);
        if ((stat & ERR) != 0)
        {
            MCTraceLib (this, eTraceError, TFCTX, _T("close device ud = '%d' failed"), ud);
            GPIBError (ud, FCTX, true);
            return false;
        }
        mDevices.erase (it);
        return true;
    }
    return false;    
}

bool TGpib::SetTimeout (Int ud, ULong timeoutMs)
{
    Int stat = ibtmo (ud, TimeoutCode (timeoutMs));
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("set timeout device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX, true);
        return false;
    }
    return true;
}

ULong TGpib::Timeout ()
{
    return mTimeout;
}

bool TGpib::EnableSRQ (Int ud, HANDLE srqEvent)
{
    if (srqEvent != INVALID_HANDLE_VALUE)
    {
        GPIBDevMap::iterator it = mDevices.find (ud);
        if (it != mDevices.end ())
        {
            (it->second).mSRQEvent = srqEvent;
            Int stat = ibnotify (mBoardID, SRQI, GpibSRQ, (void*)this);
            if ((stat & ERR) != 0)
            {
                MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
                GPIBError (ud, FCTX, true);
                return false;
            }
            MCTraceLib (this, eTraceDebug, TFCTX, _T("(SRQ)on device ud = '%d' success"), ud);
            return true;
        }
    }
    else
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("srqEvent == INVALID_HANDLE_VALUE"));
    }
    return false;
}

bool TGpib::DisableSRQ (Int /*ud*/)
{
    return true;
}

bool TGpib::Remote (Int ud)
{
    Int adr;
    ibask (ud, IbaPAD, &adr);
    adr += 32;  // Talk Address = Listen Address + 32

    char    cmdbuf[] = {MTA0, 0, LLO, UNT, UNL};
    cmdbuf[1] = char(adr);

    Int stat = ibcmd (mBoardID, &cmdbuf, 5);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX, true);
        return false;
    }
    mDevices[ud].mRemote = true;
    return true;
}

bool TGpib::Local (Int ud)
{
    mDevices[ud].mRemote = false;

    Int stat = ibloc (ud);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX, true);
        return false;
    }
    return true;
}

char TGpib::SerialPoll (Int ud)
{
    char    pollChr;

    Int stat = ibrsp (ud, &pollChr);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }
    return static_cast<char> (pollChr & 0x9F); // VM QueryError eliminieren
}

bool TGpib::DeviceClear (Int ud)
{
    Int stat = ibclr (ud);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX, true);
        return false;
    }
    return true;
}

bool TGpib::Trigger (Int ud)
{
    Int stat = ibtrg (ud);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }
    return true;
}

bool TGpib::Send (Int ud, const std::string& str)
{
    Int stat = ibeot (ud, 1);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("'EOI on' on ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }

    stat = ibwrt (ud, (void*)str.c_str (), str.length ());
    Long sent = ThreadIbcntl ();

    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }
    if (sent != static_cast<Long> (str.length ()))
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d characters sent"), sent, str.length ());
        return false;
    }
    return true;    
}

bool TGpib::SendNoEOI (Int ud, const std::string& str)
{
    Int stat = ibeot (ud, 0);
    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("'EOI off' on ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }

    stat = ibwrt (ud, (void*)str.c_str (), str.length ());
    Long sent = ThreadIbcntl ();

    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
        return false;
    }
    if (sent != static_cast<Long> (str.length ()))
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d characters sent"), sent, str.length ());
        return false;
    }
    return true;    
}

std::string TGpib::Enter (Int ud)
{
    std::string str = "";
    char* buf = new char[2048];

    Int stat = ibrd (ud, (void*)buf, 2047);
    Long got = ThreadIbcntl ();


    if ((stat & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
    }
    else
    {
        buf[got] = '\0';
        str = buf;
        // eventuelle LF und CR vom Ende entfernen!
        string::size_type idx = str.find_last_of (k_CR);
        str = str.substr (0, idx);
        idx = str.find_last_of (k_LF);
        str = str.substr (0, idx);
    }
    delete[] buf;
    return str;
}


 

0 Kudos
Message 5 of 7
(5,700 Views)

Part 3:

 

//----- EnterNoTimeout -------------------------------------------------------------
std::string TGpib::EnterNoTimeout (Int ud, ULong timeoutMs)
{
    std::string str = "";
    char* buf = new char[2048];

    TGpib_TimeoutSetter autoTimeout (this, ud, timeoutMs);

    Int stat = ibrd (ud, (void*)buf, 2047);
    Long got = ThreadIbcntl ();

    if ((stat & ERR) != 0)
    {
        if (stat == EABO)
            return str;

        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
    }
    else
    {
        buf[got] = '\0';
        str = buf;
        // eventuelle LF und CR vom Ende entfernen!
        string::size_type idx = str.find_last_of (k_CR);
        str = str.substr (0, idx);
        idx = str.find_last_of (k_LF);
        str = str.substr (0, idx);
    }
    delete[] buf;
    return str;
}

SGpibDevInfo TGpib::DeviceInfo (Int ud)
{
    SGpibDevInfo devInfo;
    devInfo.mGpibAdr = -1;

    GPIBDevMap::iterator it = mDevices.find (ud);
    if (it != mDevices.end ())
        devInfo = it->second;
    return devInfo;
}

Int TGpib::ibask (Int ud, Int option, Int* value)
{
    Int res = ::ibask (ud, option, value);
    if ((res & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
    }
    return res;
}

Int TGpib::ibcmd (Int ud, void* cmdbuf, long count)
{
    Int res = ::ibcmd (ud, cmdbuf, count);
    Long sent = ThreadIbcntl ();
    if ((res & ERR) != 0)
    {
        MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud);
        GPIBError (ud, FCTX);
    }
    if (sent != count)
        MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d commands sent"), sent, count);

    return res;    
}

void TGpib::GPIBError (Int ud, const Tstring& ctx, bool /*fatal*/)
{
    if (ErrorFlag ())
        return;

    SGpibDevInfo devInfo;
    devInfo.mGpibAdr = -1;
    if (ud >= 0)
    {
        GPIBDevMap::iterator it = mDevices.find (ud);
        if (it != mDevices.end ())
            devInfo = it->second;
    }

    Int err = ThreadIberr ();
    if (err < 0 || err > kErrorMnemonics)
    {
        //        err = kErrorMnemonics;
        ErrorMsg (ctx, _T("NI488 Fehler auf '%d': IBSTA = %d, IBERR = %d '%s'"),
            devInfo.mGpibAdr,
            ThreadIbsta (), 
            err, 
            _T("OOps")
        );
    }
    else
    {
        ErrorMsg (ctx, _T("NI488 Fehler auf '%d': IBSTA = %d, IBERR = %d '%s'"),
            devInfo.mGpibAdr,
            ThreadIbsta (), 
            err, 
            ErrorMnemonic[err]
        );
    }

}

Int __stdcall TGpib::GpibSRQ (Int, unsigned long sta, unsigned long err,
                              unsigned long cntl, void* ptr)
{
    TGpib* me = reinterpret_cast<TGpib*> (ptr);

    char poll = 0;
    GPIBDevMap::iterator it = me->mDevices.begin ();
    for (; it != me->mDevices.end (); ++it)
    {
        ibrsp (it->first, &poll);
        if ((poll & 0x40) != 0)
            break;
    }
    if (it != me->mDevices.end ())
    {
        SGpibDevInfo devInf = it->second;
        devInf.mIbsta1 = sta;
        devInf.mIberr = err;
        devInf.mIbcntl = cntl;
        if (devInf.mSRQEvent != NULL)
        {
            if ((ibsta & ERR) == 0)
                devInf.mSerialPoll = poll;

            it->second = devInf;
            SetEvent (devInf.mSRQEvent);
            //return SRQI;
        }
        else
        {
            MCTraceLib (me, eTraceError, TFCTX,
            _T("not enabled device '%d' requested service"), devInf.mGpibAdr);
        }
    }
    else
    {
        MCTraceLib (me, eTraceDebug, TFCTX,
        _T("(SRQ)unexpected interrupt received! status = '%d' error = '%d'"), sta, err);
    }

    return 0;
}
}    //    namespace MC

 

Thanks and best regards

Walter

 

0 Kudos
Message 6 of 7
(5,699 Views)

Were you able to generate a mini-dump with ni4882.dll on the stack? If you could provide this, it may help identify the cause of the failure.

0 Kudos
Message 7 of 7
(5,552 Views)