Merge branch 'main' into gac-x02da_20250616T172122

This commit is contained in:
gac-x02da
2025-06-18 18:25:55 +02:00
10 changed files with 858 additions and 594 deletions

View File

@@ -35,21 +35,22 @@ class aa1Controller(Device):
"""Ophyd proxy class for the Aerotech Automation 1's core controller functionality"""
# ToDo: Add error subscription
controllername = Component(EpicsSignalRO, "NAME", kind=Kind.config)
serialnumber = Component(EpicsSignalRO, "SN", kind=Kind.config)
apiversion = Component(EpicsSignalRO, "API_VERSION", kind=Kind.config)
controllername = Component(EpicsSignalRO, "NAME", string=True, kind=Kind.config)
serialnumber = Component(EpicsSignalRO, "SN", string=True, kind=Kind.config)
apiversion = Component(EpicsSignalRO, "API_VERSION", string=True, kind=Kind.config)
axiscount = Component(EpicsSignalRO, "AXISCOUNT", kind=Kind.config)
taskcount = Component(EpicsSignalRO, "TASKCOUNT", kind=Kind.config)
fastpoll = Component(EpicsSignalRO, "POLLTIME", auto_monitor=True, kind=Kind.normal)
slowpoll = Component(EpicsSignalRO, "DRVPOLLTIME", auto_monitor=True, kind=Kind.normal)
errno = Component(EpicsSignalRO, "ERRNO", auto_monitor=True, kind=Kind.normal)
errnmsg = Component(EpicsSignalRO, "ERRMSG", auto_monitor=True, kind=Kind.normal)
errnmsg = Component(EpicsSignalRO, "ERRMSG", string=True, auto_monitor=True, kind=Kind.normal)
_set_ismc = Component(EpicsSignal, "SET", put_complete=True, kind=Kind.omitted)
USER_ACCESS = ["reset"]
def reset(self):
""" Resets the Automation1 iSMC reloading the default configuration"""
"""Resets the Automation1 iSMC reloading the default configuration. Note that this will
erase all settings that were set during startup and not saved to the MCD file."""
self._set_ismc.set(3).wait()

View File

@@ -152,9 +152,8 @@ class aa1AxisDriveDataCollection(PSIDeviceBase, Device):
self.configure(d=d)
# Stage the data collection if not in internally launced mode
# NOTE: Scripted scans start acquiring from the scrits
if "scan_type" in scan_args and scan_args["scan_type"] in ("scripted", "script"):
self.arm()
# NOTE: Scripted scans start acquiring from the scrits at kickoff
self.arm()
# Reset readback
self.reset()

View File

