LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How can I create a subVI that has state?

I'm trying to simplify a VI that I inherited and I noticed a recurring pattern that IMHO should be a subVI.  The pattern is that we have a digital output line that is controlled by a timer.  Each output has a start time for it to activate and a duration after which it is turned off.  When the state changes, a single line entry is added to a common log file and an indicator shared variable is set so that the remote host VI updates.  We have a big while loop that checks the current time against each of the activation conditions.  To detect when the state has changed, we're using a shift register (for each actuator).  It's one thing to see the same pattern 3 times, but it's worse -- we want to sometimes use a different number of actuators.  If I was writing this in C++ (with which I'm far more comfortable than LabView), I'd write a class for the actuator and instantiate it N times.  The class would have member data to keep track of its state.  I can create a subVI that does the meat of the design pattern, but I can't figure out how to store the previous state in the subVI without requiring it to be passed in.  How do I keep the state and behavior of a VI together?  Surely there's a way to do this because otherwise I can't see how you could implement state-ful algorithms like, say, a PID controller.  But I'm at a loss to figure it out ...

Thanks.
Keith.

0 Kudos
Message 1 of 7
(3,079 Views)
You can create classes in LabVIEW 8, or you can use an "Action Engine" as detailed in this Community Nugget.
Message 2 of 7
(3,074 Views)
Wow -- that's a lot of info to digest, but I think the LV class is exactly what I want.  However, I only see an option to create a new class on the host side, not the RT target where I need it.  If I create it on the host, can I use it on the target?

0 Kudos
Message 3 of 7
(3,059 Views)
OK, I've implemented a simple LV class.  Coming from C++ land, this is familiar and seems like the Right Way to do what I want.  I have a data member that stores the previous state and a VI member that compares the new value and detects the change.  However, the only way I was able to use the new class and get it to work as I expected was (in the VI using it) to create an instance of the class outside of the while loop and wire the object to a shift register so that the previous state is available on the next iteration.  The shift register was what I was trying to avoid!  But now that I've read up on LVOOP, I see that there is no such thing as pass-by-reference for classes, so every wire is essentially a copy.  From what I've read about USRs, it appears that they are global and would not keep separate state between object instances.  So if I have more than one instance of my class, they would all share the same USR state -- which would be bad.  So I'm coming to the realization that I cannot avoid the shift register.  Is this correct?  But at least I can construct an array of objects and have a single shift register, which will still be orders of magnitude cleaner than what we have now.

0 Kudos
Message 4 of 7
(3,045 Views)

The shift register is your friend.  The wire is the variable.

When constructing an array of objects, remember that arrays must be of the same type.  However, to keep wires (and shift registers) to a minimum, you can use clusters.  Clusters can hold various data types.

R

0 Kudos
Message 5 of 7
(3,031 Views)
To save state in a subVI and not use that state in other subVI calls, make the subVI reentrant.  When a subVI that is reentrant is called it creates a unique memory space for that subVI.  This is called a clone.  That memory space is where state is held for that subVI.  Keep in mind that it also means that the memory footprint is going to be larger.

To set a subVI to be reentrant, open it and go to File -> VI Properties and select execution.  It will be a choice on the bottom left.

Hope that this helps,
Bob Young

0 Kudos
Message 6 of 7
(3,003 Views)

The reentrant option is what you want (and if you want to do it dynamically, you can call the Open VI Ref primitive with the reentrant flag), but you should note that you can create by-ref classes by using wrappers and you even have an example shipping with LabVIEW.

This won't help you, however, since LVOOP does not currently run in LVRT.

P.S. You can find an example of calling an action engine by ref here. This will work across machines as well if you enable VI server access.


___________________
Try to take over the world!
0 Kudos
Message 7 of 7
(2,993 Views)