1. User Interface Components that Ship with TestStand
TestStand provides several examples and components that you can use to help you build your user interface. The example user interfaces provide a starting point for developing a custom user interface. TestStand also ships with user interface components that implement common features used in these applications that you can reuse in your own applications.
Example User Interface Applications
TestStand ships with a simple and full-featured user interface application example. TestStand provides source code for these examples in each of the supported programming languages. You can use this source code as a starting point for developing a custom user interface.
Both examples have similar behavior but include different feature sets. The simple user interface has a minimal display and does not include a menu bar. The full-featured user interface displays more information, includes a menu bar, and provides intuitive debugging. The full-featured user interface also has a sequence editor mode that allows you to create and modify test sequences in nearly the same manner as the TestStand Sequence Editor. Press [Ctrl-Alt-Shift-Insert] to start the user interface application in sequence editor mode or enable the sequence editor mode while the user interface is running.
Both examples are robust and perfectly valid user interface application starting points. Each example has unique benefits. Certainly, you can more easily learn about the TestStand User Interfaces by studying the simple example because the interface concepts you learn about in the simple example apply directly to the full-featured user interface example. After you understand the concepts, you can develop your own user interface.
When you develop your user interface, start with one of the user interface examples. The decision to start with the simple or full-featured example depends on the functionality that you need. If you need only a simple user interface, start developing from the simple example. However, if you need any of the features that are included only in the full-featured example, consider starting with the full-featured user interface example because it is often easier to remove features than it is to add them.
The TestStand User Interface (UI) Controls are a set of ActiveX controls that implement the common functionality that applications require to display, execute, and debug test sequences. These ActiveX controls significantly reduce the amount of source code that a user interface requires to interact with the TestStand API to handle user interface tasks. You can use Properties pages or call the available properties and methods to configure these controls. Refer to Chapter 9, Creating Custom User Interfaces, of the NI TestStand Reference Manual for more information about how to use the TestStand UI Controls in your particular programming language.
TestStand provides two sets of user interface controls: manager controls and visible controls.
The manager controls provide a simple interface to the TestStand API. Manager controls handle functions such as user login, file loading, and execution launching. These controls are not visible at run time but are visible while designing the user interface application. To display information to the user, you connect the manager controls to the appropriate visible user interface controls.
There are three manager controls: Application Manager, SequenceFileView Manager, ExecutionView Manager. Refer to Chapter 9, Creating Custom User Interfaces, of the NI TestStand Reference Manual for more information about the manager controls.
Unlike the manager controls, visible controls are always visible, and you use visible controls to display information to users or retrieve commands from users when a visible controls is connected to an appropriate manager control. At design time, you can modify the properties of each of these controls in the Properties pages, which you can use to adjust how the control looks and behaves. Refer to Chapter 9, Creating Custom User Interfaces, of the NI TestStand Reference Manual for more information about the visible controls.
National Instruments recommends using the TestStand UI Controls whenever possible, but you can use the controls your programming environment natively provides alongside the TestStand UI Controls. You can use the TestStand UI Controls only to take advantage of the TestStand-specific functionality of the native controls. For example, you might connect a TestStand Button control to a manager control such that the label, enabled state, and click action of the manager control adjust automatically to perform a specific TestStand action, such as running the selected sequence. However, you can use the button control provided by your programming environment and directly call the TestStand API to implement the equivalent functionality. Refer to the Writing an Application with the TestStand Engine API topic and subtopics in the NI TestStand Help for more information about writing an application that directly calls the TestStand API.
2. Software Architecture for a TestStand User Interface
Software architecture is a large topic that can fill volumes. This article provides a focused discussion to allow you to better design and implement a TestStand User Interface application.
3. Overview of a TestStand User Interface
A test system is comprised of many parts, or modules. Understanding how the modules in a TestStand system interact helps you to build a better test executive and user interface.
Figure 1. TestStand Components
As shown in Figure 1, a TestStand system consists of many components. The user interface is the ‘face’ of a test executive system that provides for user interaction and displays test results. The face reflects what is happening during test execution, but the face is not the entire test system. The process model, another component, controls test flow and acts as the ‘brain’ of the test system. The process model controls the execution flow and handles tasks that are common to many test sequences, such as querying for UUT serial number, storing results, generating reports. The TestStand Engine acts as the ‘heart’ of the system. All TestStand components communicate with the TestStand Engine API to perform their various functions. The user interface communicates with the engine to get status or other test information. The user interface can pass information to the TestStand execution system through the TestStand Engine. Each of the components interacts with the others to form a complete test executive. This article discusses the preferred practices for communicating between the test system components.
4. Value of a Modular Architecture for User Interfaces
Over the lifetime of a test system, software maintenance can become more expensive than the initial development effort. However, if the original software architects design the system correctly by adhering to certain design principles, maintenance can be less complicated, thus reducing the long-term costs of the system.
One of the key design principles is modularity. If the system is designed using distinct modules that each have a single purpose, the development and maintenance of the entire system becomes more straightforward. As you design a system using well-defined code modules, you can more easily assign development tasks to different people, thus leading to more efficient development.
TestStand allows you to fully customize your user interface based on the requirements of your users and stakeholders. For example, you can create a very simple user interface, like the one shown in Figure 2, or a more advanced interface, like the one shown in Figure 3. The user interfaces might look entirely different but use the same test system behind the scenes. They both can share the same process model and run the same tests. The only difference is how the information is displayed and how the users can interact with the test systems.
Figure 2. Simple User Interface
Figure 3. Multi-Featured User Interface
One of your user interface requirements might be to handle different groups of users. For example, assume you have the following user groups, as shown in Table 1:
|User Group||Permitted Actions||Prohibited Actions|
|Operators||Running tests||Configuring or debugging the test system|
|Technicians||Running and debugging tests||Configuring certain aspects of the test system|
|Administrators||Running and debugging tests, configuring the test system||None|
Table 1. User Groups and Actions
To address the needs of these different user groups, you must allow or disallow access to different menu items and controls, depending on which user is currently using the system. One option for controlling access is to make a separate user interface application for each user group. For example, you can create a user interface for the administrator group that displays menu items and controls to administer, debug, and run the test system. Then, you can create a separate user interface application for operators that displays only the controls and menu items that operators require. Over the long term, maintaining multiple user interface applications can become tedious because you must propagate even a simple change common to all the interfaces to all the user interface applications.
A better practice for controlling access is to design a single application that has a login feature. When a user logs in, the application checks the privileges of that user account. The application shows or hides the various controls and menu items depending on the privileges of the user account.
TestStand has built-in user-account management and can provide this capability for the developer. The available TestStand UI Controls automatically enable or disable their state based on user privileges. In addition, TestStand provides tools to automatically enable and disable menu items based on user privileges. For privilege validation, use the, Engine.CurrentUserHasPrivilege TestStand API method or the related privilege functions. Refer to the TestStand User Interface (UI) Controls section of this article and to the NI TestStand Reference Manual for more information about using user interface controls for user privileges.
5. Best Practices to Leverage the TestStand Architecture
This section explains how to leverage the different components of a TestStand test system and the TestStand architecture. To achieve modularity, the appropriate components of TestStand must perform most of the actions of the user interface.
Figure 4 shows several of the actions that a test system user interface application might need to perform. The diagram on the left shows the modules for a generic test system, while the diagram on the right shows the TestStand-specific implementation of each module.
Figure 4. TestStand User Interface Modules
This article discusses each of the blocks in Figure 4 and how National Instruments recommends that you utilize the TestStand architecture to implement certain functionality. The description for each block explains the generic purpose followed by the TestStand-specific implementation.
Initialize → Front-End Callbacks:
This block refers to any action that needs to be performed before the test starts running or even before the process model runs. For example, you might want to initialize your hardware when the user interface launches or you might need to check for user privileges to initialize the user interface.
Front-End callbacks are sequences that are not related to the process model. You can add as many sequences as you need in the FrontEndCallbacks.seq sequence file and call them usingthe Engine.CallFrontEndCallbackEx method, which starts a new execution of the specified sequence to perform whatever task you need. Notice that you can modify your user interface to call any Front-End callback, but you cannot modify the sequence editor to call the same Front-End callback. A possible solution to this issue is to create a custom sequence editor
When you open the default FrontEndCallbacks.seq file, you see the Login and Logout operations that the TestStand Application Manager control calls for you. You can easily override these operations to perform custom Login or Logout operations, or you can add completely new operations to the Front-End callbacks.
Additional Applications → Tools:
The user interface might need to launch external applications or utilities that can have some effect on the user interface environment. For example, you might launch a database configuration utility or an analysis application.
TestStand provides a Tools menu that can invoke custom dialogs or applications. You can create tools that interact with the environment or current sequence. You can configure the Tools menu to show or enable certain tools based on user privileges or other variables. The Tools menu behaves the same in the sequence editor and user interface applications.
Configure Parameters → Configuration Entry Points:
You can include popup panels that allow the user to configure certain parameters that affect the execution of the test. For example, the user interface might launch a dialog that allows you to configure report options. These configuration settings are often linked to the process model.
You can use process model Configuration entry points to configure parameters that the process model or test sequence might require at run time. Examples of Configuration entry points include Configure Report Options, Configure Instruments, and Configure Characterization Settings. Generally, the code in a Configuration entry point saves information to a configuration file that some other component of the architecture uses. Configuration entry points are tied to a particular process model giving more flexibility to your user interface. By using them, the user interface can perform different actions depending on the currently selected process model. TestStand dynamically inserts the Configuration entry point items in the Configuration menu, and the entry point items behave the same in the sequence editor and user interface applications.
Run Test → Execution Entry Points:
You usually start test executions from the user interface with the click of a button. Start tests with an Execution entry point, which is defined in the process model. TestStand ships with Sequential, Parallel, and Batch process models that you can modify for your particular needs. For example, you can provide an additional Execution entry point that is available for a certain group of users that includes additional features.
Use the process model to handle repetitive tasks such as reporting, database logging, or prompting for UUT information. By building features into the process model, the features become available in both the user interface application and the sequence editor. However, if you build a feature only in the user interface, that feature is not available in the sequence editor. Use the process model to help build a flexible, modular test system.
User Interface Components → TestStand UI Controls:
The user interface application examples that ship with TestStand have a modular architecture. Through the TestStand UI Controls, these user interface examples provide hooks for performing the required external actions. The TestStand UI Controls also provide the synchronization with the test execution.
Summary of TestStand Architecture
An initial reaction might be to hard-code many of the above actions into the user interface because the TestStand Engine invokes the actions from the user interface. A better practice is to achieve modularity by using the mechanisms that TestStand provides to implement each of these items. Use the user interface application to act as a shell program and not perform any of these actions directly.
TestStand implements many of the above modules using TestStand sequences so that you can implement these modules using TestStand steps or expressions. You can also develop code modules using any of the supported programming languages.
By using the above modular techniques, you can achieve flexibility and maintainability in your test system. You can modify your test system without modifying the source code of your user interface application. For example, you can update the Configuration entry points by simply distributing a new process model. In your user interface design, National Instruments recommends that you leverage the TestStand architecture whenever possible.
Before you can start implementing your user interface, you must understand the communication mechanisms between different portions of the TestStand architecture. You might need to provide communication between the user interface and the process model, test sequence(s), or code modules. For the communication discussion, this article refers to the process model, test sequence(s), or code modules as the test.
While a test is executing, the test system must provide feedback to the operator, such as which test is running or the test results. The user interface might provide a progress bar or other visual indicators. The executing sequence or code module must pass this information to the user interface for display or instruct the user interface to take action. You might want to update the user interface from the process model, test sequence, or code modules. In addition, the user interface might need to pass information to the test. You might want to embed instrument configuration information into the user interface and pass that information down to the executing test.
While a test is executing, the user interface has the following tasks:
- Update the display with the execution status
- Inform the test of a user request
Different techniques exist to implement this communication, but the best approach is modular and reusable. It is important to maintain a clean interface between the different components. The TestStand framework provides for these communication techniques. Refer to Figure 5 below throughout this discussion.
Figure 5. Communication with the User Interface
Communication from the Test to the User Interface
Use TestStand UIMessages to provide updates to the user interface. UIMessages allow a synchronous or asynchronous communication from the test to the user interface. By default, the TestStand Engine and process model send UIMessages to the user interface or sequence editor. Example messages include: Start Execution, End Execution, Trace, and Progress Percent. As explained later, the user interface controls automatically handle these messages. A unique event code identifies each event.
Using the Thread.PostUIMessageEx TestStand API method, you can send predefined or custom UIMessages from code modules, test sequence(s), or the process model. The exact time at which the information is sent depends on how often you must update the user interface. Certainly, for long tests, you want to update the progress bar and a status box, for which you can use predefined event codes. Refer to the example files located in the [TestStand Public]\Examples\DisplayingProgressAndStatus directory for a demonstration of how to update progress and status information from a code module. In this example, you see that the PostUIMessage method is called with the event codes UIMsg_ProgressPercent and UIMsg_ProgressText. When you run this example, the code module sends UIMessages that the TestStand UI Controls catch and handle appropriately. The next section discusses how to catch and handle UIMessages. UIMessages can also serve as a synchronization mechanism between the execution and the user interface.
You can define your own UIMessages for custom operations, such as updating data in a chart and histogram. When you define custom UIMessages, specify unique event codes starting at the UIMsg_UserMessageBase event code. For example, you can define the following event codes for a particular test system, as shown in the following table:
|Custom UIMessage||Event Code Definition|
|Update Chart||UIMsg_UserMessageBase + 0|
|Update Histogram||UIMsg_UserMessageBase + 1|
Table 2. Event Codes for UIMessages
When you define custom event codes, define them as shown above, where the Event Code Definition contains the value UIMsg_UserMessageBase + N.
When you post a custom UIMessage, pass the defined event code and the data to be displayed. You can send string, Boolean, or numeric data items, or you can attach arbitrary data using the ActiveXDataParam parameter of the Thread.PostUIMessageEx method. The ActiveXDataParam parameter is an ActiveX reference and can contain any ActiveX object.
Ensure that no other developers for your particular test system use the same UIMessage event codes that you assign. Otherwise conflicting messages might exist with the same UI Message event code. A best practice is to maintain a master list of assigned event codes for a large development group. Usually, this list is an enumerated (enum) definition. Alternatively, you can also use the Engine.RegisterUIMessage method to define a unique event code number for each custom UIMessage.
You must add an ActiveX event callback (handler) to the user interface to catch the custom UIMessage. Handling ActiveX events is specific to your programming language. When the executing test sends a UI Message, the TestStand engine calls the appropriate event callback passing in the event code and data. When the event callback is called with the event code Update Chart, your user interface will retrieve the data and update the chart. Your user interface will catch and handle your custom user interface messages, but the sequence editor will ignore them. Because you do not have the source code to the sequence editor, you cannot directly modify it to handle your custom UI Messages. Refer to the NI TestStand Reference Manual for more information about handling ActiveX events with specific programming languages.
The user interface can pass a user request directly to the test by setting some properties or calling some methods of the TestStand API. For example, you might want to modify certain system set points. There are different techniques to pass data to the test, depending on your circumstances. One approach is to pass data through the Station Global variables. The user can set these variables from the user interface by clicking a button or selecting a menu item. The execution flow or behavior of the process model or sequence files can depend on a set of Station Global variables to comply with the user input.
You can also use a synchronous technique that utilizes a UIMessage that originates from the test. For example, you can modify the process model to post a UIMessage during initialization and pass the SequenceContext (or other object) to the user interface. When you post the UIMessage, set the synchronous parameter to True so that the execution waits until the user interface processes the message. When the user interface processes the UIMessage, it retrieves the SequenceContext object and writes or reads certain variables, such as the process model local variables. This way, the user interface can pass data back to the message sender, depending on your particular needs regarding the preferred method to pass data from the user interface to the test.
To summarize the communication between the user interface and the test, the user interface does not perform any action by itself. The only role of the user interface is to respond to commands from the UIMessages or inform the test of user requests via Station Global variables or synchronous UIMessages. When designing a test system, carefully consider using these features.
6. Design Example: Embedded Dynamic Panels
The following example describes a dynamic user interface solution that allows certain flexibility in dynamically changing the appearance and behavior of a user interface without changing the source code of the user interface.
When implementing TestStand solutions in large corporations, a common problem is that a single user interface application does not have the functionality and flexibility to fit the needs of every group within the company. Different groups can feel frustrated about the final standard functionality they get out of their single standard corporate user interface.
This example demonstrates a method for creating a single dynamic user interface, illustrating the best practices that were explained previously in this article. It is a modification of the simple LabWindows/CVI user interface that ships with TestStand in the [TestStand]\UserInterfaces\Simple\CVI directory in TestStand 4.1 and in the [TestStand]\UserInterfaces\NI\CVI directory in all previous versions of TestStand. The example allows the addition of user interface functionality on a per-test basis such that the example provides common functionality, such as executing sequences and tracing executions, but also provides a space on the user interface front panel so that users can embed their own user interface panels without modifying the user interface source code. This enhancement provides a layer of modularity that demonstraties the architecture concepts that were discussed in the Value of a Modular Architecture for User Interfaces section of this article. This modularity enhancement results in an expandable, more maintainable test system.
Figure 6. Embedded Dynamic Panels Example
Follow this link to find example code demonstrating how to implement Embedded Dynamic Panels in User Interface Application. The attached .zip file contains the modified user interface plus three example sequences:
- Custom Serial Number panel
- Custom Graph panel
- Custom Yields panel
Complete the following steps to run these examples.
- Unzip the contents of the DynamicUserInterface.zip folder into a new directory.
- Copy the DynamicUIStepTypes directory from the unzipped directory the to [TestStand Public]\Components\StepTypes directory in TestStand 4.1 or to the [TestStand]\Components\User\StepTypes\ directory in all previous versions of TestStand. The DynamicUIStepTypes directory contains code for three custom step types used in this example.
- From the unzipped directory, run testexec.exe, to launch the included simple user interface.
- In the simple user interface, open a sequence file from the ExampleDynamicPanels subdirectory of the unzipped directory. The ExampleDynamicPanels subdirectory contains the example sequences mentioned above.
- Select Execute»Test UUTs to run the MainSequence of the example.
Each of the example sequence files define the step types for this example. However, if you want the step types to be available in all sequence files, copy install_DynamicUIStepTypes.ini located in the unzipped DynamicUIStepTypes subdirectory, and place the file in your [TestStand Public]\Components \TypePalettes directory in TestStand 4.1 or in the [TestStand]\Cfg\TypePalettes directory in all previous versions of TestStand. When you launch the sequence editor, TestStand loads this type palette automatically and renames the file to DynamicUIStepTypes.ini.
Since a user interface is often distributed to target machines as an executable, and the test developers do not have access to the user interface source code, you might need a solution to allow the test developers to customize the GUI of the user interface without modifying its source code. This example modifies the simple LabWindows/CVI user interface so that the user interface processes three custom UIMessages: Attach Panel, Call Function and Detach Panel. To simplify use, the examples include three custom steps types that correspond to each of the custom UIMessages.
When test developers create a test sequence, they can create a DLL with a GUI, along with functions to manipulate that GUI. You can use a custom step type, Attach Panel, within a sequence to specify the appropriate DLL and UIR to use in the test. When you execute the sequence the Attach Panel step embeds the GUI as a dynamic panel of the user interface.
The Call Function step type specifies the functions that TestStand uses to manipulate the GUI. Call this step type whenever the developer requires a GUI update. The functions that the Call Function step type calls must have the following prototype:
int functionName(int panel, CAObjHandle seqContext)
The Call Function step passes the sequence context to the called functions, allowing the function to share data between the current execution and the called function. Finally, when testing is done, TestStand uses the Detach Panel step type to unload the panel and release the DLL.
This solution allows every test sequence to have a different GUI that meets the needs of that test. Because TestStand controls the GUI through UIMessages (Attach Panel, Call Function, Detach Panel), the original method of communication between the TestStand Engine and the user interface is not affected. The greatest benefit for the test developer is that the developer does not need to know how the user interface works. The developer only has to develop a GUI with the appropriate functions to manipulate and then embed the GUI in the user interface front panel using the included step types. For example, if a certain test requires a graph display, the test developer can create a DLL with a GUI that shows a graph control. The developer can then create all the necessary functions in the DLL required to update, manipulate, and clear the graph. When the test runs in the Dynamic User Interface example, TestStand attaches this newly created GUI to the main panel of the user interface GUI to merge their functionality.
The techniques presented in this article better equip you to design and build a more maintainable, structured user interface. By understanding software design principles, you can make better decisions regarding software modules and architectures. When you need to implement certain features in your user interface application, you can leverage the TestStand architecture to build a modular user interface.
Visit the NI TestStand Advanced Architecture Series to read other documents.
8. About the Authors
Paul Mueller, Staff Systems Engineer, has been with VI Technology in Austin, Texas, since 2005. Paul graduated from the University of Texas at Austin with a BS degree in Electrical Engineering. Over the last eight years, Paul has architected and developed numerous projects using LabVIEW, TestStand and other development tools. He is a Certified LabVIEW Architect and a Certified TestStand Developer.
Daniel Elizalde, Product Development Manager, has been with VI Technology in Austin, Texas, since 2006. Daniel graduated from ITESM Mexico City with a BS degree in Electrical Engineering. Before joining VI Technology, he worked as a Senior Systems Engineer at National Instruments where he served as a TestStand consultant for many Fortune 500 companies. Daniel is a Certified TestStand Architect and a Project Management Professional.