Skip to main content

Python wrapper Library for Pickering LXI ClientBridge driver

Project description

Python wrapper Library for Pickering LXI ClientBridge driver

Python wrapper Library for Pickering LXI ClientBridge driver. It supports both Python 2.x and 3.x.


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.


ChangeLog

  • 5.2 - Addded ATTR_C_GA_SLOT_ADDRESS attribute, updated readme.
  • 5.1 - Updated description and readme.
  • 5.0 - Adds SetAttributeDWORD, SetAttributeDWORDArray, SetAttributeDouble, SetAttributeByte and its getters. Adds DioAllPortData function.
  • 4.9 - Adds ResSetResistance() mode enum and optional parameter to pilxi (brings pilxi version to 2.0.3)
  • 4.8 - Adds calibration functions to pilxi (brings pilxi version to 2.0.2)
  • 4.7 - Adds example code for Precision Resistor cards
  • 4.6 - Fixes issues in pi743lx findInstrumentsRsrc(), wrapper changes to prevent namespace pollution by ctypes.
  • 4.5:
    • Introduces individual version numbering for all packages
    • Updated LXI_PXM78xx module -> support Trigger Matrix, Timer/Counter groups
    • Updates battery simulator functionality, including set-measure-set mode and measurement configuration.
    • Updates example code, including battery simulator example and adds Example_ListCards.py
  • 4.4 - Imported LXI_PXM78xx module support (VX Instrument's PXM78xx DMM modules)
  • 4.3 - Updates LVDT/resolver functionality and adds Battery Simulator measurement methods
  • 4.2 - Adds example for multiuser access
  • 4.1 - Fixes issue with ReadSub and ViewSub
  • 4.0 - Changes to API to add more object-oriented features, exceptions, adds 41-620 and 41-743 support, current loop simulator, 40-419 DIO card, etc.
  • 3.18 - Updates to use native strings in Python 2.x/3.x, adds pi_base.ErrorCodeToMessage() and pi_comm.ErrorCodeToMessage()
  • 3.17 - Adds pi_card.SetCrosspointRange - Adds Thermocouple Simulator Functions
  • 3.16 - Fixes pi_card.WriteSub
  • 3.15 - Adds new constructor and method for opening cards using aliases
  • 3.14 - Changes to return interger value from calc_dwords().
  • 3.13 - Fixes pi_base.EchoDirectEx and pi_base.EchoDirectEx pi_base.GetAvailableLXIEntryEx functions (increased description buffer size)
  • 3.12 - Adds version definition for all wrapper modules (plus function call definition to obtain information)
  • 3.11 - Adds Power Sequencer Python 2 support
  • 3.10 - Adds Power Sequencer support
  • 3.9 - Fixes pi_cards.CloseCards, pi_cards.Close (closes connection properly once card is closed)
  • 3.8 - Adds Linux Support
  • 3.7 - Adds Thermocouple Functions and updates calling conventions to match change in ClientBridge
  • 3.6 - Updates Calling Convetions to match recent change in ClientBridge
  • 3.5 - Fixes Resistor ClientBridge Calls
  • 3.4 - Refactor for use with pip installer - Fixes Resistor functions

Install Using pip

To install Python Pilxi from our download site using pip - open a command line prompt and navigate to the directory the library 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.

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

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:

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

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:

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

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

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

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:

# Set Resistance of given subunit, resistance value in Ohms
mode = 0
resistance = 330.0

card.ResSetResistance(subunit, resistance)

# Retrive current resistance of given subunit
resistance = card.ResGetResistance(subunit)

print("Resistance:", resistance)

# Set Resistance with specific mode:
#    RES_Mode.SET                     # Legacy/Default mode to support existing break before make with settling delay
#    RES_Mode.MBB                     # New mode to suport make before break with settling delay
#    RES_Mode.APPLY_PATTERN_IMMEDIATE # Apply new pattern immediately and wait till settling delay
#    RES_Mode.NO_SETTLING_DELAY       # Disable settling delay,same as DriverMode NO_WAIT, but at sub-unit level
#    RES_Mode.DONT_SET                # Do the calculations but don't set the card

# Set with make-before-break mode 
resistance = card.ResSetResistance(subunit, resistance, mode=pilxi.RES_Mode.MBB)

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:

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

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

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:

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

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.

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:

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

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

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:

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:

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:

error, resistance = card.ResGetResistance(subunit)

Would now become:

resistance = card.ResGetResistance(subunit)

Errors would be caught in a try/except block.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

Pilxi-5.2.tar.gz (65.6 kB view hashes)

Uploaded Source

Built Distribution

Pilxi-5.2-py3-none-any.whl (71.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page