NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

Get a permanent reference of the currently running sequence?

Hi,

 

I created a VI (StoreMyContext.vi) which is called from TS and has a context input. The plan was that TS will pass it's ThisContext to the StoreMyContext.vi which stores it in an FGV and later on I can use this context with the UseMyContext.vi to change values (for example local variables) in the sequence.

 

The ThisContext is passed properly to the VI to the StoreMyContext.vi

 

Proof: if I use the TestStand - SetPropertyValue.vi in the StoreMyContext.vi then I can change local variable values using the input ThisContext

 

Problem: it seems that the context as a reference to the sequence is only valid until the StoreMyContext.vi is running. If want to use the context in UseMyContext.vi the context is not valid after the StoreMyContext.vi finished its execution. If I not let the StoreMyContext.vi to finish (eg: adding a breakpoint to its end) then the UseMyContext.vi works fine, but again... only until the StoreMyContext.vi is running.

 

Experiment: I created a simple VI with a context input, which is converted to a variant and shown on the front panel. I called this VI twice from TS in the same sequence and observed the reference value. While the reference was certainly valid for the sequence, the value of the reference was different on the different calls of the VI in the same execution.

 

So the question is, can I somehow obtain and store a PERMANENT reference to the sequence which is valid all the way until the sequence is running? If not, what would be the right way to achieve the functionality I need?

 

Thanks.

0 Kudos
Message 1 of 13
(746 Views)

You are correct, ThisContext is only valid for a limited amount of time, that's by design since the context will change according to the state of the execution 

 

If you stated, what your use case is and what you want to achieve, we might be able to help you.

 

Message 2 of 13
(725 Views)

I agree with Oli. A few more details.

  • A SequenceContext is valid during the execution of a single sequence.
  • The context while running a sequence does have a reference to the actual sequence file, and a runtime copy of the sequence that is running.
  • Almost all these types of references under the context are released after the execution of that sequence completes.
  • The types of references that you could hold onto that are obtained from under the context are things like the engine, the sequence file, sequence file globals, and station globals, and there are some others.

Understanding what you want to do with the context post running a sequence would be helpful.

Scott Richardson
https://testeract.com
Message 3 of 13
(695 Views)

Understanding what you want to do with the context post running a sequence would be helpful.


I was thinking about passing the reference of the sequence file to labview VI which stores the ref. in an FGV. Then other labview codes running constantly can read/write local variables of the given sequence based on this reference.

 

As I wrote in my post passing the reference to the VI is not a problem, but it seems that as soon as the VI I called from TestStand (which I passed the reference to) finishes its execution the I can not use the reference to read/write variables.


I used the "ThisContext" reference, is that causing me the problem?

0 Kudos
Message 4 of 13
(668 Views)

Thanks for the inforamtion. Few thoughts from my side:

 


@1984 wrote:

Understanding what you want to do with the context post running a sequence would be helpful.


I was thinking about passing the reference of the sequence file to labview VI which stores the ref. in an FGV. Then other labview codes running constantly can read/write local variables of the given sequence based on this reference.

 

 


You don't need a reference to the sequence file (I know I am being picky on wording here). 

 

Rephrasing what I have understood: you want the possiblity to access local variables form anywhere in your LabVIEW code at anytime.. withoput access control. This would baiscally bypass all the mechanisms, TestStand has built in to ensure data consistency.

 

Welcome to the hell of race conditions and coupling!

 

I highly recommend to rethink you plans.


@1984 wrote:

Understanding what you want to do with the context post running a sequence would be helpful.


 

As I wrote in my post passing the reference to the VI is not a problem, but it seems that as soon as the VI I called from TestStand (which I passed the reference to) finishes its execution the I can not use the reference to read/write variables.


I used the "ThisContext" reference, is that causing me the problem?



ThisContext has a limited lifetime, because it gives you the context at this specific time in which the engine provides a certain amount of data integrety.

Message 5 of 13
(661 Views)

This sounded like "I know how to get what you want, but I wont tell" a bit.

0 Kudos
Message 6 of 13
(654 Views)

