Admin Production ni-theme
Current Publication

Creating and Declaring Attributes

LabWindows/CVI

Creating and Declaring Attributes

An instrument driver creates the specific and class attributes it uses by calling the Ivi_AddAttribute or Ivi_AddRepeatedAttribute functions. The IVI Engine provides specializations of these functions for each of the supported attribute data types such as Ivi_AddAttributeViInt32 and Ivi_AddRepeatedAttributeViBoolean. In the source file for the driver, the driver must declare constant names for all the hidden attributes.

The IVI Engine creates the inherent IVI attributes for each session. The include file for the driver, however, must define constant names for all public attributes. The driver include file presents a unified view of all attributes that the user can use in conjunction with the instrument driver.

Attribute IDs

Each attribute in an instrument driver must have a distinct integer ID. You must define a constant name for each attribute in the include file or the source code for the instrument driver. The constant name must begin with PREFIX_ATTR_, where PREFIX is the instrument prefix.

The include file for a specific instrument driver must define constant names for all the public attributes including attributes that the IVI Engine defines, attributes that the instrument class defines, and attributes that are specific to the particular instrument.

Note Note  The Tools»IVI Development»Create IVI Specific Driver and Tools»IVI Development»Edit IVI Specific Driver Attributes commands automatically create the correct attribute constant definitions.

Inherent IVI Attributes

For each inherent IVI attribute, use the same constant name that appears in ivi.h but replace the IVI prefix with the specific instrument prefix. For example, ivi.h defines IVI_ATTR_CACHE, and the Fluke 45 include file, fl45.h, contains the following definition:

#define FL45_ATTR_CACHE IVI_ATTR_CACHE

Class Attributes

For each class attribute, use the same constant name that appears in the class include file but replace the class prefix with the specific instrument prefix. For example, the DMM class include file, ividmm.h, defines IVIDMM_ATTR_RESOLUTION, and fl45.h contains the following definition:

#define FL45_ATTR_RESOLUTION IVIDMM_ATTR_RESOLUTION

Instrument Specific Attributes

For each instrument specific attribute that the user can access, define a constant name in the instrument driver include file and assign a value that is an offset from IVI_SPECIFIC_PUBLIC_ATTR_BASE. For example, fl45.h contains the following definition:

#define FL45_ATTR_HOLD_THRESHOLD \ (IVI_SPECIFIC_PUBLIC_ATTR_BASE + 3)

For each instrument specific attribute that is hidden from the user, define a constant name in the driver source file and assign a value that is an offset from IVI_SPECIFIC_PRIVATE_ATTR_BASE. For example, hp34401.c contains the following definition:

#define HP34401_ATTR_TRIGGER_TYPE \ (IVI_SPECIFIC_PRIVATE_ATTR_BASE + 1)

Attribute Flags

Each attribute has a set of flags that you can use to specify various types of behavior. You set the flags as bits in a ViInt32 value you specify when you create the attribute using one of the Ivi_AddAttribute functions. You can query and modify the flags for an attribute using Ivi_GetAttributeFlags and Ivi_SetAttributeFlags.

To set multiple flags, bitwise OR them together. For example, if you want an attribute to be read-only and never cached, use the following flags:

IVI_VAL_NOT_USER_WRITABLE|IVI_VAL_NEVER_CACHE

The following table lists the IVI attribute flags. A detailed discussion of each flag follows the table.

