TestController, Configuration of a SCPI devices

FirstImage

Many SCPI devices can be configured without any real programming, "just" by writing a configuration file. All existing devices have a configuration file that can be looked in for examples.
Non SCPI devices have internal driver code and used the definitions as a supplement to this, multiple devices may share the same internal driver, but with different definition files.
Main Test controller page


Contents
    Device drivers overview
    Difference between the 3 SCPI/ascii drivers (SCPI, SCPIx, Ascii)
        SCPI
        SCPIx
        Ascii
    Definition overview
    The device identification and connection parametes
    GPIB settings
        GPIB Control
    Data type definitions
    Basic communication
        #initCmd
        #finalCmd
        #prepareSample
        #askMode
        #modeFromValue
        #askValues
        #outputOff
    Fixing format and other issues
        readFormat
        mathFormat & readmath
        Timing issues
        Arduino startup reset
    Selecting mode (Mostly for multimeters)
    Selecting multiples modes
    Configuration menu
        Tags
        Control number
        Control numberInt
        Control numberDual
        Control text
        Control button
        Control buttons
        Control buttonsOn
        Control radio
        Control checkbox
        Control combobox
        Control comboboxHot
        Control info
        Control infoAsk
        Control slider
        Control indicator
        Control indicatornum
        Control multi
        Control set
        Control separator
        Control color
        Control selector
        Control updater
    A generic interface
        Definition of set...
        Definition of get...
        Definition of read...
        The #interfaceType definition
    Miscellaneous tags
        #author
        #mayModifyMode
        #notes
        #noteImages
        #help
        #helpurl
    The Other popup
        #otherList
        #otherImage
        #otherData
        #otherFunc
        #otherText
        Examples
    Creating multiple devices from one configuration file
        #meta
        #metadef
        #idstring, #name, #handle, #port, #driver, #baudrate, #subdriver, #baudrate, #subdriver, #usbvendor, #eol, #verifydevice, #help, #checksum
        #replace
        #remove
        #removeline
        #replacetext
        #sections
        #metaDebug
    Protocol is nearly SCPI, but there is a few issues (SCPIx)
    User supplied stuff
Non SCPI device drivers
Main page
Functions for use in calculator and definitions



Device drivers overview

NameTypeInterfacePurpose
SCPICommandAsciiSCPI and SCPI like devices
SCPIxCommandAsciiNearly SCPI devices (Many Chinese SCPI imlementations)
AsciiCommandAsciiDevices with ascii commands (Many old devices)
SingleValueStreaming, pollAsciiDMMs that sends a single line with value and unit
Binary DMM protocolStreamingBinaryDMMs that sends binary data (Like 7 segment encoding)
ModbusCommandBinaryDevices with Modbus
AsciiBinCommandBinaryDevices that packs ascii data in a binary frame
BlockStreaming, poll, commandBinary Binary fixed length data block
AsciiBlockStreaming, poll, commandBinaryMulti line ascii and ascii blocks

TestController contains other drivers, they are generally designed for a specific device or specific series of devices. These are not included in the documentation.
Type command is drivers where TestController send a command and wait for answer each time a value must be updated.
Type streaming is drivers where the device send a message continuous with its states/values.
Type poll is where the device need a command to send a message, but it do not support anything else or is very slow to answer.

Type streaming and poll will be running in the background and not slow down update or logging in TestController, but may return the same value multiple times.

Ascii interface is a text based interface where each line from the device ends with a CR or LF character.
Binary interface send binary data and CR/LF and other control characters have no special meaning.
TestController will select interface depending on device driver. Using a interface that do not support the required Ascii/Binary format will prevent the definition from loading.

Possible interface for driver:


Difference between the 3 SCPI/ascii drivers (SCPI, SCPIx, Ascii)

Test controller supports 3 different main drivers for two way ascii communication with a device, in some ways they are similar, but there is also significant differences.

SCPI

This is the default driver and is used when no driver is specified.


SCPIx

This is a slightly modified SCPI driver


Ascii

This driver is for devices that do not follow SCPI command syntax (Like sending answers to commands without a ? character).


Definition overview

A device definition consist of different sections, some are mandatory before the device will work at all, other is nice to have, but not strictly required. The sections are not separated in the device configuration, but the identification section must be first for the definition always to work.

The sections are:
The 3 first sections must be implemented for the device to work at all. For bench multimeters a mode selection is usually required and for power supplies, electronic loads, and many other devices a configuration menu is very nice to have.
The interface is never required, but will make scripting much more flexible.

It is possible to create multiple similar devices from one configuration file, this has its own chaper.



The device identification and connection parametes

These must be placed first in the configuration file.

The start of the file is:
Code:
#idString first two parts of *idn? answer
#name The device name
#handle A short handle
#port The port used
#baudrate Baudrate for serial devices
#driver Internal driver to use, not used for SCPI
#help Help file to use
#eol Used to change the standard LF end of line to CR or CRLF.

Two real examples:
Code:
#idString Keysight Technologies,34465A,
#name Keysight 34465A
#handle K34465
#port 5025
Code:
#idString HEWLETT-PACKARD,34401A,
#name Agilent HP34401A
#handle HP34401
#port com
#baudrate 9600

The idstring is the brand name and the device name and must exactly match the text returned from the device, the two last parameters must not be included.
The name is the name used in TestController for the device

