From 5c2021e8affcf58e1f73a6161d2726eca97b47fa Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Fri, 27 Sep 2024 18:52:49 +0100 Subject: [PATCH] fix: make Frame2TTL validation more robust --- CHANGELOG.md | 4 +++ iblrig/__init__.py | 2 +- iblrig/gui/frame2ttl.py | 56 +++++++++++++++++------------------ iblrig/hardware_validation.py | 16 ++++++---- 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7193dfefe..451f27a27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Changelog ========= +8.24.2 +------ +* make Frame2TTL validation more robust + 8.24.1 ------ * change UI workflow for appending a session diff --git a/iblrig/__init__.py b/iblrig/__init__.py index 9fe8f1ff0..60f029c22 100644 --- a/iblrig/__init__.py +++ b/iblrig/__init__.py @@ -6,7 +6,7 @@ # 5) git tag the release in accordance to the version number below (after merge!) # >>> git tag 8.15.6 # >>> git push origin --tags -__version__ = '8.24.1' +__version__ = '8.24.2' from iblrig.version_management import get_detailed_version_string diff --git a/iblrig/gui/frame2ttl.py b/iblrig/gui/frame2ttl.py index 3ae7964f9..86bed34d7 100644 --- a/iblrig/gui/frame2ttl.py +++ b/iblrig/gui/frame2ttl.py @@ -1,11 +1,11 @@ import logging from datetime import date -from PyQt5 import QtCore, QtGui, QtTest, QtWidgets +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtCore import QTimer, pyqtProperty, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QWidget from iblrig.frame2ttl import Frame2TTL -from iblrig.gui.tools import Worker from iblrig.gui.ui_frame2ttl import Ui_frame2ttl from iblrig.path_helper import save_pydantic_yaml from iblrig.pydantic_definitions import HardwareSettings @@ -14,6 +14,9 @@ class Frame2TTLCalibrationDialog(QtWidgets.QDialog, Ui_frame2ttl): + _success: bool = False + _waitForScreen = 500 + def __init__(self, *args, hardware_settings: HardwareSettings, **kwargs) -> None: super().__init__(*args, **kwargs) self.setupUi(self) @@ -23,7 +26,6 @@ def __init__(self, *args, hardware_settings: HardwareSettings, **kwargs) -> None self.hardware_settings = hardware_settings self.frame2ttl = Frame2TTL(port=hardware_settings.device_frame2ttl.COM_F2TTL) - self.target = Frame2TTLCalibrationTarget(self, color=QtGui.QColorConstants.White) self.light = None self.dark = None self._success = True @@ -34,25 +36,22 @@ def __init__(self, *args, hardware_settings: HardwareSettings, **kwargs) -> None self.buttonBox.buttons()[0].setEnabled(False) self.show() - # start worker for first calibration step: light condition - worker = Worker(self.frame2ttl.calibrate, condition='light') - worker.signals.result.connect(self._on_calibrate_light_result) - QtCore.QThreadPool.globalInstance().tryStart(worker) + # start calibration of light value (use timer to allow for drawing of target) self.uiLabelLightValue.setText('calibrating ...') + self.target = Frame2TTLCalibrationTarget(self, color=QtGui.QColorConstants.White) + QTimer.singleShot(self._waitForScreen, self._calibrateLight) - def _on_calibrate_light_result(self, result: tuple[int, bool]): - (self.light, self._success) = result + def _calibrateLight(self): + self.light, self._success = self.frame2ttl.calibrate(condition='light') self.uiLabelLightValue.setText(f'{self.light} {self.frame2ttl.unit_str}') + self.target.setColor(QtGui.QColorConstants.Black) - # start worker for second calibration step: dark condition - self.target.color = QtGui.QColorConstants.Black - worker = Worker(self.frame2ttl.calibrate, condition='dark') - worker.signals.result.connect(self._on_calibrate_dark_result) - QtCore.QThreadPool.globalInstance().tryStart(worker) + # start calibration of dark value (use timer to allow for drawing of target) self.uiLabelDarkValue.setText('calibrating ...') + QTimer.singleShot(self._waitForScreen, self._calibrateDark) - def _on_calibrate_dark_result(self, result: tuple[int, bool]): - (self.dark, self._success) = result + def _calibrateDark(self): + self.dark, self._success = self.frame2ttl.calibrate(condition='dark') self.uiLabelDarkValue.setText(f'{self.dark} {self.frame2ttl.unit_str}') if self._success: @@ -69,6 +68,8 @@ def _on_calibrate_dark_result(self, result: tuple[int, bool]): class Frame2TTLCalibrationTarget(QtWidgets.QDialog): + colorChanged = pyqtSignal(QtGui.QColor) + def __init__( self, parent: QWidget | None = None, @@ -117,8 +118,6 @@ def __init__( super().__init__(parent, **kwargs) self.setWindowModality(QtCore.Qt.WindowModality.NonModal) self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Dialog) - self.setAutoFillBackground(True) - self._set_color(color) self.setFixedSize(width, height) screen_geometry = QtWidgets.QApplication.desktop().screenGeometry(screen_index) self.move( @@ -126,20 +125,21 @@ def __init__( screen_geometry.x() + screen_geometry.width() - width, screen_geometry.y() + screen_geometry.height() - height ) ) + self.setAutoFillBackground(True) self.show() - QtTest.QTest.qWait(500) + self.focusWidget() + self.setColor(color) - def _set_color(self, color: QtGui.QColor): - palette = QtGui.QPalette() + @pyqtSlot(QtGui.QColor) + def setColor(self, color: QtGui.QColor): + palette = self.palette() palette.setColor(QtGui.QPalette.Window, color) self.setPalette(palette) + self.repaint() + self.colorChanged.emit(color) + QtWidgets.QApplication.processEvents() - @property - def color(self) -> QtGui.QColor: + def getColor(self) -> QtGui.QColor: return self.palette().color(QtGui.QPalette.Window) - @color.setter - def color(self, color: QtGui.QColor): - self._set_color(color) - self.update() - QtTest.QTest.qWait(500) + color = pyqtProperty(QtGui.QColor, fget=getColor, fset=setColor) diff --git a/iblrig/hardware_validation.py b/iblrig/hardware_validation.py index c66aae593..39db21778 100644 --- a/iblrig/hardware_validation.py +++ b/iblrig/hardware_validation.py @@ -8,6 +8,7 @@ from inspect import isabstract from math import isclose from struct import unpack +from time import sleep from typing import Any, cast import numpy as np @@ -589,10 +590,12 @@ def _run(self): from iblrig.gui.frame2ttl import Frame2TTLCalibrationTarget app = QApplication.instance() - if app_created := app is None: + if app_created := (app is None): app = QApplication([]) + + # show calibration target calibration_target = Frame2TTLCalibrationTarget(color=QColorConstants.Black) - calibration_target.show() + sleep(0.1) # allow for screen to update # Define state-machine def softcode_handler(softcode: int): @@ -604,14 +607,14 @@ def softcode_handler(softcode: int): sma = StateMachine(bpod) sma.add_state( state_name='white', - state_timer=1, - state_change_conditions={'Tup': 'black', 'BNC1High': 'black'}, + state_timer=0.1, + state_change_conditions={'Tup': 'black'}, output_actions=[('SoftCode', 1)], ) sma.add_state( state_name='black', - state_timer=1, - state_change_conditions={'Tup': 'exit', 'BNC1Low': 'exit'}, + state_timer=0.1, + state_change_conditions={'Tup': 'exit'}, output_actions=[('SoftCode', 2)], ) @@ -626,6 +629,7 @@ def softcode_handler(softcode: int): return False finally: bpod.softcode_handler_function = original_softcode_handler + sleep(0.1) # allow state machine to finish calibration_target.close() if app_created: app.quit()