LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

AF LVOOP - Property node returns other value as related accessor

Solved!
Go to solution

Hey guys,

 

my colleagues and me are developing a large scale AF based industrial testframework that is heavily relying on AF, OOP, packedlibs and advanced OOP design patterns like Mediator-based message distribution.

 

Currently I am stuck on a problem that I just cannot solve. I have a base class called epActor, which stores and AF Enqueuer to the mediator actor. This enqueuer can be accessed using an accessor. Now the problem is, that at a certain point of the code I use a property node to read the Mediator enqueuer from the current Actor's private data and I get a "Not an Enqueuer" refnum here. When doing my debugging I found that at the point where the property node is called, the accessor "Read enqMediator.vi" is called correctly and also outputs a valid refnum (I checked this using Custom probes using the "Equals not a refnum.vi" of the Message Enqueuer Class).

Now this is the point where I am confused. When the accessor is called correctly (which somehow under the hood seems to be triggered by the property node) and when this one outputs the correct value, why does the property node output an empty enqueuer?

 

Did anyone ever have a similar behaviour?

Here is the code where this is happening:

Jenso_0-1720000721395.png

And here is the related accessor:

Jenso_1-1720002128224.png

While the refnum is still valid in probes 4 and 5, it is already invalid in probe 1.

Now here are my thoughts and experiments about this problem:

- The mediator actor (the enqueuer's target) is still running at the time when I receive the value for probe 1 (i tested that with breakpoints)

- There is no child or parent class that uses a property of the same or comparable name

- Both MediatedActor (the one who executes the code above) and Mediator are part of a packed lib, which have been reworked a lot of times, so there might be a bug there aswell, but the principle has been running fine for half a year. Using packedLibs should not be the basic problem.

- I have done multiple Mass compiles and "Clear Object Cache" actions, which did not change any of the behaviour

- Used LabVIEW Version: LabVIEW 2021 64Bit f6 21.0.1

 

Any ideas are appreciated, because honestly I lack in having new ones right now 🙂

 

Thanks in advance!

0 Kudos
Message 1 of 9
(172 Views)

I have no experience with AF but looking at the pictures you posted I want to ask:

What happens in ActorID, which is executed before enqMediator? Is there a possibility that this VI changes the class data (e.g. due to a for loop running zero times without a shift register or a "use default if unwired" case of a case structure)?

 

0 Kudos
Message 2 of 9
(156 Views)
Solution
Accepted by topic author Jenso

One other idea that came to my mind.

If the 'ActorID' VI (which is called by the property node) is returning an error, I think 'enqMediator' VI will execute the 'error case'. This will return a default value ('Use default if unwired') for your object.

But I am not really sure if the error handling inside the property node is working that way.

Message 3 of 9
(128 Views)
Solution
Accepted by topic author Jenso

That is how it works by default. You can right-click the property node and check "Ignore Errors inside Node" to override this behaviour. The property node then gets a red error out terminal.

 

You can also right-click on the specific property and select "Open Accessor VI" to get to the correct VI.

 

Individual properties are named after the Property Definition Folder in which they are located (the ones with the wrench).

 

cordm_0-1720016894720.png

 

Message 4 of 9
(118 Views)

I would remove the error case structure from your accessor. That gets put in by default, but in general I've found you almost never actually want it.

 

In your case, you'll return "Not a Refnum" if there are upstream errors. Maybe you want that to happen, but generally when simply reading a refnum you always want to get the actual value even if there ARE upstream errors.

 

Read Self Enqueuer doesn't even HAVE an error input for presumably this reason.

 

Accessor VI's must have an Error In and Error Out to be used as a property node, but they don't have to have the structure inside. Just wire Error In to Error Out.

 

(You may rarely want to actually have an Error case handler inside of an Accessor for "accessors" that do some actual work behind the scenes. For example, you may have an "accessor" style function that actually reads something from a database, or sends a hardware query to a device. In those cases you might actually need them to not do anything if there are upstream errors.)

0 Kudos
Message 5 of 9
(103 Views)

Ok, so first: You gave the right hint. There indeed was an error in the read accessor of "Actor ID". Removing the error did the trick.

But second: I would have expected the Read EnqMediator to run the Error case but it did not. That was why I did not search in that direction. Seems to be working somehow different under the hood.

0 Kudos
Message 6 of 9
(79 Views)

And I also did not know about the ignore Errors in property node... that is very interesting, though I think it is somehow bad practice to do so. I would have expected LabVIEW to open its typical error popup window, just as it does for almost everywhere. But even though I set it to react to unwired errors, no error showed up...

0 Kudos
Message 7 of 9
(75 Views)

Now I have tried to reconstruct the behaviour in a dedicated test project but I see a different behaviour there. The error pops up correctly, just as expected, and the follow-up accessor VI (the next property below the error generating) does not even execute.

So the troublesome behaviour seems to be related to the current packed lib structure. I will try to investigate that.

 

Anyway thanks for your helpful suggestions!

0 Kudos
Message 8 of 9
(70 Views)

I would STRONGLY recommend disabling automatic error handling, especially for Actor-based systems. Automatic handling sometimes makes things behave oddly, and doesn't do anything in a built executable.

 

Getting a robust error handling solution is definitely the better way to go here. It doesn't have to be anything super complicated, but trust me it will be worth it in the end.

 

The super basic strategy I like is "Handle errors as close to their source as possible". If you can't recover from an error, then recontextualize it to something more informative, and pass it up the chain.

 

For example, if I have an actor that's using VISA to control a serial port, and it throws an error when trying to get access to the serial port, then it's unrecoverable by that actor. Whoever called that actor needs to handle this by informing the user that the port they selected isn't available.

 

By "recontextualize" the error, I simply mean to interpret the error differently. The error itself will likely be a cryptic VISA error message that's not useable by anyone other than a programmer. So, instead of saying "VISA Connect error 12345" I say "Error obtaining serial port", and have the actual error message either logged somewhere or hidden under a "Show full message" button or something.

0 Kudos
Message 9 of 9
(41 Views)