Example Code

Configuration Editor Framework (CEF)

Products and Environment

This section reflects the products and operating system used to create the example.

To download NI software, including the products shown below, visit ni.com/downloads.

    Software

  • LabVIEW

Code and Documents

Third-Party Code Repository

Some users manage their code in repositories outside of ni.com. Use your best judgment when following links to third-party sites. http://download.ni.com/evaluation/labview/lvtn/vipm/packages/ni_lib_config_editor/

Description

Overview

Application configuration is a large task for application architectures. In an attempt to make system configuration easier for designers as well as end-users, configuration editors are often implemented. In this document we cover the Configurator Editor Framework which is a starting point for creating a custom configuration editor in the LabVIEW Development Environment. The framework consists of a tree control and subpanel API, 2 LabVIEW project templates, and 2 abstract LabVIEW classes. The example configuration editor described in this paper is for creating a configuration tool for an embedded data logging system, but the framework can be used for creating other configuration editors for automated test, machine control, or other applications. In this document we cover the use of the basic template, the core concepts of the framework, and the hierarchical template added in version 2.0.

Description

System configuration is used to store and access semi-static data in an application which describes the hardware and behavior of the application. Configuration reduces or eliminates the need to edit source code when a user wants to:

 

• Make changes to parameters
• Change hardware specific information
• Adjust specific application behaviors 
• Customize applications for a specific use

 

The data for a configuration is stored in a file or database. At run-time, applications open the data from a file or database, rather than having the developer hardcode the information into the source. Time and money is saved by removing the need to validate new source code.


When editing configuration the user can work directly on the file with a text editor, excel or other file editing programs. General purpose file editors can work for simple applications, but forcing users to use these non-specific tools makes configuration hard to understand and error prone.


Configuration editors are typically graphical user interfaces (GUIs) that enable a user to create/edit configurations so that the resulting file conforms to a format that an application can interpret. By enabling and limiting the interactions of data in a configuration the user can create a scalable and maintainable way to store information. Using a configuration editor provides several advantages:

 

• Information can be input in application-specific ways
• Invalid configurations can be restricted by the configuration UI
• Decoupling the programmatic requirements from application requirements, makes it easier for users to visualize a complex system
• Version management can be handled by the configuration tool
• Multiple file formats can be supported as the system evolves
• Large numbers of configuration parameters can be adjusted more easily 

 

Configuration Editor Common Features

National Instruments products include many examples of configuration editors. Measurement and Automation Explorer (MAX) is a configuration editor commonly used to configure NI Hardware. Figure 1 shows the GUI for MAX.

 

 

Figure 1 NI MAX Graphical User Interface

 

 

Another configuration editor is the LabVIEW Project Explorer. The Project Explorer saves the information as an XML file with the extension “.lvproj”. Even LabVIEW has a configuration file called “labview.ini” which is stored as human readable initialization file which can be edited through the options dialog.

After reviewing the above configuration editors, four common elements can be extrapolated. These elements are displayed in Figure 2.

 

  • There is a graphical way to navigate through the configuration. Typically this is using a tree control.
  • After we navigate to a node in our tree data structure, we can edit the data stored at that node. Typically this is through another window (floating or attached).
  • Nodes in the tree data structure can be added, duplicated, removed/deleted, and moved to another location in the tree data structure.
  • There are multiple methods of setting the configuration (single element, multiple element or importing an external configuration)

 

Figure 2 Common Layout for a Configuration Editor

Hardware and Software Requirements

Steps to Implement or Execute Code

Install Toolkit:  This link will launch VI Package Manager and install the latest CEF package.

Alternative Download:  If you require a direct download, you can access the VIP file from our FTP directory. We recommend the VIP file with the highest version number or most recently modified date.

 

Implementation

The ultimate goal of this framework is to provide the majority of features required to make a configuration editor while still leaving enough flexibility to customize the editor for specific applications. The framework accomplishes this goal by providing a tree control API in LabVIEW as well as an easy way to have different views of the same data. Although the framework promotes a tree control as main way to visualize the configuration, custom views can be created.

The central part of the Configuration Editor Framework is the repository (repo). The repository is the location where all configuration parameters are stored while editing. Interaction with the repository occurs through the tree, the configuration file, and any custom views developed.

 

The tree view consists of a tree control and tree API. The file “view” is used to store information from the repository in a persistent file or to load that file in order to populate the repository. This view is also typically the component which is used on the final, deployed system.

 

Any additional custom views provide different ways to visualize and interact with the repository separate from the tree. For example, a project might require a table view for different variables in the system, so a multiple variable editor view could be developed which meets this need.

 

