Added PCO panel
This commit is contained in:
@@ -139,6 +139,8 @@ beamline console running the contros stack by:
|
||||
```
|
||||
caqtdm -macro "CAM=X02DA-CAM-GF2" X_X02DA_GIGAFROST_camControl_user.ui
|
||||
caqtdm -macro "P=X02DA-ES1-SMP1" aeroauto1_ControllerOverview.ui
|
||||
# PCO Edge camera panel
|
||||
caqtdm -macro "NAME=X02DA-CCDCAM2" CameraExpert.ui
|
||||
```
|
||||
|
||||
The std-DAQ doesn't have control panels, but the BEC can display the hard-coded preview streams.
|
||||
@@ -154,57 +156,74 @@ gui.panels['tomolive'].add_widget('BECFigure').image('daq_stream0')
|
||||
|
||||
The concept of scans is slightly different in bluesky and BEC. Bluesky strictly separates
|
||||
the device logic in ophyd from the scan logic in plans. Devices are passed in as arguments
|
||||
allowing finetuning their roles.
|
||||
i.e. their behavior is fully managed by the called scan plan in a single layer.
|
||||
|
||||
On the other hand, BEC has two scan interfaces and additional device specific scan logic is
|
||||
placed on the ophyd device itself. The general idea is that the lower-level BEC scans should
|
||||
be completely generic with absolutely minimal logic (although some examples counter this
|
||||
argument). BEC devices live on the DeviceServer, and automatically participate in scans
|
||||
whenever they are enabled. This puts the configuration role either on the ophyd device from
|
||||
the scainfo or in the high level interface that anyways manages the enabling/disabling of devices.
|
||||
placed on the ophyd device itself (total of three levels). Theese are:
|
||||
- Device self-configuration from the scaninfo on the ophyd device
|
||||
- Low-level scan API on the ScanServer
|
||||
- High-level scripting in the BEC console
|
||||
|
||||
The general idea is that the lower-level scan API should be generic with minimal device specific
|
||||
logic (although some examples counter this argument), so the same scan can be re-used across
|
||||
multiple devices. Device specific scan behavior and configuration is defined either on the ophyd
|
||||
device or in the high level interface. In practice, the former means that a device must fish for
|
||||
relevant parameters in the 'scaninfo' message, that's passed around the beginning of each scan.
|
||||
|
||||
Another major difference is that **ALL devices** live on the DeviceServer, and automatically
|
||||
participate in scans whenever they are enabled. This adds the role of scope management to the
|
||||
scripting interface, i.e. enabling/disabling of devices for the particular scan.
|
||||
|
||||
The current repository has several implemented scans to test compliance with standard BEC
|
||||
interfaces and partly cover the old EPICS IOC functionality.
|
||||
|
||||
- If a device is enabled for a scan it will be staged
|
||||
- I.e. by the time stage finishes it must be configured
|
||||
- This can be either manual or from the scan parameters
|
||||
- Some scan parameters will overwrite the configuration (can be removed...)
|
||||
- Certain scan kwargs will trigger the reconfiguration of a device
|
||||
- ALL enabled devices will participate in the scan
|
||||
- If a device is enabled for a scan it will be staged (i.e. launch acquisition, script, etc...)
|
||||
- Yes, you have to actively manage what's enabled and what's not
|
||||
- Even a motor+diode scan must disable not relevant devices across the beamline
|
||||
- Latest by the time stage finishes it must be configured
|
||||
- Either manually by the preparation or scan routine
|
||||
- Or from fishing it out from the scan parameters (generally by looking for specific kwargs)
|
||||
- Some fished scan parameters might overwrite prior configuration
|
||||
- The device will not try to make sure that the received configuration is correct
|
||||
- So tough luck if you're reusing the same parameters across different scans
|
||||
|
||||
|
||||
|
||||
parameters
|
||||
|
||||
|
||||
### anotherstepscan
|
||||
|
||||
Simple software step scan in the low-level API that almost calls the standard BEC scan routine. Its
|
||||
only difference is that it overrides the burst to use Gigafrost's HW burst mode. The ophyd devices
|
||||
are capable to allocate the required number of points for DAQ and position readback.
|
||||
Simple software step scan in the low-level API that almost calls the standard BEC scan routine.
|
||||
Its only difference is that it overrides the per-point behavior to use Gigafrost's HW burst mode
|
||||
instead of sending multiple software triggers. The ophyd devices are capable to allocate the
|
||||
required number of points for DAQ and position readback.
|
||||
|
||||
```
|
||||
def demosanotherstepscantepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event')
|
||||
demosanotherstepscantepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event')
|
||||
```
|
||||
|
||||
### snapnstep
|
||||
|
||||
AeroScript controlled high-speed step-scan that sets up the devices and calls the corresponding
|
||||
low-level scan API to substitute the jinja2 template file and launch the script. PSO and data
|
||||
low-level scan API to substitute the jinja2 template file and launch the script. The substitution
|
||||
logic was placed in the low-level API, as it's very similar to other AeroScript scans.
|
||||
The actual scan logic is in the **AerotechSnapAndStepTemplate.ascript** file. PSO and data
|
||||
readback are configured and launched internally. It also waits for the script to finish.
|
||||
```
|
||||
anothersnapnstepscan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
|
||||
anothersnapnstepscan(scan_start, scan_end, 180, exp_time=0.005, exp_burst=1800, repeats=10)
|
||||
```
|
||||
|
||||
|
||||
### anothersequencescan
|
||||
|
||||
AeroScript controlled fly scan that sets up the devices and calls the corresponding low-level scan
|
||||
to substitute the jinja2 template file and launch the script. PSO and data readback are configured
|
||||
to substitute the jinja2 template file and launch the script. The actual scan logic is in the
|
||||
**AerotechSimpleSequenceTemplate.ascript** file. PSO and data readback are configured
|
||||
and launched internally. It also waits for the script to finish. It might have problems with
|
||||
configuring the readback of the number of repeats because that's done on the IOC,
|
||||
```
|
||||
anothersequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
|
||||
anothersequencescan(scan_start, 180, 180, exp_time=0.005, exp_burst=1800, repeats=10)
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -166,18 +166,18 @@ class GigaFrostCameraMixin(CustomDetectorMixin):
|
||||
d = {}
|
||||
if 'kwargs' in scanparam:
|
||||
scanargs = scanparam['kwargs']
|
||||
if 'image_width' in scanargs:
|
||||
if 'image_width' in scanargs and scanargs['image_width']!=None:
|
||||
d['image_width'] = scanargs['image_width']
|
||||
if 'image_height' in scanargs:
|
||||
if 'image_height' in scanargs and scanargs['image_height']!=None:
|
||||
d['image_height'] = scanargs['image_height']
|
||||
if 'exp_time' in scanargs:
|
||||
d['exposure_time_ms'] = 1000*scanargs['exp_time']
|
||||
if 'exp_burst' in scanargs:
|
||||
if 'exp_time' in scanargs and scanargs['exp_time']!=None:
|
||||
d['exposure_time_ms'] = scanargs['exp_time']
|
||||
if 'exp_burst' in scanargs and scanargs['exp_burst']!=None:
|
||||
d['exposure_num_burst'] = scanargs['exp_burst']
|
||||
if 'acq_mode' in scanargs:
|
||||
if 'acq_mode' in scanargs and scanargs['acq_mode']!=None:
|
||||
d['acq_mode'] = scanargs['acq_mode']
|
||||
elif self.parent.scaninfo.scan_type == "step":
|
||||
d['acq_mode'] = "default"
|
||||
# elif self.parent.scaninfo.scan_type == "step":
|
||||
# d['acq_mode'] = "default"
|
||||
|
||||
# Perform bluesky-style configuration
|
||||
if len(d) > 0:
|
||||
@@ -533,7 +533,7 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
if d['image_height']%16 !=0:
|
||||
raise RuntimeError(f"[{self.name}] image_height must be divisible by 16")
|
||||
self.cfgRoiY.set(d['image_height']).wait()
|
||||
# Dont change theese
|
||||
# Dont change these
|
||||
scanid = d.get('scanid', 0)
|
||||
correction_mode = d.get('correction_mode', 5)
|
||||
self.cfgScanId.set(scanid).wait()
|
||||
@@ -561,11 +561,14 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
"""
|
||||
|
||||
if acq_mode == "default":
|
||||
# trigger modes
|
||||
# Trigger parameters
|
||||
self.cfgCntStartBit.set(1).wait()
|
||||
self.cfgCntEndBit.set(0).wait()
|
||||
|
||||
# set modes
|
||||
# Switch to physical enable signal
|
||||
self.cfgEnableScheme.set(0).wait()
|
||||
|
||||
# Set modes
|
||||
self.enable_mode = "soft"
|
||||
self.trigger_mode = "auto"
|
||||
self.exposure_mode = "timer"
|
||||
@@ -788,7 +791,7 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
|
||||
@property
|
||||
def enable_mode(self):
|
||||
"""Return the enable mode set in the GigaFRost camera.
|
||||
"""Return the enable mode set in the GigaFRoST camera.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -811,15 +814,33 @@ class GigaFrostCamera(PSIDetectorBase):
|
||||
|
||||
@enable_mode.setter
|
||||
def enable_mode(self, mode):
|
||||
"""Apply the enable mode for the GigaFRoST camera.
|
||||
"""
|
||||
Set the enable mode for the GigaFRoST camera.
|
||||
|
||||
NOTE: Always does not seem to work and Enablesoft works like a trigger
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mode : {'soft', 'external', 'soft+ext', 'always'}
|
||||
The enable mode to be applied.
|
||||
The GigaFRoST enable mode. Valid arguments are:
|
||||
|
||||
* 'soft':
|
||||
The GigaFRoST enable signal is supplied through a software
|
||||
signal
|
||||
* 'external':
|
||||
The GigaFRoST enable signal is supplied through an external TTL
|
||||
gating signal from the rotaiton stage or some other control
|
||||
unit
|
||||
* 'soft+ext':
|
||||
The GigaFRoST enable signal can be supplied either via the
|
||||
software signal or externally. The two signals are combined
|
||||
with a logical OR gate.
|
||||
* 'always':
|
||||
The GigaFRoST is always enabled.
|
||||
CAUTION: This mode is not compatible with the fixed number of
|
||||
frames modes!
|
||||
"""
|
||||
|
||||
if mode not in const.gf_valid_enable_modes:
|
||||
raise ValueError(
|
||||
"Invalid enable mode! Valid modes are:\n{const.gf_valid_enable_modes}"
|
||||
|
||||
@@ -24,3 +24,10 @@ The CaQtDM panel can be opened by:
|
||||
'''
|
||||
caqtdm -macro "CAM=X02DA-CAM-GF2" X_X02DA_GIGAFROST_camControl_user.ui &
|
||||
'''
|
||||
|
||||
# Opening PCO Edge panel
|
||||
|
||||
The CaQtDM panel can be opened by:
|
||||
'''
|
||||
caqtdm -macro "NAME=X02DA-CCDCAM2" CameraExpert.ui
|
||||
'''
|
||||
|
||||
@@ -40,19 +40,20 @@ class StdDaqMixin(CustomDeviceMixin):
|
||||
d = {}
|
||||
if 'kwargs' in scanparam:
|
||||
scanargs = scanparam['kwargs']
|
||||
if 'image_width' in scanargs:
|
||||
if 'image_width' in scanargs and scanargs['image_width'] != None:
|
||||
d['image_width'] = scanargs['image_width']
|
||||
if 'image_height' in scanargs:
|
||||
if 'image_height' in scanargs and scanargs['image_height'] != None:
|
||||
d['image_height'] = scanargs['image_height']
|
||||
# NOTE: Scans don't have to fully configure the device
|
||||
if "steps" in scanargs and "exp_burst" in scanargs:
|
||||
scan_steps = scanargs["steps"]
|
||||
scan_burst = scanargs["exp_burst"]
|
||||
d["num_points_total"] = (scan_steps+1) * scan_burst
|
||||
elif "exp_burst" in scanargs:
|
||||
d["num_points_total"] = scanargs["exp_burst"]
|
||||
elif "steps" in scanargs:
|
||||
d["num_points_total"] = scanargs["steps"]
|
||||
points_total = 1
|
||||
if 'steps' in scanargs and scanargs['steps'] != None:
|
||||
points_total *= scanargs['steps']
|
||||
if 'exp_burst' in scanargs and scanargs['exp_burst'] != None:
|
||||
points_total *= scanargs['exp_burst']
|
||||
if 'repeats' in scanargs and scanargs['repeats']!= None:
|
||||
points_total *= scanargs['repeats']
|
||||
if points_total != 1:
|
||||
d['num_points_total'] = points_total
|
||||
|
||||
# Perform bluesky-style configuration
|
||||
if len(d) > 0:
|
||||
|
||||
@@ -1,29 +1,41 @@
|
||||
def fede_darks(num, exp_time=None, exp_period=None, roix=None, roiy=None):
|
||||
""" Fede dark scan
|
||||
def fede_darks(nimages_dark, exposure_time=None, exposure_period=None, roix=None, roiy=None, acq_mode=None):
|
||||
"""
|
||||
Acquire a set of dark images with shutters closed.
|
||||
|
||||
This is a small BEC user-space scan that sets up the gigafrost and calls
|
||||
the low-level dark collection scan.
|
||||
Parameters
|
||||
----------
|
||||
nimages_dark : int
|
||||
Number of dark images to acquire (no default)
|
||||
exposure_time : float, optional
|
||||
Exposure time [ms]. If not specified, the currently configured value on the camera will be used
|
||||
exposure_period : float, optional
|
||||
Exposure period [ms]
|
||||
roix : int, optional
|
||||
ROI size in the x-direction [pixels]
|
||||
roiy : int, optional
|
||||
ROI size in the y-direction [pixels]
|
||||
acq_mode : str, optional
|
||||
Predefined acquisition mode (default=)
|
||||
|
||||
|
||||
|
||||
Example:
|
||||
--------
|
||||
tutorialdarks(num=100, exp_time=5)
|
||||
"""
|
||||
###### TODO check how to pass only the required arguments
|
||||
###### TODO what we want is a function common to PCO.edge and GF
|
||||
# Configure gigafrost
|
||||
cfg = {}
|
||||
if exp_time != None:
|
||||
cfg.update({"exposure_time_ms": exp_time})
|
||||
if exp_period != None:
|
||||
cfg.update({"exposure_period_ms": exp_period})
|
||||
if roix != None:
|
||||
cfg.update({"image_width": roix})
|
||||
if roiy != None:
|
||||
cfg.update({"image_height": roiy})
|
||||
|
||||
dev.gfcam.configure(d=cfg)
|
||||
dev.es1_tasks.enabled = False
|
||||
dev.es1_psod.enabled = False
|
||||
dev.es1_ddaq.enabled = False
|
||||
dev.es1_ismc.enabled = False
|
||||
dev.es1_roty.enabled = False
|
||||
dev.gfcam.enabled = True
|
||||
dev.gfdaq.enabled = True
|
||||
dev.daq_stream0.enabled = True
|
||||
dev.daq_stream1.enabled = False
|
||||
|
||||
|
||||
dev.gfcam.cfgAcqMode.set(1).wait()
|
||||
dev.gfcam.cmdSetParam.set(1).wait()
|
||||
dev.gfcam.cfgEnableExt.set(0).wait()
|
||||
dev.gfcam.cfgEnableSoft.set(0).wait()
|
||||
dev.gfcam.cfgEnableAlways.set(1).wait()
|
||||
@@ -42,8 +54,8 @@ def fede_darks(num, exp_time=None, exp_period=None, roix=None, roiy=None):
|
||||
# Commit changes to GF
|
||||
dev.gfcam.cmdSetParam.set(1).wait()
|
||||
|
||||
|
||||
### TODO: camera reset
|
||||
print("Handing over to 'scans.acquire_dark")
|
||||
scans.acquire_dark(num=num)
|
||||
scans.acquire_dark(num=1, exp_burst=nimages_dark, exp_time=exposure_time, exp_period=exposure_period, image_width=roix, image_height=roiy)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user