Reference Design Content

Showing results for 
Search instead for 
Did you mean: 

Extensible Session Framework (ESF) Library

by Active Participant David S. on ‎07-30-2010 01:30 PM - edited on ‎03-09-2017 01:17 PM by Active Participant Christian_L

LabVIEW Framework for Creating Session-based APIs

 

The Extensible Session Framework (ESF) is designed to help create APIs that provides access to or control of a "session". That session could configure and control an instrument (like an IVI session), it could manage a communication link between two processes or devices on a network, it could open and manage a file in memory...we don't limit what a session is allowed to do, as long as it's characterized by the definition "a period of time devoted to a specific activity".

 

Description

 

The framework uses a single LabVIEW class -- your API is a child of that class -- to add several features to your API. It does this via two functions that are named "Obtain Session" and "Release Session" by default.

 

  1. Multiple instances - You can create multiple unique instances of your session, each with a unique string name to identify it. So if you have a session named "Serial Waveform" and want to generate multiple different serial messages in your program, you can do so by simply creating multiple objects and naming them uniquely.
  2. Multiple accessors - Because the sessions are uniquely named, you can obtain a reference to any session that already exists from anywhere in your application space. This is analogous to the behavior provided by LV Notifiers and Queues.
  3. LV Class features - Your session is implemented as a class in LabVIEW, so you get all of the features of classes: encapsulation and inheritance, password protection of private methods, and native property nodes.
  4. Simple interface to C and TestStand - The session handle is a DVR to your class. This means that your methods, when called from TestStand or C/C++, only have to pass an integer (the DVR) to the caller. This is much much simpler than passing a cluster.

 

"Obtain Session" and "Release Session" are required in your API, but you can rename them and edit most of their behavior to act however you like. The attached slides provide a description and list of benefits. The demo projects are also attached as examples of using the framework.

 

Installation

 

VI packages for ESF are provided below and the latest version is available on the LabVIEW Tools Network VIPM repository.

 

  • Version 1.1 supports LabVIEW 2009 and later
  • Version 2.4 supports LabVIEW 2011 and later

 

The attached ZIP files contain additional examples showing APIs implemented using ESF.

 

Support

 

Please post questions, comments and feedback in the comments below.

Comments
Trusted Enthusiast Trusted Enthusiast
Trusted Enthusiast

PPTX Slides?  Seriously?  How about those of us who don't have the latest version of Office?  Can't it be made available as either PPT or PDF?

Trusted Enthusiast
Trusted Enthusiast

If you have an old MS Office version, use this. otherwise, wait for the PDF

http://www.microsoft.com/downloads/details.aspx?familyid=941b3470-3ae9-4aee-8f43-c6bb74cd1466&displa...

Active Participant David S.
Active Participant

Thank you TiTou. I don't have a PDF generator on my system (to my knowledge), so please use the plugin if you can.

Member Drew.Rankin
Member

There's also OpenOffice convertor, but the MS ppt viewer/convertor works pretty well.

Active Participant LabBEAN
Active Participant

Thought old versions of Powerpoint would open PPTX.. (apparently not)  Anyhow, here's a free viewer:

http://www.microsoft.com/downloads/details.aspx?FamilyID=048DC840-14E1-467D-8DCA-19D2A8FD7485&displa...

Member RMThebert
Member

Alternative to PPTX available in MS PowerPoint 2007 save as ODP = Open Document Presentation.  This can be opened in OpenOffice or MS PowerPoint.  I use this because I go between WinXP and Ubuntu Linux occationally, or to and from Windows machines that don't have MS Office.

The MS PowerPoint 2007 save as menu also has a publish to PDF option.

..

I think the Framework for session APIs is an excellent idea.  Is the multiple accessors feature fast?  Faster than GOOP call by reference?  There is an OpenG combination of a Queue and Notify, is this session API built on the LabVIEW Queue and Notify?

Active Participant David S.
Active Participant

Thanks for the tips on document choice and exporting tools. I'll go ahead and upload a PDF to replace the PPTX.

If you peek inside the "Obtain Session" VI in the template class, you'll see that this is built on the LV Notifier.

Member Drew.Rankin
Member

So I have begun implementing this framework; however, I am only using a single instance right now.

Coming from a .NET OO background, the terminology of accessors and using the notifier took a little bit of learning; however, after I translated things into more of a hybrid between LVOOP and .NET, I am getting the hang of things.

What I really like is the call by reference for the class data structure. I plan on implementing a fairly large data structure in the main application so I will have more opportunity to write accessors at that time.

