Basic PCO functionality tested
This commit is contained in:
@@ -5,11 +5,8 @@ Created on Wed Dec 6 11:33:54 2023
|
||||
@author: mohacsi_i
|
||||
"""
|
||||
|
||||
from ophyd import Device, Component, EpicsMotor, EpicsSignal, EpicsSignalRO, Kind
|
||||
from ophyd.status import Status, SubscriptionStatus, StatusBase, DeviceStatus
|
||||
from time import sleep
|
||||
import warnings
|
||||
import numpy as np
|
||||
from ophyd import Component, EpicsSignal, EpicsSignalRO, Kind
|
||||
from ophyd.status import SubscriptionStatus
|
||||
import time
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import PSIDetectorBase as PSIDeviceBase
|
||||
from ophyd_devices.interfaces.base_classes.psi_detector_base import CustomDetectorMixin as CustomDeviceMixin
|
||||
@@ -32,10 +29,10 @@ class PcoEdgeCameraMixin(CustomDeviceMixin):
|
||||
"""
|
||||
|
||||
# Gigafrost can finish a run without explicit unstaging
|
||||
if self.parent.infoBusyFlag.value:
|
||||
logger.warning("Camera is already running, unstaging it first!")
|
||||
if self.parent.state not in ("IDLE"):
|
||||
logger.warning(f"Trying to stage the camera from state {self.parent.state}, unstaging it first!")
|
||||
self.parent.unstage()
|
||||
sleep(0.5)
|
||||
time.sleep(0.5)
|
||||
|
||||
# Fish out our configuration from scaninfo (via explicit or generic addressing)
|
||||
scanparam = self.parent.scaninfo.scan_msg.info
|
||||
@@ -95,8 +92,6 @@ class HelgeCameraBase(PSIDeviceBase):
|
||||
The status flag state machine during re-configuration is:
|
||||
BUSY low, SET low -> BUSY high, SET low -> BUSY low, SET high -> BUSY low, SET low
|
||||
"""
|
||||
# Specify Mixin class
|
||||
custom_prepare_cls = HelgeCameraMixin
|
||||
|
||||
# ########################################################################
|
||||
# General hardware info (in AD nomenclature)
|
||||
@@ -166,14 +161,9 @@ class HelgeCameraBase(PSIDeviceBase):
|
||||
|
||||
def configure(self, d: dict = {}) -> tuple:
|
||||
""" Configure the base Helge camera device"""
|
||||
if self.state in ["OFFLINE", "REMOVED", "RUNNING"]:
|
||||
if self.state not in ("IDLE"):
|
||||
raise RuntimeError(f"Can't change configuration from state {self.state}")
|
||||
|
||||
# Stop acquisition
|
||||
self.unstage()
|
||||
if not self._initialized:
|
||||
pass
|
||||
|
||||
# If Bluesky style configure
|
||||
if d is not None:
|
||||
# Commonly changed settings
|
||||
@@ -209,7 +199,7 @@ class HelgeCameraBase(PSIDeviceBase):
|
||||
|
||||
# Subscribe and wait for update
|
||||
def isRunning(*args, old_value, value, timestamp, **kwargs):
|
||||
return bool(self.state=="RUNNING")
|
||||
return bool(value==6)
|
||||
status = SubscriptionStatus(self.camStatusCode, isRunning, timeout=5, settle_time=0.2)
|
||||
status.wait()
|
||||
|
||||
@@ -222,7 +212,7 @@ class HelgeCameraBase(PSIDeviceBase):
|
||||
# Subscribe and wait for update
|
||||
def isIdle(*args, old_value, value, timestamp, **kwargs):
|
||||
return bool(value==2)
|
||||
status = SubscriptionStatus(self.parent.camStatusCode, isIdle, timeout=5, settle_time=0.2)
|
||||
status = SubscriptionStatus(self.camStatusCode, isIdle, timeout=5, settle_time=0.2)
|
||||
status.wait()
|
||||
|
||||
|
||||
@@ -265,8 +255,6 @@ class PcoEdgeBase(HelgeCameraBase):
|
||||
bufferRecMode = Component(EpicsSignalRO, "RECMODE", auto_monitor=True, kind=Kind.config)
|
||||
bufferStoreMode = Component(EpicsSignalRO, "STOREMODE", auto_monitor=True, kind=Kind.config)
|
||||
fileRecMode = Component(EpicsSignalRO, "RECMODE", auto_monitor=True, kind=Kind.config)
|
||||
|
||||
|
||||
|
||||
def configure(self, d: dict = {}) -> tuple:
|
||||
"""
|
||||
@@ -276,9 +264,29 @@ class PcoEdgeBase(HelgeCameraBase):
|
||||
both send the settings to the camera and allocate the necessary buffers in the correct
|
||||
size and shape (that takes time). Starting the exposure with CAMERASTATUS will also
|
||||
call SET_PARAM, but it might take long.
|
||||
"""
|
||||
old = self.read_configuration()
|
||||
|
||||
|
||||
NOTE:
|
||||
The camera IOC will automatically round up RoiX coordinates to the
|
||||
next multiple of 160. This means that configure can only change image
|
||||
width in steps of 320 pixels (or manually of 160). Roi
|
||||
|
||||
Parameters as 'd' dictionary
|
||||
----------------------------
|
||||
exposure_time_ms : float, optional
|
||||
Exposure time [ms].
|
||||
exposure_period_ms : float, optional
|
||||
Exposure period [ms], ignored in soft trigger mode.
|
||||
image_width : int, optional
|
||||
ROI size in the x-direction, multiple of 320 [pixels]
|
||||
image_height : int, optional
|
||||
ROI size in the y-direction, multiple of 2 [pixels]
|
||||
image_binx : int optional
|
||||
Binning along image width [pixels]
|
||||
image_biny: int, optional
|
||||
Binning along image height [pixels]
|
||||
acq_mode : str, not yet implemented
|
||||
Select one of the pre-configured trigger behavior
|
||||
"""
|
||||
if d is not None:
|
||||
# Need to be smart how we set the ROI....
|
||||
# Image sensor is 2560x2160 (X and Y)
|
||||
@@ -300,20 +308,9 @@ class PcoEdgeBase(HelgeCameraBase):
|
||||
super().configure(d)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Automatically connect to test camera if directly invoked
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Drive data collection
|
||||
cam = HelgeCameraBase("X02DA-CCDCAM2:", name="mcpcam")
|
||||
cam = PcoEdgeBase("X02DA-CCDCAM2:", name="mcpcam")
|
||||
cam.wait_for_connection()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user