diff --git a/Readme.md b/Readme.md index d8b0e3a..3d4c00b 100644 --- a/Readme.md +++ b/Readme.md @@ -291,17 +291,44 @@ bt Localize mionitors and callbacks: ``` -grep -n 'def cb_update_img(self):' *.py +grep -Rn 'add_callback' *.py swissmx.py:698: self.sigNewCamImg.connect(self.cb_update_img) swissmx.py:745: def cb_update_img(self): +epics_widgets/MotorTweak.py:88: m.set_callback('RBV', self.emit_signals, {'source_field': 'RBV'}) +epics_widgets/SmaractMotorTweak.py:100: self._pv_readback.add_callback(self.update_label) +swissmx.py:717: cam.run(self.cb_new_frame_pv) +swissmx.py:743: self.sigNewCamImg.emit() +swissmx.py:745: def cb_update_img(self): +swissmx.py:698: self.sigNewCamImg.connect(self.cb_update_img) +camera.py:159: self._pv['pic'] = epics.PV(self._prefix + "FPICTURE", auto_monitor=True, callback=cb) +-> try to turn of the monitors during ascuisition: +zamofing_t@ganymede:~/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX$ +grep -r set_callback * + +https://pyepics.github.io/pyepics/pv.html#automatic-monitoring-of-a-pv + + +Try with: +pv.clear_auto_monitor() -> pv.reconnect() + +pv.remove_callback(index=None) -> pv.add_callback(callback=None[, index=None [, with_ctrlvars=True[, **kw]]) +pv.set_callback + +FixTargetFrame -> paint -> _log.debug() + + +Turn off jungfrau. +no motion -> wait 1h +constant up-dow motion code -> wait 1h ``` + try: #pv-monitor-func ----------------------------------- SCRATCH ----------------------------------- diff --git a/epics_widgets/SmaractMotorTweak.py b/epics_widgets/SmaractMotorTweak.py deleted file mode 100644 index 2ea597a..0000000 --- a/epics_widgets/SmaractMotorTweak.py +++ /dev/null @@ -1,341 +0,0 @@ -import math -import logging -from time import sleep -from PyQt5.QtCore import Qt, pyqtSignal -from PyQt5.QtGui import QPainter, QBrush, QColor, QPainterPath, QPen, QDoubleValidator -from PyQt5.QtWidgets import QMenu, QInputDialog, QAction -from PyQt5.uic import loadUiType -from epics import PV -from epics.ca import pend_event -from app_utils import assert_tweaker_positions - -Ui_MotorTweak, QWidget = loadUiType('epics_widgets/MotorTweak.ui') -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - -SPMG_STOP = 0 -SPMG_PAUSE = 1 -SPMG_MOVE = 2 -SPMG_GO = 3 - - - -class SmaractMotorTweak(QWidget, Ui_MotorTweak): - event_val = pyqtSignal(str, dict) - event_rbv = pyqtSignal(str, dict) - event_soft_limit = pyqtSignal(str, dict) - event_high_hard_limit = pyqtSignal(str, dict) - event_low_hard_limit = pyqtSignal(str, dict) - event_axis_fault = pyqtSignal(str, dict) - - def __init__(self, parent=None): - super(SmaractMotorTweak, self).__init__(parent=parent) - self.setupUi(self) - self._wheel_tweaks = True - self._auto_labels = True - self._locked = False - self._label_style = 'basic' - self._templates_source = { - 'basic': '{label} {{rbv:.{precision}f}} {units}', - 'small': '{label} {{rbv:.{precision}f}} {units}', - '2 lines': '{label}
{{rbv:.{precision}f}} {units}', - 'busy': '{label} {{rbv:.{precision}f}} {units}' - } - self._templates = {} - - - def connect_motor(self, rec_name, **kwargs): - # TODO: DO NOT USE so many PVs, but reduce to the only really needed PV: s.a. class QopticZoom(object) - label=kwargs['label'] - self._label=label - self._pvname = rec_name+':DRIVE' - self._pv_name = PV(rec_name+':NAME') - self._pv_drive = PV(rec_name+':DRIVE') - self._pv_readback = PV(rec_name+':MOTRBV') - self._pv_tweak_r = PV(rec_name+':TWR.PROC') - self._pv_tweak_f = PV(rec_name+':TWF.PROC') - self._pv_tweak_val = PV(rec_name+':TWV') - self._pv_status = PV(rec_name + ':STATUS') - self._pv_home_f = PV(rec_name + ':FRM_FORW.PROC') - self._pv_home_b = PV(rec_name + ':FRM_BACK.PROC') - self._pv_is_homed = PV(rec_name + ':GET_HOMED') - self._pv_llm = PV(rec_name + ':LLM') - self._pv_hlm = PV(rec_name + ':HLM') - - self.label.setToolTip('{} => {}'.format(rec_name, self._pv_name.get())) - - try: - self._prec = kwargs['prec'] - except: - self._prec = 5 - - try: - self._units = kwargs['units'] - except: - self._units = 'mm' - - self._ignore_limits = self._pv_llm.get() == self._pv_hlm.get() # if both high/low limits are equal they are meaningless - - self.set_motor_validator() - self._drive_val.setText(self._pv_drive.get(as_string=True)) - self._drive_val.returnPressed.connect(self.move_abs) - - self.jog_forward.hide() - self.jog_reverse.hide() - - tweak_min = kwargs.get("tweak_min", 0.0001) - tweak_max = kwargs.get("tweak_max", 20.0) - self._tweak_val.setText(self._pv_tweak_val.get(as_string=True)) - self._tweak_val.setValidator(QDoubleValidator(tweak_min, tweak_max, 4, self._tweak_val)) - self._tweak_val.editingFinished.connect(lambda m=self._pv_tweak_val: m.put(self._tweak_val.text())) - - self.tweak_forward.clicked.connect(lambda m: self._pv_tweak_f.put(1)) - self.tweak_reverse.clicked.connect(lambda m: self._pv_tweak_r.put(1)) - - - self.bind_wheel() - - self.update_label_template() - - self._pv_readback.add_callback(self.update_label) - self._pv_status.add_callback(self.set_val_on_status_change) - - # self._pv_drive.add_callback(self.set_val) - self._pv_drive.add_callback(self.emit_signals, source_field='VAL') - self._pv_readback.add_callback(self.emit_signals, source_field='RBV') - self._pv_hlm.add_callback(self.emit_signals, source_field='HLS') - self._pv_llm.add_callback(self.emit_signals, source_field='LLS') - - # m.set_callback('HLM', self.set_motor_validator) - - - def set_motor_validator(self, **kwargs): - lineedit = self._drive_val - min, max = self._pv_llm.get(), self._pv_hlm.get() - if min == max: - min = -1e6 - max = 1e6 - lineedit.setValidator(QDoubleValidator(min, max, 5, lineedit)) - - - def move_rel(self, dist, delay=None): - cur = self._pv_readback.get() - target = cur + dist - if delay: - sleep(delay) - self._pv_drive.put(target) - - def get_rbv(self): - return self._pv_readback.get(use_monitor=False) - - def get_val(self): - # return self._motor.get('VAL') - try: - v=self._val - except AttributeError: - self._val=v=self._pv_drive.get() - return v - - def is_homed(self): - pend_event() - return 1 == self._pv_is_homed.get(use_monitor=False) - - def get_status(self, as_string=False): - """ - States: - 0 Stopped - 1 Stepping - 2 Scanning - 3 Holding - 4 Targeting - 5 Move Delay - 6 Calibrating - 7 Finding Ref - 8 Locked - :return: - """ - return self._pv_status.get(as_string=as_string, use_monitor=False) - - def wait(self): - pend_event(.01) - while not self.is_done(): - pend_event(0.2) - - def is_done(self): - return self._pv_status.get() in (0, 3) - - def move_abs(self, drive=None, wait=False, assert_position=False): - if assert_position: - wait=True - if drive is None: - logger.debug('{} abs target from widget'.format(self._label)) - drive = float(self._drive_val.text()) - logger.debug('{} abs move => {}'.format(self._label, drive)) - self._pv_drive.put(drive) - if wait: - self.wait() - if assert_position: - assert_tweaker_positions([(self, drive, 0.05)], timeout=10.) - - def emit_signals(self, **kw): - field = kw['source_field'] - if field == 'VAL': - self.event_val.emit(self._pvname, kw) - elif field == 'RBV': - self.event_rbv.emit(self._pvname, kw) - elif field == 'LVIO': - self.event_soft_limit.emit(self._pvname, kw) - elif field == 'HLS': - self.event_high_hard_limit.emit(self._pvname, kw) - self.event_axis_fault.emit(self._pvname, kw) - elif field == 'LVIO': - self.event_low_hard_limit.emit(self._pvname, kw) - self.event_axis_fault.emit(self._pvname, kw) - elif field == 'STAT': - self.event_axis_fault.emit(self._pvname, kw) - - - def set_val_on_status_change(self, **kw): - ''' - 0 Stopped - 1 Stepping - 2 Scanning - 3 Holding - 4 Targeting - 5 Move Delay - 6 Calibrating - 7 Finding Ref - 8 Locked - :param kw: - :return: - ''' - status = kw['char_value'] - if status in ('Holding', 'Stopped'): - v = self._pv_readback.get(as_string=True) - logger.debug('updating VAL on status change to holding/stopped = {}'.format(v)) - self._drive_val.setText(v) - - def set_val(self, **kw): - v = kw['char_value'] - logger.debug('updating VAL = {}'.format(v)) - self._drive_val.setText(v) - - def update_label(self, **kwargs): - self.label.setText(self._templates[self._label_style].format(rbv=self._pv_readback.get())) - self.tweak_forward.setToolTip('tweak forward by {:.3f} {}'.format(self._pv_tweak_val.get(), self._units)) - self.tweak_reverse.setToolTip('tweak reverse by {:.3f} {}'.format(self._pv_tweak_val.get(), self._units)) - - def tweak_event(self, event): - sign = event.angleDelta().y() - if sign < 0: - self._pv_tweak_r.put(1) - else: - self._pv_tweak_f.put(1) - - def bind_wheel(self): - self.tweak_forward.wheelEvent = self.tweak_event - self.tweak_reverse.wheelEvent = self.tweak_event - - def contextMenuEvent(self, event): - name = self._pv_name.get() - unit = self._units - prec = self._prec - - menu = QMenu(self) - menu.setTitle(self._label) - - lockmotor = QAction('lock motor', menu, checkable=True) - lockmotor.setChecked(self._locked) - menu.addAction(lockmotor) - - autolabelsAction = QAction('auto', menu, checkable=True) - autolabelsAction.setChecked(self._auto_labels) - menu.addAction(autolabelsAction) - - wheel_tweaks = QAction('Mouse wheel tweaks motor', menu, checkable=True) - wheel_tweaks.setChecked(self._wheel_tweaks) - menu.addAction(wheel_tweaks) - - # stopmotorAction = QAction('Stopped', menu, checkable=True) - # stopmotorAction.setChecked(SPMG_STOP == m.stop_go) - # menu.addAction(stopmotorAction) - changeprecAction = menu.addAction("Change Precision") - changetweakstepAction = menu.addAction("Tweak step {:.3f} {}".format(self._pv_tweak_val.get(), unit)) - - tozeroAction = menu.addAction("move to Zero") - - - action = menu.exec_(self.mapToGlobal(event.pos())) - if action == lockmotor: - self._locked = not self._locked - if self._locked: - self._controlbox.setDisabled(True) - else: - self._controlbox.setDisabled(False) - elif action == changeprecAction: - msg = 'Precision for motor {}'.format(name) - logger.debug('prec before %d', prec) - prec, ok = QInputDialog.getInt(self, msg, msg, prec, 0, 10) - logger.debug('prec after (%d) %d', ok, prec) - if ok: - self._prec = prec - - elif action == changetweakstepAction: - tv = self._pv_tweak_val.get() - msg = 'Tweak step for motor {} at {} {}'.format(name, tv, unit) - tv, ok = QInputDialog.getDouble(self, msg, msg, tv, pow(10, -prec), 10.0, prec) - if ok: - self._pv_tweak_val.put(tv) - - elif action == tozeroAction: - self._pv_drive.put(0.0) - - elif action == autolabelsAction: - self._auto_labels = not self._auto_labels - - elif action == wheel_tweaks: - self._wheel_tweaks = not self._wheel_tweaks - self.bind_wheel() - - self.update_label_template() - - def resizeEvent(self, event): - pass - - def update_label_template(self): - source = self._templates_source - target = self._templates - - for k in source: - target[k] = source[k].format( - label=self._label, - precision=self._prec, - units=self._units) - self.label.setText(target[self._label_style].format(rbv=self._pv_readback.get())) - - def paintEvent(self, e): - qp = QPainter() - qp.begin(self) - qp.setRenderHint(QPainter.Antialiasing) - self._draw_limits(qp) - qp.end() - - def _draw_limits(self, qp): - pass - # width, height = self.size().width(), self.size().height() - # pad = 5 - # rounding = 2 - # size = 10 - # if m.HLS: - # x, y, w, h = width - size, pad, size, height - 2 * pad - # elif m.LLS: - # x, y, w, h = 0, pad, size, height - 2 * pad - # else: - # return - # color = QColor('indianred') - # qp.setBrush(QBrush(color, Qt.SolidPattern)) - # qp.setPen(QPen(color)) - # path = QPainterPath() - # path.setFillRule(Qt.WindingFill) - # path.addRoundedRect(x, y, w, h, rounding, rounding) - # qp.drawPath(path) diff --git a/swissmx.py b/swissmx.py index 36d26a0..8ffab76 100755 --- a/swissmx.py +++ b/swissmx.py @@ -143,7 +143,6 @@ from PyQt5.uic import loadUiType ts.log('Import part 4/8:') import pyqtUsrObj as UsrGO from epics_widgets.MotorTweak import MotorTweak -from epics_widgets.SmaractMotorTweak import SmaractMotorTweak from epics_widgets.SimMotorTweak import SimMotorTweak ts.log('Import part 5/8:') import numpy as np @@ -906,7 +905,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): if sim&0x20: m_tw=SimMotorTweak() else: - m_tw=SmaractMotorTweak() + m_tw=MotorTweak() m_tw.connect_motor(rec, **kwargs) self.tweakers[kwargs['alias']] = m_tw return m_tw @@ -1019,6 +1018,8 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): def build_group_collimator(self, toolbox): pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] + _log.warning('TODO: cleanup PV names!!!') + pfx='SARES30-SMX' c=QWidget() c.setLayout(QGridLayout()) f=lambda v: lambda x:self.move_collimator(v) #needs nested lambda to work ... @@ -1027,8 +1028,8 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): but.clicked.connect(f(v)) c.layout().addWidget(but, 0, i) widgets = [ - self.get_tweaker(f"{pfx}1", alias="colli_x", label="colli X", mtype=1,), - self.get_tweaker(f"{pfx}2", alias="colli_y", label="colli Y", mtype=1,), + self.get_tweaker(f"{pfx}:MCS1", alias="colli_x", label="colli X", mtype=1,), + self.get_tweaker(f"{pfx}:MCS2", alias="colli_y", label="colli Y", mtype=1,), c, ] qutilities.add_item_to_toolbox(toolbox,"Collimator",widget_list=widgets) @@ -1036,12 +1037,14 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): def build_group_posttube(self, toolbox): pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] + _log.warning('TODO: cleanup PV names!!!') + pfx='SARES30-SMX' widgets = [ - self.get_tweaker(f"{pfx}4", alias="tube_usx", label="upstream X", mtype=1,), - self.get_tweaker(f"{pfx}6", alias="tube_usy", label="upstream Y", mtype=1,), - self.get_tweaker(f"{pfx}5", alias="tube_dsx", label="downstream X", mtype=1,), - self.get_tweaker(f"{pfx}7", alias="tube_dsy", label="downstream Y", mtype=1,), - self.get_tweaker(f"{pfx}8", alias="tube_z", label="tube Z", mtype=1), + self.get_tweaker(f"{pfx}:MCS4", alias="tube_usx", label="upstream X", mtype=1,), + self.get_tweaker(f"{pfx}:MCS6", alias="tube_usy", label="upstream Y", mtype=1,), + self.get_tweaker(f"{pfx}:MCS5", alias="tube_dsx", label="downstream X", mtype=1,), + self.get_tweaker(f"{pfx}:MCS7", alias="tube_dsy", label="downstream Y", mtype=1,), + self.get_tweaker(f"{pfx}:MCS8", alias="tube_z", label="tube Z", mtype=1), ] c = QWidget() c.setLayout(QGridLayout()) @@ -1067,9 +1070,11 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): def build_group_xeye(self, toolbox): pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[1] + _log.warning('TODO: cleanup PV names!!!') + pfx='SARES30-SMX' widgets=[ - self.get_tweaker(f"{pfx}14", alias="xeye_x", label="X", mtype=1), - self.get_tweaker(f"{pfx}15", alias="xeye_y", label="Y", mtype=1), + self.get_tweaker(f"{pfx}:MCS14", alias="xeye_x", label="X", mtype=1), + self.get_tweaker(f"{pfx}:MCS15", alias="xeye_y", label="Y", mtype=1), ] qutilities.add_item_to_toolbox(toolbox,"X-Ray Eye",widget_list=widgets) WndSwissMx.pv_monitor_add(widgets)