LabVIEW Channel Wires

cancel
Showing results for 
Search instead for 
Did you mean: 

Am I trying to use Channel Wires like a Queue too much??

ok Blokk thanks! I will try to mess around with that idea and see if I can implement and fully understand what you are describing. Thanks!

 

 

0 Kudos
Message 11 of 17
(2,332 Views)

I recently gave a talk to a group of colleagues (I've been asking for two years to give a presentation on Channel Wires to the Rochester (NY) Users Group, but noone from NI seems to remember that we exist, and noone seems to know who would be interested).  I spoke for over four hours and covered lots of "new stuff" for them, including using

Channels instead of Queues for what I took the liberty of called the Channel Message Handler Design (CMH).

 

Using a CMH, it is really easy to build the system you want.  Here's a description (it's interesting to "do it yourself", so I'll wear my Professor hat ...):

  • Create a Message Cluster with two Elements, Msg (an Enum) and Data (a Variant) (just like QMH)
  • Define a Msg Type (Enum) with the following "states":  Init, Start, Log On, Log Off, Acquire, Stop, Quit.
  • Create some Boolean controls:  Start (Latching), Log (On/Off), Stop (Latching).
  • The CMH is a Case-inside-a-While.  On the left Outside, build an Init Message Cluster and create a Messenger Writer.  Bring the Channel into the While Loop.
  • On the "inside", bring the Channel into a Reader.  Unbundle, and send the Msg (Enum) to the Case Statement.  Add Case for Every Value (and get rid of the Default Case).
  • Digression -- an Event loop perched above the CMH.  Program the following Value Changed Events:
    • Start:  Build a Message with Start (Msg), create a Messenger Writer, and bring to right edge of Event Loop.
    • Log:  If Log = True, build Log On Message, otherwise build Log Off.  Create Messenger Channel and add to output from Event Loop.
    • Stop:  Build Stop Message, add output to Event Loop.  Also stop the Event Loop.
    • Now here's the Fun Part -- take the output Channel from the Event Loop, bring it down to between the Event and CMH Loops, bend it backwards towards the "input" side of the CMH loop, and join it to the Message Channel going into the CMH from the Init Messenger.  [Wow!]
  • So now we can send Start, Log On, Log Off, and Stop from the Event Loop.  Add appropriate code to the CMH's Start Case, which may consist of doing almost nothing (because Init did all the work) -- the last thing that Start should do is create an Acquire Message, create a Messenger Channel and bring it out of the CMH, bring that Channel up over the top of the CMH and join it to the Channel coming down from the Event Loop [Double Wow!!].
  • So now our CMH gets inputs from three source -- from an Initialization Writer (Init), from an Event Structure (Start, Stop, etc.), and from itself (Acquire).  We could add more, but that's enough for this Demo.
  • OK, so now Acquire wants to take some data.  Add a Shift Register initialized with a False Boolean (it could be initialized to False in the Init State) and call it "Logging".  Add a Case to Acquire to do Logging if the Shift Register is True.  [Extra credit -- export Logging, as in Producer/Consumer, to a Parallel Loop.  Use a Stream Channel, and take advantage of its "Last Element?" and "Element Valid?" inputs].  If you are simulating things, put an "Acquire Delay" in here.  Finally, guarding to be sure this happens after the time runs out, send an Acquire Message out to loop back around for the next Acquire State.
  • The Log On and Log Off Cases are trivial -- you just change the value of the Logging Shift Register.  Note that Acquire won't "lock out" these two Cases.
  • Stop should do any processing that might be needed to close files, turn off gadgets, etc.  This would be a good place to turn off Logging (very easy to do with a Stream -- just set Last Element? = True and Element Valid? = False, and have the Consumer recognize one or both of these and close files and stop itself).  When Stop thinks everything has been asked to Stop, it sends itself the Quit Message.
  • Quit only has to stop the QMH loop -- the other loops should already be stopped.  No more Local Variables, no more Releasing the Queue and having an Error trigger the "All Done" state.
  • But what about Errors?  If an Error occurs in the Event Loop, it can still send a Stop message, but what if it occurs in the CMH?  OK, one more Channel -- a Tag Channel whose only job is to send a Boolean "T" from the Stop Message Case to the Event Loop, where it is wired to the Stop Indicator (don't use the Stop Button to stop the Event Loop, use the CMH and a Tag Channel).  You could (should?) add one more Message, namely Error, and have it call Stop, have Stop send the Stop Tag to the Event Loop and turn off the Stream (as described earlier), and call its own Quit State.

There!  What's more, when you actually draw this up, it is so logical -- you see the feedback as Messages go from the output side of the CMH to the Input side to be acted upon, you see the various Messages being combined (FIFO style), it is compact, data flows as one expect (I've always been bothered by the retrograde "flow of data" from an Enqueue), and it's pretty.

 

As to Priority -- there is no way (at present) to make a Priority Channel.  That was an Original Design Feature (I know, because I asked in 2015, and I was convinced).  You also cannot (easily) "Flush" a Channel Wire.  There are a few other restrictions, some of which have "cheats" (ask me at NI Week).

 

Bob "Channel" Schor

Message 12 of 17
(2,329 Views)

That explanation deserves 1000 enqueued KUDOS.

 

Bob Schor, it is possible to Do this?:

 

1) Event case send "Set filter default" (for example), message to the CMH.

