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::portThe 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>