LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Event conflicts & registering dynamic events. Also, convoluted and text-like code?

This posting is evolved from an earlier one, mostly because of altenbach's comments. I decided the VI should have been a state machine all along, and using this strategy more explicitly makes it much cleaner and uses dataflow better. I can't post my real problem because it's proprietary but the attached examples demo some of its required behavior. They still need a few local variables to get things out from inside several loops, but it's much less like a text-based programming approach. The end eventually got cute. I am sorry about that.

MultipleMethodsWithEditHang.vi shows the original approach, and it malfunctions because event handlers intended to work in different machine states step on each other. As Dennis Knutson and TonP point out, event structures are enabled whether the other structures surrounding them are or not.

MultipleMethodsWithRegisteredEvents.vi tries to fix this by using "Dynamic Event Registration", but still doesn't work. I think I'm doing something wrong, and after reading TonP's link, the "caveats and recommendations...", Help, and some of Travis & Kring, still don't see the light. Maybe there's some minor error or maybe the whole approach is completely wrong.

Questions:

1) Is this code still convoluted and stuck in text-based thinking?

2) The only reason MultipleMethodsWithEditHang.vi fails is because the event handlers are fighting each other, right?

3) How could "Dynamic Event Registration" fix this? Or, what did I do wrong in MultipleMethodsWithRegisteredEvents.vi?

Thanks!

0 Kudos
Message 1 of 19
(5,246 Views)
Answers:

1. Yes
2. No
3. See below...

It looks like you need code that when it starts allows you to change one value until such time as it it has decreased in value 5 times in a row. You then want to stop monitoring that input and start monitoring arrow key presses until a right arrow is detected. At that point, the "result" value is incremented 10 times and the code shuts down.

I guess I don't understand why you are using all the dynamic registation stuff or why you have multiple event structures.  Why not just use static events. To "turn off" inappropriate events, you can either disable the controls you don't want generating events, or modify what happens when the event fires based on the state the program is in (all in one event structure).

Why do you have a timeout event with nothing in it?

What is you program really trying to do?

Mike...

Certified Professional Instructor
Certified LabVIEW Architect
LabVIEW Champion

"... after all, He's not a tame lion..."

For help with grief and grieving.
Message 2 of 19
(5,223 Views)


mikeporter wrote:
1. Yes
2. No
3. See below...

I fully agree with Mike! All you need is a single event structure. The biggest NoNo(!) is placing event structures inside case structures. An event structure needs to be able to handle events, and thus should never be bypassed by the dataflow.
 
All you need is a single loop containing a single event structure with several static events. You have about 80% too much code. 🙂
 
Please explain what the code should do and we can maybe make a quick draft on how to do things better and simpler.
0 Kudos
Message 3 of 19
(5,215 Views)
Thanks. More specifically, is my code 1A) Convoluted and stuck in text programming? or just 1B) Convoluted?
 
OK, I hope you will bear with me a bit further. I am really scratching my head and trying to understand this. Could you look at the stuff below? I'm really not trying to argue, I'm just trying to make sense of things that at the moment still seem wrong. I think I have to explain what seems wrong in order to understand how to choose the alternatives. Please help me see the light.
 
> Please explain what the code should do and we can maybe make a quick draft on how to do things better and simpler.
For an example, "MultipleMethodsWithEditHang" is very simple and already provides an example of what the code should do, except that the "How Many?" control hangs everything if you edit the text of the number in it. I wish editing the text of the number changed the value of "How Many" and didn't hang everything. All else should work as it does now. I don't know if replacing my block diagram is easy enough to qualify as a quick draft you wouldn't mind doing, but logically posting it was equivalent to explaining what the code should do. If I were to write out what the code should do, I would write out what MultipleMethodsWithEditHang was meant to do. Shall I? Alternatively, should I post a working version of this whole thing which DOES have an event structure at the top of its heirarchy and explain what I wish was different about that? Based on the previous thread I created one such sample that works correctly, but the way it is organized seems wrong to me and very hard to extend.
 
Sorry I'm being evasive about what my real overall project is supposed to do. It's confidential and they aren't my secrets to give away. I wrote the system 8 years ago in Forth and Assembly under DOS, and it has worked well all these years for about 50 different users, except that the motion controllers for some reason need power resets when they hang every few months. We are replacing the software because, at least in our organization, it's becoming burdensome to train new grads how to use DOS, and nobody else knows Forth or Assembly while several people know LabVIEW, and replacement DAQ components are becoming impossible to find (it's all based on chip-level register reads and writes, and doesn't use any of the manufacturer's device drivers, but new DAQ hardware typically doesn't document that approach anymore). By the way, I must admit I still prefer text programming, but am trying to use LabVIEW the way it's meant to be used. Whether or not I keep using LabVIEW for later projects, I should certainly be using it *correctly* for this one. I want to understand.
 