The port can contain one or more of off:
   Number: The port number for a socket connection, this is usually hidden somewhere in the documentation for the device.
   LXI: LXI connection.
   com: Serial port with baudrate setting on the "Load Devices" page.
   comFixedBaud: Serial port with fixed baudrate
   comNoBaud: A virtual serial port that do not use baudrate.
   GPIB: A IEEE488/GPIB port, this requires the use of a adapter, the adapter type is not related to the device configuration.
When multiple ports are listed it is possible to select between them with a combobox on the "Load devices" page.
For a modern device with multiple connections ports it could be something like:
Code:
#port number LXI com GPIB
Both number and LXI uses a network connection, com can be a physical RS232 port or a virtual USB com port, GPIB requires the use of a supported IEEE488/GPIB adapter.

The baudrate can be any baudrate, but can also contain more parameters line: 19200O71Dr
The D or d sets DTR high or low and R or r sets RTS high or low.
The last letter can be H for DTR flow control (Windows only) or h or RTS flow control.

For eol a string is used, to write control character escapes must be used, use: /r for CR and /r/n for CRLF



GPIB settings

The GPIB port has some settings that can be adjusted, these settings will track the device, i.e. multiple devices on the same GPIB adapter may use different settings:

Code:
#gpibReadEol eoi
#gpibReadEol characterNumber
#gpibWriteDelay timeInMs
#gpibWriteReadDelay timeInMs

The #gpibReadEol defines how the device terminiates its answers, the default uses eoi. Specifying "#gpibReadEol 10" would expect a LF character for terminating a answer.

#gpibWriteDelay will add a small delay after each GPIB write, this can slow down the processing for old slow devices.

#gpibWriteReadDelay minimum time before trying to read a answer from a device. If the GPIB adapter is connected to multiple devices, this time may be used for communicating with other devices.


GPIB Control

Some meters uses the control lines of the GPIB interface for specific functions, this can be controlled with special tags in the messages send to the interface. These messages will be ignored when other interfaces are used, this means generally they are only recommended to use on devices that only has a GPIB interface.


Data type definitions

This defines what data the device returns that must be shown on "Current values" and logged.
It will be one or more lines, each defining one data type, not all needs to be used at the same time or even used at all (The last part is when making definitions that cover multiple devices).

Code:
#value name unit format {selector}

A typical definition for a power supply:
Code:
#value Voltage V D3 
#value Current A D3 
#value VoltageSet V D3 
#value CurrentSet A D3 

A typical definition for a bench multimeter, only one is used at a time.
Code:
#value VoltageDC V d6 VDC,d
#value CurrentDC A si ADC
#value VoltageAC V d6 VAC
#value CurrentAC A si AAC
#value Resistance ohm si ohm,ohm4
#value Frequency Hz si hz
#value Ratio - d3 Ratio
#value Period s d6 Period

The name will be used for labeling the value and also for creating variables. It must be one word that starts with a letter and only contains letters, numbers or _.

The unit is shown at various places to help identify what the value is, for measurements without a unit use -.

The format uses a predefined numeric formats to show the value, the format used in a CSV file is not the same format as used on the screen, but will be with higher precision.
D0..D15 is floating point with 0 to 9 decimals.
X1..X15 is floating point with up to 1..9 decimals (A X0 is accepted and converted to a D0)
INT is integer format and is similar to D0, except when saving where it will save without any decimals.
SI will use SI prefix, i.e. Mkmu etc. after the number and will show from 0 to 7 decimals.
SI3..SI15 will use SI prefix and limit the number of digits (not decimals) to 3..9.
SI3..SI15x where x is on of _munpfazy will limit the minimum SI prefix to the specified prefix
DIGITAL(B0,B1,B2,...) This switches the value to digital mode, this means all values are converted to integer and handled as digital bits. The parameters are
names for each bit, use - to skip a bit. It is recommended to use short names (2 or 3 characters) for the bits.
TIME Use h:m:s format, value is in seconds.

The selector is used together with #askMode and #cmdMode, it is a list of device modes that must either match the mode name from #cmdMode or the result returned from #askMode. Multiple modes can be listed for each column, use a comma as delimiter.



Basic communication

This is the SCPI commands used to read and control the device. The SCPI commands can be listed after the tag with ; between them and/or on the following lines, until the next # tag.
Any command with a ? will be assumed to return an answer. A single line may contain multiple commands that each returns answer.
If a delay is needed between the SCPI commands use [delay].

Code:
#initCmd SCPI commands
#finalCmd SCPI commands
#prepareSample SCPI commands
#askMode SCPI commands
#askValues SCPI commands
#outputOff SCPI commands

Some examples, the different lines are not from the same device:
Code:
#askValues V1O?;I1O?;V1?;I1?
#askValues read?
#askValues :read? "defbuffer1",read
#initCmd :SYSTEM:REMOTE;[500]
#finalCmd abort;*cls;*rst;init;system:local
#prepareSample abort;sample:count 1;trig:source imm;trig:count inf;init


#initCmd

This command is used once after the device is connected, it is typically used to switch the user interface to remote control. This is not always required.



#finalCmd

This command is used once just before the connection is closed, it is typically used to switch the user interface to local control, turn power supplies off and set voltage and current to low values, turn electronic loads off and turn generators off.  This is not always required.



#prepareSample

This is used before reading from the device and after each mode change, this is used to setup trigger mode. This is not always required.



#askMode

