add script for online testing
This commit is contained in:
@@ -5,6 +5,7 @@ is implemented via EPICS IOC.
|
||||
"""
|
||||
|
||||
import enum
|
||||
from time import time
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from ophyd import ADBase
|
||||
@@ -13,6 +14,7 @@ from ophyd import DeviceStatus, StatusBase
|
||||
from ophyd_devices import AndStatus, CompareStatus, TransitionStatus
|
||||
from ophyd_devices.devices.areadetector.cam import ASItpxCam
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
from typeguard import typechecked
|
||||
|
||||
from superxas_bec.devices.timepix.timepix_fly_client.timepix_fly_backend import TimepixFlyBackend
|
||||
from superxas_bec.devices.timepix.timepix_fly_client.timepix_fly_interface import (
|
||||
@@ -138,8 +140,56 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
self.backend = TimepixFlyBackend(
|
||||
backend_rest_url=backend_rest_url, hostname=hostname, socket_port=socket_port
|
||||
)
|
||||
self._pixel_map = PixelMap(
|
||||
chips=[
|
||||
[{"i": 256 ^ 2 - 1, "p": [0, 1], "f": [0.5, 0.5]}],
|
||||
[{"i": 255 * 256, "p": [0, 1], "f": [0.5, 0.5]}],
|
||||
[{"i": 255, "p": [1, 2], "f": [0.5, 0.5]}],
|
||||
[{"i": 0, "p": [1, 2], "f": [0.5, 0.5]}],
|
||||
]
|
||||
)
|
||||
self._troistep = 1
|
||||
self._troin = 5000
|
||||
|
||||
@property
|
||||
def pixel_map(self) -> PixelMap:
|
||||
"""Get the current pixel map of the TimePix detector."""
|
||||
return self._pixel_map
|
||||
|
||||
@pixel_map.setter
|
||||
@typechecked
|
||||
def pixel_map(self, value: PixelMap):
|
||||
self._pixel_map = value
|
||||
|
||||
@property
|
||||
def troistep(self) -> int:
|
||||
"""Get the current ROI step size."""
|
||||
return self._troistep
|
||||
|
||||
@troistep.setter
|
||||
@typechecked
|
||||
def troistep(self, value: int):
|
||||
"""Set the ROI step size."""
|
||||
if value <= 0:
|
||||
raise ValueError("ROI step size must be a positive integer.")
|
||||
self._troistep = value
|
||||
|
||||
@property
|
||||
def troin(self) -> int:
|
||||
"""Get the current ROI number of pixels."""
|
||||
return self._troin
|
||||
|
||||
@troin.setter
|
||||
@typechecked
|
||||
def troin(self, value: int):
|
||||
"""Set the ROI number of pixels."""
|
||||
if value <= 0:
|
||||
raise ValueError("ROI number of pixels must be a positive integer.")
|
||||
self._troin = value
|
||||
|
||||
######################################################################
|
||||
### Beamline specific methods for the TimePix Detector integration ###
|
||||
######################################################################
|
||||
def on_init(self) -> None:
|
||||
"""
|
||||
Called when the device is initialized.
|
||||
@@ -173,19 +223,28 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
Information about the upcoming scan can be accessed from the scan_info (self.scan_info.msg) object.
|
||||
"""
|
||||
# currently hardcode acquire time.. -> discuss logic here
|
||||
# TODO discuss if the acquire period should be equivalent to the exposure time,
|
||||
# and acquire time always 2ms shorter than the acquire period.
|
||||
# num_images is currently hardcoded, is this basically a burst frame at each point of a step scan?
|
||||
self.cam.acquire_time.set(0.998).wait(timeout=self._pv_timeout)
|
||||
self.cam.acquire_period.set(1.0).wait(timeout=self._pv_timeout)
|
||||
self.cam.num_images.set(10).wait(timeout=self._pv_timeout)
|
||||
self.cam.raw_enable.set(1).wait(timeout=self._pv_timeout)
|
||||
# TODO: can we inspect this from the backend instead!!
|
||||
self.cam.raw_file_template.set("").wait(timeout=self._pv_timeout)
|
||||
self.cam.raw_file_path.set(f"tcp://connect@127.0.0.1:8451").wait(timeout=self._pv_timeout)
|
||||
|
||||
# -------------------------
|
||||
# Prepare TimePixFly
|
||||
other_config = self.scan_info.msg.scan_parameters.get("other_config", None)
|
||||
pixel_map = self.scan_info.msg.scan_parameters.get("pixel_map", None)
|
||||
if other_config or pixel_map is None:
|
||||
raise RuntimeError(
|
||||
f"Scan info does not contain 'other_config' or 'pixel_map' for device {self.name}."
|
||||
)
|
||||
# TODO RoiStep and TRoinN are those config parameters across many scans,
|
||||
# or parameter that are configured similar to energypoints --> pixel_map?
|
||||
|
||||
other_config = OtherConfigModel(
|
||||
TRoiStep=self.troistep,
|
||||
TRoiN=self.troin,
|
||||
output_uri=f"tcp://{self.backend.hostname}:{self.backend.socket_port}",
|
||||
)
|
||||
pixel_map = self.pixel_map
|
||||
self.backend.on_stage(other_config=other_config, pixel_map=pixel_map)
|
||||
|
||||
def on_unstage(self) -> None:
|
||||
@@ -214,7 +273,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
status_backend.add_callback(trigger_callback)
|
||||
# Trigger the backend to start, then the callback will trigger the acquisition on the detector.
|
||||
# This adds a status callback from the backend, which will resolve the status once the backend is finished.
|
||||
self.backend.on_trigger(status=status_backend)
|
||||
status_backend = self.backend.on_trigger(status=status_backend)
|
||||
|
||||
status_camera = TransitionStatus(
|
||||
self.cam.acquire_busy, [ACQUIRESTATUS.ACQUIRING, ACQUIRESTATUS.DONE]
|
||||
@@ -234,7 +293,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
status_backend = DeviceStatus(self)
|
||||
self.cancel_on_stop(status_backend)
|
||||
# Add callback to the backend complete handling
|
||||
self.backend.on_complete(status=status_backend)
|
||||
status_backend = self.backend.on_complete(status=status_backend)
|
||||
# Combine the statuses
|
||||
complete_status = AndStatus(status_backend, status_detector)
|
||||
return complete_status
|
||||
@@ -256,7 +315,55 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
|
||||
# pylint: disable=protected-access
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
pass
|
||||
|
||||
timepix = Timepix(
|
||||
name="timepix",
|
||||
prefix="X10DA-ES-TPX1:",
|
||||
backend_rest_url="P4-0017.psi.ch:8452",
|
||||
hostname="x10da-bec-001.psi.ch",
|
||||
)
|
||||
try:
|
||||
timepix.wait_for_connection(all_signals=True, timeout=10)
|
||||
timepix.on_connected()
|
||||
|
||||
print("Timepix connected and initialized.")
|
||||
timepix.stage()
|
||||
print("Timepix staged.")
|
||||
timepix.pre_scan()
|
||||
print("Timepix pre-scan completed.")
|
||||
msgs = []
|
||||
for ii in range(5):
|
||||
print(f"Starting scan {ii + 1}...; sleeping for 1s before each trigger before start")
|
||||
time.sleep(1)
|
||||
status = timepix.trigger()
|
||||
print("Timepix trigger sent.")
|
||||
start_time = time.time()
|
||||
while not status.done:
|
||||
try:
|
||||
status.wait(timeout=1)
|
||||
except Exception as exc:
|
||||
print(f" Trigger status not done yet after ({time.time() - start_time:.2f}s)")
|
||||
if time.time() - start_time > 30:
|
||||
print("Breaking loop manually after 30 seconds of waiting.")
|
||||
print(f"Received number of messsages: {len(timepix.backend.msg_buffer)}")
|
||||
msgs.append(timepix.backend.msg_buffer)
|
||||
timepix.backend.reset_message_buffer()
|
||||
print(f"Resettet message buffer after scan {ii + 1}.")
|
||||
status = timepix.complete()
|
||||
print("Waiting for timepix to complete.")
|
||||
status.wait(timeout=10)
|
||||
print("Timepix scan completed.")
|
||||
for ii, msg in enumerate(msgs):
|
||||
print(f"Received {len(msg)} messages for trigger {ii}.")
|
||||
|
||||
timepix.unstage()
|
||||
print("Timepix unstaged.")
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
logger.error(f"An error occurred: {e}")
|
||||
finally:
|
||||
timepix.destroy()
|
||||
print("Timepix destroyed.")
|
||||
|
||||
# Create a Timepix object
|
||||
# timepix = Timepix(name="TimePixDetector", prefix="")
|
||||
|
||||
@@ -332,6 +332,8 @@ if __name__ == "__main__": # pragma: no cover
|
||||
timepix.on_stage(other_config=config, pixel_map=pixel_map)
|
||||
print("TimepixFlyBackend staged with configuration and pixel map.")
|
||||
for ii in range(10):
|
||||
print(f"Starting scan {ii + 1}...; sleeping for 1 before start")
|
||||
time.sleep(1)
|
||||
status = timepix.on_trigger()
|
||||
print("TimepixFlyBackend pre-scan started.")
|
||||
status.wait(timeout=10)
|
||||
|
||||
Reference in New Issue
Block a user