Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by PaulL

  1. Yair, 1) I agree. This is simply a (harmless in our case) workaround because we don't have access to the "Panel Close?" (which would be the ideal solution!!!!) or other such event for a VI in a subpanel. We would need a front panel control to implement a user event. 2) That is the way we had it originally, but if a VI in a subpanel is aborted it can't stop any VIs in its subpanels. This is a workaround necessitated by the decisions we made in step 1. (The XControl approach actually does not have quite the same problem.) 3) Thanks. I hadn't seen that link (or the links from that page). They are most interesting. In the end, I think there is no way in the present version of LabVIEW to do what we want in an ideal fashion (regrettably). As far as I can see the only options require a compromise. I think we can either 1) wrap the view VIs with something to shut them down (abort them) -- which is what I did in the code I attached and what my colleague did with the XControl; OR 2) put a control to pass a user event on the front panel of each view VI. I actually started such a thing last week (making the control small and invisible and putting it at the origin), but I decided I didn't like it and abandoned it. Maybe this is the more palatable compromise, though. I'm going to revisit it now.
  2. OK, we thought a lot about this and we tried to implement something that adheres to the following principles: 1) The front panel of a the view the user sees, i.e., the VI that we put in the subpanel, should have no controls or indicators other than what the end user wants to see. 2) The view VI block diagram should be lightweight as well. 3) Communication, if any, should be self-contained and unambiguous. 4) The view may not run concurrently with the control component (ours don't, actually) so the view and all its components should be able to close based on a PanelClose? event on the top-level window VI. 5) Polling in a loop is not allowed. 6) Each view VI must run and stop correctly stand-alone or when called by another VI. It must be able to run as a top-level VI or inside a subpanel. We actually came up with two solutions that we think are satisfactory. We are not sure yet which we will use. One is mine. I attempted to implement something along the lines of the Composite Pattern. (Note that in the end I treated all existing elements as composites. I'm not sure what a leaf would be.) I am attaching a zip file of the concept code for those interested. I'd like some feedback. StoppingSubpanelsComposite.zip Open the Specific folder in the project and run viewMain. This shows we can open and close a view from a controller. Then run each view.vi in each of the View classes. They start and stop correctly. To create a new view we would copy a ViewX template and customize the view and init methods as needed. That's it. Unfortunately we need to specify the subpanel names in the init methods. (We can make the exact appearance different, but I don't see how to make this fundamentally simpler.) Presumably we could extend this pretty easily to add features if needed. I don't know of any bugs but this is just concept code. One of my colleagues developed an XControl approach. The XControl wraps the subpanel and of course runs in its own thread (note it is possible to do this without XControls) so there is no need for stop and start methods. I have a couple further comments: 1) I think something like this should be native to LabVIEW to simplify view development (and guide developers to build composite views). If you agree vote for my idea here: http://forums.ni.com...y/idi-p/1818645. (I see there are other similar suggestions, too.) 2) Another way to do this would be to generate a PanelClose? or equivalent (stop?) event via a reference to a VI running in a subpanel.
  3. Thank you for your prompt suggestions! Sorry for not replying on the thread sooner! I was out sick yesterday but I am happy to be fairly functional once again. On the suggestions: 1) Communications: We could extend our networked shared variable communications to do this (and use shared variable value change events), as I mentioned before, but I think there are two issues with this: a) We would be using networked shared variables for intraprocess communication. This is possible but seems inappropriate. b) Relatedly, this wouldn't scale well (at least not easily). We want each level to run stand-alone, and we must be able to reuse a subpanel in another view. If we use networked shared variables, to which variable do we subscribe? (This is one area where queues might have a slight advantage, but we have already committed to using events.) I can't think of any other purely event-driven approach (again, we are disallowing polling) that will fit the bill. Single top-level event: I like this (but with a tweak) except for one problem: 1) Tweak: Each level must be capable of creating the event because each must be able to be the top-level element. (I don't think this would be difficult to implement in some fashion.) 2) Problem: How does each level register for the user event? As far as I have worked this out I think to do this there must be a control on the front panel of the VI in the subpanel. I don't want to have such a control. (Maybe if a class does the work and handles control of the view front panel itself, though, that might be OK. Maybe that is what you are doing. I am having a somewhat difficult time envisioning how that will work with supanels, but maybe....) Can you clarify? One of my co-workers has implemented an XControl approach. We'll also look at that in a minute and see if it fills the need....
  4. OK, I have been struggling with this all day. I don't like the solutions I have found yet. Prior to today I had a top-level view (call it A) and it puts VIs (B0...n) in subpanels (and runs them dynamically). A has references to the B VIs, so when the user closed A it just aborted all the B VIs. That's a bit brute force, but it worked just fine. Today, I decided to put C in a subpanel of one of the B VIs. Starting up is not a problem and the code runs great, but shutting down the same way doesn't work since A doesn't have a reference to C (currently), so C continues running. That's not the plan. So, we could: Have B pass C's reference to A and A can shut down all parties. Have A tell B to shut down and B tell C to shut down. (Conceptually I like this much better.) Of course this means the abort mechanism won't work. Constraints: No ugliness! This means no polling (super yuck!). This should fit within the existing event structure approach. (So we can rule out global variables or single-process shared variables.) At each level the views must be able to operate stand-alone. For instance, B must be able to run without A (which was true before we added C, by the way). I have tried: Having each parent fire the FrontPanel close event on its children (FrontPanelClose? is not available via reference), but this doesn't work for subpanels (as I eventually found mentioned in other threads). Using a signaling event on a stopVI button for each VI. This works (or at least seemed to in a brief test) but it requires putting a control for this purpose on each VI. I don't like this because if I even double click on the terminal (even if the button is invisible) I have to spend time carefully putting the front panel back at its origin. More ugliness. Other ideas: We could have B pass C's reference to A, as stated above, but creating and then reading an indicator for this on B, while it would work, is quite messy. Creating a user event in A and handing this off to B. This will work but it requires some care to meet the second constraint, and it again requires adding control to each VI (or passing the event reference in some other fashion, but that doesn't provide any advantages over the control signalling method already tried). Use networked shared variables. I know this will work and we already have the mechanism in place. It is super-easy for us to implement. Moreover, we don't need to add any controls. On the other hand, in this particular circumstance I'd kind of like to avoid this because I don't really want to deploy any more libraries on the host computer. (Maybe I shouldn't worry about that.) Suggestions?
  5. NI support confirmed, by the way, that we outside NI do not have the access to do what the LabVIEW Flatten To XML and Unflatten From XML functions do (at least not using the same methodology).
  6. Later... well, no luck connecting to port 7 (or anything else yet). I'd really like to avoid opening a new port on the remote machine just to do this....
  7. Well, we would like to detect the problem and then go to the fault state gracefully within our application. As I said, we do that now, the detection time is just too long. Hmm... Thanks for the link. So I can detect a problem by trying to connect to the cRIO (the near end of the wire) or do I want to listen to a port on the remote machine (Windows in this case)? It looks like this is something to explore....
  8. So I think you are doing essentially what we are doing with the Read Variable with Timeout function. It looks like that might not be sufficient, so we may need to use a TCP function just for this check, which we can do but it is more involved for us. (If we could just configure the SV timeout we wouldn't have to write any additional code.) I'm wondering: Is there a port or service that we can anticipate will be open and can monitor with TCP/IP so that we don't have to open an additional one just for this purpose?
  9. Later... Well, it's definitely not working as I had hoped. I still don't get the error for about 20s after I pull the plug, even if I use 1 for this value (and for a value I added, Heartbeat_SendTimeoutSecs). I contacted NI Support to see if they can clarify what these parameters actually do.... Paul
  10. Well, what I said about the timeout not being configurable may not be correct. I found this http://zone.ni.com/reference/en-XX/help/370051K-01/cvi/cvinetvartips/. It is for LabWindows but I did find the relevant entry ([LOGOSXT] Heartbeat_AbsenceDetectCount) in ri-rt.ini on the CompactRIO. (We remembered seeing something like this, but then we couldn't find it, and here it is again. Maybe we installed the right software or we got it when we moved to 2011?) I am going to run a test....
  11. So you already have a port to check (the one you are already using for communication)? Is that correct?
  12. We have a requirement that any controller running on a CompactRIO should go to a fault state, stopping all motion in the process, if there is a loss of network communication (which could happen if someone disconnected the network cable, the network went down, etc.). We meet this requirement at present by monitoring the error code from a Read Variable with Timeout function we use. In the event of a network loss there this function reports an error (-1950679035) and we safe the system and go to a fault state as required. The Read Variable with Timeout function does not report error -1950679035 immediately after someone disconnects the network cable, however, in tests. It takes some finite (at least 8 s) and not configurable time. The customer has asked us to detect the network loss in a shorter (preferably configurable) time. Does anyone know how to do this? Yesterday I found that I was able to use a ping approach successfully between two Windows machines (although I think the final implementation details would be a little more involved than what I did in my test). The specific approach doesn't work on VxWorks, I think, although I have seen a reference to a pinglib, but I don't know off-hand how I would call such a function. I have seen a couple threads (and a related idea on ni.com/ideas) but I don't have an answer yet. Maybe there is a completely different approach that will work better. I thought I'd post here and see what suggestions I might get. Thanks!
  13. Oh, I see! Yes, as jgcode suggested, you can convert the URLs from one form to the other for use with the different APIs. (You can use the string form and do the conversion.) In practice, we use each of these where we need them (with the respective APIs). At present we only use the top one for shared variable value change notifications. We haven't encountered any issues with this approach. Paul
  14. Sorry, I still don't know what you are saying. Do you mean setting alarms? Shared variable binding? Generally, the DSC Module adds some functionality (e.g., alarms, logging, security) to the shared variable.
  15. This isn't correct. We use functions (actually through the Shared Variable API now) to read and write shared variables, and yes, we use the DSC Module. I'd comment more but I'm not even sure what you are saying. In any event, I recommend that you use the Shared Variable API functions (available in the more recent versions of LabVIEW), not the DataSocket functions, to read and write shared variables. The performance of the DataSocket functions is not as good as that of the methods available with the Shared Variable API (we've tested them ourselves) and I think it's awkward at best to use the DataSocket API to talk to something that isn't (at least expressly) DataSocket communication. (Yes, the DataSocket API can work with shared variables, but again, why use it?) Paul
  16. ? I'm not sure what you mean by this. Can you clarify?
  17. OK, the Controller executes Commands, which simply invoke methods on a Context (see Command Pattern). The Context methods (also trivial) delegate their instructions to State methods (see State Pattern) that implement a state machine. The State methods invoke Model methods directly (OK, via an interface). The State methods determine which Model methods to call based on: 1) A new external trigger (user interaction, message from another system) 2) An internal trigger (overheatingIsTrue). The Model has a method that calculates that overheatingIsTrue (and will create an error or warning as appropriate) but it does not determine what to do in that circumstance. The state method does. This is actually quite important. To reiterate, the State methods know what to do but not how to do it. The Model methods just now how to do what they are told. By the way, we treat an interrupt or other start loop trigger as just another instance of an external trigger (external to the controller thread, but running on the the same hardware in the same application). This simplifies things dramatically. Within our State methods we have exactly two methods where we wire an error cluster input to a case structure! [by the way, I view the state machine as part of the controller, not the model. I think the definition of the two is sufficiently ambigous in the literature I have read that you could alternatively define the "model" to encompass what I am calling Context, State, and Model here.]
  18. Well, Dave and I are advocating different things. In practice, our project uses a hybrid approach. This is from our presentation last August: Description: A user clicks a button on the view. The view code handles the button event and publishes a value (a demand). (Note that another view or controller in the application can publish this same demand, if we so design it. This is great for designing a hierarchical system.) The "Data Listener" for the component subscribes to all relevant demands (really any input data) for that component, and upon receipt of a new demand creates a corresponding Command object (see Command Pattern), which it publishes. Hence the Data Listener is a sort of mediator, I suppose. The Controller subscribes to Command, and responds accordingly. When there is something to do it invokes methods on the Model. The Model changes state as appropriate, and publishes updated aspects of its state to appropriately named topics. The View subscribes to these state topics. When a value change event occurs, it updates the appropriate indicator. (Binding the indicator to the shared variable is another way to accomplish the same thing in the very simplest cases.) Note that multiple Views can subscribe to the same information. We have implemented a number of systems now and I think this is really quite elegant. [some details: We actually use programmatic access to SVs. Also we right justify and fix the digits for numeric indicators and use proper units. For this and other reasons we use events rather than shared variable binding in most instances.]
  19. I'm not going to pretend I have comprehended the entire post, but everything I digested seems reasonable to me. I do have one concern, which is that I don't want to have create override methods for each class (especially since the only way I can use "Serializable" in LabVIEW now would be through inheritance and not via a Java-style interface). In particular, right now I can wire any LabVIEW object to a native Flatten To XML method, and the existing framework performs the serialization. It's just the output is not sufficient for sharing with the outside world, unfortunately. I like the API, though! :-)
  20. OK, plug-ins, then. See this thread (http://lavag.org/topic/14212-how-to-call-a-plug-in-object-from-an-executable/page__p__85567#entry85567), where I think we concluded the best options are source distributions (yuck!) or packed-project libraries using the method mike_nrao describes. (There is a link to the solution in that thread, post #9).
  21. This is somewhat tangential, but the Gang of Four folks (pp. 5-6) consider M-V-C a composite design pattern, where the individual design patterns are Observer, Composite, and Strategy.
  22. For the record, LabVIEW allows you to create an XControl that is a friend of a class as a way of sort of creating an editable control for a class. (I don't do this myself since XControls are too complex and limited, and I think the "friends" concept is not valuable, but it is an option.) For clarification, in our situation our users edit the values in a configuration editor we created, not the XML files directly. On the other hand, since there is only a small amount of information in each XML file, it is quite reasonable to edit the XML file directly if necessary, although certainly an ini file might be easier.
  23. We let the Flatten To XML and Unflatten From XML handle the messiness. We create a typedef'd cluster (usually, doesn't have to be a cluster; it isn't an object since a class does not have an editable control that we can put on a front panel) that defines a tightly connected set of data and use the Write To XML method to write the cluster data to a file (<clusterName.xml>). Appropriate classes have the cluster in their private data. (Note that a class can have 0..n of these, and multiple classes can use the same cluster.) Then initializing the object is as simple as what we show in the attached file. (OK, our full, flexible, configuration editor has a lot of features that make it a bit more complicated, but this is the essence of it.)
  24. There are a few different ways to implement M-V-C. In http://www.amazon.co...28725276&sr=8-1, for instance, the authors show a flavor where the Controller subscribes to the Model's published state, and another whether the View subscribes to the Model state directly. In our components the Model publishes its state (in both senses, the current parameter values, and particularly a value that describes in which State it is currently, e.g., DisabledState). Each of our Views has the responsibility of deciding what to display based on the value of the State parameter. It is pretty simple to implement this sort of thing. (There is another flavor of M-V-C where the controller takes a much more active role in determining what the View should display. We have decided to date not to implement that flavor for our purposes.)
  25. It's good to see you commenting on the forum again!!! I'm not sure I quite agree on #4. I would rather say use nested .lvlibs where this is appropriate. (We don't do this often but we have cases where this seems appropriate.) What is your concern with version control and nested project libraries? (I do think that only one developer should be working on the larger library at a time.) I certainly agree with 2 and 3. We don't do 1 (with SVN) but we don't see any issues either.
  • Create New...

Important Information

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