LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Help on shared libraries from Labview to Labwindows

Hello,

 

My problem is: I have a spectrometer HR 4000 from Ocean Optics. I want to control it from labwindows and, from that, integrate it to other labwindows program.

I have .vi from NI to control the spectrometer from labview:

http://sine.ni.com/apps/utf8/niid_web_display.download_page?p_id_guid=7833BD4A31DA1274E04400144FB7D2...

The .vi works perfectly with the spectrometer.

Then, I build a shared libraries with the usual procedure with the .vi I need. I have now a .h, .lib and .dll.

.h is given at the end.

What I do is:

 

I use the viFindRsrc function to have a char of my instrument.

The function from the labview needs a VISA ressource name.

From this subject: http://forums.ni.com/t5/LabVIEW/How-to-pass-Visa-Resoure-Name-parameter-to-labview-dll-in/td-p/24984...

I know that I need to put a string control to a VISA ressource name.

What I did: I use that program:

http://digital.ni.com/public.nsf/allkb/4737E4A5E44A81D38625698500576617

 

I rebuilt the shared libraries with this program and the other .vi I need to control the spectrometer.

Then I call StrToVISAIo first, and the reste after.

What I have is:

 


                

uintptr_t VISAResourceNameOut;
Cluster SpectralWaveform;
int32 elmtCount=32000;
AllocateDoubleArray1 (elmtCount);
AllocateDoubleArray (elmtCount);

StrToVisaIO(instrDescriptor, &VISAResourceNameOut);
OceanOptics20004000_Initialize(&VISAResourceNameOut, &VISAResourceNameOut);

OceanOptics20004000_ReadSpectralWaveform(&VISAResourceNameOut, &VISAResourceNameOut, &SpectralWaveform);
OceanOptics20004000_Close(&VISAResourceNameOut);         

 

 

 

Where instrDescriptor is a char I get with  viFindRsrc, that's not the problem.

Everything compile fine, but, when I want to know what's in SpectralWaveform, I get:

SpectralWaveform.elt1 and SpectralWaveform.elt2 are unitilialized.

 

Here is the full .h

#include "extcode.h"
#pragma pack(push)
#pragma pack(1)


#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
	int32_t dimSize;
	double elt[1];
} DoubleArrayBase;
typedef DoubleArrayBase **DoubleArray;
typedef struct {
	int32_t dimSize;
	double Numeric[1];
} DoubleArray1Base;
typedef DoubleArray1Base **DoubleArray1;
typedef struct {
	DoubleArray elt1;
	DoubleArray1 elt2;
} Cluster;

/*!
 * StrToVisaIO
 */
void __cdecl StrToVisaIO(char String[], uintptr_t *VISAResourceName);
/*!
 * Establishes communication with the instrument and optionally performs an 
 * instrument identification query and/or an instrument reset.  It also places 
 * the instrument in a default state needed for other instrument driver 
 * operations.  Therefore, call this VI before calling other instrument driver 
 * VIs for this instrument.  Generally, you need to call the Initialize VI 
 * only once at the beginning of an application.
 */
int32_t __cdecl OceanOptics20004000_Initialize(uintptr_t *VISAResourceName, 
	uintptr_t *VISAResourceNameOut);
/*!
 * Performs an instrument error query before terminating the software 
 * connection to the instrument.
 */
int32_t __cdecl OceanOptics20004000_Close(uintptr_t *VISAResourceName);
/*!
 * Configures the integration time of the spectrometer. The integration time 
 * is the amount of time that the device collects light before digitizing it 
 * and sending it out over the USB.  The longer the integration time, the more 
 * light it may collect. 
 */
int32_t __cdecl OceanOptics20004000_ConfigureIntegrationTime(
	uintptr_t *VISAResourceName, uint32_t IntegrationTime6000, 
	uintptr_t *VISAResourceNameOut);
/*!
 * Displays the spectrum vs wavelength in a waveform graph.
 * 
 * <b>Note:</b>  Do not put this VI in a loop if performance is a concern.  
 * Please see the <b>Ocean Optics 2000 4000 Acquire Continuous Waveform</b> 
 * example for an example of how to do continuous acquisition.
 * 
 * 
 */
int32_t __cdecl OceanOptics20004000_ReadSpectralWaveform(
	uintptr_t *VISAResourceName, uintptr_t *VISAResourceNameOut, 
	Cluster *SpectralWaveform);
/*!
 * Returns the intrument status information. Information included are number 
 * of pixels, intergration time, packets in spectra, packet count, USB speed 
 * and Lamp status.
 * 
 * <B>Note:</b>
 * Not supported by USB2000 and HR2000
 */