Returns the current mode, this is used to select the data types to expect when reading from the device. It must match either either directly with the select from #value or with the mode from #cmdMode
The value from the meter may not always work directly, see next chapter for ways to modify the results.
The return string may contain multiple modes, this may be necessary for #cmdModeCheck
It is possible to add a button for a #askMode by using "#cmdModeGet" definition.



#modeFromValue

For devices that may change mode outside of TestController commands and where the actual mode can be decoded from #askValues, this definition can be used.
It need a expression to convert the answer from #askValues to a mode
It is strongly recommended to use same parameters to #askMode & #askValues, also #askModeMathFormat & #modeFromValue must use the same parameters.

Code:
;Answer from device is: mode,value
#askValues value?
#askValuesReadFormat xs

#askMode value?
#askModeMathFormat getElement(value,0)
#modeFromValue getElement(value,0)



#askValues

This is the SCPI string to return all data for "Current values" and logging, it can contain more command with ? in them, but it will limit the fastest logging rate. All values must be numeric values.
The input string is split into segments on all spaces, commas and semicolons and each segment is assumed to be a value.
The values from the meter may not always work directly, see next chapter for ways to modify the results.



#outputOff

Turn power supplies, electronic loads and generator output off. This definition is used when the "Outputs off" button is pressed.



Fixing format and other issues

When asking for values not all devices return just the value, some will add something before or after the value, this will prevent the #askValues & #askModes from working directly, the result must be adjusted a bit.

Code:
#askValuesReadFormat a list of what value to use and what value to remove
#askValuesMathFormat  expression, input is called value
#askModeMathFormat  expression, input is called value
#readingDelay time in seconds
#modeChangeDelay time in seconds



readFormat

This is a simple way to edit the returned values while converting the data to numbers. It consist of a list of characters, each with a specific meaning: The input is processes by readmath and split on , and space before using this function.



mathFormat & readmath

This makes it possible to run a script on the returned string, before any other processing is done. The original input string is called value.
A simple script may be to remove quotes around the value:

Code:
#askModeMathFormat unQuote(value);

See a list of useful functions here .
When using any type of readmath it may be a good idea to enable debugging. Use the command "#debug handle" where handle is the handle for the device you are working on. This will list a couple of items. Each item can be enabled with "#debug handle item".



Timing issues

There are a couple of ways to handle timing issues, each has advantages and disadvantages.

Use a [*OPC] tag (Not all devices support this) after the SCPI command will delay until that command is done, this can be a good solution when doing different types of mode changes, but may block the communication if used after a trigger command. The [*OPC] tag will not wait more than 10 second. This function uses the *OPC SCPI command followed by some *ESR? commands, when logging only the actual delay will be shown.

Use a [delay] tag after a SCPI command, the maximum delay is [9999]. This will give the device a fixed time to process the command, before more communication is attempted. This is a last resort solution, it is better to use [*OPC].

Example:
Code:
:OUTP:STAT ON;[*OPC]
:OUTP:STAT ON;[500]

Another way to handle a slow device is to increase the timeout. The default timeout is 1 second, this may not always be enough, there are two settings for this:

#readingDelay is used to allow more time for reading values from the device
#modeChangeDelay give the device time to change mode, a value of 10 (seconds) will usual be fine.



Arduino startup reset

TC has a build in 2 second delay when initializing serial ports, it is enough for the Arduinos I have worked with, but not for all types of Arduino.
There are two ways to extend this delay:
Code:
#resetDelay seconds

#resetDelay 3.5

Add the #resetDelay in the device definition, this will work when the device is loaded, but will not find it during a "Scan serial port" operation. It is recommended to use this for all Arduinos that requires more than 2 seconds to reset.
For also handling the "Scan serial port" a command line option can be used on TC, this option is resetDelay=seconds



Selecting mode (Mostly for multimeters)

Some devices can run in different modes, that may mean they will return different values. To control this a mode change menu need to be defined. These commands cannot be used while logging, because they need to change what columns of data the device returns.

PopupModeChange

It may look like the above.

Code:
#cmdMode modeLabel deviceModeString SCPI commands

Each mode (button) needs a definition consisting of:

A example for one mode:
Code:
#cmdMode ADC CURR:DC
*cls;
:SENSE:FUNCTION:ON "CURR:DC"
sense:curr:dc:nplc 1

All defined modes are shown in a popup window, where they are sorted in alphabetically order. It is possible to take over definition of this window by defining the window size:

Code:
#cmdModeLayout columns row

A button to request a #askMode can be defined with:
Code:
#cmdModeGet Button_Text


It is also possible to add empty positions with:
Code:
#cmdMode



Selecting multiples modes

For some devices it can be useful with some secondary modes, that can be secondary channel enabled mode or just a mode where more values are read from the device. These modes are handled with a checkbox in the mode popup.

Code:
#cmdModeCheck modeLabel deviceModeString defaultState
mode on commands
mode off commands
modes where this mode is valid, use ! to invert mode. (This line is optional)

If the mode on/off commands contain [localmode] the state of the mode is handled by TestController and need not be included in the #askMode. With local mode it may not be necessary to send commands to the device, but only to add more columns and modify the #askValues command with the [mode:xxx] tag.

Changing number of columns ad requested data, depending on device mode:
Code:
#value Value1 V D3 
#value Value2 V D3 Mode2

#cmdMode Mode1 m2 SCPI commands
#cmdMode Mode2 m2 SCPI commands

