Minor fixes
This commit is contained in:
@@ -970,6 +970,8 @@ class aa1AxisDriveDataCollection(Device):
|
||||
# This allocates the memory...
|
||||
self.npoints.set(npoints).wait()
|
||||
|
||||
# Reset incremental readback
|
||||
self._switch.set(2).wait()
|
||||
new = self.read_configuration()
|
||||
return (old, new)
|
||||
|
||||
@@ -993,6 +995,9 @@ class aa1AxisDriveDataCollection(Device):
|
||||
status.set_finished()
|
||||
return status
|
||||
|
||||
def reset(self):
|
||||
"""Reset incremental readback"""
|
||||
self._switch.set("ResetRB", settle_time=0.1).wait()
|
||||
|
||||
def complete(self, settle_time=0.1) -> DeviceStatus:
|
||||
"""DDC just reads back whatever is available in the buffers"""
|
||||
|
||||
@@ -8,12 +8,16 @@ program
|
||||
// External parameters
|
||||
var $fStartPosition as real = {{ scan.startpos }}
|
||||
var $iNumSteps as integer = {{ scan.numsteps }}
|
||||
var $iNumBurst as integer = {{ scan.numburst or 1 }}
|
||||
var $fStepSize as real = {{ scan.stepsize }}
|
||||
var $fExposureTimeSec as real = {{ scan.exptime }}
|
||||
var $fSettlingTimeSec as real = {{ scan.settle }}
|
||||
var $fSettlingTimeSec as real = {{ scan.settling }}
|
||||
var $fVelJog as real = {{ scan.travel or 200 }}
|
||||
var $fVelScan as real = {{ scan.velocity or 50 }}
|
||||
var $fAcceleration = {{ scan.acceleration or 500 }}
|
||||
var $eDdcTrigger as DriveDataCaptureTrigger = DriveDataCaptureTrigger.{{ scan.psotrigger }}
|
||||
var $iNumDdcRead as integer = {{ scan.npoints }}
|
||||
|
||||
|
||||
// Internal
|
||||
var $axis as axis = ROTY
|
||||
@@ -25,8 +29,7 @@ program
|
||||
SetupAxisRampValue($axis,0,$fAcceleration)
|
||||
|
||||
// Move to start position before the scan (use soft-wait to catch errors)
|
||||
var $fPosNext as real = $fStartPosition
|
||||
MoveAbsolute($axis, $fPosNext, $fVelJog)
|
||||
MoveAbsolute($axis, $fStartPosition, $fVelJog)
|
||||
WaitForMotionDone($axis)
|
||||
|
||||
// Mandatory error checking after each movement
|
||||
@@ -35,27 +38,33 @@ program
|
||||
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
|
||||
end
|
||||
|
||||
// Configure PSO (to manual event generation)
|
||||
// Turn off PSO
|
||||
PsoDistanceConfigureInputs($axis, [PsoDistanceInput.XC4PrimaryFeedback])
|
||||
PsoDistanceCounterOff($axis)
|
||||
PsoDistanceEventsOff($axis)
|
||||
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||
PsoWaveformConfigurePulseFixedTotalTime($axis, 50)
|
||||
PsoWaveformConfigurePulseFixedOnTime($axis, 20)
|
||||
PsoWaveformConfigurePulseFixedCount($axis, 1)
|
||||
PsoWaveformApplyPulseConfiguration($axis)
|
||||
|
||||
// Configure PSO (to manual event generation in pulsed mode)
|
||||
PsoWaveformConfigureMode($axis, PsoWaveformMode.Pulse)
|
||||
PsoWaveformConfigurePulseFixedTotalTime($axis, 100)
|
||||
PsoWaveformConfigurePulseFixedOnTime($axis, 50)
|
||||
PsoWaveformConfigurePulseFixedCount($axis, $iNumBurst)
|
||||
PsoWaveformApplyPulseConfiguration($axis)
|
||||
PsoWaveformOn($axis)
|
||||
|
||||
// Activete PSO
|
||||
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||
PsoWaveformOn($axis)
|
||||
|
||||
// Configure Drive Data Collection
|
||||
var $iDdcArrayAddr as integer = 8388608
|
||||
var $iDdcArraySize as integer = iMaximum(5000, $iNumSteps)
|
||||
var $iDdcArraySize as integer = $iNumDdcRead
|
||||
var $iDdcSafeSpace as integer = 4096
|
||||
|
||||
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
|
||||
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
|
||||
|
||||
DriveDataCaptureConfigureTrigger($axis, 0, DriveDataCaptureTrigger.PsoOutput );
|
||||
DriveDataCaptureConfigureTrigger($axis, 1, DriveDataCaptureTrigger.PsoOutput );
|
||||
DriveDataCaptureConfigureTrigger($axis, 0, $eDdcTrigger );
|
||||
DriveDataCaptureConfigureTrigger($axis, 1, $eDdcTrigger );
|
||||
|
||||
DriveDataCaptureConfigureArray($axis, 0, $iDdcArrayAddr, $iDdcArraySize);
|
||||
DriveDataCaptureConfigureArray($axis, 1, $iDdcArrayAddr + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
|
||||
@@ -71,7 +80,7 @@ program
|
||||
///////////////////////////////////////////////////////////
|
||||
$iglobal[2] = $iNumSteps
|
||||
for $ii = 0 to ($iNumSteps-1)
|
||||
MoveAbsolute($axis, $fPosNext, $fVelScan)
|
||||
MoveAbsolute($axis, $fStartPosition + $ii * $fStepSize, $fVelScan)
|
||||
WaitForMotionDone($axis)
|
||||
|
||||
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
|
||||
@@ -82,7 +91,6 @@ program
|
||||
Dwell($fSettlingTimeSec)
|
||||
PsoEventGenerateSingle($axis)
|
||||
Dwell($fExposureTimeSec)
|
||||
$fPosNext = $fPosNext + $fStepSize
|
||||
$iglobal[1] = $ii
|
||||
end
|
||||
|
||||
|
||||
@@ -248,6 +248,9 @@ class StdDaqClient(Device):
|
||||
return
|
||||
except (ConnectionClosedError, ConnectionClosedOK):
|
||||
return
|
||||
except AssertionError:
|
||||
# Libraty throws after connection is closed
|
||||
return
|
||||
finally:
|
||||
self._mon = None
|
||||
|
||||
|
||||
@@ -119,13 +119,14 @@ class TemplatedScanBase(AsyncFlyScanBase):
|
||||
yield from self.stubs.send_rpc_and_wait("es1_tasks", "stage")
|
||||
if self.camera is not None:
|
||||
yield from self.stubs.send_rpc_and_wait(self.camera, "stage")
|
||||
if self.daqname is not None:
|
||||
yield from self.stubs.send_rpc_and_wait(self.daqname, "stage")
|
||||
# DAQ should be staged from script
|
||||
# if self.daqname is not None:
|
||||
# yield from self.stubs.send_rpc_and_wait(self.daqname, "stage")
|
||||
if self.preview is not None:
|
||||
yield from self.stubs.send_rpc_and_wait(self.preview, "stage")
|
||||
|
||||
# TODO : This should stage the entire beamline
|
||||
yield from super().stage()
|
||||
# yield from super().stage()
|
||||
|
||||
|
||||
def scan_core(self):
|
||||
@@ -156,10 +157,10 @@ class TemplatedScanBase(AsyncFlyScanBase):
|
||||
time.sleep(0.5)
|
||||
|
||||
# Collect
|
||||
if self.daqname is not None and self.daqmode=="collect":
|
||||
print("TOMCAT Collecting scripted scan results (from EPICS)")
|
||||
positions = yield from self.stubs.send_rpc_and_wait(self.daqname, "collect")
|
||||
logger.info(f"Finished scan with collected positions: {positions}")
|
||||
# if self.daqname is not None and self.daqmode=="collect":
|
||||
# print("TOMCAT Collecting scripted scan results (from EPICS)")
|
||||
# positions = yield from self.stubs.send_rpc_and_wait(self.daqname, "collect")
|
||||
# logger.info(f"Finished scan with collected positions: {positions}")
|
||||
|
||||
def cleanup(self):
|
||||
"""Set scan progress to 1 to finish the scan"""
|
||||
@@ -236,9 +237,12 @@ class GigaStepScanBase(ScanBase):
|
||||
required_kwargs = ["scan_start", "scan_end","steps"]
|
||||
gui_config = {
|
||||
"Movement parameters": ["steps"],
|
||||
"Acquisition parameters" : ["exp_time", "burst_at_each_point"]
|
||||
"Acquisition parameters" : ["exp_time", "burst_at_each_point", "roix", "roiy"]
|
||||
}
|
||||
|
||||
def _get_scan_motors(self):
|
||||
self.scan_motors = ["es1_roty"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scan_start: float,
|
||||
@@ -247,6 +251,8 @@ class GigaStepScanBase(ScanBase):
|
||||
exp_time = 0.005,
|
||||
settling_time = 0.2,
|
||||
burst_at_each_point = 1,
|
||||
roix = 2016,
|
||||
roiy = 2016,
|
||||
sync='event',
|
||||
**kwargs):
|
||||
super().__init__(
|
||||
@@ -265,6 +271,8 @@ class GigaStepScanBase(ScanBase):
|
||||
self.scan_stepsize = (scan_end - scan_start) / steps
|
||||
self.scan_ntotal = burst_at_each_point * (steps + 1)
|
||||
self.scan_nburst = burst_at_each_point
|
||||
self.scan_roix = roix
|
||||
self.scan_roiy = roiy
|
||||
|
||||
# Override wait time with actual latency
|
||||
# NOTE : The BEC does not wait for trigger() status done
|
||||
@@ -282,14 +290,13 @@ class GigaStepScanBase(ScanBase):
|
||||
"nimages": burst_at_each_point,
|
||||
"exposure": 1000*exp_time,
|
||||
"period": 2000*exp_time,
|
||||
"pixel_width": 2016,
|
||||
"pixel_height": 2016
|
||||
"pixel_width": self.scan_roix,
|
||||
"pixel_height": self.scan_roiy
|
||||
}
|
||||
|
||||
def _calculate_positions(self) -> None:
|
||||
""" Pre-calculate scan positions """
|
||||
self.positions = [self.scan_start]
|
||||
for ii in range(self.scan_steps):
|
||||
for ii in range(self.scan_steps+1):
|
||||
self.positions.append(self.scan_start + ii*self.scan_stepsize)
|
||||
|
||||
def stage(self):
|
||||
@@ -359,24 +366,25 @@ class SnapAndStepScanBase(TemplatedScanBase):
|
||||
|
||||
# Synthetic values
|
||||
self.scan_stepsize = (scan_end-scan_start)/steps
|
||||
self.scan_ntotal = steps * burst_at_each_point
|
||||
self.scan_ntotal = (steps+1) * burst_at_each_point
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
p_modes = {'pso': 'PsoOutput', 'event': 'PsoEvent', 'inp0': 'HighSpeedInput0RisingEdge', 'inp1': 'HighSpeedInput1RisingEdge'}
|
||||
daq_trigger = t_modes[sync]
|
||||
pso_trigger = p_modes[sync]
|
||||
|
||||
filename = "AerotechSnapAndStepTemplate.ascript"
|
||||
filesubs = {
|
||||
'startpos': self.scan_start,
|
||||
'stepsize': self.scan_stepsize,
|
||||
'numsteps': self.scan_steps,
|
||||
'exptime': self.exp_time*self.exp_burst
|
||||
'settling': self.settling_time
|
||||
'exptime': 2*self.exp_time*self.exp_burst,
|
||||
'settling': self.settling_time,
|
||||
'psotrigger': pso_trigger,
|
||||
'npoints': self.scan_ntotal
|
||||
}
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
if isinstance(sync, str):
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
daq_trigger = t_modes[sync]
|
||||
else:
|
||||
daq_trigger = int(sync)
|
||||
|
||||
# DDC config
|
||||
daqname = "es1_ddaq"
|
||||
daqcfg = {'ntotal': self.scan_ntotal, 'trigger': daq_trigger}
|
||||
# Gigafrost config
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
def bl_check_beam():
|
||||
""" Checks beamline status"""
|
||||
return True
|
||||
motor_enabled = bool(dev.es1_roty.motor_enable.get())
|
||||
result = motor_enabled
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, sync='event'):
|
||||
def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_point=1, settling_time=0, roix=2016, roiy=2016, sync='event'):
|
||||
""" Demo step scan with GigaFrost
|
||||
|
||||
This is a small BEC user-space demo step scan at the microXAS testbench
|
||||
@@ -30,7 +32,9 @@ def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_poin
|
||||
# Configure gigafrost
|
||||
cfg = {
|
||||
"ntotal": scan_ntotal, "nimages": burst_at_each_point,
|
||||
"exposure": 1000*exp_time, "period": 2000*exp_time}
|
||||
"exposure": 1000*exp_time, "period": 2000*exp_time,
|
||||
"pixel_width": roix, "pixel_height": roiy
|
||||
}
|
||||
dev.gfclient.configure(d=cfg)
|
||||
# Configure PSO trigger (trigger is normally disabled in fly mode)
|
||||
dev.es1_psod.configure(d={})
|
||||
@@ -51,7 +55,7 @@ def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_poin
|
||||
|
||||
|
||||
def demosequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
exp_time=0.005, exp_frames=180, sync='pso'):
|
||||
exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync='pso'):
|
||||
""" Demo sequence scan with GigaFrost
|
||||
|
||||
This is a small BEC user-space sequence scan at the microXAS testbench
|
||||
@@ -67,19 +71,16 @@ def demosequencescan(scan_start, gate_high, gate_low, repeats=1, repmode="PosNeg
|
||||
if not bl_check_beam():
|
||||
raise RuntimeError("Beamline is not in ready state")
|
||||
|
||||
print("Handing over to 'scans.line_scan'")
|
||||
scans.sequencescan(scan_start, gate_high, gate_low, exp_time=exp_time, exp_frames=exp_frames, repeats=repeats, repmode=repmode)
|
||||
print("Handing over to 'scans.sequencescan'")
|
||||
scans.sequencescan(scan_start, gate_high, gate_low, exp_time=exp_time, exp_frames=exp_frames, repeats=repeats, roix=roix, roiy=roiy, repmode=repmode, sync=sync)
|
||||
|
||||
|
||||
def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
exp_time=0.005, exp_frames=180, sync='pso'):
|
||||
""" Demo sequence scan with GigaFrost
|
||||
exp_time=0.005, exp_frames=180, roix=2016, roiy=2016, sync='pso'):
|
||||
""" Demo sequence scan with GigaFrost via BEC
|
||||
|
||||
This is a small BEC user-space sequence scan at the microXAS testbench
|
||||
triggering a customized scripted scan on the controller. The scan uses
|
||||
a pre-written custom low-level sequence scan, so it is really minimal.
|
||||
|
||||
NOTE: It calls the AeroScript template version.
|
||||
doing every scan logic from BEC, i.e. there's no AeroScript involved.
|
||||
|
||||
Example:
|
||||
--------
|
||||
@@ -93,8 +94,8 @@ def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
raise RuntimeError(f"Requires at least one frame per cycle, got {self.exp_frames}")
|
||||
|
||||
# Synthetic values
|
||||
scan_roix = 2016
|
||||
scan_roiy = 2016
|
||||
scan_roix = roix
|
||||
scan_roiy = roiy
|
||||
scan_repnum = repeats
|
||||
scan_repmode = repmode.upper()
|
||||
scan_velocity = gate_high / (exp_time * exp_frames)
|
||||
@@ -122,18 +123,13 @@ def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported repetition mode: {repmode}")
|
||||
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
p_modes = {'pso': 'PsoOutput', 'event': 'PsoEvent', 'inp0': 'HighSpeedInput0RisingEdge', 'inp1': 'HighSpeedInput1RisingEdge'}
|
||||
daq_trigger = t_modes[sync]
|
||||
pso_trigger = p_modes[sync]
|
||||
|
||||
# Drice data collection config
|
||||
daqname = "es1_ddaq"
|
||||
daqcfg = {'ntotal': scan_ntotal, 'trigger': daq_trigger}
|
||||
# Gigafrost config
|
||||
camname = "gfclient"
|
||||
camcfg = {
|
||||
"ntotal": scan_ntotal,
|
||||
"nimages": exp_frames,
|
||||
@@ -143,6 +139,7 @@ def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
"pixel_height": scan_roiy
|
||||
}
|
||||
|
||||
# PSO config
|
||||
# Fill PSO vectors according to scan direction
|
||||
# NOTE: Distance counter is bidirectional
|
||||
psoBoundsPos = []
|
||||
@@ -154,12 +151,7 @@ def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
if scan_repmode in ("POSNEG", "NEGPOS"):
|
||||
psoBoundsPos = [scan_accdistance, gate_high]
|
||||
psoBoundsNeg = [scan_accdistance + gate_low, gate_high]
|
||||
|
||||
# PSO config
|
||||
psocfg = {
|
||||
"distance": psoBoundsPos,
|
||||
"wmode": "toggle"
|
||||
}
|
||||
psocfg = {"distance": psoBoundsPos, "wmode": "toggle"}
|
||||
|
||||
# Move to start position
|
||||
dev.es1_roty.move(scan_start).wait()
|
||||
@@ -206,5 +198,3 @@ def becsequencescan(start, gate_high, gate_low, repeats=1, repmode="PosNeg",
|
||||
|
||||
# Move back to start
|
||||
dev.es1_roty.move(scan_start).wait()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user