Skip to content

Connections¤

The information about how to interface with equipment for computer control is based on the definitions in the Schema and may either be saved in the eXtensible Markup Language (XML) file format or in a Python module. When using the XML format, you would specify the XML file that contains the connection information as a <connections> element in your configuration file. When the configuration file is loaded (via Config), it links a Connection instance with the corresponding Equipment instance based on the equipment id.

XML Schema¤

Schema definition for connection information. See this section for details on how to validate the contents of a connections XML file against the schema.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="connections">
    <xsd:complexType>
      <xsd:sequence minOccurs="0" maxOccurs="unbounded">
        <xsd:element name="connection">
          <xsd:complexType>
            <xsd:all>
              <xsd:element name="eid" type="xsd:string">
                <xsd:annotation>
                  <xsd:documentation>
                    The equipment ID from an equipment register.
                  </xsd:documentation>
                </xsd:annotation>
              </xsd:element>
              <xsd:element name="address" type="xsd:string">
                <xsd:annotation>
                  <xsd:documentation>
                    The VISA-style address to use for the connection.
                  </xsd:documentation>
                </xsd:annotation>
              </xsd:element>
              <xsd:element name="backend" minOccurs="0">
                <xsd:annotation>
                  <xsd:documentation>
                    The backend package to use to communicate with the equipment.
                    Default is MSL if not defined.
                  </xsd:documentation>
                </xsd:annotation>
                <xsd:simpleType>
                  <xsd:restriction base="xsd:string">
                    <xsd:enumeration value="MSL"/>
                    <xsd:enumeration value="PyVISA"/>
                    <xsd:enumeration value="NIDAQ"/>
                  </xsd:restriction>
                </xsd:simpleType>
              </xsd:element>
              <xsd:element name="manufacturer" type="xsd:string" minOccurs="0">
                <xsd:annotation>
                  <xsd:documentation>
                    The name of the manufacturer of the equipment.
                  </xsd:documentation>
                </xsd:annotation>
              </xsd:element>
              <xsd:element name="model" type="xsd:string" minOccurs="0">
                <xsd:annotation>
                  <xsd:documentation>
                    The model number of the equipment.
                  </xsd:documentation>
                </xsd:annotation>
              </xsd:element>
              <xsd:element name="serial" type="xsd:string" minOccurs="0">
                <xsd:annotation>
                  <xsd:documentation>
                    The serial number (or unique identifier) of the equipment.
                  </xsd:documentation>
                </xsd:annotation>
              </xsd:element>
              <xsd:element name="properties" minOccurs="0">
                <xsd:annotation>
                  <xsd:documentation>
                    Additional name-value pairs that are required to communicate
                    with the equipment.
                  </xsd:documentation>
                </xsd:annotation>
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:all>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Example¤

Example XML file to specify connection information. Only the <eid> and <address> elements are required, all other elements are optional.

<?xml version="1.0" encoding="utf-8"?>
<connections>
  <connection>
    <eid>MSLE.M.041</eid>
    <address>TCPIP::192.168.1.10::hislip0</address>
  </connection>
  <connection>
    <eid>MSLE.M.023</eid>
    <address>ASRL/dev/ttyS1</address>
    <backend>MSL</backend>
    <manufacturer>Company Name</manufacturer>
    <model>ABC</model>
    <serial>123</serial>
    <properties>
      <baud_rate>19200</baud_rate>
      <read_termination>\r</read_termination>
      <write_termination>\r</write_termination>
      <timeout>10</timeout>
    </properties>
  </connection>
</connections>

Interfaces¤

The following interface classes are available

  • FTDI — For equipment that use a Future Technology Devices International (FTDI) chip
  • GPIB — For equipment that use the GPIB (IEEE 488) protocol
  • HiSLIP — For equipment that use the HiSLIP protocol
  • Modbus — For equipment that use the Modbus protocol
  • Prologix — Use Prologix hardware to establish a connection to GPIB-compatible equipment
  • SDK — For equipment that use a Software Development Kit (SDK) for communication
  • Serial — For equipment that is connected through a serial port (or a USB-to-Serial adaptor)
  • Socket — For equipment that is connected through a network socket
  • USB — For equipment that use the (raw) USB protocol
  • USBTMC — For equipment that use the USB Test & Measurement Class protocol
  • VXI11 — For equipment that use the VXI-11 protocol
  • ZeroMQ — For equipment that use the ZeroMQ protocol