In order to pass data between the different views, configuration data must pass through the repository. This interaction is shown in Figure 3.

 

Figure 3 CEF Repository and Views relationship

 

Project Templates

When the CEF is installed, two project templates will be added to the new project wizard, the Configuration Editor Project template and the Hierarchical Configuration Editor template.

 

The configuration editor provides all the basic features of the CEF, and provides the most flexible option but requires more programming.

 

The Hierarchical Configuration Editor template has some of the classes defined and implemented for the user. This includes the repository class, the tree node, and the file operations. This allows users to create projects faster but puts rules and limits on the behavior of the editor. In addition, this project doesn’t include the custom view implementation. Most applications will benefit from the additional code in this template.

 

Figure 4 Hierarchical Template implemented classes

 

Repository Class

The repository is where configuration information is stored in the editor. Repository developed for your project can contain additional information and auxiliary data structures for the different views. The repo is implemented as an abstract class and all its methods are expected to be overridden by a child class that the developer creates. The following are the provided class methods. Although the framework is open source, most developers will not need to know about the supporting subVIs.

 

VI Description
Open Loads the saved information into the repo. This could load multiple files at the same time. An option to add file versioning could be included in the files, and the code to manage changes would be in this VI.
ReadTree Transfers information between the repo and the tree control nodes. This is called before custom views are launched or saving to disk.
Save Stores repo information to file. It could save in multiple files or formats at the same time. File versioning is suggested.
Validate An abstract method for validating the information inside of a repo is accurate. This method should be called before saving the information to file.
WriteTree Transfers information between the repo and the tree control. This method should be called after the custom views are called or saving to disk.
Initialize Initializes the repo. StoreClassPath method should be called in this VI
CustomView Calls the custom view specified in the view name string. The purpose of this method is to allow adding a Configurator editor without modifying the main VI.
GetClassPath Gets the path to the Class based on the Class Name. The default behavior is build the path of the class on top of the class folder path. The name of the class and the folder it contains needs to be the same. A simple lookup from index and name would be the other option.
StoreClassPath Stores the paths and classes name that the repo use. The default behavior is to store the path to the main folder containing the classes and expect all classes to be in folders with the same name as the class. If a more complex file structure is required this file needs to find all the classes and store the name and path pairs.
Validate Placeholder for creating system wide validations.
GenerateMenu This Vi is called when creating a new repo, and creates the file menu for the configuration editor
HandleMenu This vi should be overridden if any additional menus were added in the GenerateMenu.vi

Table 1 Repository.lvclass Methods

Serializable Configuration.lvclass

This is an abstract class created to store information for specific nodes, and is used in the hierarchical template.

 

VI Description
to string Flattens to a String.
from string Unflattens from a string.
create default alias This is the display name that is default in the tree for the hierarchy node. The parent implementation is to use the class name.
create new identifier Called when initialized creates a new UID (unique identifier).
destroy This Vi is for cleaning up references if used inside of the class.
duplicate This will call when duplicating a class.
validate Validates the configuration.
execution class name This is used when the configuration class has a runtime component. Having this VI allows that the same configuration class can be used with different runtime classes.
dynamic initialize This the portion of initialize that can be overridden. The initialize method contains methods that must be executed every time and should not be changed.
instance count allowed Tells how many instances of the class are allowed on the system.
refresh and repair This is called by the right click menu on the tree with the option repair. It is called inside the Attempt Repair.vi
callback on load This VI should be called when loading the class for example in the FromRepo.vi

Table 2 Serializable Configuration.lvclass Methods

Hierarchy Repo Class

This class, also referred to as the “tree repository”, inherits from the repository class. The only Vis that should be overridden from this class are the ones that are also part of the repository class. And in most cases there should not be any need to create child classes for this class. To access and interact with this class an API has been created shown in Figure 6 Hierarchical Repository API

Figure 5Hierarchy Repo Private Data

 

Figure 6 Hierarchical Repository API

Node

The concept of a node is implemented as an abstract class. As with the repo class, developers are expected to create classes that inherit from it, for every node type their configuration editor. Every leaf of the tree will be represented by a node. If multiple leaves have a lot of functionality in common an abstract class should be created.

 

Each node is accessed by reference using a Data Value Reference (DVR) and stores the reference to its parent node and all its children. The tree control stores this reference as a string.

 

VI Description
Duplicate

Implements the specific behavior of a node when it is being duplicated

Can be used to change the name of the new node for example adding Copy to it.

ToRepo Transfers the information from the tree node into the repo. How it is stored in the repo depends on the Repo.
FromRepo Grabs information from the Repo and stores it in the nodes.
UIRef Stores the static reference to the UI of the node.
Initialize

