Jump to content
Fred chen

How to deal with clusters containing clusters?

Recommended Posts

Hi

 

When I call the DLL, there is a structure:

struct Signal
{
uint32 nStartBit; 
uint32 nLen;
double nFactor; 
double nOffset;
double nMin; 
double nMax;
double nValue;
uint64 nRawValue;
bool is_signed; 
char unit[11];
char strName[66];
char strComment[201]; 
};

 

 

There is another  Message structure to the above Signal:

 

struct Message
{
uint32 nSignalCount; 
uint32 nID;
uint8 nExtend; 
uint32 nSize; 
Signal vSignals[513]; 
char strName[66];
char strComment[201]; 
}

 

  The point is  Signal vSignals[513];

 

I've tried to solve it like this,but the program will crash.

 

How to create struct Message ,any good suggestions?  Thanks a lot.

 

qq.png

message.vi

Edited by Fred chen

Share this post


Link to post
Share on other sites

Hi,

Your issue is related to data structure alignment and padding. See https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member

By default, C/C++ compilers add padding to structs to improve memory alignment. However, LabVIEW does not add padding to clusters. So, in your DLL, the structs' memory layout is probably like this:

struct Signal
{
    uint32 nStartBit;     //   4 bytes
    uint32 nLen;          //   4 bytes
    double nFactor;       //   8 bytes
    double nOffset;       //   8 bytes
    double nMin;          //   8 bytes
    double nMax;          //   8 bytes
    double nValue;        //   8 bytes
    uint64 nRawValue;     //   8 bytes
    bool is_signed;       //   1 byte
    char unit[11];        //  11 bytes
    char strName[66];     //  66 bytes
    char strComment[201]; // 201 bytes
                          //   1 byte (PADDING)
}; // TOTAL: 336 bytes

struct Message
{
    uint32 nSignalCount;  //      4 bytes
    uint32 nID;           //      4 bytes
    uint8 nExtend;        //      1 byte
                          //      3 bytes (PADDING)
    uint32 nSize;         //      4 bytes
    Signal vSignals[513]; // 172368 bytes (=513*336 bytes)
    char strName[66];     //     66 bytes
    char strComment[201]; //    201 bytes
                          //      5 bytes (PADDING)
}; // TOTAL: 172656 bytes

There are two ways you can make your structs and clusters compatible:

  • If you control the DLL source code and you can compile the DLL yourself, then you can update your code to pack the structs.
  • If you cannot compile the DLL yourself or if you don't want to change the DLL, then you can add padding to your LabVIEW clusters.
    • Signal: Add 1 byte (U8) to the end of the cluster
    • Message: Add 3 bytes in between nExtend and nSize. Add 5 bytes to the end of the cluster.


I must say, the Message struct is huge! (>170 KiB)

Edited by JKSH
  • Like 1

Share this post


Link to post
Share on other sites

Hi,
I think you might want to read this paper. I am afraid that if you do not have access to the dll sources you will not be able to retrieve this data correctly. At the first place I would split up complex data into simpler types, then pass it to dll as separated arguments. That will make things easier in your dll code.

Regards,
Zyga

Share this post


Link to post
Share on other sites

Hi,JKSH,I really appreciate the information and advice you have given.

I will try follow your advice that you have provided me. :)

Share this post


Link to post
Share on other sites

You're welcome, Fred.

I see on forums.ni.com that your code is a bit different. In particular, your Signal array has 512 elements instead of 513. Which is it? You need to count accurately, or else your program might crash.

Also, nathand posted more important points at forums.ni.com:

  • You must configure the the Array to Cluster node correctly
  • Each Array to Cluster node can only handle up to 256 elements. So, you need to duplicate its output to reach 512/513 elements.

Share this post


Link to post
Share on other sites
On 1/15/2018 at 9:02 AM, JKSH said:

Hi,

Your issue is related to data structure alignment and padding. See https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member

By default, C/C++ compilers add padding to structs to improve memory alignment. However, LabVIEW does not add padding to clusters. So, in your DLL, the structs' memory layout is probably like this:

That is not quite true. LabVIEW for Windows 32 bit does indeed packed data structs. That is because when LabVIEW for Windows 3.1 was released, there were people wanting to run LabVIEW on computers with 4MB of memory :o, and 8MB of memory was considered a real workstation. Memory padding could make the difference between letting an application run in the limited memory available or crash! When releasing LabVIEW for Windows 95/NT memory was slightly more abundant but for compatibility reasons the packing of data structures was retained.

No such thing happened for LabVIEW for Windows 64 bit and all the other LabVIEW versions such as Mac OSX and Linux 64 bit. LabVIEW on these platforms uses the default padding for these platforms, which is usually 8 byte or the elements own datasize, whatever is smaller.

Quote

struct Signal
{
    uint32 nStartBit;     //   4 bytes
    uint32 nLen;          //   4 bytes
    double nFactor;       //   8 bytes
    double nOffset;       //   8 bytes
    double nMin;          //   8 bytes
    double nMax;          //   8 bytes
    double nValue;        //   8 bytes
    uint64 nRawValue;     //   8 bytes
    bool is_signed;       //   1 byte
    char unit[11];        //  11 bytes
    char strName[66];     //  66 bytes
    char strComment[201]; // 201 bytes
                          //   1 byte (PADDING)
}; // TOTAL: 336 bytes

struct Message
{
    uint32 nSignalCount;  //      4 bytes
    uint32 nID;           //      4 bytes
    uint8 nExtend;        //      1 byte
                          //      3 bytes (PADDING)
    uint32 nSize;         //      4 bytes
    Signal vSignals[513]; // 172368 bytes (=513*336 bytes)
    char strName[66];     //     66 bytes
    char strComment[201]; //    201 bytes
                          //      5 bytes (PADDING)
}; // TOTAL: 172656 bytes

There are two ways you can make your structs and clusters compatible:

The correct thing to use for byte packed data is

Quote

#pragma pack(1)

The following will reset the packing to the default setting, either the compiler default or whatever was given to the compiler as parameter (respectively what the project settings contain).

#pragma pack()
Quote
  • If you cannot compile the DLL yourself or if you don't want to change the DLL, then you can add padding to your LabVIEW clusters.
    • Signal: Add 1 byte (U8) to the end of the cluster
    • Message: Add 3 bytes in between nExtend and nSize. Add 5 bytes to the end of the cluster.


I must say, the Message struct is huge! (>170 KiB)

It sure is and I think trying to create this structure in LabVIEW may seem easier but is  in fact a big pitta. I personally would simply create a byte array with the right size (plus some safety padding at the end and then create a VI to parse the information from the byte array after the DLL call. And if there would be more in terms of complicated data parameters for this DLL even create a wrapper DLL that translates between the C datatypes and more LabVIEW friendly datatypes.

Edited by rolfk
  • Like 1

Share this post


Link to post
Share on other sites
13 hours ago, rolfk said:

That is not quite true. LabVIEW for Windows 32 bit does indeed packed data structs. That is because when LabVIEW for Windows 3.1 was released, there were people wanting to run LabVIEW on computers with 4MB of memory :o, and 8MB of memory was considered a real workstation. Memory padding could make the difference between letting an application run in the limited memory available or crash! When releasing LabVIEW for Windows 95/NT memory was slightly more abundant but for compatibility reasons the packing of data structures was retained.

No such thing happened for LabVIEW for Windows 64 bit and all the other LabVIEW versions such as Mac OSX and Linux 64 bit. LabVIEW on these platforms uses the default padding for these platforms, which is usually 8 byte or the elements own datasize, whatever is smaller.

TIL!

Thanks for the info, @rolfk

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.