LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Handling (almost) any front panel changes with an event structure. What is best practice?

I am working on updating a legacy program which is seriously outdated in architecture. The program controls a set of external relays, each of which has a boolean variable, and monitors some process pressures. Without getting into what it was before, the new program currently has two parallel loops:

 

The first loop is a state machine, which a) reads pressures from an external source, and b) checks the data against user-defined setpoints. It flips a local variable if a setpoint is exceeded.

 

The second loop is an event structure which triggers when the setpoint locals change, changes some booleans, and then writes to the external FieldPoint relays to update them. For safety reasons I don't want this loop to be doing anything else - that way the setpoints are always triggered ASAP.

 

This would all be well and good, but the user also needs to be able to flip individual boolean relays on the front panel - and some actions need to be prohibited based on the state of the system. So each time the user flips a boolean, some checks need to happen, and if it's OK the program needs to write to the external FP relays.

 

The obvious choice is to make a third parallel event structure in a loop, to respond to each of these booleans changing, but that would require configuring as many events as there are booleans, and there are dozens of them. I feel like there must be a more elegant solution than making 3 while loops and 50 events. Is there a way to catch an entire class of events (hitting a boolean control) in one trigger, and then passing which button it was along with that trigger? Or perhaps catching any front panel variable changing, and passing what the class of the changed element was?

0 Kudos
Message 1 of 16
(6,250 Views)

I would design this a little differently.  You have a set of Controls that you use to create/maintain SetPoints.  You have a loop that runs "periodically" (once a second?  one a minute?  faster?  slower?) that monitors Pressure.

 

Every time the Pressure is read, you want to "do something" with that value, which may involve changing relays, doing nothing (because everything is OK), saving a result to a file, whatever.  Whatever you do is affected by the values of the SetPoints (set by the Controls).

 

Instead of a State Machine, let's use the Queued Message Handler, which is like a "State Machine with Variable Inputs".  For simplicity, let's assume a SetPoint One Control and a Stop Button.  You have an Event Loop with Value Changed cases for SetPoint One and Stop.  The SetPoint One Event generates a Message "SetPoint One" with data from the NewVal input (i.e. it passes the new SetPoint One value to the Message Handler's SetPoint One "State"), while the Stop Event generates a Stop Message with no value (and stops the Event Loop).

 

Incidentally, if you are unfamiliar with the QMH, there's an example Template you can find in the Getting Started window by clicking "New Project" and choosing Templates.  Also, I'm a little sloppy with terminology -- I use "Message" both to refer to the Cluster that the Message Handler passes around and to the first part of that Cluster, the "Message" (which you can think of as analogous to a State, and which is either a String or an Enum, my personal preference), with the second part of the Cluster being a Variant usually called "Data".

 

So the User changes SetPoint One on the Front Panel, firing the Event, which sends a Message to the Message Handler.  All it does is take the value of SetPoint One (passed in the Data part of the Message) and stick it on a Shift Register (which can be initialized by simply wiring the SetPoint One Control to it).  The Stop Message is handled by cleaning up whatever needs it, and stopping the Message Handler Loop.

 

But what about monitoring your Pressures?  Ah, a third, independent and probably timed loop that periodically does readings and transfers the Readings via Messages to the QMH.  There, they are compared to the various values set by the SetPoints (and whatever logic you need).  With luck, nothing more need be done, but if the pressure is too high (or too low), you need to generate another Message ("Pressure too High", with Data = Pressure) and have a QMH Case that handles this.  

 

The assumption here is that all Messages that the QMH processes take very little time (changing a value on the Shift Register, doing the logic on a Pressure Reading to see if in range, sending a command to change a relay if pressure is out of bounds), so the QMH remains "responsive" and the Pressure Readings get essentially "instant Service".  

 

That's what I'd do (and what I have done, myself).

 

Bob Schor

 

P.S. -- I just realized (after I hit Post) I didn't answer a question you had about a lot of Events.  Yes, you want a Lot of Events, one per Control, so each Control gets immediately dispatched to do its "one thing" (typically updating a value in the QMH's set of Shift Registers).  Yes, it can get awkward having 20 shift registers running across your Message Handler, but I've had a dozen with no problems.  Hint -- line them up nicely (evenly spaced) and put a Text Label over them (play with font size) that names each wire ("SetPoint One", "Temp", "Pressure", etc.).

 

 

