wip debugging at the beamline
This commit is contained in:
@@ -30,7 +30,7 @@ from superxas_bec.devices.timepix.timepix_fly_client.timepix_fly_interface impor
|
||||
)
|
||||
|
||||
|
||||
class AndStatus(_AndStatus):
|
||||
class AndStatus(StatusBase):
|
||||
"""Custom AndStatus for TimePix detector."""
|
||||
|
||||
def __init__(self, left: StatusBase | DeviceStatus, right: StatusBase | DeviceStatus, **kwargs):
|
||||
@@ -54,8 +54,12 @@ class AndStatus(_AndStatus):
|
||||
# At least one is done.
|
||||
# If it failed, do not wait for the second one.
|
||||
if (not l_success) and l_done:
|
||||
if self._externally_initiated_completion is True:
|
||||
return
|
||||
self.set_exception(self.left.exception())
|
||||
elif (not r_success) and r_done:
|
||||
if self._externally_initiated_completion is True:
|
||||
return
|
||||
self.set_exception(self.right.exception())
|
||||
|
||||
elif l_success and r_success and l_done and r_done:
|
||||
@@ -67,6 +71,25 @@ class AndStatus(_AndStatus):
|
||||
self.left.add_callback(inner)
|
||||
self.right.add_callback(inner)
|
||||
|
||||
def __repr__(self):
|
||||
return "({self.left!r} & {self.right!r})".format(self=self)
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
"{0}(done={1.done}, "
|
||||
"success={1.success})"
|
||||
"".format(self.__class__.__name__, self)
|
||||
)
|
||||
|
||||
def __contains__(self, status: StatusBase) -> bool:
|
||||
for child in [self.left, self.right]:
|
||||
if child == status:
|
||||
return True
|
||||
if isinstance(child, AndStatus):
|
||||
if status in child:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -214,7 +237,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
self._troistep = 1
|
||||
self._troin = 5000
|
||||
self._pv_timeout = 3
|
||||
self._readout_time = 2e-3 # 2ms readout time
|
||||
self._readout_time = 2.1e-3 # 2.1ms readout time to ensure readout is >2ms, required from ASI serval server..
|
||||
self.r_lock = threading.RLock() # Lock to access the message buffer safely
|
||||
super().__init__(
|
||||
name=name, prefix=prefix, scan_info=scan_info, device_manager=device_manager, **kwargs
|
||||
@@ -404,7 +427,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
other_config = OtherConfigModel(
|
||||
TRoiStep=self.troistep,
|
||||
TRoiN=self.troin,
|
||||
output_uri=f"tcp://{self.backend.hostname}:{self.backend.socket_port}",
|
||||
output_uri=f"tcp:{self.backend.hostname}:{self.backend.socket_port}",
|
||||
)
|
||||
logger.info(f"Current TimePixFly configuration: {other_config}")
|
||||
pixel_map = self.pixel_map
|
||||
@@ -412,6 +435,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
|
||||
# Fetch the backend socket info
|
||||
net_add = self.backend.timepix_fly_client.get_net_addresses()
|
||||
logger.info(f"Using net_add for timepix_fly backend {net_add}")
|
||||
self.cam.raw_file_template.set("").wait(timeout=self._pv_timeout)
|
||||
self.cam.raw_file_path.set(f"tcp://connect@{net_add.address}").wait(
|
||||
timeout=self._pv_timeout
|
||||
@@ -433,36 +457,30 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
"""Called when the device is triggered."""
|
||||
|
||||
def trigger_callback(status: DeviceStatus):
|
||||
"""Trigger callback to start the acquisition."""
|
||||
"""Trigger callback to start the acquisition."""
|
||||
if status.done:
|
||||
logger.info(f"Calling acquire on detector.")
|
||||
status.device.cam.acquire.put(1)
|
||||
logger.info(f"Status callback from backend trigger. done {status.done}, success {status.success} and exception {status._exception}")
|
||||
|
||||
# Detector will be ready to start, as either pre_scan or the status_camera from a previous
|
||||
# trigger will ensure that the detector is in ACQUIRESTATUS.DONE state.
|
||||
status_backend = DeviceStatus(self)
|
||||
# Add callback that starts the acquisition on the detector
|
||||
status_backend.add_callback(trigger_callback)
|
||||
# Prepare the camera status that resolves when the camera is finished acquiring
|
||||
status_camera = TransitionStatus(
|
||||
self.cam.acquire_busy, [ACQUIRESTATUS.ACQUIRING, ACQUIRESTATUS.DONE]
|
||||
self.cam.acquire_busy, [ACQUIRESTATUS.DONE, ACQUIRESTATUS.ACQUIRING, ACQUIRESTATUS.DONE]
|
||||
)
|
||||
# Prepare the backend, attach the status to the state of the backend
|
||||
status_backend = self.backend.on_trigger(status=status_backend)
|
||||
|
||||
# TODO cleanup and test
|
||||
def failed_to_start_collect_cb(status: DeviceStatus):
|
||||
"""Callback to handle failure to start the collect."""
|
||||
if not status.done:
|
||||
logger.error("Failed to start collect on Timepix Fly backend.")
|
||||
status.device.backend.timepix_fly_client.stop_collect()
|
||||
|
||||
status_collect_backend = DeviceStatus(self, timeout=10)
|
||||
status_collect_backend.add_callback(failed_to_start_collect_cb)
|
||||
self.backend.timepix_fly_client.add_status_callback(
|
||||
status=status_collect_backend,
|
||||
success=[TimePixFlyStatus.COLLECT],
|
||||
error=[TimePixFlyStatus.EXCEPT, TimePixFlyStatus.SHUTDOWN],
|
||||
error=[TimePixFlyStatus.EXCEPT, TimePixFlyStatus.SHUTDOWN, TimePixFlyStatus.CONFIG],
|
||||
)
|
||||
# Add callback that starts the acquisition on the detector
|
||||
status_backend.add_callback(trigger_callback)
|
||||
|
||||
status = AndStatus(status_backend, status_camera)
|
||||
st = AndStatus(status, status_collect_backend)
|
||||
@@ -513,11 +531,11 @@ if __name__ == "__main__": # pragma: no cover
|
||||
timepix.wait_for_connection(all_signals=True, timeout=10)
|
||||
timepix.on_connected()
|
||||
print("Timepix connected and initialized.")
|
||||
for exp_time, frames_per_trigger in zip([10, 1], [1, 5]):
|
||||
for exp_time, frames_per_trigger, runs in zip([0.1,1], [20,5], [10,5]):
|
||||
time.sleep(0.5)
|
||||
print(
|
||||
f"Sleeping for 0.5 seconds before starting the scan with exp_time={exp_time} "
|
||||
f"and frames_per_trigger={frames_per_trigger}."
|
||||
f"and frames_per_trigger={frames_per_trigger}. and runs {runs}"
|
||||
)
|
||||
|
||||
timepix.scan_info.msg.scan_parameters.update(
|
||||
@@ -534,36 +552,24 @@ if __name__ == "__main__": # pragma: no cover
|
||||
msgs = []
|
||||
# for ii in range(runs):
|
||||
print(f"Starting scan...; exp_time={exp_time}, frames_per_trigger={frames_per_trigger}")
|
||||
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.")
|
||||
break
|
||||
|
||||
# if timepix.xes_data.get() is not None:
|
||||
# # msgs.append(timepix.backend.msg_buffer)
|
||||
# print(
|
||||
# f"Events in energy rois {timepix.xes_data.get().signals[timepix.xes_data.name]['value'].sum()}"
|
||||
# )
|
||||
# events = timepix.xes_info.get().signals[
|
||||
# f"{timepix.xes_info.name}_tds_total_events"
|
||||
# ]["value"]
|
||||
# print(f"Total number of events: {events}")
|
||||
for run in range(runs):
|
||||
print(f"Starting run {run} for exp_time {exp_time}.")
|
||||
status = timepix.trigger()
|
||||
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 > 20:
|
||||
print("Breaking loop manually after 20 seconds of waiting.")
|
||||
break
|
||||
n_messages = len(timepix._msg_dump)
|
||||
logger.warning(f"Messages in Buffer is {len(timepix._msg_dump)}")#, with types: {[';'.join([var.get('type') for var in timepix._msg_dump])]}")
|
||||
status = timepix.complete()
|
||||
print("Waiting for timepix to complete.")
|
||||
status.wait(timeout=10)
|
||||
print("Timepix scan completed.")
|
||||
n_messages = len(timepix._msg_dump)
|
||||
logger.warning(
|
||||
f"Received new messages: Length of Buffer is {n_messages}, last message {timepix._msg_dump.get(n_messages-1, 'N/A') if n_messages>0 else 'N/A'}"
|
||||
)
|
||||
|
||||
timepix.unstage()
|
||||
print("Timepix unstaged.")
|
||||
except Exception as e:
|
||||
|
||||
@@ -9,6 +9,7 @@ hooks for all the relevant ophyd interface, 'on_stage',
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import atexit
|
||||
import json
|
||||
import signal
|
||||
@@ -122,9 +123,9 @@ class TimepixFlyBackend:
|
||||
success=[TimePixFlyStatus.CONFIG],
|
||||
error=[TimePixFlyStatus.EXCEPT, TimePixFlyStatus.SHUTDOWN],
|
||||
)
|
||||
if other_config.output_uri != f"tcp:{self.hostname}:{self.socket_port}":
|
||||
other_config.output_uri = f"tcp:{self.hostname}:{self.socket_port}"
|
||||
logger.info(f"Setting output URI to {other_config.output_uri}.")
|
||||
# if other_config.output_uri != f"tcp:{self.hostname}:{self.socket_port}":
|
||||
# other_config.output_uri = f"tcp:{self.hostname}:{self.socket_port}"
|
||||
# logger.info(f"Setting output URI to {other_config.output_uri}.")
|
||||
# Make sure backend is in config state
|
||||
try:
|
||||
status.wait(timeout=5.0)
|
||||
@@ -137,6 +138,14 @@ class TimepixFlyBackend:
|
||||
raise TimeoutError(
|
||||
"Timepix Fly backend state did not reach config state. Most likely a timeout error. Please check log for detailed error message."
|
||||
)
|
||||
status = StatusBase()
|
||||
|
||||
self.timepix_fly_client.add_status_callback(
|
||||
status,
|
||||
success=[TimePixFlyStatus.CONFIG],
|
||||
error=[TimePixFlyStatus.EXCEPT, TimePixFlyStatus.SHUTDOWN],
|
||||
)
|
||||
logger.info(f"Setting other config, backend {other_config}")
|
||||
self.timepix_fly_client.set_other_config(other_config)
|
||||
self.timepix_fly_client.set_pixel_map(pixel_map)
|
||||
|
||||
@@ -156,6 +165,8 @@ class TimepixFlyBackend:
|
||||
Returns:
|
||||
StatusBase | DeviceStatus: The status object that will be updated with the operation's result
|
||||
"""
|
||||
# TODO add check that backend is in CONFIG!
|
||||
time.sleep(0.05)
|
||||
if status is None:
|
||||
status = StatusBase()
|
||||
self.timepix_fly_client.add_status_callback(
|
||||
|
||||
@@ -344,6 +344,7 @@ class TimepixFlyClient:
|
||||
Start the TimePix detector by sending a GET request to the start endpoint.
|
||||
This method is a wrapper around the REST API call to start the detector.
|
||||
"""
|
||||
logger.info(f"Start send from pixfly client")
|
||||
self._get(get_cmd="?start=true")
|
||||
self._started = True
|
||||
|
||||
@@ -478,6 +479,7 @@ class TimepixFlyClient:
|
||||
raise ValueError(
|
||||
f"Value must be an instance of OtherConfigModel. Received {type(other_config)}, {other_config}."
|
||||
)
|
||||
# logger.info(f"Value send via rest from set_other_config {other_config.model_dump()}")
|
||||
self._put(put_cmd="other-config", value=other_config.model_dump(), put_response_model=None)
|
||||
|
||||
def get_net_addresses(self) -> NetAddresses:
|
||||
|
||||
Reference in New Issue
Block a user