Bit(s) Value Flag
0 0x0001 IVI_VAL_NOT_SUPPORTED
1 0x0002 IVI_VAL_NOT_READABLE
2 0x0004 IVI_VAL_NOT_WRITABLE
3 0x0008 IVI_VAL_NOT_USER_READABLE
4 0x0010 IVI_VAL_NOT_USER_WRITABLE
3 , 4 0x0018 IVI_VAL_HIDDEN
5 0x0020 IVI_VAL_NEVER_CACHE
6 0x0040 IVI_VAL_ALWAYS_CACHE
10 0x0400 IVI_VAL_MULTI_CHANNEL
11 0x0800 IVI_VAL_COERCEABLE_ONLY_BY_INSTR
12 0x1000 IVI_VAL_WAIT_FOR_OPC_BEFORE_READS
13 0x2000 IVI_VAL_WAIT_FOR_OPC_AFTER_WRITES
14 0x4000 IVI_VAL_USE_CALLBACKS_FOR_SIMULATION
15 0x8000 IVI_VAL_DONT_CHECK_STATUS
  • IVI_VAL_HIDDEN—The combination of IVI_VAL_NOT_USER_READABLE and IVI_VAL_NOT_USER_WRITABLE. Use the IVI_VAL_HIDDEN flag when you create attributes that you do not want the user to access.
  • IVI_VAL_NOT_SUPPORTED—Indicates that the class driver defines the attribute, but the specific driver does not implement it.
  • IVI_VAL_NOT_READABLE—Indicates that neither users nor instrument drivers can query the value of the attribute. Only the IVI Engine can query the value of the attribute.
  • IVI_VAL_NOT_WRITABLE—Indicates that neither users nor instrument drivers can modify the value of the attribute. Only the IVI Engine can modify the value of the attribute.
  • IVI_VAL_NOT_USER_READABLE—Indicates that users cannot query the value of the attribute. Only the IVI Engine and instrument drivers can query the value of the attribute.
  • IVI_VAL_NOT_USER_WRITABLE—Indicates that users cannot modify the value of the attribute. Only the IVI Engine and instrument drivers can modify the value of the attribute.
  • IVI_VAL_NEVER_CACHE—Directs the IVI Engine to never use the cache value of the attribute, regardless of the state of the IVI_ATTR_CACHE attribute. The IVI Engine always calls the read and write callbacks for the attribute, if present.
  • IVI_VAL_ALWAYS_CACHE—Directs the IVI Engine to use the cache value of the attribute, if it is valid, regardless of the state of the IVI_ATTR_CACHE attribute.
  • IVI_VAL_MULTI_CHANNEL—Indicates that the attribute has a separate value for each channel. You cannot modify this flag using Ivi_SetAttributeFlags.
  • IVI_VAL_COERCEABLE_ONLY_BY_INSTR—Indicates that the instrument coerces values in a way that the instrument driver cannot anticipate in software. Do not use this flag unless the coercion algorithm of the instrument is undocumented or too complicated to encapsulate in a range table or a coerce callback. When you query the value of an attribute for which this flag is set, the IVI Engine ignores the cache value unless it obtained the cache value from the instrument. Thus, after you call an Ivi_SetAttribute function, the IVI Engine invokes the read callback the next time you call an Ivi_GetAttribute function. When you set this flag, the IVI Engine makes the following two assumptions that allow it to retain most of the benefits of state caching.

    • The instrument always coerces the same value in the same way.
    • If you send the instrument a value that you obtained from the instrument, the instrument does not coerce the value.

    Based on these two assumptions, the IVI Engine does not invoke the write callback for the attribute when you call an Ivi_SetAttribute function with the same value you just sent to, or received from, the instrument. If one or both of these assumption are not valid, use the IVI_VAL_NEVER_CACHE flag instead.
  • IVI_VAL_WAIT_FOR_OPC_BEFORE_READS—Directs the IVI Engine to call the operation complete callback for the session before calling the read callback for the attribute.
  • IVI_VAL_WAIT_FOR_OPC_AFTER_WRITES—Directs the IVI Engine to call the operation complete callback for the session after calling the write callback for the attribute.
  • IVI_VAL_USE_CALLBACKS_FOR_SIMULATION—Directs the IVI Engine to invoke the read and write callbacks for the attribute even when in simulation mode.
  • IVI_VAL_DONT_CHECK_STATUS—By default, when a user calls one of the Prefix_GetAttribute or Prefix_SetAttribute functions in an instrument driver and the IVI_ATTR_QUERY_INSTR_STATUS attribute is enabled, the IVI Engine calls the check status callback for the session after calling the read or write callback for the attribute. This flag directs the IVI Engine never to call the check status callback for the attribute.

Range Tables