int32_t __cdecl OceanOptics20004000_QueryStatus(uintptr_t *VISAResourceName, 
	uint16_t *USBSpeed, LVBoolean *LampStatus, uint8_t *PacketCount, 
	uint8_t *PacketsInSpectra, uint32_t *IntegrationTime, 
	uintptr_t *VISAResourceNameOut, uint16_t *NumberOfPixels);

MgErr __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);

/*
* Memory Allocation/Resize/Deallocation APIs for type 'DoubleArray'
*/
DoubleArray __cdecl AllocateDoubleArray (int32 elmtCount);
MgErr __cdecl ResizeDoubleArray (DoubleArray *hdlPtr, int32 elmtCount);
MgErr __cdecl DeAllocateDoubleArray (DoubleArray *hdlPtr);

/*
* Memory Allocation/Resize/Deallocation APIs for type 'DoubleArray1'
*/
DoubleArray1 __cdecl AllocateDoubleArray1 (int32 elmtCount);
MgErr __cdecl ResizeDoubleArray1 (DoubleArray1 *hdlPtr, int32 elmtCount);
MgErr __cdecl DeAllocateDoubleArray1 (DoubleArray1 *hdlPtr);

#ifdef __cplusplus
} // extern "C"
#endif

#pragma pack(pop)

 Everything compile fine, and when I run it, I have no error.

 

So whether I'm not giving it the good VISA ressource name (maybe I should change the string inside the .vi, but not sure how to do that), whether something with the pointer is quite wrong (see the prototype function in the .h). Maybe I need to initialize SpectralWaveform.elt1 and SpectralWaveform.elt2 corrrectly. But not sure how to do this either, with this struct.

 

What I want at the end is to display the spectrum.

 

Any idea ?

 

Best Regards,

Geoffrey.
            
           

0 Kudos
Message 1 of 10
(5,075 Views)

Hello Geoffrey,

 

Thanks for posting! I know you have pointed out that this probably isn't the problem, but just out of curiousity, what char are you initializing the instrDescriptor with? From what I've read, it doesn't seem like we've been able to actually make a connection to the device. To verify this, another thing we can do is to monitor the int32_t outputs of the OceanOptics functions. If we can do the following and investigate where the code stops, we should be able to get a better understanding of where the code is failing:

 

uintptr_t VISAResourceNameOut;
Cluster SpectralWaveform;
int32 elmtCount=32000;
AllocateDoubleArray1 (elmtCount);
AllocateDoubleArray (elmtCount);

int32 error = 0;

StrToVisaIO(instrDescriptor, &VISAResourceNameOut);

error = OceanOptics20004000_Initialize(&VISAResourceNameOu​t, &VISAResourceNameOut);
if(error)
{
        printf("Initialization Failed with code %d!\n", error);
        return 0;
}
error = OceanOptics20004000_ReadSpectralWaveform(&VISAReso​urceNameOut, &VISAResourceNameOut, &SpectralWaveform);
if(error)
{
       printf("Read Failed with code %d!\n", error)
}

error = OceanOptics20004000_Close(&VISAResourceNameOut); 
if(error)
{
      printf("Close Failed with code %d!\n", error)
}

Note that I was not able to test this code and just noticed all of the missing semicolons Smiley Frustrated How are you inquiring as to what is in SpectralWaveform? Are you trying to tie this output to a UI control? Can you provide any screenshots of what you're seeing?

 

I would also printf the instrDescriptor to make sure you are getting a good value into StrToVISAIo.

 

Let us know what you find out!

 

Regards,

Collin D.
Software Product Manager
0 Kudos
Message 2 of 10
(5,046 Views)

Thank you for answering.

 

What I have:http://www.hostingpics.net/viewer.php?id=726898641.png

 

uintptr_t VISAResourceNameOut;
uintptr_t dummy;
Cluster SpectralWaveform;
int32 error;


int32 elmtCount=32000;
AllocateDoubleArray1 (elmtCount);
AllocateDoubleArray (elmtCount);

printf ("instrDescriptor: %s\n",instrDescriptor);
StrToVisaIO(instrDescriptor, &VISAResourceNameOut);
error = OceanOptics20004000_Initialize(&VISAResourceNameOut, &VISAResourceNameOut);
        printf("Initialization Code: %d\n", error);


error = OceanOptics20004000_ReadSpectralWaveform(&VISAResourceNameOut, &VISAResourceNameOut, &SpectralWaveform);
       printf("Read Code: %d\n", error);