Address Syntax¤

Each Interface has a syntax for the Connection address that it supports. The following table shows the syntax for each Interface. Optional segments are shown in square brackets [ ] and capital letters represent literal text.

Interface Syntax Description
FTDI FTDI[driver]::vendor::product::serial[::iface] driver – 0=libusb, 2=d2xx [default=0]
vendor – Vendor (manufacturer) ID, in hexadecimal or decimal notation
product – Product ID, in hexadecimal or decimal notation
serial – Serial number (or unique identifier)
iface – USB Interface Number, only used with the libusb driver [default=0]
GPIB GPIB[board]::pad[::sad][::INSTR]
GPIB[board]::INTFC
board – board number [default=0]
pad – Primary address or an interface name (see gpib.conf for more details about using a name on Linux)
sad – Secondary address [default=None]
HiSLIP TCPIP[board]::host::hislip#[,port][::INSTR] board – board number (not used) [default=0]
host – Hostname or IP address of the device
hislip# – The text hislip followed by a numeric sub address (e.g., hislip0)
port – The network port number [default=4880]
Modbus MODBUS::address[::ASCII|RTU|SOCKET][::UDP] address – Serial port address or IP address (hostname). If a non-default network port must be specified, address can be expressed as host::port
The prefix MODBUS is case insensitive
PROLOGIX PROLOGIX::port[::GPIB]::pad[::sad]
PROLOGIX::host::1234[::GPIB]::pad[::sad]
port – Serial port address (GPIB-USB Controller)
host – Hostname or IP address (GPIB-ETHERNET Controller)
pad – Primary GPIB address
sad – Secondary GPIB address [default=None]
The prefix PROLOGIX is case insensitive
SDK SDK::path path – Path to the library file
SERIAL (ASRL|COM|ASRLCOM)port[::INSTR]
(ASRL|COM|ASRLCOM)?::pattern
The text ASRL, COM or ASRLCOM followed by the serial port address. Specifying ? as the port address (followed by ::) will use the search pattern to find a serial port that matches the description of the port, as shown when find is run. The pattern supports regular-expression syntax.
SOCKET TCP::host::port
UDP::host::port
TCPIP[board]::host::port::SOCKET
host – Hostname or IP address
port – Network port number
board – board number (not used) [default=0]
USB USB[board]::vendor::product::serial[::iface]::RAW board – board number (not used) [default=0]
vendor – Vendor (manufacturer) ID, in hexadecimal or decimal notation
product – Product ID, in hexadecimal or decimal notation
serial – Serial number (or unique identifier). Literal text IGNORE means that the serial number is not used (the vendor and product values uniquely identify the device)
iface – USB Interface Number [default=0]
USBTMC USB[board]::vendor::product::serial[::iface][::INSTR] board – board number (not used) [default=0]
vendor – Vendor (manufacturer) ID, in hexadecimal or decimal notation
product – Product ID, in hexadecimal or decimal notation
serial – Serial number (or unique identifier). Literal text IGNORE means that the serial number is not used (the vendor and product values uniquely identify the device)
iface – USB Interface Number [default=0]
VXI-11 TCPIP[board]::host[::name][::INSTR] board – board number (not used) [default=0]
host – Hostname or IP address
name – Device name [default=inst0]
ZMQ ZMQ::host::port host – Hostname or IP address
port – Network port number

Examples¤

The following are examples of the addresses that may be used to connect to equipment.

