Academic Company Events NI Developer Zone Support Solutions Products & Services Contact NI MyNI

Document Type: Tutorial
NI Supported: Yes
Publish Date: Sep 6, 2006


Feedback


Yes No

Related Categories

Related Links - Developer Zone

Related Links - Products and Services

Adding Custom Commands to the LabVIEW Operator Interface

3 ratings | 4.00 out of 5
Print

Overview

The Operator Interface provides a customizable interface for TestStand operations. The OI (Operator Interface) allows operators to execute sequences, configure test options, and view reports. The operator controls a test system application through commands. The Full Featured OI, which ships with TestStand, demonstrates a standard interface with the TestStand Engine. There are cases, however, where a developer would like to provide additional functionality to an operator. For instance, the Full Featured OI does not allow operators to change the limits of Numeric Limit Test step types. This tutorial demonstrates how to modify the Full Featured OI so that operators are able to set the limits of Numeric Limit step types. The modified OI utilizes custom commands and a custom context menu to provide the additional functionality.

Introduction

The Operator Interface is a programmable application interface for TestStand. TestStand provides ActiveX components that allow developers to build an application that will interact with the TestStand engine. The components are separated into visible controls and manager controls. The visible controls consist of components that facilitate user interaction with a test management system. These include custom controls such as the SequenceView and ReportView, as well as standard controls including buttons, list boxes, and menus. The manager controls are ActiveX objects that handle communication between the TestStand engine and the visible controls. User commands, issued through the visible controls, are addressed by the manager controls. The manager controls include the Application Manager, the SequenceFileView Manager, and the ExecutionView Manager. Each manager control acts as an administrator for different types of interaction. For instance, the SequenceFileView Manager owns a SequenceView visible control. The user is able to see and interact with the SequenceView control. Any user interaction is then handled by the manager controls, and the appropriate update is made to the data in the TestStand engine.



[+] Enlarge Image
Figure 1. The Full Featured OI implemented in LabVIEW.

Each visible control is capable of acting as an interface for the user to execute commands. Commands are handled by the relevant manager control, which then updates the dataset in the current instantiation of the TestStand engine. For example, a user can choose a specific sequence from the Sequence pull down menu. The manager will respond to the user selection and update the sequence in the SequenceView.

In the Full Featured OI, a context menu appears when the user right clicks on the SequenceView control. The context menu provides the option to change the run mode or run the step in interactive execution mode. Each of these options is a command that is issued to the SequenceView manager. The SequenceView manager handles the appropriate response to the command. If the user chooses the "Skip" command from the context menu, the SequenceView manager will update the step run mode in the TestStand engine. The result is visible under the "Flow Properties" column of the SequenceView.



Figure 2. The Standard SequenceView Context Menu.


There are cases where the developer may need to offer additional functionality to the operator. This tutorial demonstrates how to modify the Full Featured Operator Interface by adding a custom command to the Sequence File View context menu. Custom commands allow the developer to provide additional services to the operator. The standard Full Featured OI prohibits the user from changing the limits of a Numeric Limit Test step type. The context menu of the SequenceView is replaced with a customized menu including a custom command that allows the user to edit the limits of a Numeric Limit Test step. In order to implement this functionality, this tutorial will cover event callbacks, configuring a custom command, and finally implementing a custom command.



Figure 3. The customized SequenceView Context Menu.

Event Callbacks

ActiveX controls capture user interaction through events. An event is a notification that a specific action occurred. For instance, when a user clicks the mouse or selects a menu item, an event is issued. Events are also associated with method calls. Closing an application, for instance, issues an event. ActiveX controls handle each event through callback functions. Callback functions are sections of code which react to events. If an application closes, an event is issued, and the callback function, which handles application closure, is invoked. The developer implements code in the callback function that cleans up the application before closure. In LabVIEW, events are handled by callback VIs. Callback VIs are invoked when an event occurs.

