This content is not available in your preferred language.

The content is shown in another available language. Your browser may include features that can help translate the text.

How to Develop an IviSwtch-compliant Driver to Use with NI Switch Executive

Updated Jun 4, 2024

Environment

Software

  • Switch Executive

Driver

  • IVI Compliance Package

NI Switch Executive (NISE) is an intelligent switch management and routing application that simplifies switch system configuration and increases test performance. NISE is built on top of the IviSwtch class driver and works with IVI-compliant specific switch drivers. All NI switch modules include NI-SWITCH, a full-featured IVI-compliant driver. In addition to NI PXI switch modules, you can also control third-party PXI, VXI, and GPIB switch modules. If your switch module does not have a specific driver compliant with the IviSwtch Class Specifications, this document describes the process to develop an IVI-compliant driver to use with NISE.

This document assumes that your are familiar with the specification of the IviSwtchBase Capability Group from the IviSwtch class, general concepts of IVI driver development, the LabWindows/CVI development environment, and C programming.
Since NISE does not support switch scanning, this document does not discuss compliance to the IviSwtchScanner Extension Group. Such compliance is optional and is not required by NISE.

IVI and NISE Requirements

IVI Requirements

IVI Foundation, Inc. specifications provide the rules for the behavior of IVI instrument drivers. The Driver Architecture Specifications imposes behaviors in some situations and recommends behaviors in others. The IVI Class specifications (particularly interest is the IVI-4.6: IviSwtch Class Specification) defines the rules for the behavior of an instrument driver that claims compliance with a particular instrument class.

The IviSwtch class specification has been designed without any specific switch topology in mind. Because of the differences in switch topologies and a wide variety of implementations, the IviSwtch class specification covers all switch modules with one API: by treating all switch modules as black boxes with connection points called I/O channels.

NISE uses extensively the IVI simulation requirement. Here are the compliance notes taken for the Simulate attribute from Revision 1.0 of the IVI-3.2: Inherent Capabilities Specification, Section 5.26, dated March 05, 2002.
 

Compliance Notes

  1. The IVI specific driver shall implement both the True and False values for this attribute
  2. When Simulate is set to True, the IVI specific driver may perform less rigorous range checking operations than when Simulate is set to False.
  3. If the IVI specific driver is initialized with Simulate set to True, the specific driver shall return the Cannot Change Simulation State error if the user attempts to set Simulate to False prior to calling the Close function.


The first note is a requirement for your driver to accept the value of True for the simulation attribute In other words, the developer shall implement the simulation behavior in the driver.

The second note is a relaxation of the simulation requirement that is overridden by NISE requirements. The instrument driver is considered compliant to the IVI architecture specifications even if it implements the smallest possible level of the simulation, which is to return Success status code from every function call when simulation is turned on.

The third note prohibits the user from disabling simulation if the session has been initialized with simulation enabled. Since most of the instrument initialization code happens when the driver is initialized, it is not possible to start using the live device after the driver initialization has run in simulation mode.
 

NISE Requirements

In order for your switch instrument driver to work well with NISE, there are additional requirements that are in line with any requirements and recommendations asserted by the IVI specifications.

Since NISE uses IVI instrument drivers heavily in simulation mode, the requirement that NISE places on the instrument drivers is to fully simulate functions and attributes of the switch driver. Specifically, the functions to connect, disconnect, and get routing information shall behave exactly the same way as on the live instrument as far as error checking is concerned. Refer to the IviSwtch class specification for the complete rules and make sure that the simulation session follows the same rules as a live device session. The specific functions in question (and some examples of the rules) are:
 

  • mySwitch_Connect, (shall set the “connected” state in the driver such that a successive connect call with the same channels will give an error)
  • mySwitch_Disconnect (shall change the state in the driver so the channels are marked as not connected and return an error if the two channels are not connected)
  • mySwitch_SetPath (shall verify the validity of the path syntax, as well as the possibility of setting such path on the instrument, taking into consideration any existing connections)
  • mySwitch_GetPath (shall return the exact path between the endpoints, if the two are currently connected)
  • mySwitch_CanConnect (shall return the true path capability for the given input channels.)
  • mySwitch_DisconnectAll (shall mark all connections as disconnected)
  • mySwitch_WaitForDebounce,
  • mySwitch_IsDebounced (can return immediately when in simulation, but don’t have to. They have to return at some point, before or at the specified maximum time allowed.)