For each ViInt32, ViInt64, or ViReal64 attribute, you can specify a range table that describes the valid values for the attribute. The IVI Engine uses the table to validate and coerce values for the attribute. The write callback for the attribute also can use the table to associate each value with a command string to send to the instrument. Similarly, the read callback can use the table to convert a response string from the instrument into an attribute value.

Range Table Structures

The typedefs for IviRangeTable, IviRangeTableEntry, and IviRangeTableEntryViInt64 in ivi.h describe structures you use to define range tables as follows:

typedef struct /* describes one range table entry */

{

ViReal64 discreteOrMinValue;
ViReal64 maxValue;
ViReal64 coercedValue;
ViString cmdString; /* optional */
ViInt32 cmdValue; /* optional */

} IviRangeTableEntry;

typedef struct /* describes one ViInt64 range table entry */

{

ViInt64 discreteOrMinValue;
ViInt64 maxValue;
ViInt64 coercedValue;
ViString cmdString; /* optional */
ViInt32 cmdValue; /* optional */

} IviRangeTableEntryViInt64;

typedef struct /* describes the entire range table */

{

ViInt32 type; /* discrete, ranged, or coerced */
ViBoolean hasMin;
ViBoolean hasMax;
ViString customInfo;
void* rangeValues;

} IviRangeTable;

The rangeValues field contains a pointer to an array of IviRangeTableEntry structures. The array must contain a termination entry in which the cmdString field contains IVI_RANGE_TABLE_END_STRING. The ivi.h include file defines IVI_RANGE_TABLE_END_STRING as ((ViString)(-1)). The ivi.h include file also defines the IVI_RANGE_TABLE_LAST_ENTRY macro, which you can use to represent an entire termination entry.

Three types of range tables exist. The type determines how you interpret the discreteOrMinValue, maxValue, and coercedValue fields in the IviRangeTableEntry structure. Indicate the type in the type field of the IviRangeTable structure. The three types are as follows:

  • IVI_VAL_DISCRETE—In a discrete range table, each entry defines a discrete value. The discreteOrMinValue contains the discrete value. The maxValue and coercedValue fields are not used.
  • IVI_VAL_RANGED—In a ranged range table, each entry defines a range with a minimum and a maximum value. The discreteOrMinValue field holds the minimum value. The maxValue field holds the maximum value. The coercedValue field is not used. If the attribute has only one continuous valid range and you do not assign different command strings or command values to subsets of the range, the range table contains only one entry other than the terminating entry.
  • IVI_VAL_COERCED—In a coerced range table, each entry defines a discrete value that represents a range of values, which is useful when an instrument supports a set of ranges and when you must specify those ranges to the instrument using one discrete value. The discreteOrMinValue field holds the minimum value of the range. The maxValue field holds the maximum value. The coercedValue field holds the discrete value that represents the range.

The discreteOrMinValue, maxValue, and coercedValue fields are of type ViReal64 for ViInt32 and ViReal64. These fields for ViInt64 attributes are of type ViInt64.

The IVI Engine exports functions that access entries in the range tables. Examples of these functions include Ivi_GetViInt32EntryFromValue and Ivi_GetViInt32EntryFromCmdValue. Refer to the LabWindows/CVI Help for more information about using these and other range table functions.

Use the cmdString field to store the command string used by the write callback to set the instrument to the value defined in the range table. The read callback also can use the cmdString field to convert a response string from the instrument into an attribute value. If you do not want to associate a command string with each value, you can set the cmdString field to VI_NULL.

For a register-based instrument, you can use the cmdValue field to store the register value. The write callback uses this register value to set the instrument to the value that the range table entry defines. For a message-based instrument, you can use the cmdValue field to store an integer value that the attribute write callback formats into an instrument command string. You can use the customInfo field to store the format string for the instrument command.

