blob: 92eeef1ad6471d8a4897ae6e7fff394a44d7eda1 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import socket
class PrologixScpiDriver:
"""Wrapper for a Prologix TCP<->GPIB bridge.
http://prologix.biz/gpib-ethernet-controller.html
http://prologix.biz/index.php?dispatch=attachments.getfile&attachment_id=1
Communication is over a plain TCP stream on port 1234. Commands to
the bridge are in-band, prefixed with ++.
Notable instance variables include:
self.auto: When 1, the bridge automatically addresses the target
in listen mode. When 0, we must issue a ++read after every
query. As of Aug '11, something between us and the Agilent 8960
is wrong such that running in auto=0 mode leaves us hanging if
we issue '*RST;*OPC?'
"""
def __init__(self, hostname, port=1234, gpib_address=14):
"""Constructs a wrapper for the Prologix TCP<->GPIB bridge :
Arguments:
hostname: hostname of prologix device
port: port number
gpib_address: initial GPIB device to connect to
"""
self.socket = connect_to_port(hostname, port)
self.read_side = os.fdopen(self.socket.fileno(),'r')
self.SetAuto(1)
self.SetGpibAddress(gpib_address)
def __del__(self):
self.Close()
def SetAuto(self, auto):
"""Controls Prologix read-after-write (aka 'auto') mode."""
self.auto = int(auto) # Must be an int so we can send it as
# an arg to ++auto
self.Send('++auto %d' % self.auto)
def Close(self):
"""Close the read_side file and read/write socket in the correct order."""
if self.read_side: self.read_side.close()
if self.socket: self.socket.close()
def SetGpibAddress(self, gpib_address):
self.Send('++addr %s' % gpib_address)
actual_gpib_address = self._DirectQuery('++addr')
assert(int(actual_gpib_address) == int(gpib_address))
def Send(self, command):
self.socket.send(command + '\n')
def Reset(self):
"""Sends a standard SCPI reset and waits for it to complete."""
# There is some misinteraction between the devices such that if we
# send *RST and *OPC? and then manually query with ++read,
# occasionally that ++read doesn't come back. We currently depend
# on self.Query to turn on Prologix auto mode to avoid this
self.Send('*RST')
self.Query('*OPC?')
def Read(self):
"""Read a response from the bridge."""
response = self.read_side.readline()
if response == '':
return None
response = response.rstrip()
return response
def Query(self, command):
"""Send a GPIB command and return the response."""
self.SetAuto(1)
self.Send(command)
if not self.auto:
self.Send('++read eoi')
output = self.Read()
self.SetAuto(0)
return output
def _DirectQuery(self, command):
"""Sends a query to the prologix (do not send ++read), return response."""
self.Send(command)
return self.Read()
def connect_to_port(hostname, port):
# Right out of the python documentation,
# http://docs.python.org/library/socket.html
for res in socket.getaddrinfo(
hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except socket.error, msg:
s = None
continue
try:
s.connect(sa)
except socket.error, msg:
s.close()
s = None
continue
break
return s