@@ -39,6 +39,7 @@ class AerotechPsoBase(PSIDeviceBase, Device):
output = Component(EpicsSignalRO, "OUTPUT-RBV", auto_monitor=True, kind=Kind.normal)
address = Component(EpicsSignalRO, "ARRAY-ADDR", kind=Kind.config)
_eventSingle = Component(EpicsSignal, "EVENT:SINGLE", put_complete=True, kind=Kind.omitted)
switch = Component(EpicsSignal, "SWITCH", put_complete=True, kind=Kind.omitted)
# ########################################################################
# PSO Distance event module
@@ -119,7 +120,6 @@ class AerotechPsoBase(PSIDeviceBase, Device):
def fire(self, settle_time=0.1) -> None | DeviceStatus:
"""Fire a single PSO event (i.e. manual software trigger)"""
# Only trigger if distance was set to invalid
logger.warning(f"[{self.name}] Triggerin...")
self._eventSingle.set(1, settle_time=settle_time).wait()
status = DeviceStatus(self)
status.set_finished()
@@ -139,6 +139,8 @@ class AerotechPsoBase(PSIDeviceBase, Device):
w_pulse = d.get("pso_w_pulse", 200)
n_pulse = d.get("pso_n_pulse", 1)
self.switch.set("Manual").wait()
# Configure the pulsed/toggled waveform
if wmode in ["toggle", "toggled"]:
# Switching to simple toggle mode
@@ -161,12 +163,6 @@ class AerotechPsoBase(PSIDeviceBase, Device):
else:
raise RuntimeError(f"Unsupported window mode: {wmode}")
# Set PSO output data source
# FIXME : This is essentially staging...
if wmode in ["toggle", "toggled", "pulse", "pulsed"]:
self.outSource.set("Waveform").wait()
elif wmode in ["output", "flag"]:
self.outSource.set("Window").wait()
class aa1AxisPsoDistance(AerotechPsoBase):
@@ -227,10 +223,6 @@ class aa1AxisPsoDistance(AerotechPsoBase):
raise RuntimeError(f"Unsupported distace triggering mode: {pso_wavemode}")
old = self.read_configuration()
# Disable everything
self.winEvents.set("Off").wait()
self.dstCounterEna.set("Off").wait()
self.dstEventsEna.set("Off").wait()
# Configure distance generator (also resets counter to 0)
self._distance_value = pso_distance
@@ -288,33 +280,25 @@ class aa1AxisPsoDistance(AerotechPsoBase):
"""Fire a single PSO event (i.e. manual software trigger)"""
# Only trigger if distance was set to invalid
# if self.dstDistanceVal.get() == 0:
logger.warning(f"[{self.name}] Triggerin...")
# logger.warning(f"[{self.name}] Triggerin...")
return self.fire(settle_time)
def arm(self) -> None:
"""Bluesky style stage"""
"""Bluesky style stage
It re-arms the distance array and re-sets the distance counter at current position
"""
# Stage the PSO distance module and zero counter
if isinstance(self._distance_value, (np.ndarray, list, tuple)):
self.dstArrayRearm.set(1).wait()
# Wait for polling
sleep(0.5)
# Start monitoring the counters if distance is valid
if self.dstDistanceVal.get() > 0:
self.dstEventsEna.set("On").wait()
self.dstCounterEna.set("On").wait()
# Set distance and wait for polling
self.switch.set("Distance", settle_time=0.2).wait()
def disarm(self):
"""Standard bluesky unstage"""
# Ensure output is set to low
# if self.output.value:
# self.toggle()
# Turn off window mode
self.winOutput.set("Off").wait()
self.winEvents.set("Off").wait()
# Turn off distance mode
self.dstEventsEna.set("Off").wait()
self.dstCounterEna.set("Off").wait()
# Disable output
self.outSource.set("None").wait()
# Sleep for one poll period
sleep(0.2)
self.switch.set("Manual", settle_time=0.2).wait()
def launch(self):
"""Re-set the counters"""
if isinstance(self._distance_value, (np.ndarray, list, tuple)):
self.dstArrayRearm.set(1).wait()

View File

@@ -33,7 +33,7 @@ program
//////////////////////////////////////////////////////////////////////////
// Internal parameters - dont use
var $axis as axis = ROTY
var $axis as axis = {{ scan.rotaxis or 'ROTY' }}
var $ii as integer
var $axisFaults as integer = 0
var $iDdcSafeSpace as integer = 4096

View File

@@ -20,7 +20,7 @@ program
// Internal
var $axis as axis = ROTY
var $axis as axis = {{ scan.rotaxis or 'ROTY' }}
var $ii as integer
var $axisFaults as integer = 0

View File

