Queued state machine – is one of the most favorite and popular architecture used in LabVIEW programming. There is no need to focus on this architecture itself now, the point of this post is: what is better to use as an element for a queue, particularly for state definition element – enum, or string data type?
There are two main most popular ways to implement queue for the Queued state machine: to use typedef cluster, which contains typedef enum for state selector + variant for data transfer; or cluster with string for state selector + variant for data transfer.
I found, that usage of string for state selector in the queue gives more benefits, than enum. And these are couple thoughts about it.
- Strings make code more scalable and reusable.
Just imagine: while implementing application, you can have several loops, so also several queues. And then, after some time, you would like to reuse existing code (main loop, let’s say) in some new application. And if the new application will have some another needed states, then you need to update typedef for the queue. After it, this main loop will not be reusable in the old application. Plus – if you will update enum, then the case structure in that main loop can be also “broken”, b/c it will have definitions of the states, which do not already specified in the enum.
But, while using queue element for state machine with the string data type, you will not have this problem – basically, you will add state to case structure, but if something, this case structure will be compatible with the old application.
But, maybe, this is not the main point here. More important is need to keep on disk typedef enum + typedef cluster for each used queue. And imagine the next situation: you have project, where you have some main loop with the queue. And now, you’d like to keep in the same project, the copy of main loop, but with some modification of the states/their names/etc. But it means, that you need to rename your typedef enum, rename typedef cluster (on the disk, to avoid conflicts in the project), and to change/replace in the copied main loop all the used cluster/enums from the original main loop. A lot of work…
While using strings – no problem with it, at all. Just copy your loop, change states in the code – and don’t care about data types changes.
One more point to this – if you are creating some project templates, frameworks, etc., you are not going to use queues based on typedef enum. B/c it is not efficient from the point of view of modification/distribution. And this typedef enum will be the problem, b/c after update of its value, some parts of code can become broken.
Let’s also not forget, that LabVIEW sometimes is “slow” for updates, so if you update typedef enum, which is used in many places of your application, reloading of the code can take some time, what is quite annoying. With the strings no update is needed, no reloads.
- With strings, block diagram looks nicer.
While using string for state transfer via queue, you can decorate your case structure in the state machine loop in the following way:
It looks really nice, because states are grouped via separators, “sections”, etc.
Yes, the similar is possible to do with enum. But it means, that in typedef enum you need to create such value, like, let’s say “<—————- CAN Configuration <—————-”. And it will look afterwards weird: why to keep separator name inside of the list of state machine states names?
Also, if you use string for queues elements in all your queues in the application, you can decrease number of components on the block diagram. Because you have all the time the same data type. What I mean? This one:
It really looks a bit better, than this one, isn’t it?
- Strings are better to use for logging/tracing.
This point is not so straightforward, but I’ve highlighted it because of one experience in the recent past. If you want to log to some trace file names of the executed states, with string you directly use its value. For enums – you need to use Property Node: Stirngs, index that values array, and after it you’ll have sting data type as state name.
And this is not a problem for desktop targets. But for Real-Time targets, it is – b/c you can not use Property Node there. In this case you need to specify states names in the case structure in the state machine, what is additional work.
Plus, for RT targets we also have some small issue while using typedef enums / typedef clusters for the queues – b/c this is additional usage of memory. For “modern” controllers it is not a problem, but for old one, with 256 MB of RAM on the board – you’ll fight for each kilobyte of the memory.
But, anyway, memory usage is not such a big problem at the end…
- Using strings as selectors (not even for queued state machine) instead of enums is better for TestStand.
Yes, even for TestStand it’s really better. You can pass string value as selector from Sequence Call to subsequence (in case of enum you need to pass there numeric data type, TestStand will not “catch” string value of enum state).
If you need to add some additional state to case structure inside the code module, you don’t need to update code modules inputs, as in case of enum (if you change enum states).
For sure this statement is valid to TestStand up to 2014 version. I didn’t play so much with TestStand 2016, where it has (finally!) TS “native” enum data type.
Well, this is it. These are the main theses regarding this topic. I’ve switched to string-bases state machines, and I am more satisfied with it, then with the previous approach, mainly because of the mentioned before benefits of string usage. Of course, there are some drawbacks for it (like, you need to be careful with mistypes of states name; while changing state name you need to manually update it in all places, where it is set up, etc.), but as per now it was not so annoying or critical… Even for some FGV, sometimes it’s better to use strings as command/state selector – especially, when you use this code module in TestStand, and you are not sure about future modification of it…
Thanks for reading, hopefully that this post was (or will be) useful at least for someone.