Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions pyvisa-py/gpib.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@
from __future__ import division, unicode_literals, print_function, absolute_import
from bisect import bisect

from pyvisa import constants, logger
from pyvisa import constants, logger, attributes

from .sessions import Session, UnknownAttribute

try:
import gpib
from Gpib import Gpib

except ImportError as e:
Session.register_unavailable(constants.InterfaceType.gpib, 'INSTR',
'Please install linux-gpib to use this resource type.\n%s' % e)

raise


Expand All @@ -41,10 +39,9 @@ def _find_listeners():

StatusCode = constants.StatusCode

# linux-gpib timeout constants, in milliseconds. See self.timeout.
TIMETABLE = (0, 1e-2, 3e-2, 1e-1, 3e-1, 1e0, 3e0, 1e1, 3e1, 1e2, 3e2, 1e3, 3e3,
1e4, 3e4, 1e5, 3e5, 1e6)

# linux-gpib timeout constants, in seconds. See GPIBSession._set_timeout.
TIMETABLE = (0, 10e-6, 30e-6, 100e-6, 300e-6, 1e-3, 3e-3, 10e-3, 30e-3, 100e-3, 300e-3, 1.0, 3.0,
10.0, 30.0, 100.0, 300.0, 1000.0)

# TODO: Check board indices other than 0.
BOARD = 0
Expand Down Expand Up @@ -72,17 +69,22 @@ def after_parsing(self):
pad = self.parsed.primary_address
self.handle = gpib.dev(int(minor), int(pad))
self.interface = Gpib(self.handle)
# force timeout setting to interface
self.set_attribute(constants.VI_ATTR_TMO_VALUE, attributes.AttributesByID[constants.VI_ATTR_TMO_VALUE].default)

def _get_timeout(self, attribute):
if self.interface:
# 0x3 is the hexadecimal reference to the IbaTMO (timeout) configuration
# option in linux-gpib.
gpib_timeout = self.interface.ask(3)
if gpib_timeout and gpib_timeout < len(TIMETABLE):
self.timeout = TIMETABLE[gpib_timeout]
else:
# value is 0 or out of range -> infinite
self.timeout = None
return super(GPIBSession, self)._get_timeout(attribute)

@property
def timeout(self):

# 0x3 is the hexadecimal reference to the IbaTMO (timeout) configuration
# option in linux-gpib.
return TIMETABLE[self.interface.ask(3)]

@timeout.setter
def timeout(self, value):

def _set_timeout(self, attribute, value):
"""
linux-gpib only supports 18 discrete timeout values. If a timeout
value other than these is requested, it will be rounded up to the closest
Expand All @@ -107,7 +109,16 @@ def timeout(self, value):
16 300 seconds
17 1000 seconds
"""
self.interface.timeout(bisect(TIMETABLE, value))
status = super(GPIBSession, self)._set_timeout(attribute, value)
if self.interface:
if self.timeout is None:
gpib_timeout = 0
else:
# round up only values that are higher by 0.1% then discrete values
gpib_timeout = min(bisect(TIMETABLE, 0.999 * self.timeout), 17)
self.timeout = TIMETABLE[gpib_timeout]
self.interface.timeout(gpib_timeout)
return status

def close(self):
gpib.close(self.handle)
Expand Down
39 changes: 13 additions & 26 deletions pyvisa-py/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@

try:
import serial
from serial import Serial
from serial.tools.list_ports import comports
except ImportError as e:
Session.register_unavailable(constants.InterfaceType.asrl, 'INSTR',
'Please install PySerial (>=3.0) to use this resource type.\n%s' % e)

raise


Expand Down Expand Up @@ -62,37 +60,26 @@ def after_parsing(self):
if 'mock' in self.parsed:
cls = self.parsed.mock
else:
cls = Serial
cls = serial.Serial

self.interface = cls(port=self.parsed.board, timeout=2000, write_timeout=2000)
self.interface = cls(port=self.parsed.board, timeout=self.timeout, write_timeout=self.timeout)

for name in ('ASRL_END_IN', 'ASRL_END_OUT', 'SEND_END_EN', 'TERMCHAR',
'TERMCHAR_EN', 'SUPPRESS_END_EN'):
attribute = getattr(constants, 'VI_ATTR_' + name)
self.attrs[attribute] = attributes.AttributesByID[attribute].default

@property
def timeout(self):
value = self.interface.timeout

if value is None:
return constants.VI_TMO_INFINITE
elif value == 0:
return constants.VI_TMO_IMMEDIATE
else:
return int(value * 1000)

@timeout.setter
def timeout(self, value):
if value == constants.VI_TMO_INFINITE:
value = None
elif value == constants.VI_TMO_IMMEDIATE:
value = 0
else:
value = value / 1000.

self.interface.timeout = value
self.interface.write_timeout = value
def _get_timeout(self, attribute):
if self.interface:
self.timeout = self.interface.timeout
return super(SerialSession, self)._get_timeout(attribute)

def _set_timeout(self, attribute, value):
status = super(SerialSession, self)._set_timeout(attribute, value)
if self.interface:
self.interface.timeout = self.timeout
self.interface.write_timeout = self.timeout
return status