Each callback is registered with an ActiveX control. Registering an event callback tells the control which function to execute when an event occurs. The LabVIEW Full Featured OI registers callback VIs in "Full OI - Configure Event Callbacks.vi". ActiveX controls, including the manager and visible controls, are assigned callback VIs for specific events. For example, the OI registers callback VIs for the "ExitApplication", "DisplayExecution", and "DisplaySequenceFile" events. The registered VIs are called when the corresponding events are triggered.

Events are registered using the Register Event Callback VI found in the ActiveX palette of LabVIEW. The Register Event Callback VI accepts three terminals including the event, the callback VI reference, and the user parameter. The ActiveX control reference is wired into the event terminal. A drop down selection is populated based on the available events for a specific control. The selectable events will change from control to control. A static VI reference is wired into the VI reference terminal. The static reference points to the callback VI that is called when an event occurs. Any additional data is passed in the user parameter terminal. For instance, a reference to an external ActiveX control may be used in the callback VI. The DisplayExecution event requires a reference to the ExecutionViewManager to update the ExecutionView. The user parameter terminal expects a variant data type. The variant data type is an ActiveX type that is generic. Any data type is convertible to and from a variant data type. Figure 4 shows the event callback registration from the LabVIEW Full Featured OI. The Register Event Callback nodes are chained together. Each control event is assigned a specific callback VI.


Figure 4. Register Event Callback VIs.

Building a Custom Context Menu

The SequenceView context menu allows the user to perform commands on steps within a sequence. Figure 5 shows a snippet of the code from the SequenceView Create Context Menu callback VI. This callback VI is invoked when the user right clicks on the SequenceView control. The context menu is generated and then displayed to the user. The callback VI includes four input terminals. "Event common data" contains data about when the event occurred. CtlRef refers to the ActiveX control that handles this event. "Event data" contains arguments that are specific to each event. Here, the menuHandle is extracted from Event data. The user parameters are setup when the callback VI is registered. This callback VI grabs the SequenceFileView Manager and Application Manager references in order to build a context menu.


[+] Enlarge Image
Figure 5. The Default SequenceView Context Menu.


After extracting the Application Manager control reference, the NewCommands method is invoked. NewCommands generates a collection where the developer can insert commands. Using the reference to the Commands object, the InsertKind method is invoked. This inserts one or more commands into the Commands collection. The first parameter of the InsertKind method is cmdKind. The cmdKind terminal expects an enumeration of different command types prefixed with "CommandKind_". For the default SequenceView, the "CommandKind_DefaultSequenceViewContextMenu_Set" is inserted into the Commands collection. This enumeration inserts several commands including the Run Mode command set, the Breakpoint command set, and the Interactive Execution command set. The entire set is placed into the Commands collection. Next, the InsertIntoWin32Menu function is invoked. Using the menuHandle extracted from the Event data, the Commands collection is used to build the menu. The menu is then displayed by the SequenceView control. When the user selects a specific command from the menu, the command is executed and the SequenceView is then updated. Tip: For help on specific ActiveX methods and properties, right click on any Invoke Node or Invoke Node, then select "Help For Method/Property".

Creating a Custom Command
  1. Before the Commands collection is created with the NewCommands Invoke Node, insert an Invoke Node on the block diagram. Wire the Application Manager reference to the reference terminal. Select GetCommand from the list of methods for the Application Manager invocation. Right-click the cmdKind terminal, and select Create -> Constant from the context menu. This generates an enumeration constant of different command kinds. Select CommandKind_Custom from the enumeration drop down select. The GetCommand instantiates a new Command object of a specified command kind.
  2. Place an Invoke Node on the block diagram and wire the Command reference from the GetCommand Invoke Node to the reference terminal. Expand the Invoke Node so that the Enabled, Visible, UserData, and UserObject properties are shown. Right click on the Invoke Node and select Change All to Write. This ensures that we are setting the properties. Wire true constants into the Enabled and Visible properties. This allows the user to see and select this command. The UserData and UserObject are variant data properties. The developer can assign any data values to these properties. When the command is executed, the data is extracted and used by the command function. Wire a numeric constant into the UserData property. The numeric value is a unique identifier for the command. This identifier is used to determine which command to execute when the custom command type is called. Wire the SequenceFileView Manager reference into the UserObject terminal. The SequenceFileView Manager is needed to edit and update the numeric limits of a step. Connect the error wire.
  3. Place an Invoke Node on the block diagram and wire the Command reference from the previous Command Invoke Node to the reference terminal. Select SetDisplayName from the list of Command methods. Create a string constant and wire it into the val terminal. This method sets the string that will be displayed in the context menu. Connect the error wire.
  4. Wire the error out terminal to the error in terminal of the NewCommands Invoke Node. Figure 6 shows the section of the block diagram for building a custom command.