Another very important aspect of the simulation required by NISE is the ability for NISE to switch the simulation mode in the instrument driver to True in the middle of the live session in order to find routes between two specified endpoints. This behavior is allowed by IVI and is described in the IVI – 3.1 Driver Architecture Specification v1.2-1 in the Section 3.2 :Simulation.

“A specific driver that the user initializes with simulation disabled may allow the user to enable simulation at some point after initialization.”

Finding routes sometimes requires the closing and opening of the relays in order to protect the devices connected to the channels of the switch modules, NISE does not perform live operations when searching for a particular route but rather enables simulation. If your driver doesn’t allow for this behavior, niSE Find Route will return an error.

Fortunately, all these additional NISE features are implemented for you and are ready to use when you are creating your driver skeleton code with the LabWindows/CVI IVI Instrument Driver Development Wizard. If the steps are rigorously followed during the creation of the driver, the driver will be ready to use in NISE.
 

Using the LabWindows/CVI IVI Driver Template to Create your Driver

The best choice for IVI-C Switch instrument driver development is the LabWindows/CVI development environment IVI Wizard.

Note: If you are not using the latest LabWindows/CVI version, download and install the latest version of IVI Driver Template from ni.com.

To create your driver, start the IVI Instrument Driver Development Wizard from LabWindows/CVI Tools menu shown on Figure 1.
 

Figure 1: Invoking the IVI Instrument Driver Development Wizard in CVI
 

From the list of available types of instruments, select “Switch” shown on Figure 2.

Figure 2: Choosing the Instrument type
 

Choose the prefix for your driver and the location to generate the driver. Figure 3 shows “mySwitch” as the prefix for the driver created fro this document.

Figure 3: Select the Name, Prefix, and Location of the Driver
 

There is no need to specify channel names right now. We can do that later in the driver code once we analyze the topology and decide on the channel names. Figure 4 illustrates this step.

Figure 4: Skip Entering a Channel List String

 

Proceed through the rest of the instrument driver development wizard and generate your driver. Do not launch the attribute editor at this time shown on Figure 5. You can launch the attribute editor at any time from the instrument driver source code by pressing<Ctrl+F9>.

Figure 5: Skip the Attribute Editor​​​​​​
 


Translating the Topology of Your Device to Driver Structures (Matrix, Mux, General Purpose)

At this time, you should have generated four instrument driver source files:

  • mySwitch.c, (instrument driver source code)
  • mySwitch.h, (instrument driver header file)
  • mySwitch.fp, (function panels – help and descriptions of all functions)
  • mySwitch.sub. (attributes and attribute hierarchy help and description)


To complete the driver, you must define the channel list based on the topology of your device, translate that topology to the instrument driver structures, and finally, go through all the CHANGE comments in the four driver files in order to complete the driver.


Internal Structure of a Switch Driver Generated by LabWindows/CVI Instrument Driver Wizard

The generated skeleton driver will handle all necessary logistics for your switch instrument driver to find a route between endpoints, manage existing connected channels, and report proper errors and warnings at the proper times.

To achieve this, the instrument driver internally stores the data about existing connections and connection possibilities in the connection matrix. The connection matrix is the core of the LabWindows/CVI -generated driver code. The main purpose of the connection matrix is to mimic the state of the hardware, allowing for the same behavior of the driver regardless of the simulation mode the client code is running.

Additionally, the routing algorithms in the driver use the connection matrix in order to figure out configuration channels to use in complex routing situations that involve configuration routing channels. The matrix also stores existing connections and makes note of any necessary channel reservations that happen during the lifetime of a driver session.

Initially, the connection matrix contains connectivity information. When you initialize the drive, the connection matrix is populated with the connectivity information needed to correctly route signals between the specified endpoint channels for a given topology. The matrix is populated as N x N matrix, where N is the number of all channels on the device.

