9 Commits

9 changed files with 6026 additions and 282 deletions

10
.gitignore vendored
View File

@@ -1,5 +1,7 @@
# Temporary editor files #
##########################
*~
*.-*
*.*:*
*.*-
*.*-*
*.-*
__pycache__
__pycache__/*.*

Binary file not shown.

Binary file not shown.

View File

@@ -96,6 +96,7 @@ class PVGateway(QWidget):
notify_unison: bool = False, precision: int = 0,
monitor_dbr_time: bool = False):
super().__init__()
if parent is None:
@@ -120,6 +121,8 @@ class PVGateway(QWidget):
self.color_mode = None
self.check_rtyp = False
if color_mode is not None:
if color_mode in (self.ACT_ON_BEAM,
self.NOT_ACT_ON_BEAM,
@@ -129,6 +132,10 @@ class PVGateway(QWidget):
self.color_mode_requested = self.color_mode
#if 'READ' in self.pv_name:
#print('color mode',self.pv_name, self.color_mode,
#self.color_mode_requested )
if monitor_callback is not None:
self.monitor_callback = monitor_callback
else:
@@ -143,9 +150,13 @@ class PVGateway(QWidget):
self.cafe = self.parent.cafe
self.cyca = self.parent.cyca
self.url_archiver = None
self.url_databuffer = None
if self.parent.settings is not None:
self.url_archiver = self.parent.settings.data["url"]["archiver"]
self.url_databuffer = self.parent.settings.data["url"]["databuffer"]
if "databuffer" in self.parent.settings.data["url"]:
self.url_databuffer = self.parent.settings.data["url"]["databuffer"]
self.bg_readback = self.parent.settings.data["StyleGuide"][
"bgReadback"]
self.fg_alarm_major = self.parent.settings.data["StyleGuide"][
@@ -158,10 +169,10 @@ class PVGateway(QWidget):
"fgAlarmNoAlarm"]
else:
#self.settings = ReadJSON(self.parent.appname)
self.url_archiver = ("https://ui-data-api.psi.ch/prepare?channel=" +
self.url_archiver = ("https://data-ui.psi.ch/preselect?c1=" +
"sf-archiverappliance/")
self.url_databuffer \
= "https://ui-data-api.psi.ch/prepare?channel=sf-databuffer/"
= "https://data-ui.psi.ch/preselect?c1=sf-databuffer/"
self.daq_group_name = self._DAQ_CAFE_SG_NAME
self.desc = None
@@ -176,6 +187,7 @@ class PVGateway(QWidget):
self.monitor_id = None
self.monitor_dbr_time = monitor_dbr_time
self.mutex_post_display = QMutex()
self.mutex = QMutex()
self.precision_user = precision
self.has_precision_user = bool(precision)
@@ -266,23 +278,20 @@ class PVGateway(QWidget):
action1 = QAction("Text Info", self)
action1.triggered.connect(self.pv_status_text)
self.context_menu.addAction(action1)
action2 = QAction("Lookup in Archiver", self)
action2.triggered.connect(self.lookup_archiver)
action3 = QAction("Lookup in Databuffer", self)
action3.triggered.connect(self.lookup_databuffer)
self.context_menu.addAction(action2)
if self.url_databuffer is not None:
action3 = QAction("Lookup in Databuffer", self)
action3.triggered.connect(self.lookup_databuffer)
self.context_menu.addAction(action3)
action4 = QAction("Strip Chart (PShell)", self)
action4.triggered.connect(self.strip_chart)
self.context_menu.addAction(action4)
action6 = QAction("Configure Display Parameters", self)
action6.triggered.connect(self.display_parameters)
self.context_menu.addAction(action1)
self.context_menu.addAction(action2)
self.context_menu.addAction(action3)
self.context_menu.addAction(action4)
action5 = QAction("Reconnect: {0}".format(self.pv_name), self)
action5.triggered.connect(self.reconnect_channel)
@@ -310,6 +319,7 @@ class PVGateway(QWidget):
#The __init__ method of a class is used to initialize new objects,
#not create them. As such, it should not return any value.
return #self # used by pvgateway in CAQStripChart
@@ -378,7 +388,7 @@ class PVGateway(QWidget):
if self.pv_info is None:
self.pv_info = self.cafe.getChannelInfo(self.pv_name)
if "Not Supported" in self.pv_info.className:
if "Not Supported" in self.pv_info.className and self.check_rtyp:
_rtype = self.cafe.get(self.pv_name.split(".")[0] + ".RTYP")
self.record_type = _rtype if _rtype is not None else \
self.pv_info.className
@@ -411,8 +421,9 @@ class PVGateway(QWidget):
_max_control_abs = 0
if self.pv_ctrl is not None:
_lower_control_abs = abs(int(self.pv_ctrl.lowerControlLimit))
_upper_control_abs = abs(int(self.pv_ctrl.upperControlLimit))
#DisplayLimit preferred over ControlLimit as latter n/a for ao
_lower_control_abs = abs(int(self.pv_ctrl.lowerDisplayLimit))
_upper_control_abs = abs(int(self.pv_ctrl.upperDisplayLimit))
_max_control_abs = max(_lower_control_abs, _upper_control_abs)
if _max_control_abs is None:
_max_control_abs = 0
@@ -487,7 +498,7 @@ class PVGateway(QWidget):
time.sleep(0.01)
self.initialize_meta_data()
icount += 1
if icount > 50:
if icount > 5: #50
return False
return True
@@ -576,7 +587,7 @@ class PVGateway(QWidget):
self.pv_ctrl = self.cafe.getCtrlCache(self.handle)
self.pv_info = self.cafe.getChannelInfo(self.handle)
if self.pv_info is not None and self.record_type is None:
if "Not Supported" in self.pv_info.className:
if "Not Supported" in self.pv_info.className and self.check_rtyp:
_rtype = self.cafe.get(self.pv_name.split(".")[0] + ".RTYP")
self.record_type = _rtype if _rtype is not None else \
self.pv_info.className
@@ -754,6 +765,7 @@ class PVGateway(QWidget):
'''Callback function to be invoked on change of pv value.
cafe.getCache and cafe.set operations permitted within callback.
'''
self.mutex.lock()
pv_name = pvname
pvd = pvdata
@@ -785,8 +797,8 @@ class PVGateway(QWidget):
else:
self.trigger_monitor_float.emit(float(pvd.value[0]), pvd.status,
_alarm_severity)
self.mutex.unlock()
def monitor_start(self):
'''Initiate monitor on pv.'''
if self.handle > 0:
@@ -942,6 +954,8 @@ class PVGateway(QWidget):
elif self.qt_object_name == self.PV_DAQ_BS:
self.color_mode = self.READBACK_STATIC
#if 'READ' in self.pv_name:
# print('color mode',self.pv_name, self.color_mode)
self._qt_dynamic_property_set(self.color_mode)
else:
@@ -1332,7 +1346,7 @@ class PVGateway(QWidget):
if self.pv_info is None:
self.pv_info = self.cafe.getChannelInfo(self.handle)
if self.pv_info is not None and self.record_type is None:
if "Not Supported" in self.pv_info.className:
if "Not Supported" in self.pv_info.className and self.check_rtyp:
_rtype = self.cafe.get(self.pv_name.split(".")[0] + ".RTYP")
self.record_type = _rtype if _rtype is not None else \
self.pv_info.className
@@ -1376,7 +1390,7 @@ class PVGateway(QWidget):
if self.pv_info is None:
self.pv_info = self.cafe.getChannelInfo(self.handle)
if self.pv_info is not None and self.record_type is None:
if "Not Supported" in self.pv_info.className:
if "Not Supported" in self.pv_info.className and self.check_rtyp:
_rtype = self.cafe.get(self.pv_name.split(".")[0] + ".RTYP")
self.record_type = _rtype if _rtype is not None else \
self.pv_info.className
@@ -1481,8 +1495,7 @@ class PVGateway(QWidget):
self.pv_status_text_display_limits())
self.pv_message_in_a_box.setText(
self.pv_status_text_header(source=_source) + _text_data
)
self.pv_status_text_header(source=_source) + _text_data)
QApplication.processEvents()
self.pv_message_in_a_box.exec()

View File

@@ -96,14 +96,17 @@ class PVGateway(QWidget):
notify_unison: bool = False, precision: int = 0,
monitor_dbr_time: bool = False):
super().__init__()
if parent is None:
return
if not pv_name:
return
self.connect_callback = connect_callback
self.notify_freq_hz = abs(notify_freq_hz)
self.notify_freq_hz_default = self.notify_freq_hz
@@ -307,8 +310,11 @@ class PVGateway(QWidget):
self.pv_message_in_a_box.setDefaultButton(QMessageBox.Close)
self.initialize()
#return self - previously used by pvgateway
#The __init__ method of a class is used to initialize new objects,
#not create them. As such, it should not return any value.
return #self # used by pvgateway in CAQStripChart
def initialize(self):

1910
pvgateway.py:2.9 Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,28 @@
''' Module with channel access enabled QtWidgets.'''
__author__ = 'Jan T. M. Chrin'
import collections
import numpy as np
import re
from threading import Lock
import time
import collections
import numpy as np
from sklearn.linear_model import LinearRegression
from distutils.version import LooseVersion
from functools import reduce as func_reduce
from qtpy.QtCore import QEventLoop, QPoint, Qt, QThread, QTimer, Signal, Slot
from qtpy.QtGui import (QCloseEvent, QColor, QCursor, QFont, QFontMetricsF,
QIcon, QKeySequence)
from qtpy.QtCore import (
QEventLoop, QMutex, QPoint, Qt, QThread, QTimer, Signal, Slot)
from qtpy.QtGui import (
QCloseEvent, QColor, QCursor, QFont, QFontMetricsF, QIcon, QKeySequence)
from qtpy.QtCore import __version__ as QT_VERSION_STR
from qtpy.QtWidgets import (QAbstractItemView, QAbstractSpinBox, QAction,
QApplication, QBoxLayout, QCheckBox, QComboBox,
QDialog, QDockWidget, QDoubleSpinBox, QFrame,
QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QListWidget, QMenu, QMessageBox, QPushButton,
QSpinBox, QStyle, QStyleOptionSpinBox, QTableWidget,
QTableWidgetItem, QVBoxLayout, QWidget)
from qtpy.QtWidgets import (
QAbstractItemView, QAbstractSpinBox, QAction, QApplication, QBoxLayout,
QCheckBox, QComboBox, QDialog, QDockWidget, QDoubleSpinBox, QFrame,
QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QMenu, QMessageBox,
QPushButton, QSpinBox, QStyle, QStyleOptionSpinBox, QTableWidget,
QTableWidgetItem, QVBoxLayout, QWidget)
import pyqtgraph as pg
from pyqtgraph import PlotWidget
@@ -129,6 +131,7 @@ class CAQLineEdit(QLineEdit, PVGateway):
_width_scaling_factor = 1.15
self.setFixedHeight((fm.lineSpacing()*1.8))
self.setFixedWidth(((qrect.width()) * _width_scaling_factor))
if self.pv_within_daq_group:
self.qt_property_initial_values(qt_object_name=self.PV_DAQ_CA)
@@ -284,7 +287,6 @@ class CAQMenu(QComboBox, PVGateway):
def post_display_value(self, value):
'''Convert value to index'''
if "setCurrentIndex" in dir(self):
@@ -294,7 +296,6 @@ class CAQMenu(QComboBox, PVGateway):
if isinstance(value, str):
self.setCurrentIndex(self.cafe.getEnumFromString(self.handle,
value))
elif isinstance(value, int):
self.setCurrentIndex(value)
#Should not happen
@@ -462,13 +463,13 @@ class CAQMessageButton(QPushButton, PVGateway):
self.setFocusPolicy(Qt.StrongFocus)
self.setCheckable(True) #Recognizes press and release states
fm = QFontMetricsF(QFont("Sans Serif", 12))
fm = QFontMetricsF(QFont("Sans Serif", 10))
qrect = fm.boundingRect(self.suggested_text)
_width_scaling_factor = 1.0
self.setText(self.msg_label)
self.setFixedHeight((fm.lineSpacing()*2.0))
self.setFixedHeight((fm.lineSpacing()*1.8))
self.setFixedWidth((qrect.width() * _width_scaling_factor))
self.qt_property_initial_values(qt_object_name=self.PV_CONTROLLER)
@@ -987,6 +988,8 @@ class CAQDoubleSpinBox(QDoubleSpinBox, PVGateway):
def mouseReleaseEvent(self, event):
self.clearFocus()
self.lineEdit().clearFocus()
def setValue(self, value):
self.currentValue = self.value()
@@ -1044,14 +1047,18 @@ class CAQDoubleSpinBox(QDoubleSpinBox, PVGateway):
self.qt_style_polish()
self.clearFocus()
self.lineEdit().clearFocus()
self.lineEdit().setFocusPolicy(Qt.NoFocus)
self.setFocusPolicy(Qt.NoFocus)
del event
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
QDoubleSpinBox.keyPressEvent(self, event)
self.clearFocus()
self.lineEdit().clearFocus()
self.lineEdit().setFocusPolicy(Qt.NoFocus)
self.setFocusPolicy(Qt.NoFocus)
elif event.key() in (Qt.Key_Up, Qt.Key_Down):
QDoubleSpinBox.keyPressEvent(self, event)
else:
@@ -1098,16 +1105,29 @@ class reconnectQPushButton(QPushButton, QThread):
def reconnect(self):
QApplication.processEvents()
print("Reconnect")
self.isdirty = True
if self._handles_to_reconnect:
print("handles to reconnect", self._handles_to_reconnect, flush=True)
self.parent.cafe.reconnect(self._handles_to_reconnect)
print("handles reconnected", self._handles_to_reconnect, flush=True)
self.isdirty = False
#Uncheck reconnected channels
for i in range(0, len(self.parent.pv_gateway)):
#print(i, len(self.parent.pv_gateway), flush=True)
#print( "ischecked", self.parent.item(
# i, self.parent.no_columns-1).checkState(), Qt.Checked )
#print("Connected", self.parent.cafe.isConnected(
# self.parent.pv_gateway[i].handle), flush=True)
if self.parent.item(
i, self.parent.no_columns-1).checkState() == Qt.Checked:
if self.parent.cafe.isConnected(
self.parent.pv_gateway[i].handle):
#print("isConnected", flush=True)
self.parent.item(
i, self.parent.no_columns-1).setCheckState(False)
else:
#Even if not connected - uncheck box as action is complete
self.parent.item(
i, self.parent.no_columns-1).setCheckState(False)
@@ -1194,9 +1214,10 @@ class CAQTableWidget(QTableWidget):
def widget_update(self):
for _row, pvgate in enumerate(self.pv_gateway):
#for _row in range(0, len(self.pv_gateway)):
if not pvgate.notify_unison:
continue
_handle = pvgate.handle
_pvd = pvgate.cafe.getPVCache(_handle)
@@ -1216,10 +1237,14 @@ class CAQTableWidget(QTableWidget):
f.setPointSize(8)
qtwi.setFont(f)
self.setItem(_row, self.no_columns-3,
val_col_no = self.columns_dict['Value']
if self.show_timestamp:
ts_col_no = self.columns_dict['Timestamp']
self.setItem(_row, val_col_no,
QTableWidgetItem(qtwi))
self.item(_row, self.no_columns-3).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
self.item(_row, val_col_no).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
_ts_date = _pvd.tsDateAsString
_ts_str_len = len(_ts_date)
@@ -1245,8 +1270,9 @@ class CAQTableWidget(QTableWidget):
f.setPointSize(8)
qtwi.setFont(f)
self.setItem(_row, self.no_columns-2, QTableWidgetItem(qtwi))
self.item(_row, self.no_columns-2).setTextAlignment(Qt.AlignCenter)
if self.show_timestamp:
self.setItem(_row, ts_col_no, QTableWidgetItem(qtwi))
self.item(_row, ts_col_no).setTextAlignment(Qt.AlignCenter)
_prop = pvgate.qt_dynamic_property_get()
@@ -1268,31 +1294,29 @@ class CAQTableWidget(QTableWidget):
_fgcolor = "black"
#Colors for bg/fg reversed as is the old norm
self.item(_row, self.no_columns-3).setBackground(
QColor(_bgcolor))
self.item(_row, self.no_columns-2).setBackground(
QColor(_bgcolor))
self.item(_row, self.no_columns-3).setForeground(
QColor(_fgcolor))
self.item(_row, self.no_columns-2).setForeground(
QColor(_fgcolor))
self.item(_row, val_col_no).setBackground(QColor(_bgcolor))
self.item(_row, val_col_no).setForeground(QColor(_fgcolor))
if self.show_timestamp:
self.item(_row, ts_col_no).setBackground(QColor(_bgcolor))
self.item(_row, ts_col_no).setForeground(QColor(_fgcolor))
elif _prop == pvgate.READBACK_STATIC:
self.item(_row, self.no_columns-3).setBackground(
QColor(pvgate.bg_readback))
self.item(_row, self.no_columns-2).setBackground(
self.item(_row, val_col_no).setBackground(
QColor(pvgate.bg_readback))
if self.show_timestamp:
self.item(_row, ts_col_no).setBackground(
QColor(pvgate.bg_readback))
elif _prop == pvgate.DISCONNECTED:
self.item(_row, self.no_columns-3).setBackground(
self.item(_row, val_col_no).setBackground(
QColor("#ffffff"))
self.item(_row, self.no_columns-2).setBackground(
QColor("#ffffff"))
self.item(_row, self.no_columns-3).setForeground(
QColor("#777777"))
self.item(_row, self.no_columns-2).setForeground(
self.item(_row, val_col_no).setForeground(
QColor("#777777"))
if self.show_timestamp:
self.item(_row, ts_col_no).setBackground(QColor("#ffffff"))
self.item(_row, ts_col_no).setForeground(QColor("#777777"))
else:
print(_prop, "widget_update unknown in element/row", _row,
@@ -1305,6 +1329,8 @@ class CAQTableWidget(QTableWidget):
color_mode=None, show_units: bool = True, prefix: str = "",
suffix: str = "", ts_res: str = "milli",
init_column: bool = False, init_list: list = [],
standby_column: bool = False, standby_list: list = [],
standby_values: list = [], set_delay: float = 0.0,
notify_freq_hz: int = 0, notify_unison: bool = True,
precision: int = 0, scale_factor: float = 1,
show_timestamp: bool = True, pv_list_show: list = None):
@@ -1312,27 +1338,47 @@ class CAQTableWidget(QTableWidget):
super().__init__()
self.columns_dict = {}
_column_dict_value = 0
self.columns_dict['PV'] = _column_dict_value
if init_column:
if pv_list_show is not None:
if pv_list_show[0]:
self.columns_dict['PV'] = _column_dict_value
_column_dict_value += 1
else:
self.columns_dict['PV'] = _column_dict_value
_column_dict_value += 1
if init_column:
self.columns_dict['Init'] = _column_dict_value
_column_dict_value += 1
_column_dict_value += 1
if standby_column:
self.columns_dict['Standby'] = _column_dict_value
_column_dict_value += 1
self.columns_dict['Value'] = _column_dict_value
if show_timestamp:
_column_dict_value += 1
self.columns_dict['Timestamp'] = _column_dict_value
_column_dict_value += 1
self.columns_dict['Reconnect'] = _column_dict_value
self.setWindowModality(Qt.ApplicationModal)
self.no_columns = _column_dict_value + 1
self.no_columns = _column_dict_value + 1
self.init_column = init_column
self.init_list = init_list
if self.init_column and not self.init_list:
self.init_list = pv_list
self.standby_column = standby_column
self.standby_list = standby_list
if self.standby_column and not self.standby_list:
self.standby_list = pv_list
self.standby_values = standby_values
self.set_delay = set_delay
self.icount = 0
self.notify_freq_hz = abs(notify_freq_hz)
self.notify_freq_hz_default = self.notify_freq_hz
@@ -1374,9 +1420,13 @@ class CAQTableWidget(QTableWidget):
_color_mode = [None] * len(self.pv_list)
if isinstance(color_mode, list):
for i in range(0, len(color_mode)):
_color_mode[i] = color_mode[i]
if color_mode is not None:
if isinstance(color_mode, list):
for i in range(0, len(color_mode)):
_color_mode[i] = color_mode[i]
else:
for i in range(0, len(_color_mode)):
_color_mode[i] = color_mode
for i in range(0, len(self.pv_list)):
@@ -1412,6 +1462,7 @@ class CAQTableWidget(QTableWidget):
self.timer.singleShot(0, self.widget_update)
self.timer.start(self.notify_milliseconds)
self.reconnect_button = None
self.configure_widget()
#Connect only deals with colours - only helps on reconnect
@@ -1427,7 +1478,11 @@ class CAQTableWidget(QTableWidget):
if not self.pv_gateway[i].pv_within_daq_group:
self.pv_gateway[i].monitor_start()
self.update_init_values()
if init_column:
self.update_init_values()
if standby_column:
self.update_standby_values()
self.configure_context_menu()
@@ -1450,7 +1505,108 @@ class CAQTableWidget(QTableWidget):
QApplication.processEvents()
def set_standby_values(self, pv_list: list = []):
if self.init_column:
self.init_value_button.setEnabled(False)
self.restore_value_button.setEnabled(False)
_text = self.standby_value_button.text()
self.standby_value_button.setText("Downing")
self.standby_value_button.setEnabled(False)
if self.reconnect_button is not None:
self.reconnect_button.setEnabled(False)
_set_values_dict = self.get_standby_values()
#return 1,2,3
if not pv_list:
_pvs_to_set, _values_to_set = zip(*_set_values_dict.items())
#zip returns tuples
_pvs_to_set = list(_pvs_to_set)
_values_to_set = list(_values_to_set)
else:
_pvs_to_set = []
_values_to_set = []
for pv in pv_list:
if pv in _set_values_dict.keys():
_pvs_to_set.append(pv)
_values_to_set.append(_set_values_dict[pv])
#self.standby_value_button.setEnabled(False)
#QApplication.processEvents(QEventLoop.AllEvents, 1.0)
if self.set_delay <= 0:
status, status_list = self.cafe.setScalarList(_pvs_to_set,
_values_to_set)
else:
status_list = [self.cyca.ICAFE_NORMAL] * len(_pvs_to_set)
status = self.cyca.ICAFE_NORMAL
for i, (pv, val) in enumerate(zip(_pvs_to_set, _values_to_set)):
status_list[i] = self.cafe.set(pv, val)
if status_list[i] != self.cyca.ICAFE_NORMAL:
status = status_list[i]
##self.standby_value_button.setEnabled(False)
##QApplication.processEvents(QEventLoop.AllEvents, 1.0)
time.sleep(self.set_delay)
##self.standby_value_button.setEnabled(False)
#QApplication.sendPostedEvents()
QApplication.processEvents(QEventLoop.AllEvents, 1.0)
if status != self.cyca.ICAFE_NORMAL:
_mess = ("The following devices reported an error " +
"in 'set' operation:")
for i, status_value in enumerate(status_list):
if status_value != self.cyca.ICAFE_NORMAL:
_mess += ("\n" + _pvs_to_set[i] + " has status = " +
str(status_value) + " " +
self.cafe.getStatusCodeAsString(status_value)
+ " " + self.cafe.getStatusInfo(status_value))
qm = QMessageBox()
qm.setText(_mess)
#qm.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
#qm.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
#qm.setFixedWidth(800)
##self.standby_value_button.setEnabled(False)
##QApplication.sendPostedEvents()
qm.exec()
#QApplication.processEvents()
if self.init_column:
self.init_value_button.setEnabled(True)
self.restore_value_button.setEnabled(True)
self.standby_value_button.setText(_text)
self.standby_value_button.setEnabled(True)
if self.reconnect_button is not None:
self.reconnect_button.setEnabled(True)
return status, status_list, _pvs_to_set
def restore_init_values(self, pv_list: list = []):
_text = self.restore_value_button.text()
self.restore_value_button.setText("Restoring")
self.restore_value_button.setEnabled(False)
if self.init_column:
self.init_value_button.setEnabled(False)
if self.standby_column:
self.standby_value_button.setEnabled(False)
if self.reconnect_button is not None:
self.reconnect_button.setEnabled(False)
_set_values_dict = self.get_init_values()
if not pv_list:
@@ -1466,8 +1622,19 @@ class CAQTableWidget(QTableWidget):
_pvs_to_set.append(pv)
_values_to_set.append(_set_values_dict[pv])
status, status_list = self.cafe.setScalarList(_pvs_to_set,
_values_to_set)
if self.set_delay <= 0:
status, status_list = self.cafe.setScalarList(_pvs_to_set,
_values_to_set)
else:
status_list = [self.cyca.ICAFE_NORMAL] * len(_pvs_to_set)
status = self.cyca.ICAFE_NORMAL
for i, (pv, val) in enumerate(zip(_pvs_to_set, _values_to_set)):
status_list[i] = self.cafe.set(pv, val)
if status_list[i] != self.cyca.ICAFE_NORMAL:
status = status_list[i]
time.sleep(self.set_delay)
QApplication.processEvents(QEventLoop.AllEvents, 1.0)
if status != self.cyca.ICAFE_NORMAL:
_mess = ("The following device(s) reported an error " +
@@ -1480,12 +1647,23 @@ class CAQTableWidget(QTableWidget):
" " + self.cafe.getStatusInfo(status_value))
qm = QMessageBox()
qm.setText(_mess)
qm.exec()
QApplication.processEvents()
self.init_value_button.setEnabled(True)
if self.init_column:
self.init_value_button.setEnabled(True)
self.restore_value_button.setText(_text)
self.restore_value_button.setEnabled(True)
if self.standby_column:
self.standby_value_button.setEnabled(True)
if self.reconnect_button is not None:
self.reconnect_button.setEnabled(True)
return status, status_list, _pvs_to_set
def is_same_as_init_values(self):
_init_values_dict = self.get_column_values(self.columns_dict['Init'])
@@ -1528,6 +1706,8 @@ class CAQTableWidget(QTableWidget):
if _pvs[_row] in self.pv_list_show:
_values_dict[self.pv_gateway[_row].pv_name] = _values[_row]
else:
_values_dict[_row] = _values[_row]
return _values_dict #_pvs_to_set, _values_to_set
@@ -1535,6 +1715,9 @@ class CAQTableWidget(QTableWidget):
def get_init_values(self):
return self.get_column_values(self.columns_dict['Init'])
def get_standby_values(self):
return self.get_column_values(self.columns_dict['Standby'])
def get_init_values_previous(self):
_set_values_dict = {}
_start = 0
@@ -1562,17 +1745,69 @@ class CAQTableWidget(QTableWidget):
_set_values_dict[
self.pv_gateway[_row].pv_name] = _values_to_set[_row]
return _set_values_dict
def update_standby_values(self):
_start = 0
_end = len(self.standby_values)
if 'Standby' in self.columns_dict:
_column_no = self.columns_dict['Standby']
else:
return
for _row in range(_start, _end):
_value = self.standby_values[_row]
if self.scale_factor != 1:
_value = _value * self.scale_factor
_value = self.pv_gateway[_row].format_display_value(_value)
qtwi = QTableWidgetItem(str(_value)+ " ")
_f = qtwi.font()
_f.setPointSize(8)
qtwi.setFont(_f)
self.setItem(_row, _column_no, qtwi)
self.item(_row, _column_no).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
def set_init_values(self, values):
_start = 0
_end = min(len(self.pv_gateway), len(values))
if 'Init' in self.columns_dict:
_column_no = self.columns_dict['Init']
else:
return
for _row in range(_start, _end):
_value = self.pv_gateway[_row].format_display_value(values[_row])
qtwi = QTableWidgetItem(str(_value)+ " ")
_f = qtwi.font()
_f.setPointSize(8)
qtwi.setFont(_f)
self.setItem(_row, _column_no, qtwi)
self.item(_row, _column_no).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
def update_init_values(self):
_start = 0
_end = len(self.pv_gateway)
if 'Init' in self.columns_dict:
_column_no = self.columns_dict['Init']
else:
return
for _row in range(_start, _end):
_handle = self.pv_gateway[_row].handle
_value = self.pv_gateway[_row].cafe.getCache(_handle)
if _value is not None:
if self.scale_factor != 1:
_value = _value * self.scale_factor
@@ -1582,9 +1817,11 @@ class CAQTableWidget(QTableWidget):
_f = qtwi.font()
_f.setPointSize(8)
qtwi.setFont(_f)
self.setItem(_row, 1, qtwi)
self.item(_row, 1).setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
self.setItem(_row, _column_no, qtwi)
self.item(_row, _column_no).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
def configure_widget(self):
@@ -1599,8 +1836,10 @@ class CAQTableWidget(QTableWidget):
self.resizeColumnsToContents()
self.resizeRowsToContents()
#self.horizontalHeader().setStretchLastSection(True);
self.setColumnWidth(self.columns_dict['PV'], _column_width_pvname)
if 'PV' in self.columns_dict.keys():
self.setColumnWidth(self.columns_dict['PV'], _column_width_pvname)
_pv_column = self.columns_dict['PV']
self.setColumnWidth(self.columns_dict['Value'], _column_width_value)
if 'Init' in self.columns_dict.keys():
self.setColumnWidth(self.columns_dict['Init'], _column_width_value)
@@ -1610,18 +1849,22 @@ class CAQTableWidget(QTableWidget):
self.setColumnWidth(self.columns_dict['Reconnect'],
_column_width_checkbox)
_pv_column = self.columns_dict['PV']
for i in range(0, len(self.pv_gateway)):
qtwt = QTableWidgetItem(self.pv_list_show[i])
f = qtwt.font()
f.setPointSize(8)
qtwt.setFont(f)
istart = 1
if 'PV' in self.columns_dict.keys():
qtwt = QTableWidgetItem(self.pv_list_show[i])
f = qtwt.font()
f.setPointSize(8)
qtwt.setFont(f)
self.setItem(i, _pv_column, qtwt)
self.item(i, _pv_column).setTextAlignment(Qt.AlignHCenter |
Qt.AlignVCenter)
for i_column in range(1, self.no_columns-1):
self.setItem(i, _pv_column, qtwt)
self.item(i, _pv_column).setTextAlignment(Qt.AlignHCenter |
Qt.AlignVCenter)
else:
istart = 0
for i_column in range(istart, self.no_columns-1):
self.setItem(i, i_column, QTableWidgetItem(str("")))
self.item(i, i_column).setTextAlignment(Qt.AlignHCenter |
Qt.AlignVCenter)
@@ -1638,25 +1881,29 @@ class CAQTableWidget(QTableWidget):
if self.init_column:
self.init_widget = QWidget()
_init_layout = QHBoxLayout(self.init_widget)
self.init_layout = QHBoxLayout(self.init_widget)
self.init_value_button = QPushButton()
self.init_value_button.setText("Update")
_f = self.init_value_button.font()
_f.setPointSize(8)
self.init_value_button.setFont(_f)
self.init_value_button.setFixedWidth(80)
self.init_value_button.setFixedWidth(64)
self.init_value_button.clicked.connect(self.update_init_values)
self.init_value_button.setToolTip(
("Stores initial, pre-measurement value. Update is also " +
"typically executed automatically before new optics are set."))
_init_layout.addWidget(self.init_value_button)
_init_layout.setAlignment(Qt.AlignRight)
_init_layout.setContentsMargins(1, 1, 0, 0) #Required
self.init_widget.setLayout(_init_layout)
self.setCellWidget(len(self.pv_gateway), 1, self.init_widget)
"typically executed automatically before analysis procedure."))
self.init_layout.addWidget(self.init_value_button)
self.init_layout.setAlignment(Qt.AlignCenter)
self.init_layout.setContentsMargins(1, 1, 1, 0) #Required
self.init_widget.setLayout(self.init_layout)
if 'PV' in self.columns_dict:
self.setCellWidget(len(self.pv_gateway), 0, self.init_widget)
else:
self.setCellWidget(len(self.pv_gateway), self.columns_dict['Init'], self.init_widget)
_restore_widget = QWidget()
_restore_layout = QHBoxLayout(_restore_widget)
self.restore_widget = QWidget()
self.restore_layout = QHBoxLayout(self.restore_widget)
self.restore_value_button = QPushButton()
self.restore_value_button.setStyleSheet(
"QPushButton{background-color: rgb(212, 219, 157);}")
@@ -1668,11 +1915,36 @@ class CAQTableWidget(QTableWidget):
self.restore_value_button.clicked.connect(self.restore_init_values)
self.restore_value_button.setToolTip(
("Restore devices to their pre-measurement values"))
_restore_layout.addWidget(self.restore_value_button)
_restore_layout.setAlignment(Qt.AlignRight)
_restore_layout.setContentsMargins(1, 1, 0, 0)
_restore_widget.setLayout(_restore_layout)
self.setCellWidget(len(self.pv_gateway), 2, _restore_widget)
self.restore_layout.addWidget(self.restore_value_button)
self.restore_layout.setAlignment(Qt.AlignCenter)
self.restore_layout.setContentsMargins(1, 1, 0, 0)
self.restore_widget.setLayout(self.restore_layout)
if 'PV' in self.columns_dict:
self.setCellWidget(len(self.pv_gateway),
self.columns_dict['Init'],
self.restore_widget)
if self.standby_column:
_standby_widget = QWidget()
_standby_layout = QHBoxLayout(_standby_widget)
self.standby_value_button = QPushButton()
self.standby_value_button.setStyleSheet(
"QPushButton{background-color: rgb(212, 219, 157);}")
self.standby_value_button.setText("Standby")
_f = self.standby_value_button.font()
_f.setPointSize(8)
self.standby_value_button.setFont(_f)
self.standby_value_button.setFixedWidth(80)
self.standby_value_button.clicked.connect(self.set_standby_values)
self.standby_value_button.setToolTip(
("Set devices to their pre-set standby values"))
_standby_layout.addWidget(self.standby_value_button)
_standby_layout.setAlignment(Qt.AlignCenter)
_standby_layout.setContentsMargins(1, 1, 0, 0)
_standby_widget.setLayout(_standby_layout)
self.setCellWidget(len(self.pv_gateway), self.columns_dict['Standby'], _standby_widget)
#Do not display no for last row (Reconnect button)
_row_digit_last_cell = QTableWidgetItem(str(""))
@@ -1689,13 +1961,13 @@ class CAQTableWidget(QTableWidget):
f.setPointSize(8)
self.reconnect_button.setFixedWidth(100)
else:
f.setPointSize(6)
self.reconnect_button.setFixedWidth(58)
f.setPointSize(7) #6
self.reconnect_button.setFixedWidth(66) #58
self.reconnect_button.setFont(f)
self.reconnect_button.setText("Reconnect")
self.reconnect_button.setToolTip("Reconnect selected/checked channels")
_layout = QHBoxLayout(_qwb)
_layout.addWidget(self.reconnect_button)
_layout.setAlignment(Qt.AlignCenter)
@@ -1712,9 +1984,10 @@ class CAQTableWidget(QTableWidget):
self.setCellWidget(len(self.pv_gateway), self.no_columns-1,
self.cb_item_all)
header_item = QTableWidgetItem("Process Variable")
self.setHorizontalHeaderItem(self.columns_dict['PV'], header_item)
if 'PV' in self.columns_dict.keys():
header_item = QTableWidgetItem("Process Variable")
self.setHorizontalHeaderItem(self.columns_dict['PV'], header_item)
if 'Init' in self.columns_dict.keys():
self.setHorizontalHeaderItem(self.columns_dict['Init'],
@@ -1749,9 +2022,13 @@ class CAQTableWidget(QTableWidget):
self.setMinimumWidth(_min_table_width)
for _row in range(0, len(self.pv_gateway)):
self.item(_row, _pv_column).setForeground(QColor("#000000"))
if 'PV' in self.columns_dict.keys():
self.item(_row, _pv_column).setForeground(QColor("#000000"))
istart = 1
else:
istart = 0
for i_column in range(1, self.no_columns-2):
for i_column in range(istart, self.no_columns-2):
self.item(_row, i_column).setForeground(QColor("#000000"))
self.item(_row, i_column).setTextAlignment(Qt.AlignRight |
Qt.AlignVCenter)
@@ -1834,16 +2111,16 @@ class CAQTableWidget(QTableWidget):
if _prop == self.pv_gateway[_row].READBACK_ALARM:
if alarm_severity == self.pv_gateway[_row].cyca.SEV_MAJOR:
_bgcolor = self.pv_gateway[_row].settings.fgAlarmMajor
_bgcolor = self.pv_gateway[_row].fg_alarm_major
_fgcolor = "black"
elif alarm_severity == self.pv_gateway[_row].cyca.SEV_MINOR:
_bgcolor = self.pv_gateway[_row].settings.fgAlarmMinor
_bgcolor = self.pv_gateway[_row].fg_alarm_minor
_fgcolor = "black"
elif alarm_severity == self.pv_gateway[_row].cyca.SEV_INVALID:
_bgcolor = self.pv_gateway[_row].settings.fgAlarmInvalid
_bgcolor = self.pv_gateway[_row].fg_alarm_invalid
_fgcolor = "#777777"
else:
_bgcolor = self.pv_gateway[_row].settings.fgAlarmNoAlarm
_bgcolor = self.pv_gateway[_row].fg_alarm_noalarm
_fgcolor = "black"
#Colors for bg/fg reversed as is the old norm
@@ -2455,6 +2732,7 @@ class QNoDockWidget(QDockWidget):
class CAQStripChart(PlotWidget):
'''Channel access enabled pyqtgraph.PlotWidget'''
def __init__(self, parent=None, pv_list: list = ['PV_NAME_NOT_GIVEN'],
monitor_callback=None, pv_within_daq_group: bool = False,
color_mode=None, show_units: bool = False, prefix: str = "",
@@ -2477,17 +2755,18 @@ class CAQStripChart(PlotWidget):
self.val_previous = [None] * self.no_channels
self.curve = [None] * self.no_channels
print (self.pv_list, flush=True)
for i in range (0, len(self.pv_list)):
self.pv_gateway[i] = PVGateway().__init__(
parent, pv_list[i], monitor_callback, pv_within_daq_group,
self.pv_gateway[i] = PVGateway(
parent, self.pv_list[i], monitor_callback, pv_within_daq_group,
color_mode, show_units, prefix, suffix,
#connect_callback=self.py_connect_callback,
connect_triggers=False, notify_freq_hz=notify_freq_hz,
monitor_dbr_time = True)
print(i, pv_list[i], "gateway object", self.pv_gateway[i])
self.pv_gateway[i].is_initialize_complete()
@@ -2529,8 +2808,8 @@ class CAQStripChart(PlotWidget):
# Data stuff
self._interval = int(sampleinterval*1000)
self._bufsize = 9000 #int(timewindow/0.33)
self._bufsize2 = 9000 # int(timewindow/1.33)
self._bufsize = 10000 #int(timewindow/0.33)
self._bufsize2 = 10000 # int(timewindow/1.33)
self.databuffer = [None] * self.no_channels
self.timebuffer = [None] * self.no_channels
self.x = [None] * self.no_channels
@@ -2561,13 +2840,37 @@ class CAQStripChart(PlotWidget):
if title is not None:
self.setTitle(str(title)) #self.pv_gateway[0].pv_name)
self.showGrid(x=True, y=True)
self.setLabel('left', ylabel, self.pv_gateway[0].units)
#self.setLabel('left', ylabel, self.pv_gateway[0].units)
self.setLabel('bottom', 'time', 's')
self.setBackground((60, 60, 60)) #247, 236, 249))
self.setLimits(yMin=-0.11)
#self.setLimits(yMin=-0.11)
#self.setLimits(yMin=-1, yMax=1)
ax = pg.AxisItem('left')
ax.enableAutoSIPrefix(enable=False)
ax.setLabel(ylabel, self.pv_gateway[0].units)
ax.setGrid(155)
ay = pg.AxisItem('bottom')
ay.enableAutoSIPrefix(enable=False)
ay.setLabel('time', 'min')
ay.setGrid(175)
if 'BPM' in text_label:
ax.setTickSpacing(0.2, 0.1)
#ax.setRange(-1, 1)
#ax.setParentItem(self.graphicsItem())
axitems = {}
axitems['left'] = ax
axitems['bottom'] = ay
self.setAxisItems(axitems)
pg.setConfigOption('leftButtonPan', False)
self.plotItem.setMouseEnabled(y=True) # Only allow zoom in X-axis
self.plotItem.setMouseEnabled(x=True) # Only allow zoom in Y-axis
#(125, 249, 255)
if self.pen_color_idx == 0:
pen_list = [ (255, 155, 0), (255,255,0), (0, 180, 255) ]
@@ -2601,20 +2904,37 @@ class CAQStripChart(PlotWidget):
@Slot(object, int)
def receive_monitor_dbr_time(self, pvdata, alarm_severity):
#if not self.mutex.tryLock(): #locked():
# print("Event locked", pvdata.ts[0], pvdata.ts[1])
# return
#self.mutex.lock() #acquire()
_row = self.pv2item_dict[self.sender()]
#print("row, value from pvdata==>", _row, pvdata.value[0], self.pv_gateway[_row].pv_name)
ts_now = pvdata.ts[0] + pvdata.ts[1] * 10**(-9)
ts_previous = (self.pvd_previous_list[_row].ts[0] +
self.pvd_previous_list[_row].ts[1] * 10**(-9))
self.pvd_previous_list[_row].ts[1] * 10**(-9))
ts_delta = ts_now - ts_previous
if (pvdata.ts[0] == self.pvd_previous_list[_row].ts[0]) and (
pvdata.ts[1] == self.pvd_previous_list[_row].ts[1]):
pvdata.show()
self.pvd_previous_list[_row].show()
#print("SAME TIMESTAMP")
#pvdata.show()
#self.pvd_previous_list[_row].show()
#print("================")
#self.mutex.unlock() #release()
return
if pvdata.ts[0] < self.pvd_previous_list[_row].ts[0]:
print("Funny ts value", self.pv_gateway[_row].pv_name)
pvdata.show()
#self.mutex.unlock() #release()
return
value = pvdata.value[0]
#discard first callbacks
#if ts_delta > 2.0:
@@ -2630,6 +2950,7 @@ class CAQStripChart(PlotWidget):
highest_ts = self.timebuffer[0][0] \
if self.timebuffer[0][0] is not None else 0
for i in range(1, len(self.timebuffer)):
if self.timebuffer[i][0] is None:
continue
@@ -2655,9 +2976,10 @@ class CAQStripChart(PlotWidget):
# self.curve[row].setData(self.x_shifted[row], self.y[row][idx:])
self.curve[_row].setData(self.x_shifted[_row], self.y[_row][idx:])
self.time_delta[_row] = (
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0]
self.time_delta[_row] = ((
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0])/60
#self.mutex.unlock() #release()
#QApplication.processEvents()

View File

@@ -239,11 +239,9 @@ class CAQMenu(QComboBox, PVGateway):
super().__init__(parent, pv_name, monitor_callback,
pv_within_daq_group, color_mode, show_units, prefix,
suffix, connect_callback=self.py_connect_callback)
self.is_initialize_complete()
self.configure_widget()
#After configure:widget
self.currentIndexChanged.connect(self.value_change)
@@ -254,6 +252,7 @@ class CAQMenu(QComboBox, PVGateway):
'''Callback function to be invoked on change of
pv connection status.
'''
self.trigger_connect.emit(int(handle), str(pvname), int(status))
def configure_widget(self):
@@ -269,9 +268,10 @@ class CAQMenu(QComboBox, PVGateway):
enumStringList = self.cafe.getEnumStrings(self.handle)
self.addItems(enumStringList)
for i in range(0, self.count()):
self.setItemData(i, Qt.AlignCenter, Qt.TextAlignmentRole)
fm = QFontMetricsF(QFont("Sans Serif", 10))
qrect = fm.boundingRect(self.suggested_text)
@@ -283,9 +283,11 @@ class CAQMenu(QComboBox, PVGateway):
self.qt_property_initial_values(qt_object_name=self.PV_CONTROLLER)
def post_display_value(self, value):
'''Convert value to index'''
if "setCurrentIndex" in dir(self):
if LooseVersion(QT_VERSION_STR) >= LooseVersion("5.3"):
self.blockSignals(True)
@@ -311,7 +313,6 @@ class CAQMenu(QComboBox, PVGateway):
def value_change(self, indx):
status = self.cafe.set(self.handle, indx)
if status != self.cyca.ICAFE_NORMAL:
@@ -346,9 +347,8 @@ class CAQMenu(QComboBox, PVGateway):
if self.pv_info.accessWrite == 0:
event.ignore()
return
else:
QComboBox.mousePressEvent(self, event)
QComboBox.mousePressEvent(self, event)
self.previousIndex = self.currentIndex()
def enterEvent(self, event):
@@ -2431,10 +2431,17 @@ class QNoDockWidget(QDockWidget):
self.topLevelChanged.connect(self._top_level_changed)
self.setVisible(False)
self.setFloating(True)
x = self.geometry_from_qsettings.x() + 480 # 3500 #screen.width() - widget.width()
y = self.geometry_from_qsettings.y() + 350 #100 #screen.height() - widget.height()
self.move(x, y)
def changeEvent(self, event):
if "QAbstractButton" in str(self.sender()):
self.geometry_from_qsettings = self.parent.geometry()
def _top_level_changed(self): #, is_floating):
self.setVisible(False)
@@ -2452,40 +2459,46 @@ class CAQStripChart(PlotWidget):
monitor_callback=None, pv_within_daq_group: bool = False,
color_mode=None, show_units: bool = False, prefix: str = "",
suffix: str = "", notify_freq_hz: int = 0, title: str = "",
ylabel: str = ""):
ylabel: str = "", force_ts_align = True, text_label = [],
pen_color_idx = 0):
super().__init__()
self.no_channels = len(pv_list)
self.pen_color_idx = pen_color_idx
self.text_label = text_label
self.found = False
self.time_zero = [0] * self.no_channels
self.time_delta = [0] * self.no_channels
self.pv_list = pv_list
self.pv_list = pv_list
self.pv2item_dict = {}
self.pv_gateway = [None] * self.no_channels
self.pvd_previous_list = [None] * self.no_channels
self.val_previous = [None] * self.no_channels
self.curve = [None] * self.no_channels
for i in range(0, len(self.pv_list)):
for i in range (0, len(self.pv_list)):
print("in atripchart", i, self.pv_list[i])
self.pv_gateway[i] = PVGateway(
parent, pv_list[i], monitor_callback, pv_within_daq_group,
color_mode, show_units, prefix, suffix,
parent, self.pv_list[i], monitor_callback, pv_within_daq_group,
color_mode, show_units, prefix, suffix,
#connect_callback=self.py_connect_callback,
connect_triggers=False, notify_freq_hz=notify_freq_hz,
monitor_dbr_time=True)
monitor_dbr_time = True)
self.pv_gateway[i].is_initialize_complete()
self.pvd_previous_list[i] = self.pv_gateway[i].pvd
self.pv_gateway[i].trigger_connect.connect(
self.receive_connect_update)
self.pv_gateway[i].trigger_monitor_str.connect(
self.receive_monitor_update)
self.receive_monitor_update)
self.pv_gateway[i].trigger_monitor_int.connect(
self.receive_monitor_update)
self.pv_gateway[i].trigger_monitor_float.connect(
@@ -2493,38 +2506,40 @@ class CAQStripChart(PlotWidget):
self.pv_gateway[i].trigger_monitor.connect(
self.receive_monitor_dbr_time)
self.pv_gateway[i].widget_class = "PlotWidget"
self.pv_gateway[i].widget_class = "PlotWidget"
self.pv2item_dict[self.pv_gateway[i]] = i
self.cafe = self.pv_gateway[0].cafe
self.cyca = self.pv_gateway[0].cyca
for i in range(0, len(self.pv_gateway)):
for i in range(0, len(self.pv_gateway)):
if self.cafe.isConnected(self.pv_gateway[i].pv_name):
self.pv_gateway[i].trigger_connect.emit(
self.pv_gateway[i].handle, str(self.pv_gateway[i].pv_name),
self.pv_gateway[i].cyca.ICAFE_CS_CONN)
for i in range(0, len(self.pv_gateway)):
if not self.pv_gateway[i].pv_within_daq_group:
self.pv_gateway[i].monitor_start()
sampleinterval = 0.2
##timewindow = 1800.0
sampleinterval = 0.2
timewindow = 1800.0
self.ts_delta_max = 0.6
# Data stuff
self._interval = int(sampleinterval*1000)
self._bufsize = 9000 #int(timewindow/0.33)
self._bufsize2 = 9000 # int(timewindow/1.33)
self.databuffer = [None] * self.no_channels
self.timebuffer = [None] * self.no_channels
self.x = [None] * self.no_channels
self.y = [None] * self.no_channels
self.x = [None] * self.no_channels
self.y = [None] * self.no_channels
self.x_shifted = [None] * self.no_channels
self.idx = [0] * self.no_channels
for i in range(0, self.no_channels):
bsize = self._bufsize if i == 0 else self._bufsize2
self.databuffer[i] = collections.deque([None]*bsize, bsize)
@@ -2532,9 +2547,9 @@ class CAQStripChart(PlotWidget):
self.x[i] = np.zeros(bsize, dtype=np.float)
self.y[i] = np.zeros(bsize, dtype=np.float)
##_long_size=20
_long_size=20
#self.data_series_buffer = collections.deque([0]*_long_size, _long_size)
#self.time_series_buffer = collections.deque([0]*_long_size, _long_size)
#self.time_series_buffer = collections.deque([0]*_long_size, _long_size)
#self.data_series = [] * self.no_channels
#self.time_series = [] * self.no_channels
@@ -2545,98 +2560,118 @@ class CAQStripChart(PlotWidget):
#self.x_series = np.zeros(_long_size, dtype=np.float)
#self.y_series = np.zeros(_long_size, dtype=np.float)
if title is not None:
self.setTitle(str(title)) #self.pv_gateway[0].pv_name)
self.setTitle(str(title)) #self.pv_gateway[0].pv_name)
self.showGrid(x=True, y=True)
self.setLabel('left', ylabel, self.pv_gateway[0].units)
self.setLabel('bottom', 'time', 's')
self.setLabel('bottom', 'time', 's')
self.setBackground((60, 60, 60)) #247, 236, 249))
self.setLimits(yMin=-0.11)
self.plotItem.setMouseEnabled(y=False) # Only allow zoom in X-axis
self.plotItem.setMouseEnabled(y=True) # Only allow zoom in X-axis
self.plotItem.setMouseEnabled(x=True) # Only allow zoom in Y-axis
pen_list = [(125, 249, 255), (255, 255, 0)]
#(125, 249, 255)
if self.pen_color_idx == 0:
pen_list = [ (255, 155, 0), (255,255,0), (0, 180, 255) ]
elif self.pen_color_idx == 1:
pen_list = [ (125, 249, 255), (255,255,0), (0, 180, 255) ]
else:
pen_list = [ (0, 180, 255), (125, 249, 255), (255,255,0) ]
for i in range(0, len(self.pv_gateway)):
self.curve[i] = self.plot(self.x[0], self.y[0], pen=pen_list[i])
self.curve[i] = self.plot(self.x[0], self.y[0], pen=pen_list[i]) # (0, 253, 235))
#self.curve[1] = self.plot(self.x[1], self.y[1], pen=(255,255,0))
#offset=(1.0, 1.0),
l=pg.LegendItem() #horSpacing=20, verSpacing=0, labelTextColor=(205, 205, 205),
#labelTextSize='6px', colCount=1)
l = pg.LegendItem(offset=(0., 0.5), colCount=1)
l.setParentItem(self.graphicsItem())
l.anchor((0,0), (0.08, 0.0))
#l.setLabelTextColor((205, 205, 205))
#l.setLabelTextSize(9) does not exists(!)
#l.setOffset(-60)
for curv, label in zip(self.curve, self.text_label):
l.addItem(curv, label)
l.setLabelTextColor((255, 255, 255))
for curv, pv in zip(self.curve, self.pv_gateway):
l.addItem(curv, pv.pv_name)
#for curv, pv in zip(self.curve, self.pv_gateway):
# l.addItem(curv, self.textpv.pv_name)
#self.daq_stop()
#print(self._bufsize)
#print(len(self.x), len(self.y))
QApplication.processEvents()
@Slot(object, int)
@Slot(object, int)
def receive_monitor_dbr_time(self, pvdata, alarm_severity):
#Check on alarm_severity??
_row = self.pv2item_dict[self.sender()]
#print("row, value from pvdata==>", _row, pvdata.value[0], self.pv_gateway[_row].pv_name)
ts_now = pvdata.ts[0] + pvdata.ts[1] * 10**(-9)
ts_previous = (self.pvd_previous_list[_row].ts[0] +
self.pvd_previous_list[_row].ts[1] * 10**(-9))
##ts_delta = ts_now - ts_previous
ts_previous = (self.pvd_previous_list[_row].ts[0] +
self.pvd_previous_list[_row].ts[1] * 10**(-9))
ts_delta = ts_now - ts_previous
if (pvdata.ts[0] == self.pvd_previous_list[_row].ts[0]) and (
pvdata.ts[1] == self.pvd_previous_list[_row].ts[1]):
pvdata.show()
#pvdata.show()
self.pvd_previous_list[_row].show()
return
value = pvdata.value[0]
value = pvdata.value[0]
#discard first callbacks
#if ts_delta > 2.0:
# self.pvd_previous_list[_row] = _pvd
# self.pvd_previous_list[_row] = _pvd
# return;
self.pvd_previous_list[_row] = pvdata
self.val_previous[_row] = value
#self.pvd_previous_list[_row].ts[0] = _pvd.ts[0]
#self.pvd_previous_list[_row].ts[0] = _pvd.ts[0]
#self.pvd_previous_list[_row].ts[1] = _pvd.ts[1]
self.databuffer[_row].append(value)
self.timebuffer[_row].append(self.time_delta[_row])
highest_ts = self.timebuffer[0][0] \
if self.timebuffer[0][0] is not None else 0
for i in range(1, len(self.timebuffer)):
for i in range(1, len(self.timebuffer)):
if self.timebuffer[i][0] is None:
continue
elif self.timebuffer[i][0] > highest_ts:
highest_ts = self.timebuffer[i][0]
if self.timebuffer[_row][0] is not None:
for i, val in enumerate(self.timebuffer[_row]):
if val > highest_ts:
self.idx[_row] = i - 1
break
break
self.y[_row][:] = self.databuffer[_row]
self.x[_row][:] = self.timebuffer[_row]
idx = self.idx[_row]
self.x_shifted[_row] = list(
map(lambda m: (m - self.time_delta[_row]), self.x[_row][idx:]))
self.x_shifted[_row] = list(map(lambda m : (m - self.time_delta[_row]), self.x[_row][idx:]))
self.curve[_row].setData(self.x_shifted[_row], self.y[_row][idx:])
#print("idx", self.idx)
#if 'AVG' in self.pv_gateway[_row].pv_name:
# for row in range(0, len(self.curve)):
# self.curve[row].setData(self.x_shifted[row], self.y[row][idx:])
self.curve[_row].setData(self.x_shifted[_row], self.y[_row][idx:])
self.time_delta[_row] = (
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0]
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0]
#QApplication.processEvents()
@Slot(str, int, int)
@Slot(int, int, int)
@Slot(float, int, int)
def receive_monitor_update(self, value, status, alarm_severity):
#self.pv_gateway.receive_monitor_update(value, status, alarm_severity)
_row = self.pv2item_dict[self.sender()]
#print("row, value===>", _row, value, self.pv_gateway[_row].pv_name)
#if _row == 1:
# return
print("row, value===>", _row, value, self.pv_gateway[_row].pv_name)
_pvd = self.pv_gateway[_row].cafe.getPVCache(
self.pv_gateway[_row].handle)
@@ -2644,109 +2679,106 @@ class CAQStripChart(PlotWidget):
_pvd2 = self.pv_gateway[_row].pvd
print("val", value, _pvd2.value[0], _pvd.value[0],
self.pvd_previous_list[_row].value[0])
print ("val", value, _pvd2.value[0], _pvd.value[0], self.pvd_previous_list[_row].value[0])
ts_now = _pvd.ts[0] + _pvd.ts[1] * 10**(-9)
ts_previous = (self.pvd_previous_list[_row].ts[0] +
self.pvd_previous_list[_row].ts[1] * 10**(-9))
ts_delta = ts_now - ts_previous
ts_previous = (self.pvd_previous_list[_row].ts[0] +
self.pvd_previous_list[_row].ts[1] * 10**(-9))
ts_delta = ts_now - ts_previous
if value == self.val_previous[_row]:
#if (_pvd.ts[0] == self.pvd_previous_list[_row].ts[0]) and (
# _pvd.ts[1] == self.pvd_previous_list[_row].ts[1]):
_pvd.show()
#self.pvd_previous_list[_row].show()
return
#discard first callbacks
#if ts_delta > 2.0:
# self.pvd_previous_list[_row] = _pvd
# self.pvd_previous_list[_row] = _pvd
# return;
self.pvd_previous_list[_row] = _pvd2
self.val_previous[_row] = value
#self.pvd_previous_list[_row].ts[0] = _pvd.ts[0]
#self.pvd_previous_list[_row].ts[0] = _pvd.ts[0]
#self.pvd_previous_list[_row].ts[1] = _pvd.ts[1]
self.databuffer[_row].append(value)
self.timebuffer[_row].append(self.time_delta[_row])
highest_ts = self.timebuffer[0][0] \
if self.timebuffer[0][0] is not None else 0
for i in range(1, len(self.timebuffer)):
for i in range(1, len(self.timebuffer)):
if self.timebuffer[i][0] is None:
continue
elif self.timebuffer[i][0] > highest_ts:
highest_ts = self.timebuffer[i][0]
if self.timebuffer[_row][0] is not None:
for i, val in enumerate(self.timebuffer[_row]):
if val > highest_ts:
self.idx[_row] = i - 1
break
#for i in range(1, self.timebuffer):
# if self.timebuffer[i][0] is not None:
# a = self.timebuffer[0][0]
# for i, val in enumerate(self.timebuffer[_row]):
# if val > a:
# idx = i - 1
# break
break
'''
for i in range(1, self.timebuffer):
if self.timebuffer[i][0] is not None:
a = self.timebuffer[0][0]
for i, val in enumerate(self.timebuffer[_row]):
if val > a:
idx = i - 1
break
'''
self.y[_row][:] = self.databuffer[_row]
self.x[_row][:] = self.timebuffer[_row]
#self.y[_row][:] = self.databuffer[_row]
#self.x[_row][:] = self.timebuffer[_row]
'''
#print(ts_delta, value, self.pvd_previous.value[0])
#if (ts_delta < self.ts_delta_max) and (value <
#self.pvd_previous.value[0]) :
#if (ts_delta < self.ts_delta_max) and (value < self.pvd_previous.value[0]) :
if (value < self.pvd_previous.value[0]) :
self.data_series_buffer.append(value)
self.time_series_buffer.append(ts_now - self.time_zero )
self.time_series_buffer.append(ts_now - self.time_zero ) #self.time_delta)
self.y_series[:] = self.data_series_buffer
self.x_series[:] = self.time_series_buffer
#print(self.x_series, self.y_series)
#elif ts_delta < 1.0:
if len(self.data_series_buffer) > 15:
if len(self.data_series_buffer) > 15:
#x_series = np.array(self.time_series, dtype=np.float)
#y_series = np.array(self.data_series, dtype=np.float)
_x=self.x_series.reshape((-1, 1))
model = LinearRegression()
model.fit(_x, self.y_series)
r_sq = model.score(_x, self.y_series)
###JCprint('coefficient of determination:',
##r_sq, "slope", model.coef_ , "lifetime:",
###self.y_series[0]/model.coef_ / 3600)
###JCprint('coefficient of determination:', r_sq, "slope", model.coef_ , "lifetime:", self.y_series[0]/model.coef_ / 3600)
#print('intercept:', model.intercept_)
#print('slope:', model.coef_)
#print('max value', y_series[0], y_series[1])
if r_sq > 0.995:
_I = self.y_series[0]
###JCprint("lifetime:", _I/model.coef_ / 3600)
y_pred = model.predict(_x)
#print("len, y_pred, _x", len(y_pred),
#len(self.y_series), len(_x))
#print("len, y_pred, _x", len(y_pred), len(self.y_series), len(_x))
#print('predicted response:', y_pred, sep='\n')
m_sq_error = mean_squared_error(self.y_series, y_pred)
#print('Mean squared error: {0:.9f}'.format(
# mean_squared_error(y_series, y_pred)))
#print('Coefficient of determination: {0:.9f}'.format(
# r2_score(y_series, y_pred)))
# r2_score(y_series, y_pred)))
self.trigger_series_sequence.emit(self.x_series,
self.y_series)
self.trigger_series_sequence.emit(self.x_series, self.y_series)
#print("emit")
self.data_series = []
self.time_series = []
@@ -2754,75 +2786,73 @@ class CAQStripChart(PlotWidget):
else:
self.data_series = []
self.time_series = []
'''
#dt = (self.x[-1] - self.x[-2])
#dt = (self.x[-1] - self.x[-2])
#print("dt", dt)
#Lowet IPCT before trigger is set to t=0
idx = self.idx[_row]
self.x_shifted[_row] = list(
map(lambda m: (m - self.time_delta[_row]), self.x[_row][idx:]))
self.x_shifted[_row] = list(map(lambda m : (m - self.time_delta[_row]), self.x[_row][idx:]))
##self.y = np.where(self.y != self.y, 0, self.y) #test for nan
#print("row len len ", _row, self.time_delta[0], self.time_delta[1])
self.curve[_row].setData(self.x_shifted[_row], self.y[_row][idx:])
self.time_delta[_row] = (
_pvd.ts[0] + _pvd.ts[1]*10**(-9)) - self.time_zero[0]
_pvd.ts[0] + _pvd.ts[1]*10**(-9)) - self.time_zero[0]
'''
LOOK_BACK = -800
LOOK_BACK = -800
if 'ARIDI-PCT2:CURRENT' in self.pv_gateway[_row].pv_name:
LOOK_BACK = -250
if value > self.y[-2]:
if value > self.y[-2]:
if not self.found:
#print(x_shifted[-240:], self.y[-240:])
#self.y = np.where(self.y != self.y, 0, self.y) #test for nan
max_index = self.y[LOOK_BACK:].argmax()
if max_index == 0:
return
print("max index=", max_index)
#print(x_shifted[-600+max_index:], self.x[-600+max_index:])
#print(self.y[-600+max_index:-2])
#print(x_shifted[-600+max_index:], self.x[-600+max_index:])
#print(self.y[-600+max_index:-2])
self.found = True
#print("Are Signals blocked??", self.signalsBlocked())
self.trigger_decay_sequence.emit(np.array(
x_shifted[LOOK_BACK+max_index+9:-2]),
self.y[LOOK_BACK+max_index+9:-2])
x_shifted[LOOK_BACK+max_index+9:-2]), self.y[LOOK_BACK+max_index+9:-2])
else:
self.found = False
'''
'''
@Slot(int, str, int)
def receive_connect_update(self, handle: int, pv_name: str, status: int):
'''Triggered by connect signal'''
print("pv_name==>", pv_name)
_row = self.pv2item_dict[self.sender()]
self.pv_gateway[_row].receive_connect_update(handle, pv_name, status,
self.pv_gateway[_row].receive_connect_update(handle, pv_name, status,
post_display=False)
#self.pv_gateway.receive_connect_update(handle, pv_name, status)
_pvd = self.pv_gateway[_row].cafe.getPVCache(
self.pv_gateway[_row].handle)
_pvd = self.pv_gateway[_row].cafe.getPVCache(self.pv_gateway[_row].handle)
if self.time_zero[_row] == 0:
self.time_zero[_row] = _pvd.ts[0] + _pvd.ts[1]*10**(-9)
self.pvd_previous = _pvd
#renove highlighting which persists after mouse leaves
def mouseMoveEvent(self, event):
#event.ignore()
pass
def leaveEvent(self, event):

3461
pvwidgets.py:2.9 Normal file

File diff suppressed because it is too large Load Diff