LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

State Machine within a Queued Message Handler

Hi guys,

 

So I am thinking about a software architecture of a short project that I have. (actually thinking about converting a recently started code Smiley Wink)

I had some thoughts about creating a Message Handler Loop with a statemachine inside.

 

Instead of creating different states as strings, I created two different sequences as messages called "sequence1" and "sequence2" (attached screenshots)

 

Any ideas on how this could be bad or good?

 

 

 

 

 

 

Download All
0 Kudos
Message 1 of 11
(5,231 Views)

This sounds more like a Queued State Machine to me (a state machine that uses a queue to maintain what states to run).  I use QSMs all the time and they work very well, as long as you are careful about what states you call.



There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 2 of 11
(5,188 Views)

Right, the idea is pretty much queued state machine. The implementation is different.

 

Well, atleast the queued state machine I know would queue up different messages as states

and would execute them in the order that is queued. 

 

The implementation I suggested would stay in that case(or just queue up same message over and over)

until that specific sequence is finished or some other message has been called to execute.

I was just wondering if the implementation would be beneficial at all to convert some parts of it to a single case and stay in that case.

0 Kudos
Message 3 of 11
(5,147 Views)

@doradorachan wrote:

I was just wondering if the implementation would be beneficial at all to convert some parts of it to a single case and stay in that case.


In general, it is a bad idea for a state machine to stay in a single state for any length of time.  At the very least, you should be checking for UI or other types of messages.  But having a state enqueue itself so that it is ran again is something I do all the time.  I normally enque a check for UI events and then itself again if that is what is happening.



There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 4 of 11
(5,143 Views)

Right. That is what I am also trying to do when i "stay" in that single case.

 

If you look at "screenshot.png", you can see that I am putting the same message "sequence 1" into queue

until that sequence is finished. This gives a chance for UI and other messages to executed while that sequence 1 is executing

0 Kudos
Message 5 of 11
(5,131 Views)

The only time I have ran into an issue with that setup is if you receive an Abort command.  You have to make sure you clear out your state queue and then return to the Idle state.  But that could potentially clear out important commands (like stop the program) if you just letting any loop enqueue states on you.  That is why I prefer to have the state machine itself handle the queue.



There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 6 of 11
(5,125 Views)

Dear Dora,

 

     In some ways, a Queued Message Handler is a State Machine, with the "states" being the Messages.  It's not clear to me why you have Sequence 1 and Sequence 2 as "Messages", rather than Action 1, Action 2, etc.  When you encounter Action 1, you "do the Action", and then decide what to do next.  If it is always the same thing, simply call "Action 2" (or whatever), otherwise have a Case statement that decides the next Action.  You might well be able to simplify the data passed on the Shift Register, as Action 1 and Action 3 (I presume these correspond to Sequence 1 and Sequence 2) would not be needed.

 

Bob Schor

0 Kudos
Message 7 of 11
(5,055 Views)

Hi Bob_Schor,

 

The reason I put Sequence 1 and Sequence 2 as messages is because I thought

then I could create typedef data cluster that will hold information for each sequence independently.

 

For example, lets say I had sequences called, "Measure New Stuff" and "Measure Returned Stuff" and actions called "Measure" and "Log".

Both sequences will call "Measure" and "Log" eventually, but there will also be some other process involved that are different for each sequence.

So I thought if I created Sequence 1 and Sequence 2 as messages, then I could handle the results of "Measure" and "Log" in a similar fashion for both sequences, but still differently.

 

Currently I just put "Measure" and "Log" into a subVI so the reuseable portions will be the same for both sequences. (attached screenshots)

 

I used to just lay out actions as messages and call them in the required order just like you are suggesting.

But then I noticed the state information was harder to keep track of due to the reason I just mentioned previously.

Download All
0 Kudos
Message 8 of 11
(5,004 Views)

I don't know how you are creating your screen shots, but they are not helpful -- they are larger than my monitor, and also do not show the entire block diagram (they are cut off on the left and on the bottom).  Do you know how to make Snippets?  If you have a Snippet, you can Insert Image (the tenth button on the Forum's Toolbar), it will put your code (yes, the Snippet can be opened as code) right in the message, and we can see what's going on.

 

Here's an idea.  As I understand it, Sequence 1 and Sequence 2 both do more-or-less the same thing, but with (perhaps) some slight differences.  Use a Boolean or an Enum to register whether you're doing Sequence 1 or Sequence 2, but don't make them separate Messages, just keep them on a Shift register in your Message Handler.  Suppose Sequence 1 was "Action A, Action B, Action C", while Sequence 2 was "Action A, Action D, Action C".  Furthermore, suppose you want to do "Sequence 1, Sequence 2".  Proceed as follows:

  • Create Messages for Action A, Action B, Action C, and Action D.
  • Remove Messages for Sequence 1 and Sequence 2.
  • Where you previously called Sequence 1, first set the "Which Sequence" value in the Shift Register to Sequence 1 (if you use a Boolean called "Do Sequence 1", make it True).  Now issue the Action A Message.  This will start Sequence 1.
  • At the end of A, test the Which Sequence switch, and either call Action B (if Sequence 1) or Action D (if Sequence 2).
  • At the end of Action B, call Action C.  At the end of Action D, also call Action C.
  • At the end of Action C, if Which Sequence is Sequence 1, change it to Sequence 2 and call Action A.  This will cause Actions A, D, and C to run.  If Which Sequence is already Sequence 2, then do whatever you need to do after Sequence 2 ends (like send an "All Done" message).

Yes, the logic is a little more complex, but not that bad, and you only have a single State Machine/Message Handler to worry about.  See if this works for you.

 

Bob Schor

0 Kudos
Message 9 of 11
(4,932 Views)

Sorry, not sure why I didn't think of the snippet. But you totally got the idea.

I guess I thought just showing the case structure of the message handler would save space and would be easier to look.

 

I used to use the method you described.

But the more sequence I implemented, I noticed that organization was becoming a problem.(managing sequence specific data and such)

That's why I thought about creating different sequence as a message so that it would be more manageable.

0 Kudos
Message 10 of 11
(4,855 Views)