error = OceanOptics20004000_Close(&VISAResourceNameOut); 
      printf("Close Code: %d\n", error);

 

 

What it gives me:http://www.hostingpics.net/viewer.php?id=816943922.png

Note that I didn't use your code if(error) since error given is 0.

 

About the SpectralWaveForm, I start the program in Debug, put a red dot to stop it and use Add Watch Expression Value to see what's inside.

Like this:http://www.hostingpics.net/viewer.php?id=711989803.png

 

When I want to know what's in SpectralWaveForm, it gives me:

http://www.hostingpics.net/viewer.php?id=851920324.png

SpectralWaveForm.elt1 and 2 aren't initialized.

 

I agree with you, it seems we cannot access to the spectrometer.

 

What I was'nt sure about is if I should use

uintptr_t VISAResourceNameOut;

or

uintptr_t *VISAResourceNameOut;

As the prototype function wants pointer and not unsigned int.

If I do that:

 

 

uintptr_t* VISAResourceNameOut=NULL;
uintptr_t* dummy=NULL;
Cluster *SpectralWaveform=NULL;
int32 error;


int32 elmtCount=10000;
AllocateDoubleArray1 (elmtCount);
AllocateDoubleArray (elmtCount);

printf ("instrDescriptor: %s\n",instrDescriptor);
StrToVisaIO(instrDescriptor, VISAResourceNameOut);
error = OceanOptics20004000_Initialize(VISAResourceNameOut, VISAResourceNameOut);
        printf("Initialization Code: %d\n", error);
error = OceanOptics20004000_ReadSpectralWaveform(VISAResourceNameOut, VISAResourceNameOut, SpectralWaveform);
        printf("Read Code: %d\n", error);
error = OceanOptics20004000_Close(VISAResourceNameOut);				
	printf("Close Code: %d\n", error); 

 

Then every pointer is NULL at the end, with the same error.

http://www.hostingpics.net/viewer.php?id=937958355.png

http://www.hostingpics.net/viewer.php?id=781384446.png

 

 

To be sure this is the instrDescriptor is the one from the spectrometer, I use the NI-VISA Interactive Control, connect and disconnect the device:

With the device:http://www.hostingpics.net/viewer.php?id=224754687.png

Without the device:http://www.hostingpics.net/viewer.php?id=550632398.png

 

I also tried to just give to the Ocean Optics the adress of instrDescriptor, not working.

 

Note that I have done the driver installation with the procedure given by the .html given with the .vi I use to build the shared library (cf in attached file).

Maybe not the one to do with labwindows.

 

I hope I have given most of the necessary information.

 

0 Kudos
Message 3 of 10
(5,024 Views)

What I also tried today is:

I take Initialize.vi

Delete VISA Resource Name and wire a constant string directly. I put inside this constant the name of the USB RAW device.

I initialize, read spectrum and close perfectly with the .vi.

I build a shared libraries with it. Use it inside labwindows.

Now the initialize function look like (in the header file):

int32_t __cdecl OceanOptics20004000_Initialize(
	uintptr_t *VISAResourceNameOut);

Still nothing in SpectralWaveForm.

Same if I decide to use Query Status and read Integration time (int 32 so....), which should be easier to read, since it's a int and not a Cluster.

0 Kudos
Message 4 of 10
(5,016 Views)

Hello Melponeme,

 

A couple more things I thought of:

 

You could try using NI I/O trace to see which VISA calls the VI is making versus what calls the CVI code is making and compare every line of communication with the Ocean Optics device. NI I/O Trace Guide.

 

This could help narrow down some things because, if all of the calls are the same, we know that there is some additional initialization we have to do in the C code, if the calls are not the same, then we probably just need to change the code until it matches which calls the VI is making (which should be easy enough to do).

 

I'm not as familiar with the SpectralWaveform data type and its components but it might be worth looking into the initialization code for the Cluster class to see if it initializes its members. I'm not as confident in this because you tried the same thing with the Integration time and no cigar. Out of curiousity, was the integration time also unitiliazed or just no data?

 

Regards,

Collin D.
Software Product Manager
0 Kudos
Message 5 of 10
(5,004 Views)

When I use Ni I/O Trace, i got, for labview, with the initialize.vi.

When I do it with labwindows, I simply get nothing in the .trace.

 

When I do query the integration time, if I use pointer like

uintptr_t *VISAResourceNameOut;

I get nothing.

 

If I do it with

uintptr_t VISAResourceNameOut;

I get weird number, even so I print IntegrationTime or &IntegrationTime. Default value should be 6000, and I get millions.

 