#askValues v1?;[mode:Mode2]v2?;


Changing number of columns, device mode is not used (Note: m2 test is not used, but must be present).
Code:
#value Value1 V D3 
#value Value2 V D3 Mode2

#cmdModeCheck Mode2 m2 0
[localMode]
[localMode]


#askValues v1?;[mode:Mode2]v2?;



Configuration menu

This is a popup form that allows setting parameters on the device. This part of the definition file can be the most complicated, depending on how much is included in the setup form.
Parameters cannot include spaces, but a underscore will be replace with a space when displaying a text.

popupSetupExmaple1
popupSetupExmaple2
popupSetupExmaple3

Above is a fairly complicated setup, but it do not support all functions on the device, only the most common.

Code:
#cmdSetup controlType name {page}
tags and parameters on the following lines

The definition looks simple enough. I will explain all the types and tags below, the name is the name shown to the left, it is possible to give multiple controls the same name. With no page defined the controls will be shown without any pages, but if a page is defined the menu will have a page for each name and controls without a page will be shown below the pages.
Generally each #cmdSetup will use one line on the form, but a few will combine on the same line if they have the same name. The form will use a grid with as many lines and columns as needed. Most elements in a control needs one column in the grid, but some elements may expand to more columns on grids with many columns.
A few controls do not directly add lines, but have other functions, they are: color, selector and updater
Most of the controls will synchronize with the device when the form is opened and when used, with a update tag it is also possible to make them synchronize when other controls are used. All controls with the same name will synchronize together.



Tags

Each item will have one or more tags with or without parameters.
*Some controls will create variables with their name or pageName.name if pages are used, they are:
Number, NumberInt, NumberDual (Adds 1 & 2 to the names), buttonsOn, radio, combobox, comboboxhot, Indicator, IndicatorInt, info
To check variable names, it is possible to use (It will fail, but not before showing a list of all variable names):
Code:
:enable: displayVar(split(getVarList(1),"\n"));"


Example of regular enable/visible usage:
Code:
:enable: Config==0
:enable: !Output_2.Output
:visible: inList(Output_1.Waveform,"SQUARE PULSE");


Control number

number

A single number, it uses a :read: to show the current setting in the box and a :write: to change the setting when the button is pressed. The button will be labeled "Set" but this can be changed with the :buttontext: tag.
After the tags there must be one configuration line with "unit min max"
It is possible to have one value outside the min-max range by using the :emptyvalue: tag. If a special SCPI command is needed to set this up use :emptywrite: with the command.

Code:
#cmdSetup number downTime
:read: downTime?
:write: downTime
:update: Frequency,Period
:tip: Time output is low in each period
sec 0 3600


Control numberInt

number

The same as number, but will not accept decimal numbers.



Control numberDual

numberdual

This control uses two input boxes on the same line, it uses the same tags as number.
After the tags there must be two lines each with four parameters: "unit min max name"

Code:
#cmdSetup numberDual Limits_1
:read: limits? 1
:write: limits 1
:tip: Limits, when output is outside an error is raised (Display shows RANGE)
°C -2048 2047.94 Low
°C -2048 2047.94 High



Control text

text

This control will use one input box that is as wide as possible. The only check and parameter that can be specified is a maximum length of the text. This can be used to send any text to a device. If only a few well defined text are accepted use a combobox instead.

Code:
#cmdSetup text up_Exp
:read: upExp?
:write: upExp
:tip: Formula for up part of wave
1000



Control button

button

A single wide button, there will be no name to the left, the button will use the full width.

Code:
#cmdSetup button Clear_protection Limits
:write: clearProtection
:tip: Clear current active protection (Display shows OCP or OPP)


Control buttons

buttons

One or more buttons on a line, these buttons will always have the name to the left. The command need a :write: tag and a line with two parameters for each button: "ButtonText SCPIParam"

Code:
#cmdSetup buttons RemoteSense
:write: SENSE1
:tip: Use sense wires to get exact voltage at target
Off 0
On 1


Control buttonsOn
buttonson

One or more buttons on a line with a indicator last on the line. A :read: tag is needed to get the status for the indicator, it will be on if the read value matches second parameter line. The rest is similar to buttons.
The read result is supposed to be a numeric result, use a :string: tag for a non-numeric result.

Code:
#cmdSetup buttonsOn Output
:read: OP1?
:write: TRIPRST;*cls;OP1
:tip: Turn output on or off
:updatealloff:
Off 0
On 1


Control radio

radio

A list of radio buttons that will send the setting when selected. A :read: tag is needed to select the current setting, if the returned value do not match any setting, none will be selected (It is valid to do this). The :write: tag will send the the command when a radio button is selected. For each radio button a line with two parameters are needed: "Text SCPIParam"
The read result is supposed to be a numeric result, use a :string: tag for a non-numeric result.
This creates a variable that use the name of the control (Like: Voltage for the example below) and will be the index of the checked radio button (0..) for numeric types and the actual value string for string types.

Code:
#cmdSetup radio Voltage
:read: V1?;
:readFormat: xf
:write: V1 #; OP1 1
:tip: Setup this voltage, turn output on
3.3V 3.3
5V 5.0
12V 12.0
24V 24.0
60V 60.0


Control checkbox

checkbox

