I recently got introduced to the LabVIEW Extensible Sessions Framework (ESF). Since I’ve written many custom driver libraries for my projects over the years this object-oriented approach immediately made sense to me. I’d like to take a moment to write down some things that I have learned while writing my first ESF based driver that I wish I had known upfront.
Using the mechanisms of ESF to initialize
There are two ways how you could initialize your session: Passing the parameters to Obtain Session.vi and handling the initialization there and using Obtain Session to obtain the reference and then having another VI to update the parameters. Both valid, but the question is: Where does the next developer expect it?
To answer this question it also didn’t help that the ESF Timer Demo has both methods implemented, but it becomes clearer and in the end, there are three use cases.
- If we dive into Obtain Session.vi, we’ll find a VI reference to initialize Session Data.vi. This is a very handy VI, which automatically gets called when the session is created and only then. Subsequent acquisitions of the session reference will not call this VI. The drawback is that the data for the initialization is the class data, so if you need some config information that you don’t want to save in your Session Class, e.g. redundantly storing measurement ranges and timing information, then this is not the way to go.
- The second option is to run the Obtain Session.vi and let your references be uninitialized until you run your own init.vi. This has several drawbacks:
- Additional Error handling is required to cover the cases, where the init.vi is passed an invalid reference.
- You’d need an additional VI call, so instead of simplifying your driver you add complexity to it
- If you do need to pass configuration data to your session, but don’t want to store it in the class data, you can add the init.vi to the Obtain Session.vi. That way you offset the drawbacks from (2) and maintain your API clean.
The choice then is clear: If you need data during initialization (3) is my goto. If it’s a case where I can initialize with default values and don’t want to change the configuration at the start, I’d use (1)
The one VI that you’ll always end up writing
One of the most exciting features of ESF is the capability to acquire a session reference from anywhere in your code. This would allow for one section of your code to start the Session, e.g. your hardware, and for a completely different section of code to access that hardware without the need to explicitly pass the reference between the two parts.
It’s fairly simple if you look into the Obtain Session implementation of the root class. It checks for a Queue by name and if it doesn’t already exist, it creates it, if not, it’ll return the reference for you.
You might be tempted to run a benchmark on obtaining the session by name, as was I and I found that the VI managed to find the session and return it in less than 1 ms (0.009 ms in 1000 iteration average), so you could do this in every session. However, the better practice is to acquire the reference and use it in subsequent iterations. So You’d end up writing something similar to this VI, which obtains the session reference only if no valid session has been passed to it and also lets you auto release sessions if no valid session has been found. This is helpful if you don’t want to run on an uninitialized session.
Keeping track of all your sessions
The multi-session functionality might make it hard to track how many sessions are open and make sure all of them get closed properly at the end. Since the Session root class contains a counter for the number of Live handles it will know when the last session has been closed and then clean up. Ideally, you would be running the Release Session after every thread that uses the Session handle and whoever is last will clean up. Sometimes you might want to just end all threads from a single place. For that, the Framework has the force destroy built into the Release Session.vi, which will destroy the queue and end all subscribed threads. You then only have to handle Error 1556 indicating an invalid DVR refnum. You can then use this error to inform or shut down any active loops that are still using your driver.
It’s OK to use constants
When mentioning constants people often thoughtlessly dismiss them, so hear me out. If you’re writing a driver that will only ever exist as a singleton in your system, it makes no sense to ask the user for a session name. It is a built-in feature of the ESF to allow for multiple clones of the same session to run in parallel. If you don’t need that functionality you can just make the Session Name Input a constant and not worry about it later on.
However, it might be wise to keep it around. ESF is- after all- built to make it easily scalable.