add files and simulated modes

This commit is contained in:
2022-07-14 09:16:29 +02:00
parent 3904a1a134
commit 3815a07cdf
8 changed files with 305 additions and 24 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
__pycache__/

View File

@@ -146,3 +146,8 @@ p.put(a)
print(p.get())
https://pyepics.github.io/pyepics/arrays.html
EPICS_CA_ADDR_LIST='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/oldRepos/app/src
python swissmx.py

70
backlight.py Executable file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
import logging
_log=logging.getLogger(__name__)
import epics
#from app_config import settings
#from app_utils import assert_motor_positions
class Backlight(object):
def __init__(self, prefix: str='SAR-EXPMX:MOT_BLGT'):
if prefix is None:
self._sim={'pos':'out'}
_log.info('simulated mode:{}'.format(self._sim))
return #simulated mode
self._mot = epics.Motor(prefix)
self._pos = {'in':-29000,'out':0}
def is_pos(self,strPos):
try:
m=self._mot
except AttributeError:
_log.info('simulated mode:{}'.format(strPos))
return self._sim['pos']==strPos
m.refresh()
return abs(m.readback - self._pos[strPos]) < 10
def move(self, strPos, wait=False):
try:
m=self._mot
except AttributeError:
_log.info('simulated mode:{}'.format(strPos))
self._sim['pos']=strPos
return
m=self._mot
_log.debug("backlight to {}".format(strPos))
target=self._pos[strPos]
m.move(target, ignore_limits=True, wait=wait)
if __name__ == "__main__":
import time,os
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()
os.environ['EPICS_CA_ADDR_LIST'] = '129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
_log.debug(args)
bl = Backlight()
if args.test:
bl.move('in')
time.sleep(2)
bl.move('out')
time.sleep(2)
bl.move('in')
time.sleep(2)
bl.move('out')
time.sleep(2)

View File