Interface Address Description
FTDI FTDI::0x0403::0x6001::abc FTDI device using driver=0 (default, libusb), idVendor=0x0403, idProduct=0x6001 (hexadecimal notation), serial number=abc, USB Interface Number=0 (default)
FTDI FTDI0::1027::24577::032165::1 FTDI device using driver=0 (libusb), idVendor=1027, idProduct=24577 (decimal notation), serial number=032165, USB Interface Number=1
FTDI FTDI2::0x0403::0xfaf0::A825192 FTDI device using driver=2 (d2xx), idVendor=0x0403, idProduct=0xfaf0 (hexadecimal notation), serial number=A825192, the USB Interface Number is ignored when using the d2xx driver
GPIB GPIB::10 GPIB device at board=0 (default), primary address=10, no secondary address
GPIB GPIB0::voltmeter GPIB device at board=0, interface name=voltmeter (see gpib.conf for more details about the name option on Linux)
GPIB GPIB1::6::97::INSTR GPIB device at board=1, primary address=6, secondary address=97
GPIB GPIB2::INTFC GPIB interface at board=2
HiSLIP TCPIP::dev.company.com::hislip0 A HiSLIP LAN instrument, host=dev.company.com
HiSLIP TCPIP::10.12.114.50::hislip0,5000::INSTR A HiSLIP LAN instrument, host=10.12.114.50, port=5000
MODBUS Modbus::192.168.1.50 A Modbus device at IP address 192.168.1.50 (default TCP network protocol, default network port 502, default SOCKET frames)
MODBUS Modbus::abc-xyz::5000 A Modbus device with the hostname abc-xyz at port 5000 (default TCP network protocol, default SOCKET frames)
MODBUS Modbus::192.168.1.80::UDP A Modbus device at IP address 192.168.1.80 using the UDP network protocol (default network port 502, default SOCKET frames)
MODBUS Modbus::/dev/ttyS1 A Modbus device at the Serial port /dev/ttyS1 (default RTU frames)
MODBUS Modbus::COM3::ASCII A Modbus device at the Serial port COM3 using ASCII frames
PROLOGIX Prologix::192.168.1.110::1234::6 The GPIB-ETHERNET Controller, host=192.168.1.110, port=1234, primary GPIB address=6
PROLOGIX Prologix::192.168.1.70::1234::6::112 The GPIB-ETHERNET Controller, host=192.168.1.70, port=1234, primary GPIB address=6, secondary GPIB address=112
PROLOGIX Prologix::192.168.1.70::1234::GPIB::6::112 The GPIB-ETHERNET Controller, host=192.168.1.70, port=1234, primary GPIB address=6, secondary GPIB address=112
PROLOGIX Prologix::COM3::6 The GPIB-USB Controller, port=COM3, primary GPIB address=6
PROLOGIX Prologix::COM3::GPIB::6 The GPIB-USB Controller, port=COM3, primary GPIB address=6
PROLOGIX Prologix::/dev/ttyS0::4::96 The GPIB-USB Controller, port=/dev/ttyS0, primary GPIB address=4, secondary GPIB address=96
SDK SDK::C:\Manufacturer\library.dll Specify the full path to the SDK
SDK SDK::library Specify only the filename if the path to where the SDK file is located has been added to the PATH environment variable. You may also omit the file extension: .dll is used on Windows, .so is used on Linux, .dylib is used on macOS
SERIAL COM2 A serial port on Windows
SERIAL ASRL/dev/ttyS1 A serial port on Linux
SERIAL ASRL2::INSTR Compatible with National Instruments syntax
SERIAL ASRLCOM2 Compatible with PyVISA-py syntax
SERIAL COM?::18071105A Find the serial port that contains 18071105A in the port description
SERIAL ASRL?::VID:PID=067B:2303 Find the serial port that contains VID:PID=067B:2303 in the port description
SOCKET TCP::192.168.1.100::5000 Use the TCP protocol, host=192.168.1.100, port=5000
SOCKET UDP::192.168.1.100::5000 Use the UDP protocol, host=192.168.1.100, port=5000
SOCKET TCPIP::192.168.1.100::5000::SOCKET Compatible with National Instruments syntax
USB USB::0x2a67::0x0408::abc::RAW A (raw) USB device with board=0 (default), idVendor=0x2a67, idProduct=0x0408 (hexadecimal notation), serial number=abc, USB Interface Number=0 (default)
USB USB0::1027::24577::032165::1::RAW A (raw) USB device with board=0, idVendor=1027, idProduct=24577 (decimal notation), serial number=032165, USB Interface Number=1
USB USB::0x0381::0x06a2::IGNORE::RAW A (raw) USB device with board=0 (default), idVendor=0x0381, idProduct=0x06a2 (hexadecimal notation), serial number=IGNORE (means that the serial number is not used when finding the USB device and the first USB device found that matches idVendor and idProduct is used), USB Interface Number=0 (default)
USBTMC USB::0x2a2b::0x1122::abc A USBTMC device with board=0 (default), idVendor=0x2a2b, idProduct=0x1122 (hexadecimal notation), serial number=abc, USB Interface Number=0 (default)
USBTMC USB::10795::4386::abc::INSTR A USBTMC device with board=0 (default), idVendor=10795, idProduct=4386 (decimal notation), serial number=abc, USB Interface Number=0 (default)
USBTMC USB0::0x2a2b::0x1122::032165::1::INSTR A USBTMC device with board=0, idVendor=0x2a2b, idProduct=0x1122 (hexadecimal notation), serial number=032165, USB Interface Number=1
VXI-11 TCPIP::dev.company.com::INSTR A VXI-11.3 LAN instrument, host=dev.company.com (uses the default LAN Device Name inst0)
VXI-11 TCPIP::10.6.56.21::gpib0,2::INSTR A VXI-11.2 GPIB device, host=10.6.56.21, gpib address=2
VXI-11 TCPIP::192.168.1.100 A VXI-11.3 LAN instrument, host=192.168.1.100 (default values for board 0 and LAN device name inst0 are used)
ZMQ ZMQ::192.168.20.90::5555 Use the ZeroMQ messaging library to connect to a device, host=192.168.20.90, port=5555