A single checkbox that will set/reset a setting when checked/unchecked. Multiple checkboxes with the same name will be grouped on a single line.
Both the :read: and :write: tag is needed for this control. A single line with 3 parameters is needed: "Text uncheckedValue checkedValue".
The read result is supposed to be a numeric result, use a :string: tag for a non-numeric result.
This creates a variable that use the name of the control and the label (Like: Remote_sense.on for the example below) and will be either 0 or 1

Code:
#cmdSetup checkbox Remote_sense Main
:read: sense?
:write: sense
:update: Status
on 0 1


Control combobox

combo

A combobox that can be used to select between different non-numeric items. It needs both :read: and :write: tags and a line for each item in the checkbox with two parameters: "Text SCPIparam".
This creates a variable that use the name of the control (Like: Voltage for the example below) and will be the actual value string.


Code:
#cmdSetup combobox Waveform Output_1
:write: c1:BSWV WVTP,# 
:read: c1:BSWV?
:readmath: getElement(value,1,",")
:update: Frequency Periode Amplitude Offset Duty_cycle Symmetry Arbitrary
:updatedelayed: 0.1 
Sine SINE
Square SQUARE
Ramp RAMP
Pulse PULSE
Noise NOISE
Arbitrary ARB
DC DC



Control comboboxHot

comboxhot

This is similar to a combobox but will change the setting immediately when used and not wait for a press on a "Set" button. The configuration is the same.
This creates a variable that use the name of the control (Like: Voltage for the example below) and will be the actual value string.

Code:
#cmdSetup comboboxhot Sensor_1
:write: sensor 1
:read: sensor? 1
Type_B B
Type_E E
Type_J J
Type_K K
Type_N N
Type_R R
Type_S S
Type_T T
Voltage_1_(x8) x8
Voltage_2_(x32) x32


Control info

info

This is used to display information, multiple items with the same name will be combined on one line.
It needs a :read: tag and two lines each with one parameter, first line is unit, second line is text. To be updated other controls may need to list this control in their update tag.
This control will create vars for use in :visible: and :enable: tests, there name is control name combined with the text field.
The :layout: tag can be needed for this control.

Code:
#cmdSetup info Wave
:read: freq?
Hz
Frequency



Control infoAsk

infoAsk

This is used to display information, but only on request, this is typically used to fetch and show SCPI error messages. This control not show anything or update before the Get button is pressed.
It needs a :read: tag and can optionally have a line with a unit (Do not add the unit line for error messages).
The :layout: tag can be needed for this control.

Code:
#cmdSetup infoAsk Last_errors
:read: SYSTem:ERRor?
Unit



Control slider

slider

A slider that can be used for coarse adjustment of integer values. If much more than 10 steps or precise knowledge of the value is needed a numberInt control is probably better.
It need :read: and :write: tags and a single line with 3 parameters: "Text min max"

Code:
#cmdSetup slider Display_brightness
:read: BRIGHTNESS?
:write: BRIGHTNESS
:tip: 0=off, 1=Minimal brightness, 16=Maximal brightness
_ 0 16


Control indicator

indicator

indicator2

A indicator lamp, can be used to show the status of some functions (Typically output on/off). More indicators with same name will be grouped on one line.
It needs a :read: and one or more lines with 3 parameters each: "Text expression color".
The first line will be select when no match is found and the color will be in a off (low intensity) state. When a match is found the color will be shown at full intensity. The text will be shown next to the indicator.
The value returned from read is named "value" and the expression must not contain any spaces.
This creates some variable that use the name of the control and will be the value listed first on the definition lines. When multiple indicators is combined on a line a number (1, 2, 3, ...) is added to the name.
The variables created will be:

Code:
#cmdSetup indicator Mode
:read: mode?
Active 1 blue
Idle getElement(value,0)=="IDLE" yellow
Discharge getElement(value,0)=="DISC" red
Pulsing getElement(value,0)=="PULSE" magenta


Control indicatornum

indicator

This is the same as indicator, but instead of an expression it will match on a number. When grouping indicators on a line this will be grouped together with indicator, as long as the name match.
This creates some variable that use the name of the control and will be the value listed first on the definition lines. When multiple indicators is combined on a line a number (1, 2, 3, ...) is added to the name.
The variables created will be:


Code:
#cmdSetup indicatornum Status Main
:read: on?
:updatealloff:
Off 99 red
On 1 Red



Control multi

multi

This control is a a combination of other controls, in the above image it is four controls that are combined. It is using a compact layout where each control including label only takes one column in the layout. For the number format the "unit min max" is only shown in a tip.
The :string: tag will allow strings for info/checkbox/combobox
The supported controls are:
All controls must be read and written by one :read:/:write: line

Code:
#cmdSetup multi Entry
:read: entry? 0
:write: entry
info #
number Time _ 0 1000
number Value _ -1G 1G
checkbox Ramp 0 1



Control set

set

Like multi this will send multiple settings in one command, but for this control each setting is a standard control entry. This is useful when it is required to combine more than 3-4 settings in one command, i.e. when multi gets to large.
It will disable the set button on the selected controls.
It supports the following standard controls: number, numberInt, numberDual, text, combobox and multi
It cannot be used inside selector controls or use controls covered by a selector.
It will collect any :write: from the used controls and combine them to one long string, before using its own :write:
The :read: is not affected and must be defined in each control to initialise it, :read: in the set control is not used.

Code:
#cmdSetup set Update
:write: cmd
control1 control2 page.control3
delimiter

The delimiter is a optional string, use \x20 for a space



Control separator

separator

