LabVIEW Development Best Practices Blog

Community Browser
cancel
Showing results for 
Search instead for 
Did you mean: 

Re: Designing LabVIEW Applications Using Plugins for Scalability and Flexibility

Elijah_K
Active Participant

The use of plugins in the design of software provides an elegant and popular solution for a lot of common architecture challenges, especially when dealing with a set of several similar but different components. The encapsulation of functionality into a plugin is intended to make it easy to manage and define the behavior of a component without modifying the calling framework. It also helps enforce a number of other best practices concerning the modularity and scalability of an application.  To illustrate this, we'll be taking a look at designs that make use of a factory pattern and LabVIEW Classes, concepts we'll spend more time on in a minute.


For LabVIEW programmers, plugins can provide an especially scalable mechanism for large systems that have to interface with a wide variety of hardware - especially when the hardware may vary across different systems, or has to be regularly changed or added to.  Because of this, a plugin approach can help mitigate the costs and risks associated with hardware that becomes obsolete and has to be replaced, making plugins an integral part of almost any Hardware Abstraction Layer (HAL). This also makes it possible for development to proceed concurrently on separate parts of the application with minimal or no risk of impacting unrelated parts of a project, something which is especially useful when dealing with large teams.

5-8-2011 2-09-30 PM.png

Another example of the benefit of a plugin-based approach is a complex user interface such as an options dialog or a wizard-like dialog. As an example, consider the LabVIEW options dialog, which makes use of plugins. It displays different interfaces depending upon what software is installed. Like the hardware scenario, you have a set of similar objects that have different functionality and you want to be able to change, add or remove functionality without modifying any code that is above it in the application hierarchy. This brings me to a very important point... a plugin architecture inverts the dependency you would see in a statically linked application. This is typically referred to as the dependency inversion principle.  This principle states (source: wikipedia)

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.

To understand the dependency inversion principle, consider a large, monolithic application whose dependencies are entirely statically linked.  Top level components are dependent on the VIs it calls, which are dependent on the VIs they call.  As a result, modifying the lowest-level component can create changes that propagate up and at the very least, require recompiling the entire application or rebuilding the executable. If the code is entirely statically linked and monolithic, it tends to expose developers to additional risk when making changes because standard APIs and communication with other components has not been defined in an abstract way.  In a well designed application, the dependency is inverted such that a set of low-level components (ie: plugins) are actually dependent on the calling framework through standard APIs and communication mechanisms.  As long as these are maintained, the plugins can be modified and developed without impacting any callers.  These same abstractions and APIs make it equally possible to modify the framework without recompiling or changing the plugins - again, this relies on those abstractions remaining the same.

So how do design an application to use plugins in LabVIEW? Before jumping to a solution, there are several very important things to consider (this is not an exhaustive list):

  • will they be loaded upon initialization or during execution?  Is a delay at the start of the application okay, or should it be a background or on-demand process?
  • what information will the framework need to send the plugins?  Will commands dispatch a VI or send a commandthat the plugin handles?
  • what information will the plugins need to send to the framework?  Should commands return an acknowledgement?
  • will messages need to be broadcast to all the plugins?  If the number of plugins is potentially large, queues might not be an ideal communication mechanism. Consider user events.
  • how much functionality will be reused across plugins?  Consider putting this functionality in a parent of a class hierarchy, allowing all children to easily make use of it.
  • how will plugins be installed and organized?  Should they reside in a folder on disk, set a registry variable or be built into the exe?
  • should users be able to modify plugins?  What deployment format should be used?

And perhaps most importantly, how do you define what goes into a plugin versus what is owned by the framework?  The answers to all of these will obviously vary based upon your specific use case, but there are some common approaches that we will look at.  For starters, plugins are almost always going to be loaded dynamically, be it at initialization or at the request of some operation during execution.  In general, the act of loading a plugin is either done by bringing a VI or set of VIs into memory, or by loading a class. All of them make use of the Factory Design Pattern, making it one of the most important design patterns to familiarize yourself with.

LabVIEW Classes are an especially powerful way to create plugins. If the plugins all need to make use of some similar functionality, this can easily be encapsulated in the parent and reused by the various plugins. If plugins need to further customize or extend the default behavior, they can override the dynamic methods.  Instead of dynamically loading a new VI for every dynamic method, the use of a class hierarchy means that the act of loading a new child brings all the associated methods into memory, which can then be dynamically dispatched. The image below shows the simplified UML for the UI Plugin Framework's plugin class hierarchy.  Note that the 'Generic Plugin' class defines functionality that can then be reused by all of the children.  All of the children override the 'Configure Plugin' method, but they selectively override the other methods, depending upon what they need to do.

5-9-2011 7-26-29 AM.png

