Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor #80

Merged
merged 11 commits into from
Aug 23, 2018
33 changes: 33 additions & 0 deletions pytac/cothread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from pytac.cs import ControlSystem
from cothread.catools import caget, caput


class CothreadControlSystem(ControlSystem):
""" The EPICS control system.

It is used to communicate over channel access with the hardware
in the ring.
"""
def __init__(self):
pass

def get(self, pv):
""" Get the value of a given PV.

Args:
pv (string): The process variable given as a string. It can be a
readback or a setpoint PV.

Returns:
float: Represents the current value of the given PV.
"""
return caget(pv)

def put(self, pv, value):
""" Set the value for a given.

Args:
pv (string): The PV to set the value of. It must be a setpoint PV.
value (Number): The value to set the PV to.
"""
caput(pv, value)
158 changes: 11 additions & 147 deletions pytac/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,171 +5,35 @@
DLS is a sextupole magnet that contains also horizontal and vertical corrector
magnets and a skew quadrupole.
"""
import pytac
from pytac.exceptions import HandleException


class Device(object):
"""A device attached to an element.
"""A representation of a property of an element associated with a field.

Contains a control system, readback and setpoint PVs. A readback
or setpoint PV is required when creating a device otherwise a
DeviceException is raised. The device is enabled by default.

**Attributes:**

Attributes:
name (str): The prefix of EPICS PVs for this device.
rb_pv (str): The EPICS readback PV.
sp_pv (str): The EPICS setpoint PV.

.. Private Attributes:
_cs (ControlSystem): The control system object used to get and set
the value of a PV.
_enabled (bool-like): Whether the device is enabled. May be a
PvEnabler object.
Typically a control system will be used to set and get values on a
device.
"""
def __init__(self, name, cs, enabled=True, rb_pv=None, sp_pv=None):
""".. The constructor method for the class, called whenever a 'Device'
object is constructed.

Args:
name (str): The prefix of EPICS PV for this device.
cs (ControlSystem): The control system object used to get and set
the value of a PV.
enabled (bool-like): Whether the device is enabled. May be a
PvEnabler object.
rb_pv (str): The EPICS readback PV.
sp_pv (str): The EPICS setpoint PV.

**Methods:**
"""
self.name = name
self._cs = cs
self.rb_pv = rb_pv
self.sp_pv = sp_pv
self._enabled = enabled

def is_enabled(self):
"""Whether the device is enabled.

Returns:
bool: whether the device is enabled.
"""
return bool(self._enabled)
raise NotImplementedError()

def set_value(self, value):
"""Set the device value.

Args:
value (float): The value to set on the PV.

Raises:
HandleException: if no setpoint PV exists.
"""
if self.sp_pv is None:
raise HandleException(
"Device {0} has no setpoint PV.".format(self.name)
)
self._cs.put(self.sp_pv, value)

def get_value(self, handle):
"""Read the value of a readback or setpoint PV.

Args:
handle (str): The handle used to get the value off a readback or
setpoint PV.

Returns:
float: The value of the PV.

Raises:
HandleException: if the requested PV doesn't exist.
"""
print('getting {}'.format('handle'))
if handle == pytac.RB and self.rb_pv:
return self._cs.get(self.rb_pv)
elif handle == pytac.SP and self.sp_pv:
return self._cs.get(self.sp_pv)

raise HandleException(
"Device {0} has no {1} PV.".format(self.name, handle)
)

def get_pv_name(self, handle):
"""Get a PV name on a specified handle.

Args:
handle (str): The readback or setpoint handle to be returned.

Returns:
str: A readback or setpoint PV.

Raises:
HandleException: if the PV doesn't exist.
"""
if handle == pytac.RB and self.rb_pv:
return self.rb_pv
elif handle == pytac.SP and self.sp_pv:
return self.sp_pv

raise HandleException(
"Device {0} has no {1} PV.".format(self.name, handle)
)

def get_cs(self):
"""The control system object used to get and set the value of a PV.

Returns:
ControlSystem: The control system object used to get and set the
value of a PV.
"""
return self._cs


class PvEnabler(object):
"""A PvEnabler class to check whether a device is enabled.

The class will behave like True if the PV value equals enabled_value,
and False otherwise.

.. Private Attributes:
_pv (str): The PV name.
_enabled_value (str): The value for PV for which the device should
be considered enabled.
_cs (ControlSystem): The control system object.
"""
def __init__(self, pv, enabled_value, cs):
""".. The constructor method for the class, called whenever a
'PvEnabler' object is constructed.
"""Set the value on the device.

Args:
pv (str): The PV name.
enabled_value (str): The value for PV for which the device should
be considered enabled.
cs (ControlSystem): The control system object.
"""
self._pv = pv
self._enabled_value = str(int(float(enabled_value)))
self._cs = cs

def __nonzero__(self):
"""Used to override the 'if object' clause.

Support for Python 2.7.

Returns:
bool: True if the device should be considered enabled.
value (float): the value to set.
"""
pv_value = self._cs.get(self._pv)
return self._enabled_value == str(int(float(pv_value)))

def __bool__(self):
"""Used to override the 'if object' clause.
raise NotImplementedError()

Support for Python 3.x.
def get_value(self):
"""Read the value from the device.

Returns:
bool: True if the device should be considered enabled.
float: the value of the PV.
"""
return self.__nonzero__()
raise NotImplementedError()
30 changes: 4 additions & 26 deletions pytac/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ def get_value(self, field, handle=pytac.RB, units=pytac.ENG,
model (str): pytac.LIVE or pytac.SIM.

Returns:
object: The value of the requested field, returned from EPICS as a
string or cothread float.
float: The value of the requested field

Raises:
DeviceException: if there is no device on the given field.
Expand Down Expand Up @@ -197,34 +196,13 @@ def set_value(self, field, value, handle=pytac.SP, units=pytac.ENG,
try:
model = self._models[model]
except KeyError:
raise DeviceException('No model type {} on element {}'.format(model,
self))
raise DeviceException(
'No model type {} on element {}'.format(model, self)
)
try:
value = self._uc[field].convert(value, origin=units, target=model.units)
model.set_value(field, value)
except KeyError:
raise FieldException('No field {} on element {}'.format(model, self))
except FieldException:
raise FieldException('No field {} on element {}'.format(field, self))

def get_pv_name(self, field, handle):
"""Get a PV name on a device.

Args:
field (str): The requested field.
handle (str): pytac.RB or pytac.SP.

Returns:
str: The readback or setpoint PV for the specified field.

Raises:
DeviceException: if there is no device for this field.
FieldException: if the element does not have the specified field.
"""
try:
return self._models[pytac.LIVE].get_pv_name(field, handle)
except KeyError:
raise DeviceException('{} has no device for field {}'.format(self,
field))
except FieldException:
raise FieldException('No field {} on element {}'.format(field, self))
Loading