This commit is contained in:
2022-07-13 16:52:27 +02:00
parent 756713f230
commit 3904a1a134
5 changed files with 614 additions and 67 deletions

View File

@@ -1,3 +1,13 @@
pyqtgraph examples
------------------
```
ipython3
import pyqtgraph.examples
pyqtgraph.examples.run()
```
EPICS simulator
---------------
```
@@ -23,9 +33,38 @@ EPICS_CA_ADDR_LIST=localhost
./camera.py -u -b SwissMxSim
```
test at ESC
-----------
```
https://git.psi.ch/SwissMX/swissmx_cristallina/-/wikis/Instructions%20on%20how%20to%20use%20software
P=ESB_MX/python/SwissMX/
ssh saresc-cons-02 mkdir -p /tmp/zamofing_t/$P
rsync -vai ~/Documents/prj/SwissFEL/epics_ioc_modules/$P saresc-cons-02:/tmp/zamofing_t/$P
cd /tmp/zamofing_t/ESB_MX/python/SwissMX
/opt/gfa/python-3.7/2018.12/bin/python camera.py -u -p SARES30-CAMS156-SMX-OAV
caqtdm -macro 'NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV' /sf/controls/config/qt/Camera/CameraExpert_RF.ui
```
try revive Zac code
-------------------
```
cd /tmp/; git clone https://github.com/malcolmreynolds/transformations.git
cd /tmp/transformations.git
-> modify __init__.py -> .transformation (add dot)
setup.py install --user
cd /tmp/; git clone https://github.com/spyder-ide/qtawesome.git
cd /tmp/qtawesome
```
caQtDM -macro 'P=SAR-EXPMX' /photonics/home/gac-cristall/Documents/swissmx_cristallina/gui/SwissMX_ChipMotion.ui
caQtDM -macro 'P=SAR-EXPMX' ESB_MX_exp.ui