Figure 6. Creating a Custom Command


Building a Custom Context Menu
  1. The NewCommands Invoke Node should already be on the front panel. Make sure the error wire from the SetDisplayName Invoke Node is wired into the input error terminal of the NewCommands Invoke Node. This ensures that the ActiveX calls are executed in the proper order.
  2. Replace the default InsertKind Invoke Node. Place two Invoke Nodes on the block diagram and wire the Commands collection object from the NewCommands Invoke Node to the reference terminal. Create a constant from the command kind terminals. Choose CommandKind_RunModeSkip for the first Invoke Node and CommandKind_RunModeNormal for the second Invoke Node. Wire a numeric constant into the insertBefore terminal with the value -1 in both nodes. This inserts the command after the last available slot in the Commands collection. Assigning a value above -1 will insert the command before that index in the Collections collection. Wire an empty string constant into the currentMenuName and allMenuNames terminals for both nodes. These terminals are used for Menu Bar items. Connect the error terminals together. These nodes provide the user with ability to set the run mode of a step. The developer has the ability to provide any command from the CommandKinds list within the context menu.
  3. Place an Invoke Node on the block diagram and wire the Commands collection to the reference terminal. Select Wire from the list of Commands methods. Wire the Command reference output from the SetDisplayName Invoke Node to the Item terminal of the Insert node. Wire a numeric constant with -1 into the insertBefore terminal. Connect the error terminals. This node places our custom command into the Commands collection. Figure 7 shows the section of the block diagram for building the Collections object.
  4. Wire the reference out terminal of the Insert Invoke Node to the InsertIntoWin32Menu Invoke Node. This call builds the menu from the Collections command.
  5. Place a close reference VI onto the block diagram between the InsertIntoWin32Menu and the existing close reference VI. Wire the Command reference from the SetDisplayName Invoke Node to the new close reference VI. This ensures that we close out the reference of the newly created command object. Wire through the error terminals to make sure the VIs are executed in the proper order. Figure 8 shows the code for Inserting the Commands collection into the menu.


[+] Enlarge Image
Figure 7. Building a Custom Context Menu




Figure 8. Inserting the Commands Collection into the Menu

Handling Custom Commands

Most standard commands are automatically handled by the ActiveX controls with which they are associated. Selecting to change the run mode of a step, for instance, is handled internally by the SequenceFileView manager control. The custom command types are not automatically handled by any TestStand controls. In fact, the custom command does not perform any action when it executes. Instead, the developer must capture an event to determine when the command is issued. The Application Manager captures a PostCommandExecute and PreCommandExecute event. These events are used to determine if a custom command is issued by the user. The actual command event is not capturable because standard command executions are handled by the manager control. However, the post-command and pre-command events are capturable. The Register Event Callback node in the "Full OI - Configure Event Callbacks.vi" must be altered to handle either the PostCommandExecute or PreCommandExecute event.

Registering the PostCommandExecute Callback VI
  1. Extend the Register Event Callback to show an additional terminal set.
  2. Wire the Application Manager reference node into the Event terminal. This provides a node to capture Application Manager events.
  3. Select PostCommandExecute from the list of events. The PostCommandExecute callback is invoked after the execution of any command, including custom commands.
  4. Right click on the VI Ref terminal and choose Create Callback VI. LabVIEW will automatically generate a callback VI for handling the PostCommandExecute event. The proper input terminals are automatically provided within the VI. Figure 9 shows the modified Register Event Callback node.


