wip bugfixes

This commit is contained in:
2026-05-12 11:08:42 +02:00
parent 67a26f231d
commit 19182daa47
3 changed files with 42 additions and 32 deletions
+33 -28
View File
@@ -12,7 +12,6 @@ import os
import threading
import time
import traceback
from functools import partial
from typing import TYPE_CHECKING, Any, Literal
import numpy as np
@@ -20,12 +19,13 @@ from bec_lib.file_utils import get_full_path
from bec_lib.logger import bec_logger
from ophyd import ADBase
from ophyd import Component as Cpt
from ophyd import EpicsSignalRO, EpicsSignalWithRBV
from ophyd import Signal
from ophyd_devices import (
AndStatus,
AsyncSignal,
CompareStatus,
DeviceStatus,
EpicsSignalRO,
EpicsSignalWithRBV,
ExceptionStatus,
FileEventSignal,
PreviewSignal,
@@ -201,6 +201,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
"set_pixel_map",
"set_pixel_map_from_json_file",
"set_enable_xes",
"set_enable_image_writing",
]
xes_data = Cpt(
@@ -514,6 +515,15 @@ class Timepix(PSIDeviceBase, TimePixControl):
"""
self.enable_xes = enable
def set_enable_image_writing(self, enable: bool) -> None:
"""
Enable or disable image writing to file through the HDF5 plugin.
Args:
enable (bool): Whether to enable image writing.
"""
self.hdf.enable.set(1 if enable else 0).wait(timeout=self._pv_timeout)
@property
def enable_xes(self) -> bool:
"""Get whether XES data acquisition is enabled."""
@@ -701,18 +711,18 @@ class Timepix(PSIDeviceBase, TimePixControl):
file_path = "/".join(self._full_path.split("/")[:-1])
file_name = self._full_path.split("/")[-1]
self.cam.array_callbacks.set(1).wait(5) # Enable array callbacks
# self.hdf.enable.set(1).wait(5) # Enable HDF5 plugin
self.hdf.file_path.set(file_path).wait(5)
self.hdf.file_name.set(file_name).wait(5)
# Setup file writing for the total expected number of images
self.hdf.num_capture.set(self._n_images).wait(5)
self.hdf.capture.put(1)
self.file_event.put(
file_path=self._full_path,
done=False,
successful=False,
hinted_h5_entries={"data": "/entry/data/data"},
)
if self.hdf.enable.get() == 1:
self.hdf.capture.put(1)
self.file_event.put(
file_path=self._full_path,
done=False,
successful=False,
hinted_h5_entries={"data": "/entry/data/data"},
)
# -------------------------
# XES specific staging
@@ -807,13 +817,15 @@ class Timepix(PSIDeviceBase, TimePixControl):
def on_complete(self) -> DeviceStatus | StatusBase | None:
"""Called to inquire if a device has completed a scans."""
# Status Camera
status_camera = CompareStatus(self.cam.acquire_busy, ACQUIRESTATUS.DONE)
return_status = CompareStatus(self.cam.acquire_busy, ACQUIRESTATUS.DONE)
# Status Writer
st1 = CompareStatus(self.hdf.capture, ACQUIRESTATUS.DONE)
st2 = CompareStatus(self.hdf.write_file, ACQUIRESTATUS.DONE)
st3 = ExceptionStatus(self.hdf.write_status, 0, operation="!=")
status_written_images = CompareStatus(self.hdf.num_captured, self._n_images)
status_writer = st1 & st2 & status_written_images
status_writer = None
if self.hdf.enable.get() == 1:
st2 = CompareStatus(self.hdf.write_file, ACQUIRESTATUS.DONE)
st3 = ExceptionStatus(self.hdf.write_status, 0, operation="!=")
status_written_images = CompareStatus(self.hdf.num_captured, self._n_images)
status_writer = st1 & st2 & status_written_images & st3
# Status Backend
status_backend = None
@@ -822,25 +834,18 @@ class Timepix(PSIDeviceBase, TimePixControl):
status_backend = self.backend.on_complete(status=status_backend)
# Combine the statuses
if status_backend is not None:
return_status = status_backend & status_camera & status_writer & st3
else:
return_status = status_camera & status_writer & st3
# We check the write_status if it goes to write error
# st3 = ExceptionStatus(self.hdf.write_status, 0, operation="!=")
return_status = status_backend & return_status
if status_writer is not None:
return_status = return_status & status_writer
# def _failed_to_write_callback(status, ret_status: AndStatus):
# if status.done and status.success:
# if not ret_status.done:
# ret_status.set_exception(f"Error while writing on {self.name}")
self.cancel_on_stop(st3)
# st3.add_callback(partial(_failed_to_write_callback, ret_status=return_status))
return_status.add_callback(self._complete_callback)
self.cancel_on_stop(return_status)
return return_status
def _complete_callback(self, status: CompareStatus) -> None:
"""Callback for when the device completes a scan."""
if self.hdf.enable.get() != 1: # TODO: Not sure if we should support disabled file writing.
return
if status.success:
self.file_event.put(
file_path=self._full_path, # pylint: disable:protected-access
@@ -12,7 +12,6 @@ hooks for all the relevant ophyd interface, 'on_stage',
from __future__ import annotations
import json
import signal
import socket
import threading
import time
@@ -239,6 +238,7 @@ class TimepixFlyBackend:
def on_destroy(self):
"""Hook for on_destroy logic."""
time_started = time.time()
self.timepix_fly_client.shutdown()
self._data_thread_shutdown_event.set()
if self._data_thread is not None and self._data_thread.is_alive():
@@ -255,6 +255,9 @@ class TimepixFlyBackend:
except Exception:
content = traceback.format_exc()
logger.error(f"Error closing socket server: {content}")
logger.info(
f"Timepix Fly backend destroyed and resources cleaned up after {time.time() - time_started:.3f} seconds."
)
def on_stop(self):
"""Hook for on_stop logic."""
@@ -270,16 +270,18 @@ class TimepixFlyClient:
continue
if status in success:
dev_status.set_finished()
logger.debug(f"Status callback finished in succes: {status.value}")
logger.debug(f"Status callback finished in success: {status.value}")
self._status_callbacks.pop(cb_id)
elif status in error:
try:
last_error = self.last_error()
raise TimePixStatusError(
f"TimePixFly Backend state '{status.value}' is in list of specified errors {error}. Last error message: {last_error.message}"
f"TimePixFly state '{status.value}': {last_error.message}"
)
except Exception as e:
logger.error(f"Error in status callback from TimepixFly Backend: {e}")
logger.error(
f"Error in status callback for '{status.value}' from TimepixFly backend: {e}"
)
dev_status.set_exception(e)
self._status_callbacks.pop(cb_id)
# Reset the _started flag if the status is in CONFIG.