12-16-2015 02:04 AM
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:
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.
12-16-2015 03:51 PM
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(&VISAResourceNameOut, &VISAResourceNameOut); if(error) { printf("Initialization Failed with code %d!\n", error); return 0; } error = OceanOptics20004000_ReadSpectralWaveform(&VISAResourceNameOut, &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 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,
12-17-2015 02:49 AM
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.
12-17-2015 05:16 AM
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.
12-17-2015 08:19 AM
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,
12-17-2015 10:04 AM
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.
12-17-2015 11:12 AM
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,
12-17-2015 11:24 AM
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);
12-17-2015 12:54 PM
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,
12-18-2015 03:19 AM
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 ?