Jump to content

Self-addressed stamped envelopes


Recommended Posts

I've always been meaning to post this code library, once it is meaningfully "finished", but that may be a LONG time. So here is a very "beta", "lightly documented", and "less than entirely untested" version as of today.

Test Messenger library.zip

NOTE: newer version (2011) in a later post.

Contains a "Messenging" library and a set of examples that are up-to-date versions of the ones I posted here and in my Parallel Process thread. Dependancies are the OpenG toolkit (Data Tools, mostly) and the JKI statemachine, both available with VI Package Manager. LabVIEW 8.6.1.

Here is a a Class Diagram with labels:

post-18176-0-50096200-1317218318.png

There is a Palette Menu for the library, but if that doesn't work there is also a "Tree.vi" of the most useful VIs.

Any comments appreciated,

-- James

  • Like 1
Link to comment

Hey AQ,

I had a look over AF, but I just don't think I'm ready (no free time atm) to battle with the OOP concepts. I'm pretty sure I can achieve what I'm trying to achieve with a regular labview architecture and proper hand-shaking or queue exchanges.

Cheers,

Alex

Alex (and others interested),

I have ported the AFv3.0.6 to LV2010. I am testing it now, but I am willing to share the code. Please PM me with your email address so I can keep track of the users and send updates.

Kurt

Link to comment
  • 1 month later...

All of the examples run, here. The only comment I have is somewhat superficial and simplistic (meaning not entirely thought through): since the logger display is called by reference based on a relative path, couldn't it somehow be included in the Create.vi of CommandMessenger[A,B]? Then, instead of the observer being CC'd in the Controller, the Messenger's "Receive" could send the copy. I'm thinking only of keeping the top level VI's diagram simple.

Link to comment
The only comment I have is somewhat superficial and simplistic (meaning not entirely thought through): since the logger display is called by reference based on a relative path, couldn't it somehow be included in the Create.vi of CommandMessenger[A,B]? Then, instead of the observer being CC'd in the Controller, the Messenger's "Receive" could send the copy. I'm thinking only of keeping the top level VI's diagram simple.

Thanks for replying,

If I understand your question correctly, your asking if a message logger could automatically be attached inside the "Create" methods, thus making logging of all messages automatic while hiding this fact in the top-level diagram. Correct?

One could easily create a "Create and auto-log" VI that does exactly this, encapsulating the currently existing functions, and setting up a logger that records all messages to the created Messengers. Personally, I wouldn't use this, as I don't actually want all messages logged except when I'm debugging, and when I am logging I want this fact to be very clear from the top-level VI. What is logged and where isn't something that should be hidden, IMO.

Link to comment

BTW, here's an extension I am working on, that uses the "Self-Addressed Envelope" aspect of the framework: a class of Asynchronous Dialog boxes. This allows a process loop to display a dialog box for User input, without waiting. It can then continue to perform other actions. When the User dismisses the dialog, his/her input is sent back to the loop's Messenger via a "reply". So far, I have only created a Dialog that is a modification of the standard LabVIEW "Three Button Dialog"; an example is shown below:

post-18176-0-08073300-1320762234_thumb.p

Here, the example process increments a count every 200 ms (in the Timeout case). If the User presses the "Clear Count" button, a dialog is configured and displayed. Had the standard LabVIEW dialog been used, this would block the incrementing of Count until the dialog completes. But here the dialog is dynamically launched and asynchronous, and thus the loop keeps counting. Part of the dialog configuration is to give it a message Label (also used as the dialog title) and attach the loop's own Messenger (Event-type, in this case) as a "return address". When the User pushes a button and dismisses the dialog, the name of that button is sent back the the return address with the supplied label. Thus, the loop can perform the required action, such as resetting the Count to zero if the User responded "Yes, please!". The asynchronous dialog box has an optional timeout function (it replies "window closed") and will automatically close if it's calling VI goes idle (it uses a Notifier internally to achieve these functions).

-- James

Link to comment

... your asking if a message logger could automatically be attached inside the "Create" methods, thus making logging of all messages automatic while hiding this fact in the top-level diagram. Correct?

Yes. I believe you were asking for a different kind of comment, but it's all I have :)

One could easily create a "Create and auto-log" VI that does exactly this, encapsulating the currently existing functions, and setting up a logger that records all messages to the created Messengers. Personally, I wouldn't use this, as I don't actually want all messages logged except when I'm debugging, and when I am logging I want this fact to be very clear from the top-level VI. What is logged and where isn't something that should be hidden, IMO.

Ok. I like to put the debugging/logging code in each component (each one for me tends to be just different enough). And I can select debugging capability separately in each component, depending on what I'm looking for.

Link to comment
  • 4 weeks later...

