LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Event structure intermittent/unpredictable

Solved!
Go to solution

Anybody know what might cause an event structure to work fine before dinner, then refuse to handle certain events, then decide to work again depending on what I had for breakfast?  My event structure has only about 15 events, nothing that blocks.  It's the only one in the VI.  I can see the event shown in the Event Inspector Window as "flushed" (never was sure what that means).  In the mood it's in at the moment, I can't get the event handler for the event to run no matter what I do, firing it from a timer VI, just firing from inside the outer while loop, firing it from outside, nothing can make it actually fire.  In fact, I see several other events in the Event Inspector Window as "flushed" that did not get handled.

 

This is such a simple thing that I must be doing something silly, just can't figure out what.  Thanks for any thoughts! paul

0 Kudos
Message 1 of 18
(2,439 Views)

Hard to guess without seeing code.  What is the basic architecture of your VI?  Is it a state machine?

 

My theory based on only what I can read.

1.  Some events are set up for a limited number of instances.  So the flush would be what happens if a 2nd instance comes in before the 1st gets handled.

2.  If it was some variation of a state machine, the event structure isn't getting handled very rapidly.  Other stuff might happen and states occur before it gets back to the event structure to handle what has been queued up.  So if Value Change of Control A gets queued up, other stuff happens and Value Change of Control A gets queued up again, flushing the first instance in the queue, before your code gets back to the Event Strucutre.

Message 2 of 18
(2,433 Views)

Hey thanks for looking.  I wish I could throw the whole app in - lots of configuration files, etc. I'll just post the 'System Manager.vi'.  So it's just a classic user event based VI, no user interface.  A while loop holding an event structure.  I started out using some DVR-based timers that I stole somewhere.  I couldn't see anything wrong with them, but I ( superstitiously) replaced them with simpler looping VI's that run "alongside" my System Manager while loop.  I send timer commands to these guys via Q's.  They're identical, I'll make them into reentrant clones later after I get things working.  I've tried firing events from 'primitive' Generate User Event also, no difference.

 

Interesting, your #1 comment, got to ponder that a bit.  I have only one place I'm registering for the event, and that's in the SysMgr loop itself.  Not really a state machine, more like a switchboard for checking and forwarding messages.  Now, there are a few little FGV-based state machines in there, but they're not part of this initialization activity.  Basically, I do this:

 

1) Attempt to open TCP connections to some controllers, some of which might be there, powered up and responding, some not.

2) Send off a few TCP initialization commands to the ones I can connect to.

3) Send TCP commands that tell the controllers to start spewing UDP data packets back, parse the data, yada, yada.

 

So my initial timer function is this:  Controllers that have opened TCP connections and responded to initialization commands properly do so with 5-10 msec.  So I start a timer for, say, 250msec, when the timer expires, controllers that haven't responded by then, I do no further business with.

 

I've really got to parse your comment "Other stuff might happen and states occur before it gets back to the event structure to handle what has been queued up.  So if Value Change of Control A gets queued up, other stuff happens and Value Change of Control A gets queued up again, flushing the first instance in the queue, before your code gets back to the Event Structure."  I guess my crude understanding was that the event code 'under the hood' had a queue so that events couldn't get lost.  Must think about this.

 

Whoa dude!  I just now threw a Hail Mary pass that seemed to work.  This may be related to your comment... I vaguely remembered a problem I had that got fixed when I added a delay between registering events, and actually entering the loop and starting to fire them (back into the event structure that 'holds' the Generate Event calls in a handler).  So I stuck a 100msec delay right after Register Events, with its error cluster feeding the while loop register, so that the the loop can't start until 100msec after the Register Event *thinks* it's finished - now it works!  Of course I'll have to bang on it for a while to convince myself that it's fixed...

 

Maybe this is a downside of implementations using event structures for this sort of thing rather than queues - I've never run into this with queues.  I could throw lots of elements into a queue before there was anything running to catch them, but events seem more temperamental.  In this app I wanted to use events because some events I am handling in the both my SysMgr and my UI loop - a la "one-to-many"

 

My (even cruder) assumption was that events of any size or complexity of their data might need "a little time" to get things in order before handling events.  My events' data isn't big or anything, in fact some are just variants.

 

What are your thoughts on this? Again, thanks for looking - paul

0 Kudos
Message 3 of 18
(2,407 Views)

Well, now it's not working again (not handling the event). BUT I have what seems to be an important variable - if I plug in my ethernet hub and let my app talk to the controllers, it fails, even with the (hokey) delay after registering the events.  Unplugging the copper ethernet, which then lets the laptop connect to WiFi, makes the event handler work as designed. But oh, uh, the app then doesn't do anything.

 

So - I have 4 controllers now, will have a couple more later.  After setting things up via TCP commands, the controllers spew UDP data packets (small) back to me, which I listen to, parse, display data, make decisions, etc.  I have them set up now to send a data packet every 50msec.  Not much.

 

But - I haven't tested or debugged my UDP Listeners.  I'm beginning to suspect that I clumsily broke things, maybe by blocking and hanging something up.  Once in a while I have a hallucination where I try to "depend on" an output from a loop that then blocks everything, because the loop is doing what I told it to do - keep looping.  Silly stuff.

 

Will keep you posted, again thanks, RavensFan! paul

0 Kudos
Message 4 of 18
(2,393 Views)

