LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

DLL Pointer within a Cluster

Solved!
Go to solution

LV - 2010; Windows XP SP3.

 

I am currenly using a Yokogawa DL850 ScopeCorder to acquire data.  The scope will save data to a .wdf file as a standard.  Because this scope is capable of saving cycle history (>20,000 data records) to a single file, I thought it would be best to create a LabVIEW VI to open the file and run some analysis.  Through Yokogawa, I did receive a library of functions I can call from within LabVIEW to get certain data items out of the .wdf file, mostly the header information (Channel names, settings, units, ...).  However, I cannot get the actual measurement data API to work.

 

The functions which I have had success with require passing individual parameters.  The WdfGetScaleWave64() function requires a Handle and a TypeDef of several parameters bundled together (a cluster).  Here is the header file from the API.

 


 

/** WDFAccessParam64‰Šú’l / WDFAccessParam64 default value */
enum{
 WDF_DEFAULT_ACSPRM64_VERSION  = 1,      /**< for WDFAccessParam64::version */
 WDF_DEFAULT_ACSPRM64_PPRATE   = 131072, /**< for WDFAccessParam64::ppRate */
 WDF_DEFAULT_ACSPRM64_WAVETYPE = 0,      /**< for WDFAccessParam64::waveType */
 WDF_DEFAULT_ACSPRM64_DATATYPE = 0,      /**< for WDFAccessParam64::dataType */
 WDF_DEFAULT_ACSPRM64_COMPMODE = 0,      /**< for WDFAccessParam64::compMode */
};

#pragma pack(push, a)
#pragma pack(8)
/**
 * Žæ“¾”gŒ`ƒf[ƒ^‚̃pƒ‰ƒ[ƒ^Œ^ / Getting waveform parameter type.
 */
typedef struct{
 UINT            version;  /**< [in]  Internal Use, fixed WDF_DEFAULT_ACSPRM64_VERSION */
 WDFTrace        trace;    /**< [in]  “ǂݍž‚ݑΏ۔gŒ`ƒgƒŒ[ƒX / Target Trace */
 WDFHistoryBlock block;    /**< [in]  “ǂݍž‚ݑΏۃqƒXƒgƒŠƒuƒƒbƒN / Target History Block */
 WDFDataBlock    start;    /**< [in]  ƒf[ƒ^ƒuƒƒbƒNŠJŽnˆÊ’u / Start Index of Data Block */
 WDFDataBlock    count;    /**< [in]  ƒf[ƒ^“ǂݍž‚Ý—v‹“_” / Request Read Count */
 INT64           ppRate;   /**< [in]  ƒf[ƒ^ˆ³k—¦ / Data Compress Rate, fixed WDF_DEFAULT_ACSPRM64_PPRATE64 */
 INT             waveType; /**< [in]  Internal Use, fixed WDF_DEFAULT_ACSPRM64_WAVETYPE */
 INT             dataType; /**< [in]  Internal Use, fixed WDF_DEFAULT_ACSPRM64_DATATYPE */
 WDFDataBlock    cntOut;   /**< [out] ƒf[ƒ^“ǂݏo‚µ“_” / Read Data Count */
 void*           dst;      /**< [in]  ƒf[ƒ^o—̓oƒbƒtƒ@ / Data Output Buffer
                                 @note (1ƒuƒƒbƒN‚̃f[ƒ^ƒTƒCƒY * count)ƒTƒCƒY‚̃oƒbƒtƒ@‚ðŠm•Û‚µŽw’è‚·‚éB <br>
                                       ƒf[ƒ^ƒuƒƒbƒNŒ^(WDFVDataType)‚É‚æ‚Á‚ÄŠm•Û‚·‚郁ƒ‚ƒŠƒTƒCƒY‚ªˆÙ‚È‚éB*/
 INT             box;      /**< [out] NoUse */
 INT             compMode; /**< [in]  Internal Use, fixed WDF_DEFAULT_ACSPRM64_COMPMODE */
 INT             rsv1;     /**< Reserved */
 INT             rsv2;     /**< Reserved */
 INT             rsv3;     /**< Reserved */
 INT             rsv4;     /**< Reserved */
}WDFAccessParam64;

 


The function returns a "Parameter Boundary" Error.  I have contacted the folks at Yokogawa and their response was;

 

"Unfortunately, using the WDF File Access API is not the complete solution to extracting WDF data into LabVIEW. The problem lies with LabVIEW. LabVIEW does not support the “Pointer” parameter, which is used in some of the functions in the WDF File Access APIs. In reality, the engineer who created this API is not a LabVIEW programmer and was hence not aware of this limitation in LabVIEW. Therefore, the API (DLL) was never designed to be supported from LabVIEW. Nevertheless, for most functions, the API (DLL) does work from LabVIEW. Except the function related to getting the actual data, which is “WdfGetScaleWave64”. This function uses a pointer as one of the parameters. LabVIEW uses Clusters and cannot convert a pointer into a Cluster. Hence the limitation."

 