def close(self):
self.interface.close()
Expand Down
86 changes: 64 additions & 22 deletions pyvisa-py/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ def __init__(self, resource_manager_session, resource_name, parsed=None, open_ti

self.parsed = parsed
self.open_timeout = open_timeout
#: get default timeout from constants
self.timeout = attributes.AttributesByID[constants.VI_ATTR_TMO_VALUE].default / 1000.0

#: Used as a place holder for the object doing the lowlevel communication.
self.interface = None
Expand All @@ -183,12 +185,33 @@ def __init__(self, resource_manager_session, resource_name, parsed=None, open_ti
self.attrs = {constants.VI_ATTR_RM_SESSION: resource_manager_session,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand the above description to detail the possible values in the dictionary ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment added into after_parsing method of Session

constants.VI_ATTR_RSRC_NAME: str(parsed),
constants.VI_ATTR_RSRC_CLASS: parsed.resource_class,
constants.VI_ATTR_INTF_TYPE: parsed.interface_type}
constants.VI_ATTR_INTF_TYPE: parsed.interface_type,
constants.VI_ATTR_TMO_VALUE: (self._get_timeout, self._set_timeout)}
self.after_parsing()

def after_parsing(self):
"""Override this method to provide custom initialization code, to be
called after the resourcename is properly parsed

ResourceSession can register resource specific attributes handling of them into self.attrs.
It is also possible to change handling of already registerd common attributes. List of attributes is available in pyvisa package:
* name is in constants module as: VI_ATTR_<NAME>
* validity of attribute for resource is defined module attributes, AttrVI_ATTR_<NAME>.resources

For static (read only) values, simple readonly and also readwrite attributes simplified construction can be used:
` self.attrs[constants.VI_ATTR_<NAME>] = 100`
or
` self.attrs[constants.VI_ATTR_<NAME>] = <self.variable_name>`

For more complex handling of attributes, it is possible to register getter and/or setter. When Null is used, NotSupported error is returned.
Getter has same signature as see Session._get_attribute and setter has same signature as see Session._set_attribute. (It is possible to register also
see Session._get_attribute and see Session._set_attribute as getter/setter). Getter and Setter are registered as tupple.
For readwrite attribute:
` self.attrs[constants.VI_ATTR_<NAME>] = (<getter_name>, <setter_name>)`
For readonly attribute:
` self.attrs[constants.VI_ATTR_<NAME>] = (<getter_name>, None)`
For reusing of see Session._get_attribute and see Session._set_attribute
` self.attrs[constants.VI_ATTR_<NAME>] = (self._get_attribute, self._set_attribute)`
"""

def get_attribute(self, attribute):
Expand All @@ -215,13 +238,14 @@ def get_attribute(self, attribute):
if not attr.read:
raise Exception('Do not now how to handle write only attributes.')

# First try to answer those attributes that are common to all session types
# or user defined because they are not defined by the interface.
# First try to answer those attributes that are registered in self.attrs, see Session.after_parsing
if attribute in self.attrs:
return self.attrs[attribute], StatusCode.success

elif attribute == constants.VI_ATTR_TMO_VALUE:
return self.timeout, StatusCode.success
value = self.attrs[attribute]
status = StatusCode.success
if isinstance(value, tuple):
getter = value[0]
value, status = getter(attribute) if getter else (0, StatusCode.error_nonsupported_attribute)
return value, status

# Dispatch to `_get_attribute`, which must be implemented by subclasses.

Expand Down Expand Up @@ -256,19 +280,16 @@ def set_attribute(self, attribute, attribute_state):
if not attr.write:
return StatusCode.error_attribute_read_only

# First try to answer those attributes that are common to all session types
# or user defined because they are not defined by the interface.
# First try to answer those attributes that are registered in self.attrs, see Session.after_parsing
if attribute in self.attrs:
self.attrs[attribute] = attribute_state
return StatusCode.success

elif attribute == constants.VI_ATTR_TMO_VALUE:
try:
self.timeout = attribute_state
except:
return StatusCode.error_nonsupported_attribute_state

return StatusCode.success
value = self.attrs[attribute]
status = StatusCode.success
if isinstance(value, tuple):
setter = value[1]
status = setter(attribute, attribute_state) if setter else StatusCode.error_nonsupported_attribute
else:
self.attrs[attribute] = attribute_state
return status

# Dispatch to `_set_attribute`, which must be implemented by subclasses.

Expand Down Expand Up @@ -311,15 +332,14 @@ def _read(self, reader, count, end_indicator_checker, suppress_end_en,
# NOTE: Some interfaces return not only a single byte but a complete block for each read
# therefore we must handle the case that the termination character is in the middle of the block
# or that the maximum number of bytes is exceeded
timeout = self.get_attribute(constants.VI_ATTR_TMO_VALUE)[0] / 1000.

# Make sure termination_char is a string
try:
termination_char = chr(termination_char)
except TypeError:
pass

start = time.time()
finish_time = None if self.timeout is None else (time.time() + self.timeout)
out = b''
while True:
try:
Expand All @@ -344,5 +364,27 @@ def _read(self, reader, count, end_indicator_checker, suppress_end_en,
# Return at most the number of bytes requested
return out[:count], StatusCode.success_max_count_read

if time.time() - start > timeout:
if finish_time and time.time() > finish_timeout:
return out, StatusCode.error_timeout

def _get_timeout(self, attribute):
""" Returns timeout calculated value from python way to VI_ way
"""
if self.timeout is None:
ret_value = constants.VI_TMO_INFINITE
elif self.timeout == 0:
ret_value = constants.VI_TMO_IMMEDIATE
else:
ret_value = int(self.timeout * 1000.0)
return ret_value, StatusCode.success

def _set_timeout(self, attribute, value):
""" Sets timeout calculated value from python way to VI_ way
"""
if value == constants.VI_TMO_INFINITE:
self.timeout = None
elif value == constants.VI_TMO_IMMEDIATE:
self.timeout = 0
else:
self.timeout = value / 1000.0
return StatusCode.success;
Loading