In addition to containing the topology information of the switch module, the connection matrix stores the connection information about the current state of the switch driver session. At the initialization time, and after each call to reset the switch or to disconnect all connections, the connection matrix is reset to match the hardware state.
 

Since the rows/columns of the connection matrix are the channels from the channel list, the first thing you should do is define your channel list. Different switch topologies have different channel naming recommendations. This application note addresses the following typical switch topologies:

  • matrix,
  • multiplexer,
  • general purpose with form A and form C relays.


The design of the driver structure that takes care of the connectivity for each topology is outlined in the following sections:

  • channel list definition
  • connection matrix definition


Matrix Topology

The example matrix switch used in this application note has three rows and four columns, shown in Figure 6.

Figure 6: Sample Switch Matrix
 

Typically, names for rows and columns are zero-based indexed letters r and c. Our 3 x 4 matrix would have seven channels: {r0, r1, r2, c0, c1, c2, c3}.

The channel list is specified in the driver’s initialization function, and the CHANNEL_LIST constant is defined at the beginning of the file shown in Figure 7. (The line numbers in the screenshots are for reference only. The actual line numbers may vary depending on the modifications performed on the driver.)

Figure 7: Specifying the Channel List String in the Driver Source Code
 

The channel list, as stored in the IVI driver session is a one-based indexed list. The IVI functions that deal with channel table (such as Ivi_GetNthChannelString and Ivi_GetChannelIndex) expect and return indices from 1 to 7 for this channel list. The channel list contains channels you specify with Ivi_BuildChannelTable function in the order they appear in the channel string.

The connection matrix (the internal driver structure that mirrors the state of the switch) is a square matrix with number of rows/columns equal to the total number of channels. Each element of the matrix represents a connection possibility. When 2 channels can be directly connected (i.e. you can connect them without using a configuration channel, by calling mySwitch_SetPath(vi, “r0”, “c1”);), the element will be populated with zeros, and the elements that correspond to channels that cannot be directly connected are populated with MYSWITCH_VAL_DIRECT_CONNECTION_IMPOSSIBLE constant. Figure 8 shows an example of the connection matrix.


Figure 8: The Connection Matrix for a Sample 3x4 Matrix
 

The driver implements initializes the connection matrix in the mySwitch_DefaultInstrSetup function. Any row can connect to any column; therefore we put zeros in all elements where a row connects to a column. Rows cannot be interconnected, neither can columns. All elements that correspond to row/row or a column/column combination are marked with ‘x’, which stands for the value of the MYSWITCH_VAL_DIRECT_CONNECTION_IMPOSSIBLE constant. Figure 9 shows an implementation of the matrix connection.


Figure 9: Implementation of the Connection Matrix for a sample 3x4 matrix

 

Matrix Topology with Analog Bus

If the switch module contains an analog bus connected to the rows of the matrix, it slightly modifies the channel list string, and the connection matrix. The typical names for analog bus channels are abi, and our channel list is now {ab0, ab1, ab2, r0, r1, r2, c0, c1, c2, c3}. Figure 10 shows a matrix with an analog bus.

Figure 10: Sample Matrix with Analog Bus


The channel list is now defined as:

#define CHANNEL_LIST “ab0,ab1,ab2,r0,r1,r2,c0,c1,c2,c3”

Figure 11 shows what the connection matrix now looks like.

Figure 11: The Connection Matrix for a Sample 3x4 matrix with Analog Bus


Multiplexer Topology with Analog Bus

For a typical multiplexer topology with an analog bus shown in Figure 12, “com” or “com0” is typically chosen for the common channel name.

Figure 12: Sample 4x1 Multiplexer
 

The names typically used for the multiplexed channels are ch0 through chn-1, for the 1 x n multiplexer. The channel list string should be defined as:

#define CHANNEL_LIST               “ab0,com0,ch0,ch1,ch2,ch3”

Figure 13 shows what the connection matrix should look like.

Figure 13: The Connection Matrix for a Sample 4x1 Multiplexer with an Analog Bus