Initializes the data of a node to its default state.

The object is not created inside of this VI, because it is created from a File depending on user selection.

ShortcutMenu Defines the behavior of the shortcut menu of the node.
EditOptions

Contains the options for the Menu that will be displayed when doing right click on an item.

The sub nodes class configures which nodes can be added to this nodes

And the edit options determine which options are available for the node.

 

This configuration is stored in this VI in case some dynamic configuration is required for the menu options or sub nodes.

GetText Returns the text representation of the node used for the tree control.
LinkNodes Links 2 nodes together one as a parent and one as a child.
UnlinkNodes Breaks the link between a child and a parent node. Removing the reference to each other in both nodes.
NodeUI UI that will be called when the node is selected.
InnerCallbackOnLoadUI There is a static VI that is callback on Load UI, by doing this it will allow to add extra functionality when loading the UI.
GetOverlay Specifies which pre-loaded overlay to add to the Glyph.
AddGlyphtoGManager Optional Override that adds any necessary glyphs to the editor. The parent implementation searches the local directory for available .png files.
RemoveChildfromNode This vi runs inside of the UnLinkNodes and allows complex functionality.
AddChildtoNode This vi runs inside of the LinkNodes and allows complex functionality.
MenuHandler This should handle custom menus for the Node.
CleanUpNode Is the dynamic dispatch of the RemoveNode.

Table 3 Node.lvclass Methods

Serializable Node

This class inherits from Node and contains a serializable configuration object. The FromRepo and ToRepo classes are already implemented. In most cases the only overrides that will be required when using this node will be the UIRef, create a new UI and the GetText VIs.

 

 Figure 7 Serializable Node

 

Getting Started with the Configuration Editor Project template

This section explains how the example classes were designed and created using the Configuration editor template. The classes described in this section of the document are included when creating a new project as a reference. In your application they can be removed or modified freely.

 

In this example we have a simple configuration file which consists of an array of channels stored in binary format. This same data can be represented multiple ways. The editor allows us to have 4 different representations of the configuration data. This is shown on images Figure 8, Figure 9, Figure 10, and Figure 11

  
Figure 8 File Representation

 

 Figure 9 LabVIEW data

  

Figure 10 GUI Representation

 

 

Figure 11 Multiple Channel Editor Representation (custom view)

 

1) Creating an new project

The Configuration Editor Framework is distributed as a sample project.

  Figure 12 Create Project from template wizard

 

The following project will be generated:

 Figure 13 Configuration Editor project

 

2) Creating a Repository

The repo is the central place for your data and it allows it to travel between views, in general a simple repo will contain the cluster or LabVIEW representation of your data. In addition you want to add all the other auxiliary data structures that will be useful for your repo.

 

In the this example we created the cRIOrepo.lvclass which contains two elements, the array of channel clusters we will save to disk, and a placeholder temporary channel that would be used to store information when sending information to the repo.

 

In the case of the cRIO repo we override the following methods:

 

  • Open: Here we are read the configuration from a binary file. Then we verify that it is the right version of the configuration cluster. If not, it generates an error.
  • Save: Saves the repo information into thebinary file.
  • Write Tree: Creates a cRIO node object to be used as root and calls the from ToRepo method of the node.
  • CustomVIEW: Calls the MultipleVariableEditorUI.vi, which is the custom view created for this configuration editor.

In addition to these VIs, data access VIs were made so that it is possible to access the information inside the repository to the rest of the application.

 

Creating a new repository

 I) Right click on the class’s folder and select new class

 Figure 14 creating new class

II) Name your class and save it to disk.

III) Inherit from Repository.lvclass

a) Select class properties

b) Select Change Inheritance

 

Figure 15 changing inheritance

c) Inherit from Repository.lvclass

  

Figure 16 selecting new inheritance

 

3) Creating Tree nodes

When we are working on the tree control, each different element on the tree needs to be represented by a class. All classes should inherit from the Node.lvclass.

 

The methods that will be overridden will vary for each class. In this example we need to create cRIO.lvclass, group.lvclass, voltage.lvclass, and current.lvclass. Because both voltage and current are channels and have several properties in common it makes sense to create an abstract parent class for both channels called channels.lvclass. This also makes it easier to add additional channel types in the future.

 

The class hierarchy is shown in figure 17.

 

  

Figure 17 node class caption

cRIO.lvclass

