I know that labview doesn't have nearly enough state machine implementations, so I thought I'd make another. This one uses oop and ended up looking a bit too much like actor framework. I doubt its useful, but it could be worth looking at.
So, in developing this I identified three pieces which I thought made sense. The first is the machine itself--the thing that gets input and calls handling code. The second is the state, which contains state data and accepts inputs. Finally there are events, which is what I decided to name those inputs. That is, a machine recieves events and passes those for handling to the states. These states may elect to execute code, generate additional events (my way of creating "epsilon transitions"), or switch to a new state. The machine facilitates these.
As an example of how the code works in a completely made up and useless situation, I chose the very common ATM example. Specifically, I stole one from here:
http://www.codeproject.com/Articles/489136/UnderstandingplusandplusImplementingplusStateplusP
Core classes:
Events:
Events, by default, do nothing. These are supposed to be kind of like the messages in actor framework. They pass generic data into the states, without using a variant.
Machine:
The machine class allows you to set an initial state (using start.vi), and wraps some other state functions, but the main thing we care about is run.vi. This method is a loop which handles an incoming event and then continues transitioning until the current state runs out of events to generate. That is, if you have a reusable block of code, in a normal state machine you sould enqueue/build array/notify/whatever a set of three actions. Here you would generate an event which goes to the first state, A. A then generates an event which causes a transition to B, B generates an event which causes a transition to C, and C doesn't have another event to go to so this method stops executing.

State:
State code is the real meat of this. First, it has three simple static methods. These methods allow a state to request a transition. This request is what allows the machine code to see if a transition is required (see stage #2 above). The rest of the functions are dynamic dispatch and do nothing by default. The purpose of these functions is to suit the needs of the engine, as shown above, and their use can only be shown well through an example.
Example (ridiculously user-unfriendly ATM):
ATM Events: This event class has N children and is really only there to add one function--"perform event". This could exist in the parent class, but putting it in the child allows us to have better type information. An ATM event will always be used with an ATM state, so we don't have to use the "to more specific class" function to guess that we have the right type of state and event input. Remember, this function is basically the same as the actor framework message class' "do" method.
Child Event Classes: Similar to actor framework, these "do" methods actually just call specific functions within the atm state class, discussed below. For example, the eject card class calls the dynamic dispatch method ATM State::Eject Card.vi.

Remember, the nice thing about having this "perform event" in the ATM event class is that we always know the incoming state is an atm state. There may of course be other situations where you need different behavior, but this is a though experiment not a solution.
Machine: Because of the defined interface of events and states, the machine code does not need modification.
ATM State: The intent of this class is to provide a few features used by other classes. First, any state information shared across states (like user pin and money available for withdrawal in this example) should be in the parent class for your device. This class is also responsible for copying this data from state to state when a transition occurs. That is, because nocard (state).lvclass and cardvalid (state).lvclass both have their own instance of the parent class, we need to move information when a transition occurs. This is one of the weirder design choices I made (open for feedback) and results in the dynamic dispatch method swap state.vi:

Here, data from the old state (which we know is of ATM state type, but we have to manually cast using the "to more specific class") into the new state.
This parent class also lets us define things that are universal for our device. For example, the state machine should always stop when you have less than $20 available. We can also make a single helper function (the override "Receive Event" which converts the grandparent classes (state and event) into the classes specific to our application.

Finally, this class defines all methods which act on our state. This allows the event interation shown above. That is, when we call "perform event" on "eject card.lvclass", what we're actually doing is calling back into ATM State.lvclass::Eject Card.vi. When this method is called, dynamic dispatch allows us to use a given implementation if and only if the current state allows it. That is, if we are in the state nocard.lvclass, which does not override eject card.vi, sending the eject card event does nothing. It calls the eject card instance of the parent class which, in our case, does nothing.
So, have I confused you yet? If so, I think this should simplify things--the call chain is actually very linear, just a bit unusual:

ATM.vi:
The actual code for this becomes kind of trivial once its been set up. (of course, its a really trivial problem so that certainly helps).

If you generate en event--like "get cash"--in a state that can't handle it--like "No Card"--then nothing happens (or a default action occurs). If the event can be handled, the state does whatever it does, and may also request a transition to a new state. For example, if you enter pin 1233 we might not request a transition, while entering 1234 would lead to "card valid" state.
So, if you've read this far--thanks. Again, this was really just a little experiment, but I do hope someone finds a use for it.
Can you append ver2012? thanks!
done ![]()