161
camera.py
View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
"""
Hi Zac,
@@ -19,16 +20,21 @@ Best regards
import enum
import logging
_log = logging.getLogger(__name__)
import epics
import numpy as np
logger = logging.getLogger(__name__)
class CamMode(enum.IntEnum):
class Camera(enum.IntEnum):
OFF = 0
RUNNING = 1
class CameraStatus(enum.IntEnum):
OFFLINE = 0
IDLE = 1
RUNNING = 2
class epics_cam(object):
@@ -36,8 +42,6 @@ class epics_cam(object):
self._pv=pv=dict()
if prefix[-1]!=':': prefix+=':'
self._prefix=prefix
pv_w=self.getPv('WIDTH');pv_h=self.getPv('HEIGHT')
self._sz=(int(pv_w.value), int(pv_h.value))
def getPv(self,name):
try:
@@ -101,6 +105,31 @@ class epics_cam(object):
pic=pic[::trf[0,1],::trf[1,0]].T
self.pic=pic
return pic
def stop(self,v=CameraStatus.IDLE):
if 'pic' in self._pv:
del self._pv['pic']
if v is not None:
pv_cs = self.getPv('CAMERASTATUS')
pv_cs.put(v, wait=True)
def run(self,cb=None):
pv_cam=self.getPv('CAMERA')
if pv_cam.value==Camera.OFF:
pv_cs = self.getPv('CAMERASTATUS')
pv_cs.put(CameraStatus.RUNNING, wait=True)
while pv_cam.value==Camera.OFF:
print('wait...');time.sleep(.5)
self.update_size()
if cb is None:
self._pv['pic'] = epics.PV(self._prefix + "FPICTURE")
else:
self._pv['pic'] = epics.PV(self._prefix + "FPICTURE", auto_monitor=True, callback=cb)
def update_size(self):
pv_w=self.getPv('WIDTH');pv_h=self.getPv('HEIGHT')
self._sz=(int(pv_w.value), int(pv_h.value))
def set_exposure(self,exp):
pv_exp=self.getPv('EXPOSURE')
@@ -110,7 +139,7 @@ class epics_cam(object):
def set_roi(self,rxs,rxe,rys,rye):
pv_rxs=self.getPv('REGIONX_START');pv_rxe=self.getPv('REGIONX_END')
pv_rys=self.getPv('REGIONY_START');pv_rye=self.getPv('REGIONY_END')
self.update_params((pv_rxs,rxs),(pv_rxe,rxe),(pv_rys,rys),(pv_ryerye))
self.update_params((pv_rxs,rxs),(pv_rxe,rxe),(pv_rys,rys),(pv_rye,rye))
def set_binning(self,bx,by):
pv_bx=self.getPv('BINX');pv_by=self.getPv('BINY')
@@ -120,43 +149,71 @@ class epics_cam(object):
def update_params(self, *args):
"""update parameters on camera"""
for pv, val in args:
logging.debug("updating {} = {}".format(pv, v))
if not pv.connected:
_log.info('force connect {}'.format(pv))
pv.force_connect() #force to connect pv
_log.debug("updating {} = {}".format(pv.pvname, val))
pv.put(val, wait=True)
pv_camera=self.getPv('CAMERA')
pv_set_param=self.getPv("SET_PARAM")
pv_camera.put(CamMode.OFF, wait=True)
pv_set_param.put(1, wait=True)
pv_camera.put(CamMode.RUNNING, wait=True)
#TODO: update self._sz
pv_cam=self.getPv('CAMERA')
pv_cs = self.getPv('CAMERASTATUS')
#pv_set_param=self.getPv("SET_PARAM")
pv_cam.put(CameraStatus.IDLE, wait=True)
#pv_set_param.put(1, wait=True)
pv_cam.put(CameraStatus.RUNNING, wait=True)
self.update_size()
if __name__ == "__main__":
import time, os, PIL
logging.basicConfig(format="%(asctime)s $(levelname)s %(message)s", level=logging.DEBUG)
import time, os, PIL.Image, platform, subprocess
import argparse
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
def default_app_open(file):
if platform.system() == 'Darwin': # macOS
subprocess.call(('open', file))
elif platform.system() == 'Windows': # Windows
os.startfile(file)
else: # linux variants
subprocess.call(('xdg-open', file))
parser = argparse.ArgumentParser()
parser.add_argument("--ui", "-u", help="qt test", action="store_true")
parser.add_argument("--prefix","-p",help="PV prefix for images; default=ESB-MX-CAM",type=str,default="ESB-MX-CAM",)
parser.add_argument("--ui", "-u", help="qt test", type=int, default=0)
parser.add_argument("--prefix","-p",help="PV prefix for images: default=%(default)s",type=str,default="SARES30-CAMS156-SMX-OAV",)
args = parser.parse_args()
print('STARTING')
os.environ['EPICS_CA_ADDR_LIST']='localhost'
_log.info('STARTING')
if args.prefix=='SwissMxSim':
os.environ['EPICS_CA_ADDR_LIST']='localhost'
else:
os.environ['EPICS_CA_ADDR_LIST'] ='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
if not args.ui:
cam = epics_cam(prefix=args.base_pv)
cam = epics_cam(prefix=args.prefix)
#sz=(2448,2048)
#ctr=(1200,1400)
#sz=(1200,1000)
#cam.set_roi(int(ctr[0]-sz[0]/2),int(ctr[0]+sz[0]/2),int(ctr[1]-sz[1]/2),int(ctr[1]+sz[1]/2))
#cam.set_exposure(3)
#cam.set_binning(1,1)
cam.run()
n = 1
base = time.strftime("/tmp/image_%Y%m%d_%H%M%S_{:05d}.png")
base = "/tmp/image_{:05d}.png"
while True:
fname = base.format(n)
img=cam.get_image()
print(type(img))
type(img)
mx= img.max()
if img.dtype==np.uint16 and mx<256:
_log.info('reformat to uint 8')
img=np.uint8(img)
print(img,img.dtype)
PIL.Image.fromarray(img).save(fname)
logging.info("acquired {}".format(fname))
fn = base.format(n)
PIL.Image.fromarray(img).save(fn)
_log.info('File {} shape:{} dtype:{} max:{}'.format(fn,img.shape,img.dtype,img.max()))
default_app_open(fn)
try:
input("<enter> for next image, ctrl-c to abort")
except KeyboardInterrupt:
@@ -167,18 +224,16 @@ if __name__ == "__main__":
def __init__(self, prefix="ESB-MX-CAM"):
epics_cam.__init__(self,prefix)
self._pv['pic'] = epics.PV(self._prefix + "FPICTURE", auto_monitor=True, callback=self.new_frame_pv_cb)
pass
def new_frame_pv_cb(self, **kwargs):
pv = self._pv
sz = self._sz
if kwargs['count']==sz[0] * sz[1]:
pic = kwargs['value'].reshape(sz[::-1])
pic=kwargs['value'].reshape(sz[::-1])
else:
self._sz = (int(pv['w'].value), int(pv['h'].value))
print('new_frame_pv_cb SIZE ERROR:',pic[-1][-1],kwargs['count'])
return
sz=self.update_size()
pic=kwargs['value'].reshape(sz[::-1])
print('new_frame_pv_cb',pic[-1][-1],kwargs['count'])
if pic.dtype==np.int16:
pic.dtype=np.uint16
@@ -211,46 +266,20 @@ if __name__ == "__main__":
win.show()
win.setWindowTitle('pyqtgraph example: ImageView')
## Create random 3D data set with noisy signals
img = pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100
img = img[np.newaxis,:,:]
decay = np.exp(-np.linspace(0,0.3,100))[:,np.newaxis,np.newaxis]
data = np.random.normal(size=(100, 200, 200))
data += img * decay
data += 2
## Add time-varying signal
sig = np.zeros(data.shape[0])
sig[30:] += np.exp(-np.linspace(1,10, 70))
sig[40:] += np.exp(-np.linspace(1,10, 60))
sig[70:] += np.exp(-np.linspace(1,10, 30))
sig = sig[:,np.newaxis,np.newaxis] * 3
data[:,50:60,30:40] += sig
## Display the data and assign each frame a time value from 1.0 to 3.0
imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0]))
cam = UIcamera(prefix=args.prefix)
cam.get_image()
imv.setImage(cam.pic)
#cam.set_binning(4,4)
#cam.run()
#cam.get_image()
#imv.setImage(cam.pic, autoRange=True, autoLevels=True)
#cam.stop(None)
cam.run(cam.new_frame_pv_cb)
## Set a custom color map
colors = [
(0, 0, 0),
(45, 5, 61),
(84, 42, 55),
(150, 87, 60),
(208, 171, 141),
(255, 255, 255)
]
colors = [(0, 0, 0),(45, 5, 61),(84, 42, 55),(150, 87, 60),(208, 171, 141),(255, 255, 255)]
cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors)
imv.setColorMap(cmap)
## Start Qt event loop unless running in interactive mode.
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

152
illumination.py Executable file
View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python
import logging
_log=logging.getLogger(__name__)
import socket
'''
Please do not leave the LEDs on longer than needed, especially the colored ones.
I guess I have an issue with
power dissipation on my board. For the white LEDs it should be ok.
The lights communicate in hexidecimal, two 2bytes:
byte 1:
0x00 get status
0x01 off
0x02 on
0x04 out (unused?)
byte 2:
0x01 front white
0x02 front red
0x04 front green
0x08 front blue
0x10 back white
'''
# commands
stat= 0x00
off = 0x01
on = 0x02
# leds
front = 0x01
red = 0x02
green = 0x04
blue = 0x08
back = 0x10
all = 0xff
class IlluminationControl(object):
def __init__(self,hostname: str,port: int):
self._hostname = hostname
self._port = port
self.connect()
def connect(self):
"""creates a socket and connects to illumination controller"""
# connect to XT-PICO
self._socket=s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
s.connect((self._hostname, self._port))
def disconnect(self):
try:
self._socket.close()
except AttributeError:
pass
def is_on(self, led_flags: int) -> bool:
"""check status for light state, see CONSTANTS STATUS_BITS_*"""
try:
s = self.status()[0]
except:
print("error reading status")
return False
return bool(s & led_flags)
def send_command(self, cmd: bytes):
try:
self._socket.sendall(cmd)
except (BrokenPipeError, OSError) as e:
_log.warning("reconnecting lights")
self.connect()
try:
self._socket.sendall(cmd)
except Exception as e:
raise IlluminationControlException("unrecoverable socket error: {}".format(e.args))
def status(self):
self.send_command(bytes((stat,all)))
resp = self._socket.recv(1024)
return resp[0]&0x1f
def all(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,all)))
def front(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,front)))
def back(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,back)))
def red(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,red)))
def blue(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,blue)))
def green(self,val):
cmd = on if val else off
self.send_command(bytes((cmd,green)))
if __name__ == "__main__":
import argparse
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--mode', help='mode string with characters: "frgbka" for front,red,green,blue,back,all')
parser.add_argument("-t", "--test", help="test sequence", action="store_true")
args = parser.parse_args()
_log.debug(args)
host = "129.129.221.92"
port = 1003
leds = IlluminationControl(host,port)
if args.test:
leds.all(False)
print(bin(leds.status()));time.sleep(1)
leds.front(True)
print(bin(leds.status()));time.sleep(1)
leds.front(False); leds.red(True)
print(bin(leds.status()));time.sleep(1)
leds.red(False); leds.green(True)
print(bin(leds.status()));time.sleep(1)
leds.green(False); leds.blue(True)
print(bin(leds.status()));time.sleep(1)
leds.blue(False); leds.back(True)
print(bin(leds.status()));time.sleep(1)
leds.back(False)
print(bin(leds.status()));time.sleep(1)
else:
leds.all(False)
_log.debug('turn off all')
if args.mode is not None:
m=args.mode
l=0
if 'f' in m: l|=front
if 'r' in m: l|=red
if 'g' in m: l|=green
if 'b' in m: l|=blue
if 'k' in m: l|=back
if 'a' in m: l|=all
leds.send_command(bytes((on,l)))
_log.debug('turn on %s'%bin(l))

327
zoom.py Executable file
View File

@@ -0,0 +1,327 @@
#!/usr/bin/env python
import json
import logging
_log=logging.getLogger(__name__)
import os
import qtawesome
from PyQt5 import QtWidgets, uic
import PyQt5.QtWidgets as qtw
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import (
QApplication,
QPushButton,
QGroupBox,
QGridLayout,
QLabel,
QDoubleSpinBox,
QComboBox,
QSpinBox,
QVBoxLayout,
QHBoxLayout,
QCheckBox,
)
from PyQt5.uic import loadUiType
import epics
Ui_Zoom, QWidget = loadUiType("epics_widgets/zoom.ui")
MIN_ZOOM = 1
MAX_ZOOM = 1000
SPINNER_SINGLE_STEP = 50
SPINNER_LARGE_STEP = 200
class Zoom(QGroupBox, Ui_Zoom):
zoomChanged = pyqtSignal(float)
moveBacklight = pyqtSignal(str)
def __init__(self, parent=None):
super(Zoom, self).__init__(parent=parent)
self.setupUi(self)
self.setTitle("Sample Viewing")
def configure(self):
keys = settings.allKeys()
if "sample_viewing/zoom_buttons" not in keys:
settings.setValue("sample_viewing/zoom_buttons",
json.dumps([(1, "1"),(200, "200"),(400, "400"),(600, "600"),(800, "800"),(1000, "1000"),]),)
buttons = json.loads(settings.value("sample_viewing/zoom_buttons"))
if "backlight/backlight_pv" not in keys:
settings.setValue("backlight/backlight_pv", "SAR-EXPMX:MOT_BLGT")
backlight_pv = settings.value("backlight/backlight_pv")
if "sample_viewing/zoom_api" not in keys:
settings.setValue("sample_viewing/zoom_api", "rest://pc12818.psi.ch:9999")
zoom_api = settings.value("sample_viewing/zoom_api")
#self.get_zoom_pv = PV(zoom_api + ":ZOOM-RBV", callback=self.zoom_update_cb)
#self.status_pv = PV(zoom_api + ":ZOOM-STATUS", callback=self.zoom_status_cb)
current_zoom_value = self.get_zoom()
# zoom widgets
layout = QVBoxLayout()
layout.setSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self._button_box.setLayout(layout)
self._zoom_spinner = QSpinBox()
self._zoom_spinner.setRange(MIN_ZOOM, MAX_ZOOM)
self._zoom_spinner.setValue(current_zoom_value)
self._zoom_spinner.editingFinished.connect(self.move_zoom_a)
# self._zoom_spinner.setSingleStep(SPINNER_SINGLE_STEP)
self._zoom_spinner.setSingleStep(SPINNER_LARGE_STEP)
_box = QWidget()
_box.setLayout(QHBoxLayout())
_box.layout().setSpacing(0)
_box.layout().setContentsMargins(0, 0, 0, 0)
_box.layout().addWidget(QLabel("Zoom Level"))
_box.layout().addWidget(self._zoom_spinner)
layout.addWidget(_box)
_box = QWidget()
_box.setLayout(QGridLayout())
_box.layout().setContentsMargins(0, 0, 0, 0)
for n, b in enumerate(buttons):
row, col = n // 2, n % 2
value, label = b
but = QPushButton(label)
but.setCheckable(True)
but.setChecked(value == current_zoom_value)
but.setAutoExclusive(True)
but.setAccessibleName("zoom_button")
but.setObjectName("zoom_{}".format(value)) # used with findChild()
but.pressed.connect(lambda x=value: self.move_zoom(x))
_box.layout().addWidget(but, row, col, 1, 1)
self._zoom_buttonbox = _box
layout.addWidget(_box)
# backlight
self._top_grid.setLayout(QVBoxLayout())
lbox = QWidget()
lbox.setLayout(QHBoxLayout())
lbox.layout().setSpacing(0)
lbox.layout().setContentsMargins(0, 0, 0, 0)
self._top_grid.layout().addWidget(lbox)
#self.blgt_button = QPushButton(qtawesome.icon("material.lightbulb_outline"), "Backlight")
self.blgt_button = QPushButton( "Backlight")
self.blgt_button.clicked.connect(self.toggle_backlight)
lbox = QWidget()
lbox.setLayout(QHBoxLayout())
lbox.layout().setSpacing(0)
lbox.layout().setContentsMargins(0, 0, 0, 0)
self._top_grid.layout().addWidget(lbox)
lbox.layout().addWidget(self.blgt_button)
leds=QApplication.instance()._illumination
but = QCheckBox("Back")
but.setChecked(leds.is_on(illumination.back))
but.stateChanged.connect(self.back_toggle)
lbox.layout().addWidget(but)
but = QCheckBox("Front")
but.setChecked(leds.is_on(illumination.front))
but.stateChanged.connect(self.front_toggle)
lbox.layout().addWidget(but)
lbox = QWidget()
lbox.setLayout(QHBoxLayout())
lbox.layout().setSpacing(0)
lbox.layout().setContentsMargins(0, 0, 0, 0)
self._top_grid.layout().addWidget(lbox)
but = QCheckBox("Red")
but.setChecked(leds.is_on(illumination.red))
but.stateChanged.connect(self.red_toggle)
lbox.layout().addWidget(but)
but = QCheckBox("Green")
but.setChecked(leds.is_on(illumination.green))
but.stateChanged.connect(self.green_toggle)
lbox.layout().addWidget(but)
but = QCheckBox("Blue")
but.setChecked(leds.is_on(illumination.blue))
but.stateChanged.connect(self.blue_toggle)
lbox.layout().addWidget(but)
lbox = QWidget()
lbox.setLayout(QHBoxLayout())
lbox.layout().setSpacing(0)
lbox.layout().setContentsMargins(0, 0, 0, 0)
self._top_grid.layout().addWidget(lbox)
self.slid = None
cam=QApplication.instance()._camera
grp = QGroupBox("Camera settings")
grid = QGridLayout()
grp.setLayout(grid)
lab = QLabel("Exposure (ms)")
grid.addWidget(lab, 0, 0)
self.slid = QDoubleSpinBox()
self.slid.setValue(cam.get_exposure())
self.slid.setMinimum(0.001)
self.slid.setMaximum(1000.000)
self.slid.setDecimals(3)
self.slid.setSuffix(" ms")
grid.addWidget(self.slid, 0, 1)
#grid.addWidget(QLabel("Acq.Mode"), 1, 0)
#cbox = QComboBox()
#for mode in Camera.AcquisitionMode:
# cbox.addItem(mode.name, mode)
#cbox.setCurrentIndex(cam.pv_acqmode.get())
#cbox.currentIndexChanged.connect(self.update_camera_acqmode)
#grid.addWidget(cbox, 1, 1)
lbox.layout().addWidget(grp)
self.slid.editingFinished.connect(lambda: self.update_exposure(self.slid.value()))
def back_toggle(self, state):
leds=QApplication.instance()._illumination
leds.back(state)
def front_toggle(self, state):
leds=QApplication.instance()._illumination
leds.front(state)
def red_toggle(self, state):
leds=QApplication.instance()._illumination
leds.red(state)
def green_toggle(self, state):
leds=QApplication.instance()._illumination
leds.green(state)
def blue_toggle(self, state):
leds=QApplication.instance()._illumination
leds.blue(state)
def toggle_backlight(self):
bl=QApplication.instance()._backlight
if bl.is_in() or bl.is_diode():
self.moveBacklight.emit("out")
self.blgt_button.setText("Move Backlight IN")
else:
self.moveBacklight.emit("in")
self.blgt_button.setText("Move Backlight OUT")
def update_camera_exposure(self, nv):
cam=QApplication.instance()._camera
cam.set_exposure(nv)
def update_exposure(self, nv):
_log.debug("update_exposure: {} {}".format(nv, self.slid.singleStep()))
if nv > 100:
self.slid.setSingleStep(50)
elif 100 > nv > 50:
self.slid.setSingleStep(10)
elif 50 > nv > 10:
self.slid.setSingleStep(5)
elif 10 > nv > 2:
self.slid.setSingleStep(1)
elif 2 > nv > 1.19:
self.slid.setSingleStep(0.2)
elif 1 > nv > 0.1:
self.slid.setSingleStep(0.1)
else:
self.slid.setSingleStep(0.01)
_log.debug("update_exposure: {} {}".format(nv, self.slid.singleStep()))
if nv > 0.001:
cam = QApplication.instance()._camera
cam.set_exposure(nv)
def update_camera_acqmode(self, index):
_log.debug("changing camera mode: {}".format(index))
cam=QApplication.instance()._camera
cam.auto(index)
def move_zoom_a(self):
nval = self._zoom_spinner.value()
self.move_zoom(nval)
def move_zoom(self, value: int):
zoom=QApplication.instance()._zoom
_log.debug("zooming to : {}".format(value))
self._zoom_spinner.blockSignals(True)
zoom.set(value)
but = "zoom_{:d}".format(value)
_log.debug("looking for button: {}".format(but))
for bbut in self._zoom_buttonbox.findChildren(QPushButton):
bbut.blockSignals(True)
curbut = bbut.objectName()
checked = curbut == but
bbut.setChecked(checked) # FIXME this is not working
bbut.blockSignals(False)
self._zoom_spinner.setValue(int(value))
self._zoom_spinner.blockSignals(False)
self.zoomChanged.emit(float(value))
def get_zoom(self) -> int:
zoom=QApplication.instance()._zoom
pos = zoom.get()
_log.debug("get_zoom(epics) => {}".format(pos))
return pos
def zoom_update_cb(self, pvname, value, char_value, **kwargs):
self._zoom_spinner.blockSignals(True)
self._zoom_spinner.setValue(value)
self._zoom_spinner.blockSignals(False)
def zoom_status_cb(self, pvname, value, char_value, **kwargs):
busy = bool(value)
self.setDisabled(busy)
class QopticZoom(object):
def __init__(self, prefix='SAR-EXPMX-FETURA'):
self._pv=pv=dict()
if prefix[-1]!=':': prefix+=':'
self._prefix=prefix
def getPv(self,name):
try:
pv=self._pv[name]
except KeyError:
prefix=self._prefix
pv=epics.PV(prefix+name)
self._pv[name]=pv
return pv
def get(self) -> int:
pv=self.getPv('POS_RB')
return pv.get()
def set(self, val: int):
pv=self.getPv('POS_SP')
pv.put(val)
if __name__ == "__main__":
import sys
import backlight
import illumination
import camera
from app_config import settings, appsconf
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
_log.debug('Start')
app = QApplication(sys.argv)
app._backlight = backlight.Backlight()
app._illumination = illumination.IlluminationControl("129.129.221.92", 1003)
app._zoom = QopticZoom()
app._camera = camera.camera_server('SARES30-CAMS156-SMX-OAV')
simulated = appsconf["microscope"]["zoom"].get("simulate", False)
obj=Zoom()
obj.configure()
obj.show()
app.exec_()