LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Prevent event structure from queueing items?

Solved!
Go to solution

Is there a way to prevent an event structure from recording and queueing events?

 

I have a state machine with an event structure inside one of the states - the state waits for user input before continuing - and I'd like the event structure to only recognize events when the program is in that state. I understand that the current method of catching ALL events is sometimes (normally) the desired behavior... heck, I use it to my advantage most of the time. However, this is not one of those times.

 

Here is a quick example of my setup:

Event catching all events example.png

(See Attachment. I guess it's too big for a VI Snippet, so this is a standard PNG)

 

The issue I'm having is that the Event Structure continues to record events even after moving on to the next state. This means that if "String" is modified at any time, the next time the event queue comes up in the state machine, all the updates to "String" will execute.

 

 

So how can I set up the code in such a way so that events will only be caught and queued when the event structure loop is running?

0 Kudos
Message 1 of 16
(4,010 Views)

In general, you don't want to bury an event structure inside a case structure for the very reason you are seeing.  You are accumulating events in a section of code that may never execute, or may not execute for a long period of time until the conditions are right for that case of the case structure to execute.

 

You'd be better off separating your event structure into a parallel while loop and pass any events as appropriate into the state machine loop using a queue .  Look at File / New / design arcitectures Producer/Consumer (Events) for an example.

 

0 Kudos
Message 2 of 16
(3,990 Views)

@Ravens Fan wrote:

In general, you don't want to bury an event structure inside a case structure for the very reason you are seeing.  You are accumulating events in a section of code that may never execute, or may not execute for a long period of time until the conditions are right for that case of the case structure to execute.

 

You'd be better off separating your event structure into a parallel while loop and pass any events as appropriate into the state machine loop using a queue .  Look at File / New / design arcitectures Producer/Consumer (Events) for an example.

 


I am going to agree and disagree. It really depends what you are doing. Yes burying an event structure can be bad. But if architected correctly, it can be a relatively easy way to process user events such as with a queued state machine (as long as there is no intesive processing). However, even with parallel loops, if processing takes a long time you could have your user click a button and see no results. Yes, the program registered the click and it is queued up, but it wont be dequeued anyways until the parallel thread is done processing the first thing. The expected result from the button click will of course happen eventually if they are queued up to be processed by the parallel loop. But it may not happen as the user expects (i.e. relatively immediate results). It is important in these situations to set a busy cursor, that way you disable the user clicking things until the long processing is done. It is all in how you architect the code, to communicate to the user what is happening. Think about what you would expect to see if you were the user.

 

Next, you have no timeout on your event structure so there is really no need for that inner while loop. That's just extra junk that need not be there. And as was said above, make sure if you have a "buried" event structure you use a queued state machine to make sure you can force a return to the idle (event handling) state after all processing is finished.

0 Kudos
Message 3 of 16
(3,983 Views)

With that structure you can use Dynamic events (search the examples). The mouse drag uses them as follow: Register a null event, when mouse is clicked register a move event, and when released deregister.

 

You can do the same with button events.

 

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 4 of 16
(3,982 Views)

I agree that you need to use Dynamic Events.  Here are some improvements that you can make besides the dynamic events.  Change the mechanical action for the Start and Stop booleans to Latch when Released.  Once you do that, you will notice that the run arrow becomes broken.  That is OK for now.  Go to the initialize state and delete the local variables for Start and Stop.  The run arrow is now OK.  Move the Start boolean to inside the Start Value Change event case.  Move the Stop to its event case.  When you press Start, the event will fire, the boolean will be read at that time, and the latch action will reset it back to false after being read.  Same thing happens for Stop.  Also, move the string control to its event case.  Generally, you should always put a control inside its event case.  The latch actions take care of resetting back to false so you don' t have to.  However, you cannot use a local variable with a latch action boolean.  It causes a conflict.

 

A couple of more things.  Add a Timeout value so that this event fires every so many milliseconds.  I usually use 100.  Don't use "Use Default if Unwired" except for the stop condition since this is the only time you don't want to use the default.  Wire your boolean shift register through in all events to carry the same information and prevent the default from coming back at unexpected times.  Create constants for the state shift register in every event case.  Usually you should set this to the state that contains the event structure itself (Wait for User).  If you don't, the default state is Initialize, and everytime Timeout fires, the next state will be initialize.  Same for other events that don't have the next state wired.  This will cause problems as your code becomes more complex.  Here is a picture of the Timeout event showing the boolean wired through and the next state properly defined.

 

StateMachineandEventsexample_BD.png

- tbob

Inventor of the WORM Global
0 Kudos
Message 5 of 16
(3,957 Views)

Back up a moment... why turn the event architecture into a polling architecture by adding the 100msec timeout? For a user interface, I typically am disappointed when relegated to needing a Timeout case for polling.

0 Kudos
Message 6 of 16
(3,944 Views)

@JackDunaway wrote:

Back up a moment... why turn the event architecture into a polling architecture by adding the 100msec timeout? For a user interface, I typically am disappointed when relegated to needing a Timeout case for polling.


When calling the event structure, some event must fire before the code can continue.  In some cases, an error detected outside the event case can be made to stop the loop.  The loop won't stop until an event has fired.  So the Timeout event is useful here.  It isn't always needed, but I put it in out of habit.  It does not turn the event structure into a polling one.  Polling is when you continuously read controls in a loop.  Timeout does not cause this action at all.  It simply is an event that fires every so often.  You don't have to use it if you don't want to.  But I think it is good practice.  Did you ever try to stop a program before some event fired?  Without the Timeout, you can't.  Look at the attached example where I want to have a timeout condition.  If no event happens within a certain time period, the program stops.  Without the Timeout event, the program does not stop.

 

The first loop has a Timeout case and works.  The second loop has no Timeout event, and is never ending.  The attached VI is in LV2010 (which I finally installed).  I can save it to previous version if anyone wants.

 

 

Timeout.png

 

 

 

 

 

- tbob

Inventor of the WORM Global
0 Kudos
Message 7 of 16
(3,925 Views)

If any parallel process need to stop an event driven process, I would typically do so with a "Shutdown" User Event (or more generically, a "System Command" user event with a value of "Shutdown").

 

Or, as you point out, you can turn the event-driven process into a hybrid polling/interrupt process, but typically this is less elegant and less responsive (up to 100msec latency).

 

The original code does not mention parallel processes commanding the loop, so I'm just pointing out there's not an intrinsic need to turn it into a polling process.

0 Kudos
Message 8 of 16
(3,916 Views)

And Yamaeda hit the bullseye by mentioning Dynamic Events. The lifetime of the Dynamic Event queue can be explicitly controlled, while the queue lifetime of statically registered events lasts the entire time the VI is running.

 

Here's a plug for having more control over event queues - go and vote for these powerful Ideas! (none are mine 😉 )

 

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Expand-Event-structure-functionality-priority-for-even...

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Expand-Event-structure-functionality-Register-new-type...

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Provide-an-event-terminal-for-event-queue-size/idi-p/1...

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Option-to-discard-stale-entries-in-the-event-queue/idi...

0 Kudos
Message 9 of 16
(3,912 Views)

Keep in mind that the code I attached is only a 5-minute example of my actual program. In there, I have probably 15 states in the machine, an external event structure to process always-available events (Stop, enable/disable "admin mode", etc.), and single-frame sequence structures for program start and stop. This program is designed to be continuously running.

 

For the record, everything is working as intended. I'm asking this because I'd like to add stuff that would require this method, and it could also reduce some codesize.

 

Alrighty, lets see if I can get through all these comments...

 

Ravens Fan:

The reason I buried the event structure in the case structure in the first place was to do exactly that: trying to prevent the accumulation of events. Obviously I found out that didn't work. I left the event structure where it was because it made sense, and everything is working as intended. And sometimes my program purposely skips over the event structure because I don't want that code to execute, just another reason why I want it in the case structure.

I thought of the producer/consumer design, but I haven't done much work at trying to impliment it yet. Busy busy, after all.

 

for(imstuck):

"user click a button and see no results"

At times, specifically while a test is running, I want to prevent the processing of certain actions while allowing the processing of others, such as the STOP button.

The busy curser is a good idea, I'll keep that in mind if I notice any intentionally delayed actions.

In my example, I do need the inner while loop, because changing the String value updates a boolean (the string is set to Update While Typing). It's not shown in the PNG, so you might not have noticed that part.

 

Yamaeda:

I'm no stranger to User Events, and from what I can tell Dynamic Events are essentially the same thing. I'd like to aviod using them because of just how many possible events I have, and because adding an additional Dynamic Event can be a hassle. But nonetheless, I'll try it out.

 

tbob:

The start button stays switched because it's also a "program is running" indicator: the "On" text says "Running." Well, maybe not in the example, but in my actual code it does. Opps. The same thing goes for most buttons I use... they will stay "on" until the action is completed, and then return to their default value. It gives the user feedback regarding when an action, such as unloading a wafer, is complete.

In my actual code, I do have state machine constants in every frame, and pass through all shift registers. There are no "Use default if unwired" tunnels in my actual code - not even for the stop condition. But good suggestions nontheless 🙂

I do not understand why the timeout is needed though. From what I can tell, it just returns to the "Wait for User" state, doing nothing. Wouldn't it reduce CPU load to just not have it? (Granted, running every 100ms is eons for a computer...)

 

JackDunaway:

My thoughts exactly.

 

Damnit, more replies...

 

tbob:

Ah, ok, I see what you mean.

 

JackDunaway:

And many Kudos were given this day.

 

 

I hope I've cleared things up a bit. I'll try switching to a producer/consumer architecture, but it may take a while. Lots of code would need changing.

0 Kudos
Message 10 of 16
(3,902 Views)