Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
78 changes: 39 additions & 39 deletions slicops/device/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@


class AccessorPutError(RuntimeError):
"""The PV for this accessor is not writable"""
"""This accessor is not writable"""

pass


class DeviceError(RuntimeError):
"""Error communicating with PV"""
"""Error communicating with accessor"""

pass

Expand All @@ -45,9 +45,9 @@ def accessor(self, accessor_name):
"""Get `_Accessor` for more complex operations

Args:
accessor_name (str): friendly name for PV for this device
accessor_name (str): control system independent name
Returns:
_Accessor: object holding PV state
_Accessor: object holding control system state
"""
if self._destroyed:
raise AssertionError(f"destroyed {self}")
Expand All @@ -56,7 +56,7 @@ def accessor(self, accessor_name):
)[accessor_name]

def destroy(self):
"""Disconnect from PV's and remove state about device"""
"""Disconnect from accessors and remove state about device"""
if self._destroyed:
return
self._destroyed = True
Expand All @@ -66,31 +66,31 @@ def destroy(self):
a.destroy()

def get(self, accessor_name):
"""Read from PV
"""Read from accessor

Args:
accessor_name (str): friendly name for PV for this device
accessor_name (str):
Returns:
object: the value from the PV converted to a Python type
object: the value from the control system converted to a Python type
"""
return self.accessor(accessor_name).get()

def has_accessor(self, accessor_name):
"""Check whether device has accessor

Args:
accessor_name (str): friendly name for PV for this device
accessor_name (str): control system independent name
Returns:
bool: True if accessor is found for device
"""
return accessor_name in self.meta.accessor

def put(self, accessor_name, value):
"""Set PV to value
"""Set accessor to value

Args:
accessor_name (str): friendly name for PV for this device
value (object): Value to write to PV
accessor_name (str): control system independent name
value (object): Value to write to control system
"""
return self.accessor(accessor_name).put(value)

Expand All @@ -99,11 +99,11 @@ def __repr__(self):


class _Accessor:
"""Container for a PV, metadata, and dynamic state
"""Container for a control system value, metadata, and dynamic state

Attributes:
device (Device): object holding this accessor
meta (PKDict): meta data about the accessor, e.g. pv_name, pv_writable
meta (PKDict): meta data about the accessor, e.g. cs_name, writable
"""

def __init__(self, device, accessor_name):
Expand All @@ -116,10 +116,10 @@ def __init__(self, device, accessor_name):
self._initialized = threading.Event()
self._initializing = False
# Defer initialization
self._pv = None
self._cs = None

def destroy(self):
"""Stop all monitoring and disconnect from PV"""
"""Stop all monitoring and disconnect from accessor"""
if self._destroyed:
return
with self._lock:
Expand All @@ -128,9 +128,9 @@ def destroy(self):
self._destroyed = True
self._initializing = False
self._callback = None
if (p := self._pv) is None:
if (p := self._cs) is None:
return
self._pv = None
self._cs = None
self._initialized.set()
try:
# Clears all callbacks
Expand All @@ -139,26 +139,26 @@ def destroy(self):
pkdlog("error={} {} stack={}", e, self, pkdexc())

def get(self):
"""Read from PV
"""Read from control system

Returns:
object: the value from the PV converted to a Python type
object: the value from the accessor converted to a Python type
"""
p = self.__pv()
p = self.__cs()
if (rv := p.get(timeout=_TIMEOUT)) is None:
raise DeviceError(f"unable to get {self}")
if not p.connected:
raise DeviceError(f"disconnected {self}")
return self._fixup_value(rv)

def monitor(self, callback):
"""Monitor PV and call callback with updates and connection changes
"""Monitor accessor and call callback with updates and connection changes

The argument to the callback is a `PKDict` with one or more of:
error : str
error occured in the values from the PV callback (unlikely)
error occured in the values from the callback (unlikely)
value : object
PV reported this change
control system reported this change
connected : bool
connection state changed: True if connected

Expand All @@ -169,25 +169,25 @@ def monitor(self, callback):
self._assert_not_destroyed()
if self._callback:
raise AssertionError("may only call monitor once")
if self._pv or self._initializing:
if self._cs or self._initializing:
raise AssertionError("monitor must be called before get/put")
self._callback = callback
self.__pv()
self.__cs()

def monitor_stop(self):
"""Stops monitoring PV"""
"""Stops monitoring accessor"""
with self._lock:
if self._destroyed or not self._callback:
return
self._callback = None

def put(self, value):
"""Set PV to value
"""Set accessor to value

