From 4b5a270071093e3889c028510b17350826453b7c Mon Sep 17 00:00:00 2001 From: mohacsi_i Date: Tue, 12 Mar 2024 10:56:30 +0100 Subject: [PATCH] Flaking --- .../devices/aerotech/AerotechAutomation1.py | 837 ++++++++++++------ .../aerotech/AerotechAutomation1Enums.py | 561 ++++++------ 2 files changed, 828 insertions(+), 570 deletions(-) diff --git a/ophyd_devices/epics/devices/aerotech/AerotechAutomation1.py b/ophyd_devices/epics/devices/aerotech/AerotechAutomation1.py index 5bf804d..4f297ec 100644 --- a/ophyd_devices/epics/devices/aerotech/AerotechAutomation1.py +++ b/ophyd_devices/epics/devices/aerotech/AerotechAutomation1.py @@ -8,85 +8,126 @@ import time try: from .AerotechAutomation1Enums import * - from .AerotechAutomation1Enums import (DataCollectionMode, DataCollectionFrequency, - AxisDataSignal, PsoWindowInput, DriveDataCaptureInput, DriveDataCaptureTrigger, - TaskDataSignal, SystemDataSignal, TomcatSequencerState) + from .AerotechAutomation1Enums import ( + DataCollectionMode, + DataCollectionFrequency, + AxisDataSignal, + PsoWindowInput, + DriveDataCaptureInput, + DriveDataCaptureTrigger, + TaskDataSignal, + SystemDataSignal, + TomcatSequencerState, + ) except: from AerotechAutomation1Enums import * - from AerotechAutomation1Enums import (DataCollectionMode, DataCollectionFrequency, - AxisDataSignal, PsoWindowInput, DriveDataCaptureInput, DriveDataCaptureTrigger, - TaskDataSignal, SystemDataSignal, TomcatSequencerState) + from AerotechAutomation1Enums import ( + DataCollectionMode, + DataCollectionFrequency, + AxisDataSignal, + PsoWindowInput, + DriveDataCaptureInput, + DriveDataCaptureTrigger, + TaskDataSignal, + SystemDataSignal, + TomcatSequencerState, + ) from typing import Union from collections import OrderedDict - class EpicsMotorX(EpicsMotor): """ 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): - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) self._startPosition = None self._targetPosition = None self.subscribe(self._progress_update, run=False) def configure(self, d: dict): if "target" in d: - self._targetPosition = d['target'] - del d['target'] + self._targetPosition = d["target"] + del d["target"] if "position" in d: - self._targetPosition = d['position'] - del d['position'] + self._targetPosition = d["position"] + del d["position"] return super().configure(d) def kickoff(self): - self._startPosition = float( self.position) + self._startPosition = float(self.position) return self.move(self._targetPosition, wait=False) def move(self, position, wait=True, **kwargs): - self._startPosition = float( self.position) - return super().move(position, wait, **kwargs) + self._startPosition = float(self.position) + return super().move(position, wait, **kwargs) def _progress_update(self, value, **kwargs) -> None: """Progress update on the scan""" if (self._startPosition is None) or (self._targetPosition is None) or (not self.moving): - self._run_subs( sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, ) + self._run_subs( + sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, + ) return - progress = np.abs( (value-self._startPosition)/(self._targetPosition-self._startPosition) ) + progress = np.abs( + (value - self._startPosition) / (self._targetPosition - self._startPosition) + ) 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)), ) + value=int(100 * progress), + max_value=max_value, + done=int(np.isclose(max_value, progress, 1e-3)), + ) class EpicsPassiveRO(EpicsSignalRO): """ Small helper class to read PVs that need to be processed first. """ - def __init__(self, read_pv, *, string=False, name=None, **kwargs): + + def __init__(self, read_pv, *, string=False, name=None, **kwargs): super().__init__(read_pv, string=string, name=name, **kwargs) - self._proc = EpicsSignal(read_pv+".PROC", kind=Kind.omitted, put_complete=True) - - def wait_for_connection(self, *args, **kwargs): + self._proc = EpicsSignal(read_pv + ".PROC", kind=Kind.omitted, put_complete=True) + + def wait_for_connection(self, *args, **kwargs): super().wait_for_connection(*args, **kwargs) self._proc.wait_for_connection(*args, **kwargs) - + def get(self, *args, **kwargs): self._proc.set(1).wait() return super().get(*args, **kwargs) - - @property + + @property def value(self): return super().value - - class aa1Controller(Device): """Ophyd proxy class for the Aerotech Automation 1's core controller functionality""" + controllername = Component(EpicsSignalRO, "NAME", kind=Kind.config) serialnumber = Component(EpicsSignalRO, "SN", kind=Kind.config) apiversion = Component(EpicsSignalRO, "API_VERSION", kind=Kind.config) @@ -94,8 +135,28 @@ class aa1Controller(Device): taskcount = Component(EpicsSignalRO, "TASKCOUNT", kind=Kind.config) fastpoll = Component(EpicsSignalRO, "POLLTIME", auto_monitor=True, kind=Kind.hinted) slowpoll = Component(EpicsSignalRO, "DRVPOLLTIME", auto_monitor=True, kind=Kind.hinted) - def __init__(self, prefix="", *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) + class aa1Tasks(Device): """ Task management API @@ -127,34 +188,57 @@ class aa1Tasks(Device): ''' """ + SUB_PROGRESS = "progress" _failure = Component(EpicsSignalRO, "FAILURE", 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) taskStates = Component(EpicsSignalRO, "STATES-RBV", auto_monitor=True, kind=Kind.hinted) taskIndex = Component(EpicsSignal, "TASKIDX", kind=Kind.config, put_complete=True) switch = Component(EpicsSignal, "SWITCH", kind=Kind.config, put_complete=True) - _execute = Component(EpicsSignal, "EXECUTE", string=True, kind=Kind.config, put_complete=True) - _executeMode = Component(EpicsSignal, "EXECUTE-MODE", kind=Kind.config, put_complete=True) + _execute = Component(EpicsSignal, "EXECUTE", string=True, kind=Kind.config, put_complete=True) + _executeMode = Component(EpicsSignal, "EXECUTE-MODE", kind=Kind.config, put_complete=True) _executeReply = Component(EpicsSignalRO, "EXECUTE_RBV", string=True, auto_monitor=True) fileName = Component(EpicsSignal, "FILENAME", string=True, kind=Kind.omitted, put_complete=True) _fileRead = Component(EpicsPassiveRO, "FILEREAD", string=True, kind=Kind.omitted) - _fileWrite = Component(EpicsSignal, "FILEWRITE", string=True, kind=Kind.omitted, put_complete=True) - - def __init__(self, prefix="", *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): + _fileWrite = Component( + EpicsSignal, "FILEWRITE", string=True, kind=Kind.omitted, put_complete=True + ) + + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): """ __init__ MUST have a full argument list""" - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) self._currentTask = None - self._textToExecute = None + self._textToExecute = None self._isConfigured = False self._isStepConfig = False self.subscribe(self._progress_update, "progress", run=False) - + def _progress_update(self, value, **kwargs) -> None: - """Progress update on the scan""" + """Progress update on the scan""" value = self.progress() - self._run_subs( sub_type=self.SUB_PROGRESS, value=value, max_value=1, done=1, ) + self._run_subs( + sub_type=self.SUB_PROGRESS, value=value, max_value=1, done=1, + ) def _progress(self) -> None: """Progress update on the scan""" @@ -172,60 +256,60 @@ class aa1Tasks(Device): self.fileName.set(filename).wait() filebytes = self._fileRead.get() # C-strings terminate with trailing zero - if filebytes[-1]==0: + if filebytes[-1] == 0: filebytes = filebytes[:-1] filetext = filebytes return filetext - + def writeFile(self, filename: str, filetext: str) -> None: """ Write a file to the controller """ self.fileName.set(filename).wait() self._fileWrite.set(filetext).wait() - def runScript(self, filename: str, taskIndex: int==2, filetext=None, settle_time=0.5) -> None: + def runScript(self, filename: str, taskIndex: int == 2, filetext=None, settle_time=0.5) -> None: """ Run a script file that either exists, or is newly created and compiled""" - - self.configure({'text': filetext, 'filename': filename, 'taskIndex': taskIndex}) + + self.configure({"text": filetext, "filename": filename, "taskIndex": taskIndex}) print("Runscript configured") self.trigger().wait() print("Runscript waited") - - def execute(self, text: str, taskIndex: int=3, mode: str=0, settle_time=0.5): + + def execute(self, text: str, taskIndex: int = 3, mode: str = 0, settle_time=0.5): """ Run a short text command on the Automation1 controller""" - - print(f"Executing program on task: {taskIndex}") - self.configure({'text': text, 'taskIndex': taskIndex, 'mode': mode}) + + print(f"Executing program on task: {taskIndex}") + self.configure({"text": text, "taskIndex": taskIndex, "mode": mode}) self.kickoff().wait() - + if mode in [0, "None", None]: return None else: raw = self._executeReply.get() return raw - def configure(self, d: dict={}) -> tuple: + def configure(self, d: dict = {}) -> tuple: """ Configuration interface for flying """ # Unrolling the configuration dict - text = str(d['text']) if 'text' in d else None - filename = str(d['filename']) if 'filename' in d else None - taskIndex = int(d['taskIndex']) if 'taskIndex' in d else 4 - settle_time = float(d['settle_time']) if 'settle_time' in d else None - mode = d['mode'] if 'mode' in d else None - self._isStepConfig = d['stepper'] if 'stepper' in d else False + text = str(d["text"]) if "text" in d else None + filename = str(d["filename"]) if "filename" in d else None + taskIndex = int(d["taskIndex"]) if "taskIndex" in d else 4 + settle_time = float(d["settle_time"]) if "settle_time" in d else None + mode = d["mode"] if "mode" in d else None + self._isStepConfig = d["stepper"] if "stepper" in d else False # Validation if taskIndex < 1 or taskIndex > 31: raise RuntimeError(f"Invalid task index: {taskIndex}") if (text is None) and (filename is None): raise RuntimeError("Task execution requires either AeroScript text or filename") - + # Common operations old = self.read_configuration() - self.taskIndex.set(taskIndex).wait() + self.taskIndex.set(taskIndex).wait() self._textToExecute = None self._currentTask = taskIndex - + # Choose the right execution mode if (filename is None) and (text not in [None, ""]): # Direct command execution @@ -240,7 +324,7 @@ class aa1Tasks(Device): elif (filename is not None) and (text not in [None, ""]): print("Preparing to execute via intermediary file") # Execute text via intermediate file - self.taskIndex.set(taskIndex).wait() + self.taskIndex.set(taskIndex).wait() self.fileName.set(filename).wait() self._fileWrite.set(text).wait() self.switch.set("Load").wait() @@ -254,9 +338,9 @@ class aa1Tasks(Device): self._isConfigured = True new = self.read_configuration() return (old, new) - + ########################################################################## - # Bluesky stepper interface + # Bluesky stepper interface def stage(self) -> None: """ Default staging """ super().stage() @@ -275,10 +359,10 @@ class aa1Tasks(Device): if settle_time is not None: sleep(settle_time) return status - + def stop(self): """ Stop the currently selected task """ - self.switch.set("Stop").wait() + self.switch.set("Stop").wait() ########################################################################## # Flyer interface @@ -302,35 +386,44 @@ class aa1Tasks(Device): print("Called aa1Task.complete()") timestamp_ = 0 taskIdx = int(self.taskIndex.get()) + def notRunning2(*args, old_value, value, timestamp, **kwargs): - nonlocal timestamp_ - result = False if value[taskIdx] in ["Running", 4] else True + nonlocal timestamp_ + result = False if value[taskIdx] in ["Running", 4] else True timestamp_ = timestamp print(result) - return result + return result # Subscribe and wait for update - status = SubscriptionStatus(self.taskStates, notRunning2, settle_time=0.5) + status = SubscriptionStatus(self.taskStates, notRunning2, settle_time=0.5) return status def describe_collect(self) -> 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, + } return {self.name: dd} - + def collect(self) -> OrderedDict: ret = OrderedDict() ret["timestamps"] = {"success": time.time()} ret["data"] = {"success": 1} yield ret - + class aa1TaskState(Device): """ Task state monitoring API This is the task state monitoring interface for Automation1 tasks. It does not launch execution, but can wait for the execution to complete. """ + index = Component(EpicsSignalRO, "INDEX", kind=Kind.config) status = Component(EpicsSignalRO, "STATUS", auto_monitor=True, kind=Kind.hinted) errorCode = Component(EpicsSignalRO, "ERROR", auto_monitor=True, kind=Kind.hinted) @@ -341,34 +434,42 @@ class aa1TaskState(Device): print("Called aa1TaskState.complete()") # Define wait until the busy flag goes down (excluding initial update) timestamp_ = 0 + def notRunning(*args, old_value, value, timestamp, **kwargs): - nonlocal timestamp_ - result = False if (timestamp_== 0) else (value not in ["Running", 4]) + 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.status, notRunning, settle_time=0.5) + status = SubscriptionStatus(self.status, notRunning, settle_time=0.5) return status - + def kickoff(self) -> DeviceStatus: status = DeviceStatus(self) status.set_finished() return status - + def describe_collect(self) -> 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, + } return dd - + def collect(self) -> OrderedDict: ret = OrderedDict() ret["timestamps"] = {"success": time.time()} ret["data"] = {"success": 1} yield ret - - + + class aa1DataAcquisition(Device): """ Controller Data Acquisition - DONT USE at Tomcat @@ -381,21 +482,22 @@ class aa1DataAcquisition(Device): 3. Start your data collection 4. Read back the recorded data with "readback" """ + # Status monitoring status = Component(EpicsSignalRO, "RUNNING", auto_monitor=True, kind=Kind.hinted) - points_max = Component(EpicsSignal, "MAXPOINTS", kind=Kind.config, put_complete=True) - signal_num = Component(EpicsSignalRO, "NITEMS", kind=Kind.config) + points_max = Component(EpicsSignal, "MAXPOINTS", kind=Kind.config, put_complete=True) + signal_num = Component(EpicsSignalRO, "NITEMS", kind=Kind.config) points_total = Component(EpicsSignalRO, "NTOTAL", auto_monitor=True, kind=Kind.hinted) points_collected = Component(EpicsSignalRO, "NCOLLECTED", auto_monitor=True, kind=Kind.hinted) - points_retrieved= Component(EpicsSignalRO, "NRETRIEVED", auto_monitor=True, kind=Kind.hinted) + points_retrieved = Component(EpicsSignalRO, "NRETRIEVED", auto_monitor=True, kind=Kind.hinted) overflow = Component(EpicsSignalRO, "OVERFLOW", auto_monitor=True, kind=Kind.hinted) runmode = Component(EpicsSignalRO, "MODE_RBV", auto_monitor=True, kind=Kind.hinted) # DAQ setup numpoints = Component(EpicsSignal, "NPOINTS", kind=Kind.config, put_complete=True) frequency = Component(EpicsSignal, "FREQUENCY", kind=Kind.config, put_complete=True) _configure = Component(EpicsSignal, "CONFIGURE", kind=Kind.omitted, put_complete=True) - + def startConfig(self, npoints: int, frequency: DataCollectionFrequency): self.numpoints.set(npoints).wait() self.frequency.set(frequency).wait() @@ -408,7 +510,7 @@ class aa1DataAcquisition(Device): srcAxis = Component(EpicsSignal, "SRC_AXIS", kind=Kind.config, put_complete=True) srcCode = Component(EpicsSignal, "SRC_CODE", kind=Kind.config, put_complete=True) _srcAdd = Component(EpicsSignal, "SRC_ADD", kind=Kind.omitted, put_complete=True) - + def addAxisSignal(self, axis: int, code: int) -> None: """ Add a new axis-specific data signal to the DAQ configuration. The most common signals are PositionFeedback and PositionError. @@ -432,31 +534,31 @@ class aa1DataAcquisition(Device): # Starting / stopping the DAQ _mode = Component(EpicsSignal, "MODE", kind=Kind.config, put_complete=True) _switch = Component(EpicsSignal, "SET", kind=Kind.omitted, put_complete=True) - + def start(self, mode=DataCollectionMode.Snapshot) -> None: """ Start a new data collection """ self._mode.set(mode).wait() self._switch.set("START").wait() - + def stop(self) -> None: """ Stop a running data collection """ - self._switch.set("STOP").wait() + self._switch.set("STOP").wait() def run(self, mode=DataCollectionMode.Snapshot) -> None: """ Start a new data collection """ self._mode.set(mode).wait() - self._switch.set("START").wait() + self._switch.set("START").wait() # Wait for finishing acquisition # Note: this is very bad blocking sleep - while self.status.value!=0: + while self.status.value != 0: sleep(0.1) sleep(0.1) - + # Data readback data = self.data_rb.get() rows = self.data_rows.get() cols = self.data_cols.get() - if len(data)==0 or rows==0 or cols==0: + if len(data) == 0 or rows == 0 or cols == 0: sleep(0.5) data = self.data_rb.get() rows = self.data_rows.get() @@ -470,13 +572,13 @@ class aa1DataAcquisition(Device): data_rows = Component(EpicsSignalRO, "DATA_ROWS", auto_monitor=True, kind=Kind.hinted) data_cols = Component(EpicsSignalRO, "DATA_COLS", auto_monitor=True, kind=Kind.hinted) data_stat = Component(EpicsSignalRO, "DATA_AVG", auto_monitor=True, kind=Kind.hinted) - + def dataReadBack(self) -> np.ndarray: """Retrieves collected data from the controller""" data = self.data_rb.get() rows = self.data_rows.get() cols = self.data_cols.get() - if len(data)==0 or rows==0 or cols==0: + if len(data) == 0 or rows == 0 or cols == 0: sleep(0.2) data = self.data_rb.get() rows = self.data_rows.get() @@ -486,7 +588,6 @@ class aa1DataAcquisition(Device): return data - class aa1GlobalVariables(Device): """ Global variables @@ -505,34 +606,35 @@ class aa1GlobalVariables(Device): ret_arr = var.readFloat(1000, 1024) """ + # Status monitoring num_real = Component(EpicsSignalRO, "NUM-REAL_RBV", kind=Kind.config) - num_int = Component(EpicsSignalRO, "NUM-INT_RBV", kind=Kind.config) - num_string = Component(EpicsSignalRO, "NUM-STRING_RBV", kind=Kind.config) - + num_int = Component(EpicsSignalRO, "NUM-INT_RBV", kind=Kind.config) + num_string = Component(EpicsSignalRO, "NUM-STRING_RBV", kind=Kind.config) + integer_addr = Component(EpicsSignal, "INT-ADDR", kind=Kind.omitted, put_complete=True) integer_size = Component(EpicsSignal, "INT-SIZE", kind=Kind.omitted, put_complete=True) integer = Component(EpicsSignal, "INT", kind=Kind.omitted, put_complete=True) integer_rb = Component(EpicsPassiveRO, "INT-RBV", kind=Kind.omitted) integerarr = Component(EpicsSignal, "INTARR", kind=Kind.omitted, put_complete=True) - integerarr_rb = Component(EpicsPassiveRO, "INTARR-RBV", kind=Kind.omitted) - + integerarr_rb = Component(EpicsPassiveRO, "INTARR-RBV", kind=Kind.omitted) + real_addr = Component(EpicsSignal, "REAL-ADDR", kind=Kind.omitted, put_complete=True) real_size = Component(EpicsSignal, "REAL-SIZE", kind=Kind.omitted, put_complete=True) real = Component(EpicsSignal, "REAL", kind=Kind.omitted, put_complete=True) real_rb = Component(EpicsPassiveRO, "REAL-RBV", kind=Kind.omitted) realarr = Component(EpicsSignal, "REALARR", kind=Kind.omitted, put_complete=True) - realarr_rb = Component(EpicsPassiveRO, "REALARR-RBV", kind=Kind.omitted) - + realarr_rb = Component(EpicsPassiveRO, "REALARR-RBV", kind=Kind.omitted) + string_addr = Component(EpicsSignal, "STRING-ADDR", kind=Kind.omitted, put_complete=True) string = Component(EpicsSignal, "STRING", string=True, kind=Kind.omitted, put_complete=True) string_rb = Component(EpicsPassiveRO, "STRING-RBV", string=True, kind=Kind.omitted) - - def readInt(self, address: int, size: int=None) -> int: + + def readInt(self, address: int, size: int = None) -> int: """ Read a 64-bit integer global variable """ if address > self.num_int.get(): raise RuntimeError("Integer address {address} is out of range") - + if size is None: self.integer_addr.set(address).wait() return self.integer_rb.get() @@ -540,12 +642,12 @@ class aa1GlobalVariables(Device): self.integer_addr.set(address).wait() self.integer_size.set(size).wait() return self.integerarr_rb.get() - + def writeInt(self, address: int, value) -> None: """ Write a 64-bit integer global variable """ if address > self.num_int.get(): raise RuntimeError("Integer address {address} is out of range") - + if isinstance(value, (int, float)): self.integer_addr.set(address).wait() self.integer.set(value).wait() @@ -559,12 +661,11 @@ class aa1GlobalVariables(Device): else: raise RuntimeError("Unsupported integer value type: {type(value)}") - - def readFloat(self, address: int, size: int=None) -> float: + def readFloat(self, address: int, size: int = None) -> float: """ Read a 64-bit double global variable """ if address > self.num_real.get(): raise RuntimeError("Floating point address {address} is out of range") - + if size is None: self.real_addr.set(address).wait() return self.real_rb.get() @@ -577,7 +678,7 @@ class aa1GlobalVariables(Device): """ Write a 64-bit float global variable """ if address > self.num_real.get(): raise RuntimeError("Float address {address} is out of range") - + if isinstance(value, (int, float)): self.real_addr.set(address).wait() self.real.set(value).wait() @@ -597,7 +698,7 @@ class aa1GlobalVariables(Device): """ if address > self.num_string.get(): raise RuntimeError("String address {address} is out of range") - + self.string_addr.set(address).wait() return self.string_rb.get() @@ -605,7 +706,7 @@ class aa1GlobalVariables(Device): """ Write a 40 bytes string global variable """ if address > self.num_string.get(): raise RuntimeError("Integer address {address} is out of range") - + if isinstance(value, str): self.string_addr.set(address).wait() self.string.set(value).wait() @@ -613,7 +714,6 @@ class aa1GlobalVariables(Device): raise RuntimeError("Unsupported string value type: {type(value)}") - class aa1GlobalVariableBindings(Device): """ Polled global variables @@ -621,30 +721,124 @@ class aa1GlobalVariableBindings(Device): on the Automation1 controller. These variables are continuously polled and are thus a convenient way to interface scripts with the outside word. """ + int0 = Component(EpicsSignalRO, "INT0_RBV", auto_monitor=True, name="int0", kind=Kind.hinted) int1 = Component(EpicsSignalRO, "INT1_RBV", auto_monitor=True, name="int1", kind=Kind.hinted) int2 = Component(EpicsSignalRO, "INT2_RBV", auto_monitor=True, name="int2", kind=Kind.hinted) int3 = Component(EpicsSignalRO, "INT3_RBV", auto_monitor=True, name="int3", kind=Kind.hinted) - int8 = Component(EpicsSignal, "INT8_RBV", put_complete=True, write_pv="INT8", auto_monitor=True, name="int8", kind=Kind.hinted) - int9 = Component(EpicsSignal, "INT9_RBV", put_complete=True, write_pv="INT9", auto_monitor=True, name="int9", kind=Kind.hinted) - int10 = Component(EpicsSignal, "INT10_RBV", put_complete=True, write_pv="INT10", auto_monitor=True, name="int10", kind=Kind.hinted) - int11 = Component(EpicsSignal, "INT11_RBV", put_complete=True, write_pv="INT11", auto_monitor=True, name="int11", kind=Kind.hinted) + int8 = Component( + EpicsSignal, + "INT8_RBV", + put_complete=True, + write_pv="INT8", + auto_monitor=True, + name="int8", + kind=Kind.hinted, + ) + int9 = Component( + EpicsSignal, + "INT9_RBV", + put_complete=True, + write_pv="INT9", + auto_monitor=True, + name="int9", + kind=Kind.hinted, + ) + int10 = Component( + EpicsSignal, + "INT10_RBV", + put_complete=True, + write_pv="INT10", + auto_monitor=True, + name="int10", + kind=Kind.hinted, + ) + int11 = Component( + EpicsSignal, + "INT11_RBV", + put_complete=True, + write_pv="INT11", + auto_monitor=True, + name="int11", + kind=Kind.hinted, + ) - float0 = Component(EpicsSignalRO, "REAL0_RBV", auto_monitor=True, name="float0", kind=Kind.hinted) - float1 = Component(EpicsSignalRO, "REAL1_RBV", auto_monitor=True, name="float1", kind=Kind.hinted) - float2 = Component(EpicsSignalRO, "REAL2_RBV", auto_monitor=True, name="float2", kind=Kind.hinted) - float3 = Component(EpicsSignalRO, "REAL3_RBV", auto_monitor=True, name="float3", kind=Kind.hinted) - float16 = Component(EpicsSignal, "REAL16_RBV", write_pv="REAL16", put_complete=True, auto_monitor=True, name="float16", kind=Kind.hinted) - float17 = Component(EpicsSignal, "REAL17_RBV", write_pv="REAL17", put_complete=True, auto_monitor=True, name="float17", kind=Kind.hinted) - float18 = Component(EpicsSignal, "REAL18_RBV", write_pv="REAL18", put_complete=True, auto_monitor=True, name="float18", kind=Kind.hinted) - float19 = Component(EpicsSignal, "REAL19_RBV", write_pv="REAL19", put_complete=True, auto_monitor=True, name="float19", kind=Kind.hinted) - - # BEC LiveTable crashes on non-numeric values - str0 = Component(EpicsSignalRO, "STR0_RBV", auto_monitor=True, string=True, name="str0", kind=Kind.config) - str1 = Component(EpicsSignalRO, "STR1_RBV", auto_monitor=True, string=True, name="str1", kind=Kind.config) - str4 = Component(EpicsSignal, "STR4_RBV", put_complete=True, string=True, auto_monitor=True, write_pv="STR4", name="str4", kind=Kind.config) - str5 = Component(EpicsSignal, "STR5_RBV", put_complete=True, string=True, auto_monitor=True, write_pv="STR5", name="str5", kind=Kind.config) + float0 = Component( + EpicsSignalRO, "REAL0_RBV", auto_monitor=True, name="float0", kind=Kind.hinted + ) + float1 = Component( + EpicsSignalRO, "REAL1_RBV", auto_monitor=True, name="float1", kind=Kind.hinted + ) + float2 = Component( + EpicsSignalRO, "REAL2_RBV", auto_monitor=True, name="float2", kind=Kind.hinted + ) + float3 = Component( + EpicsSignalRO, "REAL3_RBV", auto_monitor=True, name="float3", kind=Kind.hinted + ) + float16 = Component( + EpicsSignal, + "REAL16_RBV", + write_pv="REAL16", + put_complete=True, + auto_monitor=True, + name="float16", + kind=Kind.hinted, + ) + float17 = Component( + EpicsSignal, + "REAL17_RBV", + write_pv="REAL17", + put_complete=True, + auto_monitor=True, + name="float17", + kind=Kind.hinted, + ) + float18 = Component( + EpicsSignal, + "REAL18_RBV", + write_pv="REAL18", + put_complete=True, + auto_monitor=True, + name="float18", + kind=Kind.hinted, + ) + float19 = Component( + EpicsSignal, + "REAL19_RBV", + write_pv="REAL19", + put_complete=True, + auto_monitor=True, + name="float19", + kind=Kind.hinted, + ) + # BEC LiveTable crashes on non-numeric values + str0 = Component( + EpicsSignalRO, "STR0_RBV", auto_monitor=True, string=True, name="str0", kind=Kind.config + ) + str1 = Component( + EpicsSignalRO, "STR1_RBV", auto_monitor=True, string=True, name="str1", kind=Kind.config + ) + str4 = Component( + EpicsSignal, + "STR4_RBV", + put_complete=True, + string=True, + auto_monitor=True, + write_pv="STR4", + name="str4", + kind=Kind.config, + ) + str5 = Component( + EpicsSignal, + "STR5_RBV", + put_complete=True, + string=True, + auto_monitor=True, + write_pv="STR5", + name="str5", + kind=Kind.config, + ) class aa1AxisIo(Device): @@ -655,6 +849,7 @@ class aa1AxisIo(Device): should be done in AeroScript. Only one pin can be writen directly but several can be polled! """ + polllvl = Component(EpicsSignal, "POLLLVL", put_complete=True, kind=Kind.config) ai0 = Component(EpicsSignalRO, "AI0-RBV", auto_monitor=True, kind=Kind.hinted) ai1 = Component(EpicsSignalRO, "AI1-RBV", auto_monitor=True, kind=Kind.hinted) @@ -666,7 +861,7 @@ class aa1AxisIo(Device): ao3 = Component(EpicsSignalRO, "AO3-RBV", auto_monitor=True, kind=Kind.hinted) di0 = Component(EpicsSignalRO, "DI0-RBV", auto_monitor=True, kind=Kind.hinted) do0 = Component(EpicsSignalRO, "DO0-RBV", auto_monitor=True, kind=Kind.hinted) - + ai_addr = Component(EpicsSignal, "AI-ADDR", put_complete=True, kind=Kind.config) ai = Component(EpicsSignalRO, "AI-RBV", auto_monitor=True, kind=Kind.hinted) @@ -684,13 +879,12 @@ class aa1AxisIo(Device): self.ao_addr.set(pin).wait() # Set the voltage self.ao.set(value, settle_time=settle_time).wait() - + def setDigital(self, pin: int, value: int, settle_time=0.05): # Set the address self.do_addr.set(pin).wait() # Set the voltage self.do.set(value, settle_time=settle_time).wait() - class aa1AxisPsoBase(Device): @@ -707,45 +901,48 @@ class aa1AxisPsoBase(Device): Genrator --> Event --> Waveform --> Output Specific operation modes should be implemented in child classes. - """ + """ + # ######################################################################## # General module status status = Component(EpicsSignalRO, "STATUS", auto_monitor=True, kind=Kind.hinted) output = Component(EpicsSignalRO, "OUTPUT-RBV", auto_monitor=True, kind=Kind.hinted) - _eventSingle = Component(EpicsSignal, "EVENT:SINGLE", put_complete=True, kind=Kind.omitted) - _reset = Component(EpicsSignal, "RESET", put_complete=True, kind=Kind.omitted) - posInput = Component(EpicsSignal, "DIST:INPUT", put_complete=True, kind=Kind.omitted) + _eventSingle = Component(EpicsSignal, "EVENT:SINGLE", put_complete=True, kind=Kind.omitted) + _reset = Component(EpicsSignal, "RESET", put_complete=True, kind=Kind.omitted) + posInput = Component(EpicsSignal, "DIST:INPUT", put_complete=True, kind=Kind.omitted) # ######################################################################## # PSO Distance event module - dstEventsEna = Component(EpicsSignal, "DIST:EVENTS", put_complete=True, kind=Kind.omitted) + dstEventsEna = Component(EpicsSignal, "DIST:EVENTS", put_complete=True, kind=Kind.omitted) dstCounterEna = Component(EpicsSignal, "DIST:COUNTER", put_complete=True, kind=Kind.omitted) dstCounterVal = Component(EpicsSignalRO, "DIST:CTR0_RBV", auto_monitor=True, kind=Kind.hinted) dstArrayIdx = Component(EpicsSignalRO, "DIST:IDX_RBV", auto_monitor=True, kind=Kind.hinted) - dstArrayDepleted = Component(EpicsSignalRO, "DIST:ARRAY-DEPLETED-RBV", auto_monitor=True, kind=Kind.hinted) - - dstDirection = Component(EpicsSignal, "DIST:EVENTDIR", put_complete=True, kind=Kind.omitted) + dstArrayDepleted = Component( + EpicsSignalRO, "DIST:ARRAY-DEPLETED-RBV", auto_monitor=True, kind=Kind.hinted + ) + + dstDirection = Component(EpicsSignal, "DIST:EVENTDIR", put_complete=True, kind=Kind.omitted) dstDistance = Component(EpicsSignal, "DIST:DISTANCE", put_complete=True, kind=Kind.hinted) dstDistanceArr = Component(EpicsSignal, "DIST:DISTANCES", put_complete=True, kind=Kind.omitted) dstArrayRearm = Component(EpicsSignal, "DIST:REARM-ARRAY", put_complete=True, kind=Kind.omitted) # ######################################################################## - # PSO Window event module + # PSO Window event module winEvents = Component(EpicsSignal, "WINDOW:EVENTS", put_complete=True, kind=Kind.omitted) winOutput = Component(EpicsSignal, "WINDOW0:OUTPUT", put_complete=True, kind=Kind.omitted) winInput = Component(EpicsSignal, "WINDOW0:INPUT", put_complete=True, kind=Kind.omitted) winCounter = Component(EpicsSignal, "WINDOW0:COUNTER", put_complete=True, kind=Kind.omitted) _winLower = Component(EpicsSignal, "WINDOW0:LOWER", put_complete=True, kind=Kind.omitted) _winUpper = Component(EpicsSignal, "WINDOW0:UPPER", put_complete=True, kind=Kind.omitted) - + # ######################################################################## # PSO waveform module waveEnable = Component(EpicsSignal, "WAVE:ENABLE", put_complete=True, kind=Kind.omitted) waveMode = Component(EpicsSignal, "WAVE:MODE", put_complete=True, kind=Kind.omitted) - #waveDelay = Component(EpicsSignal, "WAVE:DELAY", put_complete=True, kind=Kind.omitted) - + # waveDelay = Component(EpicsSignal, "WAVE:DELAY", put_complete=True, kind=Kind.omitted) + # PSO waveform pulse output - #pulseTrunc = Component(EpicsSignal, "WAVE:PULSE:TRUNC", put_complete=True, kind=Kind.omitted) + # pulseTrunc = Component(EpicsSignal, "WAVE:PULSE:TRUNC", put_complete=True, kind=Kind.omitted) pulseOnTime = Component(EpicsSignal, "WAVE:PULSE:ONTIME", put_complete=True, kind=Kind.omitted) pulseWindow = Component(EpicsSignal, "WAVE:PULSE:PERIOD", put_complete=True, kind=Kind.omitted) pulseCount = Component(EpicsSignal, "WAVE:PULSE:COUNT", put_complete=True, kind=Kind.omitted) @@ -754,7 +951,7 @@ class aa1AxisPsoBase(Device): # ######################################################################## # PSO output module outPin = Component(EpicsSignal, "PIN", put_complete=True, kind=Kind.omitted) - outSource = Component(EpicsSignal, "SOURCE", put_complete=True, kind=Kind.omitted) + outSource = Component(EpicsSignal, "SOURCE", put_complete=True, kind=Kind.omitted) def fire(self, settle_time=None): """ Fire a single PSO event (i.e. manual software trigger)""" @@ -767,9 +964,6 @@ class aa1AxisPsoBase(Device): self.waveMode.set(orig_waveMode).wait() - - - class aa1AxisPsoDistance(aa1AxisPsoBase): """ Position Sensitive Output - Distance mode @@ -802,11 +996,30 @@ class aa1AxisPsoDistance(aa1AxisPsoBase): pso.configure(d={'distance': 1.8, 'wmode': "pulsed", 'n_pulse': 5}) pso.kickoff().wait() """ + SUB_PROGRESS = "progress" - - def __init__(self, prefix="", *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): + + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): """ __init__ MUST have a full argument list""" - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) self._Vdistance = 3.141592 self.subscribe(self._progress_update, "progress", run=False) @@ -814,7 +1027,9 @@ class aa1AxisPsoDistance(aa1AxisPsoBase): """Progress update on the scan""" if self.dstArrayDepleted.value: print("PSO array depleted") - self._run_subs( sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, ) + self._run_subs( + sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, + ) return progress = 1 @@ -822,23 +1037,25 @@ class aa1AxisPsoDistance(aa1AxisPsoBase): print(f"PSO array proggress: {progress}") self._run_subs( sub_type=self.SUB_PROGRESS, - value=int(progress), max_value=max_value, done=int(np.isclose(max_value, progress, 1e-3)), ) + value=int(progress), + max_value=max_value, + done=int(np.isclose(max_value, progress, 1e-3)), + ) # ######################################################################## # PSO high level interface - def configure(self, d: dict={}) -> tuple: + def configure(self, d: dict = {}) -> tuple: """ Simplified configuration interface to access the most common functionality for distance mode PSO. :param distance: The trigger distance or the array of distances between subsequent points. :param wmode: Waveform mode configuration, usually pulsed/toggled. """ - distance = d['distance'] - wmode = str(d['wmode']) - t_pulse = float(d['t_pulse']) if 't_pulse' in d else 100 - w_pulse = float(d['w_pulse']) if 'w_pulse' in d else 200 - n_pulse = float(d['n_pulse']) if 'n_pulse' in d else 1 - + distance = d["distance"] + wmode = str(d["wmode"]) + t_pulse = float(d["t_pulse"]) if "t_pulse" in d else 100 + w_pulse = float(d["w_pulse"]) if "w_pulse" in d else 200 + n_pulse = float(d["n_pulse"]) if "n_pulse" in d else 1 # Validate input parameters if wmode not in ["pulse", "pulsed", "toggle", "toggled"]: @@ -851,21 +1068,21 @@ class aa1AxisPsoDistance(aa1AxisPsoBase): self.dstDistance.set(distance).wait() elif isinstance(distance, (np.ndarray, list, tuple)): self.dstDistanceArr.set(distance).wait() - + self.winEvents.set("Off").wait() - self.dstCounterEna.set("Off").wait() + self.dstCounterEna.set("Off").wait() self.dstEventsEna.set("Off").wait() - - # Configure the pulsed/toggled waveform + + # Configure the pulsed/toggled waveform if wmode in ["toggle", "toggled"]: # Switching to simple toggle mode self.waveEnable.set("On").wait() self.waveMode.set("Toggle").wait() - - elif wmode in ["pulse", "pulsed"]: - # Switching to pulsed mode - self.waveEnable.set("On").wait() - self.waveMode.set("Pulse").wait() + + elif wmode in ["pulse", "pulsed"]: + # Switching to pulsed mode + self.waveEnable.set("On").wait() + self.waveMode.set("Pulse").wait() # Setting pulse shape if w_pulse is not None: self.pulseWindow.set(w_pulse).wait() @@ -878,86 +1095,97 @@ class aa1AxisPsoDistance(aa1AxisPsoBase): # Enabling PSO waveform outputs self.waveEnable.set("On").wait() else: - raise RuntimeError(f"Unsupported waveform mode: {wmode}") - + raise RuntimeError(f"Unsupported waveform mode: {wmode}") + # Ensure output is set to low if self.output.value: - self.toggle() - + self.toggle() + # Set PSO output data source - self.outSource.set("Waveform").wait() + self.outSource.set("Waveform").wait() new = self.read_configuration() print("PSO configured") return (old, new) - + # ######################################################################## # Bluesky step scan interface def complete(self, settle_time=0.1) -> DeviceStatus: """ DDC just reads back whatever is available in the buffers""" sleep(settle_time) - status = DeviceStatus(self) + status = DeviceStatus(self) status.set_finished() return status - def trigger(self): - return super().trigger() - + def trigger(self): + return super().trigger() + def unstage(self): # Turn off counter monitoring self.dstEventsEna.set("Off").wait() - self.dstCounterEna.set("Off").wait() + self.dstCounterEna.set("Off").wait() return super().unstage() + # ######################################################################## # Bluesky flyer interface def kickoff(self) -> DeviceStatus: # Rearm the configured array - if hasattr(self, "_distanceValue") and isinstance(self._distanceValue, (np.ndarray, list, tuple)): + if hasattr(self, "_distanceValue") and isinstance( + self._distanceValue, (np.ndarray, list, tuple) + ): self.dstArrayRearm.set(1).wait() # Start monitoring the counters self.dstEventsEna.set("On").wait() - self.dstCounterEna.set("On").wait() + self.dstCounterEna.set("On").wait() status = DeviceStatus(self) status.set_finished() print("PSO kicked off") return status - + def complete(self) -> DeviceStatus: """ Bluesky flyer interface""" # Array mode waits until the buffer is empty - if hasattr(self, "_distanceValue") and isinstance(self._distanceValue, (np.ndarray, list, tuple)): + if hasattr(self, "_distanceValue") and isinstance( + self._distanceValue, (np.ndarray, list, tuple) + ): # Define wait until the busy flag goes down (excluding initial update) timestamp_ = 0 + def notRunning(*args, old_value, value, timestamp, **kwargs): - nonlocal timestamp_ - result = False if (timestamp_== 0) else bool(int(value) & 0x1000) + nonlocal timestamp_ + result = False if (timestamp_ == 0) else bool(int(value) & 0x1000) print(f"Old {old_value}\tNew: {value}\tResult: {result}") timestamp_ = timestamp return result - + # Subscribe and wait for update - #status = SubscriptionStatus(self.status, notRunning, settle_time=0.5) + # status = SubscriptionStatus(self.status, notRunning, settle_time=0.5) # Data capture can be stopped any time status = DeviceStatus(self) - status.set_finished() + status.set_finished() else: # In distance trigger mode there's no specific goal status = DeviceStatus(self) status.set_finished() return status - + def describe_collect(self) -> OrderedDict: ret = OrderedDict() - ret['index'] = {'source': "internal", 'dtype': 'integer', 'shape': [], 'units': '', 'lower_ctrl_limit': 0, 'upper_ctrl_limit': 0} + ret["index"] = { + "source": "internal", + "dtype": "integer", + "shape": [], + "units": "", + "lower_ctrl_limit": 0, + "upper_ctrl_limit": 0, + } return {self.name: ret} - + def collect(self) -> OrderedDict: ret = OrderedDict() ret["timestamps"] = {"index": time.time()} - ret["data"] = {"index": self.dstCounterVal.value } + ret["data"] = {"index": self.dstCounterVal.value} yield ret - - class aa1AxisPsoWindow(aa1AxisPsoBase): @@ -978,35 +1206,54 @@ class aa1AxisPsoWindow(aa1AxisPsoBase): with encoder counters being kept in 32 bit integers. For a more detailed description of additional signals and masking plase refer to Automation1's online manual. - """ - def __init__(self, prefix="", *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): + """ + + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): """ __init__ MUST have a full argument list""" - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) self._mode = "output" self._eventMode = "Enter" # ######################################################################## - # PSO high level interface - def configure(self, d: dict={}) -> tuple: + # PSO high level interface + def configure(self, d: dict = {}) -> tuple: """ Simplified configuration interface to access the most common functionality for distance mode PSO. :param distance: The trigger distance or the array of distances between subsequent points. :param wmode: Waveform mode configuration, usually output/pulsed/toggled. """ - bounds = d['distance'] - wmode = str(d['wmode']) - emode = str(d['emode']) - t_pulse = float(d['t_pulse']) if 't_pulse' in d else None - w_pulse = float(d['w_pulse']) if 'w_pulse' in d else None - n_pulse = float(d['n_pulse']) if 'n_pulse' in d else None + bounds = d["distance"] + wmode = str(d["wmode"]) + emode = str(d["emode"]) + t_pulse = float(d["t_pulse"]) if "t_pulse" in d else None + w_pulse = float(d["w_pulse"]) if "w_pulse" in d else None + n_pulse = float(d["n_pulse"]) if "n_pulse" in d else None # Validate input parameters if wmode not in ["pulse", "pulsed", "toggle", "toggled", "output", "flag"]: raise RuntimeError(f"Unsupported window triggering mode: {wmode}") self._mode = wmode self._eventMode = emode - + old = self.read_configuration() # Configure the window module @@ -1014,8 +1261,8 @@ class aa1AxisPsoWindow(aa1AxisPsoBase): if len(bounds) == 2: self.winCounter.set(0).wait() self._winLower.set(bounds[0]).wait() - self._winUpper.set(bounds[1]).wait() - + self._winUpper.set(bounds[1]).wait() + elif isinstance(bounds, np.ndarray): # ToDo... pass @@ -1024,16 +1271,16 @@ class aa1AxisPsoWindow(aa1AxisPsoBase): self.winOutput.set("Off").wait() self.winEvents.set("Off").wait() - # Configure the pulsed/toggled waveform + # Configure the pulsed/toggled waveform if wmode in ["toggle", "toggled"]: # Switching to simple toggle mode self.waveEnable.set("On").wait() - self.waveMode.set("Toggle").wait() - elif wmode in ["pulse", "pulsed"]: - # Switching to pulsed mode - self.waveEnable.set("On").wait() - self.waveMode.set("Pulse").wait() - # Setting pulse shape + self.waveMode.set("Toggle").wait() + elif wmode in ["pulse", "pulsed"]: + # Switching to pulsed mode + self.waveEnable.set("On").wait() + self.waveMode.set("Pulse").wait() + # Setting pulse shape self.pulseWindow.set(w_pulse).wait() self.pulseOnTime.set(t_pulse).wait() self.pulseCount.set(n_pulse).wait() @@ -1044,47 +1291,42 @@ class aa1AxisPsoWindow(aa1AxisPsoBase): elif wmode in ["output", "flag"]: self.waveEnable.set("Off").wait() else: - raise RuntimeError(f"Unsupported window mode: {wmode}") + raise RuntimeError(f"Unsupported window mode: {wmode}") # Set PSO output data source if wmode in ["toggle", "toggled", "pulse", "pulsed"]: - self.outSource.set("Waveform").wait() + self.outSource.set("Waveform").wait() elif wmode in ["output", "flag"]: - self.outSource.set("Window").wait() + self.outSource.set("Window").wait() new = self.read_configuration() return (old, new) - + def stage(self, settle_time=None): if self.outSource.get() in ["Window", 2]: self.winOutput.set("On").wait() - else: + else: self.winEvents.set(self._eventMode).wait() if settle_time is not None: sleep(settle_time) return super().stage() - def kickoff(self, settle_time=None): + def kickoff(self, settle_time=None): if self.outSource.get() in ["Window", 2]: self.winOutput.set("On").wait() - else: + else: self.winEvents.set(self._eventMode).wait() if settle_time is not None: - sleep(settle_time) - + sleep(settle_time) + def unstage(self, settle_time=None): self.winOutput.set("Off").wait() self.winEvents.set("Off").wait() if settle_time is not None: - sleep(settle_time) + sleep(settle_time) return super().unstage() - - - - - class aa1AxisDriveDataCollection(Device): """ Axis data collection @@ -1104,7 +1346,7 @@ class aa1AxisDriveDataCollection(Device): ... ret = yield from ddc.collect() """ - + # ######################################################################## # General module status state = Component(EpicsSignalRO, "STATE", auto_monitor=True, kind=Kind.hinted) @@ -1119,35 +1361,56 @@ class aa1AxisDriveDataCollection(Device): _readstatus0 = Component(EpicsSignalRO, "AREAD0_RBV", auto_monitor=True, kind=Kind.omitted) _readback1 = Component(EpicsSignal, "AREAD1", kind=Kind.omitted) _readstatus1 = Component(EpicsSignalRO, "AREAD1_RBV", auto_monitor=True, kind=Kind.omitted) - + _buffer0 = Component(EpicsSignalRO, "BUFFER0", auto_monitor=True, kind=Kind.hinted) _buffer1 = Component(EpicsSignalRO, "BUFFER1", auto_monitor=True, kind=Kind.hinted) SUB_PROGRESS = "progress" - def __init__(self, prefix="", *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs): - super().__init__(prefix=prefix, name=name, kind=kind, read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, **kwargs) + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + **kwargs, + ): + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + **kwargs, + ) self.subscribe(self._progress_update, "progress", run=False) def _progress_update(self, value, **kwargs) -> None: """Progress update on the scan""" if self.state.value not in (2, "Acquiring"): - self._run_subs( sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, ) + self._run_subs( + sub_type=self.SUB_PROGRESS, value=1, max_value=1, done=1, + ) return progress = 1 max_value = 1 self._run_subs( sub_type=self.SUB_PROGRESS, - value=int(progress), max_value=max_value, done=int(np.isclose(max_value, progress, 1e-3)), ) + value=int(progress), + max_value=max_value, + done=int(np.isclose(max_value, progress, 1e-3)), + ) - - - def configure(self, d: dict={}) -> tuple: - npoints = int(d['npoints']) - trigger = int(d['trigger']) if 'trigger' in d else DriveDataCaptureTrigger.PsoOutput - source0 = int(d['source0']) if 'source0' in d else DriveDataCaptureInput.PrimaryFeedback - source1 = int(d['source1']) if 'source1' in d else DriveDataCaptureInput.PositionCommand + def configure(self, d: dict = {}) -> tuple: + npoints = int(d["npoints"]) + trigger = int(d["trigger"]) if "trigger" in d else DriveDataCaptureTrigger.PsoOutput + source0 = int(d["source0"]) if "source0" in d else DriveDataCaptureInput.PrimaryFeedback + source1 = int(d["source1"]) if "source1" in d else DriveDataCaptureInput.PositionCommand old = self.read_configuration() @@ -1159,11 +1422,11 @@ class aa1AxisDriveDataCollection(Device): new = self.read_configuration() return (old, new) - - # Bluesky step scanning interface + + # Bluesky step scanning interface def stage(self, settle_time=0.1): super().stage() - self._switch.set("Start", settle_time=0.5).wait() + self._switch.set("Start", settle_time=0.5).wait() status = Status(timeout=0.1, settle_time=settle_time).set_finished() return status @@ -1171,19 +1434,19 @@ class aa1AxisDriveDataCollection(Device): self._switch.set("Stop", settle_time=settle_time).wait() super().unstage() print(f"Recorded samples: {self.nsamples_rbv.value}") - - # Bluesky flyer interface + + # Bluesky flyer interface def kickoff(self, settle_time=0.1) -> Status: - status = self._switch.set("Start", settle_time=settle_time) + status = self._switch.set("Start", settle_time=settle_time) return status def complete(self, settle_time=0.1) -> DeviceStatus: """ DDC just reads back whatever is available in the buffers""" sleep(settle_time) - status = DeviceStatus(self) + status = DeviceStatus(self) status.set_finished() return status - + def _collect(self, index=0): """ Force a readback of the data buffer @@ -1191,34 +1454,48 @@ class aa1AxisDriveDataCollection(Device): initial update event with the initial value but 0 timestamp. Theese old_values are invalid and must be filtered out. """ - + # Define wait until the busy flag goes down (excluding initial update) timestamp_ = 0 + def negEdge(*args, old_value, value, timestamp, **kwargs): - nonlocal timestamp_ - result = False if (timestamp_== 0) else (old_value == 1 and value == 0) - # print(f"\nBuffer1 status:\t{old_value} ({timestamp_}) to {value} ({timestamp}) Result: {result}") + nonlocal timestamp_ + result = False if (timestamp_ == 0) else (old_value == 1 and value == 0) + # print(f"\nBuffer1 status:\t{old_value} ({timestamp_}) to {value} ({timestamp}) Result: {result}") timestamp_ = timestamp return result - - if index==0: + + if index == 0: status = SubscriptionStatus(self._readstatus0, negEdge, settle_time=0.5) self._readback0.set(1).wait() - elif index==1: + elif index == 1: status = SubscriptionStatus(self._readstatus1, negEdge, settle_time=0.5) self._readback1.set(1).wait() - + # Start asynchronous readback status.wait() return status - def describe_collect(self) -> OrderedDict: ret = OrderedDict() - ret['buffer0'] = {'source': "internal", 'dtype': 'array', 'shape': [], 'units': '', 'lower_ctrl_limit': 0, 'upper_ctrl_limit': 0} - ret['buffer1'] = {'source': "internal", 'dtype': 'array', 'shape': [], 'units': '', 'lower_ctrl_limit': 0, 'upper_ctrl_limit': 0} + ret["buffer0"] = { + "source": "internal", + "dtype": "array", + "shape": [], + "units": "", + "lower_ctrl_limit": 0, + "upper_ctrl_limit": 0, + } + ret["buffer1"] = { + "source": "internal", + "dtype": "array", + "shape": [], + "units": "", + "lower_ctrl_limit": 0, + "upper_ctrl_limit": 0, + } return {self.name: ret} - + def collect(self) -> OrderedDict: self._collect(0).wait() @@ -1227,12 +1504,9 @@ class aa1AxisDriveDataCollection(Device): b0 = self._buffer0.value b1 = self._buffer1.value ret = OrderedDict() - ret["timestamps"] = {"buffer0": time.time(), "buffer1": time.time() } - ret["data"] = {"buffer0": b0, "buffer1": b1 } + ret["timestamps"] = {"buffer0": time.time(), "buffer1": time.time()} + ret["data"] = {"buffer0": b0, "buffer1": b1} yield ret - - - # Automatically start simulation if directly invoked @@ -1240,16 +1514,13 @@ if __name__ == "__main__": AA1_IOC_NAME = "X02DA-ES1-SMP1" AA1_AXIS_NAME = "ROTY" # Drive data collection - task = aa1Tasks(AA1_IOC_NAME+":TASK:", name="tsk") + task = aa1Tasks(AA1_IOC_NAME + ":TASK:", name="tsk") task.wait_for_connection() task.describe() ddc = aa1AxisDriveDataCollection("X02DA-ES1-SMP1:ROTY:DDC:", name="ddc") ddc.wait_for_connection() - globb = aa1GlobalVariableBindings(AA1_IOC_NAME+":VAR:", name="globb") + globb = aa1GlobalVariableBindings(AA1_IOC_NAME + ":VAR:", name="globb") globb.wait_for_connection() globb.describe() - mot = EpicsMotor(AA1_IOC_NAME+ ":" + AA1_AXIS_NAME, name="x") + mot = EpicsMotor(AA1_IOC_NAME + ":" + AA1_AXIS_NAME, name="x") mot.wait_for_connection() - - - diff --git a/ophyd_devices/epics/devices/aerotech/AerotechAutomation1Enums.py b/ophyd_devices/epics/devices/aerotech/AerotechAutomation1Enums.py index ac0f981..ce75eba 100644 --- a/ophyd_devices/epics/devices/aerotech/AerotechAutomation1Enums.py +++ b/ophyd_devices/epics/devices/aerotech/AerotechAutomation1Enums.py @@ -269,237 +269,235 @@ class AxisDataSignal: 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 - - - + 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 + 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 + 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 - - + 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, + 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 - + DedicatedOutput = 111 + AuxiliaryMarkerDifferential = 112 + AuxiliaryMarkerSingleEnded = 113 + + class XC4PsoOutputPin: - DedicatedOutput = 108 - AuxiliaryMarkerDifferential = 109 - AuxiliaryMarkerSingleEnded = 110 - - + DedicatedOutput = 108 + AuxiliaryMarkerDifferential = 109 + AuxiliaryMarkerSingleEnded = 110 + + """ # @brief Specifies the PSO distance input settings for each drive. class Automation1PsoDistanceInput: @@ -834,81 +832,70 @@ class Automation1PsoOutputPin: class DriveDataCaptureInput: - PositionCommand = 0 - PrimaryFeedback = 1 - AuxiliaryFeedback = 2 - AnalogInput0 = 3 - AnalogInput1 = 4 - AnalogInput2 = 5 - AnalogInput3 = 6 + 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 - - + 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, - - - - - - - - - + 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,)