feat(devices): added device classes from ophyd_devices
This commit is contained in:
@@ -12,7 +12,7 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"Topic :: Scientific/Engineering",
|
||||
]
|
||||
dependencies = []
|
||||
dependencies = ["ophyd_devices", "bec_lib"]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = ["black", "isort", "coverage", "pylint", "pytest", "pytest-random-order", "ophyd_devices", "bec_server"]
|
||||
|
||||
226
tests/tests_devices/test_grashopper_tomcat.py
Normal file
226
tests/tests_devices/test_grashopper_tomcat.py
Normal file
@@ -0,0 +1,226 @@
|
||||
# pylint: skip-file
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from tomcat_bec.devices.grashopper_tomcat import (
|
||||
COLORMODE,
|
||||
AutoMode,
|
||||
DetectorState,
|
||||
GrashopperError,
|
||||
GrashopperTimeoutError,
|
||||
GrashopperTOMCATSetup,
|
||||
ImageBinning,
|
||||
ImageMode,
|
||||
MemoryPolling,
|
||||
PixelFormat,
|
||||
TriggerSource,
|
||||
VideoMode,
|
||||
)
|
||||
|
||||
|
||||
def patch_dual_pvs(device):
|
||||
for walk in device.walk_signals():
|
||||
if not hasattr(walk.item, "_read_pv"):
|
||||
continue
|
||||
if not hasattr(walk.item, "_write_pv"):
|
||||
continue
|
||||
if walk.item._read_pv.pvname.endswith("_RBV"):
|
||||
walk.item._read_pv = walk.item._write_pv
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def mock_GrashopperSetup():
|
||||
mock_Grashopper = mock.MagicMock()
|
||||
yield GrashopperTOMCATSetup(parent=mock_Grashopper)
|
||||
|
||||
|
||||
# Fixture for scaninfo
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
{
|
||||
"scan_id": "1234",
|
||||
"scan_type": "step",
|
||||
"num_points": 500,
|
||||
"frames_per_trigger": 1,
|
||||
"exp_time": 0.1,
|
||||
"readout_time": 0.1,
|
||||
},
|
||||
{
|
||||
"scan_id": "1234",
|
||||
"scan_type": "step",
|
||||
"num_points": 500,
|
||||
"frames_per_trigger": 5,
|
||||
"exp_time": 0.01,
|
||||
"readout_time": 0,
|
||||
},
|
||||
{
|
||||
"scan_id": "1234",
|
||||
"scan_type": "fly",
|
||||
"num_points": 500,
|
||||
"frames_per_trigger": 1,
|
||||
"exp_time": 1,
|
||||
"readout_time": 0.2,
|
||||
},
|
||||
{
|
||||
"scan_id": "1234",
|
||||
"scan_type": "fly",
|
||||
"num_points": 500,
|
||||
"frames_per_trigger": 5,
|
||||
"exp_time": 0.1,
|
||||
"readout_time": 0.4,
|
||||
},
|
||||
]
|
||||
)
|
||||
def scaninfo(request):
|
||||
return request.param
|
||||
|
||||
|
||||
def test_initialize_detector(mock_GrashopperSetup):
|
||||
"""Test the initialize_detector method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.initialize_detector()
|
||||
|
||||
# Assert the correct methods are called with the expected arguments
|
||||
mock_GrashopperSetup.parent.cam.acquire.put.assert_called_once_with(0)
|
||||
mock_GrashopperSetup.parent.cam.acquire_time_auto.put.assert_called_once_with(
|
||||
AutoMode.CONTINUOUS
|
||||
)
|
||||
mock_GrashopperSetup.parent.cam.gain_auto.put.assert_called_once_with(AutoMode.CONTINUOUS)
|
||||
mock_GrashopperSetup.parent.cam.image_mode.put.assert_called_once_with(ImageMode.MULTIPLE)
|
||||
mock_GrashopperSetup.parent.cam.image_binning.put.assert_called_once_with(ImageBinning.X1)
|
||||
mock_GrashopperSetup.parent.cam.video_mode.put.assert_called_once_with(VideoMode.MODE0)
|
||||
mock_GrashopperSetup.parent.cam.pixel_format.put.assert_called_once_with(PixelFormat.MONO16)
|
||||
mock_GrashopperSetup.parent.cam.trigger_source.put.assert_called_once_with(
|
||||
TriggerSource.SOFTWARE
|
||||
)
|
||||
mock_GrashopperSetup.parent.cam.memory_polling.put.assert_called_once_with(
|
||||
MemoryPolling.SECONDS1
|
||||
)
|
||||
mock_GrashopperSetup.parent.cam.set_image_counter.put.assert_called_once_with(0)
|
||||
|
||||
|
||||
def test_initialize_detector_backend(mock_GrashopperSetup):
|
||||
"""Test the initialize_detector_backend method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.initialize_detector_backend()
|
||||
|
||||
# Assert the correct methods are called with the expected arguments
|
||||
mock_GrashopperSetup.parent.image.queue_size.put.assert_called_once_with(5)
|
||||
mock_GrashopperSetup.parent.image.array_port.put.assert_called_once_with(
|
||||
mock_GrashopperSetup.parent.cam.port_name.get()
|
||||
)
|
||||
mock_GrashopperSetup.parent.image.enable_cb.put.assert_called_once_with(1)
|
||||
mock_GrashopperSetup.parent.image.set_array_counter.put.assert_called_once_with(0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("exposure_time", [1, 0.1, 0.01, 0.001, 0.0001])
|
||||
def test_set_exposure_time(mock_GrashopperSetup, exposure_time):
|
||||
"""Test the set_exposure_time method."""
|
||||
# Call the function you want to test
|
||||
frame_rate = 1 / exposure_time
|
||||
if frame_rate > mock_GrashopperSetup.low_frame_rate:
|
||||
with pytest.raises(GrashopperError):
|
||||
mock_GrashopperSetup.set_exposure_time(exposure_time)
|
||||
else:
|
||||
mock_GrashopperSetup.set_exposure_time(exposure_time)
|
||||
mock_GrashopperSetup.parent.cam.frame_rate.put.assert_called_once_with(frame_rate)
|
||||
|
||||
|
||||
def test_prepare_detector(mock_GrashopperSetup, scaninfo):
|
||||
"""Test the prepare_detector method."""
|
||||
# setup scaninof
|
||||
for k, v in scaninfo.items():
|
||||
setattr(mock_GrashopperSetup.parent.scaninfo, k, v)
|
||||
|
||||
# Call the function you want to test
|
||||
with (
|
||||
mock.patch.object(
|
||||
mock_GrashopperSetup, "set_acquisition_params"
|
||||
) as mock_set_acquisition_params,
|
||||
mock.patch.object(mock_GrashopperSetup, "set_exposure_time") as mock_set_exposure_time,
|
||||
):
|
||||
mock_GrashopperSetup.prepare_detector()
|
||||
|
||||
# Assert the correct methods are called with the expected arguments
|
||||
mock_GrashopperSetup.parent.cam.image_mode.put.assert_called_once_with(ImageMode.MULTIPLE)
|
||||
mock_GrashopperSetup.parent.cam.acquire_time_auto.put.assert_called_once_with(
|
||||
AutoMode.CONTINUOUS
|
||||
)
|
||||
mock_GrashopperSetup.parent.set_trigger.assert_called_once_with(TriggerSource.SOFTWARE)
|
||||
mock_GrashopperSetup.parent.cam.set_image_counter.put.assert_called_once_with(0)
|
||||
mock_set_acquisition_params.assert_called_once()
|
||||
mock_set_exposure_time.assert_called_once_with(scaninfo["exp_time"])
|
||||
|
||||
|
||||
def test_prepare_detector_backend(mock_GrashopperSetup):
|
||||
"""Test the prepare_detector_backend method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.prepare_detector_backend()
|
||||
mock_GrashopperSetup.parent.image.set_array_counter.put.assert_called_once_with(0)
|
||||
assert mock_GrashopperSetup.monitor_thread is None
|
||||
assert not mock_GrashopperSetup.stop_monitor
|
||||
|
||||
|
||||
@pytest.mark.parametrize("detector_state", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
def test_arm_acquisition(mock_GrashopperSetup, detector_state):
|
||||
"""Test the arm_acquisition method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.parent.cam.detector_state.get.return_value = detector_state
|
||||
mock_GrashopperSetup.parent.timeout = 0.1
|
||||
|
||||
if detector_state != DetectorState.WAITING:
|
||||
with pytest.raises(GrashopperTimeoutError):
|
||||
mock_GrashopperSetup.arm_acquisition()
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(1)
|
||||
else:
|
||||
mock_GrashopperSetup.arm_acquisition()
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("trigger_source", [0, 1, 2, 3])
|
||||
def test_on_trigger(mock_GrashopperSetup, trigger_source):
|
||||
"""Test the on_trigger method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.parent.cam.trigger_source.get.return_value = trigger_source
|
||||
with mock.patch.object(mock_GrashopperSetup, "send_data") as mock_send_data:
|
||||
mock_GrashopperSetup.on_trigger()
|
||||
|
||||
# Assert the correct methods are called with the expected arguments
|
||||
if trigger_source == TriggerSource.SOFTWARE:
|
||||
mock_GrashopperSetup.parent.cam.software_trigger_device.put.assert_called_once_with(1)
|
||||
assert mock_send_data.call_count == 1
|
||||
|
||||
|
||||
def test_set_acquisition_params(mock_GrashopperSetup, scaninfo):
|
||||
"""Test the set_acquisition_params method."""
|
||||
# Setup scaninfo
|
||||
mock_GrashopperSetup.parent.scaninfo.num_points = scaninfo["num_points"]
|
||||
mock_GrashopperSetup.parent.scaninfo.frames_per_trigger = scaninfo["frames_per_trigger"]
|
||||
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.set_acquisition_params()
|
||||
|
||||
# Assert the correct methods are called with the expected arguments
|
||||
expected_num_images = scaninfo["num_points"] * scaninfo["frames_per_trigger"]
|
||||
mock_GrashopperSetup.parent.cam.num_images.put.assert_called_once_with(expected_num_images)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("detector_state", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
def test_stop_detector(mock_GrashopperSetup, detector_state):
|
||||
"""Test the arm_acquisition method."""
|
||||
# Call the function you want to test
|
||||
mock_GrashopperSetup.parent.cam.detector_state.get.return_value = detector_state
|
||||
mock_GrashopperSetup.parent.timeout = 0.1
|
||||
|
||||
if detector_state != DetectorState.IDLE:
|
||||
with pytest.raises(GrashopperTimeoutError):
|
||||
mock_GrashopperSetup.stop_detector()
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 2
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(0)
|
||||
else:
|
||||
mock_GrashopperSetup.stop_detector()
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_count == 1
|
||||
assert mock_GrashopperSetup.parent.cam.acquire.put.call_args == mock.call(0)
|
||||
94
tomcat_bec/device_configs/microxas_test_bed.yaml
Normal file
94
tomcat_bec/device_configs/microxas_test_bed.yaml
Normal file
@@ -0,0 +1,94 @@
|
||||
eyex:
|
||||
readoutPriority: baseline
|
||||
description: X-ray eye translation x
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig:
|
||||
prefix: MTEST-X05LA-ES2-XRAYEYE:M1
|
||||
deviceTags:
|
||||
- xray-eye
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readOnly: false
|
||||
softwareTrigger: false
|
||||
eyey:
|
||||
readoutPriority: baseline
|
||||
description: X-ray eye translation y
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig:
|
||||
prefix: MTEST-X05LA-ES2-XRAYEYE:M2
|
||||
deviceTags:
|
||||
- xray-eye
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readOnly: false
|
||||
softwareTrigger: false
|
||||
eyez:
|
||||
readoutPriority: baseline
|
||||
description: X-ray eye translation z
|
||||
deviceClass: ophyd.EpicsMotor
|
||||
deviceConfig:
|
||||
prefix: MTEST-X05LA-ES2-XRAYEYE:M3
|
||||
deviceTags:
|
||||
- xray-eye
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readOnly: false
|
||||
softwareTrigger: false
|
||||
femto_mean_curr:
|
||||
readoutPriority: monitored
|
||||
description: Femto mean current
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
deviceConfig:
|
||||
auto_monitor: true
|
||||
read_pv: MTEST-X05LA-ES2-XRAYEYE:FEMTO-MEAN-CURR
|
||||
deviceTags:
|
||||
- xray-eye
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readOnly: true
|
||||
softwareTrigger: false
|
||||
es1_roty:
|
||||
description: 'Test rotation stage'
|
||||
deviceClass: ophyd_devices.epics.devices.EpicsMotorX
|
||||
deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY'}
|
||||
onFailure: buffer
|
||||
enabled: true
|
||||
readoutPriority: monitored
|
||||
|
||||
# es1_tasks:
|
||||
# description: 'AA1 task management interface'
|
||||
# deviceClass: tomcat_bec.devices.aa1Tasks
|
||||
# deviceConfig: {prefix: 'X02DA-ES1-SMP1:TASK:'}
|
||||
# onFailure: buffer
|
||||
# enabled: true
|
||||
# readoutPriority: monitored
|
||||
|
||||
# es1_psod:
|
||||
# description: 'AA1 PSO output interface'
|
||||
# deviceClass: tomcat_bec.devices.aa1AxisPsoDistance
|
||||
# deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY:PSO:'}
|
||||
# onFailure: buffer
|
||||
# enabled: true
|
||||
# readoutPriority: monitored
|
||||
|
||||
# es1_ddaq:
|
||||
# description: 'AA1 drive data collection interface'
|
||||
# deviceClass: tomcat_bec.devices.aa1AxisDriveDataCollection
|
||||
# deviceConfig: {prefix: 'X02DA-ES1-SMP1:ROTY:DDC:'}
|
||||
# onFailure: buffer
|
||||
# enabled: true
|
||||
# readoutPriority: monitored
|
||||
|
||||
camera:
|
||||
description: Grashopper Camera
|
||||
deviceClass: tomcat_bec.devices.GrashopperTOMCAT
|
||||
deviceConfig:
|
||||
prefix: 'X02DA-PG-USB:'
|
||||
deviceTags:
|
||||
- camera
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: monitored
|
||||
softwareTrigger: true
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from .aerotech.AerotechAutomation1 import (
|
||||
EpicsMotorX,
|
||||
aa1AxisDriveDataCollection,
|
||||
aa1AxisPsoDistance,
|
||||
aa1Controller,
|
||||
aa1GlobalVariableBindings,
|
||||
aa1GlobalVariables,
|
||||
aa1Tasks,
|
||||
)
|
||||
from .grashopper_tomcat import GrashopperTOMCAT
|
||||
|
||||
1490
tomcat_bec/devices/aerotech/AerotechAutomation1.py
Normal file
1490
tomcat_bec/devices/aerotech/AerotechAutomation1.py
Normal file
File diff suppressed because it is too large
Load Diff
901
tomcat_bec/devices/aerotech/AerotechAutomation1Enums.py
Normal file
901
tomcat_bec/devices/aerotech/AerotechAutomation1Enums.py
Normal file
@@ -0,0 +1,901 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class TomcatSequencerState:
|
||||
IDLE = 0
|
||||
READY = 1
|
||||
ARMED = 2
|
||||
RUNNING = 3
|
||||
CHANGING = 4
|
||||
ERROR = 15
|
||||
|
||||
|
||||
class AxisDataSignal:
|
||||
PositionFeedback = 0
|
||||
PositionCommand = 1
|
||||
PositionError = 2
|
||||
VelocityFeedback = 3
|
||||
VelocityCommand = 4
|
||||
VelocityError = 5
|
||||
AccelerationCommand = 6
|
||||
CurrentError = 9
|
||||
PositionCommandRaw = 12
|
||||
VelocityCommandRaw = 13
|
||||
AuxiliaryFeedback = 14
|
||||
DigitalInput = 15
|
||||
DigitalOutput = 16
|
||||
FixtureOffset = 18
|
||||
CoordinatedPositionTarget = 41
|
||||
DriveStatus = 42
|
||||
AxisStatus = 43
|
||||
AxisFault = 44
|
||||
AccelerationCommandRaw = 45
|
||||
PositionCalibrationAll = 50
|
||||
PositionFeedbackRollover = 63
|
||||
PositionCommandRollover = 64
|
||||
VelocityFeedbackAverage = 65
|
||||
CurrentFeedbackAverage = 66
|
||||
AxisParameter = 68
|
||||
Backlash = 72
|
||||
HomeState = 73
|
||||
PositionCalibration2D = 74
|
||||
NormalcyDebug = 75
|
||||
TotalMoveTime = 76
|
||||
JerkCommandRaw = 78
|
||||
ProgramPositionCommand = 79
|
||||
PositionOffset = 80
|
||||
PositionCommandRawBackwardsDiff = 82
|
||||
VelocityCommandRawBackwardsDiffDelta = 83
|
||||
DriveStatusActual = 85
|
||||
ProgramPositionFeedback = 89
|
||||
JogTrajectoryStatus = 94
|
||||
PingTest = 95
|
||||
AccelerationTime = 109
|
||||
DecelerationTime = 110
|
||||
AccelerationRate = 111
|
||||
DecelerationRate = 112
|
||||
AccelerationType = 113
|
||||
DecelerationType = 114
|
||||
AccelerationMode = 115
|
||||
DecelerationMode = 116
|
||||
ProgramPosition = 124
|
||||
SpeedTarget = 128
|
||||
PositionCommandPacket = 131
|
||||
DriveSmcMotionState = 132
|
||||
PositionCommandRawCal = 140
|
||||
VelocityCommandRawCal = 141
|
||||
VelocityCommandDrive = 142
|
||||
AccelerationCommandDrive = 143
|
||||
GalvoLaserOutputRaw = 144
|
||||
DriveInterfacePacketInt32 = 147
|
||||
DriveInterfacePacketInt16 = 148
|
||||
DriveInterfacePacketInt8 = 149
|
||||
DriveInterfacePacketDouble = 150
|
||||
DriveInterfacePacketFloat = 151
|
||||
DriveInterfaceCommandCode = 152
|
||||
AccelerationFeedback = 153
|
||||
AccelerationCommandRawCal = 154
|
||||
PositionCalibrationAllDrive = 155
|
||||
BacklashTarget = 156
|
||||
DriveMotionRate = 158
|
||||
DriveMotionDelay = 159
|
||||
CalibrationAdjustmentValue = 160
|
||||
ServoRounding = 161
|
||||
FeedforwardCurrent = 162
|
||||
DriveInterfacePacketInfoBitValue = 164
|
||||
AccelerationError = 165
|
||||
SuppressedFaults = 167
|
||||
DriveInterfacePacketStreamingData = 168
|
||||
PositionCommandRawUnfiltered = 169
|
||||
TransitionOffsetErrors = 170
|
||||
FreezeVelocityCommand = 179
|
||||
FreezeVelocityFeedback = 180
|
||||
InternalPositionOffsets = 181
|
||||
StatusHighLevelOffsetsLastMsec = 182
|
||||
ProgramVelocityCommand = 183
|
||||
ProgramVelocityFeedback = 184
|
||||
DriveMotionDelayLive = 185
|
||||
DriveCommunicationDelay = 186
|
||||
DriveCommunicationDelayLive = 187
|
||||
DriveInterfacePacketResponseInt32 = 189
|
||||
DriveInterfacePacketResponseInt16 = 190
|
||||
DriveInterfacePacketResponseInt8 = 191
|
||||
DriveInterfacePacketResponseDouble = 192
|
||||
DriveInterfacePacketResponseFloat = 193
|
||||
DriveInterfacePacketBit = 194
|
||||
DriveInterfacePacketResponseBit = 195
|
||||
SpeedTargetActual = 196
|
||||
CoordinatedDistanceRemaining = 199
|
||||
SafeZoneState = 230
|
||||
PositionErrorGalvo = 235
|
||||
MoveReferencePosition = 237
|
||||
MoveReferenceCutterOffset = 250
|
||||
MoveReferenceCornerOffset = 251
|
||||
MoveReferenceTotalOffset = 252
|
||||
DistanceLog = 264
|
||||
AutoFocusError = 295
|
||||
GalvoLaserOutputRawAdvance = 296
|
||||
GalvoLaserOnDelay = 297
|
||||
GalvoLaserOffDelay = 298
|
||||
CalibrationAdjustmentState = 301
|
||||
AccuracyCorrectionStartingPosition = 302
|
||||
AccuracyCorrectionEndingPosition = 303
|
||||
DriveCommandsDelayed = 309
|
||||
DriveCommandsLost = 310
|
||||
StoStatus = 327
|
||||
DriveAssert = 336
|
||||
PrimaryFeedback = 366
|
||||
AccelerationSCurvePercentage = 371
|
||||
DecelerationSCurvePercentage = 372
|
||||
GantryMarkerDifference = 390
|
||||
PrimaryFeedbackStatus = 392
|
||||
HomeTargetPosition = 398
|
||||
GantryRealignmentMoveTargetPosition = 399
|
||||
GantryDriveControlRealignmentState = 400
|
||||
DriveInterfacePositionCommandPhysical = 434
|
||||
DriveControlReason = 435
|
||||
CurrentFeedback = 7
|
||||
CurrentCommand = 8
|
||||
AnalogInput0 = 10
|
||||
AnalogInput1 = 11
|
||||
PhaseACurrentFeedback = 19
|
||||
PhaseBCurrentFeedback = 20
|
||||
EncoderSine = 21
|
||||
EncoderCosine = 22
|
||||
AnalogInput2 = 23
|
||||
AnalogInput3 = 24
|
||||
FrequencyResponseBefore = 25
|
||||
FrequencyResponseAfter = 26
|
||||
AnalogOutput0 = 31
|
||||
AnalogOutput1 = 32
|
||||
AnalogOutput2 = 33
|
||||
AnalogOutput3 = 34
|
||||
DriveMemoryInt32 = 35
|
||||
DriveMemoryFloat = 36
|
||||
DriveMemoryDouble = 37
|
||||
PsoStatus = 38
|
||||
DriveTimerDebug = 39
|
||||
PositionFeedbackDrive = 77
|
||||
PositionCommandDrive = 84
|
||||
DriveMemoryInt16 = 125
|
||||
DriveMemoryInt8 = 126
|
||||
PsoCounter0 = 171
|
||||
PsoCounter1 = 172
|
||||
PsoCounter2 = 173
|
||||
PsoWindow0 = 174
|
||||
PsoWindow1 = 175
|
||||
DriveDataCaptureSamples = 176
|
||||
PositionCommandGalvo = 178
|
||||
PrimaryEnDatAbsolutePosition = 197
|
||||
ControlEffort = 201
|
||||
PhaseAVoltageCommand = 208
|
||||
PhaseBVoltageCommand = 209
|
||||
PhaseCVoltageCommand = 210
|
||||
AmplifierPeakCurrent = 211
|
||||
FpgaVersion = 212
|
||||
DriveTypeId = 213
|
||||
PsoWindow0ArrayIndex = 214
|
||||
PsoWindow1ArrayIndex = 215
|
||||
PsoDistanceArrayIndex = 216
|
||||
AmplifierTemperature = 217
|
||||
PsoBitArrayIndex = 218
|
||||
MxAbsolutePosition = 219
|
||||
ServoUpdateRate = 220
|
||||
SettlingTime = 221
|
||||
InternalStatusCode = 222
|
||||
FirmwareVersionMajor = 223
|
||||
FirmwareVersionMinor = 224
|
||||
FirmwareVersionPatch = 225
|
||||
FirmwareVersionBuild = 226
|
||||
DriveTimerDebugMax = 227
|
||||
MarkerSearchDistance = 228
|
||||
PositionFeedbackGalvo = 234
|
||||
LatchedMarkerPosition = 236
|
||||
PrimaryBissAbsolutePosition = 255
|
||||
FaultPositionFeedback = 258
|
||||
MotorCommutationAngle = 259
|
||||
ExpansionBoardOption = 260
|
||||
BusVoltage = 261
|
||||
PiezoVoltageCommand = 262
|
||||
PiezoVoltageFeedback = 263
|
||||
TimeSinceReset = 273
|
||||
MaximumVoltage = 274
|
||||
CommandOutputType = 275
|
||||
DriveFeedforwardOutput = 290
|
||||
LastTickCounter = 291
|
||||
BoardRevision = 292
|
||||
GalvoLaserOutput = 294
|
||||
GalvoLaserPowerCorrectionOutput = 299
|
||||
CapacitanceSensorRawPosition = 300
|
||||
PositionCalibrationGalvo = 304
|
||||
BusVoltageNegative = 325
|
||||
ProcessorTemperature = 326
|
||||
InternalStatusTimestamp = 328
|
||||
AnalogSensorInput = 329
|
||||
MotorTemperature = 330
|
||||
PrimaryBissStatus = 332
|
||||
PsoExternalSyncFrequency = 337
|
||||
EncoderSineRaw = 346
|
||||
EncoderCosineRaw = 347
|
||||
FpgaTemperature = 353
|
||||
PrimaryEnDatStatus = 355
|
||||
DriveTimerHighPriorityThread = 356
|
||||
DriveTimerLowPriorityThread = 357
|
||||
DriveTimerLowPriorityPacket = 358
|
||||
DriveTimerServoPacket = 359
|
||||
DriveTimerServoThread = 360
|
||||
DriveTimerCurrentPacket = 361
|
||||
DriveTimerCommonCoreThread = 362
|
||||
DriveTimerServoCorePacket0 = 363
|
||||
DriveTimerServoCorePacket1 = 364
|
||||
MultiplierOption = 365
|
||||
ServoLoopFeedbackInput0 = 367
|
||||
ServoLoopFeedbackInput1 = 368
|
||||
FaultSubcode = 376
|
||||
ProcessorTemperatureMax = 378
|
||||
DriveTimerHyperWireDma = 381
|
||||
AmplifierTemperatureMax = 382
|
||||
AuxiliaryEnDatAbsolutePosition = 383
|
||||
AuxiliaryEnDatStatus = 384
|
||||
AuxiliaryBissAbsolutePosition = 385
|
||||
AuxiliaryBissStatus = 386
|
||||
PsoOption = 387
|
||||
DriveArraySize = 388
|
||||
RatedMotorSupplyVoltageOption = 389
|
||||
AbsoluteEncoderOption = 391
|
||||
AuxiliaryFeedbackStatus = 393
|
||||
AmplifierStatus = 394
|
||||
LatchedCwLimitPosition = 395
|
||||
LatchedCcwLimitPosition = 396
|
||||
GalvoLaserFpgaTransitionDelay = 397
|
||||
PiezoAccumulatedCharge = 401
|
||||
PiezoChargingTime = 402
|
||||
PrimarySsiAbsolutePosition = 403
|
||||
PrimarySsiStatus = 404
|
||||
AuxiliarySsiAbsolutePosition = 405
|
||||
AuxiliarySsiStatus = 406
|
||||
PsoDistanceActiveDistance = 407
|
||||
PsoWindow0ActiveLowerBound = 408
|
||||
PsoWindow0ActiveUpperBound = 409
|
||||
PsoWindow1ActiveLowerBound = 410
|
||||
PsoWindow1ActiveUpperBound = 411
|
||||
PsoWaveformActiveTotalTime = 412
|
||||
PsoWaveformActiveOnTime = 413
|
||||
PsoWaveformActivePulseCount = 414
|
||||
PsoEventActiveBitValue = 415
|
||||
DriveTimerDriveBasedControllerOutputDma = 419
|
||||
DriveTimerPcieInboundFsm = 420
|
||||
PrimaryFeedbackServo = 425
|
||||
AuxiliaryFeedbackServo = 426
|
||||
DriveStackUsage = 427
|
||||
ShuntResistorTemperature = 436
|
||||
|
||||
|
||||
class TaskDataSignal:
|
||||
ProgramLineNumber = 17
|
||||
CoordinatedFlags = 40
|
||||
CoordinatedArcStartAngle = 53
|
||||
CoordinatedArcEndAngle = 54
|
||||
CoordinatedArcRadius = 55
|
||||
CoordinatedArcRadiusError = 56
|
||||
CoordinatedPositionCommand = 57
|
||||
CoordinatedSpeedCommand = 58
|
||||
CoordinatedAccelerationCommand = 59
|
||||
CoordinatedTotalDistance = 60
|
||||
CoordinatedPercentDone = 61
|
||||
CoordinatedPositionCommandBackwardsDiff = 62
|
||||
TaskParameter = 69
|
||||
TaskError = 70
|
||||
TaskWarning = 71
|
||||
CoordinatedSpeedTargetActual = 86
|
||||
DependentCoordinatedSpeedTargetActual = 87
|
||||
ActiveFixtureOffset = 88
|
||||
TaskStatus0 = 90
|
||||
TaskStatus1 = 91
|
||||
TaskStatus2 = 92
|
||||
SpindleSpeedTarget = 93
|
||||
CoordinateSystem1I = 96
|
||||
CoordinateSystem1J = 97
|
||||
CoordinateSystem1K = 98
|
||||
CoordinateSystem1Plane = 99
|
||||
ToolNumberActive = 100
|
||||
Mfo = 101
|
||||
CoordinatedSpeedTarget = 102
|
||||
DependentCoordinatedSpeedTarget = 103
|
||||
CoordinatedAccelerationRate = 104
|
||||
CoordinatedDecelerationRate = 105
|
||||
CoordinatedAccelerationTime = 106
|
||||
CoordinatedDecelerationTime = 107
|
||||
TaskMode = 108
|
||||
TaskState = 117
|
||||
TaskStateInternal = 118
|
||||
ExecutionMode = 121
|
||||
EnableAlignmentAxes = 127
|
||||
CoordinatedGalvoLaserOutput = 133
|
||||
CoordinatedMotionRate = 145
|
||||
CoordinatedTaskCommand = 146
|
||||
EnableState = 166
|
||||
LookaheadMovesExamined = 200
|
||||
ProfileControlMask = 231
|
||||
CoordinatedArcRadiusReciprocal = 253
|
||||
MotionEngineStage = 254
|
||||
CoordinatedTimeScale = 256
|
||||
CoordinatedTimeScaleDerivative = 257
|
||||
IfovSpeedScale = 266
|
||||
IfovSpeedScaleAverage = 267
|
||||
IfovGenerationFrameCounter = 268
|
||||
IfovGenerationTimeOriginal = 269
|
||||
IfovGenerationTimeModified = 270
|
||||
IfovCoordinatedPositionCommand = 271
|
||||
IfovCoordinatedSpeedCommand = 272
|
||||
IfovCenterPointH = 276
|
||||
IfovCenterPointV = 277
|
||||
IfovTrajectoryCount = 278
|
||||
IfovTrajectoryIndex = 279
|
||||
IfovAttemptCode = 280
|
||||
IfovGenerationFrameIndex = 281
|
||||
IfovMaximumVelocity = 282
|
||||
IfovIdealVelocity = 283
|
||||
TaskInternalDebug = 284
|
||||
IfovCoordinatedAccelerationCommand = 285
|
||||
IfovFovPositionH = 286
|
||||
IfovFovPositionV = 287
|
||||
IfovFovDimensionH = 288
|
||||
IfovFovDimensionV = 289
|
||||
MotionBufferElements = 311
|
||||
MotionBufferMoves = 312
|
||||
MotionLineNumber = 313
|
||||
MotionBufferRetraceMoves = 314
|
||||
MotionBufferRetraceElements = 315
|
||||
MotionBufferIndex = 316
|
||||
MotionBufferIndexLookahead = 317
|
||||
MotionBufferProcessingBlocked = 318
|
||||
ActiveMoveValid = 319
|
||||
TaskExecutionLines = 320
|
||||
SchedulerTaskHolds = 321
|
||||
SchedulerProgramLoopRuns = 322
|
||||
SchedulerTaskBlocked = 323
|
||||
CriticalSectionsActive = 324
|
||||
AxesSlowdownReason = 331
|
||||
TaskExecutionTime = 333
|
||||
TaskExecutionTimeMaximum = 334
|
||||
TaskExecutionLinesMaximum = 335
|
||||
LookaheadDecelReason = 338
|
||||
LookaheadDecelMoves = 339
|
||||
LookaheadDecelDistance = 340
|
||||
ProgramCounter = 341
|
||||
StackPointer = 342
|
||||
FramePointer = 343
|
||||
StringStackPointer = 344
|
||||
ProgramLineNumberSourceFileId = 349
|
||||
MotionLineNumberSourceFileId = 350
|
||||
ProgramLineNumberSourcePathId = 351
|
||||
MotionLineNumberSourcePathId = 352
|
||||
StringArgumentStackPointer = 354
|
||||
CoordinatedAccelerationSCurvePercentage = 369
|
||||
CoordinatedDecelerationSCurvePercentage = 370
|
||||
DependentCoordinatedAccelerationRate = 373
|
||||
DependentCoordinatedDecelerationRate = 374
|
||||
CriticalSectionTimeout = 375
|
||||
CommandQueueCapacity = 421
|
||||
CommandQueueUnexecutedCount = 422
|
||||
CommandQueueTimesEmptied = 423
|
||||
CommandQueueExecutedCount = 424
|
||||
|
||||
|
||||
class SystemDataSignal:
|
||||
VirtualBinaryInput = 46
|
||||
VirtualBinaryOutput = 47
|
||||
VirtualRegisterInput = 48
|
||||
VirtualRegisterOutput = 49
|
||||
Timer = 51
|
||||
TimerPerformance = 52
|
||||
GlobalReal = 67
|
||||
CommunicationRealTimeErrors = 81
|
||||
LibraryCommand = 119
|
||||
DataCollectionSampleTime = 120
|
||||
DataCollectionSampleIndex = 129
|
||||
ModbusClientConnected = 134
|
||||
ModbusServerConnected = 135
|
||||
ModbusClientError = 136
|
||||
ModbusServerError = 137
|
||||
StopWatchTimer = 157
|
||||
ScopetrigId = 163
|
||||
EstimatedProcessorUsage = 177
|
||||
DataCollectionStatus = 188
|
||||
SignalLogState = 198
|
||||
SafeZoneViolationMask = 207
|
||||
SafeZoneActiveMask = 229
|
||||
ModbusClientInputWords = 240
|
||||
ModbusClientOutputWords = 241
|
||||
ModbusClientInputBits = 242
|
||||
ModbusClientOutputBits = 243
|
||||
ModbusClientOutputBitsStatus = 244
|
||||
ModbusClientOutputWordsStatus = 245
|
||||
ModbusServerInputWords = 246
|
||||
ModbusServerOutputWords = 247
|
||||
ModbusServerInputBits = 248
|
||||
ModbusServerOutputBits = 249
|
||||
SystemParameter = 265
|
||||
ThermoCompSensorTemperature = 305
|
||||
ThermoCompControllingTemperature = 306
|
||||
ThermoCompCompensatingTemperature = 307
|
||||
ThermoCompStatus = 308
|
||||
GlobalInteger = 345
|
||||
AliveAxesMask = 348
|
||||
SignalLogPointsStored = 377
|
||||
ControllerInitializationWarning = 379
|
||||
StopWatchTimerMin = 416
|
||||
StopWatchTimerMax = 417
|
||||
StopWatchTimerAvg = 418
|
||||
EthercatEnabled = 428
|
||||
EthercatError = 429
|
||||
EthercatTxPdo = 430
|
||||
EthercatTxPdoSize = 431
|
||||
EthercatRxPdo = 432
|
||||
EthercatRxPdoSize = 433
|
||||
EthercatState = 437
|
||||
ModbusClientEnabled = 438
|
||||
ModbusServerEnabled = 439
|
||||
|
||||
|
||||
class DataCollectionFrequency:
|
||||
Undefined = 0
|
||||
Fixed1kHz = 1
|
||||
Fixed10kHz = 2
|
||||
Fixed20kHz = 3
|
||||
Fixed100kHz = 4
|
||||
Fixed200kHz = 5
|
||||
|
||||
|
||||
class DataCollectionMode:
|
||||
Snapshot = 0
|
||||
Continouous = 1
|
||||
|
||||
|
||||
# Specifies the PSO distance input settings for the XC4e drive.
|
||||
class PsoDistanceInput:
|
||||
XC4PrimaryFeedback = 130
|
||||
XC4AuxiliaryFeedback = 131
|
||||
XC4SyncPortA = 132
|
||||
XC4SyncPortB = 133
|
||||
XC4DrivePulseStream = 134
|
||||
XC4ePrimaryFeedback = 135
|
||||
XC4eAuxiliaryFeedback = 136
|
||||
XC4eSyncPortA = 137
|
||||
XC4eSyncPortB = 138
|
||||
XC4eDrivePulseStream = 139
|
||||
|
||||
|
||||
class PsoWindowInput:
|
||||
XC4PrimaryFeedback = 130
|
||||
XC4AuxiliaryFeedback = 131
|
||||
XC4SyncPortA = 132
|
||||
XC4SyncPortB = 133
|
||||
XC4DrivePulseStream = 134
|
||||
XC4ePrimaryFeedback = 135
|
||||
XC4eAuxiliaryFeedback = 136
|
||||
XC4eSyncPortA = 137
|
||||
XC4eSyncPortB = 138
|
||||
XC4eDrivePulseStream = 139
|
||||
XL5ePrimaryFeedback = (145,)
|
||||
XL5eAuxiliaryFeedback = (146,)
|
||||
XL5eSyncPortA = (147,)
|
||||
XL5eSyncPortB = (148,)
|
||||
XL5eDrivePulseStream = (149,)
|
||||
|
||||
|
||||
# @brief Specifies the PSO output pin settings for each drive.
|
||||
class XC4ePsoOutputPin:
|
||||
DedicatedOutput = 111
|
||||
AuxiliaryMarkerDifferential = 112
|
||||
AuxiliaryMarkerSingleEnded = 113
|
||||
|
||||
|
||||
class XC4PsoOutputPin:
|
||||
DedicatedOutput = 108
|
||||
AuxiliaryMarkerDifferential = 109
|
||||
AuxiliaryMarkerSingleEnded = 110
|
||||
|
||||
|
||||
"""
|
||||
# @brief Specifies the PSO distance input settings for each drive.
|
||||
class Automation1PsoDistanceInput:
|
||||
Automation1PsoDistanceInput_GL4PrimaryFeedbackAxis1 = 100,
|
||||
Automation1PsoDistanceInput_GL4PrimaryFeedbackAxis2 = 101,
|
||||
Automation1PsoDistanceInput_GL4IfovFeedbackAxis1 = 102,
|
||||
Automation1PsoDistanceInput_GL4IfovFeedbackAxis2 = 103,
|
||||
Automation1PsoDistanceInput_GL4AuxiliaryFeedbackAxis1 = 104,
|
||||
Automation1PsoDistanceInput_GL4AuxiliaryFeedbackAxis2 = 105,
|
||||
Automation1PsoDistanceInput_GL4SyncPortA = 106,
|
||||
Automation1PsoDistanceInput_GL4SyncPortB = 107,
|
||||
Automation1PsoDistanceInput_GL4DrivePulseStreamAxis1 = 108,
|
||||
Automation1PsoDistanceInput_GL4DrivePulseStreamAxis2 = 109,
|
||||
Automation1PsoDistanceInput_XL4sPrimaryFeedback = 110,
|
||||
Automation1PsoDistanceInput_XL4sAuxiliaryFeedback = 111,
|
||||
Automation1PsoDistanceInput_XL4sSyncPortA = 112,
|
||||
Automation1PsoDistanceInput_XL4sSyncPortB = 113,
|
||||
Automation1PsoDistanceInput_XL4sDrivePulseStream = 114,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis1 = 115,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis2 = 116,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis3 = 117,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis4 = 118,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis5 = 119,
|
||||
Automation1PsoDistanceInput_XR3PrimaryFeedbackAxis6 = 120,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis1 = 121,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis2 = 122,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis3 = 123,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis4 = 124,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis5 = 125,
|
||||
Automation1PsoDistanceInput_XR3AuxiliaryFeedbackAxis6 = 126,
|
||||
Automation1PsoDistanceInput_XR3SyncPortA = 127,
|
||||
Automation1PsoDistanceInput_XR3SyncPortB = 128,
|
||||
Automation1PsoDistanceInput_XR3DrivePulseStream = 129,
|
||||
Automation1PsoDistanceInput_XC4PrimaryFeedback = 130,
|
||||
Automation1PsoDistanceInput_XC4AuxiliaryFeedback = 131,
|
||||
Automation1PsoDistanceInput_XC4SyncPortA = 132,
|
||||
Automation1PsoDistanceInput_XC4SyncPortB = 133,
|
||||
Automation1PsoDistanceInput_XC4DrivePulseStream = 134,
|
||||
XC4ePrimaryFeedback = 135,
|
||||
XC4eAuxiliaryFeedback = 136,
|
||||
XC4eSyncPortA = 137,
|
||||
XC4eSyncPortB = 138,
|
||||
XC4eDrivePulseStream = 139,
|
||||
Automation1PsoDistanceInput_XC6ePrimaryFeedback = 140,
|
||||
Automation1PsoDistanceInput_XC6eAuxiliaryFeedback = 141,
|
||||
Automation1PsoDistanceInput_XC6eSyncPortA = 142,
|
||||
Automation1PsoDistanceInput_XC6eSyncPortB = 143,
|
||||
Automation1PsoDistanceInput_XC6eDrivePulseStream = 144,
|
||||
Automation1PsoDistanceInput_XL5ePrimaryFeedback = 145,
|
||||
Automation1PsoDistanceInput_XL5eAuxiliaryFeedback = 146,
|
||||
Automation1PsoDistanceInput_XL5eSyncPortA = 147,
|
||||
Automation1PsoDistanceInput_XL5eSyncPortB = 148,
|
||||
Automation1PsoDistanceInput_XL5eDrivePulseStream = 149,
|
||||
Automation1PsoDistanceInput_XC2PrimaryFeedback = 150,
|
||||
Automation1PsoDistanceInput_XC2AuxiliaryFeedback = 151,
|
||||
Automation1PsoDistanceInput_XC2DrivePulseStream = 152,
|
||||
Automation1PsoDistanceInput_XC2ePrimaryFeedback = 153,
|
||||
Automation1PsoDistanceInput_XC2eAuxiliaryFeedback = 154,
|
||||
Automation1PsoDistanceInput_XC2eDrivePulseStream = 155,
|
||||
Automation1PsoDistanceInput_XL2ePrimaryFeedback = 156,
|
||||
Automation1PsoDistanceInput_XL2eAuxiliaryFeedback = 157,
|
||||
Automation1PsoDistanceInput_XL2eSyncPortA = 158,
|
||||
Automation1PsoDistanceInput_XL2eSyncPortB = 159,
|
||||
Automation1PsoDistanceInput_XL2eDrivePulseStream = 160,
|
||||
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis1 = 161,
|
||||
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis2 = 162,
|
||||
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis3 = 163,
|
||||
Automation1PsoDistanceInput_XI4PrimaryFeedbackAxis4 = 164,
|
||||
Automation1PsoDistanceInput_XI4AuxiliaryFeedback1 = 165,
|
||||
Automation1PsoDistanceInput_XI4AuxiliaryFeedback2 = 166,
|
||||
Automation1PsoDistanceInput_XI4AuxiliaryFeedback3 = 167,
|
||||
Automation1PsoDistanceInput_XI4AuxiliaryFeedback4 = 168,
|
||||
Automation1PsoDistanceInput_XI4SyncPortA = 169,
|
||||
Automation1PsoDistanceInput_XI4SyncPortB = 170,
|
||||
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis1 = 171,
|
||||
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis2 = 172,
|
||||
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis3 = 173,
|
||||
Automation1PsoDistanceInput_XI4DrivePulseStreamAxis4 = 174,
|
||||
Automation1PsoDistanceInput_iXC4PrimaryFeedback = 175,
|
||||
Automation1PsoDistanceInput_iXC4AuxiliaryFeedback = 176,
|
||||
Automation1PsoDistanceInput_iXC4SyncPortA = 177,
|
||||
Automation1PsoDistanceInput_iXC4SyncPortB = 178,
|
||||
Automation1PsoDistanceInput_iXC4DrivePulseStream = 179,
|
||||
Automation1PsoDistanceInput_iXC4ePrimaryFeedback = 180,
|
||||
Automation1PsoDistanceInput_iXC4eAuxiliaryFeedback = 181,
|
||||
Automation1PsoDistanceInput_iXC4eSyncPortA = 182,
|
||||
Automation1PsoDistanceInput_iXC4eSyncPortB = 183,
|
||||
Automation1PsoDistanceInput_iXC4eDrivePulseStream = 184,
|
||||
Automation1PsoDistanceInput_iXC6ePrimaryFeedback = 185,
|
||||
Automation1PsoDistanceInput_iXC6eAuxiliaryFeedback = 186,
|
||||
Automation1PsoDistanceInput_iXC6eSyncPortA = 187,
|
||||
Automation1PsoDistanceInput_iXC6eSyncPortB = 188,
|
||||
Automation1PsoDistanceInput_iXC6eDrivePulseStream = 189,
|
||||
Automation1PsoDistanceInput_iXL5ePrimaryFeedback = 190,
|
||||
Automation1PsoDistanceInput_iXL5eAuxiliaryFeedback = 191,
|
||||
Automation1PsoDistanceInput_iXL5eSyncPortA = 192,
|
||||
Automation1PsoDistanceInput_iXL5eSyncPortB = 193,
|
||||
Automation1PsoDistanceInput_iXL5eDrivePulseStream = 194,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis1 = 195,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis2 = 196,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis3 = 197,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis4 = 198,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis5 = 199,
|
||||
Automation1PsoDistanceInput_iXR3PrimaryFeedbackAxis6 = 200,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis1 = 201,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis2 = 202,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis3 = 203,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis4 = 204,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis5 = 205,
|
||||
Automation1PsoDistanceInput_iXR3AuxiliaryFeedbackAxis6 = 206,
|
||||
Automation1PsoDistanceInput_iXR3SyncPortA = 207,
|
||||
Automation1PsoDistanceInput_iXR3SyncPortB = 208,
|
||||
Automation1PsoDistanceInput_iXR3DrivePulseStream = 209,
|
||||
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis1 = 210,
|
||||
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis2 = 211,
|
||||
Automation1PsoDistanceInput_GI4DrivePulseStreamAxis3 = 212,
|
||||
Automation1PsoDistanceInput_iXC2PrimaryFeedback = 213,
|
||||
Automation1PsoDistanceInput_iXC2AuxiliaryFeedback = 214,
|
||||
Automation1PsoDistanceInput_iXC2DrivePulseStream = 215,
|
||||
Automation1PsoDistanceInput_iXC2ePrimaryFeedback = 216,
|
||||
Automation1PsoDistanceInput_iXC2eAuxiliaryFeedback = 217,
|
||||
Automation1PsoDistanceInput_iXC2eDrivePulseStream = 218,
|
||||
Automation1PsoDistanceInput_iXL2ePrimaryFeedback = 219,
|
||||
Automation1PsoDistanceInput_iXL2eAuxiliaryFeedback = 220,
|
||||
Automation1PsoDistanceInput_iXL2eSyncPortA = 221,
|
||||
Automation1PsoDistanceInput_iXL2eSyncPortB = 222,
|
||||
Automation1PsoDistanceInput_iXL2eDrivePulseStream = 223,
|
||||
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis1 = 224,
|
||||
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis2 = 225,
|
||||
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis3 = 226,
|
||||
Automation1PsoDistanceInput_iXI4PrimaryFeedbackAxis4 = 227,
|
||||
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback1 = 228,
|
||||
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback2 = 229,
|
||||
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback3 = 230,
|
||||
Automation1PsoDistanceInput_iXI4AuxiliaryFeedback4 = 231,
|
||||
Automation1PsoDistanceInput_iXI4SyncPortA = 232,
|
||||
Automation1PsoDistanceInput_iXI4SyncPortB = 233,
|
||||
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis1 = 234,
|
||||
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis2 = 235,
|
||||
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis3 = 236,
|
||||
Automation1PsoDistanceInput_iXI4DrivePulseStreamAxis4 = 237,
|
||||
|
||||
# @brief Specifies the PSO window input settings for each drive.
|
||||
class Automation1PsoWindowInput:
|
||||
Automation1PsoWindowInput_GL4PrimaryFeedbackAxis1 = 100,
|
||||
Automation1PsoWindowInput_GL4PrimaryFeedbackAxis2 = 101,
|
||||
Automation1PsoWindowInput_GL4IfovFeedbackAxis1 = 102,
|
||||
Automation1PsoWindowInput_GL4IfovFeedbackAxis2 = 103,
|
||||
Automation1PsoWindowInput_GL4AuxiliaryFeedbackAxis1 = 104,
|
||||
Automation1PsoWindowInput_GL4AuxiliaryFeedbackAxis2 = 105,
|
||||
Automation1PsoWindowInput_GL4SyncPortA = 106,
|
||||
Automation1PsoWindowInput_GL4SyncPortB = 107,
|
||||
Automation1PsoWindowInput_GL4DrivePulseStreamAxis1 = 108,
|
||||
Automation1PsoWindowInput_GL4DrivePulseStreamAxis2 = 109,
|
||||
Automation1PsoWindowInput_XL4sPrimaryFeedback = 110,
|
||||
Automation1PsoWindowInput_XL4sAuxiliaryFeedback = 111,
|
||||
Automation1PsoWindowInput_XL4sSyncPortA = 112,
|
||||
Automation1PsoWindowInput_XL4sSyncPortB = 113,
|
||||
Automation1PsoWindowInput_XL4sDrivePulseStream = 114,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis1 = 115,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis2 = 116,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis3 = 117,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis4 = 118,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis5 = 119,
|
||||
Automation1PsoWindowInput_XR3PrimaryFeedbackAxis6 = 120,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis1 = 121,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis2 = 122,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis3 = 123,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis4 = 124,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis5 = 125,
|
||||
Automation1PsoWindowInput_XR3AuxiliaryFeedbackAxis6 = 126,
|
||||
Automation1PsoWindowInput_XR3SyncPortA = 127,
|
||||
Automation1PsoWindowInput_XR3SyncPortB = 128,
|
||||
Automation1PsoWindowInput_XR3DrivePulseStream = 129,
|
||||
Automation1PsoWindowInput_XC4PrimaryFeedback = 130,
|
||||
Automation1PsoWindowInput_XC4AuxiliaryFeedback = 131,
|
||||
Automation1PsoWindowInput_XC4SyncPortA = 132,
|
||||
Automation1PsoWindowInput_XC4SyncPortB = 133,
|
||||
Automation1PsoWindowInput_XC4DrivePulseStream = 134,
|
||||
XC4ePrimaryFeedback = 135,
|
||||
XC4eAuxiliaryFeedback = 136,
|
||||
XC4eSyncPortA = 137,
|
||||
XC4eSyncPortB = 138,
|
||||
XC4eDrivePulseStream = 139,
|
||||
Automation1PsoWindowInput_XC6ePrimaryFeedback = 140,
|
||||
Automation1PsoWindowInput_XC6eAuxiliaryFeedback = 141,
|
||||
Automation1PsoWindowInput_XC6eSyncPortA = 142,
|
||||
Automation1PsoWindowInput_XC6eSyncPortB = 143,
|
||||
Automation1PsoWindowInput_XC6eDrivePulseStream = 144,
|
||||
Automation1PsoWindowInput_XL5ePrimaryFeedback = 145,
|
||||
Automation1PsoWindowInput_XL5eAuxiliaryFeedback = 146,
|
||||
Automation1PsoWindowInput_XL5eSyncPortA = 147,
|
||||
Automation1PsoWindowInput_XL5eSyncPortB = 148,
|
||||
Automation1PsoWindowInput_XL5eDrivePulseStream = 149,
|
||||
Automation1PsoWindowInput_XC2PrimaryFeedback = 150,
|
||||
Automation1PsoWindowInput_XC2AuxiliaryFeedback = 151,
|
||||
Automation1PsoWindowInput_XC2DrivePulseStream = 152,
|
||||
Automation1PsoWindowInput_XC2ePrimaryFeedback = 153,
|
||||
Automation1PsoWindowInput_XC2eAuxiliaryFeedback = 154,
|
||||
Automation1PsoWindowInput_XC2eDrivePulseStream = 155,
|
||||
Automation1PsoWindowInput_XL2ePrimaryFeedback = 156,
|
||||
Automation1PsoWindowInput_XL2eAuxiliaryFeedback = 157,
|
||||
Automation1PsoWindowInput_XL2eSyncPortA = 158,
|
||||
Automation1PsoWindowInput_XL2eSyncPortB = 159,
|
||||
Automation1PsoWindowInput_XL2eDrivePulseStream = 160,
|
||||
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis1 = 161,
|
||||
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis2 = 162,
|
||||
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis3 = 163,
|
||||
Automation1PsoWindowInput_XI4PrimaryFeedbackAxis4 = 164,
|
||||
Automation1PsoWindowInput_XI4AuxiliaryFeedback1 = 165,
|
||||
Automation1PsoWindowInput_XI4AuxiliaryFeedback2 = 166,
|
||||
Automation1PsoWindowInput_XI4AuxiliaryFeedback3 = 167,
|
||||
Automation1PsoWindowInput_XI4AuxiliaryFeedback4 = 168,
|
||||
Automation1PsoWindowInput_XI4SyncPortA = 169,
|
||||
Automation1PsoWindowInput_XI4SyncPortB = 170,
|
||||
Automation1PsoWindowInput_XI4DrivePulseStreamAxis1 = 171,
|
||||
Automation1PsoWindowInput_XI4DrivePulseStreamAxis2 = 172,
|
||||
Automation1PsoWindowInput_XI4DrivePulseStreamAxis3 = 173,
|
||||
Automation1PsoWindowInput_XI4DrivePulseStreamAxis4 = 174,
|
||||
Automation1PsoWindowInput_iXC4PrimaryFeedback = 175,
|
||||
Automation1PsoWindowInput_iXC4AuxiliaryFeedback = 176,
|
||||
Automation1PsoWindowInput_iXC4SyncPortA = 177,
|
||||
Automation1PsoWindowInput_iXC4SyncPortB = 178,
|
||||
Automation1PsoWindowInput_iXC4DrivePulseStream = 179,
|
||||
Automation1PsoWindowInput_iXC4ePrimaryFeedback = 180,
|
||||
Automation1PsoWindowInput_iXC4eAuxiliaryFeedback = 181,
|
||||
Automation1PsoWindowInput_iXC4eSyncPortA = 182,
|
||||
Automation1PsoWindowInput_iXC4eSyncPortB = 183,
|
||||
Automation1PsoWindowInput_iXC4eDrivePulseStream = 184,
|
||||
Automation1PsoWindowInput_iXC6ePrimaryFeedback = 185,
|
||||
Automation1PsoWindowInput_iXC6eAuxiliaryFeedback = 186,
|
||||
Automation1PsoWindowInput_iXC6eSyncPortA = 187,
|
||||
Automation1PsoWindowInput_iXC6eSyncPortB = 188,
|
||||
Automation1PsoWindowInput_iXC6eDrivePulseStream = 189,
|
||||
Automation1PsoWindowInput_iXL5ePrimaryFeedback = 190,
|
||||
Automation1PsoWindowInput_iXL5eAuxiliaryFeedback = 191,
|
||||
Automation1PsoWindowInput_iXL5eSyncPortA = 192,
|
||||
Automation1PsoWindowInput_iXL5eSyncPortB = 193,
|
||||
Automation1PsoWindowInput_iXL5eDrivePulseStream = 194,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis1 = 195,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis2 = 196,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis3 = 197,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis4 = 198,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis5 = 199,
|
||||
Automation1PsoWindowInput_iXR3PrimaryFeedbackAxis6 = 200,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis1 = 201,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis2 = 202,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis3 = 203,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis4 = 204,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis5 = 205,
|
||||
Automation1PsoWindowInput_iXR3AuxiliaryFeedbackAxis6 = 206,
|
||||
Automation1PsoWindowInput_iXR3SyncPortA = 207,
|
||||
Automation1PsoWindowInput_iXR3SyncPortB = 208,
|
||||
Automation1PsoWindowInput_iXR3DrivePulseStream = 209,
|
||||
Automation1PsoWindowInput_GI4DrivePulseStreamAxis1 = 210,
|
||||
Automation1PsoWindowInput_GI4DrivePulseStreamAxis2 = 211,
|
||||
Automation1PsoWindowInput_GI4DrivePulseStreamAxis3 = 212,
|
||||
Automation1PsoWindowInput_iXC2PrimaryFeedback = 213,
|
||||
Automation1PsoWindowInput_iXC2AuxiliaryFeedback = 214,
|
||||
Automation1PsoWindowInput_iXC2DrivePulseStream = 215,
|
||||
Automation1PsoWindowInput_iXC2ePrimaryFeedback = 216,
|
||||
Automation1PsoWindowInput_iXC2eAuxiliaryFeedback = 217,
|
||||
Automation1PsoWindowInput_iXC2eDrivePulseStream = 218,
|
||||
Automation1PsoWindowInput_iXL2ePrimaryFeedback = 219,
|
||||
Automation1PsoWindowInput_iXL2eAuxiliaryFeedback = 220,
|
||||
Automation1PsoWindowInput_iXL2eSyncPortA = 221,
|
||||
Automation1PsoWindowInput_iXL2eSyncPortB = 222,
|
||||
Automation1PsoWindowInput_iXL2eDrivePulseStream = 223,
|
||||
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis1 = 224,
|
||||
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis2 = 225,
|
||||
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis3 = 226,
|
||||
Automation1PsoWindowInput_iXI4PrimaryFeedbackAxis4 = 227,
|
||||
Automation1PsoWindowInput_iXI4AuxiliaryFeedback1 = 228,
|
||||
Automation1PsoWindowInput_iXI4AuxiliaryFeedback2 = 229,
|
||||
Automation1PsoWindowInput_iXI4AuxiliaryFeedback3 = 230,
|
||||
Automation1PsoWindowInput_iXI4AuxiliaryFeedback4 = 231,
|
||||
Automation1PsoWindowInput_iXI4SyncPortA = 232,
|
||||
Automation1PsoWindowInput_iXI4SyncPortB = 233,
|
||||
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis1 = 234,
|
||||
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis2 = 235,
|
||||
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis3 = 236,
|
||||
Automation1PsoWindowInput_iXI4DrivePulseStreamAxis4 = 237,
|
||||
|
||||
# @brief Specifies the PSO output pin settings for each drive.
|
||||
class Automation1PsoOutputPin:
|
||||
Automation1PsoOutputPin_GL4None = 100,
|
||||
Automation1PsoOutputPin_GL4LaserOutput0 = 101,
|
||||
Automation1PsoOutputPin_XL4sNone = 102,
|
||||
Automation1PsoOutputPin_XL4sLaserOutput0 = 103,
|
||||
Automation1PsoOutputPin_XR3None = 104,
|
||||
Automation1PsoOutputPin_XR3PsoOutput1 = 105,
|
||||
Automation1PsoOutputPin_XR3PsoOutput2 = 106,
|
||||
Automation1PsoOutputPin_XR3PsoOutput3 = 107,
|
||||
Automation1PsoOutputPin_XC4DedicatedOutput = 108,
|
||||
Automation1PsoOutputPin_XC4AuxiliaryMarkerDifferential = 109,
|
||||
Automation1PsoOutputPin_XC4AuxiliaryMarkerSingleEnded = 110,
|
||||
XC4eDedicatedOutput = 111,
|
||||
XC4eAuxiliaryMarkerDifferential = 112,
|
||||
XC4eAuxiliaryMarkerSingleEnded = 113,
|
||||
Automation1PsoOutputPin_XC6eDedicatedOutput = 114,
|
||||
Automation1PsoOutputPin_XC6eAuxiliaryMarkerDifferential = 115,
|
||||
Automation1PsoOutputPin_XC6eAuxiliaryMarkerSingleEnded = 116,
|
||||
Automation1PsoOutputPin_XL5eDedicatedOutput = 117,
|
||||
Automation1PsoOutputPin_XL5eAuxiliaryMarkerDifferential = 118,
|
||||
Automation1PsoOutputPin_XL5eAuxiliaryMarkerSingleEnded = 119,
|
||||
Automation1PsoOutputPin_XC2DedicatedOutput = 120,
|
||||
Automation1PsoOutputPin_XC2eDedicatedOutput = 121,
|
||||
Automation1PsoOutputPin_XL2eDedicatedOutput = 122,
|
||||
Automation1PsoOutputPin_XI4DedicatedOutput = 123,
|
||||
Automation1PsoOutputPin_iXC4DedicatedOutput = 124,
|
||||
Automation1PsoOutputPin_iXC4AuxiliaryMarkerDifferential = 125,
|
||||
Automation1PsoOutputPin_iXC4AuxiliaryMarkerSingleEnded = 126,
|
||||
Automation1PsoOutputPin_iXC4eDedicatedOutput = 127,
|
||||
Automation1PsoOutputPin_iXC4eAuxiliaryMarkerDifferential = 128,
|
||||
Automation1PsoOutputPin_iXC4eAuxiliaryMarkerSingleEnded = 129,
|
||||
Automation1PsoOutputPin_iXC6eDedicatedOutput = 130,
|
||||
Automation1PsoOutputPin_iXC6eAuxiliaryMarkerDifferential = 131,
|
||||
Automation1PsoOutputPin_iXC6eAuxiliaryMarkerSingleEnded = 132,
|
||||
Automation1PsoOutputPin_iXL5eDedicatedOutput = 133,
|
||||
Automation1PsoOutputPin_iXL5eAuxiliaryMarkerDifferential = 134,
|
||||
Automation1PsoOutputPin_iXL5eAuxiliaryMarkerSingleEnded = 135,
|
||||
Automation1PsoOutputPin_iXR3None = 136,
|
||||
Automation1PsoOutputPin_iXR3PsoOutput1 = 137,
|
||||
Automation1PsoOutputPin_iXR3PsoOutput2 = 138,
|
||||
Automation1PsoOutputPin_iXR3PsoOutput3 = 139,
|
||||
Automation1PsoOutputPin_GI4None = 140,
|
||||
Automation1PsoOutputPin_GI4LaserOutput0 = 141,
|
||||
Automation1PsoOutputPin_iXC2eDedicatedOutput = 143,
|
||||
Automation1PsoOutputPin_iXL2eDedicatedOutput = 144,
|
||||
Automation1PsoOutputPin_iXI4DedicatedOutput = 145,
|
||||
"""
|
||||
|
||||
|
||||
class DriveDataCaptureInput:
|
||||
PositionCommand = 0
|
||||
PrimaryFeedback = 1
|
||||
AuxiliaryFeedback = 2
|
||||
AnalogInput0 = 3
|
||||
AnalogInput1 = 4
|
||||
AnalogInput2 = 5
|
||||
AnalogInput3 = 6
|
||||
|
||||
|
||||
class DriveDataCaptureTrigger:
|
||||
PsoOutput = 0
|
||||
PsoEvent = 1
|
||||
HighSpeedInput0RisingEdge = 2
|
||||
HighSpeedInput0FallingEdge = 3
|
||||
HighSpeedInput1RisingEdge = 4
|
||||
HighSpeedInput1FallingEdge = 5
|
||||
AuxiliaryMarkerRisingEdge = 6
|
||||
AuxiliaryMarkerFallingEdge = 7
|
||||
|
||||
|
||||
class PsoOutputPin:
|
||||
GL4None = (100,)
|
||||
GL4LaserOutput0 = (101,)
|
||||
XL4sNone = (102,)
|
||||
XL4sLaserOutput0 = (103,)
|
||||
XR3None = (104,)
|
||||
XR3PsoOutput1 = (105,)
|
||||
XR3PsoOutput2 = (106,)
|
||||
XR3PsoOutput3 = (107,)
|
||||
XC4DedicatedOutput = (108,)
|
||||
XC4AuxiliaryMarkerDifferential = (109,)
|
||||
XC4AuxiliaryMarkerSingleEnded = (110,)
|
||||
XC4eDedicatedOutput = (111,)
|
||||
XC4eAuxiliaryMarkerDifferential = (112,)
|
||||
XC4eAuxiliaryMarkerSingleEnded = (113,)
|
||||
XC6eDedicatedOutput = (114,)
|
||||
XC6eAuxiliaryMarkerDifferential = (115,)
|
||||
XC6eAuxiliaryMarkerSingleEnded = (116,)
|
||||
XL5eDedicatedOutput = (117,)
|
||||
XL5eAuxiliaryMarkerDifferential = (118,)
|
||||
XL5eAuxiliaryMarkerSingleEnded = (119,)
|
||||
XC2DedicatedOutput = (120,)
|
||||
XC2eDedicatedOutput = (121,)
|
||||
XL2eDedicatedOutput = (122,)
|
||||
XI4DedicatedOutput = (123,)
|
||||
iXC4DedicatedOutput = (124,)
|
||||
iXC4AuxiliaryMarkerDifferential = (125,)
|
||||
iXC4AuxiliaryMarkerSingleEnded = (126,)
|
||||
iXC4eDedicatedOutput = (127,)
|
||||
iXC4eAuxiliaryMarkerDifferential = (128,)
|
||||
iXC4eAuxiliaryMarkerSingleEnded = (129,)
|
||||
iXC6eDedicatedOutput = (130,)
|
||||
iXC6eAuxiliaryMarkerDifferential = (131,)
|
||||
iXC6eAuxiliaryMarkerSingleEnded = (132,)
|
||||
iXL5eDedicatedOutput = (133,)
|
||||
iXL5eAuxiliaryMarkerDifferential = (134,)
|
||||
iXL5eAuxiliaryMarkerSingleEnded = (135,)
|
||||
iXR3None = (136,)
|
||||
iXR3PsoOutput1 = (137,)
|
||||
iXR3PsoOutput2 = (138,)
|
||||
iXR3PsoOutput3 = (139,)
|
||||
GI4None = (140,)
|
||||
GI4LaserOutput0 = (141,)
|
||||
iXC2DedicatedOutput = (142,)
|
||||
iXC2eDedicatedOutput = (143,)
|
||||
iXL2eDedicatedOutput = (144,)
|
||||
iXI4DedicatedOutput = (145,)
|
||||
@@ -0,0 +1,140 @@
|
||||
// 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
|
||||
//
|
||||
|
||||
enum ScanType
|
||||
Pos = 0
|
||||
Neg = 1
|
||||
PosNeg = 2
|
||||
NegPos = 3
|
||||
end
|
||||
|
||||
|
||||
program
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// External parameters - USE THEESE
|
||||
var $fStartPosition as real = {{ scan.startpos }}
|
||||
var $fScanRange as real = $fStartPosition + {{ scan.scanrange }}
|
||||
var $iNumRepeat as integer = {{ scan.nrepeat }}
|
||||
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
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Internal parameters - dont use
|
||||
var $axis as axis = ROTY
|
||||
var $ii as integer
|
||||
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
|
||||
|
||||
// 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
|
||||
MoveAbsolute($axis, $fPosStart, $fVelJog)
|
||||
WaitForInPosition($axis)
|
||||
|
||||
// Configure PSO
|
||||
PsoDistanceCounterOff($axis)
|
||||
PsoDistanceEventsOff($axis)
|
||||
PsoWindowConfigureEvents($axis, PsoWindowEventMode.None)
|
||||
PsoWaveformOff($axis)
|
||||
PsoOutputConfigureSource($axis, PsoOutputSource.Waveform)
|
||||
var $iPsoArrayAddr as integer = 0
|
||||
// Simple PSO trigger pattern
|
||||
var $iPsoArrayPos[] as real = [{% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, {{ psoDist }}), {% endfor %} UnitsToCounts($axis, {{ scan.psoBoundsPos[-1] }})]
|
||||
// var $iPsoArrayPos[] as real = [UnitsToCounts($axis, $fAccDistance), {% for psoDist in scan.psoBoundsPos[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
|
||||
// var $iPsoArrayNeg[] as real = [UnitsToCounts($axis, $fAccDistance), {% for psoDist in scan.psoBoundsNeg[:-1] %} UnitsToCounts($axis, psoDist), {% endfor %}]
|
||||
|
||||
DriveArrayWrite($axis, $iPsoArrayPos, $iPsoArrayAddr, length($iPsoArrayPos), DriveArrayType.PsoDistanceEventDistances)
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 0)
|
||||
PsoDistanceEventsOn($axis)
|
||||
|
||||
PsoWaveformConfigureMode($axis, PsoWaveformMode.Toggle)
|
||||
PsoWaveformOn($axis)
|
||||
|
||||
// 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 );
|
||||
|
||||
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 ($iNumRepeat-1)
|
||||
PsoDistanceConfigureArrayDistances($axis, $iPsoArrayAddr, length($iPsoArrayPos), 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
|
||||
end
|
||||
Dwell(0.2)
|
||||
end
|
||||
|
||||
// Directly after scan
|
||||
PsoDistanceCounterOff($axis)
|
||||
DriveDataCaptureOff($axis, 0)
|
||||
DriveDataCaptureOff($axis, 1)
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
0
tomcat_bec/devices/aerotech/__init__.py
Normal file
0
tomcat_bec/devices/aerotech/__init__.py
Normal file
432
tomcat_bec/devices/grashopper_tomcat.py
Normal file
432
tomcat_bec/devices/grashopper_tomcat.py
Normal file
@@ -0,0 +1,432 @@
|
||||
import enum
|
||||
import threading
|
||||
import time as ttime
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
|
||||
# from typing import Any
|
||||
from ophyd import ADComponent as ADCpt
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import Device, EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
|
||||
|
||||
# import numpy as np
|
||||
from ophyd.ophydobj import Kind
|
||||
from ophyd_devices.epics.devices.psi_detector_base import CustomDetectorMixin, PSIDetectorBase
|
||||
|
||||
# os.environ["EPICS_CA_AUTO_ADDR_LIST"] = "No"
|
||||
# os.environ["EPICS_CA_ADDR_LIST"] = "129.129.208.143"
|
||||
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class GrashopperError(Exception):
|
||||
"""Base class for Grashopper detector errors."""
|
||||
|
||||
|
||||
class GrashopperTimeoutError(GrashopperError):
|
||||
"""Base class for Grashopper detector errors."""
|
||||
|
||||
|
||||
class AutoMode(enum.IntEnum):
|
||||
"""Acquire time auto for Grashopper detector.
|
||||
|
||||
class for acquire_auto and gain_auto
|
||||
|
||||
Off: Gain tap balancing is user controlled using Gain.
|
||||
Once: Gain tap balancing is automatically adjusted once by the device.
|
||||
Once it has converged, it automatically returns to the Off state.
|
||||
Continuous: Gain tap balancing is constantly adjusted by the device.
|
||||
"""
|
||||
|
||||
OFF = 0
|
||||
ONCE = 1
|
||||
CONTINUOUS = 2
|
||||
|
||||
|
||||
class ImageMode(enum.IntEnum):
|
||||
"""Image mode for Grashopper detector.
|
||||
|
||||
Single: Acquire a single image, ignores NumImages PV
|
||||
Multiple: Acquire NumImages images
|
||||
Continuous: Acquire images continuously
|
||||
"""
|
||||
|
||||
SINGLE = 0
|
||||
MULTIPLE = 1
|
||||
CONTINUOUS = 2
|
||||
|
||||
|
||||
class DetectorState(enum.IntEnum):
|
||||
"""Detector states for Grashopper detector"""
|
||||
|
||||
IDLE = 0
|
||||
ACQUIRE = 1
|
||||
READOUT = 2
|
||||
CORRECT = 3
|
||||
SAVING = 4
|
||||
ABORTING = 5
|
||||
ERROR = 6
|
||||
WAITING = 7
|
||||
INITIALIZING = 8
|
||||
DISCONNECTED = 9
|
||||
ABORTED = 10
|
||||
|
||||
|
||||
class ImageBinning(enum.IntEnum):
|
||||
"""Image binning for Grashopper detector"""
|
||||
|
||||
X1 = 1
|
||||
X2 = 2
|
||||
X4 = 4
|
||||
|
||||
|
||||
class VideoMode(enum.IntEnum):
|
||||
"""Video mode for Grashopper detector.
|
||||
|
||||
For details, consult EPICs IOC manual.
|
||||
"""
|
||||
|
||||
MODE0 = 0
|
||||
MODE1 = 1
|
||||
MODE2 = 2
|
||||
MODE3 = 3
|
||||
|
||||
|
||||
class PixelFormat(enum.IntEnum):
|
||||
"""Pixel format for Grashopper detector."""
|
||||
|
||||
MONO8 = 0
|
||||
MONO12PACKED = 1
|
||||
MONO12P = 2
|
||||
MONO16 = 3
|
||||
|
||||
|
||||
class COLORMODE(enum.IntEnum):
|
||||
"""Color mode for Grashopper detector.
|
||||
|
||||
Only for readback values from color_mode RO PV.
|
||||
"""
|
||||
|
||||
MONO = 0
|
||||
BAYER = 1
|
||||
RGB1 = 2
|
||||
RGB2 = 3
|
||||
RGB3 = 4
|
||||
YUV444 = 5
|
||||
YUV422 = 6
|
||||
YUV421 = 7
|
||||
|
||||
|
||||
class TriggerSource(enum.IntEnum):
|
||||
"""Trigger signals for Grashopper detector"""
|
||||
|
||||
SOFTWARE = 0
|
||||
LINE0 = 1
|
||||
LINE2 = 2
|
||||
LINE3 = 3
|
||||
|
||||
|
||||
class MemoryPolling(enum.IntEnum):
|
||||
"""Memory polling for Grashopper detector.
|
||||
|
||||
Defines update rate of memory polling for IOC (1s suggested).
|
||||
"""
|
||||
|
||||
PASSIVE = 0
|
||||
EVENT = 1
|
||||
IOINTR = 2
|
||||
SECONDS10 = 3
|
||||
SECONDS5 = 4
|
||||
SECONDS2 = 5
|
||||
SECONDS1 = 6
|
||||
SECONDS05 = 7
|
||||
SECONDS02 = 8
|
||||
SECONDS01 = 9
|
||||
|
||||
|
||||
class GrashopperTOMCATSetup(CustomDetectorMixin):
|
||||
"""Mixin class to setup TOMCAT specific implementations of the detector.
|
||||
|
||||
This class will be called by the custom_prepare_cls attribute of the detector class.
|
||||
"""
|
||||
|
||||
def __init__(self, *_args, parent: Device = None, **_kwargs) -> None:
|
||||
super().__init__(*_args, parent=parent, **_kwargs)
|
||||
|
||||
self.image_shape = (self.parent.cam.image_size_y.get(), self.parent.cam.image_size_x.get())
|
||||
self.monitor_thread = None
|
||||
self.stop_monitor = False
|
||||
self.update_frequency = 1
|
||||
self.low_frame_rate = 80
|
||||
|
||||
def initialize_detector(self) -> None:
|
||||
"""Initialize detector."""
|
||||
self.parent.cam.acquire.put(0)
|
||||
self.parent.cam.acquire_time_auto.put(AutoMode.CONTINUOUS)
|
||||
self.parent.cam.gain_auto.put(AutoMode.CONTINUOUS)
|
||||
self.parent.cam.image_mode.put(ImageMode.MULTIPLE)
|
||||
self.parent.cam.image_binning.put(ImageBinning.X1)
|
||||
self.parent.cam.video_mode.put(VideoMode.MODE0)
|
||||
self.parent.cam.pixel_format.put(PixelFormat.MONO16)
|
||||
self.parent.cam.trigger_source.put(TriggerSource.SOFTWARE)
|
||||
self.parent.cam.memory_polling.put(MemoryPolling.SECONDS1)
|
||||
self.parent.cam.set_image_counter.put(0)
|
||||
|
||||
def initialize_detector_backend(self) -> None:
|
||||
self.parent.image.queue_size.put(5)
|
||||
self.parent.image.array_port.put(self.parent.cam.port_name.get())
|
||||
self.parent.image.enable_cb.put(1)
|
||||
self.parent.image.set_array_counter.put(0)
|
||||
|
||||
def set_exposure_time(self, exposure_time: float) -> None:
|
||||
"""Set the detector framerate.
|
||||
|
||||
Args:
|
||||
framerate (float): Desired framerate in Hz smallest is 87Hz
|
||||
"""
|
||||
framerate = 1 / exposure_time
|
||||
if framerate > self.low_frame_rate:
|
||||
raise GrashopperError(
|
||||
f"Trying to set exposure time to {exposure_time}s, this is below the lowest"
|
||||
f" possible exposure of {1/self.low_frame_rate}s"
|
||||
)
|
||||
self.parent.cam.frame_rate.put(framerate)
|
||||
|
||||
def prepare_detector(self) -> None:
|
||||
"""Prepare detector for acquisition."""
|
||||
self.parent.cam.image_mode.put(ImageMode.MULTIPLE)
|
||||
self.parent.cam.acquire_time_auto.put(AutoMode.CONTINUOUS)
|
||||
self.set_exposure_time(self.parent.scaninfo.exp_time)
|
||||
self.parent.set_trigger(TriggerSource.SOFTWARE)
|
||||
self.parent.cam.set_image_counter.put(0)
|
||||
self.set_acquisition_params()
|
||||
|
||||
def set_acquisition_params(self) -> None:
|
||||
"""Set acquisition parameters for the detector"""
|
||||
|
||||
# Set number of images and frames (frames is for internal burst of detector)
|
||||
self.parent.cam.num_images.put(
|
||||
int(self.parent.scaninfo.num_points * self.parent.scaninfo.frames_per_trigger)
|
||||
)
|
||||
|
||||
def prepare_detector_backend(self) -> None:
|
||||
"""Prepare detector backend for acquisition."""
|
||||
self.parent.image.set_array_counter.put(0)
|
||||
self.monitor_thread = None
|
||||
self.stop_monitor = False
|
||||
# self.run_monitor()
|
||||
|
||||
def arm_acquisition(self) -> None:
|
||||
"""Arm grashopper detector for acquisition"""
|
||||
self.parent.cam.acquire.put(1)
|
||||
signal_conditions = [(self.parent.cam.detector_state.get, DetectorState.WAITING)]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.timeout,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
raise GrashopperTimeoutError(
|
||||
f"Failed to arm the acquisition. Detector state {signal_conditions[0][0]}"
|
||||
)
|
||||
|
||||
def on_trigger(self) -> None:
|
||||
"""Trigger the detector"""
|
||||
if self.parent.cam.trigger_source.get() == TriggerSource.SOFTWARE:
|
||||
self.parent.cam.software_trigger_device.put(1)
|
||||
ttime.sleep(0.1)
|
||||
self.send_data()
|
||||
|
||||
def run_monitor(self) -> None:
|
||||
"""
|
||||
Run the monitor loop in a separate thread.
|
||||
"""
|
||||
self.monitor_thread = threading.Thread(target=self.monitor_loop, daemon=True)
|
||||
self.monitor_thread.start()
|
||||
|
||||
def monitor_loop(self) -> None:
|
||||
"""
|
||||
Monitor the detector status and send data.
|
||||
"""
|
||||
while True:
|
||||
self.send_data()
|
||||
ttime.sleep(1 / self.update_frequency)
|
||||
if self.parent.stopped:
|
||||
break
|
||||
|
||||
def send_data(self) -> None:
|
||||
"""Send data to monitor endpoint in redis."""
|
||||
try:
|
||||
img = self.parent.image.array_data.get().reshape(self.image_shape)
|
||||
# pylint: disable=protected-access
|
||||
self.parent._run_subs(sub_type=self.parent.SUB_VALUE, value=img)
|
||||
except Exception as e:
|
||||
logger.debug(f"{e} for image with shape {self.parent.image.array_data.get().shape}")
|
||||
|
||||
def stop_detector(self) -> None:
|
||||
"""Stop detector."""
|
||||
self.parent.cam.acquire.put(0)
|
||||
signal_conditions = [(self.parent.cam.detector_state.get, DetectorState.IDLE)]
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.timeout - self.parent.timeout // 2,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
# Retry stop detector and wait for remaining time
|
||||
self.parent.cam.acquire.put(0)
|
||||
if not self.wait_for_signals(
|
||||
signal_conditions=signal_conditions,
|
||||
timeout=self.parent.timeout - self.parent.timeout // 2,
|
||||
check_stopped=True,
|
||||
all_signals=False,
|
||||
):
|
||||
raise GrashopperTimeoutError(
|
||||
f"Failed to stop detector, detector state {signal_conditions[0][0]}"
|
||||
)
|
||||
|
||||
def stop_detector_backend(self) -> None:
|
||||
"""Stop the data backend sending data."""
|
||||
self.stop_monitor = True
|
||||
|
||||
|
||||
class SLSDetectorCam(Device):
|
||||
"""
|
||||
SLS Detector Camera - Grashoppter
|
||||
|
||||
Base class to map EPICS PVs to ophyd signals.
|
||||
"""
|
||||
|
||||
## Deprecated PVs, to be checked!
|
||||
# acquire_time = ADCpt(EpicsSignal, "AcquireTime", kind=Kind.omitted)
|
||||
# num_exposures = ADCpt(EpicsSignal, "NumExposures", kind=Kind.omitted)
|
||||
# acquire_period = ADCpt(EpicsSignalWithRBV, "AcquirePeriod", kind=Kind.config)
|
||||
|
||||
# Control PVs
|
||||
acquire_time_auto = ADCpt(EpicsSignal, "AcquireTimeAuto", kind=Kind.config)
|
||||
|
||||
frame_rate = ADCpt(EpicsSignalWithRBV, "FrameRate", kind=Kind.normal)
|
||||
num_images = ADCpt(EpicsSignalWithRBV, "NumImages", kind=Kind.normal)
|
||||
num_images_counter = ADCpt(EpicsSignalRO, "NumImagesCounter_RBV", kind=Kind.normal)
|
||||
image_mode = ADCpt(EpicsSignalWithRBV, "ImageMode", kind=Kind.config)
|
||||
acquire = ADCpt(EpicsSignalWithRBV, "Acquire", kind=Kind.config)
|
||||
detector_state = ADCpt(EpicsSignalRO, "DetectorState_RBV", kind=Kind.normal)
|
||||
status_message = ADCpt(EpicsSignalRO, "StatusMessage_RBV", string=True, kind=Kind.config)
|
||||
|
||||
set_image_counter = ADCpt(EpicsSignal, "ArrayCounter", kind=Kind.config)
|
||||
image_counter = ADCpt(EpicsSignal, "ArrayCounter_RBV", kind=Kind.normal)
|
||||
image_rate = ADCpt(EpicsSignalRO, "ArrayRate_RBV", kind=Kind.omitted)
|
||||
|
||||
# Asyn Port name
|
||||
port_name = ADCpt(EpicsSignalRO, "PortName_RBV", string=True, kind=Kind.omitted)
|
||||
|
||||
# Readout related PVs
|
||||
max_image_size_x = ADCpt(EpicsSignalRO, "MaxSizeX_RBV", kind=Kind.config)
|
||||
max_image_size_y = ADCpt(EpicsSignalRO, "MaxSizeY_RBV", kind=Kind.config)
|
||||
image_size_x = ADCpt(EpicsSignalRO, "ArraySizeX_RBV", kind=Kind.config)
|
||||
image_size_y = ADCpt(EpicsSignalRO, "ArraySizeY_RBV", kind=Kind.config)
|
||||
# Only BinY PV is working, sets both
|
||||
image_binning = ADCpt(EpicsSignalWithRBV, "BinY", kind=Kind.config)
|
||||
|
||||
gain = ADCpt(EpicsSignalWithRBV, "Gain", kind=Kind.config)
|
||||
gain_auto = ADCpt(EpicsSignalWithRBV, "GainAuto", kind=Kind.config)
|
||||
video_mode = ADCpt(EpicsSignalWithRBV, "VideoMode", kind=Kind.config)
|
||||
pixel_format = ADCpt(EpicsSignalWithRBV, "PixelFormat", kind=Kind.config)
|
||||
# Desired to set this in future?
|
||||
color_mode = ADCpt(EpicsSignalRO, "ColorMode_RBV", kind=Kind.config)
|
||||
|
||||
# HW Status PVs
|
||||
temperature_actual = ADCpt(EpicsSignal, "TemperatureActual", kind=Kind.omitted)
|
||||
|
||||
# Trigger
|
||||
trigger_mode_active = ADCpt(EpicsSignalWithRBV, "TriggerMode", kind=Kind.config)
|
||||
trigger_source = ADCpt(EpicsSignalWithRBV, "TriggerSource", kind=Kind.config)
|
||||
trigger_delay = ADCpt(EpicsSignalWithRBV, "TriggerDelay", kind=Kind.omitted)
|
||||
exposure_mode = ADCpt(EpicsSignalWithRBV, "ExposureMode", kind=Kind.omitted)
|
||||
software_trigger_device = ADCpt(EpicsSignal, "SoftwareTrigger", kind=Kind.config)
|
||||
|
||||
# buffer
|
||||
memory_polling = ADCpt(EpicsSignal, "PoolUsedMem.SCAN", kind=Kind.omitted)
|
||||
|
||||
|
||||
class SLSImagePlugin(Device):
|
||||
"""SLS Image Plugin
|
||||
|
||||
Image plugin for SLS detector imitating the behaviour of ImagePlugin from
|
||||
ophyd's areadetector plugins.
|
||||
"""
|
||||
|
||||
# Control
|
||||
array_port = Cpt(EpicsSignal, "NDArrayPort", kind=Kind.omitted, string=True)
|
||||
enable_cb = Cpt(EpicsSignal, "EnableCallbacks", kind=Kind.config)
|
||||
queue_size = Cpt(EpicsSignal, "QueueSize", kind=Kind.config)
|
||||
set_array_counter = Cpt(EpicsSignal, "ArrayCounter", kind=Kind.config)
|
||||
array_counter = Cpt(EpicsSignal, "ArrayCounter_RBV", kind=Kind.normal)
|
||||
set_dropped_arrays = Cpt(EpicsSignal, "DroppedArrays", kind=Kind.config)
|
||||
dropped_arrays = Cpt(EpicsSignal, "DroppedArrays_RBV", kind=Kind.normal)
|
||||
image_id = Cpt(EpicsSignal, "UniqueId_RBV", kind=Kind.normal)
|
||||
|
||||
# Data
|
||||
array_data = Cpt(EpicsSignal, "ArrayData", kind=Kind.omitted)
|
||||
|
||||
# Size related PVs from Plugin
|
||||
array_size_0 = Cpt(EpicsSignalRO, "ArraySize0_RBV", kind=Kind.omitted)
|
||||
array_size_1 = Cpt(EpicsSignalRO, "ArraySize1_RBV", kind=Kind.omitted)
|
||||
array_size_2 = Cpt(EpicsSignalRO, "ArraySize2_RBV", kind=Kind.omitted)
|
||||
array_dimension_size = Cpt(EpicsSignalRO, "NDimensions_RBV", kind=Kind.omitted)
|
||||
|
||||
|
||||
class GrashopperTOMCAT(PSIDetectorBase):
|
||||
"""
|
||||
Grashopper detector for TOMCAT
|
||||
|
||||
Parent class: PSIDetectorBase
|
||||
|
||||
class attributes:
|
||||
custom_prepare_cls (GrashopperTOMCATSetup) : Custom detector setup class for TOMCAT,
|
||||
inherits from CustomDetectorMixin
|
||||
cam (SLSDetectorCam) : Detector camera
|
||||
image (SLSImagePlugin) : Image plugin for detector
|
||||
"""
|
||||
|
||||
# Specify which functions are revealed to the user in BEC client
|
||||
USER_ACCESS = ["describe"]
|
||||
|
||||
SUB_MONITOR = "monitor"
|
||||
SUB_VALUE = "value"
|
||||
_default_sub = SUB_VALUE
|
||||
|
||||
# specify Setup class
|
||||
custom_prepare_cls = GrashopperTOMCATSetup
|
||||
# specify minimum readout time for detector
|
||||
MIN_READOUT = 0
|
||||
# specify class attributes
|
||||
cam = ADCpt(SLSDetectorCam, "cam1:")
|
||||
image = ADCpt(SLSImagePlugin, "image1:")
|
||||
|
||||
def stage(self) -> list[object]:
|
||||
rtr = super().stage()
|
||||
self.custom_prepare.arm_acquisition()
|
||||
return rtr
|
||||
|
||||
def unstage(self) -> list[object]:
|
||||
rtr = super().unstage()
|
||||
self.custom_prepare.stop_monitor = True
|
||||
return rtr
|
||||
|
||||
def set_trigger(self, trigger_source: TriggerSource) -> None:
|
||||
"""Set trigger source for the detector.
|
||||
Check the TriggerSource enum for possible values
|
||||
|
||||
Args:
|
||||
trigger_source (TriggerSource): Trigger source for the detector
|
||||
|
||||
"""
|
||||
value = trigger_source
|
||||
self.cam.trigger_source.put(value)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
hopper = GrashopperTOMCAT(name="hopper", prefix="X02DA-PG-USB:", sim_mode=True)
|
||||
hopper.wait_for_connection(all_signals=True)
|
||||
182
tomcat_bec/devices/tomcat_rotation_motors.py
Normal file
182
tomcat_bec/devices/tomcat_rotation_motors.py
Normal file
@@ -0,0 +1,182 @@
|
||||
""" Module for Tomcat rotation motors.
|
||||
|
||||
The following classes implement the rotation motors for:
|
||||
|
||||
- AerotechAutomation1 (Tomcat), based on EpicsMotorIOC.
|
||||
|
||||
"""
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from bec_lib import threadlocked
|
||||
from ophyd import DeviceStatus
|
||||
from ophyd_devices.interfaces.base_classes.ophyd_rotation_base import EpicsRotationBase
|
||||
from ophyd_devices.interfaces.protocols.bec_protocols import BECFlyerProtocol, BECScanProtocol
|
||||
|
||||
|
||||
class TomcatAerotechRotation(EpicsRotationBase, BECFlyerProtocol, BECScanProtocol):
|
||||
"""Special motor class that provides flyer interface and progress bar."""
|
||||
|
||||
SUB_PROGRESS = "progress"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
prefix="",
|
||||
*,
|
||||
name,
|
||||
kind=None,
|
||||
read_attrs=None,
|
||||
configuration_attrs=None,
|
||||
parent=None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Implementation of the Tomcat AerotechAutomation 1 rotation motor class.
|
||||
|
||||
This motor class is based on EpicsRotationBase and provides in addition the flyer interface for BEC
|
||||
and a progress update.
|
||||
"""
|
||||
super().__init__(
|
||||
prefix=prefix,
|
||||
name=name,
|
||||
kind=kind,
|
||||
read_attrs=read_attrs,
|
||||
configuration_attrs=configuration_attrs,
|
||||
parent=parent,
|
||||
**kwargs,
|
||||
)
|
||||
self._start_position = None
|
||||
self._target_position = None
|
||||
self._stopped = False
|
||||
self._rlock = threading.RLock()
|
||||
self.subscribe(self._progress_update, run=False)
|
||||
|
||||
# ------------------ alternative to using configure method --------------------- #
|
||||
@property
|
||||
def start_position(self) -> float:
|
||||
"""Get the start position."""
|
||||
return self._start_position
|
||||
|
||||
@start_position.setter
|
||||
def start_position(self, value: float) -> None:
|
||||
"""Set the start position."""
|
||||
self._start_position = value
|
||||
|
||||
@property
|
||||
def target_position(self) -> float:
|
||||
"""Get the start position."""
|
||||
return self._target_position
|
||||
|
||||
@target_position.setter
|
||||
def target_position(self, value: float) -> None:
|
||||
"""Set the start position."""
|
||||
self._target_position = value
|
||||
|
||||
# ------------------ alternative to using configure method --------------------- #
|
||||
# configure method is optional for flyers within BEC, you can use stage method or pre_scan method to
|
||||
# set relevant parameters on the device.
|
||||
|
||||
# def configure(self, d: dict) -> dict:
|
||||
# """Configure method from the device.
|
||||
|
||||
# This method is usually used to set configuration parameters for the device.
|
||||
|
||||
# Args:
|
||||
# d (dict): Dictionary with configuration parameters.
|
||||
|
||||
# """
|
||||
# if "target" in d:
|
||||
# self._target_position = d["target"]
|
||||
# del d["target"]
|
||||
# if "position" in d:
|
||||
# self._target_position = d["position"]
|
||||
# del d["position"]
|
||||
# return super().configure(d)
|
||||
|
||||
def pre_scan(self):
|
||||
"""Perform pre-scan operation, e.g. move to start position."""
|
||||
if self._start_position:
|
||||
self.move(self._start_position, wait=True)
|
||||
|
||||
def kickoff(self) -> DeviceStatus:
|
||||
"""Kickoff the scan.
|
||||
|
||||
The kickoff method should return a status object that is set to finish once the flyer flys, and is ready for the next actions.
|
||||
I would consider the following implementation.
|
||||
"""
|
||||
self._start_position = float(self.position)
|
||||
self.move(self._target_position, wait=False)
|
||||
status = DeviceStatus(self)
|
||||
status.set_finished()
|
||||
return status
|
||||
|
||||
def complete(self) -> DeviceStatus:
|
||||
"""Complete method of the scan.
|
||||
|
||||
This will be called in a fly scan after the kickoff, thus, the stage will be moving to it's target position.
|
||||
It should
|
||||
|
||||
The complete method should return a status object that is set to finish once the flyer is done and the scan is complete.
|
||||
I would consider the following implementation.
|
||||
"""
|
||||
threading.Thread(target=self._is_motor_moving, daemon=True).start()
|
||||
status = DeviceStatus(self)
|
||||
self.subscribe(status.set_finished, event_type=self.SUB_DONE, run=False)
|
||||
return status
|
||||
|
||||
def stage(self) -> list[object]:
|
||||
"""Stage the scan.
|
||||
|
||||
We add here in addition the setting of the _stopped flag to False for the thread.
|
||||
"""
|
||||
self._stopped = False
|
||||
return super().stage()
|
||||
|
||||
def stop(self, success: bool = False) -> None:
|
||||
"""Stop the scan.
|
||||
|
||||
If the device is stopped, the _stopped flag is set to True.
|
||||
"""
|
||||
self._stopped = True
|
||||
super().stop(success=success)
|
||||
|
||||
@threadlocked
|
||||
def _is_motor_moving(self):
|
||||
"""Function to check if the motor is moving.
|
||||
|
||||
This function is used in a thread to check if the motor is moving.
|
||||
It resolves by running"""
|
||||
while self.motor_done_move.get():
|
||||
if self._stopped:
|
||||
self._done_moving(success=False)
|
||||
return
|
||||
time.sleep(0.1)
|
||||
self._done_moving(success=True)
|
||||
|
||||
# TODO This logic could be refined to be more robust for various scan types, i.e. at the moment it just takes
|
||||
# the start and target position and calculates the progress based on the current position.
|
||||
def _progress_update(self, value, **kwargs) -> None:
|
||||
"""Progress update on the scan.
|
||||
|
||||
Runs the progress update on the device progress during the scan.
|
||||
It uses the SUB_PROGRESS event from ophyd to update BEC about the progress.
|
||||
Scans need to be aware which device progress is relevant for the scan.
|
||||
|
||||
Args:
|
||||
value (float): The value of the motor position.
|
||||
"""
|
||||
if (self._start_position is None) or (self._target_position is None) or (not self.moving):
|
||||
self._run_subs(sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1)
|
||||
return
|
||||
|
||||
progress = np.abs(
|
||||
(value - self._start_position) / (self._target_position - self._start_position)
|
||||
)
|
||||
max_value = 100
|
||||
self._run_subs(
|
||||
sub_type=self.SUB_PROGRESS,
|
||||
value=int(100 * progress),
|
||||
max_value=max_value,
|
||||
done=int(np.isclose(max_value, progress, 1e-3)),
|
||||
)
|
||||
Reference in New Issue
Block a user