-
Posts
1,973 -
Joined
-
Last visited
-
Days Won
178
Content Type
Profiles
Forums
Downloads
Gallery
Everything posted by drjdpowell
-
Could be worse, look at a project of mine from a few years ago before I learned anything about architecture (the labels you can read are in 106pt font!!!): -- James PS: One thing you need to attend to, though, is your wire routing. You have many places were your wires go under other structures in very confusing ways (I think one wire is running backwards under another wire!). Learn to use the "Clean Up Wire" Menu option.
-
I'm afraid I'm not getting much further. I can upload text into the binary container (though not download it) with ODBC, but trying to upload binary (ADO datatype adBinary or adLongVarBinary) returns "Invalid type". I'm using the Database Toolkit. The admin who runs the Filemaker hasn't been able to do it with ODBC (non-LabVIEW) but he has uploaded binary with JDBC.
-
Here's an image of a recent large (for me at least) project: This is the top level of the program, which is a "Database Viewer" for displaying several different types of measurement records in a database. It is based on a free template available from JKI, a form of something known as a "Queued State Machine" or QSM (though Queued Operation Machine would be a more apt name). In a QSM, a large program is organized into various frames of the outer case structure, with some queuing mechanism for calling the frames in order, and some kind of memory for organizing data available to all frames. Google "JKI state machine" for more info. Not so obvious, but seen in the image is another technique: clustering closely-related information on one wire and having a set of subVI's that act on that wire. This allows the top-level diagram to be much clearer and simpler. The best way to do this is with LVOOP "Classes", though one can instead use type-def clusters. In the image you can see the use of a "Record" class, and most of the complexity of the program is hidden in that class's subVI's. -- James
-
I've tried adding a dynamically-dispatched method called something like "Text Description" to my classes, which outputs a human-readable summary of the object data. "Text Description" in child classes call their parent's "Text Description" and add-to or modify it, building it up (possibly through several levels of inheritance). Then this method can be used in a single probe that works on all child classes. There are some probes of mine in this image from another conversation: The probes themselves only work with Text. It works well if each level of the class hierarchy isn't too complicated, and can be meaningfully summarized in a few words. -- James
-
LapDog Messaging Library v2 Beta 1 is available!
drjdpowell replied to Daklu's topic in Announcements
I guess one of my problems is that my own messaging design has too many polymorphic VIs to add to. In the quest to make the wiring simple I have polymorphic VIs for Write(create), Extract(get), Send, Reply, Query, and Notify Observers. So using the inbuilt polymorphism of the variant-to-data primitive is attractive. For example, here's a quick rewrite of the lower receiving loop in my previous example, where the "Sett>>..." messages set the internal data values of a cluster in a shift register (a form I use a lot): To extend this to accepting Set>>Temperature messages, I just need to duplicate the frame and select the right element of the shift-register data cluster. I don't need to change the message type. Or alternately I could use the OpenG Variant tools and write one case to handle all "Set>>..." messages: The "Set>>" subVI: Now I can add new "settable" items to the shift-reg cluster (and drop corresponding controls in the UI) without any new wiring to do. -- James Opps: just noticed I left the "Get Var" subVI with the original "Get LVObj" icon; hope that isn't confusing. -
LapDog Messaging Library v2 Beta 1 is available!
drjdpowell replied to Daklu's topic in Announcements
I see the great value in using custom message objects instead of custom cluster typedefs (particularly if you use the "command pattern" and dynamically dispatch off the message), but I'm talking about using variants for standard LabVIEW datatypes. From my (more limited) programming experience, I more often use variants to write "generic" code that handles multiple simple datatypes, not large typedef clusters. Now, a large number of simple-type classes (combined with large polymorphic VIs as Steve mentions) will perhaps do everything Variants do, BUT, isn't this reinventing the wheel? Variants have a lot of nice features and are pre-existing, supported by NI, and have lots of utility code written in them already (love the OpenG stuff). Using Variants lets one interface more cleanly with LabVIEW features that already use variants to represent simple data types. For example, here's a simple code for a test UI, where all front-panel controls are connected to a message queue such that all "Value Change" events on any control are sent out as "Set>>{control name}" messages in a VarMessage: Here, I'm directly connecting to LabVIEW's ability to handle multiple control types in a single event frame, via variants. If I want to add a control, I just drop it on the front panel and give it the right name and it's done. Writing code to receive variant messages and update the appropriate control (by lookup of the control name) is only slightly more complicated. To do this UI without variants, I would have to stop and create new message types for the pressure and temperature unit DBLs (it's going to be a big polymorphic VI, Steve, once you get to all the different possible units!), then configure an event frame for each control. But again, isn't this reinventing the wheel? Your goal is to send data, and variants are designed to send data. I like things to be as "easy as hooking up a...wire". I imagine one could design a "SimpleTypeVarMessage" that would produce an error if one connected a cluster to it; that might address your dependency issues. Custom messages I see the advantages of, but that seems a lot of work. Also, isn't the use of custom messages a "dependency" in an of itself? I haven't worked with them enough to know, but it seems like custom messages to talk to a module is a dependancy. But variants ARE a pre-LVOOP solution to the problem of a wire carrying multiple datatypes. Wrapping that solution in a message class is a lot easier than reinventing it. -- James -
LapDog Messaging Library v2 Beta 1 is available!
drjdpowell replied to Daklu's topic in Announcements
Question: Why don't you have a "VariantMessage" Type? You have an I32Message, and one could extend that with U32Message, I16Message, DBLMessage, etc. etc. etc., but that's a lot of message types! Is there a reason not to use a single VariantMessage Type to send all simple data messages, rather than a long list of native types? I ask because I've been experimenting with my own (similar to LapDog) message design, and there seems to me to be a lot to be said for using VariantMessages. -- James -
I'm currently trying to upload binary data from LabVIEW into a Filemaker 11 Container field via ODBC and I'm getting nowhere. I wondered if you were able to do this? I can upload non-binary fields fine.
-
The other two methods aren't precise enough to see the <0.5ms variation in times. The ms timer can only time to the millisecond, and the datetime is even less accurate.
-
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
-
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.
-
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.
-
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
-
Self-addressed stamped envelopes
drjdpowell replied to drjdpowell's topic in Application Design & Architecture
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 -
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
-
[Article]What are you working on today?
drjdpowell replied to Aristos Queue's topic in LabVIEW General
This post has been promoted to an article -
I need to get around to upgrading; I can't seem to do this in 8.6 either
-
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
-
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
-
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
-
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
-
Message Routing Architecture
drjdpowell replied to Mark Balla's topic in Application Design & Architecture
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 -
You should be able to us a 5V input SSR. Something like this Cyrdom CN024D05.
-
Why this to more specific Class does not work?
drjdpowell replied to V_T_S's topic in Object-Oriented Programming
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 -
Message Routing Architecture
drjdpowell replied to Mark Balla's topic in Application Design & Architecture
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