Samcam image preview and smargon waiting
This commit is contained in:
@@ -448,7 +448,7 @@ samimg:
|
|||||||
prefix: 'X06DA-SAMCAM:image1:'
|
prefix: 'X06DA-SAMCAM:image1:'
|
||||||
deviceTags:
|
deviceTags:
|
||||||
- detector
|
- detector
|
||||||
enabled: true
|
enabled: false
|
||||||
readoutPriority: async
|
readoutPriority: async
|
||||||
readOnly: false
|
readOnly: false
|
||||||
softwareTrigger: false
|
softwareTrigger: false
|
||||||
@@ -599,7 +599,7 @@ abr:
|
|||||||
shx:
|
shx:
|
||||||
description: SmarGon X axis
|
description: SmarGon X axis
|
||||||
deviceClass: pxiii_bec.devices.SmarGonAxis
|
deviceClass: pxiii_bec.devices.SmarGonAxis
|
||||||
deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
onFailure: buffer
|
onFailure: buffer
|
||||||
enabled: true
|
enabled: true
|
||||||
readoutPriority: monitored
|
readoutPriority: monitored
|
||||||
@@ -608,7 +608,7 @@ shx:
|
|||||||
shy:
|
shy:
|
||||||
description: SmarGon Y axis
|
description: SmarGon Y axis
|
||||||
deviceClass: pxiii_bec.devices.SmarGonAxis
|
deviceClass: pxiii_bec.devices.SmarGonAxis
|
||||||
deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
onFailure: buffer
|
onFailure: buffer
|
||||||
enabled: true
|
enabled: true
|
||||||
readoutPriority: monitored
|
readoutPriority: monitored
|
||||||
@@ -626,7 +626,7 @@ shz:
|
|||||||
chi:
|
chi:
|
||||||
description: SmarGon CHI axis
|
description: SmarGon CHI axis
|
||||||
deviceClass: pxiii_bec.devices.SmarGonAxis
|
deviceClass: pxiii_bec.devices.SmarGonAxis
|
||||||
deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
deviceConfig: {prefix: 'SCS', low_limit: 0, high_limit: 40, sg_url: 'http://x06da-smargopolo.psi.ch:3000'}
|
||||||
onFailure: buffer
|
onFailure: buffer
|
||||||
enabled: true
|
enabled: true
|
||||||
readoutPriority: monitored
|
readoutPriority: monitored
|
||||||
@@ -641,17 +641,3 @@ phi:
|
|||||||
readoutPriority: monitored
|
readoutPriority: monitored
|
||||||
readOnly: false
|
readOnly: false
|
||||||
softwareTrigger: false
|
softwareTrigger: false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# samimgs:
|
|
||||||
# description: Sample camera image
|
|
||||||
# deviceClass: ophyd_devices.devices.areadetector.plugins.ImagePlugin_V35
|
|
||||||
# deviceConfig: {prefix: 'X06DA-SAMCAM:image1:', foo: 'bar'}
|
|
||||||
# onFailure: buffer
|
|
||||||
# enabled: false
|
|
||||||
# readoutPriority: monitored
|
|
||||||
# readOnly: true
|
|
||||||
# softwareTrigger: false
|
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class AerotechAbrMixin(CustomDeviceMixin):
|
|||||||
scan_range_y = scanargs["range"]
|
scan_range_y = scanargs["range"]
|
||||||
scan_steps_y = scanargs["steps"]
|
scan_steps_y = scanargs["steps"]
|
||||||
d["scan_command"] = AbrCmd.VERTICAL_LINE_SCAN
|
d["scan_command"] = AbrCmd.VERTICAL_LINE_SCAN
|
||||||
d["var_1"] = scan_range_y / scan_steps_y
|
d["var_1"] = scan_range_y / scan_steps_y
|
||||||
d["var_2"] = scan_steps_y
|
d["var_2"] = scan_steps_y
|
||||||
d["var_3"] = scan_exp_time
|
d["var_3"] = scan_exp_time
|
||||||
d["var_4"] = 0
|
d["var_4"] = 0
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import types
|
|||||||
from ophyd import Component, PVPositioner, Signal, EpicsSignal, EpicsSignalRO, Kind, PositionerBase
|
from ophyd import Component, PVPositioner, Signal, EpicsSignal, EpicsSignalRO, Kind, PositionerBase
|
||||||
from ophyd.status import Status, MoveStatus
|
from ophyd.status import Status, MoveStatus
|
||||||
|
|
||||||
from .A3200enums import AbrMode
|
|
||||||
|
|
||||||
from bec_lib import bec_logger
|
from bec_lib import bec_logger
|
||||||
|
|
||||||
|
from .A3200enums import AbrMode
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class A3200Axis(PVPositioner):
|
|||||||
# Patching the parent's PVs into the axis class to check for direct/locked mode
|
# Patching the parent's PVs into the axis class to check for direct/locked mode
|
||||||
if parent is None:
|
if parent is None:
|
||||||
|
|
||||||
def maybe_add_prefix(self, instance, kw, suffix):
|
def maybe_add_prefix(self, _, kw, suffix):
|
||||||
# Patched not to enforce parent prefix when no parent
|
# Patched not to enforce parent prefix when no parent
|
||||||
if kw in self.add_prefix:
|
if kw in self.add_prefix:
|
||||||
return suffix
|
return suffix
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ class NDArrayPreview(Device):
|
|||||||
This is a monolithic class to display images from AreaDetector's
|
This is a monolithic class to display images from AreaDetector's
|
||||||
ImagePlugin without the use of DynamicDeviceComponent or multiple
|
ImagePlugin without the use of DynamicDeviceComponent or multiple
|
||||||
interitance (that doesn't work with BEC).
|
interitance (that doesn't work with BEC).
|
||||||
|
|
||||||
|
NOTE: As an explicit request, it doesnt record the data, unless
|
||||||
"""
|
"""
|
||||||
# Subscriptions for plotting image
|
# Subscriptions for plotting image
|
||||||
USER_ACCESS = ["image"]
|
USER_ACCESS = ["image", "savemode"]
|
||||||
SUB_MONITOR = "device_monitor_2d"
|
SUB_MONITOR = "device_monitor_2d"
|
||||||
_default_sub = SUB_MONITOR
|
_default_sub = SUB_MONITOR
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ class NDArrayPreview(Device):
|
|||||||
derived_from="array_data",
|
derived_from="array_data",
|
||||||
shape=("array_size_z", "array_size_y", "array_size_x"),
|
shape=("array_size_z", "array_size_y", "array_size_x"),
|
||||||
num_dimensions="ndimensions",
|
num_dimensions="ndimensions",
|
||||||
kind=Kind.normal,
|
kind=Kind.omitted,
|
||||||
)
|
)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
@@ -47,6 +49,14 @@ class NDArrayPreview(Device):
|
|||||||
self._run_subs(sub_type=self.SUB_MONITOR, value=image)
|
self._run_subs(sub_type=self.SUB_MONITOR, value=image)
|
||||||
return super().read()
|
return super().read()
|
||||||
|
|
||||||
|
def savemode(self, save=False):
|
||||||
|
""" Toggle save mode for the shaped image"""
|
||||||
|
#pylint: disable=protected-access
|
||||||
|
if save:
|
||||||
|
self.shaped_image._kind = Kind.normal
|
||||||
|
else:
|
||||||
|
self.shaped_image._kind = Kind.omitted
|
||||||
|
|
||||||
def image(self):
|
def image(self):
|
||||||
""" Fallback method in case image streaming fills up the BEC"""
|
""" Fallback method in case image streaming fills up the BEC"""
|
||||||
array_size = (self.array_size_z.get(), self.array_size_y.get(), self.array_size_x.get())
|
array_size = (self.array_size_z.get(), self.array_size_y.get(), self.array_size_x.get())
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
from ophyd import Component, Device, Kind, Signal, SignalRO
|
from threading import Thread
|
||||||
|
from ophyd import Component, Device, Kind, Signal, SignalRO, PVPositioner
|
||||||
|
from ophyd.status import SubscriptionStatus
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from bec_lib import bec_logger
|
from bec_lib import bec_logger
|
||||||
@@ -36,7 +38,7 @@ class SmarGonSignal(Signal):
|
|||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
|
|
||||||
# Perform the actual write to SmargoPolo
|
# Perform the actual write to SmargoPolo
|
||||||
r = self.parent._go_n_put(f"{self.write_addr}?{self.addr.upper()}={value}", **kwargs)
|
r = self.parent._go_n_put(f"{self.write_addr}?{self.addr.upper()}={value}")
|
||||||
|
|
||||||
old_value = self._readback
|
old_value = self._readback
|
||||||
self._timestamp = timestamp
|
self._timestamp = timestamp
|
||||||
@@ -79,23 +81,32 @@ class SmarGonSignalRO(Signal):
|
|||||||
TODO: Add monitoring
|
TODO: Add monitoring
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, read_addr="readbackSCS", **kwargs):
|
def __init__(self, *args, read_addr="readbackSCS", auto_monitor=False, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._metadata["write_access"] = False
|
self._metadata["write_access"] = False
|
||||||
self.read_addr = read_addr
|
self.read_addr = read_addr
|
||||||
self.addr = self.parent.name
|
self.addr = self.parent.name
|
||||||
|
|
||||||
|
if auto_monitor:
|
||||||
|
self._mon = Thread(target=self.poll, daemon=True)
|
||||||
|
self._mon.start()
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
r = self.parent._go_n_get(self.read_addr)
|
r = self.parent._go_n_get(self.read_addr)
|
||||||
# print(r)
|
|
||||||
if isinstance(r, dict):
|
if isinstance(r, dict):
|
||||||
self.put(r[self.addr.upper()], force=True)
|
self.put(r[self.addr.upper()], force=True)
|
||||||
else:
|
else:
|
||||||
self.put(r, force=True)
|
self.put(r, force=True)
|
||||||
return super().get(*args, **kwargs)
|
return self._readback
|
||||||
|
|
||||||
|
def poll(self, *args, **kwargs):
|
||||||
|
""" Fooo"""
|
||||||
|
while True:
|
||||||
|
time.sleep(0.2)
|
||||||
|
self.get()
|
||||||
|
|
||||||
class SmarGonAxis(Device):
|
class SmarGonAxis(PVPositioner):
|
||||||
"""SmarGon client deice
|
"""SmarGon client deice
|
||||||
|
|
||||||
This class controls the SmarGon goniometer via the REST interface.
|
This class controls the SmarGon goniometer via the REST interface.
|
||||||
@@ -107,11 +118,12 @@ class SmarGonAxis(Device):
|
|||||||
mode = Component(SmarGonSignalRO, read_addr="mode", kind=Kind.config)
|
mode = Component(SmarGonSignalRO, read_addr="mode", kind=Kind.config)
|
||||||
|
|
||||||
# Axis parameters
|
# Axis parameters
|
||||||
readback = Component(SmarGonSignalRO, kind=Kind.hinted)
|
readback = Component(SmarGonSignalRO, kind=Kind.hinted, auto_monitor=True)
|
||||||
setpoint = Component(SmarGonSignal, kind=Kind.normal)
|
setpoint = Component(SmarGonSignal, kind=Kind.normal)
|
||||||
done = Component(SignalRO, value=1, kind=Kind.normal)
|
done = Component(SignalRO, value=1, kind=Kind.normal)
|
||||||
# moving = Component(SmarGonMovingSignalRO, kind=Kind.config)
|
# moving = Component(SmarGonMovingSignalRO, kind=Kind.config)
|
||||||
moving = 1
|
moving = 1
|
||||||
|
_tol = 0.001
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -122,7 +134,6 @@ class SmarGonAxis(Device):
|
|||||||
read_attrs=None,
|
read_attrs=None,
|
||||||
configuration_attrs=None,
|
configuration_attrs=None,
|
||||||
parent=None,
|
parent=None,
|
||||||
device_manager=None,
|
|
||||||
sg_url: str = "http://x06da-smargopolo.psi.ch:3000",
|
sg_url: str = "http://x06da-smargopolo.psi.ch:3000",
|
||||||
low_limit=None,
|
low_limit=None,
|
||||||
high_limit=None,
|
high_limit=None,
|
||||||
@@ -132,7 +143,7 @@ class SmarGonAxis(Device):
|
|||||||
self.__class__.__dict__["setpoint"].kwargs["write_addr"] = f"target{prefix}"
|
self.__class__.__dict__["setpoint"].kwargs["write_addr"] = f"target{prefix}"
|
||||||
self.__class__.__dict__["setpoint"].kwargs["low_limit"] = low_limit
|
self.__class__.__dict__["setpoint"].kwargs["low_limit"] = low_limit
|
||||||
self.__class__.__dict__["setpoint"].kwargs["high_limit"] = high_limit
|
self.__class__.__dict__["setpoint"].kwargs["high_limit"] = high_limit
|
||||||
|
self.__class__.__dict__["sg_url"].kwargs["value"] = sg_url
|
||||||
super().__init__(
|
super().__init__(
|
||||||
prefix=prefix,
|
prefix=prefix,
|
||||||
name=name,
|
name=name,
|
||||||
@@ -140,11 +151,8 @@ class SmarGonAxis(Device):
|
|||||||
read_attrs=read_attrs,
|
read_attrs=read_attrs,
|
||||||
configuration_attrs=configuration_attrs,
|
configuration_attrs=configuration_attrs,
|
||||||
parent=parent,
|
parent=parent,
|
||||||
# device_manager=device_manager,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
self.sg_url._metadata["write_access"] = False
|
|
||||||
self.sg_url.set(sg_url, force=True).wait()
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""Helper function for initial readings"""
|
"""Helper function for initial readings"""
|
||||||
@@ -153,6 +161,24 @@ class SmarGonAxis(Device):
|
|||||||
r = self._go_n_get("corr_type")
|
r = self._go_n_get("corr_type")
|
||||||
print(r)
|
print(r)
|
||||||
|
|
||||||
|
def move(self, position, wait=True, timeout=None, moved_cb=None):
|
||||||
|
|
||||||
|
status = self.setpoint.set(position, settle_time=0.1)
|
||||||
|
|
||||||
|
if not wait:
|
||||||
|
return status
|
||||||
|
else:
|
||||||
|
status.wait()
|
||||||
|
|
||||||
|
def on_target(*, value, **_):
|
||||||
|
distance = abs(value-position)
|
||||||
|
print(distance)
|
||||||
|
return bool(distance<self._tol)
|
||||||
|
status = SubscriptionStatus(
|
||||||
|
self.readback, on_target, timeout=timeout, settle_time=0.1
|
||||||
|
)
|
||||||
|
return status
|
||||||
|
|
||||||
def _go_n_get(self, address, **kwargs):
|
def _go_n_get(self, address, **kwargs):
|
||||||
"""Helper function to connect to smargopolo"""
|
"""Helper function to connect to smargopolo"""
|
||||||
cmd = f"{self.sg_url.get()}/{address}"
|
cmd = f"{self.sg_url.get()}/{address}"
|
||||||
|
|||||||
@@ -7,27 +7,20 @@ Created on Thu Jun 27 17:28:43 2024
|
|||||||
@author: mohacsi_i
|
@author: mohacsi_i
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import enum
|
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import zmq
|
import zmq
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from ophyd import Device, Signal, Component, Kind, DeviceStatus
|
from ophyd import Device, Signal, Component, Kind
|
||||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
||||||
CustomDetectorMixin,
|
CustomDetectorMixin,
|
||||||
PSIDetectorBase,
|
PSIDetectorBase,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bec_lib import bec_logger
|
from bec_lib import bec_logger
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
ZMQ_TOPIC_FILTER = b''
|
ZMQ_TOPIC_FILTER = b""
|
||||||
|
|
||||||
|
|
||||||
class StdDaqPreviewState(enum.IntEnum):
|
|
||||||
"""Standard DAQ ophyd device states"""
|
|
||||||
UNKNOWN = 0
|
|
||||||
DETACHED = 1
|
|
||||||
MONITORING = 2
|
|
||||||
|
|
||||||
|
|
||||||
class StdDaqPreviewMixin(CustomDetectorMixin):
|
class StdDaqPreviewMixin(CustomDetectorMixin):
|
||||||
@@ -35,6 +28,7 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
|
|
||||||
Parent class: CustomDetectorMixin
|
Parent class: CustomDetectorMixin
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_mon = None
|
_mon = None
|
||||||
|
|
||||||
def on_stage(self):
|
def on_stage(self):
|
||||||
@@ -43,9 +37,7 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
self.parent.unstage()
|
self.parent.unstage()
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
|
|
||||||
logger.info(
|
logger.info(f"[{self.parent.name}] Attaching monitor to {self.parent.url.get()}")
|
||||||
f"[{self.parent.name}] Attaching monitor to {self.parent.url.get()}"
|
|
||||||
)
|
|
||||||
self.parent.connect()
|
self.parent.connect()
|
||||||
self._stop_polling = False
|
self._stop_polling = False
|
||||||
self._mon = Thread(target=self.poll, daemon=True)
|
self._mon = Thread(target=self.poll, daemon=True)
|
||||||
@@ -66,7 +58,6 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
"""Collect streamed updates"""
|
"""Collect streamed updates"""
|
||||||
self.parent.status.set(StdDaqPreviewState.MONITORING, force=True)
|
|
||||||
try:
|
try:
|
||||||
t_last = time()
|
t_last = time()
|
||||||
while True:
|
while True:
|
||||||
@@ -82,7 +73,8 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
# Length and throtling checks
|
# Length and throtling checks
|
||||||
if len(r) != 2:
|
if len(r) != 2:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"[{self.parent.name}] Received malformed array of length {len(r)}")
|
f"[{self.parent.name}] Received malformed array of length {len(r)}"
|
||||||
|
)
|
||||||
t_curr = time()
|
t_curr = time()
|
||||||
t_elapsed = t_curr - t_last
|
t_elapsed = t_curr - t_last
|
||||||
if t_elapsed < self.parent.throttle.get():
|
if t_elapsed < self.parent.throttle.get():
|
||||||
@@ -94,26 +86,26 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
|
|
||||||
# Update image and update subscribers
|
# Update image and update subscribers
|
||||||
header = json.loads(meta)
|
header = json.loads(meta)
|
||||||
if header["type"] == "uint16":
|
image = np.frombuffer(data, dtype=header["type"])
|
||||||
image = np.frombuffer(data, dtype=np.uint16)
|
if image.size != np.prod(header["shape"]):
|
||||||
if header["type"] == "uint8":
|
|
||||||
image = np.frombuffer(data, dtype=np.uint8)
|
|
||||||
if image.size != np.prod(header['shape']):
|
|
||||||
err = f"Unexpected array size of {image.size} for header: {header}"
|
err = f"Unexpected array size of {image.size} for header: {header}"
|
||||||
raise ValueError(err)
|
raise ValueError(err)
|
||||||
image = image.reshape(header['shape'])
|
image = image.reshape(header["shape"])
|
||||||
|
|
||||||
# Update image and update subscribers
|
# Update image and update subscribers
|
||||||
self.parent.frameno.put(header['frame'], force=True)
|
self.parent.array_counter.put(header["frame"], force=True)
|
||||||
self.parent.image_shape.put(header['shape'], force=True)
|
self.parent.ndimensions.put(len(header["shape"]), force=True)
|
||||||
self.parent.image.put(image, force=True)
|
self.parent.array_size.put(header["shape"], force=True)
|
||||||
|
# self.parent.array_data.put(data, force=True)
|
||||||
|
self.parent.shaped_image.put(image, force=True)
|
||||||
|
|
||||||
self.parent._last_image = image
|
self.parent._last_image = image
|
||||||
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
|
self.parent._run_subs(sub_type=self.parent.SUB_MONITOR, value=image)
|
||||||
t_last = t_curr
|
t_last = t_curr
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[{self.parent.name}] Updated frame {header['frame']}\t"
|
f"[{self.parent.name}] Updated frame {header['frame']}\t"
|
||||||
f"Shape: {header['shape']}\tMean: {np.mean(image):.3f}"
|
f"Shape: {header['shape']}\tMean: {np.mean(image):.3f}"
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Happens when ZMQ partially delivers the multipart message
|
# Happens when ZMQ partially delivers the multipart message
|
||||||
pass
|
pass
|
||||||
@@ -125,37 +117,39 @@ class StdDaqPreviewMixin(CustomDetectorMixin):
|
|||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self._mon = None
|
self._mon = None
|
||||||
self.parent.status.set(StdDaqPreviewState.DETACHED, force=True)
|
|
||||||
logger.info(f"[{self.parent.name}]\tDetaching monitor")
|
logger.info(f"[{self.parent.name}]\tDetaching monitor")
|
||||||
|
|
||||||
|
|
||||||
class StdDaqPreviewDetector(PSIDetectorBase):
|
class StdDaqPreviewDetector(PSIDetectorBase):
|
||||||
"""Detector wrapper class around the StdDaq preview image stream.
|
"""Detector wrapper class around the StdDaq preview image stream.
|
||||||
|
|
||||||
This was meant to provide live image stream directly from the StdDAQ
|
This was meant to provide live image stream directly from the StdDAQ but
|
||||||
but also works with other ARRAY v1 streamers, like the AreaDetector
|
also works with other ARRAY v1 streamers, like the AreaDetector ZMQ plugin.
|
||||||
ZMQ plugin.
|
Note that the preview stream must be already throtled in order to cope with
|
||||||
Note that the preview stream must be already throtled in order to cope
|
the incoming data and the python class might throttle it further.
|
||||||
with the incoming data and the python class might throttle it further.
|
|
||||||
|
NOTE: As an explicit request, it does not record the image data.
|
||||||
|
|
||||||
You can add a preview widget to the dock by:
|
You can add a preview widget to the dock by:
|
||||||
cam_widget = gui.add_dock('cam_dock1').add_widget('BECFigure').image('daq_stream1')
|
cam_widget = gui.add_dock('cam_dock1').add_widget('BECFigure').image('daq_stream1')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Subscriptions for plotting image
|
# Subscriptions for plotting image
|
||||||
USER_ACCESS = ["get_image"]
|
USER_ACCESS = ["image", "savemode"]
|
||||||
SUB_MONITOR = "device_monitor_2d"
|
SUB_MONITOR = "device_monitor_2d"
|
||||||
_default_sub = SUB_MONITOR
|
_default_sub = SUB_MONITOR
|
||||||
|
|
||||||
custom_prepare_cls = StdDaqPreviewMixin
|
custom_prepare_cls = StdDaqPreviewMixin
|
||||||
|
|
||||||
# Status attributes
|
# Configuration attributes
|
||||||
url = Component(Signal, kind=Kind.config, metadata={"write_access": False})
|
url = Component(Signal, kind=Kind.config, metadata={"write_access": False})
|
||||||
throttle = Component(Signal, value=0.25, kind=Kind.config)
|
throttle = Component(Signal, value=0.25, kind=Kind.config)
|
||||||
status = Component(Signal, value=StdDaqPreviewState.UNKNOWN, kind=Kind.omitted, metadata={"write_access": False})
|
# Streamed data status
|
||||||
frameno = Component(Signal, kind=Kind.hinted, metadata={"write_access": False})
|
array_counter = Component(Signal, kind=Kind.hinted, metadata={"write_access": False})
|
||||||
image_shape = Component(Signal, kind=Kind.normal, metadata={"write_access": False})
|
ndimensions = Component(Signal, kind=Kind.normal, metadata={"write_access": False})
|
||||||
# FIXME: The BEC client caches the read()s from the last 50 scans
|
array_size = Component(Signal, kind=Kind.normal, metadata={"write_access": False})
|
||||||
image = Component(Signal, kind=Kind.omitted, metadata={"write_access": False})
|
# array_data = Component(Signal, kind=Kind.omitted, metadata={"write_access": False})
|
||||||
|
shaped_image = Component(Signal, kind=Kind.omitted, metadata={"write_access": False})
|
||||||
_last_image = None
|
_last_image = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -183,8 +177,16 @@ class StdDaqPreviewDetector(PSIDetectorBase):
|
|||||||
sleep(1)
|
sleep(1)
|
||||||
self._socket.connect(self.url.get())
|
self._socket.connect(self.url.get())
|
||||||
|
|
||||||
def get_image(self):
|
def savemode(self, save=False):
|
||||||
"""
|
""" Toggle save mode for the shaped image"""
|
||||||
|
#pylint: disable=protected-access
|
||||||
|
if save:
|
||||||
|
self.shaped_image._kind = Kind.normal
|
||||||
|
else:
|
||||||
|
self.shaped_image._kind = Kind.omitted
|
||||||
|
|
||||||
|
def image(self):
|
||||||
|
"""
|
||||||
Gets the last image as an attribute in case image must be abandoned
|
Gets the last image as an attribute in case image must be abandoned
|
||||||
due to some caching on the BEC.
|
due to some caching on the BEC.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ from .A3200 import AerotechAbrStage
|
|||||||
from .A3200utils import A3200Axis
|
from .A3200utils import A3200Axis
|
||||||
from .SmarGon import SmarGonAxis
|
from .SmarGon import SmarGonAxis
|
||||||
from .StdDaqPreview import StdDaqPreviewDetector
|
from .StdDaqPreview import StdDaqPreviewDetector
|
||||||
from .NDArrayPreview import NDArrayPreview
|
from .NDArrayPreview import NDArrayPreview
|
||||||
|
|||||||
Reference in New Issue
Block a user