Refactored the camera class
This commit is contained in:
@@ -94,7 +94,7 @@ femto_mean_curr:
|
||||
|
||||
gf2:
|
||||
description: GigaFrost camera controls
|
||||
deviceClass: tomcat_bec.devices.gigafrost.gigafrostclient.GigaFrostClient
|
||||
deviceClass: tomcat_bec.devices.gigafrost.gigafrostcamera.GigaFrostCamera
|
||||
deviceConfig:
|
||||
prefix: 'X02DA-CAM-GF2:'
|
||||
backend_url: 'http://xbl-daq-28:8080'
|
||||
@@ -106,6 +106,23 @@ gf2:
|
||||
readOnly: false
|
||||
readoutPriority: monitored
|
||||
softwareTrigger: true
|
||||
|
||||
#gf2:
|
||||
# description: GigaFrost camera controls
|
||||
# deviceClass: tomcat_bec.devices.gigafrost.gigafrostclient.GigaFrostClient
|
||||
# deviceConfig:
|
||||
# prefix: 'X02DA-CAM-GF2:'
|
||||
# backend_url: 'http://xbl-daq-28:8080'
|
||||
# auto_soft_enable: true
|
||||
# deviceTags:
|
||||
# - camera
|
||||
# enabled: true
|
||||
# onFailure: buffer
|
||||
# readOnly: false
|
||||
# readoutPriority: monitored
|
||||
# softwareTrigger: true
|
||||
|
||||
|
||||
daq:
|
||||
description: Standard DAQ controls
|
||||
deviceClass: tomcat_bec.devices.gigafrost.stddaq_ws.StdDaqWsClient
|
||||
|
||||
@@ -6,7 +6,7 @@ Created on Thu Jun 27 17:28:43 2024
|
||||
|
||||
@author: mohacsi_i
|
||||
"""
|
||||
from enum import Enum
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
gf_valid_enable_modes = ("soft", "external", "soft+ext", "always")
|
||||
@@ -16,7 +16,7 @@ gf_valid_fix_nframe_modes = ("off", "start", "end", "start+end")
|
||||
|
||||
|
||||
# STATUS
|
||||
class GfStatus(Enum):
|
||||
class GfStatus(IntEnum):
|
||||
"""Operation states for GigaFrost Ophyd device"""
|
||||
NEW = 1
|
||||
INITIALIZED = 2
|
||||
|
||||
@@ -6,9 +6,8 @@ Created on Thu Jun 27 17:28:43 2024
|
||||
|
||||
@author: mohacsi_i
|
||||
"""
|
||||
import sys
|
||||
from time import sleep
|
||||
from ophyd import Device, Component, EpicsSignal, EpicsSignalRO, Kind, DeviceStatus
|
||||
from ophyd import Signal, SignalRO, Device, Component, EpicsSignal, EpicsSignalRO, Kind, DeviceStatus
|
||||
from ophyd.device import Staged
|
||||
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import (
|
||||
@@ -26,6 +25,13 @@ try:
|
||||
except ModuleNotFoundError:
|
||||
from tomcat_bec.devices.gigafrost.gfutils import extend_header_table
|
||||
|
||||
try:
|
||||
from bec_lib import bec_logger
|
||||
logger = bec_logger.logger
|
||||
except ModuleNotFoundError:
|
||||
import logging
|
||||
logger = logging.getLogger("GfCam")
|
||||
|
||||
|
||||
class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
"""Mixin class to setup TOMCAT specific implementations of the detector.
|
||||
@@ -38,7 +44,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
elif self.parent.backendUrl.get() == const.BE999_DAFL_CLIENT:
|
||||
return const.BE999_NORTH_IP, const.BE999_SOUTH_IP
|
||||
else:
|
||||
raise RuntimeError(f"Backend not recognized. {(const.GF1, const.GF2, const.GF3)}")
|
||||
raise RuntimeError(f"Backend {self.parent.backendUrl.get()} not recognized. {(const.GF1, const.GF2, const.GF3)}")
|
||||
|
||||
def _define_backend_mac(self):
|
||||
if self.parent.backendUrl.get() == const.BE3_DAFL_CLIENT: # xbl-daq-33
|
||||
@@ -46,7 +52,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
elif self.parent.backendUrl.get() == const.BE999_DAFL_CLIENT:
|
||||
return const.BE999_NORTH_MAC, const.BE999_SOUTH_MAC
|
||||
else:
|
||||
raise RuntimeError(f"Backend not recognized. {(const.GF1, const.GF2, const.GF3)}")
|
||||
raise RuntimeError(f"Backend {self.parent.backendUrl.get()} not recognized. {(const.GF1, const.GF2, const.GF3)}")
|
||||
|
||||
def _set_udp_header_table(self):
|
||||
"""Set the communication parameters for the camera module"""
|
||||
@@ -62,11 +68,11 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
source_port = 3000 + j
|
||||
if j < 4:
|
||||
extend_header_table(
|
||||
udp_header_table, self.parent.macSouth, self.parent.ipSouth, dest_port, source_port
|
||||
udp_header_table, self.parent.macSouth.get(), self.parent.ipSouth.get(), dest_port, source_port
|
||||
)
|
||||
else:
|
||||
extend_header_table(
|
||||
udp_header_table, self.parent.macNorth, self.parent.ipNorth, dest_port, source_port
|
||||
udp_header_table, self.parent.macNorth.get(), self.parent.ipNorth.get(), dest_port, source_port
|
||||
)
|
||||
|
||||
return udp_header_table
|
||||
@@ -88,7 +94,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
self.parent.cmdWriteService.set(1).wait()
|
||||
|
||||
# Configure software triggering if needed
|
||||
if self.parent._auto_soft_enable:
|
||||
if self.parent.autoSoftEnable.get():
|
||||
# trigger modes
|
||||
self.parent.cfgCntStartBit.set(1).wait()
|
||||
self.parent.cfgCntEndBit.set(0).wait()
|
||||
@@ -120,15 +126,15 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
self.parent.state.put(const.GfStatus.INIT, force=True)
|
||||
return super().on_init()
|
||||
|
||||
|
||||
|
||||
def on_stage(self) -> None:
|
||||
"""
|
||||
Specify actions to be executed during stage in preparation for a scan.
|
||||
self.parent.scaninfo already has all current parameters for the upcoming scan.
|
||||
"""Specify actions to be executed during stage
|
||||
|
||||
In case the backend service is writing data on disk, this step should include publishing
|
||||
a file_event and file_message to BEC to inform the system where the data is written to.
|
||||
Specifies actions to be executed during the stage step in preparation
|
||||
for a scan. self.parent.scaninfo already has all current parameters for
|
||||
the upcoming scan.
|
||||
|
||||
The gigafrost camera IOC does not write data to disk, that's done by
|
||||
the DAQ ophyd device.
|
||||
|
||||
IMPORTANT:
|
||||
It must be safe to assume that the device is ready for the scan
|
||||
@@ -143,8 +149,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
self.parent._staged = Staged.no
|
||||
|
||||
def on_unstage(self) -> None:
|
||||
"""
|
||||
Specify actions to be executed during unstage.
|
||||
"""Specify actions to be executed during unstage.
|
||||
|
||||
This step should include checking if the acqusition was successful,
|
||||
and publishing the file location and file event message,
|
||||
@@ -153,7 +158,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
# Switch to idle
|
||||
self.parent.cmdStartCamera.set(0).wait()
|
||||
if self.parent.autoSoftEnable.get():
|
||||
self.cmdSoftEnable.set(0).wait()
|
||||
self.parent.cmdSoftEnable.set(0).wait()
|
||||
self.parent.state.put(const.GfStatus.STOPPED, force=True)
|
||||
|
||||
def on_stop(self) -> None:
|
||||
@@ -180,7 +185,7 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
sleep_time = self.parent.cfgFramerate.value*self.parent.cfgCntNum.value*0.001+0.050
|
||||
# There's no status readback from the camera, so we just wait
|
||||
sleep(sleep_time)
|
||||
print(f"[GF2] Slept for: {sleep_time} seconds", file=sys.stderr)
|
||||
logger.info(f"[GF2] Slept for: {sleep_time} seconds")
|
||||
else:
|
||||
self.parent.cmdSoftTrigger.set(1).wait()
|
||||
status.set_finished()
|
||||
@@ -209,13 +214,12 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
|
||||
Bugs:
|
||||
----------
|
||||
FRAMERATE : Ignored in soft trigger mode, period becomes 2xexposure time
|
||||
FRAMERATE : Ignored in soft trigger mode, period becomes 2xExposure time
|
||||
"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
|
||||
custom_prepare_cls = GigaFrostCameraMixin
|
||||
|
||||
|
||||
USER_ACCESS = [""]
|
||||
|
||||
infoBusyFlag = Component(EpicsSignalRO, "BUSY_STAT", auto_monitor=True)
|
||||
infoSyncFlag = Component(EpicsSignalRO, "SYNC_FLAG", auto_monitor=True)
|
||||
@@ -358,9 +362,13 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
|
||||
USER_ACCESS = ["exposure_mode", "fix_nframes_mode", "trigger_mode", "enable_mode"]
|
||||
|
||||
autoSoftEnable = Component(Signal, auto_monitor=True, kind=Kind.config)
|
||||
backendUrl = Component(Signal, auto_monitor=True, kind=Kind.config)
|
||||
state = Component(Signal, auto_monitor=True, kind=Kind.config)
|
||||
autoSoftEnable = Component(Signal, kind=Kind.config)
|
||||
backendUrl = Component(Signal, kind=Kind.config)
|
||||
macNorth = Component(Signal, kind=Kind.config)
|
||||
macSouth = Component(Signal, kind=Kind.config)
|
||||
ipNorth = Component(Signal, kind=Kind.config)
|
||||
ipSouth = Component(Signal, kind=Kind.config)
|
||||
state = Component(Signal, value=int(const.GfStatus.NEW), kind=Kind.config)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -376,14 +384,11 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
parent=None,
|
||||
**kwargs,
|
||||
):
|
||||
# Additional parameters
|
||||
self.autoSoftEnable._metadata["write_access"] = False
|
||||
self.backendUrl._metadata["write_access"] = False
|
||||
self.state._metadata["write_access"] = False
|
||||
self.autoSoftEnable.put(auto_soft_enable, force=True)
|
||||
self.backendUrl.put(backend_url, force=True)
|
||||
self.state.put(const.GfStatus.NEW, force=True)
|
||||
|
||||
# Ugly hack to pass values before on_init()
|
||||
self._signals_to_be_set = {}
|
||||
self._signals_to_be_set['auto_soft_enable'] = auto_soft_enable
|
||||
self._signals_to_be_set['backend_url'] = backend_url
|
||||
|
||||
# super() will call the mixin class
|
||||
super().__init__(
|
||||
prefix=prefix,
|
||||
@@ -395,6 +400,17 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def _init(self):
|
||||
"""Ugly hack: values must be set before on_init() is called"""
|
||||
# Additional parameters
|
||||
self.autoSoftEnable._metadata["write_access"] = False
|
||||
self.backendUrl._metadata["write_access"] = False
|
||||
self.state._metadata["write_access"] = False
|
||||
self.autoSoftEnable.put(self._signals_to_be_set['auto_soft_enable'], force=True)
|
||||
self.backendUrl.put(self._signals_to_be_set['backend_url'], force=True)
|
||||
self.state.put(const.GfStatus.NEW, force=True)
|
||||
return super()._init()
|
||||
|
||||
def configure(
|
||||
self,
|
||||
nimages=10,
|
||||
@@ -448,7 +464,7 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
|
||||
# Stop acquisition
|
||||
self.cmdStartCamera.set(0).wait()
|
||||
if self._auto_soft_enable:
|
||||
if self.autoSoftEnable.get():
|
||||
self.cmdSoftEnable.set(0).wait()
|
||||
|
||||
# change settings
|
||||
|
||||
Reference in New Issue
Block a user