Jump to content

drjdpowell

Members
  • Posts

    1,964
  • Joined

  • Last visited

  • Days Won

    171

Everything posted by drjdpowell

  1. Actually, I just came across an example of exactly this use, in an "LVOOP Event Handler" by Francois Normandin: http://lavag.org/top...dpost__p__79074 (you can see "Preserve Run-Time Class" being used in the image) He uses it slightly differently, to allow the publisher to specify who can subscribe to an event, while I intend to use it to allow the subscriber to specify what events they are interested, but it's basically the same. -- James
  2. If anyone is following this, here's some images from one of my first projects using (and continuing to develop) this Active Object design. Its an active object that runs an Ocean Optics USB2000 spectrometer. There are actually 6 "Parallel Process" style objects involved: "USB2000" itself, a subprocess object ("USB2000sub") that synchronously communicates over USB to the spectrometer, two clones of the simple testing UI (two to make sure changes on one reflect in the other), and two different types of message loggers (one for errors and one to monitor all communication by "USB2000"). "USB2000" and "USB2000sub" together publish events and state information via it's Observer Register, to which the UIs and loggers subscribe. There is a mix of Queue and User-Event communication here, with "USB2000sub" and the error logger being based on the queue-messenger template I showed in the initial post, while the other active objects use User Events. "USB2000" itself is based on an adapted JKI-QSM template. Here's a shot of the "State Logger", which displays the last received message of each label, organized by what VI sent it (here it's showing "USB2000sub"): There is now two different types of published messages, "Event" and "State". The difference is that the Register keeps a copy of the last inputed "State"-type message, allowing it to immediately inform newly registering observers of the current state information.
  3. I ended up leaving this feature on the to-do-list awaiting an upgrade, and just hard-wired in the ability to register for all children of "ErrorMessage", that being the only use case I need at the moment. I'm also considering adding the ability for the publishing process to organize groups of messages into "topics", with subscribing processes registering for topics of interest. This would obviate the need for registering message classes.
  4. It is? What I have is an "Observer Registry" (mentioned in my "Parallel Process" topic) that deals with "Message" objects published by one process, to which other processes can register for. I would like the other processes to be able to specify what specific types of messages they would like to be notified of. For example, Process A may be interested in all "CommandMessages", a child class of Message, and any children of CommandMessage. This could be done by Process A passing a default CommandMessage object to the Observer Register, and then having the Register check every Message published to see if it is a child of CommandMessage. The Register would then be dealing with two children of Message (on Message-type wires) and needs to see if one is the child of the other. -- James
  5. An update: As I've had the chance to improve the API for my "ObserverSet" Class, here is the more complex example from above (the one where the Metronome object is used to instruct Process A to periodically send it's time string to Process B) redone with improvements that hopefully make it clearer. Included are some custom probes to see what the Observers and Messages look like. Observers (aka ObserverSets) serve as containers of any number of Messengers (or Active Objects), where sending a message to the Observer sends it to all the contained Messengers/AOs. In addition, an Observer can be set up to automatically alter ("translate") the messages sent by it: in the example they are used to relabel a message, add prefixes, and substitute one message for another. ObserverSets are internally recursive to allow multiple levels of translation. Observers have the additional features of never throwing errors into the process using them to send (the Messenger throwing the error is just dropped internally), and never allowing the process using them to access the contained Messengers/AOs other than to send to them. -- James
  6. It indicates that control has a default value saved that is different than the usual default value for that class (i.e. someone probably choose "Make Current Values Default" after running the VI). The changed default value might be causing your issue. -- James
  7. I need to get around to upgrading; I can't seem to do this in 8.6 either
  8. Found what I need: the "Preserve Run-Time Class" function. Unfortunately this isn't in the LabVIEW 8.6 that I'm mainly using. -- James
  9. It's because I don't know either child at runtime; I only have parent-type wires. The "To More Specific Class" function only uses the type of the wire, not the actual object on the wire at runtime. See below: I could do what I want if I could programmatically get a list of an objects ancestors; does anyone know how to do that? -- James
  10. Doesn't work, because those functions use one of the inputs just for the wire type (which has to be the Parent), ignoring the specific child on the wire. -- James
  11. I'm probably missing something obvious but I can't seem to do the following: Imagine I have a class tree with parent, children, grandchildren, etc. How do I take two objects in on parent wires and tell if one object is a child of the other? So for example, if Parent P has Children A and B, with grandchildren A1 and A2 of A, and B1 and B2 of B, I want a subVI (with two "P" inputs) that if comparing A and A1 returns "true", but if passed a B and A1 returns false. -- James
  12. Have you considered adding some kind of optional local scoping to your framework? Sort of a "local router subnet". If you had the option of specifying a local scope when registering to send or receive a specific message (such as string like "UI subnet") you could easily set up an arbitrary number of Waveform Generators under different scopes, communicating independently with different modules, without needing to extend the code of any module. Local scoping could also increase the flexibility of your framework, allowing more hierarchal "module-submodule" relationships in addition to stand-alone modules. -- James
  13. You should be able to us a 5V input SSR. Something like this Cyrdom CN024D05.
  14. The "To More ____ Class" functions don't actually change the class of the object (so, as you created a Child object, you got the child's "multiply" function by dynamic dispatch). They actually just change the type of the wire. A Child object flowing on a Parent wire is still a Child object. I've found this very confusing myself. -- James
  15. Question: what if I wanted two or more of the same module. Say, I wanted to make your "Waveform Module" reentrant and use it in two different ways in my application, with the "UI Module" interacting with Waveform Module A, and, let's say, "Simulated Temperature Readings" (STR) Module interacting with Waveform Module B. Is there a way to direct the messages to only the correct module (UI to/from A and STR to/from B)? If not, I would not be able to operate A and B independently, as they both act on start/stop messages from either of the other two modules. -- James
  16. Having just watched Mike's video it seems he is mostly using asynchronous messaging (via a User Event in his example Active Object). He is using a DVR to allow some of his API methods to modify the active object's private data, and those are synchronous (but fast). My (perhaps mistaken) impression of the differences of Mike's Active Object to mine are: 1) He uses a specific reply channel for all responses from the AO (a queue in his “Send Message To Process” Method Template), while I use multiple reply channels, provided with the incoming messages themselves or "registered" as an Observer. This means (correct me if I'm wrong) that VIs based on the “Send Message To Process” template would not work properly if multiple were called simultaneously in parallel, as there is no mechanism to route the separate replies to the correct VI. 2) He uses bare User events and queues, while I wrap all communication as "Messengers". This will hopefully allow me to substitute network communication when I get the chance to develop it, without needing to modify my active objects internally. I've been following the philosophy that the active objects should know the bare minimum about the specify communication channels they are using. My example AO given in the first post, for example, only knows that it is using a "Receive-type" incoming messenger (which could easily be TCP-based instead of queue-based), and knows nothing at all about it's outgoing communication (which could be queues, TCP, shared variables, notifiers, etc., and can be several processes instead of just one). 3) His active objects are interfaced with by an associated API, while I build messages to send to mine via the generic API of the parent "Send" class. This is a minor difference as he could just use his “Send Message To Process” Template, unmodified, to send messages, and I could easily create wrapper API VIs. I'm not sure which is a better way to do things. -- James
  17. I made the same design choice in my own version of object messaging. Though I'm also not sure if there isn't a problem with this way of doing things. One possible advantage of having a VI take the parent class is that you have the option of handling more than one message type. For example, the VI to get a String might work for both a String message type and a Variant message type, where the variant contains a string. -- James
  18. The alternative communication channel is done: an easy-to-use "Observer Registry" as illustrated in my active object design. Also, although my active object template is a simple queued message handler, one can use more complex designs like a producer-consumer, where the producer loop monitors the input queue and a "Sequencer" consumer does the synchronous calls to the spectrometer and sample handler. Then if the producer were to receive an "Abort" message, say, from the UI it could send "abort" to the spectrometer and sample handler, which would then error-out the synchronous call from the Sequencer. Admittedly, the need to keep the synchronous stuff away from the input queue receiver does illustrate your and mje's point about being careful with synchronous calls. -- James (off on vacation and internetless for the next week)
  19. Following on the "Self-addressed Stamped Envelopes" topic, I'd like to present a design of an Active Object using my messaging library. This template has the ability to both "reply" to messages and to allow "observers" to register for event updates. I haven't used this template yet (just wrote the observer-registration part yesterday) and I would appreciate any feedback before I use it in a real-world project (which I'll be doing after a weeks vacation). The example object, "PP Template" does the following: Responds to "Current Time?" with a text string of the current time. Sets the format string for the time by the command "SetTimeFormat" Starts generating "TimeUpdate" messages periodically on the period given in the command "AutoGenerateTime" Allows external processes to register as observers of the following events: "SetTimeFormat" received "Current Time" issued "TimeUpdate" issued "Macro: Exit" received (this is the shutdown command for the active object) All error messages Here is how a higher-level VI might create ("launch") and communicate with "PP Template": In this example we launch "PP Template", register a Message Logger (another active object) as observer of all published events, send a nonsense message "Blah Blah" just to demonstrate error handling, set the time format, and query "Current Time?" first synchronously(*), then asynchronously with the message reply going to the "Asynchronous Receiver" loop. Then we register "Asynchronous Receiver" as an observer of TimeUpdate events (and set the autogenerate time of these events). On pushing the "stop" button, "PP Template" is sent a "Macro: Exit" command to shut down. Here's what the Message Logger receives when we run this VI: And here is the VI dynamically launched VI at the heart of the active object. It's basically a message handler with eight cases; three of the cases handle the three commands, then there is a timeout case, an error handling case, a shutdown case, an "ignore null messages" case (not shown), and a default case to catch unhandled commands (and spelling errors). The way receiver timeout and errors feed into the message case structure is stolen from Daklu's Lapdog messaging library. Some details of communication with the active object: 1) The object is launched by dynamically calling the PP Template.vi, setting it's "Startup Message" control via a VI Server call, and then doing some handshaking messages between "Launch.vi" and the "Startup" and "Acknowledge Startup" VI's. This creates the incoming command messenger for the process (in this case it is a queue based messenger, but there is an alternate "Startup" VI for a User-Event-based messenger). Calling a "Send" or "Query" method on the active object calls the same method on the command messenger. There are two startup modes: when started as an "autoshutdown slave", the messenger is created inside the Launch.vi, which means that if the main VI goes idle, the queue reference will become invalid, which triggers a "MSRReceiverError" that shuts down the launched VI ("Message Logger" in the above example shuts down in this way). The other way creates the Messenger inside the "Startup" VI, making the active object independant of the Launching process. 2) Observer registration is handled by an "ObsReg" by-ref object, with two methods: "Registration", which filters out and acts on registration commands, maintaining a list of all observers for each event message (and sets for all events and all error events), and "Notify Observers", which accepts messages and sends them to all observers registered for them. Thus, it is extremely easy to publish new event types; just package a message for the event and pass it to "Notify Observers". 3) Reply-based communication involves a "return address" (a messenger or other active object reference) to be attached to the message, and the active object using a "Reply" VI to respond (in synchronous communication, the "Query" VI creates a single-use response queue to receive the reply). For error handling, the Reply VI will package any error in it's error terminal as an error message and send this to the return address (this is in addition to an observers being notified of the error). -- James (*) Please note the potential problems of synchronous communication brought up by mje.
  20. Synchronous ONLY is perhaps not a good idea, but synchronous messaging is good for synchronizing things. As an example, suppose I had a spectrometer and a sample handler for deploying samples to be measured. I might want to deploy a calibration sample, THEN calibrate the spectrometer, THEN deploy a sample to be measured, and THEN measure the spectrum of the sample. This would be trivially easy to do with four synchronous queries chained together by their error terminals. If either spectrometer or sample handler had a problem it would return an error message as its reply (such error appear on the error-out terminal of the Query VI). Of course, if either component needs to signal something immediately there needs to be a dedicated channel. In which case, neither my synchronous nor asynchronous "reply" examples work, since in both cases the communication channel is a part of the received message. I've been developing a third communication mode as part of a "Active Object" template: registering for event updates (the OOP "Observer Pattern") that would work for this. All three modes should be useful and can be used on the same active object. -- James
  21. For completeness, here a simple example of an asynchronous query, where the controller has its own incoming messenger, which it attaches to its outgoing message to Process A, allowing it to receive the reply asynchronously: This example also shows a User-Event-based Messenger. -- James
  22. I agree, and I've been trying to design my messaging system in that way, so that one can use it for simple things without having to understand everything that might be done with it. My original design goal was to be able to have processes that send messages without having to know whether the messages are being sent by queue, or notifier, or user event, or UDP or TCP. And for processes that receive messages to be able to transparently use network communication (TCP etc.) in place of local communication. That makes things simpler, not more complicated. And my initial goal for the Parallel Processes is to have a simple template for creating "speak-only-when-spoken-to" simple active objects that can be "queried" by higher-level processes. Thus the synchronous, command-reply communication (shown below with text-varient messages) was the first thing I developed (which lead to the idea of having each message carry it's own reply method): I find this synchronous communication to be more clear and simple to use than asynchronous. I probably shouldn't have first introduced my messaging design with the complex example of my first post, as one would start out (and perhaps end) with much simpler uses. Getting back to the more complex example of my first post, although the messaging is direct from A to B, all the routing and slave interactions are setup by the main VI. In my system, one can look at the creator of the process to see who is passed the wire representing the ability to communicate with that process (hopefully, there are only a limited number of such potential message senders). And I'm hoping my "Message Logger" can be developed into a useful debugging tool. Below, I've modified the Logger to add some tracing information (the call chain of the process sending the message and the message timestamp). -- James
  23. Yes, I nearly titled this conversation "Yet another messaging system". Looking at your "MessagePump" loop, I can see the great similarity, just with different terminology. My "MSG" message class contains a label (your "message identifier") and a "Send" object (your "Callback"); children of MSG add "Data" (your "parameters") of various kinds (the example I gave used a text-data message). "Send" is a virtual class, who's central method, "Send.vi", does nothing, but it's various children override Send.vi with different communication methods or other functionality. So far, I have Queue and User-Event "Messengers" (hopefully to be extended in future to a network-enabled TCP messenger); "Parallel Process", an active-object design that uses the messengers for communication; and "ObserverSet", an extension of Send intended for allowing multiple processes to receive ("observe") the same message. Here's an extension of my first example, where I've added a Message Logger (Parallel Process) that "observes" the messages to both processes A and B: Note that I made no changes to A, B or the Controller Loop; none of these processes are aware of the existence of the Message Logger. I've been experimenting with what kind of interesting functionality I can build into the Messaging system itself, while using only quite simple processes to message between. Here's a further modification of to example where I replace the "Controller" Loop with a "Metronome" parallel process that sends "MetronomeTick" messages periodically to the ObserverSet registered with it. I've used the ability of Observers to substitute an alternate message to have Metronome send the "SendTimeString" message to process A. Note that A, B and Metronome know practically nothing about each other. They don't use any compatible message labels and they don't know what underlying communication method they are using. Metronome needs to "send" updates to its ObserverSet, but doesn't know anything about the number or nature of observers, or that it's messages are being rewritten. I had originally started writing a parallel process that maintained arrays of registered observers, with arrays of alternate message labels, but realized that all this functionality could be built into a extension of the "Send" messaging class, and thus added for free to any (much simpler) process that can register one "Send" object for updates. In a hierarchal master-slave tree structure, like Daklu suggested, there is less potential for circular dependancies, as any synchronous messaging would always be from master to slave. And, of course, one needs a timeout error; here's my synchronous "query": -- James
  24. Hello,The recent posts about "Message Routing" has inspired me to mention a variation on this idea. In particular, I am thinking of Daklu's description of his "Slave Loops" that only communicate with their masters (requiring the master to "mediate" communication between slaves), and Mark Balla's Message Routing Architecture. I have been working on my own LVOOP Messaging system, one in which there aren't specified "output" channels; instead, each message can contain the method to rely or respond to it. Sort of a self-addressed, stamped envelope. This allows one to build a "hierarchical tree of master/slave loops" as Daklu suggests, but with the ability to direct messages to thier final recipient without mediation. A simple example: In this example, the Controller (master) sends a message to Process A (label="SendTimeString") with the attached reply address (command queue) of Process B, along with an alternate label, "CurrentTime", to be used for the reply message. Thus, Process A directly sends a message to Process B, with no mediating or routing processes in between, yet without either process knowing anything at all about each other (they don'y even use the same message labels). The Controller sets up the communication link between A and B, but doesn't itself need to handle the message. One can extend this into an "Observer pattern", where the Controller registers Process B as an observer of Process A's regularly occurring "TimeString" events, (complete with message relabeling to "CurrentTime"), again with neither A nor B having to know anything about each other. -- James
×
×
  • Create New...

Important Information

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