The Forth and Assembly code is about 100 K of text. The LabVIEW setup that I have now, the "workaround" discussed below, is one main VI with 49 subvis and strict typedef controls at various levels below it in the heirarchy. It works, but like the little sample I could post, its organization seems wrong and hard to extend. Frighteningly so. This could be hard to post and discuss even if I was allowed to.
 
About having a single event structure: I am actually doing that right now for all the event handlers, in my real project, but I think - or thought - this is only a workaround until I can manage events properly.
 
The "workaround" looks like this:
 
I have (1) a single event structure inside a loop in the main VI, for various Mouse Down and Key Down and Value Change events, and it handles the things that happen on my machine that are "events" in the Windows sense.
 
I also have (2) a separate loop also running in the main VI, which contains a case structure that is switched by an enum, and the cases are things like "Startup", "Adjust Sample", "Configure Absorbance Test", "Run Absorbance Test", "Configure Heating Test", "Run Heating Test", "Run Quick Verification", "Calibrate", "Open Data File", and "Shutdown" (still can't use the real names but they might as well be these names). I think it makes sense to organize the program this way, running the equipment in several different modes like this, because in each of these modes so many things are different, including what controls are available to the user, how the system should respond to different signals, what an urgent shutdown should do, what disk files have been created and are being added to, and so forth. Especially, the conditions to be met to move into a different mode, and the tasks needed to enter a different mode, and some of the data to be handed to the next mode, are all unique to the present mode. I think I am describing that my system should function like a state machine functions. So wouldn't it be reasonable to write the software as a state machine?
 
??? A state machine has the system state or mode as its most basic level of organization. An event handler has the event as its most basic level of organization. How do you use events when programming a state machine? Maybe this is my main question, and if I understood this, everything else would fall into place. ???
 
I still have more questions but have exceeded a character count limit - I hope to post the rest in the next posting. Hope no moderators throw me out - it's not like this is spam, it's just an involved question, I think!...
0 Kudos
Message 4 of 19
(5,188 Views)

Here's the rest of what I wanted to post:

I started to create a posting example for my "workaround" approach and was pouring so much time into it I stopped. Since the only event handler is in one loop, and as much as possible is within the "state machine cases" inside the other loop, it has functionality scattered between the event loop and the state machine loop, an absolute mess. So far it still works, but it certainly seems like the wrong structure, a nightmare of confusion that gets 30% worse with every 10% increase in functionality. For example, I have a motor that moves a sample, and there are 3 choices for speed, and the user clicks one of three buttons to select one of the speeds. So, these are three separate event handlers, at the very top tier of the organization. If I had opted to have the user enter the speed into a numerical control instead, it would be one control with one little wire, all buried pretty deep down inside one of the chunks of code in the "Adjust Sample" state's case. Doesn't this mean an otherwise minor choice about the user's options for setting motor speed would have to drive a major rewrite of the overall structure of the main program?

I could create the entire system with an event handler as its basic level of organization, perhaps. This would mean the machine mode (a very fundamental thing) appears nested at multiple levels inside events (a very local and even arbitrary thing). I'm not sure what I would do when programming parts that respond to two different kinds of events, except perhaps just start taking some of the controls away to avoid the situation.

In a state machine, the most basic level of organization is thinking in terms of the machine states, which looks useful. In the event handler loop, the highest level of organization is what event you're responding to. This just doesn't seem smart for the most basic level of organization. From the point of view of the user, in one mode, a mouse click on the "Up" button and a press of the up arrow key are equivalent, and should move the sample holder upward a millimeter, but in the event structure they don't even appear at the same level of the heirarchy because controls generate separate events for each control, while the keyboard generates the same single event for all keystrokes. And in another mode when the user wants to open a data file and add comments to the header, at first the up arrow key is going to change the selection to the file that appears above the currently selected file, but seconds later it's going to let the user move the cursor up one line of text in that file. Users switch their working definitions of controls like this all the time, just by using Windows. The program's response to an event is very different in different modes, in ways the user wouldn't find surprising. So, why should the identity of the event be the most basic level of program organization? Right now, that looks as odd as, say, having the most basic level of organization be whether integer or floating point arguments are used.

Or, maybe having an event structure loop and a state machine loop both running in parallel in the main VI is the right thing to do? It sure seems like quicksand so far.

Why should an event structure never be bypassed by the dataflow? The "move sample up" code never needs to execute if the system's in "Open Data File" mode. In fact, there are a zillion events that are not handled by any event structure, so why not have Key Down sometimes get handled and sometimes be one of the many events without handlers, depending on what the program is trying to accomplish right now? Even the way the LabVIEW IDE works reflects this. If you're editing text and hold the Shift key down, it has the effect of changing the character added, but if you're dragging a front panel control it has the effect of making it move exclusively in horizontal or vertical directions. If you're reading the Help system, the Shift key doesn't make anything happen. Surely the basic level of organization of the source code for LabVIEW's IDE itself isn't organized around having an event handler for keystrokes, with scan codes driving a case statement, and the code for inserting characters versus moving a control bitmap versus doing nothing, written into the different cases of that case statement.

Why is placing event structures inside case structures a NoNo? Apparently you have to do something special to "turn them off", but why isn't that enough?

About disabling controls if I don't want their events to occur - how do I disable the entire keyboard? I think the hang I started this thread with is because I have a Key Down event handler that I wished wasn't running in one of my states.

About static events versus dynamic events - sorry, I don't have LabVIEW with me, and I don't think I understand this, but will look it up tomorrow. I don't know that I do want dynamic events in particular. I thought I wanted to handle events in some situations and not handle them in others, and something somewhere lead me to Dynamic Events.

One last thing - I guess it's pretty unlikely anybody's going to go for this - but, suppose for the sake of discussion, we really did want to have event handlers inside case structures. What'd I do wrong in MultipleMethodsWithRegisteredEvents? How could I change it so that it would do what I wanted? How do you make an event handler stop trying?

0 Kudos
Message 5 of 19
(5,187 Views)
At the risk of getting banned for life, maybe I should add a bit about the hardware system, which I realize could be shared.
 
This system includes multiple axes of motion control. The motion controllers have their own ASCII text language and are accessed over an RS232 line. On the target system there are multiple COM ports for this but on the development system there is only one COM port so they're daisy chained. LabVIEW has to compose programs in their native language and send them out, or compose instructions line by line for immediate execution, and also interpret their replies to get motor positions. The controllers downchain of a replying motor controller can chop up its reply string, which LabVIEW must untangle. There are also IO lines keeping separate track of when the controllers have finished executing programs.Every motion can complete because the motion program expects it to, or because the user stops it, or because a limit switch actuates, and LabVIEW has to manage all these with the IO lines and interpreting the reply strings. The subsystems for all this are running and seem to work.
 
The system also includes numerous instruments. Some have analog outputs. Some generate asynchronous TTL pulses to be counted in known time periods. One instrument transmits ASCII strings over RS232, and LabVIEW must interpret these and sort out error messages that break the pattern. There's an absolute encoder with graycode on 24 parallel TTL lines. There are incremental quadrature encoders. There are a dozen or so stray single IO lines, some of which need polling at different rates in different parts of the program. Almost all of this is running and seems to work.
 
There are a few dozen user inputs to configure tests, some used more often than others. Some user choices could damage the machinery, and some are logically contradictory, so LabVIEW must interpret these to generate a safe and consistent set of choices, and tell the user about any interpretation and let them adjust their inputs if they don't like the way it went. The user interface lets users pick different strategies for making their choices. For example, they can choose to describe some of their requirements in the Fourier domain, and have these interpreted in the literal machine domain and integrated with all the other choices. The controls for configuring a test are disabled and grayed out while the test itself is running, and the controls for the operation of a test are all disabled and grayed out when the test is not running. During startup and shutdown, the main components of the program, the separate polling loop for the queue I put error messages into, and other things are brought up and down in a certain order, controls are always grayed out when they are unuseable, and a "Status" box displays a line of explanatory text. All of these things are running and seem to work.
 
During the busiest parts of a test, the motors are moving, their positions are measured, all the instruments are being read into synchronous arrays, various diagnostic signals and error sorces are being polled, and the machine is constantly evaluating whether to abort the test, or whether a dangerous emergency has occurred, forcing the system to salvage test data and the history of how the emergency came about (the truly dangerous motions are stopped by switches and sensors hardwired to dedicated inputs on the motor controllers for safety). Meanwhile, as the test runs, users can type notes about what they see happening. The keystrokes for these notes and their arrival times are recorded in asynchronous arrays. During less busy parts of a test, all the synchronous and asynchronous arrays are reconciled with each other and ASCII text formatted and appended to the data file being built, so a hardware failure only takes the most recent data with it. Most of these components are running and tested, and seem to work, at least as separate components. With simplified conditions and without the notes-taking feature, the most important kind of test has worked. I'm working out getting everyone to play together nicely now. I'm doing it in the version that has event handling and state machine loops both at the most basic organizational level with functionality split between them, and crossing my fingers that this messy approach will work if basic organizing just by state machine state isn't possible.
 
The system occupies its own room. The moving mass is up to about a ton. The data files are up to several hundred megabytes in size. Tests take up to a week to run.
 
 
SPECIAL NOTE COMPARING THE MOTOR CONTROLLERS TO EVENT STRUCTURES:
 
The ongoing text conversation with a motor controller can require a lot of program logic to manage, and polling the reply stream adds overhead. But, if necessary, when both the motors have finished any old moves and the program is not sending any new instructions, this can be turned off. Wouldn't it be nice if event handlers that involve a lot of program logic could be treated the same way, just be turned off when the functionality they provide isn't wanted? Yes, we can test inside the event handler to see if we want to act on the event, but wouldn't it be better to make it act as if it had never been created? In fact, isn't it cleaner if different parts of the program can take advantage of events the same way they would use a shared resource like a DAQ task or a file, by checking any semaphores or other necessary interlocks, then using the resource, and then relinquishing it so they will not interfere with any other parts of the program?
 
If anybody is good enough to comment on all this, I would owe you a favor. Maybe I could come wash your car, or something. Well, if anybody is still along for this ride, thank you very much.
0 Kudos
Message 6 of 19
(5,175 Views)
OK, the example VI and its behavior are much simpler now.
 
Both the attached VIs have the same front panel and the same intended behavior. The intended behavior is written on the front panel and is as follows:
 
This VI works in one of two modes.
In "Key Down Mode", pressing any key displays its scan code in "Output". Clicking "Switch to Value Change Mode" moves the VI into that mode.
In "Value Change Mode", changing the value of "Input" displays its value in "Output". Clicking "Switch to Key Down Mode" moves the VI into that mode.
In either mode, the text indicator identifies the mode, and clicking "STOP" ends the VI.
 
 
 
2EventHandlersInCaseStructureInWhileLoop01.vi uses a case structure in a while loop, with cases for both operating modes, as the primary level of organization. It misbehaves by hanging in three different situations, which are documented on the front panel. It is organized as a very simple state machine.
 
OneEventHandlerAsPrimaryOrganization01.vi uses one event handler in a while loop as the primary level of organization, with case structures in the event handlers. It works as intended, with much less code.
 
If these made-up examples did everything that my big project required, we could use OneEvent...vi and be done. But OneEvent...vi isn't much use in the big project because organizing primarily around what kind of event has occurred would be impossibly messy.
 
So, can we make something like 2EventHandlers....vi that is organized like a state machine and has the intended behavior?
 
Thanks!
0 Kudos
Message 7 of 19
(5,141 Views)
For the love of everything, never ever put an event structure with 'Lock Front panel while event executes' in a case that hardly ever will be exectued

Heres the code to merge your two event case structure:


Ton


Message Edited by TonP on 06-23-2008 07:01 PM
Free Code Capture Tool! Version 2.1.3 with comments, web-upload, back-save and snippets!
Nederlandse LabVIEW user groep www.lvug.nl
My LabVIEW Ideas

LabVIEW, programming like it should be!
Message 8 of 19
(5,127 Views)
>For the love of everything, never ever put an event structure with 'Lock Front panel...
 
Oh. Hey, that fixes everything! Thanks! I guess I shouldn't need to be told.
 
Below is the example I should have written, without that error. It seems to do everything I wanted, the way I originally wanted to do it.
 
Thank you, TonP.
 
I'm studying your code to merge the two event case structure. Well, I have a lot to learn.
 
0 Kudos
Message 9 of 19
(5,118 Views)
Here's a useful article about event-driven state machines, though it looks about 6 years old and discusses V6.1.
 
 
"Another caveat when using Event Structures with state machines is that you must make sure there is always an Event Structure available to handle any user interface event that is generated."
 
The article doesn't point it out, but one way to accomplish this is unregistering an event before making the Event Structure handling it unavailable. Maybe that capability wasn't in 6.1.
0 Kudos
Message 10 of 19
(5,109 Views)