This node will act as the root node in the editor.

  • Initialize: Sets the system name to the default value cRIO.
  • EditOptions: Provides a list of available nodes which may be added as children, in this case the “group” class. Because it is used as the root it cannot be removed, duplicated or dragged, and these features are also set here.
  • ToRepo: Stores the system name in the auxiliary channel data and initializes the channel array.
  • FromRepo: All channels belong to this class, so FromRepo gets the group name from one of them and searches for the name of the different groups in the array.
  • GetText: Sets the glyph to cRIO glyph and uses the group name as the text.
  • UIRef: Returns a reference to the cRIO configuration UI.

 

Group.lvclass

This node can contain multiple channels of all both channel types and the only property it has is the group name.

  • Initialize: Sets the Group name to the default value (Group).
  • Duplicate: Adds the word copy to a group name that had been duplicated.
  • EditOptions: Provides a list of available child classes, in this case current and voltage channels. The group can be removed and duplicated, but can’t be dragged.
  • FromRepo: In this VI the channel array is scanned to search for all the channels that should belong to the group.
  • ToRepo: Stores the group name in the auxiliary channel data.
  • GetText: Sets the glyph to group glyph and uses the group name as the text.
  • UIRef: Sets the reference of the UI to GroupUI.

 

Channel abstract class

This is an abstract class and is never displayed in the tree control. It defines most of the methods for the channels than inherit from it.

  • Channel UI and Channel UI Ref: Defines the UI that will be used for all channels. If a specific channel needs a different UI the UI ref can be overridden.
  • EditOptions: Allows the channels to be moved, removed and duplicated, and specifies there are no children available to be added to the channel node.
  • GetText: Sets channel name as the display text and a default glyph is used in case a child channel doesn’t specify it.
  • ToRepo: The complete channel information is populated using the values of system and group from the current channel auxiliary data, and writes that information into the main list of channels
  • FromRepo: Using the index stored in the from repo cluster, gets all the channel info from that index in the main channel list.

There are two data access method VIs which allow you to get the data in the view cluster format or in the channel cluster format.

 

Current channel and voltage channel

These channels inherit most of their methods from the Channel abstract class. The only specific VIs for these classes are Initialize and GetText.

 

  • Initialize: Sets the channel name and the channel type to the specific ones of the corresponding classes.
  • GetText: Sets the glyph to the correct value and uses the text method from the parent, which by default returns the name of the channel.

 

1) To create a new tree node

 a) Right click on the class’s folder and select new class

 Figure 18 creating new class

2) Name your class and save it to disk.

Note: The Configurator expects all classes to be stored in a single folder which can contain one or more subfolders.

3)  Change Inheritance

a) Right click on the class and select class properties

b) Select Change Inheritance

  

Figure 19 changing inheritance

c) Inherit from from NISE_CEF_ node.lvclass

  

Figure 20 selecting new inheritance

 

4) Save to disk.

 

4) Creating the custom view

It is often more convenient to edit multiple channels at once, so the sample project has a custom view that is a multiple parameter editor.

 

For creating the multiple parameter editor we override customview.vi to call multipleparameterUI.vi

 

If more than one custom view is required you can use the view name string and use a case structure to select between the different options.

 

6. Getting started with the Hierarchical Configuration Editor template:

This section explains how the example classes were designed and created using the Hierarchical Configuration editor template. The classes described in this section of the document are included when creating a new project as a reference. In your application they can be removed or modified. This example does not include the custom view as this concept does not apply to a generic hierarchical configuration. If the hierarchy is known, a custom view could be developed.

 

 1) Creating an new project

 

The Hierarchical Configuration Editor Framework is distributed as a sample project shown in Figure 18.

   

Figure 21 Create Project from template wizard

 

The following project will be generated:

  

Figure 22 Hierarchical configuration Editor project

2) Repository

With the Hierarchical project there is no need to make any changes to the repository in most situations. If it needs to be edited, the procedure would be the same as creating a repository on the Configuration Editor Project template, except that it should inherit from NISE_CEF_HierarchyRepo.lvlcass.

3) Creating Tree nodes

When we are working on the tree control, each different element on the tree needs to be represented by a class. All classes should inherit from the Node.lvclass. Also every node should have a configuration class. But the same configuration class can be used for similar nodes.

 

The methods that must be overridden vary for each class. In this example we need to create cRIO.lvclass, group.lvclass, voltage.lvclass and current.lvclass. Because both voltage and current are channels and have several properties in common it makes sense to create an abstract parent class for both channels called channels.lvclass that will be inherited by both voltage and current. This also makes it easier to add additional channel types in the future. Because this uses the hierarchical template, the configuration classes for group, cRIO and channel are also required.

The class hierarchy is shown in figures 20 and 21.

 

 

 

Figure 23 Node Class Hierarchy

  