2) Now user wants that the corresponding case do TWO things, Set default to filter values and stop filtering. Those two things happends in other cases in the CMH.

 

My question is that if one case in the CMH can enqueue MORE than one message to itself. 

 

Probably there is another way to solve that but it is possible what I am asking?

0 Kudos
Message 13 of 17
(1,812 Views)

Yamelbio: Build an array of the messages you want to send. Put the Write endpoint inside a For Loop inside the event structure. Wire the array to the Write endpoint, thereby creating an autoindexing tunnel on the For Loop. Done! 🙂

0 Kudos
Message 14 of 17
(1,782 Views)

I totally agree with AQ's method.  As I'm sure you know, order you call them in the Array is the order they'll be processed.

 

Bob Schor

0 Kudos
Message 15 of 17
(1,766 Views)

 


@yamelbio wrote:

Bob Schor, it is possible to Do this?:

 

1) Event case send "Set filter default" (for example), message to the CMH.

2) Now user wants that the corresponding case do TWO things, Set default to filter values and stop filtering. Those two things happens in other cases in the CMH.

 


Please don't do that.  Sending "messages" to oneself, in order to combine two actions in one, is a common poor design that leads to hard to find bugs.  

 

Imagine, for example, you want a filter that is default except for on filter parameter.  You might send:

"Set filter default"

"Set parameter A=5"

"Start Filtering"

 

You would expect to now be filtering with A=5, but instead, because "Set filter default" sent two messages, placed on the back of the message queue, you actually have:

 

"Set filter default" --> does nothing but send the two messages

"Set parameter A=5"

"Start Filtering"

"Set default to filter values"

"Stop filtering"

 

Thus you you both overwrite the parameter change and leave your filter not running.  

 

The rule of thumb for messages is that they should do what they say when executed. "Set filter default" should mean that the filter has been set to default, when the very next message is handled.

 

This example bug is actually a very minor one, as it is very obvious and will thus be found and fixed.  Much more dangerous are potential race conditions, where the bug only shows itself randomly based of details of exactly when messages get sent.

 

You can send messages to yourself, but not as a way to execute subactions of your current message, even if those subactions are available as potential messages.

0 Kudos
Message 16 of 17
(1,754 Views)

jdpowell is right. I answered the "can you"... ne answered the "should you". 🙂

 

Use a subVI for the common functionality of the two events. Sending messages to yourself should be done only for continuing operations, not sub-operations. For example, it is common for a loop that has to poll some piece of hardware to finish one poll and then post a message to itself for the next poll because that allows other parts of the system to interject messages between polls. (Note that there are alternate designs for this that are often better, but it is a legitimate use case sometimes. The sub-operations use case is never legit, in my experience.)

0 Kudos
Message 17 of 17
(1,740 Views)