Sheepishly admitting to the world my brain fart, sure enough, wiring the output of a running loop & expecting it to give me immediate results leads to frustration.  This time was more interesting, tho, I'm learning the "create reentrant clones using Call By Reference" technique.  See the snippet.

 

What I might actually want to do is use Asynchronous call - start and forget.  But I had some sort trouble getting that set up when I was writing this stuff - can't remember exactly, maybe the Asych call didn't like the reentrant flag 0x8 or something.  Oh well, more fiddling to do - paul

Message 5 of 18
(2,388 Views)
Solution
Accepted by PaulOfElora

@PaulOfElora wrote:

Sheepishly admitting to the world my brain fart, sure enough, wiring the output of a running loop & expecting it to give me immediate results leads to frustration.  This time was more interesting, tho, I'm learning the "create reentrant clones using Call By Reference" technique.  See the snippet.

 

What I might actually want to do is use Asynchronous call - start and forget.  But I had some sort trouble getting that set up when I was writing this stuff - can't remember exactly, maybe the Asych call didn't like the reentrant flag 0x8 or something.  Oh well, more fiddling to do - paul


Ah, classic. Yes it can always be a bit fiddly to get it running. Typically I use a strict static VI ref to the Open type and use a property node to get the name or path as name-parameter. You'll need it to be strict to get the connector pane. If you want to side step that you can have a connector pane ref and drop your VI into it to set the pane, with the issue that any change to the VI will not be transferred.

If you do your current Call by ref it's exactly the same as simply dropping the sub vi's in there.

Start Asynch.png

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

Qestit Systems
Certified-LabVIEW-Developer
Message 6 of 18
(2,357 Views)

Good to hear from you, Yamaeda, thanks as always for your help. I will resume this fiddling right now! Happy new year! Paul

Message 7 of 18
(2,339 Views)

Well, more trouble with this same event structure.  It completely ignores an event.  The Event Inspector Window tells me that it is flushed - my tiny understanding of which is that the event handler isn't running at the time the event if fired.  But my VI with the handler has been just sitting, idle, for seconds before the event is fired, so I know that it isn't thrashing about with previous tasks.

 

The event is fired from my UI loop, it's the "Quit" command.  So I have a plain ole event structure in the UI, which fires a "Quit" message (enum + variant) to my System Manager.vi, which shuts everything down.

 

So just for laughs, I placed the same Generate User Event outside the UI event structure that also fires the same "Quit" message to SysMgr (just copied & pasted the same call).  And Lo! My SysMgr successfully receives & handles the Quit message that got fired from outside the UI event structure!

 

I tried the DETT to trace things out.  The "Quit" button happens, then the Generate User Event gets called to send a Quit message to the SysMgr, but then... The System Manager is heard from no more, lost radio contact.  But I know it's still running, because a) I turn on Highlight Execution on the Main.vi BD, and SysMgr shows as running, and b) I see no prior "VI Return" in the DETT.

 

So it seems like a clear correlation - when I fire the event from inside the UI's event structure, the receiving event in SysMgr fails to receive it properly, and the Event Inspector Window marks it as "Flushed".  When I fire the same exact event/message from outside, it succeeds as expected.

 

I probed the event refnum and the error result from the Generate User Event call, refnum is valid, error is false in both scenarios.

 

So I've read what people say about refnums becoming invalid under certain conditions, but I can't see where I'm violating any of these rules.  Also, my SysMgr event structure responds just fine to other events from other sources. It just seems to be the event structure in my UI VI that has this weirdness.

 

Any darkness to dispell for me?  thanks, paul

0 Kudos
Message 8 of 18
(2,289 Views)

So I'm getting closer to my solution, but so far I could only come up with something pretty smelly.  In order to do TWO things:

 

1) Create some number of reentrant clones, and

2) Run them asynchronously

 

I had to create TWO references, one for each of the objectives.  Because verily, the VI Reference Help sayeth unto you "

Do not use this option flag with 0x08 or 0x100"
 

Here's a snippet of this smelly thing.  This seems crazy to me - is there a better way to accomplish both objectives? thanks all, paul

0 Kudos
Message 9 of 18
(2,261 Views)

If I understand correctly, you have code known as a UDP Listener which you want to use as both an Action Engine (with the 'Initialize' action) and seemingly also as an asynchronous parallel process (with the 'Start Listening' action).

 

In one case, you want to call it and have it return data to you right away.  In the other, you want to launch it and let it do its thing in the background for an indefinite time.  And I think that's where the code "smelliness" comes from -- lack of a clear, consistent purpose for your "UDP Listener" vi.  Is it a subvi that you call and it returns quickly?  Or is it a process you launch and forget about?   Or is it a process you expect to interact with on a regular basis?

 

If you don't need to interact with it much, you might be able to just launch the sucker once at startup, and let it do its own sequencing from "Initialize" to "Start Listening" behavior.

 

But if you need to send or receive info back and forth from it repeatedly, I'd be inclined to structure that UDP code as a Queued Msg Handler (QMH).  You could use the 0x08 flag and "Call By Reference" to launch multiple reentrant instances of your whole QMH-based UDP Listener.  Each would just sit there idly waiting at their Dequeue function for messages.  The first one you'd send is "Initialize".   Later you'd send the message to "Start Listening".

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy coming to an end (finally!). Permanent license pricing remains WIP. Tread carefully.
0 Kudos
Message 10 of 18
(2,218 Views)