Surely , there is some (pick the negative adjective of your choice) way on how to achieve this, don't know one from th top of my head right now.

 

Since I am active in this forum to share my knowledge and to help people, I am definitely not giving tips on how to make software with definitive design smells.

I am not taking responsibility for giving you information that solve one problem and creates many others. And even possibly multiplying this by some AI consuming this and presenting it as a solution.

 

So all the help I am able to offer here is to recommend to rethink what you are doing.

Thanks for your understanding.

 

 

0 Kudos
Message 7 of 13
(643 Views)

Well, I guess a smelling but working app is infinitely better than non smelling but also non existing one.

 

I don't think anybody would hold anybody responsible on these forums because the person answered a question, even if the question was not a well educated one. But by practically saying that you wouldn't help - even if you would know the answer (but you don't) - because according to your evaluation the question is stupid, the impression is rather condescending.

0 Kudos
Message 8 of 13
(635 Views)


I was thinking about passing the reference of the sequence file to labview VI which stores the ref. in an FGV. Then other labview codes running constantly can read/write local variables of the given sequence based on this reference.


The scope of local variables is finite and limited to only when that specific call into the sequence. After completing the sequence call, the VI has a orphaned copy of the locals data. Subsequent calls to the sequence will create a new local variable that the VI does not have a reference.

 

TestStand does not support static variables that are local to a sequence whose values live beyond each call into the sequence.

 

I can think of 2 or 3 options for "sharing" data with a VI with any and all invocations into a sequence. 

  1. Define Sequence File Global properties and use ThisContext.FileGlobals instead of ThisContext.Locals within the sequence, and pass a reference to FileGlobals or the specific sub-properties under FileGlobals to that VI.
  2. Same as (1) but use a ThisContext.StationGlobals or ThisContext.Engine.TemporaryGlobals, see Engine.TemporaryGlobals.
  3. If there is a more parent sequence (in the same file or different file) that is lower in the call stack that has a lifetime that supersedes all the invocations to the sequence in question, you could pass the shared data as a reference parameter to the sequence and that sequence could give the pass the reference to the VI, and the life time of the data is shared until the more parent sequence invocation completes.

I personally would recommend (1) as the simplest to understand and implement.

Scott Richardson
https://testeract.com
Message 9 of 13
(615 Views)

I was thinking about passing the reference of the sequence file to labview VI which stores the ref. in an FGV. Then other labview codes running constantly can read/write local variables of the given sequence based on this reference.

The "running constantly" is a key bit of information. We're still having to infer some details here about what you're trying to accomplish.


We get it: the pressure's on for you to come up with a solution. We've all been there. Please remember that the folks helping you are volunteering.

These guys really know their stuff. (and I mean really know their stuff. The guys you've been talking to are some of the most knowledgable people on this subject matter. I'm not making that claim about myself.)

 

I'm volunteering, too, and I'm the crazy guy replying to you at 11:45 PM local time on a Friday night, pretty wrecked after finishing up my "day" -ha ha- job.)

 

It's easy to misinterpret someone's tone if all you have to go on is written text, but please cut Oli some slack and try to give him the benefit of the doubt.

There's some ambiguity here in the use case you're trying to describe and we're trying to fill in the blanks.

Based on the information he has, he really is trying to help you out by steering you away from an implementation that will likely create more work for you and confusion for other developers in the long run. ("engineering deficit")


Anyway... I'm going to try to wade through this to the best of my ability. This is all written exclusively by this human. No AI was employed.

 

Some Guesses and Inferences About the Use Case

I'm having to make a lot of assumptions about what you're trying to accomplish.

There are a lot of considerations here, and it's hard to narrow them down without more details, so we're taking a sort of broad, hypothetical approach.