Overall, this framework is something that has been missing for me to be able to make the transition to LVOOP. When I have a chance to sit down, I will write a more thorough review/critique of what I went through getting started. I have not updated to LV10 so I won't have access to the property nodes, but I don't think it would be much different than how I am implementing public properties in the project.

David, thanks for posting this.

Drew

Active Participant David S.
Active Participant

Fantastic! I am extremely interested in your writeup. Feel free to start a new Discussion and link it here if you think it'll spur lots of dialogue.

Member Burt_S
Member

-Burt

Member Drew.Rankin
Member

I see Burt's email, but the comment is missing. He was talking about class instantiation and having to pass in default data to the class for subsequent instances.

On my first use of this framework, I only passed in one variable, in my case, the comm port I was using. Any other variable that I needed to assign, I created property nodes to access different variables in the class data structure. I could modify the obtain reference vi to accept a boolean that allows me to instantiate the class without passing in any variables. This is going to be the case if I have already instantiated the class and just want to make reference to it.

The second project I used this for was in a wrapper of a C library that created handles for each component of the driver. In that case, I never have to pass in anything on init as the library automatically takes care of this. One way to automate the creation of comm ports without sending initialization data is to scan for active com ports then ask for the identity of the connected device. If the manufacturer ID matches the pattern for the class, then you could assign the com port or ID to the class instance and go on from there.

One thing I did notice that is very important is that the reference to the class does not create a new instance of the associated VI's in the class unless the all the class VI's are created as re-entrant. This is a big difference between the Session Framework and .NET class instantiation. In .NET the whole class is re-instanced for every Dim foo as New ClassObject is evaluated. For me this is an issue when creating multiple instances of a class object that accesses VISA resources, but using the ESF is no different in this case than conventional methods. Calls to a particular VISA resource need to be managed with semaphores or some other method to ensure that multiple VISA queries do not have data collisions.

Overall, once I completed the proper setup for the framework and the enclosed examples, I have been quite satisfied with the framework and am using it on a fairly sizable project to manage three different device drivers. I have not looked over the main part of the application yet, but I will probably leverage ESF to handle most everything in the application.

Member NJKirchner
Member

Drew et al.,

If there is an error passed into the release session call it does not do the cleanup, which is contrary to how the common primitives that these are based upon operate. Also there is an issue w/ the force cleanup in this scenario. I'll try to get a patch out asap, but keep an eye out for issues in your system if an error is passed into the cleanup until then

-Norm

Member Drew.Rankin
Member

Data Accessor Creation Macro, ie. Property nodes:

The data accessor creator macro does not recognize that you are using a data by reference when creating your read and writes. I know this is not a function of the ESF and is probably easier to handle in LV10, but it would be REALLY sweet if there was a data accessor macro for the ESF.

Also, I did a local fix for the error handling on session destroy which is just to not pass the in coming error terminal to the disposal code. I guess I could have used and error merge for the incoming error and any errors.

Drew

Member NJKirchner
Member

{MODULE UPDATE}

All,

Please note that the package has been updated to 1.1.0.5 which encompasses some minor changes and bug fixes including the aforementioned error handling issue.

This is a non-destructive update which does not add functionality.

Please download the updated version.

Active Participant D60
Active Participant

Dear NJKirchner!

Thanks!

Member GoofyWires
Member

Hi,

I'm using ESF in order to get a singleton TaskID from my hardware which classes are organized under HAL, thus, the lowest class in the hierarchy implements a write vi to a certain device while obtaining a specific TaskID from the device for that specific task.

What is the proper way to use ESF in a class that needs to use such a TaskID from a specific session I created:

1. init obtains a session and saves it in the class control while write.vi takes this session from the control and uses getTaskID.vi which is implemented in ESF (from the template) to get the TaskID from within the session.

