Skip to content

Commit

Permalink
Merge pull request #716 from lnls-sirius/ivu_feedforward
Browse files Browse the repository at this point in the history
IVU Feedforward GUI
  • Loading branch information
anacso17 authored Nov 1, 2024
2 parents cc365bb + a09bcf8 commit c0b95a5
Show file tree
Hide file tree
Showing 2 changed files with 188 additions and 10 deletions.
26 changes: 26 additions & 0 deletions pyqt-apps/siriushla/si_ap_idff/custom_widgets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"""Custom widgets."""

import numpy as np

from qtpy.QtCore import Qt, Slot

from pydm.widgets import PyDMLineEdit
from pydm.widgets.waveformplot import WaveformCurveItem

from ..as_ap_configdb import LoadConfigDialog as _LoadConfigDialog

Expand All @@ -19,3 +24,24 @@ def _config_changed(self, configname):
self.setText(configname)
self.send_value()
self.value_changed(configname)


class SectionedWaveformCurveItem(WaveformCurveItem):

GAP_MIN = 0 # [mm]
GAP_MAX = 24 # [mm]

def __init__(self, section, **kwargs):
super().__init__(**kwargs)
self.section = section

@Slot(np.ndarray)
def receiveYWaveform(self, new_waveform):
size = len(new_waveform)/4
min = int(size*self.section)
max = int(size*(self.section+1))
ydata = new_waveform[min:max]
npts = len(ydata)
xdata = self.GAP_MIN + (self.GAP_MAX - self.GAP_MIN) * np.arange(0, npts) / (npts - 1)
super().receiveXWaveform(xdata)
super().receiveYWaveform(ydata)
172 changes: 162 additions & 10 deletions pyqt-apps/siriushla/si_ap_idff/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"""Main window."""

from time import strftime, localtime

from qtpy.QtCore import Qt
from qtpy.QtWidgets import QLabel, QGridLayout, QSizePolicy as QSzPlcy, \
QWidget, QGroupBox, QVBoxLayout, QPushButton, QSpacerItem
QWidget, QGroupBox, QHBoxLayout, QVBoxLayout, QPushButton, QSpacerItem, \
QRadioButton, QButtonGroup, QStackedWidget
from qtpy.QtGui import QColor

import qtawesome as qta

Expand All @@ -15,12 +19,13 @@

from ..util import connect_window
from ..widgets import SiriusMainWindow, SiriusLabel, SiriusSpinbox, \
PyDMStateButton, SiriusLedState, PyDMLogLabel, SiriusLedAlert
PyDMStateButton, SiriusLedState, PyDMLogLabel, SiriusLedAlert, \
SiriusConnectionSignal, SiriusWaveformPlot
from ..widgets.dialog import StatusDetailDialog
from ..as_ps_control.control_widget.ControlWidgetFactory import \
ControlWidgetFactory
from ..as_ps_control import PSDetailWindow
from .custom_widgets import ConfigLineEdit
from .custom_widgets import ConfigLineEdit, SectionedWaveformCurveItem
from .util import get_idff_icon


Expand All @@ -32,10 +37,12 @@ def __init__(self, parent=None, prefix='', idname=''):
super().__init__(parent)
self.prefix = prefix or _VACA_PREFIX
self.idname = idname
self._const = IDFFConst(idname)
self._is_ivu = "IVU" in idname
self._idffname = IDFFConst(idname).idffname
self._idffdata = IDSearch.conv_idname_2_idff(self.idname)
self.device = _PVName(self._const.idffname)
self.dev_pref = self.device.substitute(prefix=prefix)
self.device = _PVName(self._idffname)
self.dev_pref = _PVName(f"SI-{self.device.sub}:BS-IDFF-CHCV:") if self._is_ivu else \
self.device.substitute(prefix=prefix)
self.setObjectName('IDApp')
self.setWindowTitle(self.device)
self.setWindowIcon(get_idff_icon())
Expand All @@ -50,13 +57,157 @@ def _setupUi(self):
wid = QWidget()
lay = QGridLayout(wid)
lay.addWidget(self.title, 0, 0, 1, 2)
lay.addWidget(self._idStatusWidget(), 1, 0)
lay.addWidget(self._corrStatusWidget(), 2, 0)
lay.addWidget(self._basicSettingsWidget(), 3, 0)
lay.addWidget(self._logWidget(), 4, 0)
if not self._is_ivu:
lay.addWidget(self._idStatusWidget(), 1, 0)
lay.addWidget(self._corrStatusWidget(), 2, 0)
lay.addWidget(self._basicSettingsWidget(), 3, 0)
lay.addWidget(self._logWidget(), 4, 0)
else:
lay.addWidget(self._ivuStatusWidget(), 1, 0, 1, 1)
lay.addWidget(self._ivuSettingsWidget(), 2, 0, 3, 1)
lay.addWidget(self._corrsMonitorWidget(), 1, 1, 4, 1)
self.setCentralWidget(wid)

def _ivuStatusWidget(self):
gbox = QGroupBox('ID Status', self)
hlay = QHBoxLayout(gbox)

lbl_gap = QLabel(
'Gap: ', self)
gap_val = SiriusLabel(
self, self.dev_pref.substitute(propty='IDPos-Mon'))
gap_val.showUnits = True

hlay.addWidget(lbl_gap)
hlay.addWidget(gap_val)

return gbox

def _format_timestamp_label(self, value):
self.timestamp.setText(strftime(
'%Y-%m-%d %H:%M:%S', localtime(value/1000)))

def _ivuSettingsWidget(self):
gbox = QGroupBox('Settings', self)
lay = QGridLayout(gbox)

