I'm working on a set of drivers that call functions from a DLL provided by the instrument manufacturer. They have an extremely detailed manual, which has been very helpful. When they describe the functions (and the different values I can pass), they use named constants, and then at the end they define the value of each constant.
This sort of thing works great in a text-based programming language: just assign the appropriate values to the constants at the beginning and you're ready to go. But what's the best way to store these constants in LabVIEW?
My initial approach was to use (strictly typedef'd) text rings (or occasionally enums): the constant name was the text string, and the numeric value was the value of that string. The problem is that they occasionally have multiple constants with the same numeric value, and LabVIEW doesn't let you have duplicate values in a text ring.
The thing I really like about using text rings is that this way, I have all of the values at hand to use in a control or a constant; I just plop down the appropriate text ring and select the constant I want. It's also easy to keep consistent across all of the VIs in the project, since it's a typedef.
But...since it looks like this won't work, at least not completely, what's the best alternative? Enums wired to case structures that pass out the appropriate value? Dual arrays, one with the constant name and the other with the value? Something else? The downside is that all of the above need some sort of wrapper VI, but I can't think of a way around that. What would you do?
Unlike an enum, the ring's data isn't really part of the typedef. If you drop a (strict typedef) ring constant on the diagram, the data is only up-to-date as of when the constant is dropped on the diagram; it isn't dynamically updated to reflect changes in the data of the underlying typedef. (And of course anything goes with non-strictly typedef rings, where you can set the strings at runtime.)
As for the best solution, I don't know. Despite the above problems with rings I have still used them for this purpose since usually the definitions don't change with time. Your idea of using an typedef enum + case statement in a VI seems like the safest approach for constants that can have duplicate or nonconsecutive values.
The two array constant way works good with a search. You search the string array and index the number array. Throw a error if not found (search gives index -1).
You might want to simplify your life by writing a parser vi (propably they give you some header (*.h) file. After parsing you just convert the indicators to constants and voila. You could also use a text ring control and use the Strings property to fill it, laterconvert it to the strict type def.
Nice inputs so far.
My approach to this type of problem is to not store the constants in LabVIEW at all. The problem, restated, is how to associate a name and a value (of indeterminate type?) right? Config files work well for this! just let the key:value pairs associate your data.
[Power on State]
These really are some good suggestions. Rob, thanks for pointing out that even a strict text ring wouldn't be dynamically updated. I'll definitely need to remember that. I'm leaning toward using a global to store the values, and then setting it to private inside the driver project. Maybe I'll make it read-only too. I think that will satisfy the "Don't touch!" (don't write) goal. (I was sort of tempted to be a bit more protective and go with constants inside of a case structure, with a strict typedef enum to select which one to read out, but the read-only global is appealing because it eliminates one layer of wrapping.)
Then for the actual controls that will be exposed to the user, I'll create strictly-typedef'd enums that will have more user-friendly names than, say, cExpo2Max. These will be wired to the selector of a case structure, which will map the enum value to a particular variable in the global.
I am intrigued by Jeff's idea, though. I've not really worked with config files in LabVIEW. Once I read in the key:value pairs, how do I make that data accessible to the rest of the project? Do I have to have a VI of some sort with the controls already created, and I just read in the matching values, or...? (I'd love to learn another way of doing this! Especially if it can simplify things.)
One of the most interesting ways to store constants is by using a variant and placing the constants name-based as attributes:
See this nugget from Darren for some more info
My first thought was a text ring control too..but did not realize there would be that limitation as well as the type-def not updating the rings. Text ring and enumerator constants do look nice and tidy and are easy to read on block diagrams *sigh*.
The solutions proposed that use Config files, variants, and arrays doesn't sit well with me as a solid solution. Kind of loses sight of the fact that these things are meant to be constants and not variables or settings. They are meant to be hard-coded values that do not require any "searching" at runtime other than the compiler swapping the constant names with the constant values. I'm sure the performance ramifications of this are not significant (although do exist). Still, the fundamental concept from a text based programming language to LabVIEW seems to have been lost.
If the text ring constant values in a type-def auto-updated the constants and allowed for multiple values to be the same I think that would be ideal.
Sorry, I don't have a solution. Just wanted to add to the discussion.