Refactored the camera class

This commit is contained in:
gac-x05la
2024-07-25 17:41:38 +02:00
committed by mohacsi_i
parent 7f8dd3a4bb
commit e3145dfd88
3 changed files with 69 additions and 36 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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