ld_loopstate = QLabel('Loop State: ', self)
self.sb_loopstate = PyDMStateButton(
self, self.dev_pref.substitute(propty='LoopState-Sel'))
self.lb_loopstate = SiriusLedState(
self, self.dev_pref.substitute(propty='LoopState-Sts'))

lbl_table_pointer = QLabel('Table Pointer: ', self)
self.table_pointer = SiriusLabel(
self, self.dev_pref.substitute(propty='TablePointer-Mon'))

lbl_alarm = QLabel('Alarm: ', self)
self.alarm_led = SiriusLedState(
self, self.dev_pref.substitute(propty='Alarms-Mon'))

alarm_details = QPushButton('', self)
alarm_details.setIcon(qta.icon('fa5s.list-ul'))
alarm_details.setToolTip('Open Detailed Alarms View')
alarm_details.setObjectName('sts')
alarm_details.setStyleSheet(
'#sts{min-width:25px; max-width:25px; icon-size:20px;}')
connect_window(
alarm_details, StatusDetailDialog, parent=self,
pvname=self.dev_pref.substitute(propty='Alarms-Mon'),
labels=["Mode/Polar. out of range", "Gap/phase out of range",
"Gap/phase high deviation", "Timeout for serial data"],
section='ID', title='FeedForward Status')

self.clear_alarms = PyDMPushButton(
self, "Clear Alarms",
init_channel=self.dev_pref.substitute(propty='ClearFlags-Cmd'))

lbl_plc_counter = QLabel('PLC Counter: ', self)
self.plc_counter = SiriusLabel(
self, self.dev_pref.substitute(propty='PLCCounter-Mon'))

lbl_timestamp = QLabel('PLC Timestamp: ', self)
self.timestamp = QLabel('0:00:00', self)
self.timestamp_mon = SiriusConnectionSignal(
self.dev_pref.substitute(propty='PLCTimestamp-Mon'))
self.timestamp_mon.new_value_signal[float].connect(
self._format_timestamp_label)

buttonGroupWid = QWidget()
vlay = QVBoxLayout(buttonGroupWid)
self.button_group = QButtonGroup(buttonGroupWid)
self.button_group.buttonClicked.connect(lambda btn: self.stack.setCurrentIndex(self.button_group.id(btn)))

self.stack = QStackedWidget()
self.plot_dict = {}
for idx, name in enumerate(["CH1", "CH2", "CV1", "CV2"]):
channel_btn = QRadioButton(name)
vlay.addWidget(channel_btn)
self.button_group.addButton(channel_btn, idx)

if name == "CH1":
channel_btn.setChecked(True)

graph = SiriusWaveformPlot()
graph.setShowLegend(True)
graph.autoRangeX = True
graph.autoRangeY = True
graph.showXGrid = True
graph.showYGrid = True
graph.showLegend = True
graph.setLabel('bottom', text='Index')
graph.setLabel('left', text='Current [A]')
graph.setBackgroundColor(QColor(255, 255, 255))
self.addNewTableCurve(graph, name, idx)
self.stack.addWidget(graph)
self.plot_dict[name] = graph

lay.addWidget(ld_loopstate, 0, 0)
lay.addWidget(self.sb_loopstate, 0, 1)
lay.addWidget(self.lb_loopstate, 0, 2)
lay.addWidget(lbl_table_pointer, 1, 0)
lay.addWidget(self.table_pointer, 1, 1, 1, 2)
lay.addWidget(lbl_alarm, 2, 0)
lay.addWidget(self.alarm_led, 2, 1)
lay.addWidget(alarm_details, 2, 2)
lay.addWidget(self.clear_alarms, 3, 0, 1, 3)
lay.addWidget(lbl_plc_counter, 4, 0)
lay.addWidget(self.plc_counter, 4, 1, 1, 2)
lay.addWidget(lbl_timestamp, 5, 0)
lay.addWidget(self.timestamp, 5, 1, 1, 2)
lay.addWidget(buttonGroupWid, 6, 0)
lay.addWidget(self.stack, 6, 1, 1, 2)

return gbox

def addNewTableCurve(self, plt, name, section):
if 'CH' in name:
color_sp, color_rb = 'blue', 'darkBlue'
else:
color_sp, color_rb = 'red', 'darkRed'

curve_sp = SectionedWaveformCurveItem(
section=section,
y_addr=self.dev_pref.substitute(propty='Table-SP'),
name="SP",
color=QColor(color_sp),
)
plt._needs_redraw = False
plt.addCurve(curve_sp, curve_color=QColor(color_sp))
curve_sp.data_changed.connect(plt.set_needs_redraw)

curve_rb = SectionedWaveformCurveItem(
section=section,
y_addr=self.dev_pref.substitute(propty='Table-RB'),
name="RB",
color=QColor(color_rb),
)
plt._needs_redraw = False
plt.addCurve(curve_rb, curve_color=QColor(color_rb))
curve_rb.data_changed.connect(plt.set_needs_redraw)

return plt

def _basicSettingsWidget(self):
ld_configname = QLabel(
'Config. Name: ', self, alignment=Qt.AlignRight)
Expand Down Expand Up @@ -193,6 +344,7 @@ def _idStatusWidget(self):
lay.addItem(QSpacerItem(0, 15, QSzPlcy.Ignored, QSzPlcy.Fixed), 2, 0)
lay.addWidget(ld_polar, 3, 0)
lay.addWidget(self.lb_polar, 3, 1, 1, 3)

return gbox

def _logWidget(self):
Expand Down

0 comments on commit c0b95a5

Please sign in to comment.