This control draws a line across the setup form, this can be used to separate groups of controls. A name must be present, but is not used (A - can be used).
It supports the :color: tag
There can optionally be one line of arguments with:
Solid:SeparatorSolid
Dual:SeparatorDual
DashedShort:SeparatorDashedShort
DashedLong:SeparatorDashedLong
Raised:SeparatorRaised
Sunken:SeparatorSunken
Empty:Empty space, no lines is drawn.

Code:
#cmdSetup separator - 
2 100 Solid



Control color

color

This control do not add a line to the setup, but adds a colored border to the setup form, it will also color the tab for multipage setups. It can be used for each page in a multipage control to match devices with color coded channels.
Like all #cmdSetup specifications it requires a name, it is never shown and can be a dash.
The color is either a name or (r,g,b) format. To find the rgb values a drawing program with a good color selector can be used.
It is also possible to use a :bgcolor: tag, this will change the background color for the page, but it is not recommended.

Code:
#cmdSetup color - Output_2
(250,140,20)


Control selector

By itself it is an invisible control, but it can control visibility of other controls. Invisible controls will not be updated, this means no slow update, even with many hidden controls. The controls can be enabled either based on a SCPI command or based on another control.
The first line with controls will be used for previews and when the value is empty.

Code:
#cmdSetup selector name {page}
expression
value1 control {control {control {control {control ...}}}}
value2 control {control {control {control {control ...}}}}
...

Code:
#cmdSetup selector name {page}
:read: SCPI command
value1 control {control {control {control {control ...}}}}
value2 control {control {control {control {control ...}}}}
...

The "control" is the name of a control, when pages are used use page.name or page. for all controls on that page (The page will not be created then, because all controls are inside the selector).
It is possible to include the same control on more than one selector value.
:update: & :enable: tags on the selector will affect all selected controls.
:update: & :enable: on the individual controls will only be active when the control is selected.



Control updater

This is an invisible control that is used to update other controls at regular intervals, generally it is not recommended to use, except for devices that do not disable local control.
This control only use a :update: tag that must list the controls to update and a single parameter line with one value that is the time in seconds between automatic updates.

Code:
#cmdSetup Updater update
:update:Out1 Out2 Out3 Out4 Out
0.5




A generic interface

This is a interface to use from scripting that is supposed to be mostly independent of selected device, making it easy to swap between different devices of the same type in a test setup. It can be used after an = sign or in expressions. There is a special test form in the "Popups" menu.

There are 3 primary groups of commands: In addition some support function will also be defined:
The ... is what to set/get/read, it will typically be:
For settings that is meant to limit the above value add min/max before the name, i.e. a SetMaxVoltage will set a value that prevents setVoltage higher than that. This only works for devices with native support implemented, TestController do not have any code to enforce it.

The call format for a function is one of:
Code:
setPower(device,value)
getPower(device)
readPower(device)
namePower(device)

Where device is a string with the device handle and optionally a ":channel" in the same string. Channel is used for multichannel devices and defines what channel to use, when not included 1 is assumed. Value is the desired value and is usually a number (Waveform and Mode are strings).

Code:
=readVoltage("QPX1200")

In log window:
;; 11.995
Code:
=readAmplitude("sdg2122x:2")

In log window:
;; 2.0


Definition of set...

Code:
#interface set... SCPICommand (value)
#interface set... SCPICommand (channel) (value)

The (value) and (channel) can contain expressions when needed.

Code:
#interface setVoltage voltage (value)
#interface setFrequency C(channel):BSWV FRQ,(value)
#interface setOn c(channel):outp (getElement("off on",value," "))


Definition of get...

Code:
#interface get... SCPICommand 
#interface get... SCPICommand (channel) 
:readmath:
:readformat:

This function gets a setting from the device. It is possible to use :readmath: and :readformat: to get the value into a acceptable format. In a few cases a :string: tag can be needed to allow string handling and returning a string value.

Code:
#interface getVoltage voltage?

#interface getAmplitude c(channel):BSWV?
:readmath: getElement(getMatch(value,"AMP,[^,]*,"),1,",")
:readformat: u


Definition of read...

Code:
#interface read... column
#interface read... column column...

The definition of read is very easy, because it uses the same reading as "current values" and logging, i.e. the "#askValues" command and only the actual index of the value must be specified. For multichannel devices multiple indexes must be listed, one for each channel. The first value the device returns is numbered 0.
The read definitions also defines a name... command that can be used to get the column name for the value from the actual device.


The #interfaceType definition

In addition to the actual interface calls it is also possible to assign a type to the device, this is used as a way to get a generic device from a script. This work likes this:
Code:
=var ps=getDevice("PS");
=setVoltage(ps,10);
=setCurrent(ps,1);
This means find the first power supply on the loaded device list and assigns its handle to ps. Now the different interface function can be used to setup parameters. Use getDevice("+PS") to get the second power supply or getDevice("PS:3") to get the 3 channel of the first power supply with 3 or more channels.

For this to work each device must have a #device type listing the possible types support be this device:
Code:
#interfaceType PS
#interfaceType PS PS:2 PS:3
First line is for a single channel power supply, second line is for a multichannel  power supply. A device may list more than one device type.

Device types: More will be added over time.



Miscellaneous tags

#author

This tag is used to add information to the about popup. All text after the tag is place on that popup, together with the name of the driver it is in.
It is a way to get credit for defining definitions for devices.


