first alpha version vor ARESvis application
This commit is contained in:
@@ -35,14 +35,11 @@ bitmask for simulation:
|
||||
0x80:
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QSlider, QLineEdit,\
|
||||
QCheckBox, QHBoxLayout, QVBoxLayout, QGroupBox, QGridLayout, QComboBox
|
||||
from PyQt5.QtGui import QPainter, QColor, QPen, QBrush, QPolygon, QTransform
|
||||
from PyQt5.QtCore import QPoint, QPointF, Qt
|
||||
from PyQt5.QtCore import QPoint, QPointF, Qt,pyqtSignal
|
||||
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
import PyQt5.QtGui as QtGui
|
||||
import PyQt5.QtCore as QtCore
|
||||
import PyQt5.QtWidgets as QtW
|
||||
@@ -52,8 +49,57 @@ import numpy as np
|
||||
import sys, logging, copy
|
||||
import epics
|
||||
|
||||
if sys.version_info[0] < 3 or sys.version_info[1] < 6:
|
||||
print(f"Must be using Python 3.6 or newer. Try e.g. /opt/gfa/python-3.8/latest/bin/python /sf/furka/bin/ARESvis")
|
||||
|
||||
_log=logging.getLogger(__name__)
|
||||
|
||||
import logging
|
||||
|
||||
class col:
|
||||
d = '\033[0m' #default
|
||||
r = '\033[31m' #red
|
||||
g = '\033[32m' #green
|
||||
y = '\033[33m' #yellow
|
||||
rr= '\033[91m' #red(bright)
|
||||
gg= '\033[92m' #green(bright)
|
||||
yy= '\033[93m' #yellow(bright)
|
||||
b = '\033[1m' #bold
|
||||
u = '\033[4m' #underline
|
||||
R = '\033[1;31m' #bold, red
|
||||
G = '\033[1;32m' #bold, green
|
||||
Y = '\033[1;33m' #bold, yellow
|
||||
|
||||
|
||||
class logHandler(logging.StreamHandler):
|
||||
def __init__(self):
|
||||
logging.StreamHandler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
'''override function of base class'''
|
||||
try:
|
||||
msg=self.format(record)
|
||||
# print(record.__dict__)
|
||||
if record.levelno<=10:
|
||||
c=col.g
|
||||
elif record.levelno<=20:
|
||||
c=col.y
|
||||
elif record.levelno<=30:
|
||||
c=col.yy
|
||||
elif record.levelno<=40:
|
||||
c=col.r
|
||||
else:
|
||||
c=col.rr+col.b
|
||||
msg=c+msg+col.d
|
||||
stream=self.stream
|
||||
stream.write(msg+self.terminator)
|
||||
self.flush()
|
||||
except RecursionError:
|
||||
raise
|
||||
except Exception:
|
||||
self.handleError(record)
|
||||
|
||||
|
||||
class ARESdevice():
|
||||
_lutDifrBeamPaint=( # (number of difr beam,draw mode,alpha,width)
|
||||
(4, 2, 190, 0),
|
||||
@@ -141,11 +187,11 @@ class ARESdevice():
|
||||
'drx':drx})
|
||||
|
||||
if degArm>10:
|
||||
raise(ValueError('angle arm > 10°'))
|
||||
raise(ValueError('angle arm > 10deg'))
|
||||
elif degArm<1:
|
||||
raise(ValueError('angle arm < 1°'))
|
||||
raise(ValueError('angle arm < 1deg'))
|
||||
elif abs(dd)>15:
|
||||
raise(ValueError('angle bellow to detector > 15°'))
|
||||
raise(ValueError('angle bellow to detector > 15deg'))
|
||||
|
||||
def containsPoint(self,point):
|
||||
try:
|
||||
@@ -330,6 +376,14 @@ class ARESdevice():
|
||||
# qp.setTransform(tf);self.plotOrig(qp)
|
||||
|
||||
class WndVisualize(QWidget):
|
||||
_pv2key={
|
||||
'SATES30-RIXS:MOT_RY.RBV' :'aArm',
|
||||
'SATES30-ARES:MOT_JFRY.RBV':'aJFr',
|
||||
'SATES30-ARES:MOT_2TRY.RBV':'a2Th',
|
||||
'SATES30-ARES:MOT_DRY.RBV' :'aDet',
|
||||
'SATES30-ARES:MOT_SRY.RBV' :'aTrg'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
@@ -354,7 +408,8 @@ class WndVisualize(QWidget):
|
||||
('sclA', ( -8, 8), 1),
|
||||
('sclD', (-8, 8), 1),):
|
||||
|
||||
wLb=QLabel(key)
|
||||
wLb=QLabel(f"<font>{key}</font>",objectName=key) #MOST BE with <font> as it is changed later and else creates a seg fault
|
||||
|
||||
wSl=QSlider(QtCore.Qt.Horizontal,objectName=key)
|
||||
wSl.setFixedWidth(200);wSl.setMinimum(rng[0]);wSl.setMaximum(rng[1])
|
||||
if key.startswith('scl'):
|
||||
@@ -371,35 +426,61 @@ class WndVisualize(QWidget):
|
||||
|
||||
lg.addWidget(wLb, row, 0)
|
||||
lg.addWidget(wSl, row, 1);row+=1
|
||||
|
||||
#self.event_update.connect(self.cb_update)
|
||||
self.show()
|
||||
|
||||
def cb_update(self,*args,**kwargs):
|
||||
_log.debug(f'{args} {kwargs}')
|
||||
|
||||
def connectEPICS(self):
|
||||
self._pv=pv=set()
|
||||
for rec_name in (
|
||||
'SATES30-RIXS:MOT_RY',
|
||||
'SATES30-ARES:MOT_JFRY',
|
||||
'SATES30-ARES:MOT_2TRY',
|
||||
'SATES30-ARES:MOT_DRY',
|
||||
'SATES30-ARES:MOT_SRY',):
|
||||
_log.info('connect PVs')
|
||||
self._pvDict=pvd=dict()
|
||||
self._pvConnected=0
|
||||
for pvn in self._pv2key.keys():
|
||||
pv=epics.get_pv(pvn,connection_callback=self.OnConnectionChange,callback=self.OnValueChange)
|
||||
pvd[pvn]=pv
|
||||
_log.info(f'{pv}')
|
||||
#epics.Motor checks the record type and will fail if the record is not online
|
||||
#therefore use epics.Device
|
||||
#epics.Device will force to connect the PV in Device.add_callback
|
||||
#therefore use epics.PV.add_callback to acc callback
|
||||
#as soon as the devices are online, they are connected
|
||||
#but with epics.Device creating PV is not fully flexible. epics.get_pv proviles connection and value change callbacks that is way more flexible.
|
||||
#therefore the lowest level of the library (only pvs is the best suited
|
||||
#m=epics.Motor(rec_name)
|
||||
#m=epics.Device(rec_name, delim='.',with_poll=False,attrs=('VAL', 'RBV', 'DESC', 'RVAL','LVIO', 'HLS', 'LLS'))
|
||||
#m.add_callback('RBV', self.OnChangedRBV)
|
||||
#pv=m.PV('RBV',connect=False)
|
||||
#pv.add_callback(self.OnChangedRBV)
|
||||
#pv.connection_callbacks
|
||||
#if not pv.connected:
|
||||
# disconnected.add(rec_name)
|
||||
#print(pv.connected)
|
||||
#devs.add(m)
|
||||
|
||||
m=epics.Motor(rec_name)
|
||||
pv.add(m)
|
||||
#_log.debug(m.get_position()) # this is the VAL field
|
||||
#_log.debug(m.PV('RBV').get()) # this is the RBV field
|
||||
#_log.debug(m.get('RBV')) # this is the RBV field
|
||||
#m.add_callback('RBV', self.update_label)
|
||||
#m.set_callback('RBV', self.emit_signals, {'source_field': 'RBV'})
|
||||
#/home/zamofing_t/.local/lib/python3.8/site-packages/epics/motor.py
|
||||
m.add_callback('RBV', self.OnChangedRBV)
|
||||
#print(pv)
|
||||
# def update_label(self, **kwargs):
|
||||
# _log.info(kwargs)
|
||||
def OnConnectionChange(self, pvname=None, conn=None, **kws):
|
||||
pvc=self._pvConnected
|
||||
if conn:
|
||||
pvc+=1
|
||||
else:
|
||||
if pvc>0: pvc-=1
|
||||
_log.info(f'PV connection {pvc}/{len(self._pvDict)}: {pvname} {conn}')
|
||||
self._pvConnected=pvc
|
||||
|
||||
# def emit_signals(self, **kw):
|
||||
# _log.info(kw)
|
||||
app=QApplication.instance()
|
||||
wGrp=app._wndVisualize._wdGrpDraw
|
||||
key=self._pv2key[pvname]
|
||||
wLb=wGrp.findChild(QLabel, key)
|
||||
if not conn:
|
||||
v=f"<font color='#a00000'>{key}</font>"
|
||||
wLb.setText(v)
|
||||
else:
|
||||
v=f"<font color='#00a000'>{key}</font>"
|
||||
wLb.setText(v)
|
||||
|
||||
def OnValueChange(self, pvname, value, **kw):
|
||||
#def OnChangedRBV(self, **kw):
|
||||
def OnChangedRBV(self, pvname, value, **kw):
|
||||
#_log.info(kw)
|
||||
#{
|
||||
# 'pvname': 'SATES30-ARES:MOT_2TRY.RBV',
|
||||
@@ -434,19 +515,43 @@ class WndVisualize(QWidget):
|
||||
# 'cb_info': (1, <PV 'SATES30-ARES:MOT_2TRY.RBV', count=1, type=time_double, access=read-only>)
|
||||
#}
|
||||
#_log.info(f"{kw['pvname']}:{kw['value']}")
|
||||
_log.info(f"{pvname}:{value}")
|
||||
if pvname=='SATES30-RIXS:MOT_RY.RBV':
|
||||
self.sldChanged('aArm',value)
|
||||
elif pvname=='SATES30-ARES:MOT_JFRY.RBV':
|
||||
self.sldChanged('aJFr',value)
|
||||
elif pvname=='SATES30-ARES:MOT_2TRY.RBV':
|
||||
self.sldChanged('a2Th',value)
|
||||
elif pvname=='SATES30-ARES:MOT_DRY.RBV':
|
||||
self.sldChanged('aDet',value)
|
||||
elif pvname=='SATES30-ARES:MOT_SRY.RBV':
|
||||
self.sldChanged('aTrg',value)
|
||||
else:
|
||||
_log.info(f"PV val:{pvname}:{value}")
|
||||
|
||||
try:
|
||||
key=self._pv2key[pvname]
|
||||
except KeyError as e:
|
||||
_log.warning(f"can't handle PV: {pvname}:{value}")
|
||||
return
|
||||
self.vis_update(key,value,'008000')
|
||||
|
||||
def vis_update(self,key,value,col='000000'):
|
||||
app=QApplication.instance()
|
||||
wGrp=app._wndVisualize._wdGrpDraw
|
||||
wSl=wGrp.findChild(QSlider, key)
|
||||
wSl.blockSignals(True)
|
||||
wSl.setValue(int(value)) # move the slider without emiting a signal
|
||||
wSl.blockSignals(False)
|
||||
self.sldChanged(key,value) # emit the signal
|
||||
#self.event_update.emit(pvname=pvname, value=None)
|
||||
wLb=wGrp.findChild(QLabel, key)
|
||||
v=f"<font color='#{col}'>{key}</font>"
|
||||
wLb.setText(v)
|
||||
|
||||
def liveView(self):
|
||||
# try to live update all PVs
|
||||
_log.info('')
|
||||
p2k=self._pv2key
|
||||
for pv in self._pvDict.values():
|
||||
pvn=pv.pvname
|
||||
key=p2k[pvn]
|
||||
if pv.connected:
|
||||
value=pv.get()
|
||||
self.vis_update(key,value,'008000')
|
||||
print (pvn,key,value)
|
||||
else:
|
||||
print (pvn,key)
|
||||
pass
|
||||
|
||||
|
||||
def destroy(self, destroyWindow, destroySubWindows): #overloaded function
|
||||
_log.info('destroy')
|
||||
@@ -477,6 +582,11 @@ class WndVisualize(QWidget):
|
||||
g[key]=90-val/sclA
|
||||
else:
|
||||
g[key]=val
|
||||
wGrp=app._wndVisualize._wdGrpDraw
|
||||
wLb=wGrp.findChild(QLabel, key)
|
||||
v=f"<font color='#0000ff'>{key}</font>"
|
||||
wLb.setText(v)#print(wLb,v)
|
||||
|
||||
self.update()
|
||||
|
||||
def mouseReleaseEvent(self, a0):
|
||||
@@ -494,6 +604,7 @@ class WndVisualize(QWidget):
|
||||
wGrp=self._wdGrpDraw
|
||||
#if wGrp.underMouse(): #draging sliders?
|
||||
if wGrp.geometry().contains(mousePos):
|
||||
self.liveView()
|
||||
self._mouseDrag={'obj':wGrp, 'start':mousePos}
|
||||
return
|
||||
dev=app._dev
|
||||
@@ -513,7 +624,7 @@ class WndVisualize(QWidget):
|
||||
v=int(round(np.log2(v)*2))
|
||||
else:
|
||||
v=devP[key]
|
||||
wSl.setValue(v)
|
||||
wSl.setValue(int(v))
|
||||
|
||||
self._mouseDrag={'obj':dev,'start':(mousePos,dev._paint['ofs'])}
|
||||
try:
|
||||
@@ -578,7 +689,7 @@ class WndVisualize(QWidget):
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||
logging.basicConfig(level=logging.DEBUG, handlers=[logHandler()], format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
Reference in New Issue
Block a user