0 Kudos
Message 2 of 16
(6,225 Views)

Please excuse if I am in left filed since I did not rad in great detail...

 

You can register a single event case for multiple controls of the same type. The event will return an ref to tell you which control changed (get the control name) and then you can act based on the name ( drive a case structure maybe?)

 

Ben.

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 3 of 16
(6,214 Views)

Here's a minimal, quick example of registering two buttons to one event:

 

Register array of buttons.png

In this case I'm using the array search to find the index of the button pushed, but you could use the "CtlRef" terminal to do other things, like checking the name.

 

This uses a dynamic registration rather than a fixed set in the event case, which can be a lot easier to set up if you need to change which buttons are registered easily.  In this case, scaling it to 50 buttons just means adding 48 more references to the "build array" node, which I prefer to using the event structure configuration window.

Message 4 of 16
(6,206 Views)

Ben and Kyle make valid points, but why?  I'm a proponent of the K.I.S.S. style of LabVIEW Programming, and the corollary "have it do one thing" (especially important for sub-VIs, but could also apply to Event Cases).

 

You always need to decide on "cases" -- you can put your Case Structure in the Event Loop (as Kyle does), somewhere else (not sure where Ben's is), or "let the Event Structure be your Case" (as below).  Each Event "does one thing", no arrays, no references, no need for Dynamic Event terminals (of course, this assumes that you don't need to do it dynamically).  Plus any CLAD can understand it (and, I suspect, CLA's will also understand) ...

Simple Events.png The other Event has Button 2 inside, and says "Do Something Else".

 

Bob Schor

0 Kudos
Message 5 of 16
(6,190 Views)

@Bob_Schor wrote:

Ben and Kyle make valid points, but why?  I'm a proponent of the K.I.S.S. style of LabVIEW Programming, and the corollary "have it do one thing" (especially important for sub-VIs, but could also apply to Event Cases).

 

You always need to decide on "cases" -- you can put your Case Structure in the Event Loop (as Kyle does), somewhere else (not sure where Ben's is), or "let the Event Structure be your Case" (as below).  Each Event "does one thing", no arrays, no references, no need for Dynamic Event terminals (of course, this assumes that you don't need to do it dynamically).  Plus any CLAD can understand it (and, I suspect, CLA's will also understand) ...

Simple Events.png The other Event has Button 2 inside, and says "Do Something Else".

 

Bob Schor


Because the OP asked;

 

"

The obvious choice is to make a third parallel event structure in a loop, to respond to each of these booleans changing, but that would require configuring as many events as there are booleans, and there are dozens of them. I feel like there must be a more elegant solution than making 3 while loops and 50 events. Is there a way to catch an entire class of events (hitting a boolean control) in one trigger, and then passing which button it was along with that trigger? Or perhaps catching any front panel variable changing, and passing what the class of the changed element was?

"

 

I was attempting to provide an alternative. Your approach is valid and I am not dissing that. It does run into a slight complication when you are up 50 Booleans since we could have to find a particular event case from a list of 50. Sure it can be done.

 

But then...

 

The end user decides (just an example mind you) they want to button that was pushed to start flashing. In Kyle's approach, we mod one event case and we are done. With 50 event cases... we are modifying 50 cases.

 

I think the phrase is "Scales well".

 

Just my two cents.

 

Ben

 

Edit now that I actually rad the first post...

 

FP are obsolete and were replaced by cFP which are now obsolete. I hope you are stocking up on spares!

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 6 of 16
(6,187 Views)

It all depends on how you want to skin the cat.  Eventually you have to have a whole boatload of something, whether it be events or cases.  I can't see any obvious advantages to either way.  My personal preference would be the "many events" approach because it seems more "self-documenting" - i.e., I can more easily see the one-to-one relationship of control to event.

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 7 of 16
(6,169 Views)

@Ben wrote:

@Bob_Schor wrote:

Ben and Kyle make valid points, but why?  I'm a proponent of the K.I.S.S. style of LabVIEW Programming, and the corollary "have it do one thing" (especially important for sub-VIs, but could also apply to Event Cases).

 

You always need to decide on "cases" -- you can put your Case Structure in the Event Loop (as Kyle does), somewhere else (not sure where Ben's is), or "let the Event Structure be your Case" (as below).  Each Event "does one thing", no arrays, no references, no need for Dynamic Event terminals (of course, this assumes that you don't need to do it dynamically).  Plus any CLAD can understand it (and, I suspect, CLA's will also understand) ...

Simple Events.png The other Event has Button 2 inside, and says "Do Something Else".

 

Bob Schor


Because the OP asked;

 

"

The obvious choice is to make a third parallel event structure in a loop, to respond to each of these booleans changing, but that would require configuring as many events as there are booleans, and there are dozens of them. I feel like there must be a more elegant solution than making 3 while loops and 50 events. Is there a way to catch an entire class of events (hitting a boolean control) in one trigger, and then passing which button it was along with that trigger? Or perhaps catching any front panel variable changing, and passing what the class of the changed element was?

"

 

I was attempting to provide an alternative. Your approach is valid and I am not dissing that. It does run into a slight complication when you are up 50 Booleans since we could have to find a particular event case from a list of 50. Sure it can be done.

 

But then...

 

The end user decides (just an example mind you) they want to button that was pushed to start flashing. In Kyle's approach, we mod one event case and we are done. With 50 event cases... we are modifying 50 cases.

 

I think the phrase is "Scales well".

 

Just my two cents.

 

Ben

 

Edit now that I actually rad the first post...

 

FP are obsolete and were replaced by cFP which are now obsolete. I hope you are stocking up on spares!


What happens if they just want one button to flash?

 

edit - i answered my own question.  you have reference... etc.

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
Message 8 of 16
(6,168 Views)

@billko wrote:

It all depends on how you want to skin the cat.  Eventually you have to have a whole boatload of something, whether it be events or cases.  I can't see any obvious advantages to either way.  My personal preference would be the "many events" approach because it seems more "self-documenting" - i.e., I can more easily see the one-to-one relationship of control to event.


As someone who has gone through it both ways, I much prefer combining event cases where possible.  One place to look and it is possible, especially if using the QMH, to not even need a case structure inside the event structure: just use the control's label as a value you pass through the queue's data and then let the QMH worry about it.



There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 9 of 16
(6,115 Views)

@crossrulz wrote:

@billko wrote:

It all depends on how you want to skin the cat.  Eventually you have to have a whole boatload of something, whether it be events or cases.  I can't see any obvious advantages to either way.  My personal preference would be the "many events" approach because it seems more "self-documenting" - i.e., I can more easily see the one-to-one relationship of control to event.


As someone who has gone through it both ways, I much prefer combining event cases where possible.  One place to look and it is possible, especially if using the QMH, to not even need a case structure inside the event structure: just use the control's label as a value you pass through the queue's data and then let the QMH worry about it.


And there is one very important thing here which you must keep in mind when designing your Front Panel part: do NOT use show labels for front panel elements! Use Show the captions instead! You can arbitrarily change the caption whenever you want, but keep the label, otherwise you might **** up your code (you change a label, then a different control label will be sent to a submodule/QMH; of course also use for such string controlled Case structures a "Default" case to capture such programming mistakes)...

 

edit: additional benefit with captions: you can change them during runtime via property nodes...(imagine a multi-language app)

edit2: obviously my comment was addressed to the OP 🙂

Message 10 of 16
(6,110 Views)