[+] Enlarge Image
Figure 9. Modifying the Register Event Callback Node in the Full OI - Configure Event Callbacks VI.

Implementing a Custom Command

The PostCommandExecute callback VI has the same parameter terminals as the SequenceView Create Context Menu callback VI, including the common event data, the control reference, the event data, and the user parameter. However, the PostcommandExecute callback VI handles command events, rather than context menu events. Therefore, the Event Data parameter contains different information. The callback VI is invoked by the manager control that triggers the event. When the user selects a menu item, the manager control issues the command. The PreCommandExecute event is invoked before the command executes, and the PostCommandExecute event is issued after the command executes. When the callback VI is invoked, event specific data is inserted into the Event Data and User Parameter controls. In the PostCommandExecute callback VI, the Command object reference is stored in the Event Data parameter. The Command object contains information about which command is executed.

Extracting Data from the Command Object
  1. Wire the Event Data terminal into an Unbundle by Name VI. Extract the Command reference from the cluster.
  2. Place an Invoke Node on the block diagram. Wire the Command reference into the Invoke Node. Extend the Invoke Node so that four properties are extracted from the Command reference. Select Kind, UserData, UserObject, and SequenceFileViewMgr as the properties to extract from the Invoke Node. Kind refers to the type of command. UserData and UserObject contain any data that is assigned to the Command object when the Command is created.
  3. Place a case structure on the block diagram. Wire the Kind numeric into the Case selector. Change the case selection to the 3. CommandKind_Custom is an enumeration that maps to the number 3. The PostCommandExecute callback is executed every time a command is invoked. The case structure ensures that only the custom commands are handled in this VI.
  4. Place a Variant to Data VI on the block diagram inside the case structure. Wire the UserData into the variant terminal of a Variant to Data VI. Wire an I32 representation numeric into the type terminal of the Variant to Data VI. The numeric extracted from this VI is the unique identifier assigned to the custom Command when the command is created. In this tutorial, only one custom command is created. However, using an identifier number, the developer is able to implement multiple custom commands.
  5. Place a Variant to Data VI on the block diagram inside the case structure. Wire the UserObject into the variant terminal of the Variant to Data VI. Wire the SequenceFileViewMgr from the Command Invoke Node into the type terminal of the Variant to Data VI. This extracts the reference to the Sequence File View Manager control. The control reference is required to access Numeric Limit Test step information.
  6. Wire through the error terminals. Figure 10 shows the code to extract the Command object data from the Event Data parameter.



Figure 10. Extracting the Command object from the Event Data.

Checking the Command Type
  1. Place a case structure within the command kind case structure. Wire the output terminal of the UserData Variant to Data VI into the case selector terminal. Change the case number to 61455. This is the unique identifier number assigned when the command is created. This ensures that the callback code only reacts to the proper custom command call. Additionally, it allows developers to extend the OI with additional custom command types.
  2. Place an Invoke Node inside the nested case structure. Wire the Sequence File View Manager control reference to the reference terminal of the Invoke Node. Extract the SelectedSteps property from the Invoke Node. SelectedSteps returns a collection of steps that are currently selected in the SequenceView control. Connect the error terminals.
  3. Place an Invoke Node to the right of the Sequence File View Manager Invoke Node. Wire the SelectedSteps reference to the reference terminal of the Invoke Node. Select Item from the method list of the Invoke Node. Wire a constant with the value 0 into the itemIndex parameter. This extracts the first step from the collection of selected steps. Item returns a Step object. Connect the error terminals.
  4. Place an Invoke Node to the right of the SelectedSteps Invoke Node. Wire the Item reference to the reference terminal of the Invoke Node. Extract the StepType property from the Step Invoke Node. The StepType object is used to determine what type of step is currently selected. Connect the error terminals.
  5. Place an Invoke Node to the right of the Step Invoke Node. Wire the StepType reference to the reference terminal of the Invoke Node. Extract the Name property from the StepType Invoke Node. Connect the error terminals.
  6. Place an Equal? VI on the block diagram to the right of the StepType Invoke Node. Create a string constant and wire it into the bottom terminal of the Equal? VI. Place "NumericLimitTest" into the string constant. Wire the Name property into the top terminal of the Equal? VI. This ensures that the Numeric Limit dialog is only displayed for Numeric Limit Test step types. Figure 11 shows the completed code for checking the step type of the selected step.