2. init obtains a session and like in 1 doesn't close it yet neither does it save the session in the class control, the class control saves only the session's name. Each vi like write.vi will do an obtain according to the session name, get the TaskID like in 1 inside an in place structure (unlike in 1) and release the session outside of the in place structure (writen like the template from the session yet appears in the class that uses the session and not inside the session as getTaskID is. The close vi releases the session and since this is the last one open the DVR/Session is closed since we get to 0 in the Root count.

I need to know that the TaskID won't be used by two vis simultaniously. Does one of those ways break the singleton by allowing someone else to obtain a session with a parallel TaskID?

Am I right that the second way is better since the in place structure behaves like a semaphor over the TaskID and that the Trace toolkit will be able to monitor that system better since I have different session/notifier for each call?

Besides that, do I need to create a session for each type of TaskID that I need (input/output for each device) or can I use a single session with many TaskIDs or should I use inheritance of sessions?

Thanks in advance,

Dror.

Member Drew.Rankin
Member

Dror,

I have been using this framework quite often. I think that based on your description, either method will work, but I think it depends on how you are configuring your hardware. If you are opening a seesion to your DAQ device on APP init then closing that session on APP close, method 1 makes more sense to me.

For each DAQ session you wish to create, the best way is to create a new class instance. Each class is organized by name and has exclusive rights to the associated device. I have used ESF to control motion, DAQ, and power supply functions without any interference between instances of the base class.

The best way I can describe how the ESF works is that it is like a named queue where you can refer to the queue by name from anywhere in your application and no other queues have access to the same information.

Perhaps a liberal application of caffene will help me give you more coherent answers, it is early after the holiday.

Below is similar to how I have used ESF in the past. You can put the "DAQmx Create Virtua lChannel.vi" in the "initialize Session Data.vi" and return the TaskID to the class structure. The TaskID is carried throughout the application by reference, not by value.

UsingSessions.png

Drew

Member GoofyWires
Member

Hi Drew,

the two options I described are inside each of the sequences from your jpg.

Here is a jpg of those two options (saving the session name vs saving the session itself inside the HAL class):

ESF - singleton versions.JPG

If I understand correctly you are using option 2 yet I need to know why.

Thanks,

Dror.

Member Drew.Rankin
Member

Dror,

It looks to me like you are wrapping a class within a class. I think this is over complicating things, unless you have an app class which contains references to the device classes and everything else about the application. I have done this before, but use ESF for the app class as well. Option 2 is definitely cleaner to implement and you have the reuse of the root ESF structure throughout the code.

The biggest problem I have had with the use of classes in my code is that everytime you drop a class object on the block diagram, it is a new instance of the class and does not know about any other instances. So, in your init/close above, you would have to wire "output cluster" directly to "Class 1.lvclass 2" for the code to work. That part of data flow programming is sometimes frustrating to me and is why I was not using LVOOP for so long. At some point, you almost have to use LV2_Globals to store informationin them to pass around the application, unless you are using ESF which can be refered to by name with an "Obtain Session.vi" refering to an already existing session.

Incidentally, ESF was the stepping stone to get me using LVOOP more often; however, I still have not gotten the hang of dynamic dispatching, which I think is a very cool thing and allows for easily scalable code; however, as of right now, I haven't had an application where I could practice inheritance of the "parent-child" relationships because the class structures are very different between the classes that I have been creating.

Hope that helps,

Drew

Member GoofyWires
Member

Drew,

I'm dealing with a very large scale app and having the class Class 1 call anelement of another class like ESF is normal, the second example is inside Class1 as well even though you don't see it.

I do have a framework that calls each device if it is needed for thespecific logic the user runs. Why is option 2 cleaner? Why do you say that inoption 1 I don't have the reuse of the root ESF structure throughout the code?

It seems like you are using ESF for every class in your implementation,which seems odd to me. It gets a little time but you get used to passingclasses by val and it works just fine without moving to by ref or passingclasses through ESF.

As for the inheritance, that too needs some time to get used to however youcan't turn a DVR/reference connection into a dynamic dispatch one and thatmight be a problem if you hate passing by val classes.

Anyhow, back to my question, I guess I need the opinion of someone who worksin the same style as I am. Here is a corrected version of the implementationoptions that shows where version 2 gets the session from:

ESF options.jpg

Member Drew.Rankin
Member

Dror,

I have quoted your original questions:

"I need to know that the TaskID won't be used by two vis simultaniously. Does one of those ways break the singleton by allowing someone else to obtain a session with a parallel TaskID?"

I think you may break the Singleton; however, the DVR node does block access to the refered memory location. Also, keep in mind that if another process tries to access the same memory location, there will be an error and the currently running vi might crash.

Why not just pass the TaskID as part of the parent (HAL) class?

Are your TaskID's unique on init?

"...o I need to create a session for each type of TaskID that I need (input/output for each device) or can I use a single session with many TaskIDs or should I use inheritance of sessions?"

I would create a session for each TaskID required and treat each as a completely different piece of hardware.

"Am I right that the second way is better since the in place structure behaves like a semaphor over the TaskID and that the Trace toolkit will be able to monitor that system better since I have different session/notifier for each call?"

Yes, I think you are on the right track.

Drew

Member NJKirchner
Member

Gentlemen,

I don't have too much time at the moment so please forgive the brevity.

First, dynamic dispatching is possible on DVR classes! (but only through the property node interface.

Second, although not as clean, your first implementation although not as clean as number 2 is a better implementation because #2 will open you up to a flurry of potential race conditions.

Also, don't forget you can wire a daqmx task or physical channel to the name terminal of an esf session. It will just take the string representation of the thing.

If you want to do option 2 won't  the right thing to do is to make a single session method that does the session lock, data access, modification, and data setting and finally the unlock. Just make this 1 vi and you won't have the danger of data corruption.

I am actually doing practically the same thing in one of my rf frameworks and it works well.

~Norm

Member GoofyWires
Member

Hey,

If I understand correctly then the ESF gives me many handles to the same object which is then manipulated only through the vis inside the session (from the vit).

The reason for this is the same as in FGV, if a FGV contains only read/write that the entire calculation is not atomic and prone to race conditions.

Since all the vis in the session work through an in place structure the calculation is atomic and no one else can run the same calculation at the same time.

However, there are two problems with that:

1. another vi in the session might access the same data at the same time and cause a race condition if called in parallel.

2. In this way the singleton object must be the session instance itself which can inherit only from the root, thus, making it hard to create a hardware abstraction layer.

The solution to both problems is making the obtain work more like in the case of the singleton with queues were the obtain won't return until the singleton was released.

In other words, I want the ESF to always release only one handle and wait until that session is free. This will allow us to use the ESF only to hold a singleton data and not act as a singleton object itself.

Am I correct in my diagnosis? How should I change the ESF to do that?

Thanks in advance,

Dror.

Member NJKirchner
Member

I think that you are misunderstanding the way that the IPE structure.

By using a DVR and IPE, you Prevent the ability for 2 things in parallel to operate on the same piece of data.

The IPE locks the DVR until it exits

On the second point, perhaps I'm misunderstanding your use case.

If you only want one thing to have an active reference at once....thats a bit of different paradigm that what I'm trying to accomplish with ESF

If you wanted to do this, then I would say modify your obtains to provide that functionality. (The autocreated obtains were never inteded to be the end-all-be-all of their codebase).

There could be some other things that could be modified in the core, but I would really need to see a strong strong argument in favor of a functional change like that.

Active Participant cirrusio
Active Participant

Awesome framework that solves several problems that I have had.  It is also spawning some discussion that everyone should be aware of, most notably that over at LAVA:

http://lavag.org/topic/18593-self-persistent-by-reference-class-instance/

Member NJKirchner
Member

Thanks for the kind words.

I replied on LAVA but long story short, persistent ESF sessions are going to be enabled in the already developed ESF 3.0

This will be an optional feature with will be default off to preserve reverse funtionality    

~,~

Member Shehzaada
Member

Hey guys! Great library! I'm just wondering...how do I create a Class hierarchy out of the ESF Framework? I have a bunch of devices for example that I want to communicate with, and they are all very similar. In this case, they communicate over the CAN protocol

So I would want to create a base class called CAN Device -> with methods like Initialize Device, Write Identifier, Send Message. Each new device is merely a child of this class.

However, when I make a ESF class called CAN Device, and then make a child Class and change the inheritance, LV complains that the Obtain Session VI of the Child class attempts to override a static VI. As mentioned in this thread, I don't think we can do dynamic dispatch on References, which is what ESF is built on.

Any idea guys?

Active Participant cirrusio
Active Participant

Shehzaada,

You don't necessarily want to use this framework in the way that you are proposing.  Rather than making a CAN device that inherits from this class, you want to make a CAN device that is composed of this class.  In your case, the ESF would handle the CAN communication and that session could be shared amongst multiple CAN device objects that utilize that connection.  The Init method would configure and open the CAN session and the Close method would shut the connection down properly.  All of the message implementation would take place within the device object rather than in the session.  Confused?

Matt

Member Shehzaada
Member

Hi Matt,

Thanks for the response! That's the implementation I have right now. What I was after was using the CAN Device as an abstract class and implementing all the common methods in it (Initialize, Send, Recieve, Close). Then I wanted each new CAN device to use these methods in their own implementation (upcast).

Thanks for the clarification though. I have seen other people have a class hierarchy for this stuff (even using DVR/References..).I wonder how it works.

Active Participant cirrusio
Active Participant

If all you are trying to do is create an abstract class - just do it.  You don't need this.  What this would be useful for is if you have a reference such as a connection, file, tcp/ip session that you want access to over multiple domains.

Each implementation of the ESF is contained within it's own DVR and acts as a singleton.  The ESF essentially only handles a single reference, doling out access as requested.  Since the In Place Element structure used to access the DVR (or propertie nodes) will be blocking, you can be assured that two attempts to communicate are not going to step on each other.  A counter keeps track of the number of references checked out, so it knows 1) when it has to init and 2) when the connection can be closed.  Viola!  Inversion of control.

Member NJKirchner
Member

I would have to disagree with Matt a little on this one.

You definetly can use inheritance with this framework and it can make sense in a variety of implementations.

I do agree with him, that you can indeed make a session class and then simply store a class object of a different hierarchy within it to enable what  you want. ESF woudl facilitate creating an API which gives the desired features, and your other class would facilitate the CAN.

That kind of paradigm is appropraite in certain situations where  you'll be calling different methods at the top level based upon what specific child you'll have instantiated up front.

However, if your API will 99% consist of the same calls regardless of which child implementation is invoked, then using an inheritance hierarchy of ESF is a good way to go. Its being used as such a lot @ NI in such a manner.

The way you would do this is create a class as you normally would through the Tools>>Create New Session Class menu item

This will be  your public API

Then you create a new class without the Tools menu dialog and manually inherit from your newly created ESF class.

From there  you'll create the appropriate override VI for Init session data and whatever else you like.

Keep in mind, that you won't override the "Obtain" or "Release" VI.

Anything that you want specific to happen in obtain or release should happen through the Initialize session data or Clear Session Data.

Very likely, you'll end up creating a Unique Obtain for each new class, but name them differently. There is no reason you can't because at the end of the day, the user will need to uniquely select which implementation they are desiring at edit time. Ususally putting them in a Poly VI works great from a user interaction standpoint

If you want the selection of which specific child to use at runtime, there are other ways of making that happen, either through a factory method in the obtain before the ROOT call, or by following Dave's idea of composition of your class within the session; in which you set the stored object at runtime to a specific class

Hope that makes sense

~,~

Norm

Member Shehzaada
Member

Awesome, thanks so much for your help!

Member Shehzaada
Member

That's pretty much exactly what I was looking for! Thanks a lot NJKirchner! I'll try it and let you guys know how it works out.

Active Participant cirrusio
Active Participant

Norm,

I think maybe we are talking at cross purposes; of course you can and should(?) use inheritance with this - that is not what I am suggesting.  And I guess now that I look closer, I would understand that you could do what Shehzada is suggesting.  But, I am asking - why?  It seems that you are defeating a key benefit of the framework. 

CAN is a communication mechanism.  You can open a session to a bus and communicate with multiple devices on that bus.  The benefit of the ESF is that you now have a reference to the bus handle of which no device is directly in control of.  And, you could place all of your communication with a particular device into the class itself and still get all of the benefits of that inversion of control.  But, why would you?  Let's say that further down the line you have another set of devices for which the communication between the controller and the device itself in no way resembles the communication protocol with the current devices.  The Init and Clear methods that you have written for the CAN bus can now no longer be easily reused and you now have to generate new code for the communication as well as duplicate that exact same code for creating and destroying your CAN sessions.  This just seems like not good practice.

In my use (and I am using this all over the place), I have something that looks like this in terms of hiearchy:

ESF Example - New Page (1).png

As you can see, I don't avoid inheritance, I just think it better practice to use composition rather than straight inheritance. 

Anyways, that's my two cents.

Cheers, Matt

Member NJKirchner
Member

Truth be told, I often tell people to avoid relying on inheritance to solve their problems and go to composition instead. Its too easy to slip into a very bad situation that requires a restructuring.

For his situation, I think you could go either way and it depends on how static he predicts the top level API will be.

and if at some point he needs another parent in the chain between ESF ROOT and CAN, that's an easy change.

There are plenty of times for inheritance off of the ESF session that was created by the user. Some I mentioned before.

To round off the discussion; for an API, use ESF, leverage inheriance but lean towards architecting composition more often than not.

But it would be wrong to say that it's rare or a bad move to utilize inheritance off of your created session class.

Thats the knowledge.

The wisdom is knowing when to make one call over the other

Active Participant cirrusio
Active Participant

Thanks, Norm.  I think for a lot of OOP newcomers, the tendency is to build very deep systems (I know this was true for me).  I think that is the only thing that I struggle with in this context.  But, like you say - the wisdom is know when to do what...

Active Participant cirrusio
Active Participant

Anyone know why this was taken off of the VIPM repo?

Active Participant Christian_L
Active Participant

I checked with the group managing the VIPM repo at NI, and according to our records the ESF package was never posted to the repo. Is it possible that you manually added the VIP file to your local VIPM library and assumed that it came from the LV Tool Network repo?  I will check the latest version of the VIP and submit it to be added to the repo soon.

Active Participant cirrusio
Active Participant

Hmmmmm...not sure.  Thought I installed through the repo.

That being said - ever thought about making it directly available through the repo?

Active Participant Christian_L
Active Participant

Yes, we will review it and most likely post it soon.

Contributors