@@ -5,6 +5,7 @@ interface.
@author: mohacsi_i
"""
import time
from ophyd import Device, Component, EpicsSignal, EpicsSignalRO, Kind
from ophyd.status import SubscriptionStatus
@@ -106,12 +107,8 @@ class aa1Tasks(PSIDeviceBase, Device):
self.fileName.set(d["script_file"]).wait()
if "script_text" in d:
# Compile text for syntax checking
# NOTE: This will load to 'script_file'
# NOTE: This will overwrite 'script_file'
self._fileWrite.set(d["script_text"], settle_time=0.2).wait()
self.switch.set("Load").wait()
# Check the result of load
if self._failure.value:
raise RuntimeError("Failed to load script, perhaps a syntax error?")
new = self.read_configuration()
return (old, new)
@@ -169,8 +166,22 @@ class aa1Tasks(PSIDeviceBase, Device):
"""Bluesky style stage, prepare, but does not execute"""
if self.taskIndex.get() in (0, 1, 2):
logger.error(f"[{self.name}] Loading AeroScript on system task. Daring today are we?")
if len(self.fileName.get())==0:
self.fileName.set("bec.ascript", settle_time=0.1).wait()
self._failure.read()
ts_old = float(self._failure.timestamp)
def wait_until_new(*_, old_value, value, timestamp, **__):
nonlocal ts_old
result = bool(ts_old != timestamp) and (value!=-1)
# print(f"{old_value}\t{value}\t{ts_old}\t{timestamp}\t{result}")
return result
# Subscribe and wait for update
status = SubscriptionStatus(self._failure, wait_until_new, settle_time=0.1)
# Load and check success
status = self.switch.set("Load", settle_time=0.2)
self.switch.set("Load", settle_time=0.0).wait()
status.wait()
if self._failure.value:
raise RuntimeError("Failed to load task, please check the Aerotech IOC")
@@ -191,11 +202,14 @@ class aa1Tasks(PSIDeviceBase, Device):
def complete(self) -> SubscriptionStatus:
"""Wait for a RUNNING task"""
# Sleep for foll period
time.sleep(1)
timestamp_ = 0
task_idx = int(self.taskIndex.get())
def not_running(*, value, timestamp, **_):
nonlocal timestamp_
# print(f"State {value[task_idx]} in {value}")
result = value[task_idx] not in ["Running", 4]
timestamp_ = timestamp
return result

View File

@@ -7,3 +7,7 @@ from .AerotechAutomation1 import (
aa1GlobalVariableBindings,
aa1AxisIo,
)
from .AerotechAutomation1Enums import (
DriveDataCaptureInput,
DriveDataCaptureTrigger,
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,18 @@
// Test program for zig-zag line scanning with PSO window output "enable"
// signal and DDC synchronized to external trigger input.
// Test program for simple zig-zag line scanning with PSO window output
// "enable" signal and DDC synchronized to external trigger input.
// 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
Neg = 1
PosNeg = 2
NegPos = 3
POS = 0
NEG = 1
POSNEG = 2
NEGPOS = 3
end
@@ -15,74 +20,98 @@ 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 $eScanType as ScanType = ScanType.{{ scan.scandir or 'POS' }}
var $iNumDdcRead as integer = {{ scan.npoints }}
var $fVelJog as real = {{ scan.jogvel or 200 }}
var $fVelScan as real = {{ scan.scanvel }}
var $fAcceleration = {{ scan.scanacc or 500 }}
var $fSafeDist = 10.0
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
var $ii as integer
var $axis as axis = {{ scan.rotaxis or 'ROTY' }}
var $ii as integer
var $axisFaults as integer = 0
var $iDdcSafeSpace as integer = 4096
// Set acceleration
SetupAxisRampType($axis, RampType.Linear)
SetupAxisRampValue($axis,0,$fAcceleration)
var $fAccDistance as real = 0.5 * $fVelScan * $fVelScan / $fAcceleration + $fSafeDist
SetupAxisRampValue($axis, 0, $fAcceleration)
// set the actual scan range
var $fPosStart as real
var $fPosEnd as real
if $eScanType == ScanType.Pos
if $eScanType == ScanType.POS
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.Neg
elseif $eScanType == ScanType.NEG
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
elseif $eScanType == ScanType.PosNeg
elseif $eScanType == ScanType.POSNEG
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.NegPos
elseif $eScanType == ScanType.NEGPOS
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
end
// Move to start position before the scan
// NOTE: Also wait for GigaFrost to start, otherwise early triggers might be missed
MoveAbsolute($axis, $fPosStart, $fVelJog)
WaitForInPosition($axis)
Dwell(2)
// 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 $iPsoArray[] as real = [UnitsToCounts($axis, $fAccDistance), UnitsToCounts($axis, $fScanRange)]
DriveArrayWrite($axis, $iPsoArray, $iPsoArrayAddr, length($iPsoArray), DriveArrayType.PsoDistanceEventDistances)
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, 2, 0)
// Simple PSO trigger pattern
var $iPsoArrayPosAddr as integer = PSO_ADDR
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }}) ]
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
{% if scan.psoBoundsNeg|length > 0 %}
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
var $iPsoArrayNeg[] as real = [{% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsNeg[-1] }}) ]
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
{% else %}
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
var $iPsoArrayNegSize as integer = 0
var $iPsoArrayNeg[] as real = []
// DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
{% endif %}
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 = 5000
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)
@@ -92,41 +121,44 @@ program
///////////////////////////////////////////////////////////
// Start the actual scanning
///////////////////////////////////////////////////////////
for $ii = 0 to ($iNumRepeat-1)
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, 2, 0)
if $eScanType == ScanType.Pos
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
elseif $eScanType == ScanType.Neg
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
elseif $eScanType == ScanType.PosNeg
if ($ii % 2) == 0
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
elseif ($ii % 2) == 1
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
end
elseif $eScanType == ScanType.NegPos
if ($ii % 2) == 0
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForInPosition($axis)
elseif ($ii % 2) == 1
MoveAbsolute($axis, $fPosStart, $fVelScan)
WaitForInPosition($axis)
end
if $eScanType == ScanType.POS || $eScanType == ScanType.NEG
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForMotionDone($axis)
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
if $axisFaults
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
end
elseif $eScanType == ScanType.POSNEG || $eScanType == ScanType.NEGPOS
for $ii = 0 to ($iNumRepeat-1)
// Feedback on progress
$rglobal[4] = $ii
if ($ii % 2) == 0
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
MoveAbsolute($axis, $fPosEnd, $fVelScan)
elseif ($ii % 2) == 1
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, length($iPsoArrayNeg), 0)
MoveAbsolute($axis, $fPosStart, $fVelScan)
end
WaitForMotionDone($axis)
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
if $axisFaults
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
end
Dwell(0.2)
end
Dwell(0.2)
end
// Directly after scan
PsoDistanceCounterOff($axis)
DriveDataCaptureOff($axis, 0)
DriveDataCaptureOff($axis, 1)
// move back to start position
MoveAbsolute($axis, $fPosStart, $fVelJog)
WaitForInPosition($axis)
Dwell(2)
end

View File

@@ -0,0 +1,158 @@
// Test program for simple zig-zag line scanning with PSO window output
// "enable" signal and DDC synchronized to external trigger input.
// 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
NEG = 1
POSNEG = 2
NEGPOS = 3
end
program
//////////////////////////////////////////////////////////////////////////
// External parameters - USE THEESE
var $fStartPosition as real = 42
var $fScanRange as real = 180
var $iNumRepeat as integer = 13
var $eScanType as ScanType = ScanType.NEGPOS
var $iNumDdcRead as integer = 1300
var $fVelJog as real = 200
var $fVelScan as real = 150
var $fAcceleration = 500
var $fAccDistance as real = 22.5
var $eDdcTrigger as DriveDataCaptureTrigger = DriveDataCaptureTrigger.PsoEvent
//////////////////////////////////////////////////////////////////////////
// Internal parameters - dont use
var $axis as axis = ROTY
var $ii as integer
var $axisFaults as integer = 0
var $iDdcSafeSpace as integer = 4096
// Set acceleration
SetupAxisRampType($axis, RampType.Linear)
SetupAxisRampValue($axis, 0, $fAcceleration)
// set the actual scan range
var $fPosStart as real
var $fPosEnd as real
if $eScanType == ScanType.POS
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.NEG
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
elseif $eScanType == ScanType.POSNEG
$fPosStart = $fStartPosition - $fAccDistance
$fPosEnd = $fStartPosition + $fScanRange + $fAccDistance
elseif $eScanType == ScanType.NEGPOS
$fPosStart = $fStartPosition + $fAccDistance
$fPosEnd = $fStartPosition - $fScanRange - $fAccDistance
end
// Move to start position before the scan
// NOTE: Also wait for GigaFrost to start, otherwise early triggers might be missed
MoveAbsolute($axis, $fPosStart, $fVelJog)
WaitForInPosition($axis)
Dwell(2)
// 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)
// Simple PSO trigger pattern
var $iPsoArrayPosAddr as integer = PSO_ADDR
var $iPsoArrayPos[] as real = [ UnitsToCounts($axis, 22.5), UnitsToCounts($axis, 180) ]
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayPosAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
var $iPsoArrayNegAddr as integer = ($iPsoArrayPosAddr + length($iPsoArrayPos)) * 4
var $iPsoArrayNeg[] as real = [ UnitsToCounts($axis, 22.5), UnitsToCounts($axis, 180) ]
DriveArrayWrite($axis, $iPsoArrayNeg, $iPsoArrayNegAddr, length($iPsoArrayNeg), DriveArrayType.PsoDistanceEventDistances)
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
PsoDistanceCounterOn($axis)
PsoDistanceEventsOn($axis)
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
PsoWaveformOn($axis)
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
// Configure Drive Data Collection
var $iDdcArraySize as integer = $iNumDdcRead
DriveDataCaptureConfigureInput($axis, 0, DriveDataCaptureInput.PrimaryFeedback);
DriveDataCaptureConfigureInput($axis, 1, DriveDataCaptureInput.AnalogInput0 );
DriveDataCaptureConfigureTrigger($axis, 0, $eDdcTrigger );
DriveDataCaptureConfigureTrigger($axis, 1, $eDdcTrigger );
DriveDataCaptureConfigureArray($axis, 0, DDC_ADDR, $iDdcArraySize);
DriveDataCaptureConfigureArray($axis, 1, DDC_ADDR + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
// Directly before scan
PsoDistanceCounterOn($axis)
DriveDataCaptureOn($axis, 0)
DriveDataCaptureOn($axis, 1)
///////////////////////////////////////////////////////////
// Start the actual scanning
///////////////////////////////////////////////////////////
if $eScanType == ScanType.POS || $eScanType == ScanType.NEG
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
MoveAbsolute($axis, $fPosEnd, $fVelScan)
WaitForMotionDone($axis)
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
if $axisFaults
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
end
elseif $eScanType == ScanType.POSNEG || $eScanType == ScanType.NEGPOS
for $ii = 0 to ($iNumRepeat-1)
// Feedback on progress
$rglobal[4] = $ii
if ($ii % 2) == 0
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayPosAddr, length($iPsoArrayPos), 0)
MoveAbsolute($axis, $fPosEnd, $fVelScan)
elseif ($ii % 2) == 1
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayNegAddr, length($iPsoArrayNeg), 0)
MoveAbsolute($axis, $fPosStart, $fVelScan)
end
WaitForMotionDone($axis)
$axisFaults = StatusGetAxisItem($axis, AxisDataSignal.AxisFault)
if $axisFaults
TaskSetError(TaskGetIndex(), "AxisFault on axis ROTY")
end
Dwell(0.2)
end
end
// Directly after scan
PsoDistanceCounterOff($axis)
DriveDataCaptureOff($axis, 0)
DriveDataCaptureOff($axis, 1)
// move back to start position
MoveAbsolute($axis, $fPosStart, $fVelJog)
WaitForInPosition($axis)
Dwell(2)
end