[+] Enlarge Image
Figure 11. Checking the Step Type

Executing the Edit Limits Substep
  1. Place a Case Structure to the right of the Equal? VI. Wire the boolean output terminal of the Equal? VI into the case selector terminal of the Case Structure. This ensures that the Edit Limits dialog is only shown for Numeric Limit Test step types.
  2. Place an Invoke Node inside the true case of the case structure. Wire the reference from the Item terminal in the SelectedSteps Invoke Node into the reference terminal of the Invoke Node. Select ExecuteSubstep from the list of methods of the Step Invoke Node. Wire a numeric constant with the value of zero into the substepIndex terminal. Steps are often made up of multiple substeps. The first substep of the Numeric Limit Test step type is the Edit Limits substep. This is the step that displays the Edit Limits dialog when the developer selects to edit limits from within the Sequence Editor. The Step Invoke Node is executing the substep when the user selects this command from the SequenceView context menu. Wire through the error terminals.
  3. Place an Invoke Node to the right of the Step Invoke Node. Wire the Sequence File View Manager reference to the Invoke Node reference terminal. Select Refresh from the list of methods in the Sequence File View Manager Invoke Node. This causes the SequenceView to update with the modified limits. Connect the error terminals.
  4. Place three Close Reference VIs outside the Step Type Case Structure. Wire the output error terminal of the Sequence File View Manager Invoke Node to the first Close Reference VI. Select the False case of the Step Type Case Structure. Connect the input error tunnel to the output error tunnel on the case structure. Figure 12 shows the False case block diagram.
  5. Wire the output reference terminal from the StepType Invoke Node to the first Close Reference VI. Wire the output terminal from the Step Invoke Node to the second Close Reference VI. Wire the output reference terminal from the SelectedSteps Invoke Node to the last Close Reference VI. Wire through the error terminals. The references that were opened in this VI must be closed to avoid memory leaks. Figure 11 shows the finished block diagram.



Figure 12. Executing the Edit Limits Substep.


Figure 13. The False Case of the Numeric Limit Step Type Case Structure

Conclusion

This tutorial demonstrated the implementation of a custom command in the LabVIEW Operator Interface. The developer can extend the functionality of the Operator Interface with custom commands. In order to implement a custom command, the command must be created and added to a Commands collection. In order to execute the command, the PreCommandExecute or PostCommandExecute event is captured in a callback VI. The callback VI is invoked when the command event occurs. By extracting the proper information from the command object, the developer can implement sophisticated functionality in the Operator Interface. For further information, please see the TestStand UI Controls API Reference Help or the Related Links section.

TestStand UI Controls API Reference Help Topics
  • ApplicationMgr, SequenceFileViewMgr
  • Commands
  • CommandsKinds Enumeration
  • PostCommandExecute, PreCommandExecute
3 ratings | 4.00 out of 5
Print

Reader Comments | Submit a comment »

It would be great if the code was provided for this tutorial :-)
- Ronnie Smith, Racal. rsmith@racalinst.com - Jul 8, 2009

 

Legal
This tutorial (this "tutorial") was developed by National Instruments ("NI"). Although technical support of this tutorial may be made available by National Instruments, the content in this tutorial may not be completely tested and verified, and NI does not guarantee its quality in any way or that NI will continue to support this content with each new revision of related products and drivers. THIS TUTORIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND AND SUBJECT TO CERTAIN RESTRICTIONS AS MORE SPECIFICALLY SET FORTH IN NI.COM'S TERMS OF USE (http://ni.com/legal/termsofuse/unitedstates/us/).