diff --git a/gui/control_main.py b/gui/control_main.py index 2995109e..4c4efce9 100644 --- a/gui/control_main.py +++ b/gui/control_main.py @@ -65,6 +65,7 @@ UserScreenDialog, CalculatorWindow ) +from gui.epics_signal import EpicsQObject from gui.widgets.log_widget import get_summary_widget from gui.raster import RasterCell, RasterGroup from gui.vector import VectorMarker, VectorWidget @@ -126,34 +127,7 @@ class ControlMain(QtWidgets.QMainWindow): # 1/13/15 - are these necessary? Signal = QtCore.Signal() refreshTreeSignal = QtCore.Signal() - serverMessageSignal = QtCore.Signal(str) - serverPopupMessageSignal = QtCore.Signal(str) - programStateSignal = QtCore.Signal(str) - pauseButtonStateSignal = QtCore.Signal(str) - - xrecRasterSignal = QtCore.Signal(str) - choochResultSignal = QtCore.Signal(str) - energyChangeSignal = QtCore.Signal(float) - mountedPinSignal = QtCore.Signal(int) - beamSizeSignal = QtCore.Signal(float) - controlMasterSignal = QtCore.Signal(int) - zebraArmStateSignal = QtCore.Signal(int) - govRobotSeReachSignal = QtCore.Signal(int) - govRobotSaReachSignal = QtCore.Signal(int) - govRobotDaReachSignal = QtCore.Signal(int) - govRobotBlReachSignal = QtCore.Signal(int) - detMessageSignal = QtCore.Signal(str) - sampleFluxSignal = QtCore.Signal(float) - zebraPulseStateSignal = QtCore.Signal(int) - stillModeStateSignal = QtCore.Signal(int) - zebraDownloadStateSignal = QtCore.Signal(int) - zebraSentTriggerStateSignal = QtCore.Signal(int) - zebraReturnedTriggerStateSignal = QtCore.Signal(int) - fastShutterSignal = QtCore.Signal(float) - gripTempSignal = QtCore.Signal(float) - ringCurrentSignal = QtCore.Signal(float) - threeClickSignal = QtCore.Signal(str) - sampleExposedSignal = QtCore.Signal(float) + sampMoveSignal = QtCore.Signal(int, str) roiChangeSignal = QtCore.Signal(int, str) highMagCursorChangeSignal = QtCore.Signal(int, str) @@ -190,7 +164,9 @@ def __init__(self): self.zoom2FrameRatePV = PV(daq_utils.pvLookupDict["zoom2FrameRate"]) self.zoom3FrameRatePV = PV(daq_utils.pvLookupDict["zoom3FrameRate"]) self.zoom4FrameRatePV = PV(daq_utils.pvLookupDict["zoom4FrameRate"]) - self.sampleFluxPV = PV(daq_utils.pvLookupDict["sampleFlux"]) + self.sampleFluxPV = EpicsQObject( + daq_utils.pvLookupDict["sampleFlux"], self.processSampleFlux + ) self.beamFlux_pv = PV(daq_utils.pvLookupDict["flux"]) self.stillMode_pv = PV(daq_utils.pvLookupDict["stillMode"]) self.standardMode_pv = PV(daq_utils.pvLookupDict["standardMode"]) @@ -199,20 +175,32 @@ def __init__(self): self.highMagCursorX_pv = PV(daq_utils.pvLookupDict["highMagCursorX"]) self.highMagCursorY_pv = PV(daq_utils.pvLookupDict["highMagCursorY"]) self.fastShutterOpenPos_pv = PV(daq_utils.pvLookupDict["fastShutterOpenPos"]) - self.gripTemp_pv = PV(daq_utils.pvLookupDict["gripTemp"]) + self.gripTemp_pv = EpicsQObject( + daq_utils.pvLookupDict["gripTemp"], self.processGripTemp + ) if getBlConfig(CRYOSTREAM_ONLINE): - self.cryostreamTemp_pv = PV(cryostreamTempPV[daq_utils.beamline]) + self.cryostreamTemp_pv = EpicsQObject( + cryostreamTempPV[daq_utils.beamline], self.processCryostreamTemp + ) if daq_utils.beamline == "fmx": - self.slit1XGapSP_pv = PV(daq_utils.motor_dict["slit1XGap"] + ".VAL") - self.slit1YGapSP_pv = PV(daq_utils.motor_dict["slit1YGap"] + ".VAL") + self.slit1XGapSP_pv = PV(f"{daq_utils.motor_dict['slit1XGap']}.VAL") + self.slit1YGapSP_pv = PV(f"{daq_utils.motor_dict['slit1YGap']}.VAL") ringCurrentPvName = "SR:C03-BI{DCCT:1}I:Real-I" - self.ringCurrent_pv = PV(ringCurrentPvName) + self.ringCurrent_pv = EpicsQObject(ringCurrentPvName, self.processRingCurrent) - self.beamAvailable_pv = PV(daq_utils.pvLookupDict["beamAvailable"]) - self.sampleExposed_pv = PV(daq_utils.pvLookupDict["exposing"]) + self.beamAvailable_pv = EpicsQObject( + daq_utils.pvLookupDict["beamAvailable"], self.processBeamAvailable + ) + self.sampleExposed_pv = EpicsQObject( + daq_utils.pvLookupDict["exposing"], self.processSampleExposed + ) - self.beamSize_pv = PV(daq_utils.beamlineComm + "size_mode") - self.energy_pv = PV(daq_utils.motor_dict["energy"] + ".RBV") + self.beamSize_pv = EpicsQObject( + daq_utils.beamlineComm + "size_mode", self.processBeamSize + ) + self.energy_pv = EpicsQObject( + f"{daq_utils.motor_dict['energy']}.RBV", self.processEnergyChange + ) self.rasterStepDefs = {"Coarse": 20.0, "Fine": 10.0, "VFine": 5.0} # Timer that waits for a second before calling raddose 3d @@ -2147,6 +2135,8 @@ def clearEnScanPlotCB(self): self.choochGraph.removeCurves() def displayXrecRaster(self, xrecRasterFlag): + if xrecRasterFlag == "0": + return self.xrecRasterFlag_pv.put("0") if xrecRasterFlag == "100": for i in range(len(self.rasterList)): @@ -4709,9 +4699,6 @@ def stopQueueCB(self): def mountSampleCB(self): - - - if getBlConfig("mountEnabled") == 0: self.popupServerMessage("Mounting disabled!! Call staff!") return @@ -4993,104 +4980,6 @@ def row_clicked( ) self.refreshCollectionParams(self.selectedSampleRequest) - def processXrecRasterCB(self, value=None, char_value=None, **kw): - xrecFlag = value - if xrecFlag != "0": - self.xrecRasterSignal.emit(xrecFlag) - - def processChoochResultsCB(self, value=None, char_value=None, **kw): - choochFlag = value - if choochFlag != "0": - self.choochResultSignal.emit(choochFlag) - - def processEnergyChangeCB(self, value=None, char_value=None, **kw): - energyVal = value - self.energyChangeSignal.emit(energyVal) - - def mountedPinChangedCB(self, value=None, char_value=None, **kw): - mountedPinPos = value - self.mountedPinSignal.emit(mountedPinPos) - - def beamSizeChangedCB(self, value=None, char_value=None, **kw): - beamSizeFlag = value - self.beamSizeSignal.emit(beamSizeFlag) - - def controlMasterChangedCB(self, value=None, char_value=None, **kw): - controlMasterPID = value - self.controlMasterSignal.emit(controlMasterPID) - - def zebraArmStateChangedCB(self, value=None, char_value=None, **kw): - armState = value - self.zebraArmStateSignal.emit(armState) - - def govRobotSeReachChangedCB(self, value=None, char_value=None, **kw): - armState = value - self.govRobotSeReachSignal.emit(armState) - - def govRobotSaReachChangedCB(self, value=None, char_value=None, **kw): - armState = value - self.govRobotSaReachSignal.emit(armState) - - def govRobotDaReachChangedCB(self, value=None, char_value=None, **kw): - armState = value - self.govRobotDaReachSignal.emit(armState) - - def govRobotBlReachChangedCB(self, value=None, char_value=None, **kw): - armState = value - self.govRobotBlReachSignal.emit(armState) - - def detMessageChangedCB(self, value=None, char_value=None, **kw): - state = char_value - self.detMessageSignal.emit(state) - - def sampleFluxChangedCB(self, value=None, char_value=None, **kw): - state = value - self.sampleFluxSignal.emit(state) - - def zebraPulseStateChangedCB(self, value=None, char_value=None, **kw): - state = value - self.zebraPulseStateSignal.emit(state) - - def stillModeStateChangedCB(self, value=None, char_value=None, **kw): - state = value - self.stillModeStateSignal.emit(state) - - def zebraDownloadStateChangedCB(self, value=None, char_value=None, **kw): - state = value - self.zebraDownloadStateSignal.emit(state) - - def zebraSentTriggerStateChangedCB(self, value=None, char_value=None, **kw): - state = value - self.zebraSentTriggerStateSignal.emit(state) - - def zebraReturnedTriggerStateChangedCB(self, value=None, char_value=None, **kw): - state = value - self.zebraReturnedTriggerStateSignal.emit(state) - - def shutterChangedCB(self, value=None, char_value=None, **kw): - shutterVal = value - self.fastShutterSignal.emit(shutterVal) - - def gripTempChangedCB(self, value=None, char_value=None, **kw): - gripVal = value - self.gripTempSignal.emit(gripVal) - - def cryostreamTempChangedCB(self, value=None, char_value=None, **kw): - cryostreamTemp = value - self.cryostreamTempSignal.emit(cryostreamTemp) - - def ringCurrentChangedCB(self, value=None, char_value=None, **kw): - ringCurrentVal = value - self.ringCurrentSignal.emit(ringCurrentVal) - - def beamAvailableChangedCB(self, value=None, char_value=None, **kw): - threeClickVal = value - self.threeClickSignal.emit(threeClickVal) - - def sampleExposedChangedCB(self, value=None, char_value=None, **kw): - sampleExposedVal = value - self.sampleExposedSignal.emit(sampleExposedVal) - def processSampMoveCB(self, value=None, char_value=None, **kw): posRBV = value motID = kw["motID"] @@ -5115,41 +5004,13 @@ def treeChangedCB(self, value=None, char_value=None, **kw): if self.processID != self.treeChanged_pv.get(): self.refreshTreeSignal.emit() - def serverMessageCB(self, value=None, char_value=None, **kw): - serverMessageVar = char_value - self.serverMessageSignal.emit(serverMessageVar) - - def serverPopupMessageCB(self, value=None, char_value=None, **kw): - serverMessageVar = char_value - self.serverPopupMessageSignal.emit(serverMessageVar) - - def programStateCB(self, value=None, char_value=None, **kw): - programStateVar = value - self.programStateSignal.emit(programStateVar) - - def pauseButtonStateCB(self, value=None, char_value=None, **kw): - pauseButtonStateVar = value - self.pauseButtonStateSignal.emit(pauseButtonStateVar) - - def initOphyd(self): - if daq_utils.beamline == "nyx": - # initialize devices - self.gon = GonioDevice("XF:19IDC-ES{MD2}:", name="gonio") - self.camera = CameraDevice("XF:19IDC-ES{MD2}:", name="camera") - self.md2 = MD2Device("XF:19IDC-ES{MD2}:", name="md2") - self.front_light = LightDevice("XF:19IDC-ES{MD2}:Front", name="front_light") - self.back_light = LightDevice("XF:19IDC-ES{MD2}:Back", name="back_light") - self.aperture = MD2ApertureDevice("XF:19IDC-ES{MD2}:", name="aperture") - elif daq_utils.beamline == "amx": - self.gon = GonioDevice("XF:17IDB-ES:AMX{Gon:1", name="gonio") - elif daq_utils.beamline == "fmx": - self.gon = GonioDevice("XF:17IDC-ES:FMX{Gon:1", name="gonio") - def initUI(self): self.tabs = QtWidgets.QTabWidget() self.comm_pv = PV(daq_utils.beamlineComm + "command_s") self.immediate_comm_pv = PV(daq_utils.beamlineComm + "immediate_command_s") - self.stillModeStatePV = PV(daq_utils.pvLookupDict["stillModeStatus"]) + self.stillModeStatePV = EpicsQObject( + daq_utils.pvLookupDict["stillModeStatus"], self.processStillModeState + ) self.progressDialog = QtWidgets.QProgressDialog() self.progressDialog.setCancelButtonText("Cancel") self.progressDialog.setModal(False) @@ -5212,68 +5073,52 @@ def initUI(self): fileMenu.addAction(self.staffAction) fileMenu.addAction(self.resolutionAction) # Define all of the available actions for the overlay color group - self.BlueOverlayAction = QtWidgets.QAction("Blue", self, checkable=True) - self.RedOverlayAction = QtWidgets.QAction("Red", self, checkable=True) - self.GreenOverlayAction = QtWidgets.QAction("Green", self, checkable=True) - self.WhiteOverlayAction = QtWidgets.QAction("White", self, checkable=True) - self.BlackOverlayAction = QtWidgets.QAction("Black", self, checkable=True) - # Connect all of the trigger callbacks to their respective actions - self.BlueOverlayAction.triggered.connect(self.blueOverlayTriggeredCB) - self.RedOverlayAction.triggered.connect(self.redOverlayTriggeredCB) - self.GreenOverlayAction.triggered.connect(self.greenOverlayTriggeredCB) - self.WhiteOverlayAction.triggered.connect(self.whiteOverlayTriggeredCB) - self.BlackOverlayAction.triggered.connect(self.blackOverlayTriggeredCB) + color_names = ["Blue", "Red", "Green", "White", "Black"] + qt_colors = [ + QtCore.Qt.GlobalColor.blue, + QtCore.Qt.GlobalColor.red, + QtCore.Qt.GlobalColor.green, + QtCore.Qt.GlobalColor.white, + QtCore.Qt.GlobalColor.black, + ] + self.overlay_actions = { + color.upper(): QtWidgets.QAction(color, self, checkable=True) + for color in color_names + } + colors = { + color_name.upper(): qt_color + for color_name, qt_color in zip(color_names, qt_colors) + } + # Create the action group and populate it self.overlayColorActionGroup = QtWidgets.QActionGroup(self) self.overlayColorActionGroup.setExclusive(True) - self.overlayColorActionGroup.addAction(self.BlueOverlayAction) - self.overlayColorActionGroup.addAction(self.RedOverlayAction) - self.overlayColorActionGroup.addAction(self.GreenOverlayAction) - self.overlayColorActionGroup.addAction(self.WhiteOverlayAction) - self.overlayColorActionGroup.addAction(self.BlackOverlayAction) + + # Connect all of the trigger callbacks to their respective actions + for color_name, action in self.overlay_actions.items(): + color = colors[color_name] + action.triggered.connect( + lambda _, color=color: self.colorOverlayTriggeredCB(color) + ) + self.overlayColorActionGroup.addAction(action) + # Create the menu item with the submenu, add the group self.overlayMenu = settingsMenu.addMenu("Overlay Settings") self.overlayMenu.addActions(self.overlayColorActionGroup.actions()) try: - if getBlConfig("defaultOverlayColor") == "GREEN": - self.GreenOverlayAction.setChecked(True) - else: - self.BlueOverlayAction.setChecked(True) + action = self.overlay_actions[getBlConfig("defaultOverlayColor")] + action.setChecked(True) except KeyError as e: logger.warning("No value for defaultOverlayColor") - self.BlueOverlayAction.setChecked(True) + self.overlay_actions["BLUE"].setChecked(True) fileMenu.addAction(exitAction) self.setGeometry(300, 300, 1550, 1000) # width and height here. self.setWindowTitle("LSDC on %s" % daq_utils.beamline) self.show() - def blueOverlayTriggeredCB(self): - overlayBrush = QtGui.QBrush(QtCore.Qt.blue) - self.centerMarker.setBrush(overlayBrush) - self.imageScale.setPen(QtGui.QPen(overlayBrush, 2.0)) - self.imageScaleText.setPen(QtGui.QPen(overlayBrush, 1.0)) - - def redOverlayTriggeredCB(self): - overlayBrush = QtGui.QBrush(QtCore.Qt.red) - self.centerMarker.setBrush(overlayBrush) - self.imageScale.setPen(QtGui.QPen(overlayBrush, 2.0)) - self.imageScaleText.setPen(QtGui.QPen(overlayBrush, 1.0)) - - def greenOverlayTriggeredCB(self): - overlayBrush = QtGui.QBrush(QtCore.Qt.green) - self.centerMarker.setBrush(overlayBrush) - self.imageScale.setPen(QtGui.QPen(overlayBrush, 2.0)) - self.imageScaleText.setPen(QtGui.QPen(overlayBrush, 1.0)) - - def whiteOverlayTriggeredCB(self): - overlayBrush = QtGui.QBrush(QtCore.Qt.white) - self.centerMarker.setBrush(overlayBrush) - self.imageScale.setPen(QtGui.QPen(overlayBrush, 2.0)) - self.imageScaleText.setPen(QtGui.QPen(overlayBrush, 1.0)) - - def blackOverlayTriggeredCB(self): - overlayBrush = QtGui.QBrush(QtCore.Qt.black) + def colorOverlayTriggeredCB(self, color): + overlayBrush = QtGui.QBrush(color) self.centerMarker.setBrush(overlayBrush) self.imageScale.setPen(QtGui.QPen(overlayBrush, 2.0)) self.imageScaleText.setPen(QtGui.QPen(overlayBrush, 1.0)) @@ -5292,15 +5137,13 @@ def closeAll(self): QtWidgets.QApplication.instance().quit() def initCallbacks(self): - self.beamSizeSignal.connect(self.processBeamSize) - self.beamSize_pv.add_callback(self.beamSizeChangedCB) - self.treeChanged_pv = PV(daq_utils.beamlineComm + "live_q_change_flag") self.refreshTreeSignal.connect(self.dewarTree.refreshTreeThreaded) self.treeChanged_pv.add_callback(self.treeChangedCB) - self.mountedPin_pv = custom_pv.MountedPinPV(daq_utils.beamlineComm + "mounted_pin") - self.mountedPinSignal.connect(self.processMountedPin) - self.mountedPin_pv.add_callback(self.mountedPinChangedCB) + self.mountedPin_pv = EpicsQObject( + daq_utils.beamlineComm + "mounted_pin", self.processMountedPin, + custom_pv=custom_pv.MountedPinPV + ) det_stop_pv = daq_utils.pvLookupDict["stopEiger"] logger.info("setting stop Eiger detector PV: %s" % det_stop_pv) self.stopDet_pv = PV(det_stop_pv) @@ -5313,104 +5156,92 @@ def initCallbacks(self): rz_reboot_pv = daq_utils.pvLookupDict["zebraRebootIOC"] logger.info("setting zebra reboot ioc PV: %s" % rz_reboot_pv) self.rebootZebraIOC_pv = PV(rz_reboot_pv) - self.zebraArmedPV = PV(daq_utils.pvLookupDict["zebraArmStatus"]) - self.zebraArmStateSignal.connect(self.processZebraArmState) - self.zebraArmedPV.add_callback(self.zebraArmStateChangedCB) - - self.govRobotSeReachPV = PV(daq_utils.pvLookupDict["govRobotSeReach"]) - self.govRobotSeReachSignal.connect(self.processGovRobotSeReach) - self.govRobotSeReachPV.add_callback(self.govRobotSeReachChangedCB) - - self.govRobotSaReachPV = PV(daq_utils.pvLookupDict["govRobotSaReach"]) - self.govRobotSaReachSignal.connect(self.processGovRobotSaReach) - self.govRobotSaReachPV.add_callback(self.govRobotSaReachChangedCB) - - self.govRobotDaReachPV = PV(daq_utils.pvLookupDict["govRobotDaReach"]) - self.govRobotDaReachSignal.connect(self.processGovRobotDaReach) - self.govRobotDaReachPV.add_callback(self.govRobotDaReachChangedCB) - - self.govRobotBlReachPV = PV(daq_utils.pvLookupDict["govRobotBlReach"]) - self.govRobotBlReachSignal.connect(self.processGovRobotBlReach) - self.govRobotBlReachPV.add_callback(self.govRobotBlReachChangedCB) - - self.detectorMessagePV = PV(daq_utils.pvLookupDict["eigerStatMessage"]) - self.detMessageSignal.connect(self.processDetMessage) - self.detectorMessagePV.add_callback(self.detMessageChangedCB) - - self.sampleFluxSignal.connect(self.processSampleFlux) - self.sampleFluxPV.add_callback(self.sampleFluxChangedCB) + self.zebraArmedPV = EpicsQObject( + daq_utils.pvLookupDict["zebraArmStatus"], self.processZebraArmState + ) + self.govRobotSeReachPV = EpicsQObject( + daq_utils.pvLookupDict["govRobotSeReach"], self.processGovRobotSeReach + ) - self.stillModeStateSignal.connect(self.processStillModeState) - self.stillModeStatePV.add_callback(self.stillModeStateChangedCB) + self.govRobotSaReachPV = EpicsQObject( + daq_utils.pvLookupDict["govRobotSaReach"], self.processGovRobotSaReach + ) - self.zebraPulsePV = PV(daq_utils.pvLookupDict["zebraPulseStatus"]) - self.zebraPulseStateSignal.connect(self.processZebraPulseState) - self.zebraPulsePV.add_callback(self.zebraPulseStateChangedCB) + self.govRobotDaReachPV = EpicsQObject( + daq_utils.pvLookupDict["govRobotDaReach"], self.processGovRobotDaReach + ) - self.zebraDownloadPV = PV(daq_utils.pvLookupDict["zebraDownloading"]) - self.zebraDownloadStateSignal.connect(self.processZebraDownloadState) - self.zebraDownloadPV.add_callback(self.zebraDownloadStateChangedCB) + self.govRobotBlReachPV = EpicsQObject( + daq_utils.pvLookupDict["govRobotBlReach"], self.processGovRobotBlReach + ) - self.zebraSentTriggerPV = PV(daq_utils.pvLookupDict["zebraSentTriggerStatus"]) - self.zebraSentTriggerStateSignal.connect(self.processZebraSentTriggerState) - self.zebraSentTriggerPV.add_callback(self.zebraSentTriggerStateChangedCB) + self.detectorMessagePV = EpicsQObject( + daq_utils.pvLookupDict["eigerStatMessage"], self.processDetMessage + ) - self.zebraReturnedTriggerPV = PV( - daq_utils.pvLookupDict["zebraTriggerReturnStatus"] + self.zebraPulsePV = EpicsQObject( + daq_utils.pvLookupDict["zebraPulseStatus"], self.processZebraPulseState ) - self.zebraReturnedTriggerStateSignal.connect( - self.processZebraReturnedTriggerState + + self.zebraDownloadPV = EpicsQObject( + daq_utils.pvLookupDict["zebraDownloading"], self.processZebraDownloadState ) - self.zebraReturnedTriggerPV.add_callback( - self.zebraReturnedTriggerStateChangedCB + + self.zebraSentTriggerPV = EpicsQObject( + daq_utils.pvLookupDict["zebraSentTriggerStatus"], + self.processZebraSentTriggerState, ) - self.controlMaster_pv = PV(daq_utils.beamlineComm + "zinger_flag") - self.controlMasterSignal.connect(self.processControlMaster) - self.controlMaster_pv.add_callback(self.controlMasterChangedCB) + self.zebraReturnedTriggerPV = EpicsQObject( + daq_utils.pvLookupDict["zebraTriggerReturnStatus"], + self.processZebraReturnedTriggerState, + ) + self.controlMaster_pv = EpicsQObject( + f"{daq_utils.beamlineComm}zinger_flag", self.processControlMaster + ) self.beamCenterX_pv = PV(daq_utils.pvLookupDict["beamCenterX"]) self.beamCenterY_pv = PV(daq_utils.pvLookupDict["beamCenterY"]) - self.choochResultFlag_pv = PV(daq_utils.beamlineComm + "choochResultFlag") - self.choochResultSignal.connect(self.processChoochResult) - self.choochResultFlag_pv.add_callback(self.processChoochResultsCB) - self.xrecRasterFlag_pv = PV(daq_utils.beamlineComm + "xrecRasterFlag") - self.xrecRasterFlag_pv.put("0") - self.xrecRasterSignal.connect(self.displayXrecRaster) - self.xrecRasterFlag_pv.add_callback(self.processXrecRasterCB) - self.message_string_pv = PV(daq_utils.beamlineComm + "message_string") - self.serverMessageSignal.connect(self.printServerMessage) - self.message_string_pv.add_callback(self.serverMessageCB) - self.popup_message_string_pv = PV( - daq_utils.beamlineComm + "gui_popup_message_string" + self.choochResultFlag_pv = EpicsQObject( + f"{daq_utils.beamlineComm}choochResultFlag", self.processChoochResult + ) + self.xrecRasterFlag_pv = EpicsQObject( + f"{daq_utils.beamlineComm}xrecRasterFlag", + self.displayXrecRaster, + use_string=True, + ) + self.message_string_pv = EpicsQObject( + f"{daq_utils.beamlineComm}message_string", + self.printServerMessage, + use_string=True, ) - self.serverPopupMessageSignal.connect(self.popupServerMessage) - self.popup_message_string_pv.add_callback(self.serverPopupMessageCB) - self.program_state_pv = PV(daq_utils.beamlineComm + "program_state") - self.programStateSignal.connect(self.colorProgramState) - self.program_state_pv.add_callback(self.programStateCB) - self.pause_button_state_pv = PV(daq_utils.beamlineComm + "pause_button_state") - self.pauseButtonStateSignal.connect(self.changePauseButtonState) - self.pause_button_state_pv.add_callback(self.pauseButtonStateCB) - - self.energyChangeSignal.connect(self.processEnergyChange) - self.energy_pv.add_callback(self.processEnergyChangeCB, motID="x") - - self.sampx_pv = PV(self.gon.x.readback.pvname) + self.popup_message_string_pv = EpicsQObject( + f"{daq_utils.beamlineComm}gui_popup_message_string", + self.popupServerMessage, + use_string=True, + ) + self.program_state_pv = EpicsQObject( + f"{daq_utils.beamlineComm}program_state", self.colorProgramState + ) + self.pause_button_state_pv = EpicsQObject( + f"{daq_utils.beamlineComm}pause_button_state", self.changePauseButtonState + ) + + self.sampx_pv = PV(f"{daq_utils.motor_dict['sampleX']}.RBV") self.sampMoveSignal.connect(self.processSampMove) self.sampx_pv.add_callback(self.processSampMoveCB, motID="x") - self.sampy_pv = PV(self.gon.y.readback.pvname) + self.sampy_pv = PV(f"{daq_utils.motor_dict['sampleY']}.RBV") self.sampy_pv.add_callback(self.processSampMoveCB, motID="y") - self.sampz_pv = PV(self.gon.z.readback.pvname) + self.sampz_pv = PV(f"{daq_utils.motor_dict['sampleZ']}.RBV") self.sampz_pv.add_callback(self.processSampMoveCB, motID="z") if self.scannerType == "PI": - self.sampFineX_pv = PV(daq_utils.motor_dict["fineX"] + ".RBV") + self.sampFineX_pv = PV(f"{daq_utils.motor_dict['fineX']}.RBV") self.sampFineX_pv.add_callback(self.processSampMoveCB, motID="fineX") - self.sampFineY_pv = PV(daq_utils.motor_dict["fineY"] + ".RBV") + self.sampFineY_pv = PV(f"{daq_utils.motor_dict['fineY']}.RBV") self.sampFineY_pv.add_callback(self.processSampMoveCB, motID="fineY") - self.sampFineZ_pv = PV(daq_utils.motor_dict["fineZ"] + ".RBV") + self.sampFineZ_pv = PV(f"{daq_utils.motor_dict['fineZ']}.RBV") self.sampFineZ_pv.add_callback(self.processSampMoveCB, motID="fineZ") self.omega_pv = PV(self.gon.omega.setpoint.pvname) @@ -5426,20 +5257,9 @@ def initCallbacks(self): ) # I think monitoring this allows for the textfield to monitor val and this to deal with the graphics. Else next line has two callbacks on same thing. self.photonShutterOpen_pv = PV(daq_utils.pvLookupDict["photonShutterOpen"]) self.photonShutterClose_pv = PV(daq_utils.pvLookupDict["photonShutterClose"]) - self.fastShutterRBV_pv = PV(daq_utils.motor_dict["fastShutter"] + ".RBV") - self.fastShutterSignal.connect(self.processFastShutter) - self.fastShutterRBV_pv.add_callback(self.shutterChangedCB) - self.gripTempSignal.connect(self.processGripTemp) - self.gripTemp_pv.add_callback(self.gripTempChangedCB) - if getBlConfig(CRYOSTREAM_ONLINE): - self.cryostreamTempSignal.connect(self.processCryostreamTemp) - self.cryostreamTemp_pv.add_callback(self.cryostreamTempChangedCB) - self.ringCurrentSignal.connect(self.processRingCurrent) - self.ringCurrent_pv.add_callback(self.ringCurrentChangedCB) - self.threeClickSignal.connect(self.processThreeClickCentering) - self.beamAvailable_pv.add_callback(self.beamAvailableChangedCB) - self.sampleExposedSignal.connect(self.processSampleExposed) - self.sampleExposed_pv.add_callback(self.sampleExposedChangedCB) + self.fastShutterRBV_pv = EpicsQObject( + f"{daq_utils.motor_dict['fastShutter']}.RBV", self.processFastShutter + ) self.highMagCursorChangeSignal.connect(self.processHighMagCursorChange) self.highMagCursorX_pv.add_callback(self.processHighMagCursorChangeCB, ID="x") self.highMagCursorY_pv.add_callback(self.processHighMagCursorChangeCB, ID="y") diff --git a/gui/epics_signal.py b/gui/epics_signal.py new file mode 100644 index 00000000..10ae60eb --- /dev/null +++ b/gui/epics_signal.py @@ -0,0 +1,43 @@ +from qtpy.QtCore import Signal, QObject +from epics import PV +from typing import Optional, Type + +class EpicsQObject(QObject): + """ + Class to simplify the process of triggering a qt signal based on an epics PV + Previously there were multiple unique signals defined and their corresponding callbacks + But their code is not unique. This class attempts to reduce the noise + """ + + # Define the PyQt signal + epics_pv_changed = Signal(object) + + def __init__(self, pv_name, qt_callback, use_string=False, pv_callback=None, + custom_pv: Optional[Type[PV]]=None): + super().__init__() + self.use_string = use_string + # Define the pyepics PV and its callback + if not pv_callback: + pv_callback = self.on_pv_changed + + EpicsPV: Type[PV] = PV if custom_pv is None else custom_pv + + if not issubclass(EpicsPV, PV): + raise TypeError("custom_pv must be a PV class or a subclass of PV") + + self.pv = EpicsPV(pv_name, callback=pv_callback, auto_monitor=True) + self.epics_pv_changed.connect(qt_callback) + + # Define the callback for the pyepics PV + def on_pv_changed(self, value, char_value, **kwargs): + # Emit the PyQt signal + if self.use_string: + self.epics_pv_changed.emit(char_value) + else: + self.epics_pv_changed.emit(value) + + def get(self): + return self.pv.get() + + def put(self, *args, **kwargs): + self.pv.put(*args, **kwargs)