Jump to content

Daklu

Members
  • Posts

    1,824
  • Joined

  • Last visited

  • Days Won

    83

Everything posted by Daklu

  1. I should have said I've never seen a LV application that started with a state diagram. It doesn't surprise me that VIE and Ben use them; being professional development houses carries with it a different set of expectations than being an internal tool developer. Down here in the mud I just haven't seen them. I actually did try to put one together for an app I built and it turned out to be surprisingly difficult. I haven't found much information on how to best go about creating state diagrams. The examples I've seen online tend to be fairly trivial. ----------------------- Well, first let me 'splain that my thoughts are driven primarily by problems I've seen in my own state machine implementations. Some of the ideas I don't like might in fact be good implementation practices... I dunno. I also don't claim to fully understand state machine theory. I've read what I can find on Moore and Mealy State Machines, as well as information on Hierarchical State Machines and various other bits of information. The pieces haven't fallen into place yet. Sequence Machines seems to have been covered fairly well. I admit that I use them on occasion; however, I do try to make it obvious what it is by wiring a loop index into the case input, as shown below, rather than using strings or enums as inputs. (If a stacked sequence behaved like this they might not have the terrible reputation they have now.) I use sequence machines primarily as a 'light abstraction' layer in situations where I don't necessarily want to hide what's going on in a sub vi, but I do want to encapsulate and contain the functionality for readability (or I simply need the extra room.) For example, in a current app I use a sequence machine for writing data to a file. Case 0 contains all the logic for obtaining a file reference. Case 1 retrieves and writes the test information. Following that are cases for writing column headers, iterating through and writing the data, closing the file, etc. I believe a sequence machine should be contained in a single state and not built as part of the top level state machine itself. When I have a state that always leads directly into another, predetermined state, I have to ask myself "why do I need two states here?" What I called a 'Procedure Machine' is different, and I didn't do a very good job of explaining it. All applications have some sort of operations (procedures) they perform. A procedure machine codifies procedures in the case statements rather than states. Is that good practice? I don't really know... I do know my state machines tend to be procedure machines rather than state machines and that is reflected in the names I give my states. ("Init," "Save Data," "Exit," etc.) Intuitively a procedure isn't really a state, so my gut feeling is that I'm not doing it right. Looking over old code I've written I see states I've built that could (should?) have been a sub vi integrated into other states rather than a unique state called as part of a sequence of states. This is bad on several counts: First, my state machine now has an extra state that unnecessarily complicates the overall application. Second, and more critical, is that I often have to implement extra code to make sure the correct states are executed after my procedure state. Just thinking out loud, but I'll bet if you use a QSM and find yourself queueing up the next several states to be executed you're working with a Procedure Machine. Like I said earlier, I'm not particularly knowledgable in state machine best practices. I've implemented the state machine design pattern plenty of times but I've always got a nagging feeling that it's not quite right. A few of these questions really resonate with me. Are the states well factored? What makes a state well-factored? How do you decide if you've met that goal or not? Is the code properly contained in sub-vi's for re-use? What criteria do you use to decide if particular functionality should be contained in a unique state or in a sub vi which you can then use in several different states? Can you shoot yourself in the foot by calling them in the wrong order? This one sounds important. My procedure machines (and pretty much every state machine implementation I've seen) will break if you get the sequencing wrong. Is this a good indicator of a properly factored state machine? The others, especially "single responsibility," I'm not convinced of.
  2. I like the balloon idea. Simple, inexpensive, and everyone gets to participate. (Might want to blow up the balloons before-hand though.) Given their age and your time limit I wouldn't try to teach them anything... instead just show them something cool they will remember.
  3. I agree with this comment, but it's not a fault of the JKI State Machine or state machines in general. From what I've seen it's due to the way people use the state machine architecture. (Me included.) Most state machines I've seen are a combination of "sequence machines" where a series of states are called in the same order every time and "procedure machines" where a specific state essentially takes the place of a sub-vi. I don't think I've ever heard of a developer actually sitting down to figure out what the valid states of his application are and developing around that.
  4. I can't speak for other engineers, but there's one main reason I would never go into politics. The issues are too big for my comfort level. The scope of the problems politicians try to solve are much, much larger and have far more unknowns than the problems I solve as an engineer. As an engineer I always have to deal with compromises and unknowns, but I can usually get the information I need to get a feel for what those unknowns are and make an informed decision. Decisions politicians make have so many far reaching consequences there's simply no way to get a handle on the unknowns. Even the "known" consequences often hotly debated with no clear answer. Politicians either have to delude themselves into believing they fully understand the tradeoffs or they must admit they are making an uninformed decision. Thanks, but I'll pass. Regarding Margaret Thatcher, I was watching a television show about the British SAS and the hostage rescue training they do in their kill house. Sometimes political dignitaries would come observe training exercises. Apparently Thatcher insisted on playing the role of the hostage during one exercise (note they train with live ammo) and sat in a chair with several targets around her. The SAS broke into the room and amidst a barrage gunfire and noise eliminated all the targets. When the few seconds of chaos were over, Thatcher was still sitting in her chair looking very dignified while her aide cowered on the floor. She looked at him and said, "Get off the floor <name>, you're embarrassing me." Iron Lady indeed.
  5. I agree with Mark on this. You're at a point where your application requirements cannot be satisfied by keeping your logic inside the same loop as the event structure. Don't try to fix it with band-aids--take the time to refactor it correctly. Break out the intermediate level vi calls into a second queued state machine and send it messages from your UI loop. You'll thank yourself later.
  6. I doubt it's flashy enough to attract any attention on the idea exchange. I figured I'd have a better chance of quietly getting an .ini switch put in place.
  7. A picture is worth a thousand words. Since I only typed ~100 words your solution is 10 times better than mine.
  8. Is there a hidden .ini switch that will turn off the annoying dialog box that pops up every time I remove a structure? Yes, I know everything in the other cases will be deleted. You don't have to tell me that every time. If I make a mistake... well, that's what cntl-z is for.
  9. You can do this using User Events. First, I'm assuming your dialog box is running in a separate thread from the calling vi. If not, there's no reason to use events. There are several ways to accomplish what you want to do. Here's one way... If your dialog box is a single vi and you don't want to expand it beyond a single vi, the calling vi needs to create a User Event. Fork the User Event wire and pass one branch into the dialog vi as a parameter and the other branch into a Register For Events prim. Then wire the Event Registration Refnum into the Dynamic Events terminal of the calling vi's event structure. In the dialog vi, you have an event structure that fires on the value changed event. Inside that event case, wire the caller's User Event (that was passed in as a parameter) into a Generate User Event prim. When the value changed event on the dialog box fires, it will in turn fire an event in the caller's event structure.
  10. I recently took over responsibility for our Fanuc robot, though I have not had a chance to really dig into it yet. I'm interested in what you come up with.
  11. My apologies. I assumed you were referring the compiling that takes place when building an executable. In this post AQ describes the compiling process in LV and compares it to C++. I read it as something that happens continuously, not just when the run button is pressed. I could be wrong though. Ehh... not quite. "Super-macro" might be more accurate. Wikipedia has this to say... "Both macros and templates [The c++ version of generics - Ed.] are expanded at compile time. Macros are always expanded inline; templates can also be expanded as inline functions when the compiler deems it appropriate. Thus both function-like macros and function templates have no run-time overhead. However, templates are generally considered an improvement over macros for these purposes. Templates are type-safe. Templates avoid some of the common errors found in code that makes heavy use of function-like macros. Perhaps most importantly, templates were designed to be applicable to much larger problems than macros." (Tomi has a much better understanding of the differences between c++ templates, type parameters, and other generic implementations. He might have more to say regarding this question.) Yes, but the difference is with polymorphic vis we have to manually implement the code for any type we want the polymorphic vi to support. With generics we can implement the code for a single "generic method" and Labview will automatically generate the required code for any data type we wire into it.* (Provided the real data type meets the constraints defined by the generic.) Recently I built a Collection class, which was essentially an attempt to implement .Net style collections. It has the standard methods... Add, Remove, Count, Item, etc. However, to really duplicate .Net collections I'd have to create and implement child classes for every possible combination of native and user-generated data type. Not only is that a lot of duplicate code (since, for example, the code behind every child class' Remove method is identical except for the data type,) but there's an infinite number of combinations. Clearly covering all potential inputs is an impossible task. If generics were available in Labview, I could write the class once and use it anywhere. Less code. Less maintenance. Less headache (presumbably.) [*This leads me to another question for Tomi. As far as I know generics in other languages don't produce new source code--there is a clear distinction between pre-compiled code and post-compiled code. In Labview that distinction is muddied... in a sense all our block diagrams are post-compiled code. Would the code generated by a generic be saved as a separate vi, in which case the feature behaves almost like a toolkit, or do you create it dynamically on an as-needed basis?] Meh... not a good enough reason for me. If you're trying to optimize a tight real-time loop, then yeah... but my apps run on desktop computers on a preemptive multitasking os. I have bigger things to worry about than an extra data copy here and there.
  12. I see I'm a little behind the curve here. Oh well... Actually Labview does type check at compile time. Labview is always compiling your code behind the scenes while you're in the dev environment. Ergo, in Labview compile time == dev time. (Compiling is part of the process of building an executable, but building an executable != compiling.) No. I imagine a properly implemented generic vi in Labview would behave in much the same way as a polymorphic vi, except that you wouldn't have to write individual sub vis for each data type you want to support. You create a single vi with 'type placeholders' and Labview automatically creates the correct "sub vi" based on what you connected to the input terminal. Some prims do, but we can't create classes or vis that do this. That's what Tomi is asking for.
  13. That's part of it, but more importantly how do you create a generic type in Labview? What does it look like? class Array[T] { typedef T; typedef U &gt;= T; param head : T; param tail : Array[T]; create_array('array in' : Array[T], elem : T) -&gt; ('array out' : Array[T]) { 'array in'.head = elem; 'array out' = 'array in'; } add_element('array in' : Array[T], elem : U) -&gt; ('array out' : Array[U]) { 'array in'.tail = 'array in'; 'array in'.head = elem; 'array out'='array in'; } I don't have much experience with generics and the syntax is a little confusing, but here are a couple obstacles I see: In your example code you have the variables T and U representing arbitrary data. Labview doesn't have variables, only data. To implement the above code in Labview you have to create some sort of data construct representing T and U that you can drop on a front panel. How do you create a data type that, by definition, has no type? The first two lines in the class define the relationship between T and U based on their type information. How do you establish that relationship in Labview? It can't be in a vi; the relationship has to be enforced at compile-time, not at run-time. As I understand it, generics emulate some characteristics of dynamic typed systems by automatically generating the correctly typed code at compile time. Generics in a statically typed language still produce statically typed code. Violating the generic's defined typing rules results in a compiler error, which translates into a broken wire in Labview. It is!? I've never heard that and strongly disagree with it. (Until someone can convince me otherwise.) It seems plain silly not to use them in places where they are appropriate.
  14. Hmm... perhaps he was dictating? ---------------------------------------- I agree there are times when Labview generics would be useful. How would you implement them in a way that maintains Labview's "everything is data" paradigm?
  15. I haven't done any benchmarking but everything I've read indicates a queue messaging implementation would be better/faster/stronger/smarter/prettier and offer tantalizing coversation to boot! Messaging also decouples the engine from UI better, making it easier to modify the behaviors of either. However, control refnums is (probably) faster to implement. If you do go this route a second UI that uses different controls won't cause problems as long as the engine supports the superset of all controls on all user interfaces. Chris has way more experience than I do so I'm not really qualified to disagree with him... but here I go. For anything except very simple VIs that won't change ever, I'd strongly recommend queues or user events over control refnums. IMO, there are too many disadvantages with control references to even consider using them in this situation. (After rereading Chris' post, I see he didn't actually suggest using control references; he was simply explaining the demo's implementation. Lucky me... I didn't disagree with him.)
  16. *grumble* *grumble* ...crotchety old geezers taunting us with code they have but won't post... *grumble* *anxiously awaiting answers to these questions* Creating thin, bolt-on UIs has driven my recent interest in the Observer pattern. Observer seems like a natural fit for this kind of task but I haven't figured out the best way to implement it yet.
  17. I just upgraded to W7 and would have loved to use it, but my laptop processor doesn't have the hardware support.
  18. Excellent observation. I hadn't thought of that. It certainly puts a damper on the idea of using user events across code module boundaries. Yeah, but having to reimplement that for every code module? Ugh. Since the UsrEv and UsrEvReg refnums are strongly typed I can't even generalize the functionality in a parent class. I'll have to write custom code for each set of user events exposed by a code module. NI targets non-professional programmers with Labview so I shouldn't be surprised ease-of-use trumps robust code. If we want to use user events to cross code module boundaries, I guess we're stuck with implementing event mediators (i.e. your suggestion) in each module or Ton's Option B, registering the listener's user event with the subject. I suspect the mediator is slightly easier for the developer using the code module, though I don't see any clear advantages of one over the other. I guess I'll have to implement them and see.
  19. The knock against VirtualPC is that it doesn't have good usb support. From what I understand usb mice and keyboards usually work fine but other usb stuff may or may not work. What's your experience been? Any USB issues?
  20. Wow, three years of LV programming and I never knew that feature existed. Funny how little tricks like this pop up unexpectedly. And now it's gone... Farewell little 'Suspend when called.' Though I knew you not, I miss you already.
  21. I made a few changes over the weekend to the Interface model. I've gone back to the idea of 'casting' an interfaceable object into an interface, operating on it, then 'casting' it back into the original object. Internally the functionality is pretty much the same but by using this model it becomes possible to create interfaces for by-val objects. It also makes the class user branch the wire before getting an interface from an object rather than hiding the branch inside Interfaceable:GetInterface. I believe this improves code readability. Code can be found in the code repository.
  22. Version 1.0.0

    2,338 downloads

    Interface Framework v1.0.0 Copyright © 2009, Dave Snyder All rights reserved. Author: Dave Snyder LAVA Name: Daklu Contact Info: Contact via PM on lavag.org LabVIEW Versions: 2009 Dependencies: JKI's VI Tester is required if you want to execute the unit tests. Description: In object oriented programming, often a designer needs a class to include the behavior of two or more unrelated classes. Traditionally programming languages address this situation with "mulitple inheritance" or "Interfaces." Unfortunately, Labview supports neither. The Interface Framework provides a structure for giving your classes Interface-like behavior. Installation and instructions: Option 1 - Install the OpenG Package using VIPM. This will install the framework in \LAVA\Interfaces\_Framework. Navigate to the 'User Libraries -> LAVA Code Repository -> Interfaces' palette to use previously implmented interfaces. The 'Advanced' palette provides vis for interface implementers. Option 2 - Copy the 'Interfaceable Class' and 'IUnknown Class' folders from Core\Source to the location of your choice. Documentation: The Core\Documentation folder contains the following files, -Changelist.txt - Contains the revision history. -Interface Framework.uml - Contains two class diagrams, one for the core framework and one for the Baby class implementation of the ISleepable interface, and a sequence diagram of the Interfaceable:GetInterface method. Use StarUML to view this file. Examples: Examples of implementing interfaces in classes and using the framework in applications can be found in the Sample Implementation or Unit Testing folders. Known Issues: No testing has been done with Interfaces that inherit from other Interfaces. Very little testing has been done with interfaceable objects inheriting from other interfaceable objects. Acknowledgements: Special thanks to kugr and SciWare for taking the time to look it over and provide valuable feedback. Thanks to Stephen Mercer for patiently answering my numerous questions and providing detailed explanantions. Thanks to the LAVA community for being willing to share knowledge and ideas. Version History: (For previous changes see changelist.txt) v0.12.0 - Nov 1, 2009 (Unreleased) [Note - Public api has changed. Backwards compatibility may be broken.] -Renamed Interfaceable:GetInterface to Interfaceable:CastToInterface. -Renamed Interfaceable:RecoverObject to Interfaceable:CastToInterfaceable. -Changed connector panes and icons for CastToInterface and CastToInterfaceable. -Added context help text to CastToInterfaceable. -Changed error message generated when CastToInterfaceable fails. v0.11.0 - Oct 18, 2009 [Note - Public api has changed. Backwards compatibility may be broken.] -The framework now follows a more intuitive model where the interfaceable object is "cast" into an Interface, operated on using the Interface, and "cast" back into the original object. This allows the framework to work with static, by-ref, and by-val data in classes and more closely follows Labview's data-flow model. -Added Interfaceable:RecoverObject method. (Name is likely to change in a future version.) -Changed connector pane of Interfaceable:GetInterface method to one similar to the 'To More Specific Class' primitive. -IUnknown now has both protected and community scoped methods for SetTargetObject and GetTargetObject. -Added by-val, by-ref, and static objects for unit testing. Added test cases for testing by-val and by-ref object. Added mock interface IInt and concrete implementations. -Changed some banners and icons. License: Copyright © 2009, David Snyder All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY DAVID SNYDER ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID SNYDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. Name: Interface Framework Submitter: Daklu Submitted: 19 Oct 2009 File Updated: 24 Apr 2011 Category: LabVIEW OOP LabVIEW Version: 2009 License Type: BSD (Most common) Interface Framework v1.0.0 Copyright © 2009, Dave Snyder All rights reserved. Author: Dave Snyder LAVA Name: Daklu Contact Info: Contact via PM on lavag.org LabVIEW Versions: 2009 Dependencies: JKI's VI Tester is required if you want to execute the unit tests. Description: In object oriented programming, often a designer needs a class to include the behavior of two or more unrelated classes. Traditionally programming languages address this situation with "mulitple inheritance" or "Interfaces." Unfortunately, Labview supports neither. The Interface Framework provides a structure for giving your classes Interface-like behavior. Installation and instructions: Option 1 - Install the OpenG Package using VIPM. This will install the framework in \LAVA\Interfaces\_Framework. Navigate to the 'User Libraries -> LAVA Code Repository -> Interfaces' palette to use previously implmented interfaces. The 'Advanced' palette provides vis for interface implementers. Option 2 - Copy the 'Interfaceable Class' and 'IUnknown Class' folders from Core\Source to the location of your choice. Documentation: The Core\Documentation folder contains the following files, -Changelist.txt - Contains the revision history. -Interface Framework.uml - Contains two class diagrams, one for the core framework and one for the Baby class implementation of the ISleepable interface, and a sequence diagram of the Interfaceable:GetInterface method. Use StarUML to view this file. Examples: Examples of implementing interfaces in classes and using the framework in applications can be found in the Sample Implementation or Unit Testing folders. Known Issues: No testing has been done with Interfaces that inherit from other Interfaces. Very little testing has been done with interfaceable objects inheriting from other interfaceable objects. Acknowledgements: Special thanks to kugr and SciWare for taking the time to look it over and provide valuable feedback. Thanks to Stephen Mercer for patiently answering my numerous questions and providing detailed explanantions. Thanks to the LAVA community for being willing to share knowledge and ideas. Version History: (For previous changes see changelist.txt) v0.12.0 - Nov 1, 2009 (Unreleased) [Note - Public api has changed. Backwards compatibility may be broken.] -Renamed Interfaceable:GetInterface to Interfaceable:CastToInterface. -Renamed Interfaceable:RecoverObject to Interfaceable:CastToInterfaceable. -Changed connector panes and icons for CastToInterface and CastToInterfaceable. -Added context help text to CastToInterfaceable. -Changed error message generated when CastToInterfaceable fails. v0.11.0 - Oct 18, 2009 [Note - Public api has changed. Backwards compatibility may be broken.] -The framework now follows a more intuitive model where the interfaceable object is "cast" into an Interface, operated on using the Interface, and "cast" back into the original object. This allows the framework to work with static, by-ref, and by-val data in classes and more closely follows Labview's data-flow model. -Added Interfaceable:RecoverObject method. (Name is likely to change in a future version.) -Changed connector pane of Interfaceable:GetInterface method to one similar to the 'To More Specific Class' primitive. -IUnknown now has both protected and community scoped methods for SetTargetObject and GetTargetObject. -Added by-val, by-ref, and static objects for unit testing. Added test cases for testing by-val and by-ref object. Added mock interface IInt and concrete implementations. -Changed some banners and icons. License: Copyright © 2009, David Snyder All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY DAVID SNYDER ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID SNYDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Click here to download this file
  24. At the risk of beating a dead horse... I think it's a huge mistake to let the reliability of your code depend on documentation and alert developers. (Remember when Windows was a cooperatively multitasking OS?) In a single application where the developer has complete control over where user events are destroyed it's probably okay, though I still prefer the encapsulation of keeping the user events private. For reusable code modules, plug in architectures, or other systems where third party code would be using your user events, I think you're just asking for trouble. A well-written error message that crashes your application still crashes your application. It's not any harder to pass out a RegRefnum than it is a UserEvent. The added protection it provides eliminates an entire category of potential errors future developers have to test for. If the additional protection is essentially free, why wouldn't that be the preferred way to do it? (I feel like I'm missing something fundamental about user events, but I don't know what it is.)
  25. Yep, with the way I was doing it they certainly can and that would screw everything up. Thanks to Jeffery's correction and AQ's remark about waiting until someone asks for the reference before creating it, maybe a better way to handle it is to register the user event when the user calls GetRegRefnum and pass the RegRefnum out. That way (presumably) each caller gets a unique RegRefnum and they can't step on those of other listeners. Maybe that's what AQ is saying...? I read it as creating the User Event, not the Registration Refnum, in the GetUserEvent method, and I don't understand why that is preferable. Creating unique user events for each listener requires a lot more supporting code than creating unique registration refnums.
×
×
  • Create New...

Important Information

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