If your switch module does not have an analog bus, omit channel ab0 from the channel list and from the connection matrix.

General-Purpose Switch Topology

The two most common forms of relays used in general-purpose switch modules are form A (Single Pole Single Throw: SPST) and form C (Single Pole Double Throw: SPDT). Switch modules typically contain several of these relays. Since the IviSwtch specification treats all switch modules equally (as black boxes with channels as access points) we have to change the usual paradigm of opening and closing relays to the IviSwtch paradigm of connecting endpoint channels.

For form A relays (SPST), closing relay k translates to connecting channel comk to channel chk.

For form C relays (SPDT) , closing relay k translates to connecting channel comk to channel nok (Normally Open) . Opening relays k translates into connecting channel comk to channel nck (Normally Closed).

This paradigm, when applied to form C relays, brings us to one major difference compared to all other topologies. Form C relays have existing connections between their com channel and either no or nc channels, at all times. The connection matrix, as we stated, reflects the state of the hardware. However, in order to use all switches the same way with the IviSwtch class driver, we must make an exception in how the connection matrix treats the implicit connections. The IviSwtch class specification allows for this case by requiring calls to disconnect and disconnect all channels to return the MYSWITCH_WARN_PATH_REMAINS warning status code. In the case of the form C relays, the state of the switch driver, must reflects the client’s intent. If a client application executes a disconnect call on com and nc channels, the matrix connection that maintains the state should reflect the fact that com and nc channels are disconnected, even though they might remain connected on a hardware module.

Refer to Special Consideration for Form C Relays for more details on how to implement the disconnect function.

Since the IviSwtch class specification does not allow for implicit disconnects, meaning that to disconnect two channels you need to explicitly call the disconnect function, you cannot connect the com channel to the no channel if the com channel is already connected to the nc channel.

As an general purpose switch module example, we will use four form A relays, depicted in Figure 14.

Figure 14: Sample General-purpose Switch Module with four Form A
 

The channel names typically used for the form A switch are comi and chi pairs. The channel list string for our sample switch module can be defined as

#define CHANNEL_LIST       “com0,ch0,com1,ch1,com2,ch2,com3,ch3”

The corresponding connection matrix is shown in Figure 15.

Figure 15: Connection Matrix for a General-purpose Switch Module with Form A Relays
 

A general-purpose switch module with form C relays is shown in Figure 16.

Figure 16: General-Purpose Switch Module with Two Form C Relays
 


The channel names typically used for Form C relays are comi, nci and noi. The channel list for this sample Form C switch module driver can be defined as:

#define CHANNEL_LIST                     “com0,nc0,no0,com1,nc1,no1”

The corresponding connection matrix is shown in Figure 17.

Figure 17: Connection Matrix for a General-purpose Switch Module with Form C Relays
 


Special Considerations for Common Mux Channel Connectivity

Special Considerations for Common Mux Channel Connectivity

Another thing to consider is whether the given topology allows connections of channels to more than one connection at the time. Take a look at the topologies and their corresponding connection matrix shown in Figure 18.

Figure 18: Mux and Matrix Topologies with Corresponding Connection Matrices

 

Look at the connection matrix for both topologies. According to the connection matrix for the mux, com0 can be connected to both channels ch1 and ch2. On the matrix side, r0 can be connected to both channels c1 and c2. However, nothing in the connection matrix suggests the uniqueness of the connection in the mux case. With switch matrices, you can connect r0 to c1 and still be able to connect the same r0 to c2. However, with multiplexers, you cannot connect the common mux channel to more than one channel at a time. If you have connected com0 to ch1, you cannot connect com0 to ch2 before disconnecting the previous com0 from ch1. The existence of analog bus channels adds to the complexity of requirements. While you cannot connect a com channel to more than one channel at a time, you can connect the same com channel to an associated analog bus channel regardless of its connection state.

To solve the issue of common multiplexer channels, the LabWindows/CVI wizard generates a skeleton code that can be modified to fit your needs of your module. The connection matrix stores the information about the channel role, whether a channel is a com channel, an analog bus channel, or regular channel.

