From f718b81e16b881a13e57c0046210f3ea90473742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Fri, 10 Jan 2025 18:38:14 +0100 Subject: [PATCH] [feat] gui sparc: if laser interlock is triggered, also blank the beam One of the most common reason for the laser interlock to be triggered is that the user opened the SPARC ATM cover. The inside of the ATM can receive X-rays caused by the e-beam. So, to be extra safe, also blank the e-beam whenever the laser interlock is triggered. --- src/odemis/gui/cont/acquisition/sparc_acq.py | 46 ++++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/odemis/gui/cont/acquisition/sparc_acq.py b/src/odemis/gui/cont/acquisition/sparc_acq.py index c33959fc37..68e16b53a9 100644 --- a/src/odemis/gui/cont/acquisition/sparc_acq.py +++ b/src/odemis/gui/cont/acquisition/sparc_acq.py @@ -67,6 +67,12 @@ def __init__(self, tab_data, tab_panel, streambar_controller): self._tab_panel = tab_panel self._streambar_controller = streambar_controller self._interlockTriggered = False # local/private bool to track interlock status + if self._main_data_model.ebeam and model.hasVA(self._main_data_model.ebeam, "blanker"): + # blanker state before interlock (to restore it when interlock is reset) + self._ebeam_blanker = self._main_data_model.ebeam.blanker + self._pre_interlock_blanker = self._ebeam_blanker.value + else: + self._ebeam_blanker = None if model.hasVA(self._main_data_model.light, "interlockTriggered"): # subscribe to the VA and initialize the warning status @@ -217,33 +223,45 @@ def on_change_file(self, evt): self.conf.fn_ptn, self.conf.fn_count = guess_pattern(new_name) logging.debug("Generated filename pattern '%s'", self.conf.fn_ptn) - def on_interlock_change(self, value): + def on_interlock_change(self, value: bool) -> None: """ If the connected interlock status changes, the label on the acquisition panel has to be updated. Either the status is not triggered and the notification label will not be visible or the status is triggered and the user is notified through the label. Update the label status through calling update_acquisition_time() without any arguments. - :param value (BooleanVA): current interlockTriggered VA value + :param value: current interlockTriggered VA value """ if value == self._interlockTriggered: # if the value did not change in respect to the previous value return - logging.warning(f"Interlock status changed from {not value} -> " - f"{value}") + logging.warning(f"Interlock status changed from {not value} -> {value}") if value: - popup.show_message(wx.GetApp().main_frame, - title="Laser safety", - message=f"Laser was suspended automatically due to interlock trigger.", - timeout=10.0, - level=logging.WARNING) + # The laser is connected electronically to the interlock, so nothing to do in software. + # For the e-beam (to protect the user from X-rays), we force the blanker on. + if self._ebeam_blanker: + self._pre_interlock_blanker = self._ebeam_blanker.value + self._ebeam_blanker.value = True + message = "Laser and e-beam were suspended automatically due to interlock trigger." + else: + message = "Laser was suspended automatically due to interlock trigger." else: - popup.show_message(wx.GetApp().main_frame, - title="Laser safety", - message=f"Laser interlock trigger is reset to normal.", - timeout=10.0, - level=logging.WARNING) + message = "Laser interlock trigger is reset to normal." + # Put back the e-beam blanker to its original state, but only if it is (still) forced + # on (otherwise, it's a sign that the user is manually handling it). + if self._ebeam_blanker and self._ebeam_blanker.value is True: + self._ebeam_blanker.value = self._pre_interlock_blanker + if self._pre_interlock_blanker is False: + message += " E-beam blanker disabled." + elif self._pre_interlock_blanker is None: # Automatic mode (= blanker active when not acquiring) + message += " E-beam blanker set back to automatic mode." + + popup.show_message(wx.GetApp().main_frame, + title="Laser safety", + message=message, + timeout=10.0, + level=logging.WARNING) self._interlockTriggered = value self.update_acquisition_time()