diff --git a/app_config.py b/app_config.py index 9ad70d4..9b3a7b2 100644 --- a/app_config.py +++ b/app_config.py @@ -9,11 +9,13 @@ import logging _log = logging.getLogger(__name__) from PyQt5.QtCore import QSettings -from PyQt5.QtWidgets import QApplication, QLineEdit +from PyQt5.QtWidgets import QApplication, QLineEdit, QWidget, QGridLayout, QLabel import json +import pyqtgraph as pg import numpy as np import GenericDialog +#from pyqtgraph.Qt import QtCore, QtGui class MyJsonEncoder(json.JSONEncoder): """ Special json encoder for numpy types """ @@ -31,6 +33,7 @@ class MyJsonEncoder(json.JSONEncoder): class AppCfg(QSettings): GBL_FLD_SCR_SHOT="global/folder_screenshot" + GBL_DEV_PREFIX="global/device_prefix" #SAR-EXPMX GEO_OPT_CTR='geometry/opt_ctr' GEO_PIX2POS='geometry/pix2pos' @@ -44,6 +47,11 @@ class AppCfg(QSettings): WINDOW_SPLITTER="window/splitter" WINDOW_STATE= "window/state" + DFT_POS_DET ="default_position/detector" #json + DFT_POS_PST ="default_position/post_sample_tube" #json + DFT_POS_COL ="default_position/collimator" #json + DFT_POS_BKLGT ="default_position/backlight" #json + PST_X_UP ="post_sample_tube/x_up" PST_Y_UP ="post_sample_tube/y_up" PST_X_DOWN="post_sample_tube/x_down" @@ -96,6 +104,11 @@ class AppCfg(QSettings): # print(k, self.value(k)) #set default keys if not existing + + if AppCfg.GBL_DEV_PREFIX not in keys: + _log.warning(f'{AppCfg.GBL_DEV_PREFIX} not defined. set default') + self.setValue(AppCfg.GBL_DEV_PREFIX, ['SAR-EXPMX','SARES30-ESBMX']) #prefix deltatau,smaract + if AppCfg.GEO_BEAM_SZ not in keys: _log.warning(f'{AppCfg.GEO_BEAM_SZ} not defined. set default') self.setValue(AppCfg.GEO_BEAM_SZ, [30.2, 25.6]) #([40, 20) -> tuples are not supported natively @@ -200,7 +213,6 @@ class AppCfg(QSettings): self.setValue(key, not v) self.sync() - #inst_folder = Path(__file__).absolute().parent #config_file = inst_folder / "swissmx.yaml" #configs = yaml.load(config_file.read_text(),Loader=yaml.FullLoader) @@ -410,3 +422,114 @@ class AppCfg(QSettings): settings.setValue(k, v) settings.sync() +# ---------------------------------------------- + +class WndParameter(): + def __init__(self,mainWnd): + from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType + params=[ + {'name':'Basic parameter data types', 'type':'group', 'children':[ + {'name':'Integer', 'type':'int', 'value':10}, + {'name':'Float', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'Subgroup', 'type':'group', 'children':[ + {'name':'Sub-param 1', 'type':'int', 'value':10}, + {'name':'Sub-param 2', 'type':'float', 'value':1.2e6}, + ]}, + ]}, + {'name':'geometry', 'type':'group', 'children':[ + {'name':'size of the beam', 'type':'group', 'children':[ + {'name':'width', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'height', 'type':'float', 'value':10.5, 'step':0.1}, + ]}, + ]}, + {'name':'post sample tube reference positions', 'type':'group', 'children':[ + {'name':'Up X', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'Up Y', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'Down X', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'Down Y', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'out delta X', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'out delta Y', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'tube Z in position', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'tube Z OUT position', 'type':'float', 'value':10.5, 'step':0.1}, + ]}, + {'name':'collimator reference positions', 'type':'group', 'children':[ + {'name':'in X', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'in Y', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'out deltaX', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'out deltaY', 'type':'float', 'value':10.5, 'step':0.1}, + ]}, + {'name':'Back Light reference positions', 'type':'group', 'children':[ + {'name':'In position', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'Out position', 'type':'float', 'value':0.0, 'step':0.1}, + ]}, + {'name':'Delta Tau Parameters', 'type':'group', 'children':[ + {'name':'host name (host[:port:port_gather])', 'type':'float', 'value':10.5, 'step':0.1}, + {'name':'show plots after collection', 'type':'bool', 'value':True, 'tip':"This is a checkbox"}, + ]}, + {'name':'Save/Restore functionality', 'type':'group', 'children':[ + {'name':'Save State', 'type':'action'}, + {'name':'Restore State', 'type':'action', 'children':[ + {'name':'Add missing items', 'type':'bool', 'value':True}, + {'name':'Remove extra items', 'type':'bool', 'value':True}, + ]}, + ]}, + ] + + self._p=p=Parameter.create(name='params', type='group', children=params) + p.sigTreeStateChanged.connect(lambda a,b: self.cb_change(a,b)) + # Too lazy for recursion: + for child in p.children(): + child.sigValueChanging.connect(lambda a,b: self.cb_valueChanging(a,b)) + for ch2 in child.children(): + ch2.sigValueChanging.connect(lambda a,b: self.cb_valueChanging(a,b)) + p.param('Save/Restore functionality', 'Save State').sigActivated.connect(self.cb_save) + p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(self.cb_restore) + + t=ParameterTree() + t.setParameters(p, showTop=False) + t.setWindowTitle('pyqtgraph example: Parameter Tree') + t.resize(400, 800) + self._wnd=t + + def cb_change(self,param, changes): + p=self._p + print("tree changes:") + for param, change, data in changes: + path=p.childPath(param) + if path is not None: + childName='.'.join(path) + else: + childName=param.name() + print(' parameter: %s'%childName) + print(' change: %s'%change) + print(' data: %s'%str(data)) + print(' ----------') + + def cb_valueChanging(self,param, value): + print("Value changing (not finalized): %s %s"%(param, value)) + + def cb_save(self): + self._state=p.saveState() + + def cb_restore(self): + add=p['Save/Restore functionality', 'Restore State', 'Add missing items'] + rem=p['Save/Restore functionality', 'Restore State', 'Remove extra items'] + p.restoreState(self._state, addChildren=add, removeChildren=rem) + + +## Start Qt event loop unless running in interactive mode or using pyside. +if __name__ == '__main__': + + import sys + + app=QApplication([]) + ## Create tree of Parameter objects + + cfg=AppCfg() + + w=WndParameter(None) + w._wnd.show() + + + if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + QApplication.instance().exec_() diff --git a/swissmx.py b/swissmx.py index 3c21317..7ac199d 100755 --- a/swissmx.py +++ b/swissmx.py @@ -598,6 +598,13 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): action.triggered.connect(cfg.dlg_deltatau_parameters) self.menuAdvanced.addAction(action) + action = QAction("parameters", self) + action.setToolTip("modify application parameters") + action.setStatusTip("modify application parameters") + action.triggered.connect(lambda x: cfg.dlg_parameters(self)) + + self.menuAdvanced.addAction(action) + #action = QAction("Cryojet Reference Positions", self) #action.setToolTip("Update the reference positions for the cryojet nozzle position") #action.setStatusTip("Update the reference positions for the cryojet nozzle position") @@ -887,32 +894,36 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): self._message_critical_fault.setText(msg) def build_group_faststage(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] qutilities.add_item_to_toolbox(toolbox,"Fast Stage", widget_list=[ - # self.get_tweaker('SAR-EXPMX:MOT_BLGT', alias='backlight', label='backlight'), - self.get_tweaker("SAR-EXPMX:MOT_FY", alias="fast_y", label="fast Y"), - self.get_tweaker("SAR-EXPMX:MOT_FX", alias="fast_x", label="fast X"), - self.get_tweaker("SAR-EXPMX:MOT_ROT_Y",alias="omega",label="omega",tweak_min=0.001,tweak_max=180.0,), - self.get_tweaker("SAR-EXPMX:MOT_CX", alias="base_x", label="base X"), - self.get_tweaker("SAR-EXPMX:MOT_CZ", alias="base_z", label="base Z"), + #self.get_tweaker('f"{pfx}:MOT_BLGT', alias='backlight', label='backlight'), + self.get_tweaker(f"{pfx}:MOT_FY", alias="fast_y", label="fast Y"), + self.get_tweaker(f"{pfx}:MOT_FX", alias="fast_x", label="fast X"), + self.get_tweaker(f"{pfx}:MOT_ROT_Y",alias="omega",label="omega",tweak_min=0.001,tweak_max=180.0,), + self.get_tweaker(f"{pfx}:MOT_CX", alias="base_x", label="base X"), + self.get_tweaker(f"{pfx}:MOT_CZ", alias="base_z", label="base Z"), + self.get_tweaker(f"{pfx}:MOT_DET_Z", alias="det_z", label="detector Z"), ], ) def build_group_collimator(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] qutilities.add_item_to_toolbox(toolbox,"Collimator", widget_list=[ - self.get_tweaker("SARES30-ESBMX1", alias="colli_x", label="colli X", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX2", alias="colli_y", label="colli Y", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}1", alias="colli_x", label="colli X", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}2", alias="colli_y", label="colli Y", mtype="smaract_motor",), ], ) def build_group_posttube(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] widgets = [ - self.get_tweaker("SARES30-ESBMX4", alias="tube_usx", label="upstream X", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX6", alias="tube_usy", label="upstream Y", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX5", alias="tube_dsx", label="downstream X", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX7", alias="tube_dsy", label="downstream Y", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX8", alias="tube_z", label="tube Z", mtype="smaract_motor"), + self.get_tweaker(f"{pfx}4", alias="tube_usx", label="upstream X", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}6", alias="tube_usy", label="upstream Y", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}5", alias="tube_dsx", label="downstream X", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}7", alias="tube_dsy", label="downstream Y", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}8", alias="tube_z", label="tube Z", mtype="smaract_motor"), ] c = QWidget() c.setLayout(QGridLayout()) @@ -937,12 +948,13 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): toolbox.addItem(block, label) def build_group_xeye(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] qutilities.add_item_to_toolbox( toolbox, "X-Ray Eye", widget_list=[ - self.get_tweaker("SARES30-ESBMX14", alias="xeye_x", label="X", mtype="smaract_motor"), - self.get_tweaker("SARES30-ESBMX15", alias="xeye_y", label="Y", mtype="smaract_motor"), + self.get_tweaker(f"{pfx}14", alias="xeye_x", label="X", mtype="smaract_motor"), + self.get_tweaker(f"{pfx}15", alias="xeye_y", label="Y", mtype="smaract_motor"), ], ) @@ -1516,8 +1528,9 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): self.close() def cb_deltatau_home_faststages(self): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] _log.warning("homing fast stages") - epics.PV("SAR-EXPMX1:ASYN.AOUT").put(b"enable plc 1") + epics.PV(f"{pfx}1:ASYN.AOUT").put(b"enable plc 1") def cb_testcode(self): try: @@ -2087,6 +2100,32 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): usy.move_rel(-tandem_twv) dsy.move_rel(-tandem_twv) + def move_detector(self, pos): + #SAR-EXPMX: MOT_DET_Z.VAL + app=QApplication.instance() + cfg=app._cfg + det_z = self.tweakers["det_z"] + if AppCfg.DFT_POS_DET not in cfg.allKeys(): + msg="detector default positions are not configured." + _log.warning(msg) + QMessageBox.warning(self, "configuration incomplete", msg) + return + + pos = cfg.value(AppCfg.DFT_POS_DET) + _log.info("moving collimator {} to X,Y = {:.3f}, {:.3f}".format(pos, x_pos, y_pos)) + + if pos == "out": + cy.move_abs(y_pos+dy, assert_position=True) + cx.move_abs(x_pos+dx, assert_position=True) + elif pos == "in": + cx.move_abs(x_pos, assert_position=True) + cy.move_abs(y_pos, assert_position=True) + elif pos == "ready": + cx.move_abs(x_pos, assert_position=True) + cy.move_abs(y_pos+dy, assert_position=True) + else: + raise ValueError("Collimator position *{}* is not known!!") + def move_collimator(self, pos): app=QApplication.instance() cfg=app._cfg @@ -2118,6 +2157,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): else: raise ValueError("Collimator position *{}* is not known!!") + # **************** OBSOLETE AND/OR OLD STUFF **************** @@ -2737,37 +2777,40 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): cx.move_abs(to_pos, assert_position=True) def _OLD_build_cryo_group(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] qutilities.add_item_to_toolbox( toolbox, "Cryojet", widget_list=[ - self.get_tweaker("SAR-EXPMX:MOT_CRYO", alias="cryo", label="cryo X") + self.get_tweaker(f"{pfx}:MOT_CRYO", alias="cryo", label="cryo X") ], ) def _OLD_build_wegde_group(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] qutilities.add_item_to_toolbox(toolbox,"Wedge Mover", widget_list=[ - self.get_tweaker("SAR-EXPMX:MOT_WEDGE1", alias="wedge_1", label="wedge_1"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGE2", alias="wedge_2", label="wedge_2"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGE3", alias="wedge_3", label="wedge_3"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGE4", alias="wedge_4", label="wedge_4"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGEX", alias="wedge_x", label="wedge_x"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGEY", alias="wedge_y", label="wedge_y"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGEA", alias="wedge_a", label="wedge_a"), - self.get_tweaker("SAR-EXPMX:MOT_WEDGEB", alias="wedge_b", label="wedge_b"), + self.get_tweaker(f"{pfx}:MOT_WEDGE1", alias="wedge_1", label="wedge_1"), + self.get_tweaker(f"{pfx}:MOT_WEDGE2", alias="wedge_2", label="wedge_2"), + self.get_tweaker(f"{pfx}:MOT_WEDGE3", alias="wedge_3", label="wedge_3"), + self.get_tweaker(f"{pfx}:MOT_WEDGE4", alias="wedge_4", label="wedge_4"), + self.get_tweaker(f"{pfx}:MOT_WEDGEX", alias="wedge_x", label="wedge_x"), + self.get_tweaker(f"{pfx}:MOT_WEDGEY", alias="wedge_y", label="wedge_y"), + self.get_tweaker(f"{pfx}:MOT_WEDGEA", alias="wedge_a", label="wedge_a"), + self.get_tweaker(f"{pfx}:MOT_WEDGEB", alias="wedge_b", label="wedge_b"), ], ) def _OLD_build_slits_group(self, toolbox): + pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] qutilities.add_item_to_toolbox( toolbox, "Slits", widget_list=[ - self.get_tweaker("SARES30-ESBMX10", alias="slit_right", label="left", mtype="smaract_motor", ), - self.get_tweaker("SARES30-ESBMX11", alias="slit_left", label="right", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX12", alias="slit_bottom", label="bottom", mtype="smaract_motor",), - self.get_tweaker("SARES30-ESBMX13",alias="slit_top",label="top",mtype="smaract_motor",), + self.get_tweaker(f"{pfx}10", alias="slit_right", label="left", mtype="smaract_motor", ), + self.get_tweaker(f"{pfx}11", alias="slit_left", label="right", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}12", alias="slit_bottom", label="bottom", mtype="smaract_motor",), + self.get_tweaker(f"{pfx}13",alias="slit_top",label="top",mtype="smaract_motor",), ], )