Figure 19 shows the macros in the driver source that are generated by the LabWindows/CVI wizard.

Figure 19: Connection Matrix Macros Manipulation

 

These macros are used by routing algorithms to perform connect, disconnect, and route query operations on the driver session. You do not need to understand the algorithm to successful development of a driver, but it is good to know at least the basics of the connection matrix and the associated manipulation functions and macros. The driver uses these macros and functions to determine the connectivity of given endpoints on the live device and during simulation.

Now let us look closely at the generated driver code, and the way to implement the guards on the common mux channels, to prevent the common mux channels from connecting to more than one channel at a time. We can formulate this requirement differently to allow the common mux channel to connect only to an analog bus channel if it is already connected to another channel. Figure 20 shows the function generated by the LabWindows/CVI wizard that handles this behavior.

Figure 20: Mux Channel Connectivity Functions


This function needs to be replaced with the following, model for common mux channel connectivity. Again we will make use of the connection matrix to store information about the channels. Instead of using an IVI attribute (the LabWindows/CVI wizard generates sample that uses the MYSWITCH_ATTR_IS_MUX_CHANNEL attribute), we will use the existing connection matrix and assign a bit in the 32-bit element of the matrix to denote the channel classification. To do that, we need to add two definitions of a bit field for our two channel roles: MYSWITCH_VAL_IS_ABUS_CHANNEL and MYSWITCH_VAL_IS_MUX_CHANNEL. Refer to Figure 21 for details.

Figure 21: Definition of New bit–fields in the Connection Matrix Element for the Channel Role


With the bit-field constant in place, we need to add new macros for accessing the state of a channel, right after the existing connection matrix manipulation macro definitions:

#define mySwitch_isAnalogBusChannel(ch) ((connections[ch][1]&MYSWITCH_VAL_IS_ABUS_CHANNEL)!=0)

#define mySwitch_markAnalogBusChannel(ch) \
{                                                  \
   connections[ch][1]|=MYSWITCH_VAL_IS_ABUS_CHANNEL;  \
}
                       
#define mySwitch_markAsMuxCommon(ch) \
{                                        \
   connections[ch][1]|=MYSWITCH_VAL_IS_MUX_CHANNEL;   \
}

#define mySwitch_isCommonMuxChannel(ch) ((connections[ch][1]&MYSWITCH_VAL_IS_MUX_CHANNEL)!=0)

Now that infrastructure is ready, you need to modify two functions in the driver. First, you need to use the “mark” macros in the initialization routine, right after you create the connection matrix. The example topology that clearly shows what you need to do is the 4x1 mux with the analog bus channel. Assuming the a channel list: {ab0, com0, ch0, ch1, ch2, ch3}, the code that populates the connection matrix is:

// prepare the matrix by marking all as not connectable
   for (i=1; i<=6 /*numChannels*/; i++)
   {
      for (j=1; j<=6 /*numChannels*/; j++)
      {
         connections[i][j]=MYSWITCH_VAL_DIRECT_CONNECTION_IMPOSSIBLE;
      }
   }

   // channel list has a-bus, then a common, and then channels
   mySwitch_markAnalogBusChannel(1);
   // abus can connect only to com0;
   // i.e. first two channels can connect
   connections[2][1] = connections[1][2] = 0;
   // now, common channel can connect to all other channels
   mySwitch_markAsMuxCommon(2);
   for (i=2; i<6 /* numChannels */; i++)
   {
      connections[2][i+1] = connections[i+1][2] = 0;
   }

Second, you need modify the function that checks for the prohibited connections, that is connections to the com channel from the channels when another channel is already connected to the com channel:

/*********************************************************************
 *            Function: mySwitch_IsConnectedMuxChannel
 *            Purpose:  This function verifies that you are not trying to connect
 *            a channel to a mux common without previously marking the
 *            common channel as available by attempting to disconnect
 *            it.
 **********************************************************************/
