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: 

How does the "Flatten to string" function actually work?

Is there a workaround? Like building a .net dll out of the labview function and then using it in my application?

0 Kudos
Message 11 of 45
(1,767 Views)

Well theoretically yes. Practically I think you will have a huge problem. That DLL will be rather complicated.

Once you receive the data from the wire and then pass it to that DLL to be passed to the Byte String to Variant function you have the situation that you have the fully constructed Variant and now have to get it back into your application.

 

Basically the whole architecture of the current application is build in such a way that it now has an Anything data and needs to find out what this Anything is. This is done by the Variant Type functions in LabVIEW which you can use to introspect the Variant. So you need to know what you expect in the Variant in some way and go from there and then parse it dynamically. Then you could of course put everything back into Windows Variants and pass that to your application. Then do the whole game on your client side again with introspection of the passed back variant. Possible yes! Easy? Hell no!!

 

If the number of possible data formats in the variant is limited you could probably do the introspection in the DLL and then pass that data back in a simple format. If the number of Variants that can be generated by the host is however high this is surely going to be a nightmare and one could ask if the original developer gained anything by trying to seperate host and client through something like that as they clearly are anything but separated from each other. Any change of the data format on the host side will require modifications of the UI client to adapt to that.

Rolf Kalbermatter
My Blog
0 Kudos
Message 12 of 45
(1,763 Views)

As rolfk explained the conversion seems to be done in a 'LabVIEW'-internal format.

Since we don't know the format of your variant, and that serialisation isn't a open format like protobuf 

your client and application are linked. (So a future requirement migth be to add a protocol definition;) )

A quick try get me to this:

conversion01.png

 

  My guess got quite close  😉 , however the "Abs" seems to be predefined in an other way...

You have the sources... that already help a lot. The 'easy way' if you need a link to another client app would be to write a wrapper in that LabVIEW version ...if you can't change the main application.

I don't know how many different message types you have, but this type looks quite simple...  (if you use a custom probe with a string set to hex display , I bet you identify 3 numbers (two floating and a I32?) 😉 

However, if client and application got recompiled to another LV version that migth change.

 

 

 

Greetings from Germany
Henrik

LV since v3.1

“ground” is a convenient fantasy

'˙˙˙˙uıɐƃɐ lɐıp puɐ °06 ǝuoɥd ɹnoʎ uɹnʇ ǝsɐǝld 'ʎɹɐuıƃɐɯı sı pǝlɐıp ǝʌɐɥ noʎ ɹǝqɯnu ǝɥʇ'


0 Kudos
Message 13 of 45
(1,749 Views)

"Once you receive the data from the wire and then pass it to that DLL" 
I need to go the other way around - create the flattened string in order to send it over the wire to the machine.

0 Kudos
Message 14 of 45
(1,741 Views)

I don't think it's quite as bad as Rolf's 'Practically I think you will have a huge problem' suggests, because as I understand it in your case you have the LabVIEW code and can inspect it to see what data types are originally going into the variant, and coming back out again if your app also needs to receive flattened-variant data - you're trying to encode/decode a known data structure to/from variant, not arbitrary data. So you can build a DLL that takes that data structure from your external code, flattens it by the same process as your existing LabVIEW code, and returns the result, and vice versa if necessary.

0 Kudos
Message 15 of 45
(1,717 Views)

Thinking about it a bit more I believe there is a fairly straight forward way, or actually two:

 

1) Create a LabVIEW .Net DLL that gets the byte buffer from your application (assuming you want to do the actual TCP/IP communication in your .Net GUI). In the DLL run this "string" through the Flattened String to Variant function, then through the Flatten to JSON function. Return the resulting string to your .Net application and start parsing the JSON string in whatever way you want to in your .Net application.

 

2) As a follow-up step improve the LabVIEW server application to allow to set a protocol format on connection request from the client. By default if nothing is requested (the old LabVIEW GUI application) just continue to serve the Variant to Flattened String stream to the client. If the client however requests JSON (or XML or whatever you want to add to the plate) on the initial connection request, store that format along with the connection and when serving data to the client, format the response according this format, replacing the Variant to Flattened String with the Flatten to JSON or whatever other format you chose. This will remove the need to use a LabVIEW generated .Net assembly on the client and avoid to have to install the according LabVIEW runtime engine on that machine. If the LabVIEW server is programmed relatively clean it should be fairly straight forward to add this extra variable to the connection handle (object or DVR or whatever) and use it in the final step of sending data over the wire. Basically you just have to allow a way to request a format from the client after connection and then create a case in the sending routine that uses the Flatten method that matches the requested format. You can keep the extra Flatten to String in all cases to make it prepend the actual length of the byte-stream data that follows.

Rolf Kalbermatter
My Blog
0 Kudos
Message 16 of 45
(1,700 Views)

I did some analysis of this some time ago and it's not extremely hard. First thing you need to do is look at the data as hex-mode instead of normal text (change radix). I don't remember all the details, but if you start with a single value and/or an empty array/cluster and slowly change stuff you will see a pattern emerge. A couple of things has already been mentioned, like the first 4 bytes being an Integer saying how long the string is. If it's an array or cluster this will say how many elements is included. With a Variant you'll get your type definition and then the data, with a Flatten you'll just get the data part.

 

I don't have LV on this computer so all details are very approximate. 🙂 Also, since Variants and Flatten is 'internal' functions they might differ between versions.

But, as experiment, an Error cluster would look something like:

00 00 00 03 [3 elements as int]

00 [boolean as byte]

00 00 00 00 [error code as int]

00 00 00 00 [string length as int]

00 [String as char/byte array]

 

/Y

 

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 17 of 45
(1,677 Views)

@Yamaeda wrote:

I did some analysis of this some time ago and it's not extremely hard. First thing you need to do is look at the data as hex-mode instead of normal text (change radix). I don't remember all the details, but if you start with a single value and/or an empty array/cluster and slowly change stuff you will see a pattern emerge. A couple of things has already been mentioned, like the first 4 bytes being an Integer saying how long the string is. If it's an array or cluster this will say how many elements is included. With a Variant you'll get your type definition and then the data, with a Flatten you'll just get the data part.

 

I don't have LV on this computer so all details are very approximate. 🙂 Also, since Variants and Flatten is 'internal' functions they might differ between versions.

But, as experiment, an Error cluster would look something like:

00 00 00 03 [3 elements as int]

00 [boolean as byte]

00 00 00 00 [error code as int]

00 00 00 00 [string length as int]

00 [String as char/byte array]

 

/Y

 


Clusters do not prepend the length since they have a defined length/number of elements.  Any strings and/or arrays inside of the clusters will prepend their size for their part of the data.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 18 of 45
(1,669 Views)

@crossrulz wrote:

 


Clusters do not prepend the length since they have a defined length/number of elements.  Any strings and/or arrays inside of the clusters will prepend their size for their part of the data.


Thanks. I said the details were approximate. 😄

 

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 19 of 45
(1,667 Views)

Flatten Variant.png

So, Variant to flatten data and Flatten data gives the exact same result. As mentioned it's a pure byte conversion sent as text, in this case:

01 - 1 byte for Boolean

00 00 04 D3 - 4 bytes for the integer with the Error code

00 00 00 07 - 4 bytes for the integer saying how long the string is

7961 6D61 6564 61 - 7 bytes with the string.

Changing the string indicator to 'normal' mode is useless in this case.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 20 of 45
(1,626 Views)