The hasMin and hasMax fields indicate whether the table contains a relevant minimum value and maximum value. The Ivi_GetAttrMinMaxViInt32, Ivi_GetAttrMinMaxViInt64, and Ivi_GetAttrMinMaxViReal64 functions use these fields to determine whether they can calculate the minimum and maximum values that the instrument implements for an attribute. For coerced range tables, these functions use the coercedValue field to calculate the minimum and maximum values that the instrument actually implements. In discrete range tables that contain values that represent non-numeric settings, assign VI_FALSE to the hasMin and hasMax fields. For example, the measurement function attribute of a DMM does not have a relevant minimum or maximum value.

If you select Tools»IVI Development»Edit IVI Specific Driver Attributes, you can view and modify range tables in a dialog box. The Edit IVI Specific Driver Attributes command requires that the name of the array of IviRangeTableEntry structures always be the name of the IviRangeTable structure followed by Entries.

Discrete Range Table Example

The following is an example of a discrete range table.

static IviRangeTableEntry functionTableEntries[] = {
	/* discrete value */			/* cmdString */
	{FL45_VAL_DC_VOLTS,		0, 0,	"VDC", 0},
	{FL45_VAL_AC_VOLTS,		0, 0, 	"VAC", 0},
	{FL45_VAL_AC_PLUS_DC_VOLTS,	0, 0, 	"VACDC", 0},
	{FL45_VAL_DC_CURRENT,		0, 0, 	"ADC", 0},
	{FL45_VAL_AC_CURRENT,		0, 0, 	"AAC", 0},
	{FL45_VAL_AC_PLUS_DC_CURRENT,	0, 0,	"AACDC", 0},
	{FL45_VAL_2_WIRE_RES,		0, 0, 	"OHMS", 0},
	{FL45_VAL_FREQ,			0, 0,	"FREQ", 0},
	{FL45_VAL_CONTINUITY, 		0, 0, 	"CONT", 0},
	{FL45_VAL_DIODE,		0, 0,	"DIODE", 0},
	{IVI_RANGE_TABLE_LAST_ENTRY}
};

static IviRangeTable functionTable = {

IVI_VAL_DISCRETE, /* type */
VI_FALSE, /* hasMin */
VI_FALSE, /* hasMax */
VI_NULL, /* customInfo */
functionTableEntries,

};

This range table lists all the possible values for a DMM measurement function attribute. The table also lists the command strings the driver uses to set the instrument to each possible value and convert instrument response strings to attribute values.

Coerced Range Table Example

The following is an example of a coerced range table.

static IviRangeTableEntry resolutionTableEntries [] = {
	/* min max coerced cmdString */
	{0.0, 4.5, 4.5, "F", 0},
	{4.5, 5.5, 5.5, "M", 0},
	{5.5, 6.5, 6.5, "S", 0},
	{IVI_RANGE_TABLE_LAST_ENTRY}
};

static IviRangeTable resolutionTable = {

IVI_VAL_COERCED, /* type */
VI_TRUE, /* hasMin */
VI_TRUE, /* hasMax */
VI_NULL, /* customInfo */
resolutionTableEntries

};

This range table lists all the possible ranges for a DMM resolution attribute, in terms of digits of precision. For each range, the range table specifies a coerced value. In this case, the coerced value is the highest value in the range. The table also lists the command string the driver uses to set the instrument to each possible coerced value and convert instrument response strings to coerced values.

Ranged Range Table Example

The following is an example of a ranged range table.

static IviRangeTableEntry triggerDelayTableEntries [] = {
	/* min		max */
	{1.0e-6, 100.0, 0, VI_NULL, 0},
	{IVI_RANGE_TABLE_LAST_ENTRY}
};

static IviRangeTable triggerDelayTable = {

IVI_VAL_RANGED, /* type */
VI_TRUE, /* hasMin */
VI_TRUE, /* hasMax */
VI_NULL, /* customInfo */
triggerDelayTableEntries

};

This range table declares the minimum and maximum value for a trigger delay attribute.

Static and Dynamic Range Tables

A static range table is a single range table associated with an attribute. Pass the range tables address to Ivi_AddAttributeViInt32, Ivi_AddAttributeViInt64, and Ivi_AddAttributeViReal64 to make this association.