I've uploaded several examples of a plugin framework to this community page for you to explore.

  • Basic Subpanel Options Dialog - this is a very simple illustration of how you can dynamically load VIs as plugins. In this case, the plugins are a VI which is displayed in the subpanel, much like the LabVIEW Options dialog.
  • LabVIEW Benchmarking Utility - this is a utility that allows users to create and add their own benchmarks for comparing LabVIEW and executables written in other languages. Each benchmark is a plugin.
  • User Interface Plugin Framework - this plugin framework shows how LabVIEW classes can be used to represent the individual plugins. This framwork uses Dynamic User Events to broadcast or unicast messages to registered listeners, eliminating the need for individual queues. It also makes use of an API that is defined by the parent class of the plugins, which is then reused by the various children.
  • Hardware Abstraction Layer - this simple example loads different plugins depending upon the configuration that is specified in an XML file. It abstracts the measurement tasks in avery simple test application to exemplify a hardware abstraction layer.

In the next entry, I'll discuss the use of User Events for sending messages to the plugins.

Elijah Kerry
NI Director, Software Community
Download All
Comments
FraggerFox
Active Participant

Could you post a LV2009 version of this example?

-FraggerFox!
Certified LabVIEW Architect, Certified TestStand Developer
"What you think today is what you live tomorrow"
Elijah_K
Active Participant

Absolutely. I posted the original example in 2011 by mistake. I've added an example in 8.6.

Elijah Kerry
NI Director, Software Community
Member

Hello Elijah,

     I liked the subpanel idea so I was trying to re-use it in my current project to replace a tab control with more or less thirty pages. And each of those pages is associated to the attributes of a class that specifies the attributes of a more generic class. My problem with this approach is its maintainability.

     So, switching to the subpanel pattern. It's simple to load a subpanel based on a class but my problem is to establish an efficient data communication mechanism because I want the main VI to receive the class object of the sub-panel with it's new configuration parameters.

     So basically a subpanel would be a sub-vi of my class that updates the class properties but once it's done how could I recover the data?

     Am I applying the right pattern to solve my problem?

Thanks

Luiz Carlos Maia Junior
Elijah_K
Active Participant

It sounds like the right patterns to me.  Have you looked at the User Interface Plugin Framework as an example of plugins with communication?

Elijah Kerry
NI Director, Software Community
Member

took a look at the example, and I see that you used queues to do the communication, in my case I would like to 'give control' of the object being modified to the subpanel, so, is it possible to send a class reference through a queue so that I no longer need to maintain a two way communication?

Luiz Carlos Maia Junior
Elijah_K
Active Participant

That is a really interesting idea, and it should work great.  You'll have to be wary of any deadlock that could occur when modifying references in multiple locations at the same time, but I think it could work well for the sake of two-way communication.

Elijah Kerry
NI Director, Software Community
Member

Thanks Elijah!

And about your user interface plugin framework, what if LabVIEW had support for polymorphic methods on the same class? (maybe it has and I'm not aware of it)

That could simplify your code I think. You wouldn't have to create one class just to implement one method to make use of the dynamic dispatch.

Just a thought that crossed my mind.

Luiz Carlos Maia Junior
RayFarmer
Trusted Enthusiast

Eliijah not sure what version this is for but can you provide a version I can load in LabVIEW 2009

Regards Ray Farmer

Regards
Ray Farmer
Elijah_K
Active Participant

Unfortunately, this example uses features that are only available in 2011 or later.

Elijah Kerry
NI Director, Software Community
PaulRijk
Member

Hi Elija,

How do I create plugins for an executable in such a way that I can add new plugins to an existing executable without the need for re-compiling.

I should like to just send a new plugin to a user of my appplication instead sending a new executable.

Regards,

Paul Rijkers

vishots.com
Member

Why not just build a new executable? What would be the benefit in your case? I'm asking this because I think you will find that the work involved to accomplish this goal is much more than the benefits you will get.

PaulRijk
Member

We have an application that is distributed to several customers in different flavours.

It would be nice to be able (e.g.) to add the possibility to handle a new device for some customers.

When using plugins we don't have to check which flavour the customer has when we can just add a new plugin and just send the file(s) needed.

crossrulz
Knight of NI

Then you will want to look at Packed Project Libraries.  These will take a lot of planning and upfront work to get them to work properly.  But when done correctly, your main executable does not change and you just send the compiled ppl to the customer.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
PaulRijk
Member

I will do so.

Thanks for the tip!

LuI
Active Participant
Active Participant

Michael Aivaliotis wrote:


                       

Why not just build a new executable? What would be the benefit in your case? I'm asking this because I think you will find that the work involved to accomplish this goal is much more than the benefits you will get.


                   

Michael,

consider you need approvals for your code, which include a lot of tests with external devices and UUTs. In such cases it is probably worth the effort to keep the main app in approved state and 'just' get approval for the added PlugIn and its cooperation with the main app.

Not that I was able to reach that goal with my test systems, but I am still trying ...

Greetings from Germany!

--

UF

Gab008
Member

User Interface Plugin Framework    link is not working. Anyone has idea where can i download this example?

Kuddo welcomed
CLAD-CTD
leahmedwards
Member

@Gab008 wrote: 
User Interface Plugin Framework    link is not working. Anyone has idea where can i download this example?

Probably 4 years late, but I think it is the attachment here.