However, using NI I/O Trace, Now, I know what the .vi do to initialize, query etc...

Does that mean I can simply reproduce it in labwindows with visa.h ?

With ViOpen etc... ?

If Yes, I think doing that would be easier.

0 Kudos
Message 6 of 10
(4,992 Views)

Hello Melponeme,

 

Making all the raw VISA calls could be a temporary solution to get you up and running but that might be many more lines of code than you'd like to see. I would try recreating the VISA calls with visa.h and then when you are able to get some data, try and go back to working with the driver created by Ocean Optics. I'm not sure why you were unable to see the VISA calls being made with the CVI code.

 

Regards,

 

Collin D.
Software Product Manager
0 Kudos
Message 7 of 10
(4,986 Views)

Well, actually, I use viOpenDefaultRM, viFindRsrc, viOpen, viClose etc.. on labwindows to have the char instrDescriptor. That I can see it on the Ni I/O Trace (see ttest. nitrace)

What I don't see is the call the driver from Ocean Optics should do like they do on labview. It seems to simply do nothing.

 

Here is the code I use to find the instrument:

 

/*!
 * Establishes communication with the instrument and optionally performs an 
 * instrument identification query and/or an instrument reset.  It also places 
 * the instrument in a default state needed for other instrument driver 
 * operations.  Therefore, call this VI before calling other instrument driver 
 * VIs for this instrument.  Generally, you need to call the Initialize VI 
 * only once at the beginning of an application.
 */


   /* First we will need to open the default resource manager. */
   status = viOpenDefaultRM (&defaultRM);
   if (status < VI_SUCCESS)
   {
      printf("Could not open a session to the VISA Resource Manager!\n");
      exit (EXIT_FAILURE);
   }  

   /* Find all the RAW USB VISA resources in our system and store the  */
   /* number of resources in the system in numInstrs.                  */
   status = viFindRsrc (defaultRM, "USB?*RAW", &findList, &numInstrs, instrDescriptor);
   
   if (status < VI_SUCCESS)
   {
      printf ("An error occurred while finding resources.\nHit enter to continue.");
      fflush(stdin);
      getchar();
      viClose (defaultRM);
      return status;
   }

   //  printf("%d USB RAW instruments found \n\n",numInstrs);
   //printf("%s \n\n",instrDescriptor);

   /* Now we will open a session to the instrument we just found. */
   status = viOpen (defaultRM, instrDescriptor, VI_NULL, VI_NULL, &instr);
   if (status < VI_SUCCESS)
   {
      printf ("An error occurred opening a session to %s\n",instrDescriptor);
   }
   else
   {
     // DisplayDeviceDescriptor(instr);
     // DisplayConfigDescriptor(instr);
      viClose (instr);
   }
    while (--numInstrs)
   {
      /* stay in this loop until we find all instruments */
      status = viFindNext (findList, instrDescriptor);  /* find next desriptor */
      if (status < VI_SUCCESS) 
      {   /* did we find the next resource? */
         printf ("An error occurred finding the next resource.\nHit enter to continue.");
         fflush(stdin);
         viClose (defaultRM);
         return status;
      } 
     //                  printf("%s \n",instrDescriptor);
    
      /* Now we will open a session to the instrument we just found */
      status = viOpen (defaultRM, instrDescriptor, VI_NULL, VI_NULL, &instr);
      if (status < VI_SUCCESS)
      {
         printf ("An error occurred opening a session to %s\n",instrDescriptor);
      }
      else
      {
       //  DisplayDeviceDescriptor(instr);
       //  DisplayConfigDescriptor(instr);
         viClose (instr);
      }				  
   }    /* end while */     
  
						 
   status = viClose(findList);
   status = viClose(defaultRM);
   fflush(stdin);

 

 

0 Kudos
Message 8 of 10
(4,982 Views)

Hello Melponeme,

 

Yeah, if you're able to see the other VI calls but not the ones that the instrument should be making, it sounds like the .dll you created might be a little off. Have you tried using the LabVIEW Instrument Driver Export Wizard?

 

http://www.ni.com/gate/gb/GB_INFOLVDRIVER/US

 

That's the best way I know of to make a C interface from a set of VI's. If using raw VISA calls still seems to cumbersome, I would look into using this wizard.

 

Regards,

 

Collin D.
Software Product Manager
0 Kudos
Message 9 of 10
(4,973 Views)

I'm on labview 15.0, and your driver need labview to be before 8.5.

So, most probably, it's my way to do dll that does'nt work ?

 

0 Kudos
Message 10 of 10
(4,953 Views)