Args:
value (object): Value to write to PV
value (object): Value to write to control system
"""
if not self.meta.pv_writable:
if not self.meta.writable:
raise AccessorPutError(f"read-only {self}")
if self.meta.py_type == bool:
v = bool(value)
Expand All @@ -198,7 +198,7 @@ def put(self, value):
else:
raise AccessorPutError(f"unhandled py_type={self.meta.py_type} {self}")
# ECA_NORMAL == 0 and None is normal, too, apparently
p = self.__pv()
p = self.__cs()
if (e := p.put(v)) != 1:
raise DeviceError(f"put error={e} value={v} {self}")
if not p.connected:
Expand Down Expand Up @@ -244,11 +244,11 @@ def _on_value(self, **kwargs):
pkdlog("error={} {} stack={}", e, self, pkdexc())
raise

def __pv(self):
def __cs(self):
with self._lock:
self._assert_not_destroyed()
if self._pv:
return self._pv
if self._cs:
return self._cs
if not (i := self._initializing):
self._initializing = True
if i:
Expand All @@ -260,21 +260,21 @@ def __pv(self):
else PKDict()
)
if self.accessor_name == "image":
# TODO(robnagler) this has to be done here, because you can't get pvs
# TODO(robnagler) this has to be done here, because you can't get accessor
# from within a monitor callback.
# TODO(robnagler) need a better way of dealing with this
self._image_shape = (self.device.get("n_row"), self.device.get("n_col"))
self._pv = epics.PV(
self.meta.pv_name,
self._cs = epics.PV(
self.meta.cs_name,
connection_callback=self._on_connection,
connection_timeout=_TIMEOUT,
**k,
)
self._initialized.set()
return self._pv
return self._cs

def __repr__(self):
return f"<_Accessor {self.device.device_name}.{self.accessor_name} {self.meta.pv_name}>"
return f"<_Accessor {self.device.device_name}.{self.accessor_name} {self.meta.cs_name}>"

def _run_callback(self, **kwargs):
k = PKDict(accessor=self, **kwargs)
Expand Down
24 changes: 12 additions & 12 deletions slicops/device_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ class DeviceDbError(Exception):

_ACCESSOR_META_DEFAULT = PKDict(
py_type=float,
pv_writable=False,
writable=False,
)

_ACCESSOR_META = PKDict(
acquire=PKDict(py_type=bool, pv_writable=True),
enabled=PKDict(py_type=int, pv_writable=False),
image=PKDict(py_type=numpy.ndarray, pv_writable=False),
n_bits=PKDict(py_type=int, pv_writable=False),
n_col=PKDict(py_type=int, pv_writable=False),
n_row=PKDict(py_type=int, pv_writable=False),
start_scan=PKDict(py_type=int, pv_writable=True),
target_control=PKDict(py_type=int, pv_writable=True),
target_status=PKDict(py_type=int, pv_writable=False),
acquire=PKDict(py_type=bool, writable=True),
enabled=PKDict(py_type=int, writable=False),
image=PKDict(py_type=numpy.ndarray, writable=False),
n_bits=PKDict(py_type=int, writable=False),
n_col=PKDict(py_type=int, writable=False),
n_row=PKDict(py_type=int, writable=False),
start_scan=PKDict(py_type=int, writable=True),
target_control=PKDict(py_type=int, writable=True),
target_status=PKDict(py_type=int, writable=False),
)


Expand Down Expand Up @@ -174,12 +174,12 @@ class DeviceMeta(PKDict):
"""Information about a device

Attributes:
accessor (PKDict): name to PKDict(name, pv_name, pv_writable, py_type, ...)
accessor (PKDict): name to PKDict(name, cs_name, writable, py_type, ...)
beam_area (str): area where device is located
beam_path (tuple): which beam paths does it go through
device_type (str): type device, e.g. "PROF"
device_name (str): name of device
pv_prefix (str): prefix to all accessor PVs for device
cs_name (str): prefix to all accessors for device
"""

pass
Expand Down
22 changes: 12 additions & 10 deletions slicops/device_sql_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def device(name):
accessor=PKDict(
{
r.accessor_name: PKDict(r)
for r in s.select("device_pv", PKDict(device_name=name))
for r in s.select("device_accessor", PKDict(device_name=name))
}
),
)
Expand Down Expand Up @@ -77,8 +77,8 @@ def upstream_devices(device_type, required_accessor, beam_path, end_device):
s.t.beam_path.c.beam_area == s.t.device.c.beam_area,
)
.join(
s.t.device_pv,
s.t.device_pv.c.device_name == c,
s.t.device_accessor,
s.t.device_accessor.c.device_name == c,
)
)
.where(
Expand All @@ -87,7 +87,7 @@ def upstream_devices(device_type, required_accessor, beam_path, end_device):
s.t.device_meta_float.c.device_meta_value
< _device_meta(end_device, "sum_l_meters", s),
s.t.device.c.device_type == device_type,
s.t.device_pv.c.accessor_name == required_accessor,
s.t.device_accessor.c.accessor_name == required_accessor,
)
.order_by(s.t.device_meta_float.c.device_meta_value)
)
Expand Down Expand Up @@ -165,10 +165,12 @@ def _devices(self, session):
device_name=d.name,
beam_area=d.metadata.area,
device_type=d.metadata.type,
pv_prefix=d.pv_prefix,
cs_name=d.cs_name,
)
for k, v in d.pvs.items():
session.insert("device_pv", device_name=n, accessor_name=k, pv_name=v)
for k, v in d.device_accessors.items():
session.insert(
"device_accessor", device_name=n, accessor_name=k, cs_name=v
)
for k, v in d.metadata.items():
if k not in self._METADATA_SKIP:
session.insert(
Expand Down Expand Up @@ -199,12 +201,12 @@ def _init():
device_name=p,
beam_area=n + " foreign",
device_type=n,
pv_prefix=s,
cs_name=s,
),
device_pv=PKDict(
device_accessor=PKDict(
device_name=p + " foreign",
accessor_name=p,
pv_name=s,
cs_name=s,
),
device_meta_float=PKDict(
device_name=p + " foreign",
Expand Down
Binary file modified slicops/package_data/device_db.sqlite3
Binary file not shown.
4 changes: 2 additions & 2 deletions slicops/package_data/sliclet/screen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fields:
ui:
widget: heatmap_with_lineouts
writable: false
pv:
cs_name:
prototype: String
ui:
label: PV
Expand Down Expand Up @@ -57,7 +57,7 @@ ui_layout:
rows:
- beam_path
- camera
- pv
- cs_name
- cell_group:
- start_button
- stop_button
Expand Down
Loading