diff --git a/tomcat_bec/devices/aerotech/AerotechSimpleSequenceTemplate.ascript b/tomcat_bec/devices/aerotech/AerotechSimpleSequenceTemplate.ascript index 8bb6516..73a3d97 100644 --- a/tomcat_bec/devices/aerotech/AerotechSimpleSequenceTemplate.ascript +++ b/tomcat_bec/devices/aerotech/AerotechSimpleSequenceTemplate.ascript @@ -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 diff --git a/tomcat_bec/scans/tomcat_scanbase.py b/tomcat_bec/scans/tomcat_scanbase.py index 1e26ce0..7506950 100644 --- a/tomcat_bec/scans/tomcat_scanbase.py +++ b/tomcat_bec/scans/tomcat_scanbase.py @@ -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() diff --git a/tomcat_bec/scripts/demoscans.py b/tomcat_bec/scripts/demoscans.py index b9e3ed6..8db467a 100644 --- a/tomcat_bec/scripts/demoscans.py +++ b/tomcat_bec/scripts/demoscans.py @@ -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) \ No newline at end of file