From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Accessing a VME card via LV 2012 SP1

title: Accessing a VME card via LV 2012 SP1
date: 29jun16

 

Hello LabVIEW Forum.

 

We produce cards & modules (i.e., "daughter boards") to simulate a standard communications interface protocol. We create software DLLs for using the same hardware on different base boards - PCI and VME. For the VME interface, we use National Instruments VXI-MXI-2 card in a NI FlexFrame box. This connects to our desktop computer running Windows, via a cable connecting to a PCI-MXI-2 card in the desktop. For this PCI-MXI connection, we use VISA software library routines to connect to the VXI-MXI-2 card, which then allows us to communicate directly with our module on our VME card.

 

In our DLL, our first function call (Init_Module) to initialize the module makes standard VISA calls:
        viOpenDefaultRM(&defaultRM);
where defaultRM==VI_NULL, followed by
        viOpen(defaultRM, rsrcName, VI_NULL, VI_NULL, &tmpinstr);
with a properly formed resource name (rscName).

We then call
        viMapAddress(tmpinstr, where, 0, memsize, VI_FALSE, 0, &card_address);
to get a pointer to the module on the card, and then we can perform operations on the module.

 

When the LabVIEW VIs open this DLL directly (in the setting of "Library name or path" on the Call Library Function Node), and thereby calls this Init_Module function directly, the viOpenDefaultRM call returns 0, and the initialization proceeds with success. However, when LabVIEW opens intermediate "dispatcher" DLL, which itself opens the underlying DLL which contains the function Init_Module, the call to viOpenDefaultRM returns error code 0x3FFF0077. At which point, all further VISA function calls fail.

 

So, I added a call to viOpenDefaultRM directly in the intermediate "dispatcher" DLL. And it returns 0, that is, success. And I did this in various places in the code of this intermediate DLL; all calls return success (0).

 

Question: What do I need to do so that the intermediate DLL can call my real underlying DLL, which calls viOpenDefaultRM, so that the function will return with success (0) ? I.E., so that I can access my VME card.

 

You might ask - Why not work directly with the underlying DLL ? Because we have different products, each with their own DLL (e.g., LabVIEW, LabVIEW RT, PCI, VME), and we want to be able to have one intermediate "dispatcher" DLL for the different products.

 

I attach two NI-Trace files, one showing the error (using the intermediate DLL), and one showing success (using the underlying DLL directly).

 

I would most appreciate any help. Thank you.

 

Asher Meth
Excalibur Systems
ameth@ mil-1553.com

Download All
0 Kudos
Message 1 of 4
(2,920 Views)

Are you trying to call the function that tries to open the viOpenDefaultRM() in your DLL_PROCESS_ATTACH case inside DllMain()?

 

That could explain the failing as Microsoft specifically warns from doing a lot of things inside DLL_PROCESS_ATTACH, including trying to load other DLLs explicitedly. During the loading of a DLL which also does call the DllMain() function in a DLL, Windows maintains a loader lock to protect from various race conditions, and many things like loading other DLLs can then simply fail, depending if that library is already loaded into the process space or not. So it could work sometimes if that DLL was loaded before by other parts of the application and fail if it hasn't already been loaded.

 

NI-VISA being another DLL that does all kind of involved secondary DLL loading during its initialization definitely could be sensitive to such attempts and its initialization might simply fail because of the loader lock being held during the loading of your own intermediate DLL. Try to move the initialization of your VISA resources out of DLLMain() for instance by using a global static for your resource manager VISA handle, explicitedly initialized to VI_NULL and on each call of your first DLL API function that initializes the resource, check for this variable to be NULL, and if it is do the viOpenDefaultRM() call.

 

While I can understand that you would rather only have one DLL to maintain for LabVIEW and any other possible programming environment, I'm sure you are aware that LabVIEW can do all the VISA programming directly. That would be hardly more complicated than writing your intermediate DLL for use in LabVIEW and give you a pretty smooth experience as you won't have to worry about such low level details. The only possible drawback could be if you want to keep the address map of your hardware device private.

Rolf Kalbermatter
My Blog
0 Kudos
Message 2 of 4
(2,919 Views)

Hello Rolf.

 

Thank you for your reply.

 

We do not use DllMain(). When our initialization VI is called, it calls the routine to LoadLibrary, opens the underlying DLL, sets up pointers to all the functions in the DLL (using GetProcAddress).

 

The call to the initialization VI actually runs the routine that is set up for this. It gets from the dispatcher dll into the underlying ("real") dll - loads the dll, executes the function, gets to the call for viOpenDefaultRM, and returns an error value. We see this in the NI-Trace which I previously attached to the thread.

 

Re: your suggestion about doing the VISA programming within LabVIEW. This is not a solution for us, since we are using the same set of LabVIEW VIs for both VISA and non-VISA environments (i.e., VME cards and PCI cards).

 

Any other ideas would be welcome. Thank you. (30 June 16)

 

Asher Meth
Excalibur Systems
ameth@ mil-1553.com

0 Kudos
Message 3 of 4
(2,861 Views)

Hello Forum.

 

Just to follow up & update you with our status.
We cracked it, but do not understand why our solution works.
Any explanations would be welcome. Thank you.

 

Here is what we did.

 

In the dispatcher DLL project (which is compiled using LabWindows CVI)
1. #include the two .h files needed for VISA projects: visa.h, visatype.h
2. In addition to the source files needed for this dispatcher DLL, add to the project the file visa32.dll from c:\Windows\System32
3. In the function that loads the underlying ("real") DLL, we first add the following lines of code

 

defaultRM=VI_NULL;
if (defaultRM == VI_NULL)
{
      vstatus = viOpenDefaultRM(&defaultRM);
      if (vstatus < VI_SUCCESS)
      return eopendefaultrm;
}
viClose(defaultRM);

 

4. Then, we load library for the "real" DLL, and set up pointers to each of the functions in this "real" DLL.

5. NOW, when we run a VI which calls the function from the underlying VME based DLL to call VISA functions, the function viOpenDefaultRM returns 0, and the other viOpen, and "viWhatEver" functions work OK. We cannot explain *why* this is necessary, but without these two actions, it would not work.

 

NOTE that item 2. without item 3. does not help; viOpenDefaltRM returns an error code.

 

 

Asher Meth
Excalibur Systems
ameth@ mil-1553.com

(18 July 16)

0 Kudos
Message 4 of 4
(2,766 Views)