Installation Instructions
We provide both a python module that can be installed to the system using pip
and can be added manually to a project by copying a file into the directory that you are working in. For either installation method please make sure that you have installed ClientBridge. If you intend to use ClientBridge with PXI please make sure you also install Pickering PXI Installer Package. These can be found at the following addresses:
Please note that there is an additional dependency 'enum34' for Python 2.x and Python 3.x versions < 3.4. This package must be installed prior to using the wrapper with older versions of Python.
Install Using pip
To install Python Pilxi using pip open a command line prompt and navigate to the directory the driver has been extracted to. From there enter the following command:
pip install .
Install Manually
To install Python Pilxi manually please copy pilxi directory containing __init__.py
to your project.
Using Pilxi
Pilxi can be used to control our 40/50/60 series pickering products.
Open a session with LXI
In order to query an LXI unit and open/operate cards, you must first open a session. This can be done by passing an IP address to the pilxi.Pi_Session
constructor. To use local PXI cards, pass "PXI" in place of the IP address.
?ximport pilxi
IP_Address = "192.168.1.1"
try:
session = pilxi.Pi_Session(IP_Address)
except pilxi.Error as ex:
print("Error occurred opening LXI session:", ex.message)
List cards
To get a list of the available cards IDs use GetUsableCards()
. This will return a list of card IDs. To list the bus and slot number for all of the cards use FindFreeCards()
, which takes in the total card count. Please see below for worked examples on how to use both of these functions:
xxxxxxxxxx
import pilxi
# Connect to chassis
IP_Address = '192.168.1.1'
# Port, timeout parameters are optional, defaults will be used otherwise.
session = pilxi.Pi_Session(IP_Address)
# or
session = pilxi.Pi_Session(IP_Address, port=1024, timeout=5000)
# Get list of Card IDs for cards in chassis
cardID_array = session.GetUsableCards(0)
print("Card IDs:", cardID_array)
# Get list of Card Bus and Device Numbers
card_array = session.FindFreeCards()
for card in card_array:
bus, device = card
print("Card at bus {} device {}".format(bus, device))
Open Card
There are three ways to open a card:
- Using the Bus and Device number
- Using the Card ID and Access mode
- Using an alias specified using Resource Manager
To open a card at a specific bus and device location, use Pi_Session.OpenCard(bus, device)
. When opening a card with Bus and Slot number only one program can access the card at a time, which means that you cannot have another program monitor the card. To do that the card needs to be opened with the Card ID and specifying the Access mode to allow multiple programs at once. The Card ID can be obtained from the list of cards show in the earlier example. Please see below for a worked example on how to use pi_card
in either way:
xxxxxxxxxx
# Open a card by bus and device:
import pilxi
card = session.OpenCard(bus, device)
# accessType parameter is optional, default value is 1 (shared access)
# see pilxi.AccessTypes enum for options
card = session.OpenCardByID(cardID, accessType=pilxi.AccessTypes.MULTIUSER)
# Cards can be closed explicitly, garbage collection will close cards and sessions otherwise
card.Close()
Aliases must be specified in the Resource Manager application. From there you can save a copy of the resource file locally which can be copied into your project directory for easy access. You can then open a card by alias using the pilxi.Pi_Card_ByAlias
class:
xxxxxxxxxx
rsrcfile = "LocalResources.rml"
alias = "my_alias"
# Resource file, access type and timeout parameters are optional.
card = pilxi.Pi_Card_ByAlias(alias, rsrcfile, accessType=1, timeout=5000)
card.Close()
Operate Switching cards
There are three main types of switching cards: - Switches - Multiplexer - Matrix
To operate Switches and Multiplexers use OpBit()
providing subunit, switch point, and switch state. Matrices can be controller using OpCrosspoint()
which requires the subunit, row, column, and switch state. Please see below for worked examples on using these functions:
xxxxxxxxxx
# Control Switches and Multiplexer cards
subunit = 1
switchpoint = 1
state = True
card.OpBit(subunit, switchpoint, state)
state = False
card.OpBit(subunit, switchpoint, state)
# Control Matrix cards
row = 1
column = 1
card.OpCrosspoint(subunit, row, column, True)
card.OpCrosspoint(subunit, row, column, False)
# Set a range of crosspoints on a given row
start = 1
end = 8
card.SetCrosspointRange(subunit, row, start, end, 1)
Using Subunit States
The Python-Pilxi wrapper contains methods to read entire subunit states, e.g. the current switch configuration of a switching or matrix card, manipulate these states and apply the state back to the card in one single operation. This means, for example, multiple crosspoints can be connected at once, or the user may have multiple desired matrix/switch states and alternate between them.
Example for manipulating matrix card states:
xxxxxxxxxx
# Get an object representing the current state of the specified matrix subunit:
subState = card.GetSubState(subunit)
# Set matrix crosspoints 1, 1 and 2, 2 on the subunit state;
# No actual switching occurs yet.
subState.PreSetCrosspoint(1, 1, True)
subState.PreSetCrosspoint(2, 2, True)
# Apply the subunit state.
# Crosspoints changed will now be applied to the physical card.
card.WriteSubState(subunit, subState)
Example for manipulating switching card states:
xxxxxxxxxx
# Get an object representing the current state of the specified switch subunit:
subState = card.GetSubState(subunit)
# Set switches 1 and 2 on the subunit state;
# No actual switching occurs yet.
subState.PreSetBit(1, True)
subState.PreSetBit(2, True)
# Apply the subunit state.
# Switches changed will now be applied to the physical card.
card.WriteSubState(subunit, subState)
It is also possible to obtain a subunit state object representing a clear subunit:
xxxxxxxxxx
blankSubunitState = card.GetBlankSubState(subunit)
Operate Resistor Cards
Resistor cards come in two varieties: Programmable Resitor, and Presision Resistor. Programmable Resistors are controlled like Switch Cards shown above. Presision Resistor Cards have specific resistor functions. To set a resistance ResSetResistance
is used and to get the current resistance ResGetResistance
is used as shown below:
xxxxxxxxxx
# Set Resistance of given subunit, resistance value in Ohms
mode = 0
resistance = 330.0
card.ResSetResistance(subunit, mode, resistance)
# Retrive current resistance of given subunit
resistance = card.ResGetResistance(subunit)
print("Resistance:", resistance)
Operate Attenuator
Attenuators have specific functions for controlling them. To set attenuation use SetAttenuation()
providing the subunit and attenuation expressed in decibels. To retrieve the current attenuation use GetAttenuation()
giving the subunit. It returns an error code and the attenuation expressed in decibels. Please see below for worked examples on how to use these functions:
xxxxxxxxxx
# Setting Attenuation
attenuation = 1.5 # Attenuation in dB
card.SetAttenuation(subunit, attenuation)
# Retrieving Attenuation
attenuation = card.GetAttenuation(subunit)
print("Attenuation (dB):", attenuation)
Operate Power Supply
Power Supplies have specific functions for controlling them. To set voltage use PsuSetVoltage()
providing the subunit and voltage. To retrieve voltage use PsuGetVoltage()
giving the subunit. To enable output use PsuEnable
providing the subunit and the state to be set. Please see below for worked examples on how to use these functions:
xxxxxxxxxx
# Set Voltage
volts = 3.3
card.PsuSetVoltage(subunit, volts)
# Enable output
card.PsuEnable(subunit, 1)
# Get Voltage
volts = card.PsuGetVoltage(subunit)
# Disable output
card.PsuEnable(subunit, 0)
Operate Battery Simulator
Battery Simulators have specific methods for controlling them. To set voltage use BattSetVoltage()
providing the subunit and voltage. To retrieve the voltage set use BattGetVoltage()
giving the subunit. To set current use BattSetcurrent()
providing the subunit and current. To retrieve the set current use BattGetcurrent()
giving the subunit. To enable output use BattSetEnable()
providing the subunit and the state to be set. To retrieve the present output state use BattGetEnable()
. On supported Battery Simulator cards, real channel voltage and current can be measured back using BattMeasureVoltage()
and BattMeasureCurrentmA()
methods. Please see below for worked examples on how to use these functions:
xxxxxxxxxx
volts = 3.3
current = 0.5
# Set Voltage
card.BattSetVoltage(subunit, volts)
# Set Current
card.BattSetCurrent(subunit, current)
# Enable Output
card.BattSetEnable(subunit, True)
# Get Voltage
volts = card.BattGetVoltage(subunit)
# Set Current
current = card.BattGetCurrent(subunit)
# Get Output state
state = card.BattGetEnable(subunit)
If you attempt to enable the outputs of a battery simulator card without the hardware interlock, BattSetEnable()
will throw an exception (error code 70, hardware interlock error). Therefore it is important to call functions in a try
block and handle errors appropriately.
41-752A-01x functionality
The 41-752A-01x battery simulator cards have extra capabilities beyond what is supported by other cards. Please consult your manual for information on your product's capabilities. Worked examples on using the extra functionality are below:
xxxxxxxxxx
# The following functionality is not supported by all battery simulator
# cards. Please consult your product manual for information on your card's
# functionality.
# Enable set-measure-set mode (increases measurement accuracy on supported cards)
card.BattSetMeasureSet(subunit, True)
# Configure measurement mode to alter device accuracy/sampling:
numSamples = pilxi.BattNumSamples.SAMPLES_128 # Average values after 128 samples
VConversionTimePerSample = pilxi.BattConversionTime.T_1052us # 1052 us voltage sample time
IConversionTimePerSample = pilxi.BattConversionTime.T_540us # 540 us current sample time
triggerMode = pilxi.BattOperationMode.CONTINUOUS # Measure continuously (no wait for trigger)
card.BattSetMeasureConfig(subunit, numSamples, VConversionTimePerSample, IConversionTimePerSample, triggerMode)
# The battery simulator (41-752A-01x) has the capability to take into consideration the load
# at which the voltage must be provided. Calculated data for voltage at different loads are
# used to provide this functionality.
load = 100 # units: mA
card.BattSetLoad(subunit, load)
# Measure channel voltage
voltage = card.BattMeasureVoltage(subunit)
# Measure channel current (in milliamps)
currentmA = card.BattMeasureCurrentmA(subunit)
# Measure channel current (in amps)
current = card.BattMeasureCurrentA(subunit)
Operate Thermocouple Simulator
Thermocouple Simulators have specific functions for controlling them. To set the range use VsourceSetRange()
providing the subunit and the range. To retrieve the range use VsourceGetRange()
providing the subunit. To set the voltage use VsourceSetVoltage()
providing the subunit and the voltage in millivolts. To retrieve the voltage use VsourceGetVoltage()
providing the subunit. It returns the voltage in millivolts. To enable or disable outputs use OpBit()
providing the subunit, bit number for the channel isolations, and the state that should be set. To retrieve the state of the outputs use ViewBit()
providing the subunit and bit number for the channel isolations. Please refer to the product manual for more information on what subunit and bits to operate. To retrieve temperature readings from a connected thermocouple compensation block us VsourceGetTemperatures()
providing either card.ATTR["TS_TEMPERATURES_C"]
or card.ATTR["TS_TEMPERATURES_F"]
for temperature unit. It will return a list of four temperatures. Please see below for worked examples on how to use these functions:
xxxxxxxxxx
range = 0.0
mvolts = 0.0
range = card.TS_RANGE["AUTO"]
# Set Range
card.VsourceSetRange(subunit, range)
# Get Range
range = card.VsourceGetRange(subunit)
# Set Voltage
card.VsourceSetVoltage(subunit, mvolts)
# Get Voltage
mvolts = card.VsourceGetVoltage(subunit)
# Set Isolation switches (41-760-001)
isosub = 33
card.OpBit(isosub, 1, 1) # Turn Vo1 on
card.OpBit(isosub, 2, 1) # Turn Vcold1 on
card.OpBit(isosub, 1, 0) # Turn Vo1 off
card.OpBit(isosub, 2, 0) # Turn Vcold1 off
# Get Thermocouple subunit information
# This will return a dictionary containing keys corresponding
# to attributes of the thermocouple subunit and their values.
VsourceInfoDict = card.VsourceInfo(subunit)
for key, value in VsourceInfoDict.items():
print("Attribute: {}, Value: {}".format(key, value))
# Get Compensation Block Temperatures
temperatures = card.VsourceGetTemperature(card.ATTR["TS_TEMPERATURE_C"])
for temp in temperatures:
print(temp)
Error Codes
Most of the functions in python-pilxi will raise an exception on any errors. The exception is defined in the python module you are using e.g. pilxi, pi620lx, pipslx.
xxxxxxxxxx
try:
# Call pilxi methods here
# On error, an exception will be raised
except pilxi.Error as ex:
# The exception object contains a string description of the error:
errorMessage = ex.message
# It is also possible to retrive the error code returned from the driver:
errorCode = ex.errorCode
Close Card/Session
A card and session can be closed when it is no longer used, or the object's destructor can be called:
xxxxxxxxxx
# Closes individual card.
card.Close()
# Closes the session with the LXI.
session.Close()
# Calling the object's destructor or deleting all references will also call
# the driver's Close() method:
del card
del session
Using Pipslx
Pipslx python module can be used to control Pickering Power Sequencer
, for
example 600-200-001. (Remote AC power management switch)
Here is a code snippet, how to
connect to Power Sequencer
, begin the startup and shutdown sequences, as well as
getting and setting individual channel states:
xxxxxxxxxx
# Required imports
import pilxi
import pipslx
# IP address of the LXI Power Management Switch
IP_Address = "192.168.0.244"
# Open a session with the LXI unit and get the session ID
session = pilxi.Pi_Session(IP_Address)
sessionID = session.GetSessionID()
# Open the pipslx library using the LXI session
powerSequencer = pipslx.Pipslx(sessionID)
# Start sequence
powerSequencer.sequence(pipslx.SEQUENCE_START)
# Get the state of a specified channel
channel = 2
state = powerSequencer.get_chan_state(channel)
# Set the state of a specified channel
state = 1
powerSequencer.set_chan_state(channel, state)
emergency = False
if emergency:
# In an emergency, call shutdown method to immediately disconnect
# all channels. No sequence times applied.
powerSequencer.shutdown()
else:
# Otherwise, begin the regular shutdown sequence
powerSequencer.sequence(pipslx.SEQUENCE_STOP)
# Close pipslx
powerSequencer.close()
# Close LXI session
session.Close()
Using Pi620lx
The Pi620lx python module can be used to control Pickering 41-620 Function Generator cards installed in an LXI chassis. The 41-620 3-channel function generator card can be used to generate arbitrarily defined waveforms, as well as standard waveforms such as sine, square and triangle with variable attenuation and DC offsets.
Here is some example code for controlling the 41-620 card using Pi620lx:
xxxxxxxxxx
import pilxi
import pi620lx
IP_Address = "192.168.1.1"
# Open an LXI session and get the session ID which must be passed to
# the pi620lx module
session = pilxi.Pi_Session(IP_Address)
sessionID = session.GetSessionID()
# Open the pi620lx library
pi620base = pi620lx.Base(sessionID)
# Open a card. With no arguments passed, the openCard() method will open the
# first 41-620 card found in the LXI unit.
bus = 4
device = 14
card = pi620base.openCard(bus, device)
# Set active channel to use
channel = 1
card.setActiveChannel(channel)
# Switch off channel output before configuring it
card.outputOff()
# Set trigger mode to continuous (no trigger)
card.setTriggerMode(card.triggerSources["FRONT"], card.triggerModes["CONT"])
# Set DC offset to generated waveform (float value from -5 to 5 volts)
# The first argument specifies the desired offset voltage;
# the second enables or disables DC offset.
offsetVoltage = 4.0
enableDCOffset = True
card.setOutputOffsetVoltage(offsetVoltage, enableDCOffset)
# Set attenuation to signal amplitude (float value in dB)
attenuation = 3
card.setAttenuation(attenuation)
# Generate a signal
# Signal shape can be defined using constants available with the Pi620_Card class:
shape = card.signalShapes["SINE"]
# shape = card.signalShapes["SQUARE"]
# shape = card.signalShapes["TRIANGLE"]
# Frequency of signal in kHz:
frequency = 1
# Symmetry of signal (0 - 100):
symmetry = 20
try:
# Start generating a signal. By default, this method will start generating immediately without
# first calling card.outputOn().
# card.generateSignal(frequency, shape, symmetry)
# The card.generateSignal() method can also be used with optional parameters to specify
# a start phase offset and to enable/disable immediate signal generation.
# For example, the following call will set the same signal as above, but with a
# 90 degree phase offset and will disable signal output until card.outputOn() is called:
card.generateSignal(frequency, shape, symmetry, startPhaseOffset=90, generate=False)
# Set output on
card.outputOn()
except pi620lx.Error as error:
print("Error generating signal:", error.message)
# Close card. Note this will not stop the card generating a signal.
card.close()
Migrating from old versions of the pilxi Python wrapper
From wrapper version 4.0 onwards, major changes were made to the Python pilxi wrapper API. Most notably, opening/listing cards and error handling conventions have changed. The new wrapper does not rely on returning an integer error code from every method, as is conventional in a C program. Instead. Python-style exceptions are raised, and the exception contains attributes giving the integer error code, and a human-readable description of the error.
Old wrapper example:
xxxxxxxxxx
from pilxi import *
# Connect to chassis
ip_address = "192.168.1.1"
port = 1024
timeout = 1000
# Opening a session with LXI device.
# Note that strings must be encoded with str.encode()
com = pi_comm(0, str.encode(ip_address), port, timeout)
mode = 0 # Last two parameters treated as Bus and Slot
bus = 19
slot = 1
card_obj = pi_card(0, str.encode(ip_address), port, timeout, mode, bus, slot)
column = 1
row = 1
subunit = 1
state = 1
err = card_obj.OpCrosspoint(subunit, row, column, state)
# C-style error checking
# Note that strings must be decoded from byte strings (Python 3.x only)
if err:
error, err_str = card_obj.ErrorCodeToMessage(err)
print(err_str.decode())
err = card_obj.OpCrosspoint(subunit, column, row, 0)
if err:
error, err_str = card_obj.ErrorCodeToMessage(err)
print(err_str.decode())
# Cards must be closed explicitly or they will not be released
card_obj.CloseSpecifiedCard()
# Session must be closed explicitly or they may be orphaned
com.Disconnect()
New wrapper example:
xxxxxxxxxx
import pilxi
# Connect to chassis and open a card by bus and device IDs.
# Error checking is done using try/except blocks to catch
# exceptions.
try:
# Port, timeout parameters are optional, defaults will be used otherwise.
IP_Address = '192.168.1.5'
session = pilxi.Pi_Session(IP_Address)
bus = 19
device = 1
card = session.OpenCard(bus, device)
except pilxi.Error as ex:
print("Error connecting to chassis/opening card: ", ex.message)
print("Driver error code:", ex.errorCode)
exit()
# Set and unset a matrix crosspoint, with error checking:
try:
row = 1
column = 1
subunit = 1
card.OpCrosspoint(subunit, row, column, True)
card.OpCrosspoint(subunit, row, column, False)
except pilxi.Error as ex:
print("Error operating crosspoint: ", ex.message)
print("Driver error code: ", ex.errorCode)
# Close session and card explicitly. This is entirely optional, cards and sessions
# will be closed by Python's garbage collection.
card.Close()
session.Close()
Function signatures remain largely identical between versions of the wrapper, except error codes are not returned. Therefore, previously a function returning a value would also return an error code:
xxxxxxxxxx
error, resistance = card.ResGetResistance(subunit)
Would now become:
xxxxxxxxxx
resistance = card.ResGetResistance(subunit)
Errors would be caught in a try/except block.