diff --git a/pyqt-apps/scripts/sirius-hla-si-ap-idff.py b/pyqt-apps/scripts/sirius-hla-si-ap-idff.py
index 00cb5e5d5..8c727452c 100644
--- a/pyqt-apps/scripts/sirius-hla-si-ap-idff.py
+++ b/pyqt-apps/scripts/sirius-hla-si-ap-idff.py
@@ -15,9 +15,14 @@
'-p', "--prefix", type=str, default=VACA_PREFIX,
help="Define the prefix for the PVs in the window.")
parser.add_argument("idname", type=str, help="ID name.")
+parser.add_argument(
+ '-g', "--idffgroup", type=str, default=None,
+ help="Power supplies subgroup controlled by IDFF instance.")
args = parser.parse_args()
app = SiriusApplication()
app.open_window(
- IDFFWindow, parent=None, prefix=args.prefix, idname=args.idname)
+ IDFFWindow, parent=None, prefix=args.prefix,
+ idname=args.idname, idffgroup=args.idffgroup,
+)
_sys.exit(app.exec_())
diff --git a/pyqt-apps/scripts/sirius-hla-si-id-control.py b/pyqt-apps/scripts/sirius-hla-si-id-control.py
index ca9c68368..831a85b26 100644
--- a/pyqt-apps/scripts/sirius-hla-si-id-control.py
+++ b/pyqt-apps/scripts/sirius-hla-si-id-control.py
@@ -7,7 +7,8 @@
from siriushla.sirius_application import SiriusApplication
from siriuspy.envars import VACA_PREFIX
from siriushla.si_id_control import IDControl, APUControlWindow, \
- DELTAControlWindow, IVUControlWindow, VPUControlWindow
+ DELTAControlWindow, IVUControlWindow, VPUControlWindow, \
+ UEControlWindow
parser = _argparse.ArgumentParser(
@@ -37,6 +38,9 @@
elif 'VPU' in args.device:
app.open_window(
VPUControlWindow, parent=None, prefix=prefix, device=device)
+elif 'UE44' in args.device:
+ app.open_window(
+ UEControlWindow, parent=None, prefix=prefix, device=device)
elif not device or isall:
app.open_window(IDControl, parent=None, prefix=prefix)
sys.exit(app.exec_())
diff --git a/pyqt-apps/siriushla/VERSION b/pyqt-apps/siriushla/VERSION
index 141f2e805..15b989e39 100644
--- a/pyqt-apps/siriushla/VERSION
+++ b/pyqt-apps/siriushla/VERSION
@@ -1 +1 @@
-1.15.0
+1.16.0
diff --git a/pyqt-apps/siriushla/as_ap_launcher/menu.py b/pyqt-apps/siriushla/as_ap_launcher/menu.py
index f064db237..13bb6e1a0 100755
--- a/pyqt-apps/siriushla/as_ap_launcher/menu.py
+++ b/pyqt-apps/siriushla/as_ap_launcher/menu.py
@@ -468,7 +468,7 @@ def _create_id_menu(self):
'SI-08SB:ID-IVU18',
'SI-09SA:ID-APU22',
'SI-10SB:ID-DELTA52',
- 'SI-11SP:ID-APU58',
+ 'SI-11SP:ID-UE44',
'SI-14SB:ID-IVU18',
'SI-17SA:ID-APU22',
'SI-20SB:ID-APU22',
@@ -479,10 +479,10 @@ def _create_id_menu(self):
text = '{0} - {1} ({2})'.format(
idname.dev, idname.sub, beamline) \
if LEVEL2A == QAction else beamline
- APU = LEVEL2A(text, menu)
+ ID_DEV = LEVEL2A(text, menu)
self.connect_newprocess(
- APU, ['sirius-hla-si-id-control.py', '-dev', idname])
- self.add_object_to_level1(menu, APU)
+ ID_DEV, ['sirius-hla-si-id-control.py', '-dev', idname])
+ self.add_object_to_level1(menu, ID_DEV)
return menu
diff --git a/pyqt-apps/siriushla/as_ap_monitor/util.py b/pyqt-apps/siriushla/as_ap_monitor/util.py
index 4d75de4d8..a9e7a666f 100644
--- a/pyqt-apps/siriushla/as_ap_monitor/util.py
+++ b/pyqt-apps/siriushla/as_ap_monitor/util.py
@@ -28,5 +28,5 @@ def get_sec2dev_laypos(sec, label):
SEC2LABEL2SECPOS['BO'].update({
'RF': (2, 1, 1, 1)})
SEC2LABEL2SECPOS['SI'].update({
- 'RF': (0, 6, 1, 1)})
+ 'RF': (0, 8, 1, 1)})
return SEC2LABEL2SECPOS[sec][label]
diff --git a/pyqt-apps/siriushla/as_ps_commands/main.py b/pyqt-apps/siriushla/as_ps_commands/main.py
index cd4134975..c6d9666e9 100644
--- a/pyqt-apps/siriushla/as_ps_commands/main.py
+++ b/pyqt-apps/siriushla/as_ps_commands/main.py
@@ -1178,7 +1178,7 @@ def _get_ps_tree_names(self):
# add SI Corrs
psnames.extend(PSSearch.get_psnames(
{'sec': 'SI', 'sub': '[0-2][0-9].*', 'dis': 'PS',
- 'dev': '(LCH|CH|CV|CC)'}))
+ 'dev': '(LCH|LCV|CH|CV|CC)'}))
# add SI QTrims
psnames.extend(PSSearch.get_psnames(
{'sec': 'SI', 'sub': '[0-2][0-9].*', 'dis': 'PS',
diff --git a/pyqt-apps/siriushla/as_ps_control/SummaryWidgets.py b/pyqt-apps/siriushla/as_ps_control/SummaryWidgets.py
index a43f92528..0a514f295 100644
--- a/pyqt-apps/siriushla/as_ps_control/SummaryWidgets.py
+++ b/pyqt-apps/siriushla/as_ps_control/SummaryWidgets.py
@@ -21,7 +21,7 @@
Quadrupole = re.compile("^.*:PS-Q.*$")
QuadrupoleSkew = re.compile("^.*:PS-QS.*$")
Sextupole = re.compile("^.*:PS-S.*$")
-Corrector = re.compile("^.*:PS-(LCH|CH|CV|CC|FCH|FCV).*$")
+Corrector = re.compile("^.*:PS-(LCH|LCV|CH|CV|CC|FCH|FCV).*$")
FastCorrector = re.compile("^SI-.*:PS-(FCH|FCV).*$")
IsPulsed = re.compile("^.*:PU-.*$")
IsDCLink = re.compile("^.*:PS-DCLink.*$")
diff --git a/pyqt-apps/siriushla/as_ps_control/control_widget/BasePSControlWidget.py b/pyqt-apps/siriushla/as_ps_control/control_widget/BasePSControlWidget.py
index d32a66507..414a7e7cf 100644
--- a/pyqt-apps/siriushla/as_ps_control/control_widget/BasePSControlWidget.py
+++ b/pyqt-apps/siriushla/as_ps_control/control_widget/BasePSControlWidget.py
@@ -237,7 +237,10 @@ class BasePSControlWidget(QWidget):
HORIZONTAL = 0
VERTICAL = 1
- def __init__(self, subsection=None, orientation=0, parent=None):
+ def __init__(
+ self, subsection=None, idffsubgroup=None, orientation=0,
+ parent=None,
+ ):
"""Class constructor.
Parameters:
@@ -246,11 +249,18 @@ def __init__(self, subsection=None, orientation=0, parent=None):
orientation
Default to HORIZONTAL. Define how the different groups
(defined in subclasses) will be laid out.
+ idffsubgroup
+ Default to None. To be used in filters defined in subclass.
"""
super(BasePSControlWidget, self).__init__(parent)
self._orientation = orientation
self._subsection = subsection
- self._dev_list = PSSearch.get_psnames(self._getFilter(subsection))
+ self._idffsubgroup = idffsubgroup
+ filtargs = [subsection]
+ if idffsubgroup:
+ filtargs.append(idffsubgroup)
+ filt = self._getFilter(*filtargs)
+ self._dev_list = PSSearch.get_psnames(filt)
dev0 = PVName(self._dev_list[0])
if dev0.sec == 'LI':
if dev0.dev == 'Slnd':
diff --git a/pyqt-apps/siriushla/as_ps_control/control_widget/ControlWidgetFactory.py b/pyqt-apps/siriushla/as_ps_control/control_widget/ControlWidgetFactory.py
index 699de1dcc..13bb72906 100644
--- a/pyqt-apps/siriushla/as_ps_control/control_widget/ControlWidgetFactory.py
+++ b/pyqt-apps/siriushla/as_ps_control/control_widget/ControlWidgetFactory.py
@@ -32,7 +32,10 @@ def _device_not_found(section, device):
raise AttributeError("{} not defined for {}".format(device, section))
@staticmethod
- def factory(parent, section, device, subsection=None, orientation=0):
+ def factory(
+ parent, section, device, subsection=None, orientation=0,
+ idffsubgroup=None
+ ):
if section == "LI":
if device == "spectrometer":
return LISpectControlWidget(
@@ -122,7 +125,7 @@ def factory(parent, section, device, subsection=None, orientation=0):
elif device == "corrector-idff":
return IDFFCorrectorControlWidget(
subsection=subsection, orientation=orientation,
- parent=parent)
+ parent=parent, idffsubgroup=idffsubgroup)
elif device == "skew-quadrupole":
return SISkewQuadControlWidget(
subsection=subsection, orientation=orientation,
diff --git a/pyqt-apps/siriushla/as_ps_control/control_widget/IDFFCorrectorControlWidget.py b/pyqt-apps/siriushla/as_ps_control/control_widget/IDFFCorrectorControlWidget.py
index 00b31e13d..8792dbf92 100644
--- a/pyqt-apps/siriushla/as_ps_control/control_widget/IDFFCorrectorControlWidget.py
+++ b/pyqt-apps/siriushla/as_ps_control/control_widget/IDFFCorrectorControlWidget.py
@@ -5,15 +5,19 @@
class IDFFCorrectorControlWidget(BasePSControlWidget):
"""IDFF corrector control widget."""
- def _getFilter(self, subsection=None):
- subsectype = subsection[-1] # 'A' | 'B' | 'P'
- qd = "QD" + subsectype # for A type sections
- qf = "QF" + subsectype
- qd1 = qd + "1" # for B and P type sections
- qd2 = qd + "2" # for B and P type sections
- trims = qd + "|" + qd1 + "|" + qf + "|" + qd2
- dev = "(CH|CV|QS|" + trims + "|LCH|CC1|CC2)"
- return {"sec": "SI", "sub": subsection, "dev": dev}
+ def _getFilter(self, subsection=None, idffsubgroup=None):
+ if idffsubgroup:
+ filt = {"sec": "SI", "sub": subsection, "dev": idffsubgroup}
+ else:
+ subsectype = subsection[-1] # 'A' | 'B' | 'P'
+ qd = "QD" + subsectype # for A type sections
+ qf = "QF" + subsectype
+ qd1 = qd + "1" # for B and P type sections
+ qd2 = qd + "2" # for B and P type sections
+ trims = qd + "|" + qd1 + "|" + qf + "|" + qd2
+ dev = "(CH|CV|QS|" + trims + "|LCH|LCV|CC1|CC2)"
+ filt = {"sec": "SI", "sub": subsection, "dev": dev}
+ return filt
def _hasTrimButton(self):
return False
@@ -27,6 +31,6 @@ def _getGroups(self):
('Vertical Corretors', '-CV'),
('Skew Quadrupole', '-QS'),
('Trim Quadrupoles ', '-(QF[ABP]|QDA|QDB[12]|QDP[12])'),
- ('Long Coils', '-LCH'),
+ ('Long Coils', '-LC'),
('Corrector Coils', '-CC')
]
diff --git a/pyqt-apps/siriushla/as_ps_control/control_widget/SlowCorrectorControlWidget.py b/pyqt-apps/siriushla/as_ps_control/control_widget/SlowCorrectorControlWidget.py
index 4c533e190..3f7b91f49 100644
--- a/pyqt-apps/siriushla/as_ps_control/control_widget/SlowCorrectorControlWidget.py
+++ b/pyqt-apps/siriushla/as_ps_control/control_widget/SlowCorrectorControlWidget.py
@@ -6,7 +6,7 @@ class SISlowCorrectorControlWidget(BasePSControlWidget):
"""Storage ring slow correctors."""
def _getFilter(self, subsection=None):
- filt = {"sec": "SI", "sub": "\w{4}", "dev": "(CH|CV|CC|LCH).*"}
+ filt = {"sec": "SI", "sub": "\w{4}", "dev": "(CH|CV|CC|LCH|LCV).*"}
if subsection:
filt.update({'sub': subsection})
return filt
diff --git a/pyqt-apps/siriushla/as_ps_diag/monitor.py b/pyqt-apps/siriushla/as_ps_diag/monitor.py
index ec72a9d8a..22d224b5e 100644
--- a/pyqt-apps/siriushla/as_ps_diag/monitor.py
+++ b/pyqt-apps/siriushla/as_ps_diag/monitor.py
@@ -111,7 +111,7 @@ def update_gridpos(row, col, col_count, offset=0):
aux = devices.pop(-1)
devices.insert(0, aux)
elif sec == 'SI':
- if label not in ['FCH', 'FCV', 'ID-CH/CV/QS/CC']:
+ if label not in ['FCH', 'FCV', 'ID-FF Correctors']:
aux = devices.pop(-1)
devices.insert(0, aux)
if label == 'Trims':
diff --git a/pyqt-apps/siriushla/as_ps_diag/util.py b/pyqt-apps/siriushla/as_ps_diag/util.py
index 3f5237d19..55f4b635f 100644
--- a/pyqt-apps/siriushla/as_ps_diag/util.py
+++ b/pyqt-apps/siriushla/as_ps_diag/util.py
@@ -26,8 +26,8 @@
'S': {'sec': 'SI', 'sub': '.*', 'dev': 'S.*'},
'CV': {'sec': 'SI', 'sub': '.*(M|C).*', 'dev': 'CV.*'},
'CH': {'sec': 'SI', 'sub': '.*(M|C).*', 'dev': 'CH.*'},
- 'ID-CH/CV/QS/CC': {'sec': 'SI', 'sub': '.*S(A|B|P)',
- 'dev': '(LCH|CH|CV|CC|QS)'},
+ 'ID-FF Correctors': {'sec': 'SI', 'sub': '.*S(A|B|P)',
+ 'dev': '(LCH|LCV|CH|CV|CC|QS)'},
'FFCH/FFCV': {'sec': 'SI', 'dev': 'FFC.*'},
'Trims': {'sec': 'SI', 'sub': '[0-2][0-9].*',
'dev': 'Q(F|D|[1-4]).*'},
@@ -89,10 +89,10 @@ def get_label2devices(sec):
'SI': {
'B': (0, 1, 1, 1),
'PM': (0, 2, 1, 1),
- 'FFCH/FFCV': (0, 3, 1, 1),
- 'Q': (0, 4, 1, 1),
- 'S': (0, 5, 1, 1),
- 'ID-CH/CV/QS/CC': (0, 7, 1, 2),
+ 'Q': (0, 3, 1, 1),
+ 'S': (0, 4, 1, 1),
+ 'ID-FF Correctors': (0, 5, 1, 2),
+ 'FFCH/FFCV': (0, 7, 1, 1),
'QS': (1, 1, 1, 2),
'CH': (1, 3, 1, 1),
'CV': (1, 4, 1, 1),
@@ -117,15 +117,15 @@ def get_col2dev_count(sec, label):
if 'Trims' in label:
return 14
if 'FFC' in label:
- return 4
+ return 2
if 'ID' in label:
- return 8
+ return 13
if 'FC' in label:
return 4
if label == 'S':
- return 11
+ return 7
if label == 'Q':
- return 10 if sec != 'SI' else 6
+ return 10 if sec != 'SI' else 5
if label == 'Slnd':
return 21
return 10
diff --git a/pyqt-apps/siriushla/si_ap_idff/main.py b/pyqt-apps/siriushla/si_ap_idff/main.py
index a0eb10f4f..6d4ddb84e 100644
--- a/pyqt-apps/siriushla/si_ap_idff/main.py
+++ b/pyqt-apps/siriushla/si_ap_idff/main.py
@@ -39,25 +39,34 @@ class IDFFWindow(SiriusMainWindow):
# so as to provide the same PVs as the low level ioc (particularly
# "IDPos-Mon")
- def __init__(self, parent=None, prefix='', idname=''):
+ def __init__(self, parent=None, prefix='', idname='', idffgroup=''):
"""Initialize."""
super().__init__(parent)
self.prefix = prefix or _VACA_PREFIX
self.idname = _PVName(idname)
- self._is_llidff = self.idname.dev.startswith(("IVU", "SIMUL", "VPU"))
- if self._is_llidff and self.idname.dev.startswith(("IVU", "SIMUL")):
+ self._is_llidff = self.idname.dev.startswith(
+ ("IVU", "SIMUL", "VPU", "UE44", )
+ )
+ if self.idname.dev.startswith(("IVU", "SIMUL")):
self._idffname = _PVName(f"SI-{self.idname.sub}:BS-IDFF-CHCV")
- elif self._is_llidff and self.idname.dev.startswith("VPU"):
+ elif self.idname.dev.startswith("VPU"):
self._idffname = _PVName(f"SI-{self.idname.sub}:BS-IDFF-CC")
+ elif self.idname.dev.startswith("UE44"):
+ if not idffgroup:
+ raise ValueError('idffgroup input need to be defined for UE44')
+ self._idffname = _PVName(f"SI-{self.idname.sub}:BS-IDFF-{idffgroup}")
else:
self._idffname = _PVName(f"SI-{self.idname.sub}:AP-IDFF")
- self.dev_pref = _PVName(self._idffname + ':')
- # self._idffname = IDFFConst(idname).idffname
+ self.dev_pref = _PVName(self._idffname)
self._idffdev = self._create_idffdev()
self._idffdata = IDSearch.conv_idname_2_idff(self.idname)
- self.device = _PVName(self._idffname)
+ dis = "BS" if self._is_llidff else "AP"
+ self._idffnickname = _PVName(f"SI-{self.idname.sub}:{dis}-IDFF")
+ self._idffgroup = idffgroup
+ if idffgroup:
+ self._idffnickname = self._idffnickname.substitute(idx=idffgroup)
self.setObjectName('IDApp')
- self.setWindowTitle(self.device)
+ self.setWindowTitle(self._idffnickname)
self.setWindowIcon(get_idff_icon())
self._setupUi()
self.setFocusPolicy(Qt.StrongFocus)
@@ -74,6 +83,8 @@ def _setupUi(self):
corrs += self._idffdev.ctrldev.IDFF_CH_LABELS
corrs += self._idffdev.ctrldev.IDFF_CV_LABELS
corrs += self._idffdev.ctrldev.IDFF_CC_LABELS
+ corrs += self._idffdev.ctrldev.IDFF_LC_LABELS
+ corrs += self._idffdev.ctrldev.IDFF_QS_LABELS
lay.addWidget(self._llStatusWidget(), 1, 0, 1, 1)
lay.addWidget(self._llSettingsWidget(corrs), 2, 0, 3, 1)
else:
@@ -288,7 +299,7 @@ def _basicSettingsWidget(self):
'Calc. values:', self, alignment=Qt.AlignRight)
glay_calccorr = QGridLayout()
glay_calccorr.addWidget(ld_calccorr, 0, 0)
- corr_fams = ['CH', 'CV', 'QS', 'LCH', 'QD1', 'QF', 'QD2', 'CC']
+ corr_fams = ['CH', 'CV', 'QS', 'LCH', 'LCV', 'QD1', 'QF', 'QD2', 'CC']
for ridx, corr in enumerate(corr_fams):
if corr == 'CH' and not chnames:
continue
@@ -296,7 +307,7 @@ def _basicSettingsWidget(self):
continue
if corr == 'QS' and not qsnames:
continue
- if corr == 'LCH' and not lcnames:
+ if corr in ('LCH', 'LCV') and not lcnames:
continue
if corr in ('QD1', 'QF', 'QD2') and not qnnames:
continue
@@ -495,9 +506,19 @@ def _logWidget(self):
return gbox
def _corrsMonitorWidget(self):
+ idffsubgroup = None
+ if self._idffgroup:
+ idffsubgroup = (
+ "(CH|CV)" if self._idffgroup == "CHCV" else
+ "LC(H|V)" if self._idffgroup == "LC" else
+ "QS" if self._idffgroup == "QS" else
+ None
+ )
widget = ControlWidgetFactory.factory(
self, section='SI', device='corrector-idff',
- subsection=self.device.sub, orientation=Qt.Vertical)
+ subsection=self._idffnickname.sub,
+ idffsubgroup=idffsubgroup,
+ orientation=Qt.Vertical)
for wid in widget.get_summary_widgets():
detail_bt = wid.get_detail_button()
psname = detail_bt.text()
diff --git a/pyqt-apps/siriushla/si_id_control/__init__.py b/pyqt-apps/siriushla/si_id_control/__init__.py
index e130af5bf..d025ba540 100644
--- a/pyqt-apps/siriushla/si_id_control/__init__.py
+++ b/pyqt-apps/siriushla/si_id_control/__init__.py
@@ -6,4 +6,5 @@
# from .papu import PAPUControlWindow
from .ivu import IVUControlWindow
from .vpu import VPUControlWindow
+from .ue import UEControlWindow
from .id_control import IDControl
diff --git a/pyqt-apps/siriushla/si_id_control/id_control.py b/pyqt-apps/siriushla/si_id_control/id_control.py
index 78d2f3855..3f1edd056 100644
--- a/pyqt-apps/siriushla/si_id_control/id_control.py
+++ b/pyqt-apps/siriushla/si_id_control/id_control.py
@@ -4,7 +4,7 @@
from qtpy.QtGui import QMovie
from qtpy.QtCore import Qt, Slot, QSize
from qtpy.QtWidgets import QVBoxLayout, QWidget, QGroupBox, QGridLayout, \
- QLabel, QAction, QMenu
+ QLabel, QAction, QMenu, QScrollArea
from pydm.connection_inspector import ConnectionInspector
from siriuspy.envars import VACA_PREFIX as _vaca_prefix
@@ -16,6 +16,7 @@
from .delta import DELTASummaryHeader, DELTASummaryWidget
from .ivu import IVUSummaryHeader, IVUSummaryWidget
from .vpu import VPUSummaryHeader, VPUSummaryWidget
+from .ue import UESummaryHeader, UESummaryWidget
from .util import get_id_icon
@@ -39,7 +40,8 @@ def _setupUi(self):
label = QLabel('
ID Control Window
',
self, alignment=Qt.AlignCenter)
- label.setStyleSheet('QLabel{min-height: 3em; max-height: 3em;}')
+ label.setStyleSheet(
+ 'QLabel{min-height: 3em; max-height: 3em; min-width: 75em;}')
self.label_mov1 = QLabel(self)
self.label_mov1.setVisible(False)
@@ -67,14 +69,32 @@ def _setupUi(self):
self._gbox_vpu = QGroupBox('VPU', self)
self._gbox_vpu.setLayout(self._setupVPULayout())
+ self._gbox_ue = QGroupBox('UE', self)
+ self._gbox_ue.setLayout(self._setupUELayout())
+
+ scarea = QScrollArea(self)
+ scarea.setStyleSheet(
+ '.QScrollArea{min-width: 30em;}')
+ scarea.setSizeAdjustPolicy(scarea.AdjustToContents)
+ scarea.setWidgetResizable(True)
+ scr_ar_wid = QWidget()
+ scr_ar_wid.setObjectName('scrollarea')
+ scr_ar_wid.setStyleSheet(
+ '#scrollarea {background-color: transparent;}')
+ laysa = QVBoxLayout(scr_ar_wid)
+ laysa.setContentsMargins(0, 0, 0, 0)
+ laysa.addWidget(self._gbox_apu)
+ laysa.addWidget(self._gbox_delta)
+ laysa.addWidget(self._gbox_ivu)
+ laysa.addWidget(self._gbox_vpu)
+ laysa.addWidget(self._gbox_ue)
+ scarea.setWidget(scr_ar_wid)
+
lay = QGridLayout(cwid)
lay.addWidget(self.label_mov1, 0, 0)
lay.addWidget(label, 0, 1)
lay.addWidget(self.label_mov2, 0, 2)
- lay.addWidget(self._gbox_apu, 1, 0, 1, 3)
- lay.addWidget(self._gbox_delta, 2, 0, 1, 3)
- lay.addWidget(self._gbox_ivu, 3, 0, 1, 3)
- lay.addWidget(self._gbox_vpu, 4, 0, 1, 3)
+ lay.addWidget(scarea, 1, 0, 1, 3)
lay.setColumnStretch(0, 1)
lay.setColumnStretch(1, 15)
lay.setColumnStretch(2, 1)
@@ -88,7 +108,6 @@ def _setupAPULayout(self):
idlist = [
'SI-09SA:ID-APU22',
- 'SI-11SP:ID-APU58',
'SI-17SA:ID-APU22',
'SI-20SB:ID-APU22',
]
@@ -126,8 +145,8 @@ def _setupIVULayout(self):
lay = QVBoxLayout()
lay.setAlignment(Qt.AlignTop)
- self._delta_header = IVUSummaryHeader(self)
- lay.addWidget(self._delta_header)
+ self._ivu_header = IVUSummaryHeader(self)
+ lay.addWidget(self._ivu_header)
idlist = ['SI-08SB:ID-IVU18', 'SI-14SB:ID-IVU18']
for idname in idlist:
@@ -145,8 +164,8 @@ def _setupVPULayout(self):
lay = QVBoxLayout()
lay.setAlignment(Qt.AlignTop)
- self._delta_header = VPUSummaryHeader(self)
- lay.addWidget(self._delta_header)
+ self._vpu_header = VPUSummaryHeader(self)
+ lay.addWidget(self._vpu_header)
idlist = ['SI-06SB:ID-VPU29', 'SI-07SP:ID-VPU29']
for idname in idlist:
@@ -160,6 +179,25 @@ def _setupVPULayout(self):
return lay
+ def _setupUELayout(self):
+ lay = QVBoxLayout()
+ lay.setAlignment(Qt.AlignTop)
+
+ self._ue_header = UESummaryHeader(self)
+ lay.addWidget(self._ue_header)
+
+ idlist = ['SI-11SP:ID-UE44', ]
+ for idname in idlist:
+ ue_wid = UESummaryWidget(self, self._prefix, idname)
+ lay.addWidget(ue_wid)
+ self._id_widgets.append(ue_wid)
+ ch_mov = SiriusConnectionSignal(_PVName(idname).substitute(
+ prefix=self._prefix, propty='Moving-Mon'))
+ ch_mov.new_value_signal[int].connect(self._handle_moving_vis)
+ self._channels_mov.append(ch_mov)
+
+ return lay
+
def _create_actions(self):
self.blctrl_enbl_act = QAction("Enable Beamline Control", self)
self.blctrl_enbl_act.triggered.connect(
diff --git a/pyqt-apps/siriushla/si_id_control/ue.py b/pyqt-apps/siriushla/si_id_control/ue.py
new file mode 100644
index 000000000..1e9caaac6
--- /dev/null
+++ b/pyqt-apps/siriushla/si_id_control/ue.py
@@ -0,0 +1,653 @@
+"""UE Control Module."""
+
+from qtpy.QtCore import Qt, QSize
+from qtpy.QtWidgets import QGroupBox, QLabel, QWidget, \
+ QPushButton, QHBoxLayout, QGridLayout, QSizePolicy
+import qtawesome as qta
+from pydm.widgets import PyDMPushButton
+
+from siriuspy.namesys import SiriusPVName as _PVName
+from siriushla.util import connect_newprocess, connect_window
+from ..widgets import SiriusLedAlert, SiriusLabel, SiriusSpinbox, \
+ SiriusLedState, SiriusLineEdit, SiriusEnumComboBox, \
+ PyDMStateButton
+from ..widgets.dialog import StatusDetailDialog
+
+from .base import IDCommonControlWindow, IDCommonDialog, \
+ IDCommonSummaryBase, IDCommonSummaryHeader, IDCommonSummaryWidget
+
+
+class UEControlWindow(IDCommonControlWindow):
+ """UE Control Window."""
+
+ OPERATION_PVS = {
+ "Power Off": {
+ "StateMon": "PowerOff-Mon"
+ },
+ "Kill Override": {
+ "StateMon": "KillOverride-Mon"
+ },
+ "Is Remote": {
+ "StateMon": "IsRemote-Mon"
+ },
+ "Device Status": {
+ "StateMon": "DeviceStatus-Mon"
+ },
+ }
+
+ MAIN_CONTROL_PVS = {
+ "KParam": {
+ "SP": "KParam-SP",
+ "Mon": "KParam-Mon",
+ "RB": "KParam-RB"
+ },
+ "Change KParam": {
+ "Cmd": "KParamChange-Cmd",
+ "icon": "fa5s.play"
+ },
+ "PParam": {
+ "SP": "PParam-SP",
+ "Mon": "PParam-Mon",
+ "RB": "PParam-RB"
+ },
+ "Change PParam": {
+ "Cmd": "PParamChange-Cmd",
+ "icon": "fa5s.play"
+ },
+ "CParam": {
+ "SP": "CParam-SP",
+ "Mon": "CParam-Mon",
+ "RB": "CParam-RB"
+ },
+ "Change CParam": {
+ "Cmd": "CParamChange-Cmd",
+ "icon": "fa5s.play"
+ },
+ "Offset": {
+ "SP": "Offset-SP",
+ "Mon": "Offset-Mon",
+ "RB": "Offset-RB"
+ },
+ "Offset Speed": {
+ "Mon": "OffsetVelo-Mon"
+ },
+ "Speed Setpoint": {
+ "SP": "Velo-SP",
+ "Mon": "Velo-Mon",
+ "RB": "Velo-RB"
+ },
+ "Acc. Setpoint": {
+ "SP": "Acc-SP",
+ "Mon": "Acc-Mon",
+ "RB": "Acc-RB"
+ },
+ "Pol": {
+ "SP": "Pol-Sel",
+ "Mon": "Pol-Mon",
+ "RB": "Pol-RB"
+ },
+ "Moving": {
+ "StateMon": "Moving-Mon"
+ }
+ }
+
+ SCANS_PVS = {
+ "Scan Mode": {
+ "SP": "ScanMode-Sel"
+ },
+ "Scan Done": {
+ "StateMon": "ScanDone-Mon"
+ },
+ "Read Traj": {
+ "Cmd": "ReadTraj-Cmd",
+ "icon": "fa5s.play"
+ },
+ "Write Traj": {
+ "Cmd": "WriteTraj-Cmd",
+ "icon": "mdi.keyboard-return"
+ },
+ "Fly First Pos": {
+ "StateMon": "FlyFirstPos-Mon"
+ },
+ }
+
+ def _mainControlsWidget(self):
+ group = QGroupBox('Main Controls')
+ lay = QGridLayout()
+ lay.setContentsMargins(3, 3, 3, 3)
+ group.setLayout(lay)
+
+ lay.addWidget(
+ QLabel('SP
', self, alignment=Qt.AlignCenter), 0, 1)
+ lay.addWidget(
+ QLabel('RB
', self, alignment=Qt.AlignCenter), 0, 2)
+ lay.addWidget(
+ QLabel('Mon
', self, alignment=Qt.AlignCenter), 0, 3)
+
+ row = 1
+ for title, pv_info in self.MAIN_CONTROL_PVS.items():
+ label = QLabel(
+ title, self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ label.setFixedWidth(150)
+ lay.addWidget(label, row, 0)
+
+ if isinstance(pv_info, dict):
+ if "Cmd" in pv_info:
+ self._createCmdBtns(pv_info, lay, row)
+ elif "StateMon" in pv_info:
+ self._createLedState(pv_info, lay, row)
+ else:
+ self._createParam(pv_info, lay, row)
+ else:
+ raise NotImplementedError
+ row += 1
+
+ self._lb_start = QLabel(
+ 'Start Movement', self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ self._pb_start = PyDMPushButton(
+ self, label='', icon=qta.icon("fa5s.play"))
+ self._pb_start.channel = self.dev_pref.substitute(propty='DevCtrl-Cmd')
+ self._pb_start.pressValue = 120
+ self._pb_start.setObjectName("Start")
+ self._pb_start.setStyleSheet(
+ '#Start{min-width:30px; max-width:30px; icon-size:25px;}')
+
+ self._lb_abort = QLabel(
+ 'Abort', self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ self._pb_abort = PyDMPushButton(
+ self, label='', icon=qta.icon("fa5s.stop"))
+ self._pb_abort.channel = self.dev_pref.substitute(propty='Abort-Cmd')
+ self._pb_abort.pressValue = 1
+ self._pb_abort.setObjectName("Stop")
+ self._pb_abort.setStyleSheet(
+ '#Stop{min-width:30px; max-width:30px; icon-size:25px;}')
+
+ self._lb_reset = QLabel(
+ 'Reset', self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ self._pb_reset = PyDMPushButton(
+ self, label='', icon=qta.icon('fa5s.sync'))
+ self._pb_reset.channel = self.dev_pref.substitute(propty='DevCtrl-Cmd')
+ self._pb_reset.pressValue = 100 # Reset
+ self._pb_reset.setObjectName('Reset')
+ self._pb_reset.setStyleSheet(
+ '#Reset{min-width:30px; max-width:30px; icon-size:25px;}')
+
+ lay.addWidget(self._lb_start, row, 0)
+ lay.addWidget(self._pb_start, row, 1)
+ lay.addWidget(self._lb_abort, row+1, 0)
+ lay.addWidget(self._pb_abort, row+1, 1)
+ lay.addWidget(self._lb_reset, row+2, 0)
+ lay.addWidget(self._pb_reset, row+2, 1)
+
+ return group
+
+ def _statusWidget(self):
+ gbox = QGroupBox("Status")
+ gbox.setSizePolicy(
+ QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
+ lay = QGridLayout(gbox)
+ lay.setVerticalSpacing(15)
+ row = 0
+
+ self._pb_dtls = QPushButton(
+ "Servo Motors and General Status Details", self)
+ self._pb_dtls.setIcon(qta.icon('fa5s.list-ul'))
+ connect_window(
+ self._pb_dtls, UEDetails, self,
+ prefix=self._prefix, device=self._device)
+ lay.addWidget(self._pb_dtls, row, 0, 1, 2)
+ row += 1
+
+ axis_status_labels = {
+ 'TOStatusIO-Mon': [
+ 'Min SW limit reached',
+ 'Max SW limit reached',
+ 'Min limit switch activated',
+ 'Max limit switch activated',
+ 'Min kill switch activated',
+ 'Max kill switch activated',
+ 'Pneumatic brake released',
+ 'Pneumatic brake locked',
+ 'Pneumatic brake Worn',
+ 'Linear encoder fault',
+ 'Driver channel fault'
+ ],
+ 'TIStatusIO-Mon': [
+ 'Min SW limit reached',
+ 'Max SW limit reached',
+ 'Min limit switch activated',
+ 'Max limit switch activated',
+ 'Min kill switch activated',
+ 'Max kill switch activated',
+ 'Pneumatic brake released',
+ 'Pneumatic brake locked',
+ 'Pneumatic brake Worn',
+ 'Linear encoder fault',
+ 'Driver channel fault'
+ ],
+ 'BOStatusIO-Mon': [
+ 'Min SW limit reached',
+ 'Max SW limit reached',
+ 'Min limit switch activated',
+ 'Max limit switch activated',
+ 'Min kill switch activated',
+ 'Max kill switch activated',
+ 'Pneumatic brake released',
+ 'Pneumatic brake locked',
+ 'Pneumatic brake Worn',
+ 'Linear encoder fault',
+ 'Driver channel fault'
+ ],
+ 'BIStatusIO-Mon': [
+ 'Min SW limit reached',
+ 'Max SW limit reached',
+ 'Min limit switch activated',
+ 'Max limit switch activated',
+ 'Min kill switch activated',
+ 'Max kill switch activated',
+ 'Pneumatic brake released',
+ 'Pneumatic brake locked',
+ 'Pneumatic brake Worn',
+ 'Linear encoder fault',
+ 'Driver channel fault'
+ ]
+ }
+
+ servos_lay = QGridLayout()
+ servos_row = 0
+
+ for status, labels in axis_status_labels.items():
+ pvname = self.dev_pref.substitute(propty=status)
+ servo_lbl = status.split('-')[0]
+ lbl = QLabel(
+ servo_lbl, self,
+ alignment=Qt.AlignRight | Qt.AlignVCenter)
+ read_sts = SiriusLedAlert(self, pvname)
+ pbt = QPushButton('', self)
+ pbt.setIcon(qta.icon('fa5s.ellipsis-v'))
+ pbt.setObjectName('sts')
+ pbt.setStyleSheet(
+ '#sts{min-width:18px; max-width:18px; icon-size:20px;}')
+ connect_window(
+ pbt, StatusDetailDialog, pvname=pvname, parent=self,
+ labels=labels, section="ID", title=f'{servo_lbl} Detailed Status')
+ servos_lay.addWidget(lbl, servos_row, 0)
+ servos_lay.addWidget(read_sts, servos_row, 1, alignment=Qt.AlignRight)
+ servos_lay.addWidget(pbt, servos_row, 2, alignment=Qt.AlignLeft)
+ servos_row += 1
+ lay.addLayout(servos_lay, 1, 0, 1, 2, alignment=Qt.AlignHCenter)
+ row += 1
+
+ status2labels = {
+ 'DeviceStatus-Mon': [
+ 'Error',
+ 'Power Off',
+ 'Software limit enabled',
+ 'Hardware limit enabled',
+ 'Kill switches enabled',
+ 'Control enabled',
+ 'Moving',
+ 'Emergency stop button',
+ 'One or more SW limit reached',
+ 'One or more HW limit reached',
+ 'One or more kill SW reached'
+ ]
+ }
+
+ for dev_sts, label in status2labels.items():
+ pvname = self.dev_pref.substitute(propty=dev_sts)
+ dev_lay = QGridLayout()
+ dev_title = QLabel(f'{dev_sts}
',
+ self, alignment=Qt.AlignCenter)
+ dev_lay.addWidget(dev_title, 0, 0, alignment=Qt.AlignCenter)
+ for idx, lbl in enumerate(label):
+ sts_lbl = QLabel(lbl)
+ irow = idx + 1
+ read_sts = SiriusLedAlert(self, pvname, bit=idx)
+ if lbl == "Error":
+ read_sts.onColor = SiriusLedState.Red
+ else:
+ read_sts.onColor = SiriusLedState.Yellow
+ dev_lay.addWidget(read_sts, irow, 0)
+ dev_lay.addWidget(sts_lbl, irow, 1)
+ lay.addLayout(dev_lay, row, 0)
+
+ return gbox
+
+ def _ctrlModeWidget(self):
+ gbox = QGroupBox("Operation Status")
+ gbox.setSizePolicy(
+ QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
+ lay = QGridLayout(gbox)
+ lay.setVerticalSpacing(15)
+ row = 0
+
+ for title, pv_info in self.OPERATION_PVS.items():
+ label = QLabel(
+ title, self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ label.setFixedWidth(150)
+ lay.addWidget(label, row, 0)
+
+ if isinstance(pv_info, dict):
+ if "Cmd" in pv_info:
+ self._createCmdBtns(pv_info, lay, row)
+ elif "StateMon" in pv_info:
+ self._createLedState(pv_info, lay, row)
+ else:
+ self._createParam(pv_info, lay, row)
+ else:
+ raise NotImplementedError
+ row += 1
+
+ return gbox
+
+ def _auxCommandsWidget(self):
+ # scan controls
+ scangroup = QGroupBox('Scan Controls')
+ scanlay = QGridLayout()
+ scanlay.setContentsMargins(3, 3, 3, 3)
+ scangroup.setLayout(scanlay)
+
+ row = 0
+ for title, pv_info in self.SCANS_PVS.items():
+ label = QLabel(
+ title, self, alignment=Qt.AlignRight | Qt.AlignVCenter)
+ label.setFixedWidth(150)
+ scanlay.addWidget(label, row, 0)
+
+ if isinstance(pv_info, dict):
+ if "Cmd" in pv_info:
+ self._createCmdBtns(pv_info, scanlay, row)
+ elif "StateMon" in pv_info:
+ self._createLedState(pv_info, scanlay, row)
+ else:
+ self._createParam(pv_info, scanlay, row)
+ else:
+ raise NotImplementedError
+ row += 1
+
+ # auxiliary parameters
+ auxgbox = QGroupBox('Auxiliary Parameters', self)
+
+ self._speed_lim = QLabel('Max Speed [mm/s]', self)
+ self._spin_box_sl = SiriusSpinbox(
+ self, self.dev_pref.substitute(propty="MaxVelo-SP"))
+ self._spin_box_sl.setStyleSheet('max-width:4.5em;')
+ self._lb_spin_box_sl = SiriusLabel(
+ self, self.dev_pref.substitute(propty="MaxVelo-RB"))
+
+ self._ld_periodlen = QLabel('Period Length', self)
+ self._lb_periodlen = SiriusLabel(
+ self, self.dev_pref.substitute(propty='PeriodLength-Cte'))
+
+ self._ld_kpark = QLabel('KParam Park Pos.', self)
+ self._lb_kpark = SiriusLabel(
+ self, self.dev_pref.substitute(propty='KParamParked-Cte'))
+
+ self._ld_ppark = QLabel('PParam Park Pos.', self)
+ self._lb_ppark = SiriusLabel(
+ self, self.dev_pref.substitute(propty='PParamParked-Cte'))
+
+ self._ld_cpark = QLabel('CParam Park Pos.', self)
+ self._lb_cpark = SiriusLabel(
+ self, self.dev_pref.substitute(propty='CParamParked-Cte'))
+
+ self._lb_park = QLabel('Start Parking', self)
+ self._pb_park = PyDMPushButton(
+ self, label='', icon=qta.icon("fa5s.parking"))
+ self._pb_park.channel = self.dev_pref.substitute(propty="StartParking-Cmd")
+ self._pb_park.pressValue = 1
+ self._pb_park.setIconSize(QSize(20, 20))
+ self._pb_park.setMaximumWidth(25)
+ self._pb_park.setStyleSheet(
+ '#Start{min-width:30px; max-width:30px; icon-size:25px;}')
+
+ auxlay = QGridLayout(auxgbox)
+ auxlay.addWidget(self._speed_lim, 0, 0)
+ auxlay.addWidget(self._spin_box_sl, 0, 1)
+ auxlay.addWidget(self._lb_spin_box_sl, 0, 2)
+ auxlay.addWidget(self._ld_periodlen, 1, 0)
+ auxlay.addWidget(self._lb_periodlen, 1, 1)
+ auxlay.addWidget(self._ld_kpark, 2, 0)
+ auxlay.addWidget(self._lb_kpark, 2, 1)
+ auxlay.addWidget(self._ld_ppark, 3, 0)
+ auxlay.addWidget(self._lb_ppark, 3, 1)
+ auxlay.addWidget(self._ld_cpark, 4, 0)
+ auxlay.addWidget(self._lb_cpark, 4, 1)
+ auxlay.addWidget(self._lb_park, 5, 0)
+ auxlay.addWidget(self._pb_park, 5, 1)
+
+ auxgbox.setStyleSheet(
+ '.QLabel{qproperty-alignment: "AlignRight | AlignVCenter";}')
+
+ group = QWidget()
+ lay = QGridLayout(group)
+ lay.setContentsMargins(0, 0, 0, 0)
+ lay.addWidget(scangroup, 0, 0)
+ lay.addWidget(auxgbox, 1, 0)
+
+ return group
+
+ def _ffSettingsWidget(self):
+ group = QGroupBox('Feedforward Settings')
+ lay = QGridLayout(group)
+
+ hlay = QHBoxLayout()
+ lb_glob = QLabel(
+ "Global Loop State:", alignment=Qt.AlignRight | Qt.AlignVCenter
+ )
+ idff_pref = _PVName(f"SI-{self.dev_pref.sub}:BS-IDFF")
+ self.bt_idffglob = PyDMStateButton(
+ self, init_channel=idff_pref.substitute(propty="LoopState-Sel")
+ )
+ self.led_idffglob = SiriusLedState(
+ self, init_channel=idff_pref.substitute(propty="LoopState-Sts")
+ )
+ hlay.addStretch()
+ hlay.addWidget(lb_glob)
+ hlay.addWidget(self.bt_idffglob)
+ hlay.addWidget(self.led_idffglob)
+ hlay.addStretch()
+ lay.addLayout(hlay, 0, 0, 1, 3)
+
+ for col, idffgroup in enumerate(["CHCV", "QS", "LC"]):
+ but = QPushButton(f'{idffgroup}', self)
+ connect_newprocess(
+ but, ['sirius-hla-si-ap-idff.py', self._device,
+ '-g', idffgroup]
+ )
+ lay.addWidget(but, 1, col)
+ return group
+
+ def _createCmdBtns(self, pv_info, lay, row):
+ btn = PyDMPushButton(self, label='', icon=qta.icon(pv_info["icon"]))
+ btn.channel = self.dev_pref.substitute(propty=pv_info["Cmd"])
+ btn.pressValue = 1
+ btn.setIconSize(QSize(20, 20))
+ btn.setMaximumWidth(25)
+ btn.setStyleSheet(
+ '#Start{min-width:30px; max-width:30px; icon-size:25px;}')
+ lay.addWidget(btn, row, 1, 1, 4)
+
+ def _createLedState(self, pv_info, lay, row):
+ pvname = self.dev_pref.substitute(propty=pv_info["StateMon"])
+ led = SiriusLedState(self, init_channel=pvname)
+ lay.addWidget(led, row, 1, alignment=Qt.AlignLeft)
+
+ def _createParam(self, pv_info, lay, row):
+ if "SP" in pv_info:
+ pvname = self.dev_pref.substitute(propty=pv_info["SP"])
+ widtype = SiriusEnumComboBox if pvname.endswith('Sel') \
+ else SiriusLineEdit
+ cb = widtype(self, init_channel=pvname)
+ lay.addWidget(cb, row, 1, 1, 1)
+
+ for col, key in {2: "RB", 3: "Mon"}.items():
+ if key not in pv_info:
+ continue
+ pvname = self.dev_pref.substitute(propty=pv_info[key])
+ lbl = SiriusLabel(self, init_channel=pvname, keep_unit=True)
+ lbl.setMinimumWidth(125)
+ lbl.showUnits = True
+ lbl.setAlignment(Qt.AlignCenter)
+ lay.addWidget(lbl, row, col, 1, 1)
+
+
+class UESummaryBase(IDCommonSummaryBase):
+ """UE Summary Base Widget."""
+
+ MODEL_WIDTHS = (
+ ('Device Status', 4),
+ ('KParam', 6),
+ ('Speed', 6),
+ ('Start', 4),
+ ('Stop', 4),
+ )
+
+
+class UESummaryHeader(IDCommonSummaryHeader, UESummaryBase):
+ """UE Summary Header."""
+
+
+class UESummaryWidget(IDCommonSummaryWidget, UESummaryBase):
+ """UE Summary Widget."""
+
+ def _get_widgets(self, prop):
+ wids, orientation = super()._get_widgets(prop)
+ if prop == 'Device Status':
+ led = SiriusLedAlert(
+ self, self.dev_pref.substitute(propty='DeviceStatus-Mon'))
+ wids.append(led)
+ elif prop == 'KParam':
+ spb = SiriusSpinbox(
+ self, self.dev_pref.substitute(propty='KParam-SP'))
+ wids.append(spb)
+ lbl = SiriusLabel(
+ self, self.dev_pref.substitute(propty='KParam-Mon'))
+ wids.append(lbl)
+ elif prop == 'Speed':
+ spb = SiriusLineEdit(
+ self, self.dev_pref.substitute(propty='Velo-SP'))
+ wids.append(spb)
+ lbl = SiriusLabel(
+ self, self.dev_pref.substitute(propty='Velo-RB'))
+ wids.append(lbl)
+ elif prop == 'Start':
+ btn = PyDMPushButton(self, label='', icon=qta.icon('fa5s.play'))
+ btn.channel = self.dev_pref.substitute(propty='DevCtrl-Cmd')
+ btn.pressValue = 120
+ btn.setObjectName('Start')
+ btn.setStyleSheet(
+ '#Start{min-width:30px; max-width:30px; icon-size:25px;}')
+ wids.append(btn)
+ elif prop == 'Stop':
+ btn = PyDMPushButton(self, label='', icon=qta.icon('fa5s.stop'))
+ btn.setToolTip('Stop all motion, lock all brakes.')
+ btn.channel = self.dev_pref.substitute(propty='Abort-Cmd')
+ btn.pressValue = 1
+ btn.setObjectName('Stop')
+ btn.setStyleSheet(
+ '#Stop{min-width:30px; max-width:30px; icon-size:25px;}')
+ wids.append(btn)
+ return wids, orientation
+
+
+class UEDetails(IDCommonDialog):
+ """UE Drive Details"""
+
+ def __init__(self, parent=None, prefix='', device=''):
+ """Init."""
+ super().__init__(
+ parent, prefix, device, title=device+' Servo Motors and General Status Details')
+
+ def _setupUi(self):
+ ld_pos = QLabel('Pos.
', self)
+ ld_posmin = QLabel('Min Pos.
', self)
+ ld_posmax = QLabel('Max Pos.
', self)
+ ld_ncstate = QLabel('NC State
', self)
+ ld_ncerror = QLabel('NC Error', self)
+ ld_status = QLabel('StatusIO
', self)
+ ld_temp = QLabel('Temperature
', self)
+
+ gbox = QGroupBox('Status Details', self)
+ glay = QGridLayout(gbox)
+ glay.addWidget(ld_pos, 1, 0)
+ glay.addWidget(ld_posmin, 2, 0)
+ glay.addWidget(ld_posmax, 3, 0)
+ glay.addWidget(ld_ncstate, 4, 0)
+ glay.addWidget(ld_ncerror, 5, 0)
+ glay.addWidget(ld_status, 6, 0)
+ glay.addWidget(ld_temp, 7, 0)
+
+ details = [
+ "KParam",
+ "PParam",
+ "CParam",
+ "Offset",
+ "KShift",
+ "PShift",
+ "TI",
+ "TO",
+ "BI",
+ "BO",
+ ]
+
+ for idx, title in enumerate(details):
+ col = idx + 1
+ posname = 'Pos' if title not in \
+ ['KParam', 'PParam', 'CParam', 'Offset'] else ''
+ ld_dtl = QLabel(''+title+'
', self)
+
+ if title not in ['KShift', 'PShift']:
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}{posname}-Mon')
+ lb_pos = SiriusLabel(self, pvname)
+ else:
+ lb_pos = QLabel("-", self)
+
+ if title in ['KParam', 'PParam', 'CParam', 'Offset']:
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}MinPos-Cte')
+ lb_posmin = SiriusLabel(self, pvname)
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}MaxPos-Cte')
+ lb_posmax = SiriusLabel(self, pvname)
+ else:
+ lb_posmin = QLabel("-", self)
+ lb_posmax = QLabel("-", self)
+
+ if title not in ['KParam', 'PParam']:
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}StateNC-Mon')
+ lb_ncstate = SiriusLabel(self, pvname)
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}ErrorNC-Mon')
+ lb_ncerror = SiriusLabel(self, pvname)
+ else:
+ lb_ncstate = QLabel("-", self)
+ lb_ncerror = QLabel("-", self)
+
+ if title in ["TI", "TO", "BI", "BO"]:
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}StatusIO-Mon')
+ lb_status = SiriusLabel(self, pvname)
+ pvname = self.dev_pref.substitute(
+ propty=f'{title}Temp-Mon')
+ lb_temp = SiriusLabel(self, pvname)
+ else:
+ lb_status = QLabel("-", self)
+ lb_temp = QLabel("-", self)
+
+ glay.addWidget(ld_dtl, 0, col)
+ glay.addWidget(lb_pos, 1, col)
+ glay.addWidget(lb_posmin, 2, col)
+ glay.addWidget(lb_posmax, 3, col)
+ glay.addWidget(lb_ncstate, 4, col)
+ glay.addWidget(lb_ncerror, 5, col)
+ glay.addWidget(lb_status, 6, col)
+ glay.addWidget(lb_temp, 7, col)
+
+ gbox.setStyleSheet(
+ 'QLabel{qproperty-alignment: AlignCenter; max-width: 12em;}')
+ lay = QHBoxLayout(self)
+ lay.addWidget(gbox)