Some cases exist in which the set of valid values for one attribute depends on the current setting of another attribute. In such cases, you can define multiple static range tables for the attribute. Instead of specifying one range table when you call Ivi_AddAttributeViInt32, for example, call Ivi_SetAttrRangeTableCallback to install a range table callback. Each time the IVI Engine invokes the range table callback, the callback must obtain the value of the second attribute and then return a pointer to the appropriate range table.

You can obtain the address of the current range table for an attribute by calling Ivi_GetAttrRangeTable. Ivi_GetAttrRangeTable invokes the range table callback if the attribute has one. Otherwise, Ivi_GetAttrRangeTable returns the address of the range table you specify when you call Ivi_AddAttributeViInt32, Ivi_AddAttributeViInt64, or Ivi_AddAttributeViReal64. You can call Ivi_GetStoredRangeTablePtr to bypass the range table callback and get the address of the range table you specify when you call Ivi_AddAttributeViInt32, Ivi_AddAttributeViInt64, or Ivi_AddAttributeViReal64. You can replace this range table with a different one by calling Ivi_SetStoredRangeTablePtr.

In certain instances, the set of valid values for an attribute varies so much that you must create a large number of static range tables for the attribute. A better approach in this case is to modify the contents of a single range table depending on the current settings of other attributes. If you want to modify the contents of a range table dynamically, you must create a dynamic range table using Ivi_RangeTableNew. You also must install a range table callback using Ivi_SetAttrRangeTableCallback. In the range table callback, you modify the contents of the range table and then return its address.

To allow for multithreading and multiple sessions to the same instrument type, you must create a separate dynamic range table for each IVI session. Pass the address of the dynamic range table to Ivi_AddAttributeViInt32, Ivi_AddAttributeViInt64, or Ivi_AddAttributeViReal64 when you create the attribute. Your range table callback then can use Ivi_GetStoredRangeTablePtr to obtain the address of the dynamic range table for the session before modifying its contents.

Default Check and Coerce Callbacks

The IVI Engine supplies default check and coerce callback functions that use the range tables. When you specify a static range table callback for an attribute, the IVI Engine automatically calls the default check callback. For coerced range tables, the IVI Engine also calls the coerce callback. When you specify a range table callback for an attribute, the IVI Engine automatically calls the default check and coerce callbacks. The following are the names of the default callbacks that use range tables.

  • Ivi_DefaultCheckCallbackViInt32
  • Ivi_DefaultCoerceCallbackViInt32
  • Ivi_DefaultCheckCallbackViInt64
  • Ivi_DefaultCoerceCallbackViInt64
  • Ivi_DefaultCheckCallbackViReal64
  • Ivi_DefaultCoerceCallbackViReal64

You can invoke the default callbacks from your own check and coerce callbacks. To add functionality to one of the default callbacks, call a callback that performs the additional functionality before or after calling the default callback.

Comparison Precision

Because of the imprecision inherent in the computer representation of floating-point numbers, it is not always possible to determine if two ViReal64 values are equal by comparing them based on strict equality. When attempting to find ViReal64 values in range tables, the IVI Engine performs comparisons using 14 decimal digits of precision.

Some instruments represent floating-point numbers differently than computers do. Consequently, comparisons between instrument and computer floating-point numbers can be less precise than comparisons between two computer floating-point numbers. The IVI Engine makes a comparison between an instrument and a computer floating-point number whenever it compares an attribute cache value it obtained from the instrument against a new value to which you attempt to set the attribute. If the values are equal within the degree of precision that you specify for the attribute, the IVI Engine does not invoke the write callback.

Call Ivi_AddAttributeViReal64 to specify the degree of precision for an attribute. You can specify from 1 to 14 digits of precision. The more digits of precision, the closer the two values must be for the IVI Engine to consider them equal. To obtain or modify the degree of precision for an attribute, call Ivi_GetAttrComparePrecision or Ivi_SetAttrComparePrecision.

The IVI Engine uses the compare precision when the binary representations of two ViReal64 values are not exactly equal. The IVI Engine uses the following logic, where a and b are the values you want to compare, and d is the number of digits of precision.