If we explored all the possible unknowns with the use case, this could be a lengthy white paper. (No, I'm not doing that. Or am I? )

 

Here's my guess:

  • You have multiple VIs that are running independent of your test socket thread(s) and stay running indefinitely until something signals them to stop. (daemons?)
  • I'm going to assume that you have a good or justifiable reason for going to all this trouble and taking this approach.
  • It sounds like the daemon VIs are primarily producers of data, maybe reading from shared instruments, and the TestStand thread(s), maybe for test socket(s), are consuming this data.

WARNING: If the TestStand thread(s) are both reading data from the daemons and writing data to them, it's going to get ugly very quickly and I agree with Oli that you should really reconsider the big picture of what you're trying to accomplish. It's not condescension and it's nothing against you, it's just a direct answer.

 

Side note: If all you need to do is read the latest data from one of the daemon VIs, this gets a lot easier. You don't need to worry about persistently storing the data in TestStand. Just read the latest data from the daemon on move on. Otherwise, keep reading.

 

Push or Pull the Data?

Again, I'll assume your daemons are strictly data producers and the TestStand thread(s) are strictly consumers.

  1. You could either have your TestStand thread(s) poll (pull) the daemon VIs for values
  2. ... or you could have the daemon VIs publish (push) data to TestStand thread(s) / execution(s) by writing values to PropertyObjects (e.g. file globals, locals) from within the VI

It sounds like you want to take the second approach.

 

I've seen various implementations of this kind of thing, some outright hackery, most "kinda sorta" okay, and very few elegantly done.

One of the first things I did as a freshly minted TestStand developer was debug and rearchitect a pretty nightmarish approach to this because it was falling down constantly in volume production.

 

Possible Approaches

Having your daemon(s) publish data to locals in a given sequence is not what you want to do, because locals are by nature volatile and aren't designed to be persistent outside of a single execution of a sequence.

TestStand is fighting you on this approach and winning because it's doing exactly what it was designed to do. (Listen to Scott.)

 

If you're going to push data from the daemons into TestStand where it can be held persistently and consumed asynchronously by one or more threads, the best place to store the data depends on where in your code the consumers of the data are. To reiterate what Scott is saying (and I hope I'm getting this right, Scott):

 

Option 1:

If the consumers of the data from the daemon are in the same sequence file, then a file global might be the least complicated approach. The only thing that makes this a little tricky is that, if your VIs are running continuously, somehow you have to get a reference to a file global to the VI so that it can write data to it.

Note that Scott is saying that passing the sequence context to the VI is not the best idea.

 

Option 2:

This is kind of a crude approach, but it'll get you what you want with very little effort.

  • You could have the VI publish the data to StationGlobals.<variable name>, which is truly global across anything running in TestStand. In my opinion, use of station globals should be rare because a given station global should be shared and used regularly by any given sequence / sequence file, regardless of the specific test or application.
  • You can get the exact same functionality of a station global by using Engine.TemporaryGlobals, except the values don't persist between restarting TestStand. These are actually very useful because they're temporary and don't clutter up StationGlobals. They're also universally accessible by any code running in TestStand at any given time. This can be a blessing and a curse. (Oli mentioned race conditions.) If your daemon VI is only a producer of the data, there are multiple consumers, and synchronization doesn't matter, then this will work well.

Option 3:

From a purist's perspective, the "right" way to do it, but I agree with Scott in that it's not the easiest to understand and it's the most complex approach.

If I personally chose this option, this is how I would do it:

  • If you're running your test in the parallel or batch models, do the following, otherwise skip this step: In the sequence that you run to start the test at the very beginning, set the "shared" flag on a local variable in MainSequence (only in MainSequence) or a file global. The shared flag means that all threads in TestStand share the same value rather than having their own separate instances of it.
  • At the beginning of MainSequence, start up your daemon VI and pass it a reference to a local variable in MainSequence (only in MainSequence) or a file global.
  • If you're using the parallel or batch model, you'll have to put some synchronization in place so that only one thread launches the daemon while the other threads wait until it's running. If you're using the sequential model, don't worry about this.
  • Pass the file global or local by reference as a parameter to each sequence call so that all the sequences in the call stack have access to it
  • Since the daemon VI has a reference to this property, it can write data to it, and then any sequence call that has the property as a parameter can read from it.

 

I spent wayyyy too long on this and I may have just made it very confusing. I hope it's not, though, and I hope it's useful in some form.

If you appreciate this, please hit the yellow star to give me a kudos. (Do the same for others who help you)

 

Jim

Message 10 of 13
(600 Views)