09-08-2011 02:50 PM
Hello All,
This is my first post on the NI Discussion Forums - exciting! I have only been using LabVIEW for a month or so now and I absolutely love it. Here's a description of conundrum I'm in - hopefully someone with a bit more experience can help me out.
I will have a series of typedefs (each containing different types and amounts of data) that I wish to convert to variants. I then wish to store each of these variants in an array in an arbitrary order, chosen by some user. I would then like to convert that array to a variant, flatten it to a string (or binary maybe?) and store it in a MySQL database. For simplicity's sake, let's call the array of variants data a "Sequence". There will be many Sequences residing in this database.
When I read any random Sequence out of the database, I must unflatten it before it is again useful to me. My problem is that I do not know the specific type of each variant at any given position in this Sequence in order to unflatten it. The order of each variant is arbitrary. How can I go about unflattening this data without knowing which type a specific variant in the array may be? I am beginning to think that LabVIEW doesn't have the flexibility for something like this. In my case, it doesn't need to be all that efficient, it just needs to be relatively simple to implement. Am I asking too much of LabVIEW to be able to do this?
To circumvent this, I am thinking that I could also store, in the same row in my database, a comma delimited string that contains indicators denoting order of typedefs stored in the variant array, and then use a case structure to choose the type to use for unflattening. I am just hoping that I can find a bit simpler, and more elegant solution.
I hope that wasn't too confusing. I look forward to your suggestions and learning more about the intricacies of LabVIEW in general. Thanks for the help in advance!
-Jim Neumann
09-08-2011 03:26 PM
What you can do is store an array of clusters and flatten that. The clusters will contain two items - one is your variant and the other is an enum or string identifying the type. Convert that array to a variant or flatten it and store it.
When you retrieve a sequence you know how to unflatten the array. You will have an array of clusters and each has an enum identifying the type. Loop over the array. For each iteration feed the enum to a case selector. Inside the case structure you will know the type of the variant in order to unflatten it.
09-08-2011 04:13 PM
One approach would be to assign every variant an attribute that tells you what type of data it contains. So long as every variant has an attribute with the same name (but different data), you'll be able to load any of the variant data, get that attribute name, and use the value to determine how to convert it back to usable data. When you flatten a variant to a string (using "Flatten to String", but NOT when using "Variant to Flattened String") the attributes are preserved.
09-09-2011 03:48 AM
I hesitate to suggest this to someone with one months LabView experience, but, you might want to explore LVOOP, the ability to define object classes in LabView. Your proposed use of variants is practically "poor-man's LVOOP".
Basically, your clusters would become child classes of a parent class (let's call it "Step"). Your Sequence would be an Array of Steps, which can be flattened and added to the database. Unflattening would be easy as you just have to know that it is an Array of Steps (the individual Steps know which child class they are; you don't have to know what they are to unflatten them). Using your Sequence in your program would be a lot easier also if you learn something called "dynamic dispatch".
-- James
09-09-2011 04:02 AM - edited 09-09-2011 04:03 AM
Here's an image from a project I'm working on, involving a Furnace and Camera and a sequence of Steps ("Actions") to do things like ramp the temperature, turn on/off the camera, hold temperature for a period of time, etc. Each Action contains a cluster internally that is different for each type, yet they can all be combined in arrays.
09-09-2011 11:37 AM
Thanks for the insight, drjdpowell. I think this is exactly what I need. Lookign at your Ramp (rate) class, does your Get method simply unbundle and rebundle the data in the class to an output cluster so it can be accessed publicly? Should I be using the accessor methods instead? If i were to build my system this way, some of my classes might end up with a lot of a lot of data inside of them, thus a lot of read and write accessors in my project folder - seems like a lot of extra VIs. Is this standard practice?
Still very new to this LVOOP thing, so please excuse me if some of my terminology is incorrect.
09-09-2011 02:15 PM
You will find that typically with LVOOP you will have many more VIs but they tend to be very simple. You can easily create the accessors by right clicking on the control data and selecting create accessor. The VIs will be created for you. You can create read or write accessors (or both) for multiple controls simultaniously. Just go get a cup of coffee while two hundred VIs are being magically created.
One other thing you can do is to make the data available via property nodes. There is a checkbox for that in the create accessor tool.
09-10-2011 04:19 AM - edited 09-10-2011 04:21 AM
Before you follow up on Steve's excellent advice and automatically create accessors for 101 data items, first step back and consider a few things:
1) is any of this data common to all your "Steps"? Because such data should be a part of the parent class, allowing all its children to "inherit". My individual "actions" don't actually have an individual data, they all use the parent's ("ProfileAction") data cluster. And they thus can all use the parent's accessor VI's (as well as several other VIs belonging to the parent class):
2) Is any of your data closely related enough that it should really be it's own typedef subcluster (or better yet, it's own class)? If so, combine it, and you will need many fewer accessors. ProfileAction, for example, only has one item of data, an array of "TableCells", which is the parent of a set of object classes for User-enterable cells is a table displaying the list of actions.
3) Do you need to access everything outside of a VI of the class itself? A VI belonging to the class itself can access the data cluster by bundle/unbundle. For many operations, it's easier to let the class itself have a VI to do it, than access multiple items and do the operation outside.
-- James
09-10-2011 10:57 AM - edited 09-10-2011 10:59 AM
Absolutely true, if you are creating 101 accessors you should think about the design
The point is that the mechanics are simple with a lot of convenience features that you would not otherwise get. The design of an object oriented program is it's own science/art.
But bonesjackson, don't let the advanced features of inheritence and polymorphism and the various design patterns scare you off. You can do a lot with just the basics. At the heart of it LabVIEW classes are nothing more than a cluster with VIs that have permission to bundle and unbundle it.
Play around with it and don't worry that you are not initially creating a "correct" OOP design. Get your feet wet. Jump in and splash around a little. That is the only way to learn how to swim.
You will find a lot of books on correct object oriented programming. Some can be quite intimidating. The one I recommend is The Object Oriented Thought Process. The examples are in Java but are simple enough to understand even if you don't know Java. It is not one of those huge 1000 page books with nothing but images. I think it is only around 200 pages and gets right to the point.