#mayModifyMode

Each tag list the start of a command, if there is a match to any command typed from the Command screen the current column layout is invalidated and a new one will be created using the askmode function.



#notes

This tag will add a small "view" button to the device list and pressing this button will show any text after #notes until the next # tag
This can be used to write about required settings on the device, limitations in the device definition, etc.
Only one #notes is supported, but as stated above it can be multiline.



#noteImages

This tag will add a small "view" button to the device list and pressing this button will show any images that is listed after the tag. The images will usually be stored on my server.
This can be used to show imaged with switches/jumpers that need to be set a specific way or in some cases a image of the device can be useful.



#help

Specifies the name of a file with help to the SCPI commands, this file is placed on my server and downloaded when the device is loaded. A local backup is kept in ...\Documents\TestController\Settings for offline conditions.
The device name is used as default file name when no #help tag is present.



#helpurl

This URL is used when F1 is pressed on a mode or setup popup.
It can link to a page describing how the device work in test controller (If anybody writes this type of pages I can host them).
It can also link to the manufactures page about the device or a manual for the device.
Using DEVICEIP for IP address/name will link to the device itself, if it uses a socket or LXI protocol.



The Other popup

This button/menu was added in V1.65, it access some device configuration and works very differently from the "Setup" popup, because it uses scripts to handle the functions. All functions defined here will run in the background, i.e. they do not block TestControllers user interface, but it is usually a bad idea to do other operations on the device will a transfer is in progress.
This requires a couple of entries in the configuration file.



#otherList

This entry is used to define the other menu, the menu will only be shown if a script here defines it (or a screendump definition exist). What is has to do is assign text lines to a array called menuItem.
This can be done two ways:
menuItem[0]="item1";
menuItem[1]="item2";
menuItem[2]="item3";
or
menuItem=array("item1","item2","item3");
There must not be any missing items in the array.
Each item must end with an extension, these extensions matches file extensions and defines what type of function is required:
.bmp .png .jpgWill assume it is image related.
This means a entry defined as: menuItem[0]="item1.png"; will be show as a menu entry called "Image: item1"

.csv Will assume it is a list of measurement data that can be transferred to the table is TestController.
This means a entry defined as: menuItem[0]="item1.csv"; will be show as a menu entry called "Data: item1"

.xxx Will assume it is a command (These are usually best put in the Setup popup), no data is accepted by TestController
This means a entry defined as: menuItem[0]="item1.xxx"; will be show as a menu entry called "item1"

Any other extension (Please use .txt) will assume it is a list of information that must be shown as text.
This means a entry defined as: menuItem[0]="item1.txt"; will be show as a menu entry called "Text: item1"

All menu entries will call a program at another tag depending on the extension. If there are more menu entries that calls the same tag it is possible to use the name variable to see the name of the menu entry that called the tag.



#otherImage

This function must fetch the named image (Menu entry name is present in variable name) and send it to the image viewer. The coding here will often be limited to using deviceReadBytes() and addImage().
For more complex downloads native code must probably be added to TestController.



#otherData

This function download data and adds them to the table page, replacing anything already in the table. This can work two ways: In both cases it is also a good idea to show a progress bar, this must be coded with popupShowProgressAsync() and popupShowProgressSetPosition()
It may be necessary to use modeColumnNames() to get the correct column names for a device.



#otherFunc

This can be used to do more advanced functions on the device where a script is required or to clear the log on devices where that requires a lot of keypresses.
Use the deviceWrite() function for writing commands and deviceRead() for reading values.



#otherText

This is for data that must be showed as text, it can be logged data that is unrelated (a entry saved each time a button is pressed) or it could be some other information from the device. For column based data it is a good idea to use a tab ("\t") separator, this allows the data to be easily copied to a spreadsheet.

The script must collect all the data in a string and return it when it is finished. This can be done by writing the variable name last in the script. The return data can also be collected with "print()" statement, these are combined and used as a function return value.
If it takes some time to collect the data it is a good idea to show a progress bar, this must be coded with popupShowProgressAsync() and popupShowProgressSetPosition()



Examples

I will not list examples, but instead list some definitions that uses these functions:
Keysight344xxA.txt can fetch a screen dump and access the internal flash drive for saved screen dumps and csv files.
KeysightU1461A.txt Download log data from some multimeters as either text or csv data.



Creating multiple devices from one configuration file

With similar devices it is possible to make many device definitions from one configuration file.



#meta

Mark a definition to not be include in the device list, but only used as the basic for other definitions. This type of definition is referred to by their filename (Without path and extension).



#metadef

Create a definition based on another definition, either a real definition or a #meta definition. It is possible to replace some tags, change parameters and remove tags, but it is not possible to add new tags. The original definition must contain everything needed.

Code:
#metadef
#metadef filename without path and extension
#metadef device name

The #metadef tag can be used 3 ways, without a name means it will expect a #meta definition in the same file and then with either the filename of a file with a #meta tag or the device name of a existing device configuration.

After the #metadef there will often be a couple of lines to modify the definition, but for definition in the same file there may be one #metadef without any modification instruction.



#idstring, #name, #handle, #port, #driver, #baudrate, #subdriver, #baudrate, #subdriver, #usbvendor, #eol, #verifydevice, #help, #checksum

These tag after a #metadef will replace the corresponding tag in the original definition.

Code:
#metadef
#idString ITECH Ltd, IT8511A,  
#name Itech IT8511A+
#handle IT8511A