I've been meaning for the longest time to add a Network-messaging capability to this library, and finally made the time to do it this week. I thought I would update my example here with TCP communication. Converting the example took only a few minutes, which shows the advantage of the "plug-and-play" nature of using a LVOOP class structure for message communication methods.

Here's good old "Process A", now standing alone in its own App instance (Application 2), with the new "TCPMessenger" plugged in in place of the original QueueMessenger:

post-18176-0-53183900-1323259364_thumb.p

And here is the rest of the example on Application 1 (haven't had a chance to test on a separate computer yet). It uses "RemoteTCPMessenger" to connect to the server created internally by Process A's "TCPMessenger". Otherwise it is identical to before.

post-18176-0-29337400-1323259378_thumb.p

Note how the reply from Process A is routed back through the Process A's TCP connection. This is because the "reply address" on the "SendTimeString" message, "CommandMessenger B", is a QueueMessenger, and its internal queue is local, and not valid on the remote Application 2 that contains Process A. The two TCP connection "Actors", running in the background, inspect and alter the reply addresses of sent messages to perform this routing of replies through the sending TCP connection. As the "Observer Registration" messages, shown in Parallel Process, utilize the same "reply address", that system of publishing information also works via a TCP connection, even if the observer has a local-only messenger.

Here is a Message custom probe showing summary information about the message received by Process A. The "X"s after the QueueMessenger (queue refnum 4076863496), which is Process B's, and the Message Logger indicates they are invalid in Application 2 (but they are still valid in Application 1). QueueMessenger (refnum 4091543557) leads to the TCP Connection Actor.

post-18176-0-52777100-1323261258.png

The TCP communication is all run by "actors" based on the Parallel Process design. Creating "TCPMessenger" launches a "TCP Listener Actor" in the background. "RemoteTCPMessenger" launches a "TCP Client Actor" which initiates the connection; the TCP Listener then launches a "TCP Connection Actor" to handle its side of the connection. Multiple RemoteTCPMessengers can connect to the same TCPMessenger server (a new TCP Connection Actor is launched to serve each new connection).

-- James

Link to comment
  • 1 month later...

I LOVE this Test Messenger Library! I am fairly new to OOP and I have picked this right up. I have put to good use your Metronome Method and the Parallel Launching of VI's. I had a Class of Instruments, and children classes of Power Supplies and Ammeters. I have an array of Class Instruments, with each element a child class. I simply made a parallel process for each instrument, and launched all the parallel processs in one simple for loop indexed on the array of Class Instruments. Next I used the metronome method to send a broadcast message to each parallel process to grab an update from all the instruments. Works Great! and solves so many timing issues.

Now I am trying to learn the Actor Framework, but It is proving fairly challenging.

Link to comment

Hi monzue, thanks so much for your highly positive feedback! Gives me the impetus to push forward and get a new version in the Code Repository.

I wasn’t aware of anyone using this, and I apologize in advance as updating your code to use the new version will involve a couple of tedious hours tracking down and replacing VI’s that have moved/been renamed/put in a different library. I’ve done a lot of reorganization. It looks scary the first time you open a VI that can’t find some of its classes, since all the class methods show up as question marks, but it is usually easier than it looks to fix by just replace the missing class constant, with all the methods magically reappearing. I promise to make the next version more finalized so you don’t have to do it again.

Alternately, feel free to take the previously posted version and build on it to make it your own. The new version will have the TCP Messengers shown above, though, which is a major new feature if one has a distributed application (unfortunately, I don’t have a distributed application at the moment to really test it on). It will also have the above "Asynchronous Dialog box” and Futures.

BTW, what LabVIEW version are you using? I have recently upgraded from 8.6 to 2011, and I was going to use the new “Async Call by Ref” node of 2011 in place of the “Run” method for launching VIs (this has very important performance advantages), but I could try and keep a separate 8.6 version available. It’s more (unpaid) work for me, so I need to know if there’s a need.

Thanks again,

— James

BTW on the Actor Framework: My Messenger library is the work of a lone programmer who’s interested in easy use of dynamic VIs talking to each other. The Actor Framework comes from a very different perspective, that of a framework for a diverse team of programmers working on a large project, where restrictions are needed to prevent hard-to-see flaws compounding into severe problems. I don’t have the multi-programmer experience to analyze my Messenger library from that perspective.

Link to comment

Oh, the new version will also contain the “Actor Manager” (I’ve started to call my “Parallel Process” things “actors”, it’s a lot shorter and is an established computer science term) which makes knowing what’s running, and accessing the Front Panels or Block Diagrams, much easier.

Below is a tree of actors running TCP communication tests (same computer, but three different projects):

post-18176-0-35069200-1328610877_thumb.p

If one tries something complicated, with umpteen copies of “Observer Register” or “Metronome” used in different ways, this really helps diagnostics. As does being able to quickly open the Block Diagram of any actor and place the “MessageTable” probe to observe the incoming message stream.

— James

Edited by drjdpowell
Link to comment

Hey James,

You are very welcome! I can tell that you have really put a lot of hard work into this framework.

I'm using Labview 2011.

Also, here is a little more feedback:

I found that I the default way of launching a parallel process using the path of the class did not always work for me. This is because I dynamically loaded a child class onto a parent class string. So when it came time to launch the parallel process (for the parent class), the messenger library was looking for a VI that didn't exist (because the child class path was on the string). I started to modify the code in the launch.vi, but then I noticed that you had a nifty little data access vi named "Specify Process.vi" that easily allowed me to specify the path to the correct process.

Also, when I noticed that you had this Specify Process.vi I started looking around more in your code and seen that there are a LOT of other very usefull VI's that are not indicated in your tree of vi's.

On another Note, I really haven't completely understood how to harness the power of your event registers, or should I say the ObserverRegistry. For example, I am not really getting why that you create Observer Registry in every parallel process and why you seem to notify every time a state executes in the parallel process. Or even what the difference is between Notify State and Notify Event.

What I imagine the Notify to be used for is that if you send a message with a certain name, you can register other Observers to "catch" that message also.

What happens when you have a lot of notifiers in the code, but nothing ever listens for the notifications? What happens when you send messages, but nothing recieves them? For instance in a parallel process you have a Msg:Reply. I would leave this unwired, or let the case structure node be Use default when unwired.

Is it good programming practice to when there is a reply message in the parallel loop, should there always be a NOTIFY attached to the message?

Ok, I thought that i would attach some screen shots of my code, also, so you could see what I had done.

Launching Parallel Processes

Instrument Updates linked To Metronome

- Ben Yeske

Link to comment

I found that I the default way of launching a parallel process using the path of the class did not always work for me. This is because I dynamically loaded a child class onto a parent class string.

The new version uses the VI qualified name, rather than the path. Hopefully, this will work better.

Also, when I noticed that you had this Specify Process.vi I started looking around more in your code and seen that there are a LOT of other very usefull VI's that are not indicated in your tree of vi’s.

Some of those are experiments, since this framework kind of grew over time through trial and error, so be careful.

On another Note, I really haven't completely understood how to harness the power of your event registers, or should I say the ObserverRegistry. For example, I am not really getting why that you create Observer Registry in every parallel process and why you seem to notify every time a state executes in the parallel process. Or even what the difference is between Notify State and Notify Event.

There are two ways that one can get information out of a launched Parallel Process: (1) having it respond to a message sent to it, or (2) “registering" with it to have “notification” messages sent whenever something happens (an “event”) or the state of the actor changes (“state”). These are separate methods; one could probably just use one or the other. My examples are perhaps overloaded with trying to do both, and that might be confusing. But then, a reusable component may be more useful if it can communicate in a variety of ways. I actually tend to rely on the Observer Registry stuff primarily, but having replies can still be useful, especially for synchronizing things (as you do in your application).

What I imagine the Notify to be used for is that if you send a message with a certain name, you can register other Observers to "catch" that message also.

Exactly. Note, however that this is NOT a global thing like a named queue or global variable. To “register” to receive a notification one must send a registration message to the Parallel Process in question. You do this in your App when you register for “MetronomeTick” events.

An “Event” is, well, an event. ”Tell me when this happens”. “MetronomeTick” is an event.

If you look at the “Metronome” Block Diagram as an example, you’ll see that you can also register to receive Error Messages, and the “Shutdown” event which is the last thing sent when the Metronome shuts down.

A “State” Notification is slightly different. Here, you don’t want to be told when something happens in the future, but what something is right now, and to be notified of any changes. Metronome has a “MetronomePeriod” State notification. If you were to register to receive this notification, you would immediately be sent a message containing the current period (the Observer Register remembers the last state message so it can notify any new observers). You would also be sent a message any time the state changed.

What happens when you have a lot of notifiers in the code, but nothing ever listens for the notifications? What happens when you send messages, but nothing recieves them?

Nothing happens. Neither “Notify Observers” nor “Reply” throws any errors if no one is listening. If you launch an actor and don’t subscribe to its published notifications or bother to listen to its replies that is not the responsibility of that actor. It is the job of the code launching the actor to decide who should receive messages from it. This is a deliberate design choice; actors are reusable components that are not coupled to the code that launches them. They don’t demand anything and only provide services. If you don’t use all the services… whatever.

In your code, for example, “Metronome” attempted to reply to your “SetPeriod” message, but you attached no return address. It also published its period and a shutdown message, but no one asked to be notified of them. No problem, “Metronome” doesn’t mind. It stands ready to provide these messages, should the code that launched it want them. You could, for example, register your UI to receive “MetronomePeriod” state updates so you could display the period. Or you could change your “SetPeriod” message from a “Send” to a “Query” (that waits for a reply) to check that Metronome did what you asked (if you try to set the period less than 10 ms, for example it will comeback saying 10, because that is the lower limit). Queries are good for making sure something has happened before continuing; if you sent a “SetPeiod” message by accident, the reply would be the Error Message “Unhandled: “SetPeiod””, code 52. This message would also be published to anyone registered to receive error messages.

Is it good programming practice to when there is a reply message in the parallel loop, should there always be a NOTIFY attached to the message?

Not necessarily. My simple examples mostly involve commands that change the actor’s important state (“SetPeriod”, etc.), so they naturally involve a Notify. But one could have commands that don’t change state, or the state can change for some reason other than a command. And it is OK to have actors that don’t have an Observer Registry at all, if that isn’t really needed.

— James

  • Like 1
Link to comment

Ben, small note:

I see in one of your images that you index over your array of Instruments and individually configure an Observer to substitute a message and then register this Observer with the Metronome. You’ll have less overhead if you take the entire array of instruments, create a single Observer, configure it to substitute a message, and register it. Observers can hold any number of “Send” objects internally. To make your array into a single Observer, use what is now called “Create Observer (polymorphic)” but was then called something like “Make Observer” or “Add Observer”.

post-18176-0-46000900-1328961853.png

Another small note: There is a bug that is a problem for a feature that you might not be using but should know about. For Variant-type messages, one can not fill in the label and let the message use the variant data name as the label. But a bug in converting to variant sometimes doesn’t take the right name:

post-18176-0-19071300-1328962724.png

Edited by drjdpowell
Link to comment
  • 2 months later...

Hello,

I’m uploading the latest version of my framework, even though it isn’t polished, as I’m unlikely to have any time to polish it for months (baby on the way). It includes all the extra stuff since the last version, including the Actor Manager, and TCP-network versions of the Queue and User Event Messengers. It is in LabVIEW 2011.

— James

Messenging.zip

  • Like 2
Link to comment
  • 7 months later...
  • 2 months later...

hey drjdpowell!

 

So, I have downloaded your newest version of the messager library.  I really like this library, and have been starting to use it.  It has really helped me to understand the LVOOP.

 

I really like the way that the Actors are Launched using the type 2 Actor, where simply the vi with the name of Actor is called in the Class; that Dynamic Launch Shell VI with the child class implementation is simply ingenious.

 

I havent really played around with the Actor Manager much yet, I noticed that the file is missing in the VIPM distribution. That would be cool if you could add it!  :)

 

