Jump to content
jgcode

JKI State Machine Sub States

Recommended Posts

Howdy, I wanted to post what I have been working on lately in order to get some feedback.

There has been some discussion about managing a large number of states in a state machine neatly.

Jim Carmody came up with this brilliant solution.

This particular implementation is also based on the JKI State Machine mainly due to the fact I now seem to be using it all the time (I have become addicted).

I have been working on modifying the architecture of the state machine to accommodate a large number of states by introducing sub states.

I also want to do it in such a way I can upgrade existing code quickly and easily.

If a group of states (e.g. UI) gets too large, I will move all UI states to their own case (owned by the separator case).

This seems to be neater and easy to read then having to scroll the state drop down menu when the number of states starts getting large.

Plus the states are all grouped, so it is quite natural for them to sit together (IMO) in an owner case.

post-10325-125914513628_thumb.png

The JKI Syntax lends itself really nicely to this. So I wrote a parser that is a wrapper for the JKI Parse State Queue.vi.

If no sub states are configured with the parser, then the VI behaves exactly the same as the JKI parser.

With respect to the state machine, everything else stays the same, so no code gets changed as such, just its location really.

I guess a disadvantage to this is readability from the point of view that I have now have increased the nesting of case structures.

But so far adding depth the the state drop down menu on the block diagram works fine.

post-10325-125914513833_thumb.png

I am sure other people have done this before, anyone care to discuss the advantages and disadvantages to such a design?

Cheers

JG

JKI State Machine with Sub States (LV8.2).zip

[LabVIEW 8.2]

  • Like 1

Share this post


Link to post
Share on other sites

Wouldn't it work to set the main state case to:

'---------------UI------------, UI: .. UI:z' ?

No need for an extra VI.

Ton

Share this post


Link to post
Share on other sites

You may also pass substates as parameters:

"State Name >> SubState Name"

Share this post


Link to post
Share on other sites

Hi JG,

This looks like an interesting way to group substates.

I could only think of a couple drawbacks:

  • You can't see all the states in one glance (but, I guess if you have a great many states, you can't effectively do that, either)
  • You can't easily move a substate from one category to another (for example, rename "UI: Open Control Panel" to "Control Panel: Open UI").

Cheers,

-Jim

Share this post


Link to post
Share on other sites

I'm not a fan of substates or nested states. I've gone down that road many years ago and came to the conclusion that it's simply too hard to work with. It makes the code harder to trace and debug. I had a colleague that swore by that technique. I hated working on his code.

If the code on the diagram is so complex that you need to break it down into nested states then I would consider using more subVIs instead. Makes the code easier to work with and debug.

Share this post


Link to post
Share on other sites

I'm not a fan of substates or nested states. I've gone down that road many years ago and came to the conclusion that it's simply too hard to work with. It makes the code harder to trace and debug. I had a colleague that swore by that technique. I hated working on his code.

If the code on the diagram is so complex that you need to break it down into nested states then I would consider using more subVIs instead. Makes the code easier to work with and debug.

I'm not a big fan of the queued message handler to begin with. Throwing in nested states and substates gives me a headache just thinking about it. blink.gif

Share this post


Link to post
Share on other sites

There has been some discussion about managing a large number of states in a state machine neatly.

Jim Carmody came up with this brilliant solution.

   Stop. :wub: You're embarrassing me... 
[...] If a group of states (e.g. UI) gets too large, I will move all UI states to their own case (owned by the separator case).

This seems to be neater and easy to read then having to scroll the state drop down menu when the number of states starts getting large.

I addressed this issue (to my satisfaction) in the CaseSelect RCF plugin by using a tree with collapsible branches.  The context menu lets you collapse or expand them all at once so you don't need to scroll past a long list. 

I like the work you did, however I almost got my feelings hurt in another thread that suggested *gasp* that a State Machine should never have as many states as I use.  One thing I got out of that discussion got me thinking of my habit of using macros.  I make a macro to perform a complicated function, but the steps of that function are all exposed as well.  It's not so much trouble for me to maintain the software, but someone else after me may not recognize the utility of the macro and either miss some necessary steps or waste time redeveloping it.  I'm thinking that I need to use sub-VIs rather than more sections in my State Machine. (Encapsulation?)

Jim

Share this post


Link to post
Share on other sites

I like the work you did, however I almost got my feelings hurt in another thread that suggested *gasp* that a State Machine should never have as many states as I use.

I'm thinking that I need to use sub-VIs rather than more sections in my State Machine. (Encapsulation?)

Thanks Jim

I used to be an enum/variant guy myself (I was exposed to my first LV State Machine in an NI course). And I was reluctant to use strings. I started using the JKI State Machine when it came out and after a while, I couldn't stop using it. When I combined this with encapsulation (in particular LVOOP), I started to make some really neat code (IMO :)) that did, as you say, cut down the number of unnecessary states (and logic) due to encapsulation.

Is there an agreed maximum number of states before readability becomes a factor? I find I can still easily fill the State drop down menu list out of the screen for medium-large UI's - there is already quite a few states in the template to start with. For dialog boxes, and small UI's this is not such a problem, but for my main UI it does become harder to read, I find, by scrolling. I usually find states map to user functions (play, stop, pause) so that is ok, but I can have a lot of "UI" states. This are normally quite basic e.g. Set A, Get A, Set B, Get B etc.. Maybe I need to encapuslate the UI more with X-controls, but I don't know if that's the best work-time tradeoff if the UI is not going to be reusable? Do other people find encapsulating the UI using X-controls is worth the effort?