National Instruments also provides examples if you are using PyVISA as the backend.

Backends¤

When a Connection instance is created, the backend keyword argument decides which backend to use when interfacing with the equipment. There are different Backends to choose from: MSL (default), PyVISA or NIDAQ.

The interface classes can be used if the backend is MSL. The corresponding interface classes for the external backends are PyVISA and NIDAQ.

Python Examples¤

If you are primarily interested in using msl-equipment to interface with equipment (and not the Equipment Registers aspect), the simplest approach is to create Connection instances in a module and call the connect method (which is equivalent to calling Equipment.connect() if you are using Equipment Registers).

from msl.equipment import Connection

device = Connection("COM3").connect()
print(device.query("*IDN?"))
device.disconnect()

All interfaces can be used as a context manager, where the disconnect method is called when exiting the code block. The previous example is equivalent to the following.

from msl.equipment import Connection

with Connection("COM3").connect() as device:
  print(device.query("*IDN?"))

If you have multiple equipment that you want to interface with and you also want to include some additional metadata so that you can keep track of which device is associated with the corresponding address, you could do something like the following. Also, for some interfaces, such as when using a manufacturer's SDK, the serial number must be passed to the SDK when opening the connection and therefore the serial number must be specified as a keyword argument (or as an element in a connections XML file).

from msl.equipment import Connection

# Assign custom names to associate with each equipment
connections = {
    "alice": Connection("GPIB::22", model="3458A"),
    "bob": Connection("COM3", manufacturer="HP", model="34401A"),

    # not used below but is available to use for another day
    "eve": Connection("SDK::company.dll", manufacturer="ABC", serial="4621"),
}

# Connect to the equipment using the names that were assigned
alice = connections["alice"].connect()
bob = connections["bob"].connect()

# Query the identity
print(alice.query("ID?"))
print(bob.query("*IDN?"))

# Disconnect when finished
alice.disconnect()
bob.disconnect()

Better IDE Support¤

The returned type when the connect() method is called is Any, because the Interface or Resource to use to communicate with the equipment is not known until runtime. The Integrated Development Environment (IDE) that you may be using to develop your code cannot provide type checking, code completion or other diagnostic features for the Any type. The following illustrates different ways to get the features that your IDE supports, depending on how you may be using msl-equipment.

If you create a Connection instance in a module, annotate the returned object

from msl.equipment import GPIB, Connection

device: GPIB = Connection("GPIB::22").connect()

