I am trying to make a rather simple vi (Test VI.vi is attached) where i press a button to make an LED blink and then to stop it. I have an event structure in each of the three different states Init -> ON -> OFF. Init waits for either the Play button or the Exit button to be pressed. If the Play button is pressed it will go to the ON state and after a timeout (as decided by time On) it will go to the OFF state (and then back to the ON state after time OFF). If the Stop button is pressed in either of these states, the program goes to the init state and waits for further commands. While this works for the first run, it becomes erratic from the second run.
I figured the issue was that when I call the Stop button, the event structures in both ON and OFF states irrespective of which state the program was in was called. I assume the structure in the called state was processed and the other call went into the queue. I tried to find a way to forcefully flush the queue, but I couldn't find a proper way to do that. Can someone help me with this problem? I am rather new to the labVIEW programming environment. I would be happy to read up on the architectures if you could point me to one.
Solved! Go to Solution.
You are doing bad things by having multiple event structures.
When you trigger an event such as Stop button value change, all event structures that are registered for that event will get that event queued up, whether the VI is in that current path of execution or not. So when it finally gets that event structure in the path of execution, it will run the event case that was queued up, even though you triggered that event a long time ago, and think you've already handled it (you did, but in a completely different event structure.)
What is worse and is a common rookie mistake with event structures, is to have the Front Panel locked until event case completes, but the event structure is not in the path of execution, and to get it in the path of execution, you need to click some other button to change the case structure. But you can't because the front panel is locked. A Catch-22.
Only have one event structure in your VI, because I guarantee that unless you completely understand event structures, you'll screw up your code execution.
Your VI is inside out. You should have one event structure just inside your while loop. Inside the event cases, should be case structures that determine what the next step of the state machine should be.
You could also look at the example for Producer/Consumer that is event based, as opposed to the typical "data-based" P/C architecture.
I've attached a pair of examples using an approximation to the Queue-Driven State Machine. See State Machine for the basic idea, and as RavensFan suggested, the Producer/Consumer can be useful in a large number of situations.
In the attached files, I didn't use a typedef for my enum, a typedef for my queue, or a project file. These are all mistakes that I regretted before I finished - you should definitely use them, even for throwaway example VIs, it turns out!
In the first example, I used two states to control the state of the boolean LED, "On" and "Off". In the second example I scrapped these states and chose instead "Active", using a separate boolean shift register to carry information about the state of the LED. This made it much easier to control the behaviour for first/last state, and cleared up the Active state in the State Machine. I suppose what I'm trying to say here is that you should try to choose a "natural" representation for your program's data, and don't be afraid to change your mind if you find you didn't make the best choice the first time.
Hopefully the example shows a possible solution to your question. I chose not to use the queue's data as the state of the state machine directly, since that would probably have required allowing the State Machine to also enqueue items, a process that I have avoided. There are several posts on this forum and elsewhere discussing problems with allowing both your "UI" type event-handler and the "consumer" to enqueue actions or instructions, typically involving a lack of knowledge as to whether you might be reordering items, and so on.
As I finish typing, I remember that I forgot to destroy the queue reference. You should take care to do this after both loops have finished - in all cases with this example the consumer/SM will finish after the producer/UI loop, so you can wire the queue out of that loop if you wanted.
Thank you so much for the example files. The VIs make pretty good sense to me. I will still read up and practice a bit with Producer/Consumer queues before dabbling with a larger project. I noticed that you had a wait 10ms on the loop with the state machine.
When I remove the wait the VI sometimes works and sometimes it does not.
Is this to ensure that there are no race conditions?
The wait is there to prevent my loop from maxing out my CPU. I don't think there should be a race condition, but you might have strange timing issues with the LED if you don't define a loop rate (note the divisions to get from ms to iterations).
With no wait (and no divisions), you won't have a defined speed in this example, which might make it look broken.
A real example might have something taking a defined time (maybe DAQmx, or similar) and so it could be less necessary. In general, you should always take care to avoid unnecessarily greedy loops (maxing the cpu).
Create a simple VI with just a while loop and the i wired to an indicator. Check the cpu usage as it runs, then repeat with a wait. You'll go from 100% on a single core to something like 2% probably.