#replace

Code:
#replace #tag params
...

Replace all settings between a tag and the following tag.

Code:
#replace #cmdSetup indicator State
:read: test?
off 0 red
on 1 green



#remove

Remove section, both line with #tag and all lines until the next #tag

Code:
#remove #cmdSetup indicator State



#removeline

Remove any line that starts with the text after the tag.

Code:
#removeLine 60A
#removeLine 120A
#removeLine 240A



#replacetext

Replaces the first word after the tag with the second word after the text. This makes it possible to adjust limits and other values in the original definition.

Code:
#replaceText MinVoltage 0.1
#replaceText MinResistance 0.05
#replaceText MaxCurrent 30
#replaceText MaxVoltage 150
#replaceText MaxResistance 7500
#replaceText MaxPower 150



#sections

This tag is used together with #metaSection in the actual definition to include or exclude larger blocks of lines. Only one #sections tag is used in each #metadef section.


Code:
#sections
#sections dual
#sections dual 20A
The above are examples of section specifications in the #metadef part

Code:
#metaSection dual

#metaSection dual 20A

#metaSection 
In the actual definition the #metaSection tag is used. The first one will be include in any #metadef/#sections that specifies dual, the second one will only be include for #metadef/#sections that both specify dual and 20A. The last is always included and is used to end a conditional (#metaSection) section.

Note: #metaSection is only valid in #meta definitions, a normal definition will always fail to load when containing a #metaSection tag.



#metaDebug

This is a debug tag that can be placed on the line after a #metadef tag, this will list all performed modification instructions on the console output (This requires starting testController from the command line).

Code:
#metaDebug
#metaDebug save
Adding a save tag after the #metaDebug will save a file with the processed definition



Protocol is nearly SCPI, but there is a few issues (SCPIx)

This driver is designed to handle minor non-scpi details, in some ways it is similar to "Ascii" driver, but as default commands are passed to the device and they do not support all the same configurations.
Code:
#driver SCPIx
See Difference between the 3 SCPI/ascii drivers (SCPI, SCPIx, Ascii) for a explanation of the different ascii drivers.



Some devices requires the commands to be in uppercase, this tag will handle it:
Code:
#forceUpperCase 1


Some older device may return a prompt on the serial connection, to get rid of it use:
Code:
#removePromptChars count
This will remove count characters after each command and also wait until the prompt is received or timeout occurs.
This function will be disabled on GPIB interfaces.


Transmit a command and optionally receive an answer.
Code:
#scpiCmd name tx cmd
#scpiCmd name txrx cmd
#scpiCmd name? txrx? cmd
#scpiCmd name? txrx? cmd
#scpiCmd name? txrx2? cmd
#scpiCmd name? txrxn? lines cmd
#scpiCmd name? txrxnBin? bytes cmd
#scpiCmd name? txrx1Bin? cmd
#scpiCmd name? rxuntil? expression
#scpiCmd name? rxalluntil? expression
#scpiCmd name none
#scpiCmd name? none?

#scpiCmd name tx cmd (value)
#scpiCmd name txrx cmd (value)
#scpiCmd name? txrx? cmd (value)

#scpiCmd name #pgm#
#scpiCmd name? #pgm#
Use (value) to insert parameters from the "name" command. It is possible to use value multiple times and it is also possible to use an expression inside the brackets.
A number or n in the command lines means multiple lines, except with bin where it means bytes (Up to 8, answer is return as a number).
The until functions need a expression to check the "value" for the correct answer, all means all answer up to that point is combined.
The none functions are used together with :setvar: and a local variable. With none? use ":readmath: definedVariableName" to get contents of variable.


Reading a binary value from a device:
Code:
txrx1bin? command (Use \n at the end).
This command will return a number from 0 to 255, with ":readmath: int(value)&0x??" bits can be tested. This command is typically used in #scpiCmd definitions.

The most significant update is support for redefining commands:
Code:
#scpiCmd name definition
These definitions support :readmath: and :setvar: tags.
The command will replace name with definition before transmitting it to the device. Parameters must be added with (value)
This instance of #scpiCmd also support the [xxxx] delay specifications.

Code:
#scpiCmd name #pgm#
#scpiCmd name? #pgm#
The string #pgm# means the rest of this definition is a calculator script, it can use deviceWrite() & deviceRead() to access the device, but there is no requirement it must access the device. This definition type is only designed for fairly advanced usage. To see more about calculator script see here
Any parameters can be accessed as value (at least until deviceWrite() or deviceRead() is called), it shares variables with :setvar: and :readmath:, this means it is possible create and use variables between this script and other scripts in other part of this definition. The deviceWrite() and deviceRead() functions can only access the actual device and it is legal to use a empty handle (i.e. "");
Two variables describing the connection are available:
portType is the connection type: None, Serial, Socket, LXI, USBHID, GPIB, UDP
portAddress is the value in the address field.

Example of handling a init command that is not supported in GPIB mode:
Code:
#scpiCmd MyInit #pgm#
if (portType!="GPIB")
  deviceWrite(handle,"SYST:REM;");
endif;

This command can then be used:
 #initCmd *RST;MyInit;

This driver is used for the Korad_KAxxxxP supplies.



User supplied stuff

Some explanation/hint on making device definition: User config hints

Script to pretty up device definition and check a definition: Python script

Script to generate a second channel from channel 1: Python script