Jump to content

PaulL

Members
  • Posts

    544
  • Joined

  • Last visited

  • Days Won

    17

Everything posted by PaulL

  1. Well, there are times when we want to see an event when the variable has a new instance of the same value. A simple example immediately comes to mind: Latched Boolean on View: The View sends a true value for this button each time the user clicks it. So, the user might click Start, do stuff, stop, and then click Start again. The Start shared variable has a value of True in both cases, but the controller needs to know the user clicked the button again. (There are other ways to do this but this is about the simplest we have found.) Similarly, we might have the same situation when we send a setpoint. The controller may use an old or default setpoint until it receives a new value, which perhaps only occurs upon user demand. It is entirely plausible that the user could send the same setpoint after starting the controller on two successive runs. We sometimes program publishers only to write certain data on first call or if the values have changed (it sounds like you did something similar). If you can only edit the subscribers, that won't help, of course, and you will have to do the filtering on the subscriber side, but currently that means after the event triggers. I think generally the given behavior of getting an event is correct, however. EDIT: OK, I just looked at what sachsm suggested. That could be what you are seeking. I admit I've never paid any attention to that option. I definitely learned another new thing today! Thanks!
  2. In keeping with the Model-View-Controller paradigm we separate the View from the Controller/Model, so our Model classes do not have references to the View elements. (Disclaimer: We do have at least one exception, but that is not important here.) The View communicates via the Observer Pattern (so that we can replace the View with another view or even a separate subsystem). In practice, we use network-published shared variables (generally) to handle the publish-subscribe communication (i.e., the Observer Pattern). In practice, the indicators on the view change behavior when the state of the system changes operational state, so in our view code we register for a shared variable value change event on the state shared variable. When this changes (i.e., the event fires) we update the appearance of the controls and indicators accordingly (either on the view diagram or delegated to subVIs, e.g., in a View or <ViewElement class>, as appropriate). Updating values on indicators we can usually accomplish simply by binding to the matching shared variables. (If we have to transform the data for display purposes we register for the appropriate value change event and then do the calculations when the event fires.) (More advanced comment: Note that you can actually put the behavior for a specific type of element into class methods and pass a reference for a specific view element to the object, hence arriving at a view that is truly a Composite of individual elements.) In the opposite direction, when a user clicks a button, this triggers a control value change event, and the code to handle the event sends the appropriate message to the Controller. The resulting Views only "care" about the data to send and receive and interact directly only with the shared variables (which makes them easy to test, even without the actual system in place).
  3. John, The way I would approach your task is to use the Command Pattern, including an object representing the Target as an attribute in the Command object I send as a message. Hence you could have a top-level Command class, and its private data could include a Context object. Subclass Command into the particular commands, and Context into the particular contexts. Then each loop gets all the messages (not quite what you asked) but only acts on those that apply. (An Invoker class can handle this.) Further, if your loops are really clones of one another (not sure if this is the case), you could actually use a single controller, and just have instance Model objects that contain the state of the particular instance. Then you have something really quite elegant. (All of this is very straightforward if you've done it once. It can be challenging otherwise. I can explain further if you're interested.) If each loop really must get a specific set of messages you can use point-to-point communications or, what I suggest, a publish-subscribe paradigm (e.g., with Networked Shared Variables, with one variable for each loop [Context]). My biggest concern (and it's not a big one) would be having multiple writers (6, in fact) on each channel. That's actually OK as long as the application won't get confused. Paul
  4. See these threads for a start: packed project libraries Libraries, Packed Libraries, Source Code Distributions, and the End of the Universe
  5. Lots of great ideas in this thread! I would recommend using project libraries, but be very careful if you want to use packed project libraries. I tried them when they came out last fall and regret that. They don't deliver on performance and they are a maintenance disaster since you can't replace them with a project library (currently one direction only), which you likely will need to do at some point. For us this was resulted in a very costly nightmare. Maybe packed project libraries will be good in a future version, but I think in LabVIEW 2010 they are best avoided. (On the other hand, if you want to help make them better by providing good feedback, that would be great.) Of course, I highly recommend using objects (and I agree with using by-value objects generally) and design patterns. Also, I think it is important to learn how to create and use simple interfaces, since this can make sections of the code separable, helps to demarcate the limits of their design, and (because you can greatly reduce links between classes) makes building applications more robust and faster. Good luck with the project! Paul
  6. I use search and replace, too. It is simple but it would be nice not to have to do this (so maybe I should use of the tools already mentioned, although I think it would be great if NI would incorporate such a feature into the LabVIEW core). Anyway, right now I do a text-based search and limit the search scope to the VIs in the target class. This works well.
  7. Thank you all for your replies. Yes, we are using RT on a cRIO. I think our application will be fine performance-wise since we only have one event structure (OK, most of the time) and I don't think we will ever have more than three events queued at any one time. On the other hand, if for some unforeseen reason the application started to run away, it would be good to be able to preempt the existing triggers with a stop trigger. I don't think this is possible with user events, so that is a strong point in favor of queues. So I will probably implement a queue version of what I am doing (which won't take long at all), but since the events seem to be capable of doing the job (and they are certainly working functionally fine so far) I won't need to make a queued version today. Thanks!
  8. I am writing an application where functionally I can use user events or queues to sen messages (triggers)O between threads. On the other hand, since this is a real-time application, if there is a significant difference in the CPU processor requirements between the two, I would definitely want to pick the more efficient method. I have implemented a solution using user events mostly because we use events elsewhere so the paradigm is more familiar. I am guessing that events add some small overhead versus queues, but is it much? Has anyone bench tested one versus the other? (I might need to do such a test myself, which is easy enough, but I thought someone might already have some results....) Paul
  9. I agree with mje seconding AQ. It would be nice to have something. Maybe the class designer can somehow make it private. I at least partially understand the security risk, though. (Don't probes have to have the same rules?) I'm sure there are lots of implications here I haven't yet pondered. I also would prefer something other than creating an XControl for each class, only because my impression is XControls are complex enough to make me think twice about going down that road (but to be fair I've never made a really serious effort to build one for any actual project) and, more importantly, because I can't make them part of a class so I can't extend them easily (or at least such is my perception, which may be not entirely correct). (I'm guessing I can put OO code inside an XControl so probably it is possible to extend parts. I am completely out of my element here, though. Hopefully someone else will help out here with a better analysis.) By the way, I've seen some super-cool XControls! I'm just not eager to have to create one for each class.
  10. I'm sure this has been discussed already (maybe as part of the XControls as default control for class) but anyway, LabVIEW provides a handy view into the contents of a class in the probe window (thanks, NI!). Is there any reasonable way to put this on the front panel of a VI? (I think the answer is no, unfortunately. I'm hoping somebody can explain why. It would be really helpful if I could do that.) Edit: (I know I can convert the flatten the class to a string and extract the name of the parent class and the actual class. Hmm... maybe I can take that further. Maybe that's kind of the answer. Well, I don't think I can everything the probe does, though.)
  11. One more clarification. StandbyState:init (or whatever concrete state has an implementation of init) can consist of Context:loadSettings...Context:clearDisplay...Context:setWindowPosition if these methods don't vary according to the state.
  12. I see. I will need to read through the topics but I can say this right away: We use the State Pattern as described by the Gang of Four. In this pattern we would never create a macro or queue of states, although we can and do create macros of triggers (could be commands) that we can invoke serially on the statemachine. Specifying a series of states would be antithtetical to the concept of a statemachine, I think. For instance, working off ShaunR's example, "Load Settings," "Clear Display," and then "Set Window Position" could all be separate commands (triggers) wrapped into an "Init" macro command, but these are not states. An Invoker calls the corresponding methods on the Context, which in turn delegates the operations to the State (so our abstract State would have the methods loadSettings, clearDisplay, and setWindowPosition, and the implementation behavior for these methods would vary between states--which is the point of having a statemachine). One clarification is in order. It is both possible and reasonable for a Context method to invoke several methods on State in sequence (hence decomposing a command into smaller operations). So, we could alternately implement Context:init as State:loadSettings...State:clearDisplay...State:setWindowPosition. (For ease of comprehension in practice we only do this if won't change states along the way--and rarely, at that--but there is really no theoretical reason you couldn't change state at each step.) Even in this case, though, we are assembling a series of operations, not states. Again, I don't thing specifying a sequence of states is in keeping with the concept of a statemachine.
  13. Can you give an example link where this term appears? I'm not sure what a Macro State would be. I know what a Superstate is. Paul
  14. Thanks for the link. That does explain this better. You are of course correct--I meant .lvlib files. Thanks for the correction! Yes, I want logical collections; but it is important to be able to use the logical collections in multiple projects in much the same way as I currently use project libraries. In practice I have found it necessary to move to flatter and flatter hierarchies because of this limitation, but I also find this is often far from ideal when it comes to code reuse.
  15. I’ve been thinking about how best to use libraries in LabVIEW for some time. There are definitely still some things that confuse me a bit, so I thought I’d throw out some questions for the larger community to solicit ideas. I’m going to focus on LabVIEW project libraries (.lvlib files), as these seem to have the properties in which we are most interested. I think of project libraries primarily as collections of things. We use these collections in a couple different ways. Templates and Namespaces In some cases we have a low-level set of concrete classes and other types of files [e.g., shared variable libraries, XML configuration files, and typedefs (which we only use for Enums and when we need a representation on a View, since classes don’t have controls—but that is another topic altogether)]. For each application the contents of these files vary. (The concrete classes inherit behavior from abstract classes in another set.) So for each application we need to write custom code, but we only need to change a few things. Of course we can copy and rename each class or file one by one, but we have found it practical instead to put the items in template collection (e.g., A.lvlib), and then copy the library to A’. lvlib or A’’.lvlib, and customize the implementations there. Since each project library has its own namespace, we can use the elements of the collection with their original names without creating conflicts. This may not be an ideal solution, however. It has worked well for us so far. Note: In UML a “package” (which has a folder icon) has its own namespace and is essentially a collection of elements as well. Collections for Isolation and Reuse We also use project libraries as convenient collections of related items we want to group together. We may or may not want to reuse the collections in other applications. (An obvious advantage if we do choose to reuse a project library is that changes to a project library in one instance will reflect in all other instances of that library, so that we only have to make changes once.) One example of a not for reuse (probably) collection is a set of classes implementing the State Pattern. We have an abstract State class, and then a collection of <ConcreteState> classes. None of the <ConcreteState> classes knows about any of the others (an important improvement we made to our earlier implementation), and State only knows about (via an input on its methods) an abstract Context class (in our implementation actually a Model class, but that isn’t important). What is important is that we can open a project library containing a collection of <ConcreteState> classes, and it only will include the abstract State and Context classes (functioning as interfaces) in the dependencies, so we can focus on implementing the State classes without concerning myself with the implementation — or even presence — of a <ConcreteModel> class. Then my application consists of an assembly of smaller collections. It seems logical, then, to have a project library containing smaller project libraries. Here, though, is where I get confused about how project libraries work in LabVIEW. In particular, if we open a project library contained in a larger project library, LabVIEW opens the entire project library hierarchy (i.e., the top-level project library and all its sublibraries). LabVIEW does not allow opening a sublibrary independently. Is that necessary? In particular, such behavior prevents reuse of sublibraries. For instance, if b and c are sublibraries of E, we can’t reuse b in another project without E and c coming along for the ride. That seems odd (and counterproductive). (I think the reason for this is that each element has membership in one and only library, and each member “knows” its library membership. LabVIEW considers a sublibrary simply another element in a superlibrary.) Note: In the UML tool we use (Enterprise Architect), we can check in a package at any level. We can retrieve any checked-in (controlled) package, and this means we include the controlled package and its subpackages—but not its superpackages—in the new project. This allows us to reuse subpackages in various projects. I wish LabVIEW project libraries worked the same way. Is there some good reason they don’t or can’t? Is there another good way to accomplish the same goal?
  16. For the record, the CAR for the issue I reported is 279298. I also forgot to mention that I would especially like to use the property node accessor feature because I they don't look like VIs so it is quicker to see what is happening in the calling VIs....
  17. There is also this example from ni.com I remember from a while back: Multi-client Server. I don't think it does the whole thing (skimming it now I don't see how to add a new publisher) but I think it is an interesting example. Paul
  18. I just encountered (this?) issue with property nodes for accessor methods as well. (I don't use Data Value References, for the record. I know those have already been exonerated in this thread.) There is no still no mention of either CAR on the known issues page. Anyway, I set up a part of my application to deploy and run on my real-time target, and it mostly crashes after deployment but before execution, but sometimes runs. (It always runs fine on Windows, by the way.) I deleted all the property node accessor methods from the classes, recreated regular accessor methods, and the test VI now runs fine.... Bummer! I really like the property node accessor method feature. I don't have to edit accessor method icons (really not fun), I can read or write more than one accessor method at a time, and I don't even have to find the accessor method in the project. I look forward to using the fixed version!
  19. Publish-Subscribe and Observer Pattern are two names for the same thing. (Larman on p.468 explains a bit of the history of the terms and lots of web pages that explain they are equivalent.) (OK, very strictly speaking, the Gang of Four Observer Pattern is an Object-Oriented implementation, and I don't know exactly how NI implemented NI-PSP. On the other hand, NI-PSP has an interface--the shared variable--to the Shared Variable Engine, which manages the connections, so it serves the purpose.) Head First Design Patterns walks you through an implementation of the Observer Pattern step by step. The authors recommend you know how to roll your own, even though there is a native implementation in Java (much like there are shared variables in LabVIEW) and you can just implement the provided interface. If you are an application developer, I don't think you need to invest in doing your own implementation (unless you are way ahead of schedule...). If you want to make a new toolset to replace or at least compete with NI-PSP, super! (If so, you might take a look at the DDS standard.) In any event, learning how the Observer Pattern works is a great exercise!
  20. We saw this with the 2009 RTE after adding the 2010 RTE to the same computer. (At least that's what we found. We never went very deep into this.) Paul
  21. I've been thinking about this. I wasn't aware that project libraries didn't necessarily load all their dependencies (although I encountered precisely that after I posted but before you replied). You are quite right about the behavior. On the other hand, what I am proposing for this use case is that one put all custom code in project libraries and include all required project libraries in the project. Since each project library loads all its parts, then all items will be in memory, if I understand correctly. So I think my proposal works for this situation. Of course, I am in favor of using objects in any case!
  22. Exactly. (We use DSC but shared variables and therefore shared variable events should be part of the LabVIEW core.) Overal NI-PSP provides what you need from the Observer Pattern, has good performance, works over a network(!), and (with DSC) adds logging. For many users I think it will be sufficient (and cheaper) to use the off-the-shelf solution. (If someone wants to make a better off-the-shelf solution that's fine, too!)
  23. For the record, you can achieve the intended effect using project libraries (.lvlib files).
×
×
  • Create New...

Important Information

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