Figure 24 Configuration class Hierarchy

cRIO node root.lvclass

This node will act as the root node in the Configurator. Note that using the hierarchical project, you do not have to implement the ToRepo or FromRepo methods.

  • Initialize: Sets the system name to the default value, cRIO. It is stored inside of the cRIO configuration class.
  • EditOptions: Provides a list of available nodes which may be added as children, in this case the “group” class. Because it is used as the root it cannot be removed, duplicated or dragged, and these features are also set here.
  • GetText: Sets the glyph to cRIO glyph and uses the group name as the text.
  • UIRef: Returns a reference to the cRIO configuration UI.

 

cRIO configuration.lvclass

 

Figure 25 cRIO configuration private data

 

Only property we are interested in at the cRIO level is the system name. The system name field is stored in the private data of the configuration class.

 

group node.lvclass

This node can contain multiple channels of all both channel types and the only property it has is the group name.

  • Initialize: Sets the Group name to the default value (Group).
  • Duplicate: Adds the word copy to a group name that had been duplicated.
  • EditOptions: Allow to add sub nodes consisting of current and voltage Channels. The group can be removed and duplicated, but can’t be dragged.
  • GetText: Sets the glyph to group glyph and uses the group name as the text.
  • UIRef: Returns the GroupUI VI reference.

 

group configuration.lvcass

 

Figure 26 group configuration private data

 

Only property we are interested in at the group level is the name. The group name field is stored in the private data of the configuration class.

 

Channel node.lvclass (abstract)

This is an abstract class and is never displayed on the tree control. It defines most of the methods for the channels that inherit from it.

 

Channel UI and Channel UI Ref. Defines the UI that will be used for all channels. If a specific channel needs a different UI the UI ref can be overridden.

 

EditOptions: Allows the channels to be moved, removed and duplicated. And specify no sub nodes can be added to them.

 

GetText: Sets channel name as the display text and a default Glyph is used in case a channel doesn’t specify it.

There are two data access method VIs which allows you to get the data in the view cluster format or in the channel cluster format.

 

channel configuration.lvclass

  

Figure 27 channel configuration private data

 

In here we created the fields for all the relevant information for channel as well as access methods to this information. In addition there are overrides in the following methods:

 

validate: this VI performs a simple validation check, making sure the sensor ID is not empty.

from string: This VI includes code for version management and serialization of the channel configuration.

to string: This VI flattens the data in the configuration cluster and adds versioning information.

 

Current channel and voltage channel.lvclass

These channels inherit most of their methods from the Channel abstract class. The only specific VIs for these classes are Initialize and GetText.

 

Initialize: Sets the channel name and the channel type to the specific ones of the corresponding classes.

GetText: Sets the glyph to the right value and uses the text data from the parent (which defaults to the channel name).

 

 

 To create a new tree node

 1) Right click on the class’s folder and select new class

 

Figure 28 creating new class

2) Name your class and save it to disk.

Note: The Configurator expects all classes to be stored in a single folder which can contain one or more subfolders.

3)  Change Inheritance

a) Right click on the class and select class properties

b) Select Change Inheritance

 

Figure 29 changing inheritance

 

c) Inherit from from NISE_CEF_serializable node.lvclass or NISE_CEF_serializable configuration.lvclass

 

Figure 30 selecting new inheritance

 

4) Save to disk.

5) Repeat steps 1 to 4 but inherit from NISE_CEF_serializable configuration.lvclass

6) Add the Serializable configuration class inside of the private data of the Node class

 

Figure 31 Node Private Data

 

7) Add the methods in the node class to access the configuration class (Read Configuration and Write Configuration)

:smiling_face_with_sunglasses: Add the information you want to store inside of the configuration class

9) Add methods to access this information.

 

Additional Information or References

This reference application was created by the NI Systems Engineering group. 

Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.

Comments
jaws13fr
Member
Member
on

Hello,

CEF is great, do you have a simple example of reading data in the generated File ?

BR,

Enrique.Noe
Member Member
Member
on

Also interested

marco.daurelio.peivm
Member
Member
on

Hello,

 

This framework is very useful; it requires practice to handle it properly, but once you grasp its concepts you can use it in a lot of applications

However, with the current version (2.3.0.6) of the framework, according to my analysis it's not possible to:

 

- add child nodes automatically when a new node is inserted

- allow the user to add ONLY ONE child node of a specific class

 

Does NI SE have a solution to accomplish these tasks?

 

Thanks

 

Marco D'Aurelio

 

UMASO
Member
Member
on

Hello, 

 

How much is a class multiplicity of the association between "serializable node" and "serializable configuration"?  

 

Thanks!