Jordan Kuehn Posted January 23, 2011 Report Share Posted January 23, 2011 I've recently picked up the JKI state machine and am really enjoying it. However, I have a (hopefully not stupid) question regarding the UI aspect of it. From what I see, the event structure only ever executes while the state queue is empty. In this event structure you put controls that you want to use to trigger new actions and other controls you put in a case to read as necessary? How then do you ensure responsiveness from one of the event controls if the state machine is off running for awhile through the queue? For example to have the program respond to a click of the built in 'OK' button and stop execution immediately rather than waiting an indeterminate amount of time while emptying the queue? Perhaps my thoughts aren't too well organized, but any pointers to discussions or just some advice would be great. I think what I'm after may be an asynchronous design and to move the event structure to a parallel loop? A simple example would probably speak a 1000 words here. Quote Link to comment
SuperS_5 Posted January 23, 2011 Report Share Posted January 23, 2011 Hi, I use a variant to the JKI state-machine for almost all of my work. It is a strategy that has it's purposes. Generally it is used for UI loops, where states are only executing after some user interaction. It can be used in other situations too, but this I prefer this type of state-machine for UI loops. (Semi-)deterministic architectures will differ for their specific needs. States generally execute quickly, unless the user is required wait for something. (I used a busy cursor when it is desired for the user to wait.) If the states do not execute quickly, (such as timeout case - screen updates) I would optimize/strip the code until it is within the responsiveness requested. Anything that is required to always run, but, does not execute quickly enough, another loop will be used. Quote Link to comment
Popular Post Justin Goeres Posted January 24, 2011 Popular Post Report Share Posted January 24, 2011 From what I see, the event structure only ever executes while the state queue is empty. In this event structure you put controls that you want to use to trigger new actions and other controls you put in a case to read as necessary? How then do you ensure responsiveness from one of the event controls if the state machine is off running for awhile through the queue? For example to have the program respond to a click of the built in 'OK' button and stop execution immediately rather than waiting an indeterminate amount of time while emptying the queue? That's a great question, and one that comes up frequently. You're absolutely correct -- if the state machine is off processing a long list of queued states that take a long time to execute, it won't poll the Event Structure until those states finish executing. The implication, then, is that if you want your JKISM to stay responsive, the states in your state queue need to always execute quickly. So your observations are dead on . Sometimes, though, you've got operations that just take a long time, right? The way to handle this with the JKISM is to move long operations to a separate loop or refactor them so you can poll the Event Structure frequently. Two examples of how to do this: Data Collection That Takes a While Say you've got a data acquisition operation that takes a few seconds or more. In this case, I'd put the acquisition in a separate loop (it could be another JKISM, or simple asynchronous loop driven by a notifer or something). Then your JKISM's state flow could look like this: DAQ: Start << sends notifier to start acquisition DAQ: Check for Data Ready << checks a return notifier from the asynchronous DAQ loop to see if the acquired data is ready yet. If not, it executes:Idle << go back and poll the Event Structure DAQ: Check for Data Ready << then come back to the same state to check the notifier again This way you're passing the slow work of data acquisition off to an asynchronous loop, while your UI/main logic loop remains responsive. Waiting for a Motor to Move Another common use case is sending a motor on a long move. In this case, we don't need the extra asynchronous loop because the motor itself is probably asynchronous (unless you're unlucky and your motor library is crap ). The state queue in this case still looks similar to the first one: Motor: Start Move << start an asynchronous motor move (assuming your motor supports it) Motor: Check Move Done << read the motor's "In Motion" or "Move Complete" flag (again, assuming it has one) to see if the move is complete. If not, execute:Idle << go back and poll the Event Structure Motor: Check Move Done << then come back to the same state to check the motor again Note that in either of these cases you can also add extra logic so that waiting for the DAQ or the Motor can time out with an error if the operation takes too long, etc. You can even use the Event Structure itself to communicate between the loops -- for instance, in the first example instead of sending data back in a notifier, you could send it back in a User Event. There's a lot of flexibility depending on what the specific application requires. So to get back to your original point -- yes, the JKISM is built with the assumption that states generally execute very quickly. That imposes some requirements on what the states themselves do, and biases your application in general to be very parallel, asynchronous, and event-driven. Hope that helps! 4 Quote Link to comment
Jordan Kuehn Posted January 24, 2011 Author Report Share Posted January 24, 2011 Thanks for your quick replies! Justin, that hit the nail on the head and did a great job of getting rid of my confusion. I think right now I can get away with refactoring to poll the event structure occasionally, but will keep everything you said in mind as I move on to other projects. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.