Simplesequence posneg triggers correctly
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
// The file expects external parameter validation
|
||||
// The PSO locations arrays are set externally from EPICS PV
|
||||
//
|
||||
#define DDC_ADDR 0x800000
|
||||
#define PSO_ADDR 0x0
|
||||
|
||||
|
||||
|
||||
enum ScanType
|
||||
POS = 0
|
||||
@@ -16,7 +20,7 @@ program
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// External parameters - USE THEESE
|
||||
var $fStartPosition as real = {{ scan.startpos }}
|
||||
var $fScanRange as real = $fStartPosition + {{ scan.scanrange }}
|
||||
var $fScanRange as real = {{ scan.scanrange }}
|
||||
var $iNumRepeat as integer = {{ scan.nrepeat }}
|
||||
var $eScanType as ScanType = ScanType.{{ scan.scandir or 'POS' }}
|
||||
var $iNumDdcRead as integer = {{ scan.npoints }}
|
||||
@@ -25,7 +29,8 @@ program
|
||||
var $fVelScan as real = {{ scan.scanvel }}
|
||||
var $fAcceleration = {{ scan.scanacc }}
|
||||
var $fAccDistance as real = {{ scan.accdist }}
|
||||
|
||||
var $eDdcTrigger as DriveDataCaptureTrigger = DriveDataCaptureTrigger.{{ scan.psotrigger }}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Internal parameters - dont use
|
||||
var $axis as axis = ROTY
|
||||
@@ -34,7 +39,7 @@ program
|
||||
|
||||
// Set acceleration
|
||||
SetupAxisRampType($axis, RampType.Linear)
|
||||
SetupAxisRampValue($axis,0,$fAcceleration)
|
||||
SetupAxisRampValue($axis, 0, $fAcceleration)
|
||||
|
||||
// set the actual scan range
|
||||
var $fPosStart as real
|
||||
@@ -57,36 +62,48 @@ program
|
||||
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||
WaitForInPosition($axis)
|
||||
|
||||
// Set globals for feedback
|
||||
$rglobal[2] = $fPosStart
|
||||
$rglobal[3] = $fPosEnd
|
||||
|
||||
// Configure PSO
|
||||
// FIXME : When the controller is restarted
|
||||
PsoDistanceConfigureInputs($axis, [PsoDistanceInput.XC4PrimaryFeedback])
|
||||
PsoDistanceCounterOff($axis)
|
||||
PsoDistanceEventsOff($axis)
|
||||
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||
PsoWaveformOff($axis)
|
||||
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||
var $iPsoArrayAddr as integer = 0
|
||||
var $iPsoArrayPosAddr as integer = PSO_ADDR
|
||||
// Simple PSO trigger pattern
|
||||
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
|
||||
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
|
||||
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }}) ]
|
||||
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsNeg[-1] }}) ]
|
||||
var $iPsoArrayPosSize as integer = {{ scan.psoBoundsPosSize }}
|
||||
var $iPsoArrayNegSize as integer = {{ scan.psoBoundsNegSize }}
|
||||
// Calculate negative array offset (in bytes)
|
||||
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
|
||||
|
||||
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 0)
|
||||
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
|
||||
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
|
||||
PsoDistanceCounterOn($axis)
|
||||
PsoDistanceEventsOn($axis)
|
||||
|
||||
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
|
||||
PsoWaveformOn($axis)
|
||||
PsoWaveformOn($axis)
|
||||
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||
|
||||
// Configure Drive Data Collection
|
||||
var $iDdcArrayAddr as integer = 8388608
|
||||
var $iDdcArraySize as integer = $iNumDdcRead
|
||||
|
||||
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);
|
||||
DriveDataCaptureConfigureArray($axis, 0, DDC_ADDR, $iDdcArraySize);
|
||||
DriveDataCaptureConfigureArray($axis, 1, DDC_ADDR + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
|
||||
|
||||
// Directly before scan
|
||||
PsoDistanceCounterOn($axis)
|
||||
@@ -97,31 +114,38 @@ program
|
||||
// Start the actual scanning
|
||||
///////////////////////////////////////////////////////////
|
||||
for $ii = 0 to ($iNumRepeat-1)
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 0)
|
||||
// Feedback on progress
|
||||
$rglobal[4] = $ii
|
||||
|
||||
if $eScanType == ScanType.POS
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif $eScanType == ScanType.NEG
|
||||
elseif $eScanType == ScanType.NEG
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif $eScanType == ScanType.POSNEG
|
||||
elseif $eScanType == ScanType.POSNEG
|
||||
if ($ii % 2) == 0
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif ($ii % 2) == 1
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, $iPsoArrayNegSize, 0)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
end
|
||||
elseif $eScanType == ScanType.NEGPOS
|
||||
if ($ii % 2) == 0
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, $iPsoArrayPosSize, 0)
|
||||
MoveAbsolute($axis, $fPosEnd, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
elseif ($ii % 2) == 1
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, $iPsoArrayNegSize, 0)
|
||||
MoveAbsolute($axis, $fPosStart, $fVelScan)
|
||||
WaitForInPosition($axis)
|
||||
end
|
||||
|
||||
@@ -363,7 +363,7 @@ class SnapAndStepScanBase(TemplatedScanBase):
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
if isinstance(sync, str):
|
||||
t_modes = {'event': 1, 'pso': 2, 'inp0': 3, 'inp1': 1}
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
daq_trigger = t_modes[sync]
|
||||
else:
|
||||
daq_trigger = int(sync)
|
||||
@@ -436,7 +436,6 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
self.scan_repmode = repmode
|
||||
self.exp_time = exp_time
|
||||
self.exp_frames = exp_frames
|
||||
self.acc_dist = 42
|
||||
|
||||
# Synthetic values
|
||||
self.scan_velocity = gate_high / (exp_time * exp_frames)
|
||||
@@ -444,28 +443,36 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
self.scan_safedistance = 10
|
||||
self.scan_accdistance = self.scan_safedistance + 0.5* self.scan_velocity * self.scan_velocity / self.scan_acceleration
|
||||
self.scan_ntotal = exp_frames * repeats
|
||||
if repmode.lower() in ("pos", "neg"):
|
||||
self.scan_range = gate_high + gate_low
|
||||
elif repmode.lower() in ("posneg", "negpos"):
|
||||
self.scan_range = repeats *(gate_high + gate_low)
|
||||
|
||||
if repmode.upper() in ("POS", "NEG"):
|
||||
self.scan_range = repeats *(gate_high + gate_low)
|
||||
elif repmode.upper() in ("POSNEG", "NEGPOS"):
|
||||
self.scan_range = gate_high + gate_low
|
||||
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]
|
||||
|
||||
# AeroScript substitutions
|
||||
filename = "AerotechSimpleSequenceTemplate.ascript"
|
||||
filesubs = {
|
||||
'startpos': self.scan_start,
|
||||
'scanrange': self.scan_range,
|
||||
'nrepeat': self.scan_repnum,
|
||||
'scanvel': self.scan_velocity,
|
||||
'scanacc': self.scan_acceleration,
|
||||
'accdist': self.scan_accdistance,
|
||||
'npoints' : self.scan_ntotal,
|
||||
'scandir' : self.scan_repmode.upper()
|
||||
'scandir' : self.scan_repmode.upper(),
|
||||
'psotrigger': pso_trigger
|
||||
}
|
||||
|
||||
# Aerotech DDC settings: Internal event trigger: PsoEvent = 1
|
||||
if isinstance(sync, str):
|
||||
t_modes = {'event': 1, 'pso': 2, 'inp0': 3, 'inp1': 1}
|
||||
daq_trigger = t_modes[sync]
|
||||
else:
|
||||
daq_trigger = int(sync)
|
||||
|
||||
print(filesubs)
|
||||
# Drice data collection config
|
||||
# FIXME: The data sources need to be set to same as the script
|
||||
daqname = "es1_ddaq"
|
||||
daqcfg = {'ntotal': self.scan_ntotal, 'trigger': daq_trigger}
|
||||
# Gigafrost config
|
||||
@@ -497,34 +504,26 @@ class SequenceScanBase(TemplatedScanBase):
|
||||
self.psoBoundsPos = []
|
||||
self.psoBoundsNeg = []
|
||||
if self.scan_repmode in ("pos", "Pos"):
|
||||
self.psoBoundsPos.append(self.acc_dist)
|
||||
self.psoBoundsPos.append(self.scan_accdistance)
|
||||
for ii in range(self.scan_repnum):
|
||||
self.psoBoundsPos += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsPos[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
# self.psoBoundsPos[-1] = 10* (self.scan_accdistance+self.gate_low)
|
||||
if self.scan_repmode in ("neg", "Neg"):
|
||||
self.psoBoundsNeg.append(self.acc_dist)
|
||||
self.psoBoundsNeg.append(self.scan_accdistance)
|
||||
for ii in range(self.scan_repnum):
|
||||
self.psoBoundsNeg += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsNeg[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
# self.psoBoundsNeg[-1] = 10* (self.scan_accdistance+self.gate_low)
|
||||
if self.scan_repmode in ("posneg", "PosNeg"):
|
||||
self.psoBoundsPos.append(self.acc_dist)
|
||||
self.psoBoundsNeg.append(self.acc_dist + self.gate_low)
|
||||
for ii in range(self.scan_repnum // 2):
|
||||
self.psoBoundsPos += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsNeg += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsPos[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
self.psoBoundsNeg[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
self.psoBoundsPos = [self.scan_accdistance, self.gate_high]
|
||||
self.psoBoundsNeg = [self.scan_accdistance + self.gate_low, self.gate_high]
|
||||
if self.scan_repmode in ("negpos", "NegPos"):
|
||||
self.psoBoundsPos.append(self.acc_dist + self.gate_low)
|
||||
self.psoBoundsNeg.append(self.acc_dist)
|
||||
for ii in range(self.scan_repnum // 2):
|
||||
self.psoBoundsPos += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsNeg += [self.gate_high, self.gate_low]
|
||||
self.psoBoundsPos[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
self.psoBoundsNeg[-1] = 10* (self.acc_dist+self.gate_low)
|
||||
self.psoBoundsNeg = [self.scan_accdistance, self.gate_high]
|
||||
self.psoBoundsPos = [self.scan_accdistance + self.gate_low, self.gate_high]
|
||||
|
||||
self.filesubs['psoBoundsPos'] = self.psoBoundsPos
|
||||
self.filesubs['psoBoundsNeg'] = self.psoBoundsNeg
|
||||
self.filesubs['psoBoundsPosSize'] = len(self.psoBoundsPos)
|
||||
self.filesubs['psoBoundsNegSize'] = len(self.psoBoundsNeg)
|
||||
# Call super() to do the substitutions
|
||||
yield from super().prepare_positions()
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ def demostepscan(scan_start, scan_end, steps, exp_time=0.005, burst_at_each_poin
|
||||
scan_ntotal = burst_at_each_point * (steps + 1)
|
||||
|
||||
# Move to start position
|
||||
t_modes = {'event': 1, 'pso': 2, 'inp0': 3, 'inp1': 1}
|
||||
t_modes = {'pso': 0, 'event': 1, 'inp0': 2, 'inp1': 4}
|
||||
cfg = {'ntotal': scan_ntotal, 'trigger': t_modes[sync]}
|
||||
dev.es1_ddaq.configure(d=cfg)
|
||||
# Configure gigafrost
|
||||
@@ -50,62 +50,22 @@ 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'):
|
||||
""" Demo sequence scan with GigaFrost
|
||||
|
||||
This is a small BEC user-space sequence scan at the microXAS testbench
|
||||
triggering the gigafrost in gate-enable mode. It tries to do everything
|
||||
through BEC, so while still setting up the environment.
|
||||
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's not exactlythe same as the AeroScript template version.
|
||||
NOTE: It calls the AeroScript template version.
|
||||
|
||||
Example:
|
||||
--------
|
||||
demostepscan(scan_start=-32, scan_end=148, steps=180, exp_time=0.005, burst_at_each_point=5)
|
||||
>>> demosequencescan(33, 180, 180, exp_time=0.005, exp_frames=1800, repeats=10)
|
||||
"""
|
||||
if not bl_check_beam():
|
||||
raise RuntimeError("Beamline is not in ready state")
|
||||
|
||||
# Synthetic values
|
||||
scan_velocity = gate_high / (exp_time * exp_frames)
|
||||
scan_acceleration = 500
|
||||
scan_safedistance = 10
|
||||
scan_accdistance = scan_safedistance + 0.5* scan_velocity * scan_velocity / scan_acceleration
|
||||
scan_ntotal = exp_frames * repeats
|
||||
|
||||
# Move to start position
|
||||
t_modes = {'event': 1, 'pso': 2, 'inp0': 3, 'inp1': 1}
|
||||
cfg = {'ntotal': scan_ntotal, 'trigger': t_modes[sync]}
|
||||
dev.es1_ddaq.configure(d=cfg)
|
||||
# Configure gigafrost
|
||||
cfg = {
|
||||
"ntotal": scan_ntotal, "nimages": exp_frames,
|
||||
"exposure": 1000*exp_time, "period": 2000*exp_time}
|
||||
dev.gfclient.configure(d=cfg)
|
||||
|
||||
# Fill PSO vectors according to scan direction
|
||||
psoBounds = []
|
||||
if repmode in ("pos", "Pos"):
|
||||
psoBounds.append(scan_accdistance)
|
||||
for ii in range(repeats):
|
||||
psoBounds += [gate_high, gate_low]
|
||||
psoBounds[-1] = 10* (scan_accdistance+gate_low)
|
||||
|
||||
dev.es1_psod.configure(d={'distance': psoBounds, 'wmode': 'toggle'})
|
||||
|
||||
# Explicitly arm trigger (and detector in future)
|
||||
dev.es1_psod.prepare()
|
||||
|
||||
print("Handing over to 'scans.line_scan'")
|
||||
wait_time = 0.1 + 2*exp_time * burst_at_each_point
|
||||
scans.line_scan(
|
||||
dev.es1_roty, scan_start, scan_end,
|
||||
steps=steps, exp_time=wait_time, relative=False, settling_time=settling_time)
|
||||
|
||||
# Cleanup: disable SW trigger
|
||||
dev.es1_psod.software_trigger = False
|
||||
|
||||
|
||||
scans.sequencescan(scan_start, gate_high, gate_low, exp_time=exp_time, exp_frames=exp_frames, repeats=repeats, repmode=repmode)
|
||||
Reference in New Issue
Block a user