Another way is to push out UI commands via a queue to another loop. Benefits of this is that updates to the UI can be asynchronous and the UI can be abstracted from the main engine VI (if user inputs are also accounted for) but this limits sharing the statefullness of the original state machine which, IMO is one of the key benefits I get e.g. I can use more LVOOP and not worry about sharing data byRef with another loop :) (this makes me very happy).

[Thinking out loud] Maybe I have too many UI states because updates are not asynchronous... removing the UI states would serve to reduce the length of the State drop down menu which in turn may help with my readability hmmm..... :blink:

I'm not a big fan of the queued message handler to begin with. Throwing in nested states and substates gives me a headache just thinking about it.

Thanks Paul,

I thought it would be quite common for developers to use some type of queued messaging for a UI architecture?

If not, what design pattern do you prefer?

Please post (I love discussions on design patterns).

I'm not a fan of substates or nested states. I've gone down that road many years ago and came to the conclusion that it's simply too hard to work with. It makes the code harder to trace and debug. I had a colleague that swore by that technique. I hated working on his code.

If the code on the diagram is so complex that you need to break it down into nested states then I would consider using more subVIs instead. Makes the code easier to work with and debug.

Thanks Michael

I too, have met some people that swear by string based state machines as that can parse *anything* from a string (sub states, arguments, data etc..).

Cheers for the heads up on your experiences.

I have found, as mentioned above, that encapsulation has led to neater state machines.

When you talk about using more subVIs do you mean you would use encapsulated State Machines (in subVIs) over Sub States?

Positives I can think of is that they could be unit tested (so they are easier to debug) and make the main UI more readable.

I do try to use a Integration subVIs so I never use multiple states just because I have exceeded the BD size available within a state.

Or do you mean something else?

I could only think of a couple drawbacks:

  • You can't see all the states in one glance (but, I guess if you have a great many states, you can't effectively do that, either)
  • You can't easily move a substate from one category to another (for example, rename "UI: Open Control Panel" to "Control Panel: Open UI").

Thanks Jim

Your first point is the the first thing that came to mind that I was worried about - readability.

Although the design has parts that are already nested: (I though I few more would be ok ;))

- Idle (event) case is nested, but it does not lend it self to readability issue (at the end of the day it has to be there, but its readable).

- And I usually have to nest my menu handling (from the RTM) in the event structure as well. If it's complex though, that normally goes in a subVI though to help with readability.

And with your second, yes you would have to cut and paste instead of a nice "Rearrange Cases..."

While this may be avoided by good initial design, this would crop up again in maintenance - so you would loose some a lot of flexibility there as well.

You may also pass substates as parameters:

"State Name >> SubState Name"

Thanks Vugie

That is a great idea also.

Do you do this?

I was trying to keep all the original functionality of the JKI State Machine so if need I could still pass arguments as well as Sub States so the syntax is the same.

I was trying cause less confusion by not deviating too much from the original design.

Wouldn't it work to set the main state case to:

'---------------UI------------, UI: .. UI:z' ?

No need for an extra VI.

Thanks Ton

Are you able to elaborate? I do not think I am following (sorry!).

The owner is the "---------- UI ----------" case

Any Group of states registered as a Sub State will get sent here.

---------- Summary ----------

Summary: A poll would be nice to see who likes using Sub States and who doesn't.

Summary: Thanks to everyone who's posted so far for the great feedback!!

Summary: Please continue to post your feedback it has been very, very much appreciated.

Summary: I like to keep trying new things, so I will keep busy experimenting with this.

Cheers

JG

Share this post


Link to post
Share on other sites

post-2399-12592312885_thumb.png

Here you go.

Ton

Ah, a picture speaks a thousand words - I understand now thanks.

Do you do this?

Share this post


Link to post
Share on other sites

post-2399-12592312885_thumb.png

Here you go.

Ton

Great idea, but it's worth noting that one must be extremely careful with string-based Case Structure ranges.

For example:

1) The range of "UI:".."UI:Z" is not inclusive of "UI:Z". To be inclusive you need to explicitly add it like this: "UI:".."UI:Z", "UI:Z" -- see docs for details.

2) If you wanted to include frames like "UI: Zoom Out" (that have more characters than just "UI: Z"), then you'd probably want to set your range to something like "UI:".."UI:zzzzzzzzzzzzz" (Note: I used lowercase "z" on purpose -- see #3, below)

3) String range matches are case sensitive (even if your case structure is configured for Case Insensitive Match, I believe), so you'd want to use a range like "UI:".."UI:zzzzzzzzzzzzzz", since "z" (0x7A) > "Z" (0x5A) -- see docs for details.

Cheers,

-Jim

  • Like 1

Share this post


Link to post
Share on other sites

Ah, a picture speaks a thousand words - I understand now thanks.

Do you do this?

No, for several reasons, I hardly have the need for a large state machine and there are numerous caveats (as pointed out by Jim)

Great idea, but it's worth noting that one must be extremely careful with string-based Case Structure ranges.

I was aware there were some caveats with this technique, thanks for the insight.

I hope you got them all.

Ton

Share this post


Link to post
Share on other sites

No, for several reasons, I hardly have the need for a large state machine and there are numerous caveats (as pointed out by Jim)

Why would you suggest it then? ;)

Share this post


Link to post
Share on other sites

Great idea, but it's worth noting that one must be extremely careful with string-based Case Structure ranges.

2) If you wanted to include frames like "UI: Zoom Out" (that have more characters than just "UI: Z"), then you'd probably want to set your range to something like "UI:".."UI:zzzzzzzzzzzzz" (Note: I used lowercase "z" on purpose -- see #3, below)

Apparently the trick is to use a tilde (~) after the :. (so says the wiki)

Ton

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.