static ViStatus mySwitch_IsConnectedMuxChannel (ViSession vi,
                                    ViConstString channel,
                                    ViBoolean *isConnectedMuxChannel)
{
   ViStatus    error = VI_SUCCESS;
   ViInt32     ndxCommon;
   ViBoolean   connected = VI_FALSE;
   ViInt32     i, numChannels;
   ViInt32     **connections;
   
   checkErr( Ivi_GetAttributeViAddr (vi, VI_NULL,
                                     MYSWITCH_ATTR_CHANNEL_MATRIX,
                                     0, (ViAddr*)&connections));
   checkErr( Ivi_GetAttributeViInt32 (vi, VI_NULL,
                                      MYSWITCH_ATTR_CHANNEL_COUNT,
                                      0, &numChannels));
   checkErr( Ivi_GetChannelIndex (vi, channel, &ndxCommon));
   // the common mux channel is considered 'connected' only if it
   // connects to one of its output channels, not to an
   // analog bus channel
   if (mySwitch_isCommonMuxChannel(ndxCommon))
   {
      for (i=1; !connected && (i <= numChannels); i++)
      {
         connected=mySwitch_ChannelsAreExplicitlyConnected(ndxCommon,i)
                  && !mySwitch_isAnalogBusChannel(i);
      }
   }
Error:
   *isConnectedMuxChannel = connected;
   return error;
}

Implementing the Communication with the Instrument

Modifying the Source Code

The switch driver algorithm breaks down the requested route into path legs, and passes those path legs to the mySwitch_ConnectPathOnInstrument and mySwitch_DisconnectPathOnInstrument functions. Now you have to translate the two channels into the specific instrument I/O commands and perform the instrument I/O.

Figure 22: Connecting Path with the Code Generated by the LabWindows/CVI Wizard
 


Inside the CHANGE block of code, you have channel strings channel1 and channel2, and all you need is translate those channels into the specific instrument commands. For completed examples, you can look at other switch drivers created with CVI. Drivers at the NI INstrument Driver Network web site are developed using CVI and can be used as a reference.

 

Special Considerations for Form C Relays

As we have mentioned before, the specification treats all switch modules as black boxes with connection points called I/O channels. For general purpose switches with form C relays, it means that instead of opening a relay, the driver needs to disconnect the com channel from no channel.

Since the form C relay can never disconnect all of its connections in the IVI sense (disconnect all channels from all channels), the developer needs to decide how to interpret the behavior of the disconnect function. When a user calls the disconnect function, the driver shall reflect the connectivity of the endpoint channels in the connection matrix, marking them as disconnected. For the actual instrument, you have three options:

  • Don’t change the state of the relay.
  • Always set the relay to one (default) position.
  • Always actuate the relay to the opposite position.


All three options are valid as far as the IVI class specification is concerned. In all cases, the switch driver will leave a connection closed. Both the disconnect and the disconnect all functions needs to return a warning. As far as to which option to choose between the three mentioned above, the first one statistically means the least number of relay operations and is best for preserving relay life. Moreover, for the user of an IviSwtch API, it does not matter and should not matter what the relay state is after calling disconnect. The only way to ensure that ensure that the specific path is closed is to call the connect function.

Therefore, the best implementation for form C switch drivers is to not implement the mySwitch_DisconnectPathOnInstrument at all. Remove the function from the driver, and remove the only reference to it from the mySwitch_Disconnect function. The implementation of the mySwitch_Disconnect function is shown on Figure 23.

Figure 23: Implementation of the Disconnect Function for Form C Relays

 

Finishing your Driver

Now that the core of the driver is created, you need to perform the two remaining tasks:

  • Populate the default values for the signal characteristics attributes.
  • Resolve all CHANGE comments in the driver.


When we ran the IVI instrument driver development wizard, we chose not to execute the attribute editor. The IviSwtch specification defines a handful of attributes that describe the switch module electrical specification. NISE uses these attributes to evaluate channels conformance with the route constraints defined by the Switch Executive Virtual Device.

 

References


IVI Foundation Specifications

IVI-3.1: Driver Architecture Specification
IVI-3.2: Inherent Capabilities Specification
IVI-3.3: Standard Cross-Class Capabilities
IVI-4.6: IviSwtch Class Specification