@@ -1,4 +1,10 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
"""
Hi Zac,
@@ -38,7 +44,11 @@ class CameraStatus(enum.IntEnum):
class epics_cam(object):
def __init__(self, prefix="ESB-MX-CAM"):
def __init__(self, prefix='SARES30-CAMS156-SMX-OAV'):
if prefix is None:
self._sim={'exp':3.1315}
_log.info('simulated mode:{}'.format(self._sim))
return #simulated mode
self._pv=pv=dict()
if prefix[-1]!=':': prefix+=':'
self._prefix=prefix
@@ -132,9 +142,21 @@ class epics_cam(object):
self._sz=(int(pv_w.value), int(pv_h.value))
def set_exposure(self,exp):
pv_exp=self.getPv('EXPOSURE')
try:
pv_exp=self.getPv('EXPOSURE')
except AttributeError:
_log.info('simulated mode:{}'.format(exp))
self._sim['exp']=exp
return
pv_exp.put(exp, wait=True)
pass
def get_exposure(self):
try:
pv_exp=self.getPv('EXPOSURE')
except AttributeError:
exp=self._sim['exp'];_log.info('simulated mode:{}'.format(exp))
return exp
return pv_exp.get()
def set_roi(self,rxs,rxe,rys,rye):
pv_rxs=self.getPv('REGIONX_START');pv_rxe=self.getPv('REGIONX_END')

82
geometry.py Normal file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
'''
coordinate systems, optical center, xray axis, pixel sizes etc.
'''
class gepmetry:
def __init__(self):
pass
def find_optical_center(p):
# p is an array of
# at zoom out: (p1x,p1y),(p2x,p2y),(p3x,p3y),...
# at zoom in : (p1x,p1y),(p2x,p2y),(p3x,p3y),...
#
# the pixel positions are given in chip pixel coordinates (0/0= top/right)
# and ignore roi and binning
# the returned (cx,cy) is the pixel koordinate that does not change with zoom
# this coordinate represents also the origin of other coordinates
pass
def zoom2pixsz(zoom):
# this returns the pixel size at a given zoom level
# the returned value is a 2x2 matrix:
# [pxx pxy]
# [pyx pyy] which is interpolated out of a lookup table
#
# [pxx pxy] [nx]
# [pyx pyy]*[ny] results in a vector in meter of a vector [nx,ny] pixels in x and y direction
pass
def set_zoom2pixsz():
#tx: 2d-vector in m when moving px pixel in x direction
#ty: 2d-vector in m when moving py pixel in y direction
# the _lut_z2p is dictionaty a lookuptable
# zoom {1,200,400,600,800,1000}
#[pxx pxy]
#[pyx pyy]
self._lut_z2p=_lut_z2p={
'zoom': np.array((1,200,400,600,800,1000),dtype=np.float32),
'pixsz': np.array(
#((pxx,pxy),(pyx,pyy)), # zoom n
(( 1,0),(0, 1)), # zoom 1
(( 2,0),(0, 2)), # zoom 200
(( 4,0),(0, 4)), # zoom 400
(( 6,0),(0, 6)), # zoom 600
(( 8,0),(0, 8)), # zoom 800
((10,0),(0,10)), # zoom 1000
dtype=np.float32)}
def autofocus():
# cam camera object
# mot motor object
# rng region (min max relative to current position) to seek
# n number of images to take in region
# roi region of interrest to calculate sharpness
# mode mode to calculate sharpness (sum/max-min/hist? of edge detection in roi)
pass
def pix2pos(p,zoom=None):
# returns the position m(x,y) in meter relative to the optical center at a given zoom level of the pixel p(x,y)
# if zoom=None, the last zoom value is used
pass
def pos2pix(p,zoom=None):
# returns the pixel p(x,y) of the position m(x,y) in meter relative to the optical center at a given zoom level
# if zoom=None, the last zoom value is used
pass
def optctr2xray():
# returns the vector m(x,y) of the optical center to the xray
pass

View File

@@ -1,4 +1,10 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
import logging
_log=logging.getLogger(__name__)
@@ -39,7 +45,11 @@ all = 0xff
class IlluminationControl(object):
def __init__(self,hostname: str,port: int):
def __init__(self,hostname: str="129.129.221.92",port: int=1003):
if hostname is None: #simulated mode
self._sim={'stat':0}
_log.info('simulated mode:{}'.format(self._sim))
return
self._hostname = hostname
self._port = port
self.connect()
@@ -59,14 +69,15 @@ class IlluminationControl(object):
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
s = self.status()
return bool(s & led_flags)
def send_command(self, cmd: bytes):
try:
s=self._socket
except AttributeError: #simulated mode
_log.info('simulated mode:{}'.format(cmd))
return
try:
self._socket.sendall(cmd)
except (BrokenPipeError, OSError) as e:
@@ -75,9 +86,14 @@ class IlluminationControl(object):
try:
self._socket.sendall(cmd)
except Exception as e:
raise IlluminationControlException("unrecoverable socket error: {}".format(e.args))
_log.error("unrecoverable socket error: {}".format(e.args))
def status(self):
try:
s=self._socket
except AttributeError: #simulated mode
_log.info('simulated mode')
return self._sim['stat']
self.send_command(bytes((stat,all)))
resp = self._socket.recv(1024)
return resp[0]&0x1f

63
zoom.py
View File

@@ -1,5 +1,12 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
'''
'''
import json
import logging
@@ -25,7 +32,7 @@ from PyQt5.QtWidgets import (
from PyQt5.uic import loadUiType
import epics
Ui_Zoom, QWidget = loadUiType("epics_widgets/zoom.ui")
Ui_Zoom, QWidget = loadUiType("zoom.ui")
MIN_ZOOM = 1
MAX_ZOOM = 1000
SPINNER_SINGLE_STEP = 50
@@ -199,7 +206,7 @@ class Zoom(QGroupBox, Ui_Zoom):
def toggle_backlight(self):
bl=QApplication.instance()._backlight
if bl.is_in() or bl.is_diode():
if bl.is_pos('in'):
self.moveBacklight.emit("out")
self.blgt_button.setText("Move Backlight IN")
else:
@@ -277,6 +284,9 @@ class Zoom(QGroupBox, Ui_Zoom):
class QopticZoom(object):
def __init__(self, prefix='SAR-EXPMX-FETURA'):
if prefix is None:
self._val=1
return #simulated mode
self._pv=pv=dict()
if prefix[-1]!=':': prefix+=':'
self._prefix=prefix
@@ -291,32 +301,57 @@ class QopticZoom(object):
return pv
def get(self) -> int:
pv=self.getPv('POS_RB')
try:
pv = self.getPv('POS_RB')
except AttributeError:
val=self._val; _log.info('simulated mode:{}'.format(val))
return val
else:
pv=self.getPv('POS_RB')
return pv.get()
def set(self, val: int):
pv=self.getPv('POS_SP')
pv.put(val)
try:
pv=self.getPv('POS_SP')
except AttributeError:
_log.info('simulated mode:{}'.format(val))
self._val=val #simulated mode
else:
pv.put(val)
if __name__ == "__main__":
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 ')
parser = argparse.ArgumentParser()
parser.add_argument("--sim", "-s", help="simulate all devices", action='store_true')
args = parser.parse_args()
import sys
import backlight
import illumination
import camera
_log.info('Start')
os.environ['EPICS_CA_ADDR_LIST'] = '129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
app = QApplication(sys.argv)
from app_config import settings, appsconf
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
if args.sim:
app._backlight = backlight.Backlight(None)
app._illumination = illumination.IlluminationControl(None)
app._zoom = QopticZoom(None)
app._camera = camera.epics_cam(None)
else:
app._backlight = backlight.Backlight()
app._illumination = illumination.IlluminationControl()
app._zoom = QopticZoom()
app._camera = camera.epics_cam()
_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)

50
zoom.ui Normal file
View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QGroupBox" name="_top_grid">
<property name="title">
<string>Lighting &amp;&amp; Camera</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="_button_box">
<property name="title">
<string>Zoom</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>