here is an idea for you regarding a usefull Parallel Process, you may have already thought of this, though.  I have an actor TCP Client and and actor TCP Server that simply sets up the port with either a service name or a port number, and listens/sends TCP packets as strings. (I'm not trying to sent class messages over the TCP port.)  So any Actor that registers its observer with the TCP Client will automatically recieve the message "TCP Packet" when there are bytes available at the port. 

Link to comment

Hi Ben,

The launch technique is stolen from mje’s “message pump” package.  It’s used by the Actor Framework, also.  

 

The Actor Manager installs in a different location, and should be available under the Tools menu:

post-18176-0-74878200-1361877295.png

Please note that the Actor Manager is badly in need of rewriting.  It’s not pretty.

 

What’s your use case for TCP?  I have TCP Messengers in the package (which use TCP actors to run the client/server) that are intended to seamlessly substitute for other messengers (handling replies and observer registrations).  At some point I will write the code to launch an actor sitting behind one of these servers.  Do you want a TCP actor to talk to external non-LabVIEW code?

 

BTW, I’m in the midst of writing a talk on this package that I’m going to present at the European CLA Summit.  Of course, this has made me relook at lots of things I did and want to change them  :) .  I’m going to upload a new version before that summit in April.  

 

— James

Link to comment
Do you want a TCP actor to talk to external non-LabVIEW code?

 

 

— James

 

Yes, that is correct.  I have written so many TCP servers and Clients, its not funny and I'm tired of writing them.  So, A prebuilt Server or Client that I just drop on the diagram that Executes in parallel is awesome! And I'll just register the tcp message processing actor with the client.  or for a server, the UI or processor simply sends a message to the TCP server actor. 

 

 

Usually there seems to be two ways that data is sent over a TCP to a client. one way is the TCP string is appended with the size of the string, and the other is no size information with the TCP string, the loop simply waits for data and timeouts if no data.

 

so basically how it would work is one section of the actor will listen for connections/disconnects, and the other loop processes messages.  really very similar to your TCP messaging framework that you've written.  I will work on creating this drop in TCP server/client, i'll post it when im done... might be a little while though.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.