Has anyone faced a similar issue or know if this is indeed a LV issue?

 

In the meantime, I am saving both the .wdf file for the header information and a .fpd file for the raw data and opening both in a single LV VI.  I would like to only use the one file.

 

Thanks,

Josh

0 Kudos
Message 1 of 35
(6,782 Views)

You can handle pointers in LabVIEW, it's just not simple.  Can you post the function prototype for the function you're trying to call?  Do you have any documentation about what "dst" should point at?  How large does the buffer need to be, and do you need to fill it with anything before you call the function?

 

You'll want to create a cluster in LabVIEW that matches the C struct.  In place of the pointer, put in a pointer-sized integer (most likely 32 bits unless you're running LabVIEW for a 64-bit platform).  Call DSNewPtr (search on this forum, or in the LabVIEW help) to allocate the right amount of memory.  That will return a pointer that you can bundle into the cluster.  Then pass the cluster to the function.  After the function fills the data, unbundle the pointer from the cluster and use MoveBlock to copy the data into a LabVIEW array, then manipulate it as necessary.  If you post the relevant portion of your LabVIEW code, along with the C function prototype, someone may be able to help you configure the Call Library Node parameters properly.

Message 2 of 35
(6,775 Views)

Nathand,

 

The .zip file contains:

.DLL

Test0000.wdf acquired using the DL850 Scope

LV program thus far (ver. 2010, 32-bit platform); refer to sequence #6.

Other reference material that was pacjaged with the DL850.dll

 

If "dst" is the raw data, that will be 40040 measurements in size for the attached .wdf file (block size).

 

Function prototype:

 

int32_t WdfGetScaleWave64(uint32_t handle, void *param);

 

I have tried setting dst equal to an array of I32 with n=40040 and including that in the cluster.  No success.

 

Thanks,

Josh

0 Kudos
Message 3 of 35
(6,771 Views)

I think you left your VI out of the zip archive.

0 Kudos
Message 4 of 35
(6,756 Views)

Sure did.  Now added.

0 Kudos
Message 5 of 35
(6,753 Views)
Solution
Accepted by topic author jrayeske

OK, I think I've made it work.  See attached (I flattened your VI into one long chain of calls, without the state machine and local variables).  The key fix was adding one extra 32-bit padding element to the param cluster, because the header file specifies #pragma pack(8).  That means that items in the struct are aligned on the smaller of the item's size, or 8 bytes.  The param struct starts with three 4-byte values, followed by an 8-byte (64-bit) value.  In order to align that 8-byte value properly (on an 8-byte boundary), an additional 8 bytes of padding are needed ahead of it.  I may also have changed the dst parameter to 32-bit integer (I can't remember now if you had it as 64 bits or 32 bits, but it's working as a 32-bit value).

 

Be careful about your DLL calls.  In the call to DSNewPtr, you are passing the size parameter by pointer rather than by value.  At least on my machine this caused a "Not enough memory" error because it tried to allocate an amount of memory equal to the address of the size parameter.

 

EDIT: one more note, I changed DsNewPtr to DSNewPClr so that if the data came back as non-zero I'd know the DLL call had filled it.

Message 6 of 35
(6,733 Views)

Thanks a million (and a kudos) Nathan!

 

I had noticed the #pragma line, but I had no idea what that was.  To be honest, I'm still not completely clear on it, but your explination did help a bit.

 

Now I can move with this project!

0 Kudos
Message 7 of 35
(6,726 Views)

 


@nathand wrote:

The param struct starts with three 4-byte values, followed by an 8-byte (64-bit) value.  In order to align that 8-byte value properly (on an 8-byte boundary), an additional 8 bytes of padding are needed ahead of it.


 

Minor error in the above sentence which probably makes the explanation of packing more confusing than it should be.  That should say "an additional 4 bytes of padding are needed."

0 Kudos
Message 8 of 35
(6,672 Views)

I'm trying to do the exact same thing.With help of the code presented here I got to the point that I get exactly half of the data out my .WDF file of 100k points, multiple channels, the rest being padded with zero's.The position of the valid data also changes. First time I read a file, the 50% zero's is in the middle of the array, the next time it is in the first half.

 

This makes me think there is something wrong with the use of the buffer management blocks, (also because Labview keeps crashing badly 😉

 

Did you have better luck? Something that works?

 

I also would like to know where I can find information on the Labview library used, because at the moment I can only guess at what the blocks are supposed to do...

 

And of course, the padding added to the WaveGet struct doesn't make me sleep better either...

 

Thanks,

Frank

 

 

0 Kudos
Message 9 of 35
(6,396 Views)

Can you upload your code?

 

To which LabVIEW library are you referring?  The code I uploaded earlier in this thread does not make use of any LabVIEW library, only the built-in "Call Library Function Node" and a DLL that the original poster provided (along with documentation for it).

0 Kudos
Message 10 of 35
(6,384 Views)