-
Posts
1,973 -
Joined
-
Last visited
-
Days Won
178
Content Type
Profiles
Forums
Downloads
Gallery
Everything posted by drjdpowell
-
This made me think of this past conversation of yours as an example of where having an extra type-checking primitive would be useful. Though, I see Daklu already made the same points in that conversation. You may have reason not to like a check for exact equivalence, but clearly people do have reason for some types of checks. And, remember this conversation? People have been using the object primitives that are available to substitute for operations that aren’t, and this leads to overly complex and unclear code.
-
That’s my point. The “zero iteration loop” is producing results that depend on intricacies of the complier, which are not intuitive extensions of G. I agree with MJE in expecting my example to output the default object of the wire type, but we’re both wrong. Since as AQ said, the default behavior is to return the default object *as if the loop had iterated once* he would I guess expect the “Error Report Message” (the thing returned if the loop iterated once) but he’d be wrong also. The actual answer is “Temp Update Message”, an object would never be produced by the loop on any iteration.
-
Not a trick. Just seeing if anyone can read code based on this. Sometimes it is important to understand the esoterics of what the compiler is doing, in order to work with it in producing the most optimized code. But this is really esoteric, for something that seems like it should be trivial. From looking at the below image from NI.com I would naively say that determining if two objects are the same class should be trivially easy and blindingly fast on RT or desktop systems because we just compare the two type pointers. Why is there no primitive to do this? P.S. Anyone else care to guess what object comes out of the zero-iteration loop?
-
Couldn’t we have a few nice primitives for determining class relationships, so I don’t have to learn this weird compiler voodoo? Quick quiz: what class of object results from the code below?
-
If you’ll forgive me… Why does that work?!? With no loop iterations the code can’t pass the objects across and must output default values. OK, but the default value of a LabVIEW Object wire is a LabVIEW Object; how does the child class identity get passed across the void when the actual child-class objects do not? That doesn’t seem right at all. Another issue: aren’t all these object manipulating techniques rather obtuse code? Sort of LabVIEW alchemy? The uninitiated will be mystified as to why we are “preserving run-time class” or finding the path to a class in order to tell if A and B are the same type, let alone understand a zero-iteration loop. — James
-
MVC through class control - feedback required
drjdpowell replied to 0_o's topic in Application Design & Architecture
Uploading a few pictures would be helpful, such as a a screenshot of the old code and of one of your new accessors (complete with property-node update of the front panel). Otherwise I only have a vague impression of what your dealing with, though the technical term for your old code is "Big Ball of Mud". I worry that in attempting to tame the BBoM, your in danger of just adding a new layer of mud. On the other hand, you might successfully end up in a situation where new code can have much improved architecture, interfacing to the BBoM only through your "db" object. Some thoughts: 1) the biggest speed issue is your property nodes, which are inherently slow. Don't put property nodes inside your In-Place-Element structures as other IPEs will be blocked while the property node is executing. 2) (1) is not a huge issue, as once you successfully weave "db" though the BBoM you can immediately go further is separating the UI from the logic by eliminating the direct update of FP controls from db's methods, and instead have a separate "UI loop" that periodically queries db and updates the UI. For example, if part of the code updates a state variable 1000 times a second, that would cause 1000 property-node updates/sec (which is a problem), but the UI loop could query db and update the control terminal directly 5 times per second. 3) at step (2), you can take the time to modernize your UI, since it is no longer tied one-to-one with program state variables. You could use all sorts of clever ways to present information. This could be a major improvement that you can show to your boss as payoff for your code upgrade. 4) You might have a speed issue with the DVR access (as only one IPE structure can act at any one time). I believe DVRs are very, very fast, but you are going to use it a very, very large number of times a second. And every access locks up every state variable. You could consider an alternate structure for "db": instead of a DVR of "db" that holds all the state variables, have db hold a set of DVRs of clusters of related state variables (i.e., all the "Camera" variables would be in one DVR). Then, any method of db only has to lock up the part of the state data that it is dealing with, and unrelated methods can operate in parallel. Even better would be if you could separate db into several objects corresponding to subsystems, but as you say the BBoM may not allow that. -- James No, only the 32/64-bit DVR reference will ever be copied. Way faster than either; it's a memory access, faster than any file access. ??? What's an "esf"? The issue with the DVR is that only one thing can access it at once, so you can't do anything slow inside an IPE structure without blocking other code. That requirement can conflict with the need to prevent race conditions by doing things inside the IPE. An issue you have is that you are putting the entire program's state variables in one DVR, so unrelated parts of the code will block each other without reason. -
MVC through class control - feedback required
drjdpowell replied to 0_o's topic in Application Design & Architecture
Is the old code really that badly designed? Any reasonable code should have some level of separation between components; OO Classes just allow that separation to be more complete and clear. I'm just suggesting what is mostly a cut-and-paste job: identify the variables related to the camera, drag-copy them into a "Camera" class control; find a bit of code that initializes the camera, cut and paste it into an "Init" method. Don't redesign the details, just get the applications components cleanly separated, so that in future you can do things like use a different type of camera, or test the camera separately, or improve the camera code without introducing bugs in unrelated components. To use some jargon, what I'm talking about is "Abstraction Layers". -- James -
MVC through class control - feedback required
drjdpowell replied to 0_o's topic in Application Design & Architecture
Your initial post is a bit of a scattergun blast of concepts, patterns and acronyms, which, though all somewhat familiar to me, are not directly translatable into specific LabVIEW code in my head. And you didn't include any pictures! That, combined with the holidays, is why your not getting any responses. Anyway, I'll give it a go. The image I'm getting is of a past LabVIEW application written with the Front-Panel controls/indicators serving as the data-space ("state", "model") of the system. Perhaps with lots of local variables and Value property nodes. Your trying to partially automate the conversion of the data-space into a single "Model" object that maps onto the existing controls/indicators (there being dozens and dozens of such). Personally, this is not how I would approach such a old program. I would instead look at how to upgrade the program part-by-part, bottom up, looking for natural encapsulation. For example, if the application uses a Camera, say, I would try and replace all the variables related to the camera with a single "Camera" class. I would try to get as much of the logic related to the camera in method VIs of the Camera class, and try to limit the number of actual "accessors" to the internal Camera data. When the "Camera" upgrade is working, I would look for some other subsystem that can be encapsulated in a class. This should slowly, step-by-step, lead to a simplification of the top-level program logic until the point that I could consider a rewrite of the application as a whole. This might contain a "Model" object, but it would itself be made up of a small number of component objects like "Camera", rather than be a huge sprawling "everything from the old program including the kitchen sink". -- James -
Techniques for componentizing code
drjdpowell replied to Daklu's topic in Object-Oriented Programming
FYI from a couple of months later: I have now made use of "outer envelopes". They were very useful in the writing of TCP Messengers for my message-sending reuse framework, allowing the sent messages to be packaged inside outer envelopes carrying labels that mean something to the "Client" and "Connection" actors that run the TCP communication. Using the outer envelope label obviated the need for any parsing or inspecting of a message to determine what to do with it, and led to clearer code. For example, the "Client" receives envelopes labelled "Send Via TCP", while replies to messages, to be routed back through the TCP connection, are received by the "Connection" actor in envelopes labelled "Route Back Message". Note: all use of these outer envelopes is internal to the TCP messaging structure, and are completely transparent to the processes at each end of the connection, which do not need to do any marking of messages themselves. -- James Part of "TCP Client Actor" where messages to be sent through TCP are received inside "outer envelopes" marked "Send Via TCP" (the marking is done by the "RemoteTCPMessenger" class to which the messages are initially "sent"). -
Regarding the initial post: John, you don't have to worry about the robustness of using an uninitiallized shift register. Even if this use of a USR was not originally foreseen, it has been a common method of LabVIEW programing for many years, as are other design patterns using shift registers. However, you should carefully consider what Norm said about the possibility of eventually needing more than one copy of the thing you program as a functional global. -- James
-
Can you get your hands on one example unit now? Learn the tuning procedure manually and then you might be able to code a simple step-by-step procedure (tune V1 until X is true, tune V2 until Y is minimized, etc.).
-
Line Graph in LabVIEW with Repeating X Values
drjdpowell replied to JohnLV's topic in LabVIEW General
What is your question? If it is the line drawn back from (10 8) back to (0 7) that you don't want, then adding an extra point with a Y value of "NaN" (Not a Number) between them will eliminate the line.- 4 replies
-
- line graph
- repeating x values
-
(and 1 more)
Tagged with:
-
By coincidence I'm working on a similar thing right now: Message objects via TCP. Like you, I've mostly done two VIs on the same machine (except for one brief proof-of-principle test between England and California which worked fine). The one issue I can add is the rather large size of flattened objects, especially objects that contain other objects (which might contain even more objects). Sending a simple "Hello World" as one of my Message objects flattens to an embarrassing 75 bytes, while the "SendTimeString" message in my linked post (which has a complex 7-object reply address) flattens to 547 bytes! I've just started using the ZLIB string compression (OpenG ZIP Tools) and that seems to be a help with the larger objects (compresses the 547 bytes down to 199). I've also made a custom flattening of the more common objects to get the size down ("Hello World" becomes 17 bytes). -- James
-
LVClasses in LVLibs: how to organize things
drjdpowell replied to drjdpowell's topic in Object-Oriented Programming
Well, I can't say that was fun, but I've managed get my code in such a way that only required parts of it will load. I found that I had a few VIs here and there that existed to help use diverse classes together. I had placed these helper VIs inside one of the classes involved; because of this they served as linkers that caused all the classes to load when the first one did, even if that VI and those other classes were never used. Just dropping an instance of my parent class loaded 75% the entire toolkit! Tracking these Vis down and getting them out of the classes broke the cross links. I found a use for a few LVLib libraries to hold collections of these VIs and others that didn't need to be in their related classes (and didn't always need to be loaded with the class). -
Memory and Variant Attributes as a Lookup Table
drjdpowell replied to drjdpowell's topic in LabVIEW General
Kudoed. I was going to make the same suggestion if you hadn't already. Don't see why it wouldn't work with objects, though. My array is relatively static (rare additions, no deletions), but perhaps I'll live with the copies for now, until I get to the point that I can do comparative testing. -
Memory and Variant Attributes as a Lookup Table
drjdpowell replied to drjdpowell's topic in LabVIEW General
Thanks, I was worried that copies are made. I was considering storing an index to an array and Tim suggests, but I might wait till I upgrade (still on 8.6) and go with the DVR as the code would be simpler. -
Hello, I've been using the feature of Variant Attributes to store and lookup values in an efficient way. In particular, I've been storing complex objects such as the (simplified) example below where I post messages to "Observers" of those messages. My question is: is this the most efficient way to do this? In particular, I select one attribute, modify it, and then return it to the variant: does this involve copying the entire cluster of objects, or does the LabVIEW compiler identify this as an operation that can be done "in place"? -- James
-
LVClasses in LVLibs: how to organize things
drjdpowell replied to drjdpowell's topic in Object-Oriented Programming
Thanks everyone, I think I'm slowly getting a better feel for how to structure things. Mostly by keeping classes out of LVLibraries, but identifying small groups that need to be closely tied together. I actually have a small section of my messaging code that uses Command-Pattern messages; if I don't put them in a Library I could accidentally build an exe that wouldn't contain its own commands! I might retain a library for the core classes that will always be needed; though the boundary of such a core isn't very distinct, so perhaps not. I also like Paul's idea of a set of classes as one template. I don't (yet) have any such groupings, but I'm toying with the idea of a Command-Pattern-style Actor Template (ripping off inspired by the Actor Framework) and that would involve a template of multiple classes. Part of what motivated my question is that I am currently in the middle of trying to adapt my messaging system, up to this point working only within a single Application instance, to work via TCP between different App instances or over the network. Thus, I've had to consider the issue of different instances having limited subsets of the messaging package (particularly if one instance is on a memory-limited Real Time system). A whole new dimension to worry over... Thanks again, -- James -
LVClasses in LVLibs: how to organize things
drjdpowell posted a topic in Object-Oriented Programming
I have a largish set of reuse code for inter-process messaging that I've been using in all my new projects. But I realize that I haven't really thought about how to organize things in Libraries. Given the difficulty in reorganizing libraries once they are referenced by many different projects, I'd like to get a good organization decided now. Currently, I have one large library with many classes in it, but that leads to any project using any part of the library loading every single class in it (and lots of VIs), even if individual projects only use a small subset of the classes. Classes that aren't in the library only load if needed, which seem a better feature. This makes me wonder if I shouldn't keep Classes in Libraries at all, unless they are very closely connected such that they will always be used together. What do other people do in organizing with Classes and Libraries? -- James -
Self-addressed stamped envelopes
drjdpowell replied to drjdpowell's topic in Application Design & Architecture
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: 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. 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. 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 -
Wait, wait, wait.. I thought the dialog was a simple while loop with two buttons; where'd this event structure come from? If you have an event structure in a dialog you have to be careful to clear any leftover events, otherwise those extra key presses or clicks will be queued up and ready to go the next time the dialog runs. I think the only way to go is to dynamically register for any events you want, and unregister as you exit the dialog. Re-registering on the next call to the dialog will ensure there are no leftover events from last time. Never use statically-registered events in a dialog, as they can't be cleared.
-
I found this conversation which illustrates that event registrations seem to behave strangely and not like other refnum objects as I understand them. Something is going on under the LabVIEW hood that might be affected be a subVI, and perhaps I would be better to restrict event registrations to the same block diagram as their corresponding event structure
-
I learned that through painful experience. But I don't understand the relation to subVI's. I understand that if the subVI returns a previously created and saved reference, then it will be the same each time. But if the subVI creates a new event registration, then it should be different each time. And both these are independent of the subVI being "inlined". Here is an example. Since I did this two days ago, and it is the first time I've put an event reg in a subVI, it is an important case for me! Is there something I should be worried about with this code? It's my understanding that this subVI should always create a new event registration for each call. -- James
-
Just a small suggestion, but you could place your code in the TRUE case of case structure connected to the "NewVal" output of the event case. That would drop any double clicks by the user (as the second would be false). Can't help with the dialogs; though the primitive 2-button can be OKed with the Enter key, your second one has no key bindings and thus should require a very deliberate User action to dismiss. How do you know the event happened, BTW? Are you sure the action contained isn't being triggered by some other method than the event case? -- James