Added templated scan and required status updates

This commit is contained in:
mohacsi_i 2024-03-05 16:47:23 +01:00
parent 1f3ef42a9d
commit 16f033a833
2 changed files with 122 additions and 4 deletions

View File

@ -119,6 +119,7 @@ class aa1Tasks(Device):
it and run it directly on a certain thread. But there's no way to it and run it directly on a certain thread. But there's no way to
retrieve the source code. retrieve the source code.
""" """
SUB_PROGRESS = "progress"
_failure = Component(EpicsSignalRO, "FAILURE", kind=Kind.hinted) _failure = Component(EpicsSignalRO, "FAILURE", kind=Kind.hinted)
errStatus = Component(EpicsSignalRO, "ERRW", auto_monitor=True, kind=Kind.hinted) errStatus = Component(EpicsSignalRO, "ERRW", auto_monitor=True, kind=Kind.hinted)
warnStatus = Component(EpicsSignalRO, "WARNW", auto_monitor=True, kind=Kind.hinted) warnStatus = Component(EpicsSignalRO, "WARNW", auto_monitor=True, kind=Kind.hinted)
@ -139,7 +140,23 @@ class aa1Tasks(Device):
self._textToExecute = None self._textToExecute = None
self._isConfigured = False self._isConfigured = False
self._isStepConfig = False self._isStepConfig = False
self.subscribe(self._progress_update, "progress", run=False)
def _progress_update(self, value, **kwargs) -> None:
"""Progress update on the scan"""
value = self.progress()
self._run_subs( sub_type=self.SUB_PROGRESS, value=value, max_value=1, done=1, )
def _progress(self) -> None:
"""Progress update on the scan"""
if self._currentTaskMonitor is None:
return 1
else:
if self._currentTaskMonitor.status.value in ["Running", 4]:
return 0
else:
return 1
def readFile(self, filename: str) -> str: def readFile(self, filename: str) -> str:
""" Read a file from the controller """ """ Read a file from the controller """
# Have to use CHAR array due to EPICS LSI bug... # Have to use CHAR array due to EPICS LSI bug...
@ -198,7 +215,8 @@ class aa1Tasks(Device):
old = self.read_configuration() old = self.read_configuration()
self.taskIndex.set(taskIndex).wait() self.taskIndex.set(taskIndex).wait()
self._textToExecute = None self._textToExecute = None
#self._currentTaskMonitor = aa1TaskState() self._currentTaskMonitor = aa1TaskState(prefix=self.prefix+f"T{taskIndex}:", name="taskmon")
self._currentTaskMonitor.wait_for_connection()
# Choose the right execution mode # Choose the right execution mode
if (filename is None) and (text not in [None, ""]): if (filename is None) and (text not in [None, ""]):
@ -270,11 +288,22 @@ class aa1Tasks(Device):
def complete(self) -> DeviceStatus: def complete(self) -> DeviceStatus:
""" Execute the script on the configured task""" """ Execute the script on the configured task"""
print("Called aa1Task.complete()")
#return self._currentTaskMonitor.complete() #return self._currentTaskMonitor.complete()
status = DeviceStatus(self) #status = DeviceStatus(self)
status.set_finished() #status.set_finished()
#return status
timestamp_ = 0
def notRunning(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_
result = False if (timestamp_== 0) else (value not in ["Running", 4])
timestamp_ = timestamp
print(result)
return result
# Subscribe and wait for update
status = SubscriptionStatus(self._currentTaskMonitor.status, notRunning, settle_time=0.5)
return status return status
def describe_collect(self) -> OrderedDict: def describe_collect(self) -> OrderedDict:
dd = OrderedDict() dd = OrderedDict()
dd['success'] = {'source': "internal", 'dtype': 'integer', 'shape': [], 'units': '', 'lower_ctrl_limit': 0, 'upper_ctrl_limit': 0} dd['success'] = {'source': "internal", 'dtype': 'integer', 'shape': [], 'units': '', 'lower_ctrl_limit': 0, 'upper_ctrl_limit': 0}
@ -300,12 +329,14 @@ class aa1TaskState(Device):
def complete(self) -> StatusBase: def complete(self) -> StatusBase:
""" Bluesky flyer interface""" """ Bluesky flyer interface"""
print("Called aa1TaskState.complete()")
# Define wait until the busy flag goes down (excluding initial update) # Define wait until the busy flag goes down (excluding initial update)
timestamp_ = 0 timestamp_ = 0
def notRunning(*args, old_value, value, timestamp, **kwargs): def notRunning(*args, old_value, value, timestamp, **kwargs):
nonlocal timestamp_ nonlocal timestamp_
result = False if (timestamp_== 0) else (value not in ["Running", 4]) result = False if (timestamp_== 0) else (value not in ["Running", 4])
timestamp_ = timestamp timestamp_ = timestamp
print(result)
return result return result
# Subscribe and wait for update # Subscribe and wait for update

View File

@ -0,0 +1,87 @@
// Snap-and-step
// Test program for high speed step scanning with individual triggers on PSO output.
// The file expects external parameter validation.
program
// External parameters
var $fStartPosition as real = {{ scan.startpos }}
var $iNumSteps as integer = {{ scan.numsteps }}
var $fStepSize as real = {{ scan.stepsize }}
var $fExposureTimeSec as real = {{ scan.exptime }}
var $fVelJog as real = {{ scan.travel or 200 }}
var $fVelScan as real = {{ scan.velocity or 50 }}
var $fAcceleration = {{ scan.acceleration or 500 }}
// Internal
var $axis as axis = ROTY
var $ii as integer
// Set acceleration
SetupAxisRampType($axis, RampType.Linear)
SetupAxisRampValue($axis,0,$fAcceleration)
// Move to start position before the scan
var $fPosNext as real = $fStartPosition
MoveAbsolute($axis, $fPosNext, $fVelJog)
WaitForInPosition($axis)
// Configure PSO (to manual event generation)
PsoDistanceEventsOff($axis)
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
PsoWaveformConfigurePulseFixedTotalTime($axis, 50)
PsoWaveformConfigurePulseFixedOnTime($axis, 20)
PsoWaveformConfigurePulseFixedCount($axis, 1)
PsoWaveformApplyPulseConfiguration($axis)
PsoWaveformConfigureMode($axis, PsoWaveformMode.Pulse)
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
PsoWaveformOn($axis)
// Configure Drive Data Collection
var $iDdcArrayAddr as integer = 8388608
var $iDdcArraySize as integer = iMaximum(5000, $iNumSteps)
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 );
DriveDataCaptureConfigureArray($axis, 0, $iDdcArrayAddr, $iDdcArraySize);
DriveDataCaptureConfigureArray($axis, 1, $iDdcArrayAddr + $iDdcSafeSpace + 8 * $iDdcArraySize, $iDdcArraySize);
// Directly before scan
PsoDistanceCounterOn($axis)
DriveDataCaptureOn($axis, 0)
DriveDataCaptureOn($axis, 1)
///////////////////////////////////////////////////////////
// Start the actual scanning
///////////////////////////////////////////////////////////
for $ii = 0 to ($iNumSteps-1)
MoveAbsolute($axis, $fPosNext, $fVelScan)
WaitForInPosition($axis)
PsoEventGenerateSingle($axis)
Dwell($fExposureTimeSec)
$fPosNext = $fPosNext + $fStepSize
end
// Directly after scan
PsoWaveformOff($axis)
DriveDataCaptureOff($axis, 0)
DriveDataCaptureOff($axis, 1)
end
// Demonstrates using a switch/case conditional.
function iMaximum($A as integer, $B as integer) as integer
var $retVal
if ($A > $B)
$retVal = $A
else
$retVal = $B
end
return $retVal
end