add files and simulated modes
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__/
|
||||
@@ -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
70
backlight.py
Executable 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)
|
||||
28
camera.py
28
camera.py
@@ -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
82
geometry.py
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
63
zoom.py
@@ -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
50
zoom.ui
Normal 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 && 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>
|
||||
Reference in New Issue
Block a user