Kurt Friday Posted September 14, 2009 Report Share Posted September 14, 2009 Name: By Ref Active Object Framework Submitter: SciWare Submitted: 14 Sep 2009 File Updated: 14 Sep 2009 Category: LabVIEW OOP Version: 1.0.0 LabVIEW Version: 2009 License Type: BSD (Most common) By Ref Active Object Framework Copyright © 2009, Kurt Friday All rights reserved. Author: Kurt Friday LAVA Name: SciWare Contact Info: Contact via PM on lavag.org LabVIEW Versions: 2009 Dependencies: None Description: This is an OOP Framework that allows the development of By Reference Objects with the capability to also be Active Objects. By Reference capability is achieved by wrapping a DVR of the Data Members in a LVOOP Object. An Active Object is one that has its own background process which is launched when the object is instantiated. Active Objects are useful if your object requires time dependent characteristics. Examples: By Reference Object Demo Demos\BikeDemo\Src\BikeDemo.vi By Reference Active Object Demo Demos\PumpDemo\Src\PumpDemo.vi Version History: v1.0.0: Initial release of the code. License: ### BSD License (http://www.opensource.org/licenses/bsd-license.php) Begin ### Copyright © 2009, SciWare <http://www.sciware.com.au>, Author: Kurt Friday 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 SciWare,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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. ### BSD License End ### Support: If you have any problems with this code or want to suggest features: please go to lavag.org and Navigate to LAVA > Resources > Code Repository (Certified) and search for the "By Ref Active Object Framework" support page. Distribution: This code was downloaded from the LAVA Code Repository found at lavag.org Click here to download this file Quote Link to comment
Daklu Posted December 24, 2009 Report Share Posted December 24, 2009 Kurt, I think I'll finally get some time to implement some of my own active objects based on your example, but I wanted to toss out some questions to make sure I'm understanding it correctly and only change what I need to. All the vis/controls in the private folder should remain untouched, except DataRef, which I customize with my own data, and Process, in which I delete all the cases (except "shutdown") and add cases to handle my object's commands. Create and Destroy are the only public methods that are part of the framework; the others are unique to the example. Correct? There is both a command queue and a message queue. I couldn't find the message queue used anywhere. Is this an artifact of the development process or is there an intended use for it? I'm a little confused about the occurrence you use in LaunchProcess and CloseProcess. Both vis have a "Wait on Occurrence" before exiting with a 1 sec timeout, but there's no action based on whether or not the occurrence was set. Is this just a placeholder to show where to put code that does need the occurrence? I see you've set up the methods and controls with dynamic dispatching and protected scope. Have you tried creating a generalized ActiveObject for the core functionality and deriving child objects for specific implementations? Quote Link to comment
IBerg Posted January 23, 2011 Report Share Posted January 23, 2011 As one who has grown to love endevo's GOOP tookit and recently disappointed after re-acquainting myself with LabVIEW's native oop features (which still seems like illegitimate OOP to me, but I am biased due to coming to OOP from C++ background), To put it mildly I was dismayed by the native default by-value behavior but like teh by reference capabilities of this DVR Active Object architecture much better. Thank you for posting it! One thing I noticed about the pump example is if you follow commanding the pump to pump a volume by any other action on the front panel which invokes another command being sent before the pump finishes, the timeout set in Process.vi won't have time to expire. Not having had time to expire is maybe ok if the next action was turn pump on, or turn pump off, but problematic if the user had simply hit 'Pump volume" again. Did you really intend for a double-use of either pump's "Pump volume' button to effectively turn the pump on indefinitely? If not, we get to the real question i am wondering about... what is the best way to fix it and yet preserve the elegant simplicity of this example? Handshaking (: i.e. disable and grey the "pump volume" button until a message comes back to say the time out has been reached sounds ... I guess within "process.vi" if the most recently executed command was "Pump volume" then the return message that triggers the re-enable would need to be sent as soon as the dequeue times out or returns any newly sent command (getting another "pump volume' would then be ruled out). Quote Link to comment
Daklu Posted January 29, 2011 Report Share Posted January 29, 2011 Kurt has been MIA for quite some time, so while I wouldn't presume to speak for him I'll take a stab at answering your questions. Did you really intend for a double-use of either pump's "Pump volume' button to effectively turn the pump on indefinitely? Probably not, but for the sake of simplicity lots of error checking and whatnot is usually left out of code when the purpose is to illustrate a specific concept. If not, we get to the real question i am wondering about... what is the best way to fix it and yet preserve the elegant simplicity of this example? Hmm... can't really answer that without defining what the system behavior should be when the Pump Volume button is pressed while the pump is running. Should the button tell the system that regardless of where it is or what it's doing now, it should pump x additional volume then stop (restarting the process with the new endpoint), or should it overwrite the current Volume to Pump value (continuing the same process but replacing the endpoint), or should it ignore the message altogether? You can get part of the way towards the first definition by removing the state boolean check inside the 'pumpvol' case, though that single change causes the Volume Pumped indicator to reset, so there's more work that needs to be done. I didn't explore implementing the other definitions. In general terms your question is 'how do we make sure the system remains robust when it receives unexpected messages?' Disabling front panel controls to prevent messages from being sent is one way to approach it, though I don't particularly like that technique. IMO it's much better to build message filtering into the system itself rather than require the clients to pre-filter the messages before sending them. But this question is not really related to Kurt's framework, so if you want to discuss it more it would be better to start a new topic. Quote Link to comment
Kurt Friday Posted April 26, 2011 Author Report Share Posted April 26, 2011 Hi All Apologies for not replying I didn't realise that there were posts here. Regarding the Pump example, its just a simple demo of the capability of the framework. Probably the best way to handle not pushing another pump volume command while it is already pumping is to have a busy state in the datamembers and don't allow any new pump volume commands to be placed in the queue until it is not busy. All the vis/controls in the private folder should remain untouched, except DataRef, which I customize with my own data, and Process, in which I delete all the cases (except "shutdown") and add cases to handle my object's commands. Create and Destroy are the only public methods that are part of the framework; the others are unique to the example. Correct? Spot on! There is both a command queue and a message queue. I couldn't find the message queue used anywhere. Is this an artifact of the development process or is there an intended use for it? In most cases all you need is the command queue to send commands into the process, however there are situations where you would want the process to message up to the public level. I'm a little confused about the occurrence you use in LaunchProcess and CloseProcess. Both vis have a "Wait on Occurrence" before exiting with a 1 sec timeout, but there's no action based on whether or not the occurrence was set. Is this just a placeholder to show where to put code that does need the occurrence? In the launcher there is a wait on occurrence, and that occurrence is the 1st thing that is set when the process is launched. We want a situation that when the launcher has completed execution the process is confirmed to be up and running. So the launcher waits until the process is live. The same is true for the close process, it waits until the occurrence is set when the process shuts down. I see you've set up the methods and controls with dynamic dispatching and protected scope. Have you tried creating a generalized ActiveObject for the core functionality and deriving child objects for specific implementations? I've tested inheritance and all works as expected, you can have parent active object and call its constructor within a child and the parent process is launched. Take a look at the Bike example, although the Bike is not active you could make the Bike active and the Racer would inherit the active capabilities of the Bike. A good example where you could use this is to make a general server class and the child is protocol specific. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.