or if you use a context manager, annotate the object before entering the code block.

from msl.equipment import GPIB, Connection

device: GPIB
with Connection("GPIB::22").connect() as device:
    pass

If you create an Equipment instance in a module.

from msl.equipment import GPIB, Connection, Equipment

equipment = Equipment(
    connection=Connection("GPIB::22"),
    # specify more keyword arguments...
)

# Use the connect() method and annotate the returned object
device: GPIB = equipment.connect()

# Pass the Equipment instance to the GPIB class
device = GPIB(equipment)

# Use as a context manager
with GPIB(equipment) as device:
    pass

If you create a Config instance in a module.

from msl.equipment import GPIB, Config

cfg = Config("path/to/configuration.xml")

# Get the Equipment instance by its "name" in an Equipment Register,
# call the connect() method and annotate the returned object
device: GPIB = cfg.equipment["dmm"].connect()

# Pass the Equipment instance to the appropriate Interface class
device = GPIB(cfg.equipment["dmm"])

# Use as a context manager
with GPIB(cfg.equipment["dmm"]) as device:
    pass

Resources also take an Equipment instance as an argument. If you know the Resource that is used for communicating with the equipment, you have multiple choices. The following uses the MXSeries Resource for the examples.

If you create a Connection instance in a module.

from msl.equipment import Connection
from msl.equipment.resources import MXSeries

connection = Connection(
    "TCPIP::169.254.100.2::inst0::INSTR",
    manufacturer="Aim-TTi",  # required
    model="MX100TP",  # required (but may be a different model number)
)

# Use the connect() method and annotate the returned object
device: MXSeries = connection.connect()

# Use as a context manager
device: MXSeries
with connection.connect() as device:
    pass

If you create an Equipment instance in a module.

from msl.equipment import Connection, Equipment
from msl.equipment.resources import MXSeries

dcv_supply = Equipment(
    connection=Connection("TCPIP::169.254.100.2::inst0::INSTR"),
    manufacturer="Aim-TTi",  # required if calling dcv_supply.connect()
    model="MX100TP",  # required if calling dcv_supply.connect()
    # specify more keyword arguments...
)

# Use the connect() method and annotate the returned object.
# The manufacturer and model values must be specified for the
# MXSeries Resource to be chosen.
device: MXSeries = dcv_supply.connect()

# Pass the `dcv_supply` instance to the MXSeries Resource class.
# The manufacturer and model values are not required
device = MXSeries(dcv_supply)

# Use as a context manager
with MXSeries(dcv_supply) as device:
    pass

If you create a Config instance in a module.

from msl.equipment import Config
from msl.equipment.resources import MXSeries

cfg = Config("path/to/configuration.xml")

# Get the Equipment instance by its "name" in an Equipment Register,
# call the connect() method and annotate the returned object. The
# <equipment> element in the Equipment Register must also specify the
# appropriate <manufacturer> and <model> sub-elements to automatically
# use the MXSeries Resource.
device: MXSeries = cfg.equipment["dcv-supply"].connect()

# Pass the Equipment instance to the appropriate Resource class
device = MXSeries(cfg.equipment["dcv-supply"])

# Use as a context manager
with MXSeries(cfg.equipment["dcv-supply"]) as device:
    pass

Debugging Communication¤

The logging module may be used to help debug communication issues, especially when interfacing with multiple equipment. By enabling the DEBUG level you will be able to capture the bytes that are written to and read from the equipment.

import logging
from msl.equipment import Connection

logging.basicConfig(level=logging.DEBUG, format="%(levelname)s %(message)s")

c = Connection("COM3", manufacturer="HP", model="34401A", serial="3146A")
with c.connect() as dmm:
    identity = dmm.query("*IDN?")

Running the previous example would display something similar to the following.

DEBUG Connecting to Serial<HP|34401A|3146A at COM3>
DEBUG Serial<HP|34401A|3146A>.write(b'*IDN?\r\n')
DEBUG Serial<HP|34401A|3146A>.read() -> b'Hewlett Packard,34401A,3146A,A03-02\n'
DEBUG Disconnected from Serial<HP|34401A|3146A at COM3>