Using the TestStand API in LabWindows/CVI

Updated Apr 26, 2023

Environment

Software

  • TestStand
  • LabWindows/CVI

When working with TestStand, you may need to perform tasks programmatically using the TestStand API. We will look at how to achieve this in LabWindows/CVI.

 Creating a Code Module with Access to the API in LabWindows/CVI

The process for using the API in a LabWindows/CVI code module is fairly similar to LabVIEW.  In this tutorial, you create a new code module from a template to get started.

  1. Create a new step which uses the CVI Adapter
  2. Specify a DLL (dynamic link library) name and function name.
  3. Add the parameters to pass into the function using the + button and configure the name and data type of each. For TestStand objects, select Object for catagory and CVI Active X Automation Handle for type.

    Note: You can also select a preconfigured prototype using the Code Template menu.
  4. Click Create Code to have TestStand generate a DLL with the function you specified.

The generated code will have the TestStand API function panel and header files included so you can immediately begin programming with the TestStand API.

Template code:

#include <cviauto.h>
#include "tsapicvi.h"

void __declspec(dllexport) renameStep(CAObjHandle ThisContext, const char *CurrentName)
{
   //Insert function body here.
}

 How to use the TestStand API in a code module

The TestStand API functions are named to help clarify what they do on a quick glance. For example, observe the following function:

TS_SequenceGetStepByName()

Each part of the function indicates something about the functionality:

This is very useful for finding API functions. If you know the class of the object you are referring to, you can just begin typing "TS_Sequence", and the available property and method functions will be automatically listed.

TestStand Properties are accessed through Set and Get functions. For example TS_SequenceSetName and TS_SequenceGetName.  The naming pattern in the image above still applies.

Observe the simple example below using the TestStand API in LabWindows/CVI.  In this example, you change the name of the current sequence.

Equivalent TestStand expression:

ThisContext.Sequence.Name= "newName"

#include <cviauto.h>
#include "tsapicvi.h"

void __declspec(dllexport) renameStep(CAObjHandle ThisContext)
{
   //create a reference to store the sequence object.
   //Initialize to 0 to avoid accessing invalid memory addresses
   TSObj_Sequence sequenceObj = 0;

   //get the current sequence
   TS_SeqContextGetSequence (ThisContext, NULL, &sequenceObj);

   //set the name property of the sequence
   TS_SequenceSetName(sequenceObj, NULL, "newName");

   //free resources
   CA_DiscardObjHandle(sequenceObj);
}

When the output of a function is a TestStand object (such as TS_SeqContextGetSequence), you need to pass by reference (using the "&" character) so that the function can place the result in the memory location of the variable. The variable types for TestStand objects (in this case the sequenceObj variable in the TS_SeqContextGetSequence function) are specified in the function prototype (press <Ctrl-Shift-Space> while the cursor is on the function to see the prototype of the selected function). Also, press <Ctrl-D> with the variable selected to have LabWindows/CVI create the variable declaration for you.

Now, observe the original example of changing a step name.  Like LabVIEW, you cannot directly access contained properties. You need to use a lookup string to navigate the containment hierarchy.  Again, there are two possible methods. 

Use the GetPropertyObject method to specify the location of the object via lookup string (similar to expression syntax). Since this is a method of the PropertyObject class, you first need to use the AsPropertyObject method.  In the example below, you use this approach to access a particular step.

Equivalent expression: 

ThisContext.Sequence.Main["Action"].Name = "newStepName"

void __declspec(dllexport) renameStep(CAObjHandle ThisContext)
{
   CAObjHandle stepObj = 0;
   CAObjHandle sequencePropObj = 0;
   TSObj_Sequence sequenceObj = 0;
   
   //get the current sequence
   TS_SeqContextGetSequence (ThisContext, NULL, &sequenceObj);
   
   //treat the sequence object as a PropertyObject
   TS_SequenceAsPropertyObject(sequenceObj,NULL,&sequencePropObj);
   
   //get the step object using the lookup string "Main[\"Action\"]"
   TS_PropertyGetPropertyObject(sequencePropObj,NULL,
          "Main[\"action\"]",0,&stepObj);
   
   //rename the step
   TS_PropertySetName(stepObj,NULL,"newStepName");
   
   //free resources
   CA_DiscardObjHandle(sequenceObj);
}

If available, use a method supplied in the API to get the sub-object.  For this example, you can call the GetStepByName method to directly access the step object.  If no method exists, you will have to use the approach above.

Equivalent expression: 

ThisContext.Sequence.GetStepByName("Action",StepGroup_Main).Name = "newStepName"

#include <cviauto.h>
#include "tsapicvi.h"

void __declspec(dllexport) renameStep(CAObjHandle ThisContext)
{
   char lookupString[100] = "";
   CAObjHandle stepObj = 0;
   CAObjHandle sequencePropObj = 0;
   TSObj_Sequence sequenceObj = 0;
   
   //get the current sequence
   TS_SeqContextGetSequence (ThisContext, NULL, &sequenceObj);
   
   //get the step by name (action)
   TS_SequenceGetStepByName(sequenceObj,NULL,"action",
       TS_StepGroup_Main,&stepObj);

   //rename the step
   TS_StepSetName(stepObj,NULL,"newStepName");
   
   //free resources
   CA_DiscardObjHandle(sequenceObj);
}

 Error Handling in LabWindows/CVI

It is good practice to implement error handling in the function so that you can notify the calling sequence if any errors occur in the module.  TestStand provides a macro (tsErrChk) you can use to check if any function returns an error.  This macro checks the value of the errorInfo variable, which all TestStand API functions will populate.  If an error does occur, the code will jump to the Error: section. The code below contains added error handling for the sequence renaming code (new code in bold).

#include <cviauto.h>
#include "tsapicvi.h"
#include "tsutil.h"

int __declspec(dllexport) renameStep(CAObjHandle ThisContext)
{   
   //required variables for tsErrChk macro
   int error = 0;
   ErrMsg errMsg = "";
   ERRORINFO errorInfo;

   TSObj_Sequence sequenceObj = 0;

   //get the current sequence
   tsErrChk(TS_SeqContextGetSequence (ThisContext, &errorInfo, 
        &sequenceObj));
   
   //set the name property of the sequence
   tsErrChk(TS_SequenceSetName(sequenceObj, &errorInfo, "newName"));
   
   //free resources
   CA_DiscardObjHandle(sequenceObj);
   
   Error:
       return error;
}

More information and examples of calling the TestStand API in LabWindows/CVI can be found in Chapter 16 of the Using LabVIEW and LabWindows/CVI with TestStand manual.