From c2ea62fe0722955e33468a8dcb7fcb764adf0812 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 20 Sep 2023 18:15:47 -0300 Subject: [PATCH 001/309] DEV.ORBINTLK.ENH: add new methods to set enable state and use position and angle readings from interlock orbit core --- siriuspy/siriuspy/devices/orbit_interlock.py | 92 ++++++++++---------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index 41fcecbe0..e5e2fcf52 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -130,9 +130,6 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): """This device group the orbit interlock PVs from one BPM.""" PROPERTIES_DEFAULT = ( - # ============================================================== - # Basic properties - 'PosX-Mon', 'PosY-Mon', 'Sum-Mon', # ============================================================== # General # +++++++ @@ -186,6 +183,9 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): 'IntlkPosLowerLtc-Mon', 'IntlkPosUpperLtc-Mon', 'IntlkPosLowerLtcX-Mon', 'IntlkPosUpperLtcX-Mon', 'IntlkPosLowerLtcY-Mon', 'IntlkPosUpperLtcY-Mon', + # Position orbit interlock core measure + 'IntlkPosX-Mon', + 'IntlkPosY-Mon', # ============================================================= # Angular (interlock de ângulo) # +++++++++++++++++++++++++++++ @@ -221,6 +221,9 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): 'IntlkAngLowerLtc-Mon', 'IntlkAngUpperLtc-Mon', 'IntlkAngLowerLtcX-Mon', 'IntlkAngUpperLtcX-Mon', 'IntlkAngLowerLtcY-Mon', 'IntlkAngUpperLtcY-Mon', + # Angulation orbit interlock core measure + 'IntlkAngX-Mon', + 'IntlkAngY-Mon', # ============================================================ ) @@ -233,19 +236,24 @@ def __init__(self, devname, props2init='all'): _Device.__init__(self, devname, props2init=props2init) @property - def posx(self): - """Position X, Monit rate.""" - return self['PosX-Mon'] * self.CONV_NM2UM + def intlkposx(self): + """Orbit interlock core Position X.""" + return self['IntlkPosX-Mon'] * self.CONV_NM2UM + + @property + def intlkposy(self): + """Orbit interlock core Position Y.""" + return self['IntlkPosY-Mon'] * self.CONV_NM2UM @property - def posy(self): - """Position Y, Monit rate.""" - return self['PosY-Mon'] * self.CONV_NM2UM + def intlkangx(self): + """Orbit interlock core Angle X.""" + return self['IntlkAngX-Mon'] * self.CONV_NM2UM @property - def possum(self): - """Sum, Monit rate.""" - return self['Sum-Mon'] + def intlkangy(self): + """Orbit interlock core Angle Y.""" + return self['IntlkAngY-Mon'] * self.CONV_NM2UM @property def pair_down_up_bpms(self): @@ -624,6 +632,12 @@ def __init__(self, devname=None, props2init='all'): # --- general interlock --- + def set_gen_enable(self, value, timeout=TIMEOUT): + """Set enable state for BPM general interlock.""" + self._set_devices_propty(self.devices, 'IntlkEn-Sel', value) + return self._wait_devices_propty( + self.devices, 'IntlkEn-Sts', value, timeout=timeout) + def cmd_gen_enable(self, timeout=TIMEOUT): """Enable all BPM general interlock.""" for dev in self.devices: @@ -666,6 +680,12 @@ def gen_latch(self): # --- minimum sum threshold --- + def set_minsumthres_enable(self, value, timeout=TIMEOUT): + """Set enable state for BPM minimum sum interlock.""" + self._set_devices_propty(self.devices, 'IntlkMinSumEn-Sel', value) + return self._wait_devices_propty( + self.devices, 'IntlkMinSumEn-Sts', value, timeout=timeout) + def cmd_minsumthres_enable(self, timeout=TIMEOUT): """Enable all BPM minimum sum threshold.""" for dev in self.devices: @@ -697,6 +717,12 @@ def minsumthres(self, value): # --- position interlock --- + def set_pos_enable(self, value, timeout=TIMEOUT): + """Set enable state for BPM position interlock.""" + self._set_devices_propty(self.devices, 'IntlkPosEn-Sel', value) + return self._wait_devices_propty( + self.devices, 'IntlkPosEn-Sts', value, timeout=timeout) + def cmd_pos_enable(self, timeout=TIMEOUT): """Enable all BPM position interlock.""" for dev in self.devices: @@ -903,6 +929,12 @@ def pos_latch_upper_y(self): # --- angulation interlock --- + def set_ang_enable(self, value, timeout=TIMEOUT): + """Set enable state for BPM angulation interlock.""" + self._set_devices_propty(self.devices, 'IntlkAngEn-Sel', value) + return self._wait_devices_propty( + self.devices, 'IntlkAngEn-Sts', value, timeout=timeout) + def cmd_ang_enable(self, timeout=TIMEOUT): """Enable all BPM angulation interlock.""" for dev in self.devices: @@ -1107,32 +1139,6 @@ def ang_latch_upper_y(self): """ return _np.array([b.ang_latch_upper_y for b in self._devices]) - @property - def slow_orbit(self): - """Slow orbit vectors. - - Returns: - orbx (numpy.ndarray, 160): Horizontal Orbit. - orby (numpy.ndarray, 160): Vertical Orbit. - - """ - orbx, orby = [], [] - for bpm in self._devices: - orbx.append(bpm.posx) - orby.append(bpm.posy) - orbx = _np.array(orbx) - orby = _np.array(orby) - return orbx, orby - - @property - def possum(self): - """Sum vector, at Monit rate. - - Returns: - possum (numpy.ndarray, 160): Sum vector, at Monit rate. - """ - return _np.array([b.possum for b in self._devices]) - @property def position(self): """Position vectors. @@ -1144,9 +1150,8 @@ def position(self): posx (numpy.ndarray, 160): Horizontal Position. posy (numpy.ndarray, 160): Vertical Position. """ - orbx, orby = self.slow_orbit - posx = _np.array(self.calc_intlk_metric(orbx, metric='pos')) - posy = _np.array(self.calc_intlk_metric(orby, metric='pos')) + posx = _np.array([b.intlkposx for b in self._devices]) + posy = _np.array([b.intlkposy for b in self._devices]) return posx, posy @property @@ -1160,9 +1165,8 @@ def angulation(self): angx (numpy.ndarray, 160): Horizontal Angulation. angy (numpy.ndarray, 160): Vertical Angulation. """ - orbx, orby = self.slow_orbit - angx = _np.array(self.calc_intlk_metric(orbx, metric='ang')) - angy = _np.array(self.calc_intlk_metric(orby, metric='ang')) + angx = _np.array([b.intlkangx for b in self._devices]) + angy = _np.array([b.intlkangy for b in self._devices]) return angx, angy def _handle_thres_input(self, value): From 413b5216c84c4e8a4920e90a974f9995caf2cbc2 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 20 Sep 2023 19:03:07 -0300 Subject: [PATCH 002/309] DEV.ORBINLKT.ENH: rename minimum sum threshold methods --- siriuspy/siriuspy/devices/orbit_interlock.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index e5e2fcf52..e455ff295 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -680,20 +680,20 @@ def gen_latch(self): # --- minimum sum threshold --- - def set_minsumthres_enable(self, value, timeout=TIMEOUT): + def set_minsum_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM minimum sum interlock.""" self._set_devices_propty(self.devices, 'IntlkMinSumEn-Sel', value) return self._wait_devices_propty( self.devices, 'IntlkMinSumEn-Sts', value, timeout=timeout) - def cmd_minsumthres_enable(self, timeout=TIMEOUT): + def cmd_minsum_enable(self, timeout=TIMEOUT): """Enable all BPM minimum sum threshold.""" for dev in self.devices: dev.minsumthres_enable = 1 return self._wait_devices_propty( self.devices, 'IntlkMinSumEn-Sts', 1, timeout=timeout) - def cmd_minsumthres_disable(self, timeout=TIMEOUT): + def cmd_minsum_disable(self, timeout=TIMEOUT): """Disable all BPM minimum sum threshold.""" for dev in self.devices: dev.minsumthres_enable = 0 From 6ab37d7cb55920212a3fb194a4b95c64af385856 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 20 Sep 2023 19:05:24 -0300 Subject: [PATCH 003/309] WIP: orbit interlock ioc --- siriuspy/siriuspy/orbintlk/__init__.py | 1 + siriuspy/siriuspy/orbintlk/csdev.py | 216 +++++++++++++ siriuspy/siriuspy/orbintlk/main.py | 417 +++++++++++++++++++++++++ 3 files changed, 634 insertions(+) create mode 100644 siriuspy/siriuspy/orbintlk/__init__.py create mode 100644 siriuspy/siriuspy/orbintlk/csdev.py create mode 100644 siriuspy/siriuspy/orbintlk/main.py diff --git a/siriuspy/siriuspy/orbintlk/__init__.py b/siriuspy/siriuspy/orbintlk/__init__.py new file mode 100644 index 000000000..dc29d2c3b --- /dev/null +++ b/siriuspy/siriuspy/orbintlk/__init__.py @@ -0,0 +1 @@ +"""Orbit Interlock subpackage.""" diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py new file mode 100644 index 000000000..acd2875e5 --- /dev/null +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -0,0 +1,216 @@ +"""Define PVs, contants and properties of High Level FOFB.""" + +import os as _os + +from .. import csdev as _csdev +from ..search import BPMSearch as _BPMSearch +from ..diagbeam.bpm.csdev import Const as _csbpm + + +NR_BPM = 160 + + +# --- Enumeration Types --- + +class ETypes(_csdev.ETypes): + """Local enumerate types.""" + + STS_LBLS_BPMS = ( + 'Connected', + 'PosEnblSynced', 'AngEnblSynced', 'MinSumSynced', 'GlobEnblSynced', + 'PosLimsSynced', 'PosLimsSynced', 'MinSumLimsSynced') + STS_LBLS_EVG = ( + 'Connected', 'IntlkEnblSynced') + + +_et = ETypes # syntactic sugar + + +# --- Const class --- + +class Const(_csdev.Const): + """Const class defining Orbit Interlock constants.""" + + CONV_UM_2_NM = 1e3 + + DEF_TIMEOUT = 10 # [s] + DEF_TIMESLEEP = 0.1 # [s] + DEF_TIMEWAIT = 3 # [s] + + DEF_TIME2WAIT_DRYRUN = 10 # [s] + + State = _csdev.Const.register('State', _et.OFF_ON) + + def __init__(self): + """Class constructor.""" + + # bpm names and nicknames + self.bpm_names = _BPMSearch.get_names({'sec': 'SI', 'dev': 'BPM'}) + if NR_BPM != len(self.bpm_names): + raise ValueError('Inconsistent NR_BPM parameter!') + self.bpm_nicknames = _BPMSearch.get_nicknames(self.bpm_names) + + # bpm position along the ring + self.bpm_pos = _BPMSearch.get_positions(self.bpm_names) + + # bpm number + self.nr_bpms = len(self.bpm_names) + + # data folder + path = _os.path.join( + '/home', 'sirius', 'iocs-log', 'si-ap-orbintlk', 'data') + self.pos_enbl_fname = _os.path.join(path, 'pos_enbllist.enbl') + self.ang_enbl_fname = _os.path.join(path, 'ang_enbllist.enbl') + self.minsum_enbl_fname = _os.path.join(path, 'minsum_enbllist.enbl') + + self.limits = _os.path.join(path, 'limits.txt') + + def get_database(self): + """Return Soft IOC database.""" + pvs_database = { + # Global + 'Version-Cte': {'type': 'string', 'value': 'UNDEF'}, + 'Log-Mon': {'type': 'string', 'value': 'Starting...'}, + + 'State-Sel': { + 'type': 'enum', 'enums': _et.OFF_ON, + 'value': self.OffOn.Off}, + 'State-Sts': { + 'type': 'enum', 'enums': _et.OFF_ON, + 'value': self.OffOn.Off}, + 'BPMStatus-Mon': {'type': 'int', 'value': 0b1111111}, + 'EVGStatus-Mon': {'type': 'int', 'value': 0b11}, + + # Enable lists + 'BPMPosEnblList-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used in orbit position interlock'}, + 'BPMPosEnblList-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used in orbit position interlock'}, + + 'BPMAngEnblList-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used in orbit angle interlock'}, + 'BPMAngEnblList-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used in orbit angle interlock'}, + + 'BPMMinSumEnblList-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used with minimum sum threshold enabled'}, + 'BPMMinSumEnblList-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[1], + 'unit': 'BPM used with minimum sum threshold enabled'}, + + # Limits + 'PosMinLimX-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position minimum limits for X'}, + 'PosMinLimX-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position minimum limits for X'}, + 'PosMaxLimX-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position maximum limits for X'}, + 'PosMaxLimX-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position maximum limits for X'}, + + 'PosMinLimY-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position minimum limits for Y'}, + 'PosMinLimY-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position minimum limits for Y'}, + 'PosMaxLimY-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position maximum limits for Y'}, + 'PosMaxLimY-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'position maximum limits for Y'}, + + 'AngMinLimX-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle minimum limits for X'}, + 'AngMinLimX-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle minimum limits for X'}, + 'AngMaxLimX-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle maximum limits for X'}, + 'AngMaxLimX-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle maximum limits for X'}, + + 'AngMinLimY-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle minimum limits for Y'}, + 'AngMinLimY-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle minimum limits for Y'}, + 'AngMaxLimY-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle maximum limits for Y'}, + 'AngMaxLimY-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], + 'unit': 'angle maximum limits for Y'}, + + 'MinSumLim-SP': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], 'unit': 'minimum sum limits'}, + 'MinSumLim-RB': { + 'type': 'int', 'count': self.nr_bpms, + 'value': self.nr_bpms*[0], 'unit': 'minimum sum limits'}, + + # Reset + 'ResetBPMGen-Cmd': {'type': 'int', 'value': 0}, + 'ResetBPMPos-Cmd': {'type': 'int', 'value': 0}, + 'ResetBPMAng-Cmd': {'type': 'int', 'value': 0}, + 'ResetBPM-Cmd': {'type': 'int', 'value': 0}, + 'Reset-Cmd': {'type': 'int', 'value': 0}, + + # Acquisition + 'PsMtmAcqChannel-Sel': { + 'type': 'enum', 'value': _csbpm.AcqChan.FAcq, + 'enums': Const.AcqChan._fields}, + 'PsMtmAcqChannel-Sts': { + 'type': 'enum', 'value': _csbpm.AcqChan.FAcq, + 'enums': Const.AcqChan._fields}, + 'PsMtmAcqSamplesPre-SP': { + 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'PsMtmAcqSamplesPre-RB': { + 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'PsMtmAcqSamplesPost-SP': { + 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'PsMtmAcqSamplesPost-RB': { + 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'PsMtmAcqConfig-Cmd': {'type': 'int', 'value': 0}, + + # TODO: + # add commands to sync enable status and limits + } + pvs_database = _csdev.add_pvslist_cte(pvs_database) + return pvs_database diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py new file mode 100644 index 000000000..a637c02d7 --- /dev/null +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -0,0 +1,417 @@ +"""High Level FOFB main application.""" + +import os as _os +import logging as _log +import time as _time +from functools import partial as _part +import epics as _epics +import numpy as _np + +from ..util import update_bit as _updt_bit, get_bit as _get_bit +from ..epics import PV as _PV +from ..callbacks import Callback as _Callback +from ..envars import VACA_PREFIX as _vaca_prefix +from ..namesys import SiriusPVName as _PVName +from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ + EVG as _EVG + +from .csdev import Const as _Const, ETypes as _ETypes + + +class App(_Callback): + """High Level Orbit Interlock main application.""" + + SCAN_FREQUENCY = 1 # [Hz] + + def __init__(self, tests=False): + """Class constructor.""" + super().__init__() + self._const = _Const() + self._pvs_database = self._const.get_database() + self._init = False + + # internal states + self._state = self._const.OffOn.Off + self._bpm_status = self._pvs_database['BPMStatus-Mon']['value'] + self._evg_status = self._pvs_database['EVGStatus-Mon']['value'] + self._enable_lists = { + 'pos': _np.ones(self._const.nr_bpms, dtype=bool), + 'ang': _np.ones(self._const.nr_bpms, dtype=bool), + 'minsum': _np.ones(self._const.nr_bpms, dtype=bool), + } + self._limits = { + 'posx_min': _np.zeros(self._const.nr_bpms, dtype=float), + 'posx_max': _np.zeros(self._const.nr_bpms, dtype=float), + 'posy_min': _np.zeros(self._const.nr_bpms, dtype=float), + 'posy_max': _np.zeros(self._const.nr_bpms, dtype=float), + 'angx_min': _np.zeros(self._const.nr_bpms, dtype=float), + 'angx_max': _np.zeros(self._const.nr_bpms, dtype=float), + 'angy_min': _np.zeros(self._const.nr_bpms, dtype=float), + 'angy_max': _np.zeros(self._const.nr_bpms, dtype=float), + 'minsum': _np.zeros(self._const.nr_bpms, dtype=float), + } + self._acq_chan = self._pvs_database['PsMtmAcqChannel-Sel']['value'] + self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] + self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] + + # devices and connections + self._evg_dev = _EVG( + props2init=[ + 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', + 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts']) + + self._orbintlk_dev = _OrbitIntlk() + + self._fambpm_dev = _FamBPMs( + devname=_FamBPMs.DEVICES.SI, ispost_mortem=True, + props2init=[ + 'ACQChannel-Sel', 'ACQChannel-Sts', + 'ACQSamplesPre-SP', 'ACQSamplesPre-RB', + 'ACQSamplesPost-SP', 'ACQSamplesPost-RB', + 'ACQTriggerRep-Sel', 'ACQTriggerRep-Sts', + 'ACQTrigger-Sel', 'ACQTrigger-Sts', + 'ACQTriggerEvent-Sel', 'ACQTriggerEvent-Sts', + 'ACQStatus-Sts', + ]) + + havebeam_pvname = _PVName( + 'SI-Glob:AP-CurrInfo:StoredEBeam-Mon').substitute( + prefix=_vaca_prefix) + self._havebeam_pv = _PV( + havebeam_pvname, connection_timeout=0.05, + callback=self._callback_havebeam) + + # pvs to write methods + self.map_pv2write = { + 'State-Sel': self.set_state, + 'BPMPosEnblList-SP': _part(self.set_enbllist, 'pos'), + 'BPMAngEnblList-SP': _part(self.set_enbllist, 'ang'), + 'BPMMinSumEnblList-SP': _part(self.set_enbllist, 'minsum'), + 'PosMinLimX-SP': _part(self.set_intlk_lims, 'posx_min'), + 'PosMaxLimX-SP': _part(self.set_intlk_lims, 'posx_max'), + 'PosMinLimY-SP': _part(self.set_intlk_lims, 'posy_min'), + 'PosMaxLimY-SP': _part(self.set_intlk_lims, 'posy_max'), + 'AngMinLimX-SP': _part(self.set_intlk_lims, 'angx_min'), + 'AngMaxLimX-SP': _part(self.set_intlk_lims, 'angx_max'), + 'AngMinLimY-SP': _part(self.set_intlk_lims, 'angy_min'), + 'AngMaxLimY-SP': _part(self.set_intlk_lims, 'angy_max'), + 'MinSumLim-SP': _part(self.set_intlk_lims, 'minsum'), + 'ResetBPMGen-Cmd': _part(self.cmd_reset, 'bpm_gen'), + 'ResetBPMPos-Cmd': _part(self.cmd_reset, 'bpm_pos'), + 'ResetBPMAng-Cmd': _part(self.cmd_reset, 'bpm_ang'), + 'ResetBPM-Cmd': _part(self.cmd_reset, 'bpm_all'), + 'Reset-Cmd': _part(self.cmd_reset, 'all'), + 'PsMtmAcqChannel-Sel': self.set_acq_channel, + 'PsMtmAcqSamplesPre-SP': self.set_acq_nrspls_pre, + 'PsMtmAcqSamplesPost-SP': self.set_acq_nrspls_post, + 'PsMtmAcqConfig-Cmd': self.cmd_config_acq, + } + + # configuration scanning + self.quit = False + self.scanning = False + self.thread_check_configs = _epics.ca.CAThread( + target=self._check_configs, daemon=True) + self.thread_check_configs.start() + + def init_database(self): + """Set initial PV values.""" + pvn2vals = { + 'State-Sel': self._state, + 'State-Sts': self._state, + 'BPMStatus-Mon': self._bpm_status, + 'EVGStatus-Mon': self._evg_status, + 'PosMinLimX-SP': self._limits['posx_min'], + 'PosMinLimX-RB': self._limits['posx_min'], + 'PosMaxLimX-SP': self._limits['posx_max'], + 'PosMaxLimX-RB': self._limits['posx_max'], + 'PosMinLimY-SP': self._limits['posy_min'], + 'PosMinLimY-RB': self._limits['posy_min'], + 'PosMaxLimY-SP': self._limits['posy_max'], + 'PosMaxLimY-RB': self._limits['posy_max'], + 'AngMinLimX-SP': self._limits['angx_min'], + 'AngMinLimX-RB': self._limits['angx_min'], + 'AngMaxLimX-SP': self._limits['angx_max'], + 'AngMaxLimX-RB': self._limits['angx_max'], + 'AngMinLimY-SP': self._limits['angy_min'], + 'AngMinLimY-RB': self._limits['angy_min'], + 'AngMaxLimY-SP': self._limits['angy_max'], + 'AngMaxLimY-RB': self._limits['angy_max'], + 'MinSumLim-SP': self._limits['minsum'], + 'MinSumLim-RB': self._limits['minsum'], + 'ResetBPMGen-Cmd': 0, + 'ResetBPMPos-Cmd': 0, + 'ResetBPMAng-Cmd': 0, + 'ResetBPM-Cmd': 0, + 'Reset-Cmd': 0, + 'PsMtmAcqChannel-Sel': self._acq_chan, + 'PsMtmAcqChannel-Sts': self._acq_chan, + 'PsMtmAcqSamplesPre-SP': self._acq_spre, + 'PsMtmAcqSamplesPre-RB': self._acq_spre, + 'PsMtmAcqSamplesPost-SP': self._acq_spost, + 'PsMtmAcqSamplesPost-RB': self._acq_spost, + 'PsMtmAcqConfig-Cmd': 0, + } + for pvn, val in pvn2vals.items(): + self.run_callbacks(pvn, val) + + # load autosave data + # enable lists + for ilk in ['Pos', 'Ang', 'MinSum']: + okl = self._load_enbllist(ilk) + pvn = f'BPM{ilk}EnblList-SP' + enb = self._enable_lists[ilk] + self.run_callbacks(pvn, enb) + if not okl: + self.run_callbacks( + pvn.replace('SP', 'RB').replace('Sel', 'Sts'), enb) + self._update_log('Started.') + self._init = True + + @property + def pvs_database(self): + """Return pvs_database.""" + return self._pvs_database + + def process(self, interval): + """Sleep.""" + _time.sleep(interval) + + def read(self, reason): + """Read from IOC database.""" + value = None + return value + + def write(self, reason, value): + """Write value to reason and let callback update PV database.""" + _log.info('Write received for: %s --> %s', reason, str(value)) + if reason in self.map_pv2write.keys(): + status = self.map_pv2write[reason](value) + _log.info('%s Write for: %s --> %s', + str(status).upper(), reason, str(value)) + return status + _log.warning('PV %s does not have a set function.', reason) + return False + + @property + def evg_dev(self): + """EVG device.""" + return self._evg_dev + + @property + def orbintlk_dev(self): + """Orbit interlock device.""" + return self._orbintlk_dev + + @property + def fambpm_dev(self): + """FamBPMs device.""" + return self._fambpm_dev + + @property + def havebeam(self): + """Return if there is stored beam.""" + return self._havebeam_pv.connected and self._havebeam_pv.value + + # --- interlock control --- + + def set_state(self, value): + """Set orbit interlock state. + Configure global BPM interlock enable and EVG interlock enable.""" + if not 0 <= value < len(_ETypes.OFF_ON): + return False + + if value: + pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] + glob_en = _np.logical_or(pos, ang) + else: + glob_en = _np.zeros(self._const.nr_bpms) + if not self._orbintlk_dev.set_gen_enable(list(glob_en)): + self._update_log('ERR:Could not set BPM general') + self._update_log('ERR:interlock enable.') + return False + self._update_log('Configured BPM general interlock enable.') + + self._evg_dev['IntlkCtrlEnbl-Sel'] = value + if not self._evg_dev._wait( + 'IntlkCtrlEnbl-Sts', value, timeout=self._const.DEF_TIMEOUT): + self._update_log('ERR:Could not set EVG interlock enable.') + return False + self._update_log('Configured EVG interlock enable.') + + self._state = value + self.run_callbacks('LoopState-Sts', self._state) + return True + + # --- enable lists --- + + def set_enbllist(self, intlk, value): + """Set enable list for interlock type.""" + self._update_log('Setting {0:s} EnblList'.format(intlk.upper())) + + # check size + bkup = self._enable_lists[intlk] + new = _np.array(value, dtype=bool) + if bkup.size != new.size: + self._update_log( + 'ERR: Wrong {0:s} EnblList size.'.format(intlk.upper())) + return False + + self._enable_lists[intlk] = new + + # do not set enable lists and save to file in initialization + if self._init: + # handle devices enable configuration + fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') + fun(list(value)) + # set_gen_enable + + + # save to autosave files + self._save_enbllist(intlk, _np.array([value], dtype=bool)) + + # update readback pv + self.run_callbacks(intlk.upper()+'EnblList-RB', new) + return True + + def _load_enbllist(self, intlk): + filename = getattr(self._const, intlk+'_enbl_fname') + if not _os.path.isfile(filename): + return + okl = self.set_enbllist(intlk, _np.loadtxt(filename)) + if okl: + msg = f'Loaded {intlk} enable list!' + else: + msg = f'ERR:Problem loading {intlk} enable list from file.' + self._update_log(msg) + return okl + + def _save_enbllist(self, intlk, value): + try: + filename = getattr(self._const, intlk+'enbl_fname') + path = _os.path.split(filename)[0] + _os.makedirs(path, exist_ok=True) + _np.savetxt(filename, value) + except FileNotFoundError: + self._update_log( + f'WARN:Could not save {intlk} enable list to file.') + + # --- limits --- + + def set_intlk_lims(self, intlk_lim, value): + + + # --- callbacks --- + + def _callback_havebeam(self, value, **kws): + if not value and self._loop_state == self._const.LoopState.Closed: + self._update_log('FATAL:We do not have stored beam!') + self._update_log('FATAL:Opening FOFB loop...') + self.set_loop_state(self._const.LoopState.Open, abort=True) + + def _callback_intlk(self, pvname, value, **kws): + sub = _PVName(pvname).sub[:2] + old = self._intlk_values[pvname] + orbdis = _get_bit(value, 0) and not _get_bit(old, 0) + paclos = _get_bit(value, 1) and not _get_bit(old, 1) + self._intlk_values[pvname] = value + if value != 0: + pref = ('FATAL' if self._loop_state else 'WARN') + \ + ':Ctrlr.' + sub + ' detected ' + if orbdis: + self._update_log(pref + 'large orb.dist.!') + if paclos: + self._update_log(pref + 'packet loss!') + + if self._loop_state != self._const.LoopState.Closed: + return + + if self._thread_loopstate is None or \ + (self._thread_loopstate is not None and + not self._thread_loopstate.is_alive()) or \ + (self._thread_loopstate is not None and + self._thread_loopstate.is_alive() and + self._loop_state_lastsp != self._const.LoopState.Open): + self._update_log('FATAL:Opening FOFB loop...') + self.run_callbacks('LoopState-Sel', self._const.LoopState.Open) + self.run_callbacks('LoopState-Sts', self._const.LoopState.Open) + self.set_loop_state(self._const.LoopState.Open, abort=True) + + # --- auxiliary log methods --- + + def _update_log(self, msg): + if 'ERR' in msg: + _log.error(msg[4:]) + elif 'FATAL' in msg: + _log.error(msg[6:]) + elif 'WARN' in msg: + _log.warning(msg[5:]) + else: + _log.info(msg) + self.run_callbacks('Log-Mon', msg) + + # --- auxiliary status methods --- + + def _check_configs(self): + tplanned = 1.0/App.SCAN_FREQUENCY + while not self.quit: + if not self.scanning: + _time.sleep(tplanned) + continue + + _t0 = _time.time() + + # bpm status + value = 0 + if self._orbintlk_dev.connected: + idcs = _np.where(self.corr_enbllist[:-1] == 1)[0] + # PwrStateOn + state = self._const.OffOn.On + if not self._corrs_dev.check_pwrstate( + state, psindices=idcs, timeout=0.2): + value = _updt_bit(value, 1, 1) + # OpModeConfigured + opmode = self._corrs_dev.OPMODE_STS.manual \ + if self._loop_state == self._const.LoopState.Open \ + else self._corrs_dev.OPMODE_STS.fofb + if not self._corrs_dev.check_opmode( + opmode, psindices=idcs, timeout=0.2): + value = _updt_bit(value, 2, 1) + # AccFreezeConfigured + freeze = self._get_corrs_fofbacc_freeze_desired() + if not self._corrs_dev.check_fofbacc_freeze( + freeze, timeout=0.2): + value = _updt_bit(value, 3, 1) + # InvRespMatRowSynced + if not self._corrs_dev.check_invrespmat_row(self._pscoeffs): + value = _updt_bit(value, 4, 1) + # AccGainSynced + if not self._corrs_dev.check_fofbacc_gain(self._psgains): + value = _updt_bit(value, 5, 1) + # AccSatLimsSynced + chn, chl = self._const.ch_names, self._ch_maxacccurr + cvn, cvl = self._const.cv_names, self._cv_maxacccurr + isok = self._corrs_dev.check_fofbacc_satmax(chl, psnames=chn) + isok &= self._corrs_dev.check_fofbacc_satmin(-chl, psnames=chn) + isok &= self._corrs_dev.check_fofbacc_satmax(cvl, psnames=cvn) + isok &= self._corrs_dev.check_fofbacc_satmin(-cvl, psnames=cvn) + if not isok: + value = _updt_bit(value, 6, 1) + # AccDecimationSynced + dec = self._corr_accdec_val + if not self._corrs_dev.check_fofbacc_decimation(dec): + value = _updt_bit(value, 7, 1) + else: + value = 0b11111111 + + self._corr_status = value + self.run_callbacks('BPMStatus-Mon', self._corr_status) + + ttook = _time.time() - _t0 + tsleep = tplanned - ttook + if tsleep > 0: + _time.sleep(tsleep) + else: + _log.warning( + 'Corrector configuration check took more than planned... ' + '{0:.3f}/{1:.3f} s'.format(ttook, tplanned)) From 972054102d9f7bf73c67d49f08406da0fbb0cc13 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 27 Sep 2023 16:50:57 -0300 Subject: [PATCH 004/309] orbintlk.WIP: update devices and continue IOC main application implementation --- siriuspy/siriuspy/devices/orbit_interlock.py | 301 +++++++------ siriuspy/siriuspy/orbintlk/csdev.py | 86 ++-- siriuspy/siriuspy/orbintlk/main.py | 421 ++++++++++++------- 3 files changed, 489 insertions(+), 319 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index e455ff295..616a03fc7 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -132,96 +132,91 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): PROPERTIES_DEFAULT = ( # ============================================================== # General - # +++++++ + # ************************************************************** # General interlock enable: 'IntlkEn-Sel', 'IntlkEn-Sts', - # General interlock clear: - 'IntlkClr-Cmd', # maybe -Cmd? + # General interlock reset: + 'IntlkClr-Cmd', # Minimum sum threshold enable: - # Habilita interlock de órbita apenas quando threshold da soma - # ultrapassar o valor em "IntlkLmtMinSum-SP" + # Enable orbit interlock only when sum is higher than IntlkLmtMinSum-RB 'IntlkMinSumEn-Sel', 'IntlkMinSumEn-Sts', - # Minimum sum threshold (em contagens da Soma da taxa FAcq): + # Minimum sum threshold (sum counts in FAcq rate): 'IntlkLmtMinSum-SP', 'IntlkLmtMinSum-RB', - # Status Instantâneo: - # Interlock instântaneo, dificilmente será detectado com - # a implementação atual do gateware + # Instantaneous interlock, dificult to be checked in the current + # gateware implementation 'Intlk-Mon', - # Latch do interlock, limpo apenas acionando-se a PV "Clr" - # correspondente + # Latch interlock, clean only when respective "Clr" PV is triggered 'IntlkLtc-Mon', # =============================================================== - # Position (interlock de posição) - # +++++++++++++++++++++++++++++++++++++ + # Position Interlock # *************************************************************** - # Condição para interlock de posição: + # Condition for position interlock: # thres_min > (pos BPM downstream + pos BPM upstream)/2 or # thres_max < (pos BPM downstream + pos BPM upstream)/2 - # BPMs são agrupados 2 a 2 seguindo a ordem do feixe: + # BPMs are grouped 2 by 2 following the order seen by the beam: # - M1/M2 # - C1-1/C1-2 # - C2/C3-1 # - C3-2/C4 - # BPM upstream é sempre o "primeiro" BPM da dupla acima e BPM - # downstream é sempre o "segundo" BPM da dupla. + # upstream BPM is always the "first" BPM of the pairs above and + # downstream BPM is always the "second" BPM of the pair. # *************************************************************** # Position interlock enable: 'IntlkPosEn-Sel', 'IntlkPosEn-Sts', # Position interlock clear: 'IntlkPosClr-Cmd', - # Thresholds (em nm da taxa Monit1): + # Thresholds (nm, FAcq rate): 'IntlkLmtPosMaxX-SP', 'IntlkLmtPosMaxX-RB', 'IntlkLmtPosMinX-SP', 'IntlkLmtPosMinX-RB', 'IntlkLmtPosMaxY-SP', 'IntlkLmtPosMaxY-RB', 'IntlkLmtPosMinY-SP', 'IntlkLmtPosMinY-RB', - # Todos os interlocks são mascarados pelo "Enable" - # Status Instantâneo: + # All interlocks are masked by the "Enable" state + # Instantaneous Status: 'IntlkPosLower-Mon', 'IntlkPosUpper-Mon', # X ou Y 'IntlkPosLowerX-Mon', 'IntlkPosUpperX-Mon', # X 'IntlkPosLowerY-Mon', 'IntlkPosUpperY-Mon', # Y - # Status Latch, limpo apenas acionando-se a PV "Clr" correspondente: + # Latch Status, clean only when respective "Clr" PV is triggered 'IntlkPosLowerLtc-Mon', 'IntlkPosUpperLtc-Mon', 'IntlkPosLowerLtcX-Mon', 'IntlkPosUpperLtcX-Mon', 'IntlkPosLowerLtcY-Mon', 'IntlkPosUpperLtcY-Mon', - # Position orbit interlock core measure + # Position measure from orbit interlock core 'IntlkPosX-Mon', 'IntlkPosY-Mon', # ============================================================= - # Angular (interlock de ângulo) - # +++++++++++++++++++++++++++++ + # Angle Interlock # ************************************************************* - # Condição para interlock de ângulo: - # thres_min > (posição BPM downstream - posição BPM upstream) or - # thres_max < (posição BPM downstream - posição BPM upstream) - # BPMs são agrupados 2 a 2 seguindo a ordem do feixe: + # Condition for angle interlock: + # thres_min > (pos BPM downstream - pos BPM upstream) or + # thres_max < (pos BPM downstream - pos BPM upstream) + # BPMs are grouped 2 by 2 following the order seen by the beam: # - M1/M2 # - C1-1/C1-2 # - C2/C3-1 # - C3-2/C4 - # BPM upstream é sempre o "primeiro" BPM da dupla acima e BPM - # downstream é sempre o "segundo" BPM da dupla. + # upstream BPM is always the "first" BPM of the pairs above and + # downstream BPM is always the "second" BPM of the pair. # ************************************************************ - # Angulation interlock enable: + # Angle interlock enable: 'IntlkAngEn-Sel', 'IntlkAngEn-Sts', - # Angulation interlock clear: + # Angle interlock clear: 'IntlkAngClr-Cmd', - # Thresholds (em rad.nm da taxa FAcq). - # Thresholds devem ser calculados como ângulo (em rad) - # entre os 2 BPMs adjacentes * distância (em nm) entre eles): + # Thresholds (rad.nm, FAcq rate). + # Thresholds must be calculated as angle (rad) + # between the 2 adjacent BPMs * distance (nm) between them: 'IntlkLmtAngMaxX-SP', 'IntlkLmtAngMaxX-RB', 'IntlkLmtAngMinX-SP', 'IntlkLmtAngMinX-RB', 'IntlkLmtAngMaxY-SP', 'IntlkLmtAngMaxY-RB', 'IntlkLmtAngMinY-SP', 'IntlkLmtAngMinY-RB', - # Todos os interlocks são mascarados pelo "Enable" - # Status Instantâneo: + # All interlocks are masked by the "Enable" state + # Intantaneous Status 'IntlkAngLower-Mon', 'IntlkAngUpper-Mon', 'IntlkAngLowerX-Mon', 'IntlkAngUpperX-Mon', # X 'IntlkAngLowerY-Mon', 'IntlkAngUpperY-Mon', # Y - # Status Latch, limpo apenas acionando-se a PV "Clr" correspondente: + # Latch Status, clean only when respective "Clr" PV is triggered 'IntlkAngLowerLtc-Mon', 'IntlkAngUpperLtc-Mon', 'IntlkAngLowerLtcX-Mon', 'IntlkAngUpperLtcX-Mon', 'IntlkAngLowerLtcY-Mon', 'IntlkAngUpperLtcY-Mon', - # Angulation orbit interlock core measure + # Angle measure from orbit interlock core 'IntlkAngX-Mon', 'IntlkAngY-Mon', # ============================================================ @@ -289,26 +284,26 @@ def gen_latch(self): # --- minimum sum threshold --- @property - def minsumthres_enable(self): + def minsum_enable(self): """ Minimum sum threshold enable. - If enabled, generate orbit interlock only when sum threshold exceeds - value in 'minsumthres' property. + If enabled, generate orbit interlock only when sum exceeds + value in 'minsum_thres' property. """ return self['IntlkMinSumEn-Sts'] - @minsumthres_enable.setter - def minsumthres_enable(self, value): + @minsum_enable.setter + def minsum_enable(self, value): self['IntlkMinSumEn-Sel'] = int(value) @property - def minsumthres(self): + def minsum_thres(self): """Minimum sum threshold [sum count, FAcq rate].""" return self['IntlkLmtMinSum-RB'] - @minsumthres.setter - def minsumthres(self, value): + @minsum_thres.setter + def minsum_thres(self, value): self['IntlkLmtMinSum-SP'] = int(value) # --- position interlock --- @@ -328,39 +323,39 @@ def cmd_reset_pos(self): return True @property - def pos_thresminx(self): + def pos_x_min_thres(self): """Minimum X position threshold.""" return self['IntlkLmtPosMinX-RB'] - @pos_thresminx.setter - def pos_thresminx(self, value): + @pos_x_min_thres.setter + def pos_x_min_thres(self, value): self['IntlkLmtPosMinX-SP'] = value @property - def pos_thresmaxx(self): + def pos_x_max_thres(self): """Maximum X position threshold.""" return self['IntlkLmtPosMaxX-RB'] - @pos_thresmaxx.setter - def pos_thresmaxx(self, value): + @pos_x_max_thres.setter + def pos_x_max_thres(self, value): self['IntlkLmtPosMaxX-SP'] = value @property - def pos_thresminy(self): + def pos_y_min_thres(self): """Minimum Y position threshold.""" return self['IntlkLmtPosMinY-RB'] - @pos_thresminy.setter - def pos_thresminy(self, value): + @pos_y_min_thres.setter + def pos_y_min_thres(self, value): self['IntlkLmtPosMinY-SP'] = value @property - def pos_thresmaxy(self): + def pos_y_max_thres(self): """Maximum Y position threshold.""" return self['IntlkLmtPosMaxY-RB'] - @pos_thresmaxy.setter - def pos_thresmaxy(self, value): + @pos_y_max_thres.setter + def pos_y_max_thres(self, value): self['IntlkLmtPosMaxY-SP'] = value @property @@ -476,39 +471,39 @@ def cmd_reset_ang(self): return True @property - def ang_thresminx(self): + def ang_x_min_thres(self): """Minimum X angulation threshold.""" return self['IntlkLmtAngMinX-RB'] - @ang_thresminx.setter - def ang_thresminx(self, value): + @ang_x_min_thres.setter + def ang_x_min_thres(self, value): self['IntlkLmtAngMinX-SP'] = value @property - def ang_thresmaxx(self): + def ang_x_max_thres(self): """Maximum X angulation threshold.""" return self['IntlkLmtAngMaxX-RB'] - @ang_thresmaxx.setter - def ang_thresmaxx(self, value): + @ang_x_max_thres.setter + def ang_x_max_thres(self, value): self['IntlkLmtAngMaxX-SP'] = value @property - def ang_thresminy(self): + def ang_y_min_thres(self): """Minimum Y angulation threshold.""" return self['IntlkLmtAngMinY-RB'] - @ang_thresminy.setter - def ang_thresminy(self, value): + @ang_y_min_thres.setter + def ang_y_min_thres(self, value): self['IntlkLmtAngMinY-SP'] = value @property - def ang_thresmaxy(self): + def ang_y_max_thres(self): """Maximum Y angulation threshold.""" return self['IntlkLmtAngMaxY-RB'] - @ang_thresmaxy.setter - def ang_thresmaxy(self, value): + @ang_y_max_thres.setter + def ang_y_max_thres(self, value): self['IntlkLmtAngMaxY-SP'] = value @property @@ -632,6 +627,16 @@ def __init__(self, devname=None, props2init='all'): # --- general interlock --- + @property + def gen_enable(self): + """General interlock enable. + + Returns: + enbl (numpy.ndarray, 160): + enable state for each BPM. + """ + return _np.array([b.gen_enable for b in self._devices]) + def set_gen_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM general interlock.""" self._set_devices_propty(self.devices, 'IntlkEn-Sel', value) @@ -678,7 +683,17 @@ def gen_latch(self): """ return _np.array([b.gen_latch for b in self._devices]) - # --- minimum sum threshold --- + # --- minimum sum threshold --- + + @property + def minsum_enable(self): + """Minimum sum threshold enable. + + Returns: + enbl (numpy.ndarray, 160): + enable state for each BPM. + """ + return _np.array([b.gen_enable for b in self._devices]) def set_minsum_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM minimum sum interlock.""" @@ -689,34 +704,44 @@ def set_minsum_enable(self, value, timeout=TIMEOUT): def cmd_minsum_enable(self, timeout=TIMEOUT): """Enable all BPM minimum sum threshold.""" for dev in self.devices: - dev.minsumthres_enable = 1 + dev.minsum_enable = 1 return self._wait_devices_propty( self.devices, 'IntlkMinSumEn-Sts', 1, timeout=timeout) def cmd_minsum_disable(self, timeout=TIMEOUT): """Disable all BPM minimum sum threshold.""" for dev in self.devices: - dev.minsumthres_enable = 0 + dev.minsum_enable = 0 return self._wait_devices_propty( self.devices, 'IntlkMinSumEn-Sts', 0, timeout=timeout) @property - def minsumthres(self): + def minsum_thres(self): """Minimum sum thresholds. Returns: thres (numpy.ndarray, 160): min.sum threshold for each BPM. """ - return _np.array([b.minsumthres for b in self._devices]) + return _np.array([b.minsum_thres for b in self._devices]) - @minsumthres.setter - def minsumthres(self, value): + def set_minsum_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.minsumthres = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtMinSum-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtMinSum-RB', value, timeout=timeout) # --- position interlock --- + @property + def pos_enable(self): + """Position interlock enable. + + Returns: + enbl (numpy.ndarray, 160): + enable state for each BPM. + """ + return _np.array([b.pos_enable for b in self._devices]) + def set_pos_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM position interlock.""" self._set_devices_propty(self.devices, 'IntlkPosEn-Sel', value) @@ -744,68 +769,68 @@ def cmd_reset_pos(self): return True @property - def pos_thresminx(self): + def pos_x_min_thres(self): """Minimum x position thresholds. Returns: thres (numpy.ndarray, 160): min. x position threshold for each BPM. """ - return _np.array([b.pos_thresminx for b in self._devices]) + return _np.array([b.pos_x_min_thres for b in self._devices]) - @pos_thresminx.setter - def pos_thresminx(self, value): + def set_pos_x_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.pos_thresminx = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtPosMinX-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtPosMinX-RB', value, timeout=timeout) @property - def pos_thresmaxx(self): + def pos_x_max_thres(self): """Maximum x position thresholds. Returns: thres (numpy.ndarray, 160): max. x position threshold for each BPM. """ - return _np.array([b.pos_thresmaxx for b in self._devices]) + return _np.array([b.pos_x_max_thres for b in self._devices]) - @pos_thresmaxx.setter - def pos_thresmaxx(self, value): + def set_pos_x_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.pos_thresmaxx = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtPosMaxX-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtPosMaxX-RB', value, timeout=timeout) @property - def pos_thresminy(self): + def pos_y_min_thres(self): """Minimum y position thresholds. Returns: thres (numpy.ndarray, 160): min. y position threshold for each BPM. """ - return _np.array([b.pos_thresminy for b in self._devices]) + return _np.array([b.pos_y_min_thres for b in self._devices]) - @pos_thresminy.setter - def pos_thresminy(self, value): + def set_pos_y_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.pos_thresminy = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtPosMinY-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtPosMinY-RB', value, timeout=timeout) @property - def pos_thresmaxy(self): + def pos_y_max_thres(self): """Maximum y position thresholds. Returns: thres (numpy.ndarray, 160): max. y position threshold for each BPM. """ - return _np.array([b.pos_thresmaxy for b in self._devices]) + return _np.array([b.pos_y_max_thres for b in self._devices]) - @pos_thresmaxy.setter - def pos_thresmaxy(self, value): + def set_pos_y_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.pos_thresmaxy = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtPosMaxY-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtPosMaxY-RB', value, timeout=timeout) @property def pos_inst_lower(self): @@ -929,6 +954,16 @@ def pos_latch_upper_y(self): # --- angulation interlock --- + @property + def ang_enable(self): + """Angle interlock enable. + + Returns: + enbl (numpy.ndarray, 160): + enable state for each BPM. + """ + return _np.array([b.ang_enable for b in self._devices]) + def set_ang_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM angulation interlock.""" self._set_devices_propty(self.devices, 'IntlkAngEn-Sel', value) @@ -956,68 +991,68 @@ def cmd_reset_ang(self): return True @property - def ang_thresminx(self): + def ang_x_min_thres(self): """Minimum x angulation thresholds. Returns: thres (numpy.ndarray, 160): min. x angulation threshold for each BPM. """ - return _np.array([b.ang_thresminx for b in self._devices]) + return _np.array([b.ang_x_min_thres for b in self._devices]) - @ang_thresminx.setter - def ang_thresminx(self, value): + def set_ang_x_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.ang_thresminx = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtAngMinX-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtAngMinX-RB', value, timeout=timeout) @property - def ang_thresmaxx(self): + def ang_x_max_thres(self): """Maximum x angulation thresholds. Returns: thres (numpy.ndarray, 160): max. x angulation threshold for each BPM. """ - return _np.array([b.ang_thresmaxx for b in self._devices]) + return _np.array([b.ang_x_max_thres for b in self._devices]) - @ang_thresmaxx.setter - def ang_thresmaxx(self, value): + def set_ang_x_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.ang_thresmaxx = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtAngMaxX-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtAngMaxX-RB', value, timeout=timeout) @property - def ang_thresminy(self): + def ang_y_min_thres(self): """Minimum y angulation thresholds. Returns: thres (numpy.ndarray, 160): min. y angulation threshold for each BPM. """ - return _np.array([b.ang_thresminy for b in self._devices]) + return _np.array([b.ang_y_min_thres for b in self._devices]) - @ang_thresminy.setter - def ang_thresminy(self, value): + def set_ang_y_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.ang_thresminy = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtAngMinY-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtAngMinY-RB', value, timeout=timeout) @property - def ang_thresmaxy(self): + def ang_y_max_thres(self): """Maximum y angulation thresholds. Returns: thres (numpy.ndarray, 160): max. y angulation threshold for each BPM. """ - return _np.array([b.ang_thresmaxy for b in self._devices]) + return _np.array([b.ang_y_max_thres for b in self._devices]) - @ang_thresmaxy.setter - def ang_thresmaxy(self, value): + def set_ang_y_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) - for idx, dev in enumerate(self.devices): - dev.ang_thresmaxy = value[idx] + self._set_devices_propty(self.devices, 'IntlkLmtAngMaxY-SP', value) + return self._wait_devices_propty( + self.devices, 'IntlkLmtAngMaxY-RB', value, timeout=timeout) @property def ang_inst_lower(self): @@ -1155,15 +1190,15 @@ def position(self): return posx, posy @property - def angulation(self): - """Angulation vectors. + def angle(self): + """Angle vectors. - Angulation at each BPM is defined as: + Angle at each BPM is defined as: (posição BPM downstream - posição BPM upstream) Returns: - angx (numpy.ndarray, 160): Horizontal Angulation. - angy (numpy.ndarray, 160): Vertical Angulation. + angx (numpy.ndarray, 160): Horizontal Angle. + angy (numpy.ndarray, 160): Vertical Angle. """ angx = _np.array([b.intlkangx for b in self._devices]) angy = _np.array([b.intlkangy for b in self._devices]) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index acd2875e5..94e438e4e 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -1,4 +1,4 @@ -"""Define PVs, contants and properties of High Level FOFB.""" +"""Define PVs, constants and properties of High Level Orbit Interlock app.""" import os as _os @@ -17,8 +17,8 @@ class ETypes(_csdev.ETypes): STS_LBLS_BPMS = ( 'Connected', - 'PosEnblSynced', 'AngEnblSynced', 'MinSumSynced', 'GlobEnblSynced', - 'PosLimsSynced', 'PosLimsSynced', 'MinSumLimsSynced') + 'PosEnblSynced', 'AngEnblSynced', 'MinSumEnblSynced', 'GlobEnblSynced', + 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced') STS_LBLS_EVG = ( 'Connected', 'IntlkEnblSynced') @@ -39,7 +39,9 @@ class Const(_csdev.Const): DEF_TIME2WAIT_DRYRUN = 10 # [s] - State = _csdev.Const.register('State', _et.OFF_ON) + AcqChan = _csbpm.AcqChan + AcqTrigTyp = _csbpm.AcqTrigTyp + AcqRepeat = _csbpm.AcqRepeat def __init__(self): """Class constructor.""" @@ -63,7 +65,15 @@ def __init__(self): self.ang_enbl_fname = _os.path.join(path, 'ang_enbllist.enbl') self.minsum_enbl_fname = _os.path.join(path, 'minsum_enbllist.enbl') - self.limits = _os.path.join(path, 'limits.txt') + self.pos_x_min_lim_fname = _os.path.join(path, 'pos_x_min.lim') + self.pos_x_max_lim_fname = _os.path.join(path, 'pos_x_max.lim') + self.pos_y_min_lim_fname = _os.path.join(path, 'pos_y_min.lim') + self.pos_y_max_lim_fname = _os.path.join(path, 'pos_y_max.lim') + self.ang_x_min_lim_fname = _os.path.join(path, 'ang_x_min.lim') + self.ang_x_max_lim_fname = _os.path.join(path, 'ang_x_max.lim') + self.ang_y_min_lim_fname = _os.path.join(path, 'ang_y_min.lim') + self.ang_y_max_lim_fname = _os.path.join(path, 'ang_y_max.lim') + self.minsum_lim_fname = _os.path.join(path, 'minsum.lim') def get_database(self): """Return Soft IOC database.""" @@ -72,108 +82,108 @@ def get_database(self): 'Version-Cte': {'type': 'string', 'value': 'UNDEF'}, 'Log-Mon': {'type': 'string', 'value': 'Starting...'}, - 'State-Sel': { - 'type': 'enum', 'enums': _et.OFF_ON, - 'value': self.OffOn.Off}, - 'State-Sts': { - 'type': 'enum', 'enums': _et.OFF_ON, - 'value': self.OffOn.Off}, - 'BPMStatus-Mon': {'type': 'int', 'value': 0b1111111}, + 'Enable-Sel': { + 'type': 'enum', 'enums': _et.DSBL_ENBL, + 'value': self.DsblEnbl.Dsbl}, + 'Enable-Sts': { + 'type': 'enum', 'enums': _et.DSBL_ENBL, + 'value': self.DsblEnbl.Dsbl}, + 'BPMStatus-Mon': {'type': 'int', 'value': 0b11111111}, 'EVGStatus-Mon': {'type': 'int', 'value': 0b11}, # Enable lists - 'BPMPosEnblList-SP': { + 'PosEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used in orbit position interlock'}, - 'BPMPosEnblList-RB': { + 'PosEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used in orbit position interlock'}, - 'BPMAngEnblList-SP': { + 'AngEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used in orbit angle interlock'}, - 'BPMAngEnblList-RB': { + 'AngEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used in orbit angle interlock'}, - 'BPMMinSumEnblList-SP': { + 'MinSumEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used with minimum sum threshold enabled'}, - 'BPMMinSumEnblList-RB': { + 'MinSumEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[1], 'unit': 'BPM used with minimum sum threshold enabled'}, # Limits - 'PosMinLimX-SP': { + 'PosXMinLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for X'}, - 'PosMinLimX-RB': { + 'PosXMinLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for X'}, - 'PosMaxLimX-SP': { + 'PosXMaxLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for X'}, - 'PosMaxLimX-RB': { + 'PosXMaxLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for X'}, - 'PosMinLimY-SP': { + 'PosYMinLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for Y'}, - 'PosMinLimY-RB': { + 'PosYMinLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for Y'}, - 'PosMaxLimY-SP': { + 'PosYMaxLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for Y'}, - 'PosMaxLimY-RB': { + 'PosYMaxLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for Y'}, - 'AngMinLimX-SP': { + 'AngXMinLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for X'}, - 'AngMinLimX-RB': { + 'AngXMinLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for X'}, - 'AngMaxLimX-SP': { + 'AngXMaxLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for X'}, - 'AngMaxLimX-RB': { + 'AngXMaxLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for X'}, - 'AngMinLimY-SP': { + 'AngYMinLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for Y'}, - 'AngMinLimY-RB': { + 'AngYMinLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for Y'}, - 'AngMaxLimY-SP': { + 'AngYMaxLim-SP': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for Y'}, - 'AngMaxLimY-RB': { + 'AngYMaxLim-RB': { 'type': 'int', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for Y'}, @@ -194,11 +204,11 @@ def get_database(self): # Acquisition 'PsMtmAcqChannel-Sel': { - 'type': 'enum', 'value': _csbpm.AcqChan.FAcq, - 'enums': Const.AcqChan._fields}, + 'type': 'enum', 'value': self.AcqChan.FAcq, + 'enums': self.AcqChan._fields}, 'PsMtmAcqChannel-Sts': { - 'type': 'enum', 'value': _csbpm.AcqChan.FAcq, - 'enums': Const.AcqChan._fields}, + 'type': 'enum', 'value': self.AcqChan.FAcq, + 'enums': self.AcqChan._fields}, 'PsMtmAcqSamplesPre-SP': { 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqSamplesPre-RB': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index a637c02d7..c3cde9db1 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1,4 +1,4 @@ -"""High Level FOFB main application.""" +"""High Level Orbit Interlock main application.""" import os as _os import logging as _log @@ -23,9 +23,10 @@ class App(_Callback): SCAN_FREQUENCY = 1 # [Hz] - def __init__(self, tests=False): + def __init__(self, tests=True): """Class constructor.""" super().__init__() + self._is_dry_run = tests self._const = _Const() self._pvs_database = self._const.get_database() self._init = False @@ -40,25 +41,30 @@ def __init__(self, tests=False): 'minsum': _np.ones(self._const.nr_bpms, dtype=bool), } self._limits = { - 'posx_min': _np.zeros(self._const.nr_bpms, dtype=float), - 'posx_max': _np.zeros(self._const.nr_bpms, dtype=float), - 'posy_min': _np.zeros(self._const.nr_bpms, dtype=float), - 'posy_max': _np.zeros(self._const.nr_bpms, dtype=float), - 'angx_min': _np.zeros(self._const.nr_bpms, dtype=float), - 'angx_max': _np.zeros(self._const.nr_bpms, dtype=float), - 'angy_min': _np.zeros(self._const.nr_bpms, dtype=float), - 'angy_max': _np.zeros(self._const.nr_bpms, dtype=float), - 'minsum': _np.zeros(self._const.nr_bpms, dtype=float), + 'pos_x_min': _np.zeros(self._const.nr_bpms, dtype=int), + 'pos_x_max': _np.zeros(self._const.nr_bpms, dtype=int), + 'pos_y_min': _np.zeros(self._const.nr_bpms, dtype=int), + 'pos_y_max': _np.zeros(self._const.nr_bpms, dtype=int), + 'ang_x_min': _np.zeros(self._const.nr_bpms, dtype=int), + 'ang_x_max': _np.zeros(self._const.nr_bpms, dtype=int), + 'ang_y_min': _np.zeros(self._const.nr_bpms, dtype=int), + 'ang_y_max': _np.zeros(self._const.nr_bpms, dtype=int), + 'minsum': _np.zeros(self._const.nr_bpms, dtype=int), } self._acq_chan = self._pvs_database['PsMtmAcqChannel-Sel']['value'] self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] + self._thread_acq = None # devices and connections self._evg_dev = _EVG( props2init=[ 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', - 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts']) + 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts', + 'IntlkEvtStatus-Mon']) + self._evg_intlk_pv = self._evg_dev.pv_object('IntlkEvtStatus-Mon') # TODO> confirmar com maurício se é essa PV mesmo + self._evg_intlk_pv.auto_monitor = True + self._evg_intlk_pv.add_callback(self._callback_intlk) self._orbintlk_dev = _OrbitIntlk() @@ -74,27 +80,20 @@ def __init__(self, tests=False): 'ACQStatus-Sts', ]) - havebeam_pvname = _PVName( - 'SI-Glob:AP-CurrInfo:StoredEBeam-Mon').substitute( - prefix=_vaca_prefix) - self._havebeam_pv = _PV( - havebeam_pvname, connection_timeout=0.05, - callback=self._callback_havebeam) - # pvs to write methods self.map_pv2write = { - 'State-Sel': self.set_state, - 'BPMPosEnblList-SP': _part(self.set_enbllist, 'pos'), - 'BPMAngEnblList-SP': _part(self.set_enbllist, 'ang'), - 'BPMMinSumEnblList-SP': _part(self.set_enbllist, 'minsum'), - 'PosMinLimX-SP': _part(self.set_intlk_lims, 'posx_min'), - 'PosMaxLimX-SP': _part(self.set_intlk_lims, 'posx_max'), - 'PosMinLimY-SP': _part(self.set_intlk_lims, 'posy_min'), - 'PosMaxLimY-SP': _part(self.set_intlk_lims, 'posy_max'), - 'AngMinLimX-SP': _part(self.set_intlk_lims, 'angx_min'), - 'AngMaxLimX-SP': _part(self.set_intlk_lims, 'angx_max'), - 'AngMinLimY-SP': _part(self.set_intlk_lims, 'angy_min'), - 'AngMaxLimY-SP': _part(self.set_intlk_lims, 'angy_max'), + 'Enable-Sel': self.set_enable, + 'PosEnblList-SP': _part(self.set_enbllist, 'pos'), + 'AngEnblList-SP': _part(self.set_enbllist, 'ang'), + 'MinSumEnblList-SP': _part(self.set_enbllist, 'minsum'), + 'PosXMinLim-SP': _part(self.set_intlk_lims, 'pos_x_min'), + 'PosXMaxLim-SP': _part(self.set_intlk_lims, 'pos_x_max'), + 'PosYMinLim-SP': _part(self.set_intlk_lims, 'pos_y_min'), + 'PosYMaxLim-SP': _part(self.set_intlk_lims, 'pos_y_max'), + 'AngXMinLim-SP': _part(self.set_intlk_lims, 'ang_x_min'), + 'AngXMaxLim-SP': _part(self.set_intlk_lims, 'ang_x_max'), + 'AngYMinLim-SP': _part(self.set_intlk_lims, 'ang_y_min'), + 'AngYMaxLim-SP': _part(self.set_intlk_lims, 'ang_y_max'), 'MinSumLim-SP': _part(self.set_intlk_lims, 'minsum'), 'ResetBPMGen-Cmd': _part(self.cmd_reset, 'bpm_gen'), 'ResetBPMPos-Cmd': _part(self.cmd_reset, 'bpm_pos'), @@ -104,7 +103,7 @@ def __init__(self, tests=False): 'PsMtmAcqChannel-Sel': self.set_acq_channel, 'PsMtmAcqSamplesPre-SP': self.set_acq_nrspls_pre, 'PsMtmAcqSamplesPost-SP': self.set_acq_nrspls_post, - 'PsMtmAcqConfig-Cmd': self.cmd_config_acq, + 'PsMtmAcqConfig-Cmd': self.cmd_acq_config, } # configuration scanning @@ -117,28 +116,10 @@ def __init__(self, tests=False): def init_database(self): """Set initial PV values.""" pvn2vals = { - 'State-Sel': self._state, - 'State-Sts': self._state, + 'Enable-Sel': self._state, + 'Enable-Sts': self._state, 'BPMStatus-Mon': self._bpm_status, 'EVGStatus-Mon': self._evg_status, - 'PosMinLimX-SP': self._limits['posx_min'], - 'PosMinLimX-RB': self._limits['posx_min'], - 'PosMaxLimX-SP': self._limits['posx_max'], - 'PosMaxLimX-RB': self._limits['posx_max'], - 'PosMinLimY-SP': self._limits['posy_min'], - 'PosMinLimY-RB': self._limits['posy_min'], - 'PosMaxLimY-SP': self._limits['posy_max'], - 'PosMaxLimY-RB': self._limits['posy_max'], - 'AngMinLimX-SP': self._limits['angx_min'], - 'AngMinLimX-RB': self._limits['angx_min'], - 'AngMaxLimX-SP': self._limits['angx_max'], - 'AngMaxLimX-RB': self._limits['angx_max'], - 'AngMinLimY-SP': self._limits['angy_min'], - 'AngMinLimY-RB': self._limits['angy_min'], - 'AngMaxLimY-SP': self._limits['angy_max'], - 'AngMaxLimY-RB': self._limits['angy_max'], - 'MinSumLim-SP': self._limits['minsum'], - 'MinSumLim-RB': self._limits['minsum'], 'ResetBPMGen-Cmd': 0, 'ResetBPMPos-Cmd': 0, 'ResetBPMAng-Cmd': 0, @@ -156,15 +137,34 @@ def init_database(self): self.run_callbacks(pvn, val) # load autosave data + # enable lists for ilk in ['Pos', 'Ang', 'MinSum']: okl = self._load_enbllist(ilk) - pvn = f'BPM{ilk}EnblList-SP' + pvn = f'{ilk}EnblList' enb = self._enable_lists[ilk] - self.run_callbacks(pvn, enb) + self.run_callbacks(pvn+'-SP', enb) if not okl: - self.run_callbacks( - pvn.replace('SP', 'RB').replace('Sel', 'Sts'), enb) + self.run_callbacks(pvn+'-RB', enb) + + # limits + for ilk in ['Pos', 'Ang']: + for pln in ['X', 'Y']: + for lim in ['Min', 'Max']: + atn = f'{ilk}_{pln}_{lim}'.lower() + pvn = f'{ilk}{pln}{lim}Lim' + okl = self._load_limits(atn) + val = self._limits[atn] + self.run_callbacks(pvn+'-SP', val) + if not okl: + self.run_callbacks(pvn+'-RB', val) + + okl = self._load_limits('minsum') + val = self._limits['minsum'] + self.run_callbacks('MinSumLim-SP', val) + if not okl: + self.run_callbacks('MinSumLim-RB', val) + self._update_log('Started.') self._init = True @@ -208,22 +208,16 @@ def fambpm_dev(self): """FamBPMs device.""" return self._fambpm_dev - @property - def havebeam(self): - """Return if there is stored beam.""" - return self._havebeam_pv.connected and self._havebeam_pv.value - # --- interlock control --- - def set_state(self, value): + def set_enable(self, value): """Set orbit interlock state. Configure global BPM interlock enable and EVG interlock enable.""" - if not 0 <= value < len(_ETypes.OFF_ON): + if not 0 <= value < len(_ETypes.DSBL_ENBL): return False if value: - pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] - glob_en = _np.logical_or(pos, ang) + glob_en = self._get_gen_bpm_intlk() else: glob_en = _np.zeros(self._const.nr_bpms) if not self._orbintlk_dev.set_gen_enable(list(glob_en)): @@ -240,38 +234,49 @@ def set_state(self, value): self._update_log('Configured EVG interlock enable.') self._state = value - self.run_callbacks('LoopState-Sts', self._state) + self.run_callbacks('Enable-Sts', self._state) return True # --- enable lists --- def set_enbllist(self, intlk, value): """Set enable list for interlock type.""" - self._update_log('Setting {0:s} EnblList'.format(intlk.upper())) + intlkname = intlk.capitalize().replace('sum', 'Sum') + self._update_log(f'Setting {intlkname} EnblList...') # check size bkup = self._enable_lists[intlk] new = _np.array(value, dtype=bool) if bkup.size != new.size: - self._update_log( - 'ERR: Wrong {0:s} EnblList size.'.format(intlk.upper())) + self._update_log(f'ERR: Wrong {intlkname} EnblList size.') return False self._enable_lists[intlk] = new # do not set enable lists and save to file in initialization if self._init: - # handle devices enable configuration - fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') - fun(list(value)) - # set_gen_enable + # handle device enable configuration + # set BPM interlock specific enable state + fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') + if not fun(list(value)): + self._update_log(f'ERR:Could not set BPM {intlkname}') + self._update_log('ERR:interlock enable.') + return False + + # if interlock is already enabled, update BPM general enable state + if self._state and intlk in ['pos', 'ang']: + glob_en = self._get_gen_bpm_intlk() + if not self._orbintlk_dev.set_gen_enable(list(glob_en)): + self._update_log('ERR:Could not set BPM general') + self._update_log('ERR:interlock enable.') + return False # save to autosave files self._save_enbllist(intlk, _np.array([value], dtype=bool)) # update readback pv - self.run_callbacks(intlk.upper()+'EnblList-RB', new) + self.run_callbacks(f'{intlkname}EnblList-RB', new) return True def _load_enbllist(self, intlk): @@ -288,7 +293,7 @@ def _load_enbllist(self, intlk): def _save_enbllist(self, intlk, value): try: - filename = getattr(self._const, intlk+'enbl_fname') + filename = getattr(self._const, intlk+'_enbl_fname') path = _os.path.split(filename)[0] _os.makedirs(path, exist_ok=True) _np.savetxt(filename, value) @@ -299,43 +304,154 @@ def _save_enbllist(self, intlk, value): # --- limits --- def set_intlk_lims(self, intlk_lim, value): + """Set limits for interlock type.""" + parts = intlk_lim.split('_') + if len(parts) > 1: + ilk, pln, lim = parts + limname = f'{ilk.capitalize()}{pln.capitalize()}{lim.capitalize()}' + else: + limname = intlk_lim.capitalize().replace('sum', 'Sum') + self._update_log(f'Setting {limname} limits...') + # check size + bkup = self._limits[intlk_lim] + new = _np.array(value, dtype=int) + if bkup.size != new.size: + self._update_log(f'ERR: Wrong {limname} limits size.') + return False - # --- callbacks --- + self._limits[intlk_lim] = new + + # do not set limits and save to file in initialization + if self._init: + # handle device limits configuration + + # set BPM interlock limits + fun = getattr(self._orbintlk_dev, f'set_{intlk_lim}_thres') + if not fun(list(value)): + self._update_log(f'ERR:Could not set BPM {limname}') + self._update_log('ERR:interlock limits.') + return False + + # save to autosave files + self._save_limits(intlk_lim, _np.array([value])) + + # update readback pv + self.run_callbacks(f'{limname}Lim-RB', new) + return True + + def _load_limits(self, intlk_lim): + filename = getattr(self._const, intlk_lim+'_lim_fname') + if not _os.path.isfile(filename): + return + okl = self.set_intlk_lims(intlk_lim, _np.loadtxt(filename)) + if okl: + msg = f'Loaded {intlk_lim} limits!' + else: + msg = f'ERR:Problem loading {intlk_lim} limits from file.' + self._update_log(msg) + return okl + + def _save_limits(self, intlk_lim, value): + try: + filename = getattr(self._const, intlk_lim+'_lim_fname') + path = _os.path.split(filename)[0] + _os.makedirs(path, exist_ok=True) + _np.savetxt(filename, value) + except FileNotFoundError: + self._update_log( + f'WARN:Could not save {intlk_lim} limits to file.') + + # --- reset --- + + def cmd_reset(self, state): + """Reset interlock states.""" + # if it is a BPM position, BPM general or a global reset + if 'pos' in state or 'all' in state: + self._orbintlk_dev.cmd_reset_pos() + self._update_log('Sent reset BPM position flags.') + # if it is a BPM angle, BPM general or a global reset + if 'ang' in state or 'all' in state: + self._orbintlk_dev.cmd_reset_ang() + self._update_log('Sent reset BPM angle flags.') + # if it is a BPM general or a global reset + if 'gen' in state or 'all' in state: + self._orbintlk_dev.cmd_reset_gen() + self._update_log('Sent reset BPM general flags.') + + # if it is a global reset, reset EVG + if state == 'all': + self._evg_dev['IntlkCtrlRst-Sel'] = 1 + self._update_log('Sent reset EVG interlock flag.') + + return True + + # --- configure acquisition --- + + def set_acq_channel(self, value): + """Set BPM PsMtm acquisition channel.""" + self._acq_chan = value + self.run_callbacks('PsMtmAcqChannel-Sts', value) + return True + + def set_acq_nrspls_pre(self, value): + """Set BPM PsMtm acquisition number of samples pre.""" + self._acq_spre = value + self.run_callbacks('PsMtmAcqSamplesPre-RB', value) + return True + + def set_acq_nrspls_post(self, value): + """Set BPM PsMtm acquisition number of samples post.""" + self._acq_spost = value + self.run_callbacks('PsMtmAcqSamplesPost-RB', value) + return True - def _callback_havebeam(self, value, **kws): - if not value and self._loop_state == self._const.LoopState.Closed: - self._update_log('FATAL:We do not have stored beam!') - self._update_log('FATAL:Opening FOFB loop...') - self.set_loop_state(self._const.LoopState.Open, abort=True) + def cmd_acq_config(self, value=None): + """Configure BPM PsMtm acquisition.""" + if self._thread_acq is None or not self._thread_acq.is_alive(): + self._thread_acq = _epics.ca.CAThread( + target=self._acq_config, daemon=True) + self._thread_acq.start() + return True + else: + self._update_log('WARN:BPM configuration already in progress.') + return False + + def _acq_config(self): + self._update_log('Aborting BPM acquisition...') + ret = self._fambpm_dev.cmd_mturn_acq_abort() + if ret > 0: + self._update_log('ERR:Failed to abort BPM acquisition.') + return + self._update_log('...done. Configuring BPM acquisition...') + for bpm in self._fambpm_dev.devices: + bpm.acq_repeat = self._const.AcqRepeat.Normal + bpm.acq_channel = self._acq_chan + bpm.acq_trigger = self._const.AcqTrigTyp.External + bpm.acq_nrsamples_pre = self._acq_spre + bpm.acq_nrsamples_post = self._acq_spost + self._update_log('...done. Starting BPM acquisition...') + ret = self.cmd_mturn_acq_start() + if ret > 0: + self._update_log('ERR:Failed to start BPM acquisition.') + return + self._update_log('...done!') + + # --- callbacks --- def _callback_intlk(self, pvname, value, **kws): - sub = _PVName(pvname).sub[:2] - old = self._intlk_values[pvname] - orbdis = _get_bit(value, 0) and not _get_bit(old, 0) - paclos = _get_bit(value, 1) and not _get_bit(old, 1) - self._intlk_values[pvname] = value - if value != 0: - pref = ('FATAL' if self._loop_state else 'WARN') + \ - ':Ctrlr.' + sub + ' detected ' - if orbdis: - self._update_log(pref + 'large orb.dist.!') - if paclos: - self._update_log(pref + 'packet loss!') - - if self._loop_state != self._const.LoopState.Closed: - return - - if self._thread_loopstate is None or \ - (self._thread_loopstate is not None and - not self._thread_loopstate.is_alive()) or \ - (self._thread_loopstate is not None and - self._thread_loopstate.is_alive() and - self._loop_state_lastsp != self._const.LoopState.Open): - self._update_log('FATAL:Opening FOFB loop...') - self.run_callbacks('LoopState-Sel', self._const.LoopState.Open) - self.run_callbacks('LoopState-Sts', self._const.LoopState.Open) - self.set_loop_state(self._const.LoopState.Open, abort=True) + if value != 0: # TODO> confirmar o valor que a PV assume em caso de interlock + self._update_log('FATAL:Orbit interlock raised by EVG.') + + if self._is_dry_run: + self._update_log('Waiting a little before rearming (dry run)...') + _time.sleep(self._const.DEF_TIME2WAIT_DRYRUN) + + # reset latch flags for BPM interlock core and EVG + self.cmd_reset('all') + + # reconfigure BPM configuration + self.cmd_acq_config() # --- auxiliary log methods --- @@ -352,6 +468,10 @@ def _update_log(self, msg): # --- auxiliary status methods --- + def _get_gen_bpm_intlk(self): + pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] + return _np.logical_or(pos, ang) + def _check_configs(self): tplanned = 1.0/App.SCAN_FREQUENCY while not self.quit: @@ -362,56 +482,61 @@ def _check_configs(self): _t0 = _time.time() # bpm status + dev = self._orbintlk_dev value = 0 - if self._orbintlk_dev.connected: - idcs = _np.where(self.corr_enbllist[:-1] == 1)[0] - # PwrStateOn - state = self._const.OffOn.On - if not self._corrs_dev.check_pwrstate( - state, psindices=idcs, timeout=0.2): - value = _updt_bit(value, 1, 1) - # OpModeConfigured - opmode = self._corrs_dev.OPMODE_STS.manual \ - if self._loop_state == self._const.LoopState.Open \ - else self._corrs_dev.OPMODE_STS.fofb - if not self._corrs_dev.check_opmode( - opmode, psindices=idcs, timeout=0.2): - value = _updt_bit(value, 2, 1) - # AccFreezeConfigured - freeze = self._get_corrs_fofbacc_freeze_desired() - if not self._corrs_dev.check_fofbacc_freeze( - freeze, timeout=0.2): - value = _updt_bit(value, 3, 1) - # InvRespMatRowSynced - if not self._corrs_dev.check_invrespmat_row(self._pscoeffs): - value = _updt_bit(value, 4, 1) - # AccGainSynced - if not self._corrs_dev.check_fofbacc_gain(self._psgains): - value = _updt_bit(value, 5, 1) - # AccSatLimsSynced - chn, chl = self._const.ch_names, self._ch_maxacccurr - cvn, cvl = self._const.cv_names, self._cv_maxacccurr - isok = self._corrs_dev.check_fofbacc_satmax(chl, psnames=chn) - isok &= self._corrs_dev.check_fofbacc_satmin(-chl, psnames=chn) - isok &= self._corrs_dev.check_fofbacc_satmax(cvl, psnames=cvn) - isok &= self._corrs_dev.check_fofbacc_satmin(-cvl, psnames=cvn) - if not isok: - value = _updt_bit(value, 6, 1) - # AccDecimationSynced - dec = self._corr_accdec_val - if not self._corrs_dev.check_fofbacc_decimation(dec): - value = _updt_bit(value, 7, 1) + if dev.connected: + # PosEnblSynced + val = dev.pos_enable == self._enable_lists['pos'] + value = _updt_bit(value, 1, val) + # AngEnblSynced + val = dev.ang_enable == self._enable_lists['ang'] + value = _updt_bit(value, 2, val) + # MinSumEnblSynced + val = dev.minsum_enable == self._enable_lists['minsum'] + value = _updt_bit(value, 3, val) + # GlobEnblSynced + val = dev.gen_enable == self._get_gen_bpm_intlk() + value = _updt_bit(value, 4, val) + # PosLimsSynced + okp = dev.pos_x_min_thres == self._limits['pos_x_min'] + okp = dev.pos_x_max_thres == self._limits['pos_x_max'] + okp = dev.pos_y_min_thres == self._limits['pos_y_min'] + okp = dev.pos_y_max_thres == self._limits['pos_y_max'] + value = _updt_bit(value, 5, okp) + # AngLimsSynced + oka = dev.ang_x_min_thres == self._limits['ang_x_min'] + oka = dev.ang_x_max_thres == self._limits['ang_x_max'] + oka = dev.ang_y_min_thres == self._limits['ang_y_min'] + oka = dev.ang_y_max_thres == self._limits['ang_y_max'] + value = _updt_bit(value, 6, oka) + # MinSumLimsSynced + oks = dev.minsum_thres == self._limits['minsum'] + value = _updt_bit(value, 7, oks) else: value = 0b11111111 - self._corr_status = value - self.run_callbacks('BPMStatus-Mon', self._corr_status) + self._bpm_status = value + self.run_callbacks('BPMStatus-Mon', self._bpm_status) + + # evg status + dev = self._evg_dev + value = 0 + if dev.connected: + # IntlkEnblSynced + val = dev['IntlkCtrlEnbl-Sts'] == self._state + value = _updt_bit(value, 1, val) + else: + value = 0b11 + + self._evg_status = value + self.run_callbacks('EVGStatus-Mon', self._evg_status) + # check time elapsed ttook = _time.time() - _t0 tsleep = tplanned - ttook if tsleep > 0: _time.sleep(tsleep) else: _log.warning( - 'Corrector configuration check took more than planned... ' + 'Configuration check took more than planned... ' '{0:.3f}/{1:.3f} s'.format(ttook, tplanned)) From 7c95aca9337fd429cea15ae61885b842ce49260b Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 6 Oct 2023 10:52:58 -0300 Subject: [PATCH 005/309] THREAD.BUG: FIx problem with RepeaterThread stop method when loop is_paused is True. --- siriuspy/siriuspy/thread.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/thread.py b/siriuspy/siriuspy/thread.py index ad8602f42..ac29f76db 100644 --- a/siriuspy/siriuspy/thread.py +++ b/siriuspy/siriuspy/thread.py @@ -102,6 +102,8 @@ def run(self): _use_initial_context() self._unpaused.wait() + if self._stopped.is_set(): + return self.function(*self.args, **self.kwargs) dtime = 0.0 while ((not self._stopped.wait(self.interval - dtime)) and @@ -140,8 +142,8 @@ def isPaused(self): def stop(self): """Stop execution.""" - self._unpaused.set() self._stopped.set() + self._unpaused.set() class _BaseQueueThread(_Queue): From ca0780784834749413f397d60b75966d8ff832e5 Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 6 Oct 2023 10:54:10 -0300 Subject: [PATCH 006/309] DEV.BPM.ENH: Generalize FamBPMs.mturn_config_acquisition to handle integer values for acq_rate. --- siriuspy/siriuspy/devices/bpm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm.py b/siriuspy/siriuspy/devices/bpm.py index ccc99e7c6..9b19f24a4 100644 --- a/siriuspy/siriuspy/devices/bpm.py +++ b/siriuspy/siriuspy/devices/bpm.py @@ -1114,8 +1114,8 @@ def mturn_config_acquisition( nr_points_after (int): number of points after trigger. nr_points_before (int): number of points after trigger. Defaults to 0. - acq_rate (str, optional): Acquisition rate ('TbT', 'TbTPha', - 'FOFB', 'FOFBPha', 'FAcq', 'ADC', 'ADCSwp'). + acq_rate (int|str, optional): Acquisition rate name ('TbT', + 'TbTPha', 'FOFB', 'FOFBPha', 'FAcq', 'ADC', 'ADCSwp') or value. Defaults to 'FAcq'. repeat (bool, optional): Whether or not acquisition should be repetitive. Defaults to True. @@ -1129,6 +1129,8 @@ def mturn_config_acquisition( >0: Index of the first BPM which is not ready for acq. plus 1. """ + if acq_rate in self._csbpm.AcqChan: + pass if acq_rate.lower().startswith('facq'): acq_rate = self._csbpm.AcqChan.FAcq elif acq_rate.lower().startswith('fofbpha'): From d1e9bf3c63e1745f1301411f29209fb543a8da3f Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 6 Oct 2023 10:54:55 -0300 Subject: [PATCH 007/309] DEV.ORBINTLK.MNT: Add comments to some methods. --- siriuspy/siriuspy/devices/orbit_interlock.py | 96 +++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index 616a03fc7..f898a0a6c 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -142,7 +142,7 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): 'IntlkMinSumEn-Sel', 'IntlkMinSumEn-Sts', # Minimum sum threshold (sum counts in FAcq rate): 'IntlkLmtMinSum-SP', 'IntlkLmtMinSum-RB', - # Instantaneous interlock, dificult to be checked in the current + # Instantaneous interlock, dificult to be checked in the current # gateware implementation 'Intlk-Mon', # Latch interlock, clean only when respective "Clr" PV is triggered @@ -683,8 +683,8 @@ def gen_latch(self): """ return _np.array([b.gen_latch for b in self._devices]) - # --- minimum sum threshold --- - + # --- minimum sum threshold --- + @property def minsum_enable(self): """Minimum sum threshold enable. @@ -725,6 +725,16 @@ def minsum_thres(self): return _np.array([b.minsum_thres for b in self._devices]) def set_minsum_thres(self, value, timeout=TIMEOUT): + """Set minimum sum thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtMinSum-SP', value) return self._wait_devices_propty( @@ -779,6 +789,16 @@ def pos_x_min_thres(self): return _np.array([b.pos_x_min_thres for b in self._devices]) def set_pos_x_min_thres(self, value, timeout=TIMEOUT): + """Set minimum x position thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMinX-SP', value) return self._wait_devices_propty( @@ -795,6 +815,16 @@ def pos_x_max_thres(self): return _np.array([b.pos_x_max_thres for b in self._devices]) def set_pos_x_max_thres(self, value, timeout=TIMEOUT): + """Set maximum x position thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMaxX-SP', value) return self._wait_devices_propty( @@ -811,6 +841,16 @@ def pos_y_min_thres(self): return _np.array([b.pos_y_min_thres for b in self._devices]) def set_pos_y_min_thres(self, value, timeout=TIMEOUT): + """Set minimum y position thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMinY-SP', value) return self._wait_devices_propty( @@ -827,6 +867,16 @@ def pos_y_max_thres(self): return _np.array([b.pos_y_max_thres for b in self._devices]) def set_pos_y_max_thres(self, value, timeout=TIMEOUT): + """Set maximum y position thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMaxY-SP', value) return self._wait_devices_propty( @@ -1001,6 +1051,16 @@ def ang_x_min_thres(self): return _np.array([b.ang_x_min_thres for b in self._devices]) def set_ang_x_min_thres(self, value, timeout=TIMEOUT): + """Set minimum x angle thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMinX-SP', value) return self._wait_devices_propty( @@ -1017,6 +1077,16 @@ def ang_x_max_thres(self): return _np.array([b.ang_x_max_thres for b in self._devices]) def set_ang_x_max_thres(self, value, timeout=TIMEOUT): + """Set maximum x angle thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMaxX-SP', value) return self._wait_devices_propty( @@ -1033,6 +1103,16 @@ def ang_y_min_thres(self): return _np.array([b.ang_y_min_thres for b in self._devices]) def set_ang_y_min_thres(self, value, timeout=TIMEOUT): + """Set minimum y angle thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMinY-SP', value) return self._wait_devices_propty( @@ -1049,6 +1129,16 @@ def ang_y_max_thres(self): return _np.array([b.ang_y_max_thres for b in self._devices]) def set_ang_y_max_thres(self, value, timeout=TIMEOUT): + """Set maximum y angle thresholds. + + Args: + value (numpy.ndarray|float): Values for minimum sum. + timeout (float, optional): timeout to wait. Defaults to TIMEOUT. + + Returns: + bool: True if set was successful. + + """ value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMaxY-SP', value) return self._wait_devices_propty( From 7cb20afb1cd3cd89207caf29c9911066aae45893 Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 6 Oct 2023 12:32:37 -0300 Subject: [PATCH 008/309] ORBINTLK.ENH: Add a few functionalities, refactor code and fix some bugs. --- siriuspy/siriuspy/orbintlk/csdev.py | 43 ++- siriuspy/siriuspy/orbintlk/main.py | 537 +++++++++++++++++----------- 2 files changed, 373 insertions(+), 207 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 94e438e4e..4c3b74105 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -19,8 +19,12 @@ class ETypes(_csdev.ETypes): 'Connected', 'PosEnblSynced', 'AngEnblSynced', 'MinSumEnblSynced', 'GlobEnblSynced', 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced') - STS_LBLS_EVG = ( - 'Connected', 'IntlkEnblSynced') + STS_LBLS_TIMING = ( + 'EVGConn', 'IntlkEnblSynced', 'EVGConfig', + 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', + 'LLRFTrigConn', 'LLRFTrigStatusOK', 'LLRFTrigConfig', + ) + STS_LBLS_LLRF = ('Connected', 'Configured') _et = ETypes # syntactic sugar @@ -39,6 +43,28 @@ class Const(_csdev.Const): DEF_TIME2WAIT_DRYRUN = 10 # [s] + EVG_CONFIGS = ( + ('IntlkTbl0to15-Sel', 1), + ('IntlkTbl16to27-Sel', 0), + ('IntlkCtrlRepeat-Sel', 0), + ('IntlkCtrlRepeatTime-SP', 0), + ('IntlkEvtIn0-SP', 117), + ('IntlkEvtOut-SP', 124), + ) + ORBINTLKTRIG_CONFIG = ( + ('Src-Sel', 4), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 0), + ('Direction-Sel', 1), + ) + LLRFTRIG_CONFIG = ( + ('Src-Sel', 5), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 0), + ) + AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp AcqRepeat = _csbpm.AcqRepeat @@ -89,7 +115,17 @@ def get_database(self): 'type': 'enum', 'enums': _et.DSBL_ENBL, 'value': self.DsblEnbl.Dsbl}, 'BPMStatus-Mon': {'type': 'int', 'value': 0b11111111}, - 'EVGStatus-Mon': {'type': 'int', 'value': 0b11}, + 'TimingStatus-Mon': {'type': 'int', 'value': 0b111111111}, + 'LLRFStatus-Mon': {'type': 'int', 'value': 0b11}, + 'BPMStatusLabels-Cte': { + 'type': 'string', 'count': len(_et.STS_LBLS_BPMS), + 'value': _et.STS_LBLS_BPMS}, + 'TimingStatusLabels-Cte': { + 'type': 'string', 'count': len(_et.STS_LBLS_TIMING), + 'value': _et.STS_LBLS_TIMING}, + 'LLRFStatusLabels-Cte': { + 'type': 'string', 'count': len(_et.STS_LBLS_LLRF), + 'value': _et.STS_LBLS_LLRF}, # Enable lists 'PosEnblList-SP': { @@ -221,6 +257,7 @@ def get_database(self): # TODO: # add commands to sync enable status and limits + 'IntlkStateConfig-Cmd': {'type': 'int', 'value': 0} } pvs_database = _csdev.add_pvslist_cte(pvs_database) return pvs_database diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c3cde9db1..d25287926 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -4,16 +4,18 @@ import logging as _log import time as _time from functools import partial as _part -import epics as _epics + import numpy as _np -from ..util import update_bit as _updt_bit, get_bit as _get_bit +from ..util import update_bit as _updt_bit +from ..thread import RepeaterThread as _Repeat from ..epics import PV as _PV +from ..epics.threading import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..envars import VACA_PREFIX as _vaca_prefix from ..namesys import SiriusPVName as _PVName from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ - EVG as _EVG + EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger from .csdev import Const as _Const, ETypes as _ETypes @@ -32,14 +34,15 @@ def __init__(self, tests=True): self._init = False # internal states + self._llrf_intlk_state = 0b111011 if self._is_dry_run else 0b000000 self._state = self._const.OffOn.Off self._bpm_status = self._pvs_database['BPMStatus-Mon']['value'] - self._evg_status = self._pvs_database['EVGStatus-Mon']['value'] + self._timing_status = self._pvs_database['TimingStatus-Mon']['value'] self._enable_lists = { 'pos': _np.ones(self._const.nr_bpms, dtype=bool), 'ang': _np.ones(self._const.nr_bpms, dtype=bool), 'minsum': _np.ones(self._const.nr_bpms, dtype=bool), - } + } self._limits = { 'pos_x_min': _np.zeros(self._const.nr_bpms, dtype=int), 'pos_x_max': _np.zeros(self._const.nr_bpms, dtype=int), @@ -50,24 +53,53 @@ def __init__(self, tests=True): 'ang_y_min': _np.zeros(self._const.nr_bpms, dtype=int), 'ang_y_max': _np.zeros(self._const.nr_bpms, dtype=int), 'minsum': _np.zeros(self._const.nr_bpms, dtype=int), - } + } self._acq_chan = self._pvs_database['PsMtmAcqChannel-Sel']['value'] self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] self._thread_acq = None # devices and connections - self._evg_dev = _EVG( - props2init=[ - 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', - 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts', - 'IntlkEvtStatus-Mon']) - self._evg_intlk_pv = self._evg_dev.pv_object('IntlkEvtStatus-Mon') # TODO> confirmar com maurício se é essa PV mesmo - self._evg_intlk_pv.auto_monitor = True - self._evg_intlk_pv.add_callback(self._callback_intlk) + self._evg_dev = _EVG(props2init=[ + 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', + 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts', + 'IntlkCtrlRepeat-Sel', 'IntlkCtrlRepeat-Sts', + 'IntlkCtrlRepeatTime-SP', 'IntlkCtrlRepeatTime-RB', + 'IntlkTbl0to15-Sel', 'IntlkTbl0to15-Sts', + 'IntlkTbl16to27-Sel', 'IntlkTbl16to27-Sts', + 'IntlkEvtIn0-SP', 'IntlkEvtIn0-RB', + 'IntlkEvtOut-SP', 'IntlkEvtOut-SP', + 'IntlkEvtStatus-Mon']) + # TODO: confirmar com maurício se é essa PV mesmo + pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') + pvo.auto_monitor = True + pvo.add_callback(self._callback_intlk) + + self._llrf_trig = _Trigger( + devname='SI-Glob:TI-LLRF-PsMtn', props2init=[ + 'Src-Sel', 'Src-Sts', + 'DelayRaw-SP', 'DelayRaw-RB', + 'State-Sel', 'State-Sts', + 'WidthRaw-SP', 'WidthRaw-RB', + 'Status-Mon', + ]) + + self._orbintlk_trig = _Trigger( + devname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ + 'Src-Sel', 'Src-Sts', + 'DelayRaw-SP', 'DelayRaw-RB', + 'State-Sel', 'State-Sts', + 'WidthRaw-SP', 'WidthRaw-RB', + 'Direction-Sel', 'Direction-Sts', + 'Status-Mon', + ]) self._orbintlk_dev = _OrbitIntlk() + self._llrf = _ASLLRF(devname=_ASLLRF.DEVICES.SI, props2init=[ + 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', + ]) + self._fambpm_dev = _FamBPMs( devname=_FamBPMs.DEVICES.SI, ispost_mortem=True, props2init=[ @@ -77,8 +109,7 @@ def __init__(self, tests=True): 'ACQTriggerRep-Sel', 'ACQTriggerRep-Sts', 'ACQTrigger-Sel', 'ACQTrigger-Sts', 'ACQTriggerEvent-Sel', 'ACQTriggerEvent-Sts', - 'ACQStatus-Sts', - ]) + 'ACQStatus-Sts']) # pvs to write methods self.map_pv2write = { @@ -104,13 +135,13 @@ def __init__(self, tests=True): 'PsMtmAcqSamplesPre-SP': self.set_acq_nrspls_pre, 'PsMtmAcqSamplesPost-SP': self.set_acq_nrspls_post, 'PsMtmAcqConfig-Cmd': self.cmd_acq_config, - } + 'IntlkStateConfig-Cmd': self.cmd_state_config} # configuration scanning - self.quit = False - self.scanning = False - self.thread_check_configs = _epics.ca.CAThread( - target=self._check_configs, daemon=True) + self.thread_check_configs = _Repeat( + 1.0/App.SCAN_FREQUENCY, self._check_configs, niter=0, + is_cathread=True) + self.thread_check_configs.pause() self.thread_check_configs.start() def init_database(self): @@ -119,7 +150,7 @@ def init_database(self): 'Enable-Sel': self._state, 'Enable-Sts': self._state, 'BPMStatus-Mon': self._bpm_status, - 'EVGStatus-Mon': self._evg_status, + 'TimingStatus-Mon': self._timing_status, 'ResetBPMGen-Cmd': 0, 'ResetBPMPos-Cmd': 0, 'ResetBPMAng-Cmd': 0, @@ -137,10 +168,10 @@ def init_database(self): self.run_callbacks(pvn, val) # load autosave data - + # enable lists for ilk in ['Pos', 'Ang', 'MinSum']: - okl = self._load_enbllist(ilk) + okl = self._load_file(ilk, 'enbl') pvn = f'{ilk}EnblList' enb = self._enable_lists[ilk] self.run_callbacks(pvn+'-SP', enb) @@ -153,13 +184,13 @@ def init_database(self): for lim in ['Min', 'Max']: atn = f'{ilk}_{pln}_{lim}'.lower() pvn = f'{ilk}{pln}{lim}Lim' - okl = self._load_limits(atn) + okl = self._load_file(atn, 'lim') val = self._limits[atn] self.run_callbacks(pvn+'-SP', val) if not okl: self.run_callbacks(pvn+'-RB', val) - - okl = self._load_limits('minsum') + + okl = self._load_file('minsum', 'lim') val = self._limits['minsum'] self.run_callbacks('MinSumLim-SP', val) if not okl: @@ -179,19 +210,20 @@ def process(self, interval): def read(self, reason): """Read from IOC database.""" - value = None - return value + _ = reason + return None def write(self, reason, value): """Write value to reason and let callback update PV database.""" _log.info('Write received for: %s --> %s', reason, str(value)) - if reason in self.map_pv2write.keys(): - status = self.map_pv2write[reason](value) - _log.info('%s Write for: %s --> %s', - str(status).upper(), reason, str(value)) - return status - _log.warning('PV %s does not have a set function.', reason) - return False + if reason not in self.map_pv2write: + _log.warning('PV %s does not have a set function.', reason) + return False + + status = self.map_pv2write[reason](value) + _log.info( + '%s Write for: %s --> %s', str(status).upper(), reason, str(value)) + return status @property def evg_dev(self): @@ -205,7 +237,7 @@ def orbintlk_dev(self): @property def fambpm_dev(self): - """FamBPMs device.""" + """Return FamBPMs device.""" return self._fambpm_dev # --- interlock control --- @@ -213,13 +245,13 @@ def fambpm_dev(self): def set_enable(self, value): """Set orbit interlock state. Configure global BPM interlock enable and EVG interlock enable.""" - if not 0 <= value < len(_ETypes.DSBL_ENBL): + if value not in _ETypes.DSBL_ENBL: return False if value: glob_en = self._get_gen_bpm_intlk() else: - glob_en = _np.zeros(self._const.nr_bpms) + glob_en = _np.zeros(self._const.nr_bpms, dtype=bool) if not self._orbintlk_dev.set_gen_enable(list(glob_en)): self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') @@ -245,62 +277,43 @@ def set_enbllist(self, intlk, value): self._update_log(f'Setting {intlkname} EnblList...') # check size - bkup = self._enable_lists[intlk] new = _np.array(value, dtype=bool) - if bkup.size != new.size: + if self._const.nr_bpms != new.size: self._update_log(f'ERR: Wrong {intlkname} EnblList size.') return False self._enable_lists[intlk] = new # do not set enable lists and save to file in initialization - if self._init: - # handle device enable configuration + if not self._init: + # update readback pv + self.run_callbacks(f'{intlkname}EnblList-RB', new) + return True - # set BPM interlock specific enable state - fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') - if not fun(list(value)): - self._update_log(f'ERR:Could not set BPM {intlkname}') + # handle device enable configuration + + # set BPM interlock specific enable state + fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') + if not fun(list(value)): + self._update_log(f'ERR:Could not set BPM {intlkname}') + self._update_log('ERR:interlock enable.') + return False + + # if interlock is already enabled, update BPM general enable state + if self._state and intlk in ['pos', 'ang']: + glob_en = self._get_gen_bpm_intlk() + if not self._orbintlk_dev.set_gen_enable(list(glob_en)): + self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') return False - - # if interlock is already enabled, update BPM general enable state - if self._state and intlk in ['pos', 'ang']: - glob_en = self._get_gen_bpm_intlk() - if not self._orbintlk_dev.set_gen_enable(list(glob_en)): - self._update_log('ERR:Could not set BPM general') - self._update_log('ERR:interlock enable.') - return False - - # save to autosave files - self._save_enbllist(intlk, _np.array([value], dtype=bool)) + + # save to autosave files + self._save_file(intlk, _np.array([value], dtype=bool), 'enbl') # update readback pv self.run_callbacks(f'{intlkname}EnblList-RB', new) return True - def _load_enbllist(self, intlk): - filename = getattr(self._const, intlk+'_enbl_fname') - if not _os.path.isfile(filename): - return - okl = self.set_enbllist(intlk, _np.loadtxt(filename)) - if okl: - msg = f'Loaded {intlk} enable list!' - else: - msg = f'ERR:Problem loading {intlk} enable list from file.' - self._update_log(msg) - return okl - - def _save_enbllist(self, intlk, value): - try: - filename = getattr(self._const, intlk+'_enbl_fname') - path = _os.path.split(filename)[0] - _os.makedirs(path, exist_ok=True) - _np.savetxt(filename, value) - except FileNotFoundError: - self._update_log( - f'WARN:Could not save {intlk} enable list to file.') - # --- limits --- def set_intlk_lims(self, intlk_lim, value): @@ -314,54 +327,35 @@ def set_intlk_lims(self, intlk_lim, value): self._update_log(f'Setting {limname} limits...') # check size - bkup = self._limits[intlk_lim] new = _np.array(value, dtype=int) - if bkup.size != new.size: + if self._const.nr_bpms != new.size: self._update_log(f'ERR: Wrong {limname} limits size.') return False self._limits[intlk_lim] = new # do not set limits and save to file in initialization - if self._init: - # handle device limits configuration - - # set BPM interlock limits - fun = getattr(self._orbintlk_dev, f'set_{intlk_lim}_thres') - if not fun(list(value)): - self._update_log(f'ERR:Could not set BPM {limname}') - self._update_log('ERR:interlock limits.') - return False + if not self._init: + # update readback pv + self.run_callbacks(f'{limname}Lim-RB', new) + return True + + # handle device limits configuration + + # set BPM interlock limits + fun = getattr(self._orbintlk_dev, f'set_{intlk_lim}_thres') + if not fun(list(value)): + self._update_log(f'ERR:Could not set BPM {limname}') + self._update_log('ERR:interlock limits.') + return False - # save to autosave files - self._save_limits(intlk_lim, _np.array([value])) + # save to autosave files + self._save_file(intlk_lim, _np.array([value]), 'lim') # update readback pv self.run_callbacks(f'{limname}Lim-RB', new) return True - def _load_limits(self, intlk_lim): - filename = getattr(self._const, intlk_lim+'_lim_fname') - if not _os.path.isfile(filename): - return - okl = self.set_intlk_lims(intlk_lim, _np.loadtxt(filename)) - if okl: - msg = f'Loaded {intlk_lim} limits!' - else: - msg = f'ERR:Problem loading {intlk_lim} limits from file.' - self._update_log(msg) - return okl - - def _save_limits(self, intlk_lim, value): - try: - filename = getattr(self._const, intlk_lim+'_lim_fname') - path = _os.path.split(filename)[0] - _os.makedirs(path, exist_ok=True) - _np.savetxt(filename, value) - except FileNotFoundError: - self._update_log( - f'WARN:Could not save {intlk_lim} limits to file.') - # --- reset --- def cmd_reset(self, state): @@ -378,7 +372,7 @@ def cmd_reset(self, state): if 'gen' in state or 'all' in state: self._orbintlk_dev.cmd_reset_gen() self._update_log('Sent reset BPM general flags.') - + # if it is a global reset, reset EVG if state == 'all': self._evg_dev['IntlkCtrlRst-Sel'] = 1 @@ -386,7 +380,7 @@ def cmd_reset(self, state): return True - # --- configure acquisition --- + # --- configure acquisition --- def set_acq_channel(self, value): """Set BPM PsMtm acquisition channel.""" @@ -409,8 +403,7 @@ def set_acq_nrspls_post(self, value): def cmd_acq_config(self, value=None): """Configure BPM PsMtm acquisition.""" if self._thread_acq is None or not self._thread_acq.is_alive(): - self._thread_acq = _epics.ca.CAThread( - target=self._acq_config, daemon=True) + self._thread_acq = _CAThread(target=self._acq_config, daemon=True) self._thread_acq.start() return True else: @@ -424,30 +417,213 @@ def _acq_config(self): self._update_log('ERR:Failed to abort BPM acquisition.') return self._update_log('...done. Configuring BPM acquisition...') - for bpm in self._fambpm_dev.devices: - bpm.acq_repeat = self._const.AcqRepeat.Normal - bpm.acq_channel = self._acq_chan - bpm.acq_trigger = self._const.AcqTrigTyp.External - bpm.acq_nrsamples_pre = self._acq_spre - bpm.acq_nrsamples_post = self._acq_spost - self._update_log('...done. Starting BPM acquisition...') - ret = self.cmd_mturn_acq_start() - if ret > 0: - self._update_log('ERR:Failed to start BPM acquisition.') + ret = self._fambpm_dev.mturn_config_acquisition( + nr_points_before=self._acq_spre, + nr_points_after=self._acq_spost, + acq_rate=self._acq_chan, + repeat=False, + external=True) + if ret < 0: + self._update_log( + 'ERR:Failed to abort acquisition for ' + + f'{self._const.bpm_names[-ret-1]:s}.') + return + elif ret > 0: + self._update_log( + 'ERR:Failed to start acquisition for ' + + f'{self._const.bpm_names[ret-1]:s}.') return self._update_log('...done!') + # --- status methods --- + + def cmd_state_config(self, value=None): + """Configure Interlock State according to setpoints. + + Args: + value (int, optional): Not used. Defaults to None. + + Returns: + bool: True if configuration worked. + """ + for name, enbl in self._enable_lists.items(): + if not self.set_enbllist(name, enbl): + self._update_log( + f'ERR: could not configure {name:s} enable list') + return False + + for name, lim in self._limits.items(): + if not self.set_intlk_lims(name, lim): + self._update_log( + f'ERR:Could not configure {name:s} limit') + return False + + if not self.set_enable(self._state): + return False + if not self._config_timing(): + return False + if not self._config_llrf(): + return False + return True + + def _config_timing(self): + dev = self._evg_dev + for prp, val in self._const.EVG_CONFIGS: + dev[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not dev._wait(prp_rb, val): + self._update_log(f'ERR:Failed to configure EVG PV {prp:s}') + return False + # Orbit Interlock Trigger + dev = self._orbintlk_trig + for prp, val in self._const.ORBINTLKTRIG_CONFIG: + dev[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not dev._wait(prp_rb, val): + self._update_log( + f'ERR:Failed to configure OrbIntlk Trigger PV {prp:s}') + return False + # Orbit Interlock Trigger + dev = self._llrf_trig + for prp, val in self._const.LLRFTRIG_CONFIG: + dev[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not dev._wait(prp_rb, val): + self._update_log( + f'ERR:Failed to configure LLRF Trigger PV {prp:s}') + return False + return True + + def _config_llrf(self): + self._llrf['ILK:BEAM:TRIP:S'] = self._llrf_intlk_state + if not self._llrf._wait('ILK:BEAM:TRIP', self._llrf_intlk_state): + self._update_log('ERR:Failed to configure LLRF.') + return False + return True + + def _get_gen_bpm_intlk(self): + pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] + return _np.logical_or(pos, ang) + + def _check_configs(self): + _t0 = _time.time() + + # bpm status + dev = self._orbintlk_dev + value = 0b11111111 + if dev.connected: + # PosEnblSynced + val = _np.array_equal( + dev.pos_enable, self._enable_lists['pos']) + value = _updt_bit(value, 1, val) + # AngEnblSynced + val = _np.array_equal( + dev.ang_enable, self._enable_lists['ang']) + value = _updt_bit(value, 2, val) + # MinSumEnblSynced + val = _np.array_equal( + dev.minsum_enable, self._enable_lists['minsum']) + value = _updt_bit(value, 3, val) + # GlobEnblSynced + val = _np.array_equal(dev.gen_enable, self._get_gen_bpm_intlk()) + value = _updt_bit(value, 4, val) + # PosLimsSynced + okp = True + for prp in ['pos_x_min', 'pos_x_max', 'pos_y_min', 'pos_y_max']: + okp &= _np.array_equal( + getattr(dev, prp+'_thres'), self._limits[prp]) + value = _updt_bit(value, 5, okp) + # AngLimsSynced + oka = True + for prp in ['ang_x_min', 'ang_x_max', 'ang_y_min', 'ang_y_max']: + oka &= _np.array_equal( + getattr(dev, prp+'_thres'), self._limits[prp]) + value = _updt_bit(value, 6, oka) + # MinSumLimsSynced + oks = _np.array_equal(dev.minsum_thres, self._limits['minsum']) + value = _updt_bit(value, 7, oks) + + self._bpm_status = value + self.run_callbacks('BPMStatus-Mon', self._bpm_status) + + # Timing Status + value = 0 + # EVG + dev = self._evg_dev + if dev.connected: + val = dev['IntlkCtrlEnbl-Sts'] == self._state + value = _updt_bit(value, 1, val) + okg = True + for prp, val in self._const.EVG_CONFIGS: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + okg &= dev[prp_rb] == val + value = _updt_bit(value, 2, okg) + else: + value = 0b111 + # Orbit Interlock trigger + dev = self._orbintlk_trig + if dev.connected: + value = _updt_bit(value, 3, True) + value = _updt_bit(value, 4, not bool(dev['Status-Mon'])) + oko = True + for prp, val in self._const.ORBINTLKTRIG_CONFIG: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + oko &= dev[prp_rb] == val + value = _updt_bit(value, 5, oko) + else: + value += 0b111 << 3 + # LLRF trigger + dev = self._llrf_trig + oko = False + if dev.connected: + value = _updt_bit(value, 6, True) + value = _updt_bit(value, 7, not bool(dev['Status-Mon'])) + oko = True + for prp, val in self._const.LLRFTRIG_CONFIG: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + oko &= dev[prp_rb] == val + value = _updt_bit(value, 8, oko) + else: + value += 0b111 << 6 + + self._timing_status = value + self.run_callbacks('TimingStatus-Mon', self._timing_status) + + # LLRF Status + value = 0b11 + dev = self._llrf + if dev.connected: + value = _updt_bit(value, 0, True) + value = _updt_bit( + value, 1, dev['ILK:BEAM:TRIP'] == self._llrf_intlk_state) + self.run_callbacks('LLRFStatus-Mon', value) + + # check time elapsed + ttook = _time.time() - _t0 + tplanned = self.thread_check_configs.interval + tsleep = tplanned - ttook + if tsleep <= 0: + _log.warning( + 'Configuration check took more than planned... ' + '{0:.3f}/{1:.3f} s'.format(ttook, tplanned)) + # --- callbacks --- def _callback_intlk(self, pvname, value, **kws): - if value != 0: # TODO> confirmar o valor que a PV assume em caso de interlock + trh = _CAThread( + target=self._do_callback_intlk, args=(value, ), daemon=True) + trh.start() + + def _do_callback_intlk(self, value): + # TODO: confirmar o valor que a PV assume em caso de interlock + if value != 0: self._update_log('FATAL:Orbit interlock raised by EVG.') if self._is_dry_run: self._update_log('Waiting a little before rearming (dry run)...') _time.sleep(self._const.DEF_TIME2WAIT_DRYRUN) - - # reset latch flags for BPM interlock core and EVG + + # reset latch flags for BPM interlock core and EVG self.cmd_reset('all') # reconfigure BPM configuration @@ -466,77 +642,30 @@ def _update_log(self, msg): _log.info(msg) self.run_callbacks('Log-Mon', msg) - # --- auxiliary status methods --- + # ---------------- File handlers --------------------- - def _get_gen_bpm_intlk(self): - pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] - return _np.logical_or(pos, ang) + def _load_file(self, intlk_lim, dtype='en'): + suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' + msg = 'enable list' if dtype.startswith('en') else 'limits' + filename = getattr(self._const, intlk_lim + suff) + if not _os.path.isfile(filename): + return + okl = self.set_intlk_lims(intlk_lim, _np.loadtxt(filename)) + if okl: + msg = f'Loaded {intlk_lim} {msg}!' + else: + msg = f'ERR:Problem loading {intlk_lim} {msg} from file.' + self._update_log(msg) + return okl - def _check_configs(self): - tplanned = 1.0/App.SCAN_FREQUENCY - while not self.quit: - if not self.scanning: - _time.sleep(tplanned) - continue - - _t0 = _time.time() - - # bpm status - dev = self._orbintlk_dev - value = 0 - if dev.connected: - # PosEnblSynced - val = dev.pos_enable == self._enable_lists['pos'] - value = _updt_bit(value, 1, val) - # AngEnblSynced - val = dev.ang_enable == self._enable_lists['ang'] - value = _updt_bit(value, 2, val) - # MinSumEnblSynced - val = dev.minsum_enable == self._enable_lists['minsum'] - value = _updt_bit(value, 3, val) - # GlobEnblSynced - val = dev.gen_enable == self._get_gen_bpm_intlk() - value = _updt_bit(value, 4, val) - # PosLimsSynced - okp = dev.pos_x_min_thres == self._limits['pos_x_min'] - okp = dev.pos_x_max_thres == self._limits['pos_x_max'] - okp = dev.pos_y_min_thres == self._limits['pos_y_min'] - okp = dev.pos_y_max_thres == self._limits['pos_y_max'] - value = _updt_bit(value, 5, okp) - # AngLimsSynced - oka = dev.ang_x_min_thres == self._limits['ang_x_min'] - oka = dev.ang_x_max_thres == self._limits['ang_x_max'] - oka = dev.ang_y_min_thres == self._limits['ang_y_min'] - oka = dev.ang_y_max_thres == self._limits['ang_y_max'] - value = _updt_bit(value, 6, oka) - # MinSumLimsSynced - oks = dev.minsum_thres == self._limits['minsum'] - value = _updt_bit(value, 7, oks) - else: - value = 0b11111111 - - self._bpm_status = value - self.run_callbacks('BPMStatus-Mon', self._bpm_status) - - # evg status - dev = self._evg_dev - value = 0 - if dev.connected: - # IntlkEnblSynced - val = dev['IntlkCtrlEnbl-Sts'] == self._state - value = _updt_bit(value, 1, val) - else: - value = 0b11 - - self._evg_status = value - self.run_callbacks('EVGStatus-Mon', self._evg_status) - - # check time elapsed - ttook = _time.time() - _t0 - tsleep = tplanned - ttook - if tsleep > 0: - _time.sleep(tsleep) - else: - _log.warning( - 'Configuration check took more than planned... ' - '{0:.3f}/{1:.3f} s'.format(ttook, tplanned)) + def _save_file(self, intlk, value, dtype): + suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' + msg = 'enable list' if dtype.startswith('en') else 'limits' + try: + filename = getattr(self._const, intlk+suff) + path = _os.path.split(filename)[0] + _os.makedirs(path, exist_ok=True) + _np.savetxt(filename, value) + except FileNotFoundError: + self._update_log( + f'WARN:Could not save {intlk} {msg} to file.') From d42100a851508b096f0fe0cb258723220188aaf6 Mon Sep 17 00:00:00 2001 From: Fernando Date: Tue, 10 Oct 2023 14:39:01 -0300 Subject: [PATCH 009/309] DEV.ORBINTLK.MNT: Return numpy arrays in calc_intlk_metric. --- siriuspy/siriuspy/devices/orbit_interlock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index f898a0a6c..799d378c5 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -115,7 +115,7 @@ def calc_intlk_metric(self, posarray, operation='', metric=''): func = self._oper[operation] val = func(dval, uval) data_values.append(val) - return data_values + return _np.array(data_values) @staticmethod def _mean(var1, var2): From 44fe5a32c1be47a7d1ccb8c7b3eade8522f4bdab Mon Sep 17 00:00:00 2001 From: Fernando Date: Tue, 10 Oct 2023 14:39:28 -0300 Subject: [PATCH 010/309] ORBINTLK.MNT: Define IOC_PREFIX in Const class. --- siriuspy/siriuspy/orbintlk/csdev.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 4c3b74105..83c42b8e8 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -4,6 +4,7 @@ from .. import csdev as _csdev from ..search import BPMSearch as _BPMSearch +from ..namesys import SiriusPVName as _PVName from ..diagbeam.bpm.csdev import Const as _csbpm @@ -37,6 +38,7 @@ class Const(_csdev.Const): CONV_UM_2_NM = 1e3 + IOC_PREFIX = _PVName('SI-Glob:AP-OrbIntlk') DEF_TIMEOUT = 10 # [s] DEF_TIMESLEEP = 0.1 # [s] DEF_TIMEWAIT = 3 # [s] From 99b8f2e21461c049fa3bafec2a5b6692e6257e8d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 20 Oct 2023 16:57:20 -0300 Subject: [PATCH 011/309] DEV.BPM.FIX: do not implement __getitem__ and __setitem__, this was causing problems for post mortem acquisitions --- siriuspy/siriuspy/devices/bpm.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm.py b/siriuspy/siriuspy/devices/bpm.py index 9b19f24a4..ae467cf1a 100644 --- a/siriuspy/siriuspy/devices/bpm.py +++ b/siriuspy/siriuspy/devices/bpm.py @@ -4,8 +4,8 @@ import time as _time # from threading import Event as _Flag -import numpy as _np from copy import deepcopy as _dcopy +import numpy as _np from .device import Device as _Device, DeviceSet as _DeviceSet from ..diagbeam.bpm.csdev import Const as _csbpm @@ -134,16 +134,6 @@ def __str__(self): stg += '\n' return stg - def __getitem__(self, propty): - """Return value of property.""" - propty = self.get_propname(propty) - return super().__getitem__(propty) - - def __setitem__(self, propty, value): - """Set value of property.""" - propty = self.get_propname(propty) - super().__setitem__(propty, value) - @property def is_ok(self): """.""" From 1dec70f9c7ed5650f3612efef06e376895b59b85 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 20 Oct 2023 16:58:10 -0300 Subject: [PATCH 012/309] ORBINTLK.FIX: fix expected value for widthraw --- siriuspy/siriuspy/orbintlk/csdev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 83c42b8e8..32dcada0d 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -57,14 +57,14 @@ class Const(_csdev.Const): ('Src-Sel', 4), ('DelayRaw-SP', 0), ('State-Sel', 1), - ('WidthRaw-SP', 0), + ('WidthRaw-SP', 1), ('Direction-Sel', 1), ) LLRFTRIG_CONFIG = ( ('Src-Sel', 5), ('DelayRaw-SP', 0), ('State-Sel', 1), - ('WidthRaw-SP', 0), + ('WidthRaw-SP', 9369), ) AcqChan = _csbpm.AcqChan From 2e53860b32e8f582afb971bd67f025c90657d73f Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 20 Oct 2023 16:59:47 -0300 Subject: [PATCH 013/309] ORBINTLK.MNT: cleanup code and improve logs --- siriuspy/siriuspy/orbintlk/csdev.py | 9 ++++----- siriuspy/siriuspy/orbintlk/main.py | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 32dcada0d..3ecf8b79c 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -16,7 +16,7 @@ class ETypes(_csdev.ETypes): """Local enumerate types.""" - STS_LBLS_BPMS = ( + STS_LBLS_BPM = ( 'Connected', 'PosEnblSynced', 'AngEnblSynced', 'MinSumEnblSynced', 'GlobEnblSynced', 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced') @@ -120,8 +120,8 @@ def get_database(self): 'TimingStatus-Mon': {'type': 'int', 'value': 0b111111111}, 'LLRFStatus-Mon': {'type': 'int', 'value': 0b11}, 'BPMStatusLabels-Cte': { - 'type': 'string', 'count': len(_et.STS_LBLS_BPMS), - 'value': _et.STS_LBLS_BPMS}, + 'type': 'string', 'count': len(_et.STS_LBLS_BPM), + 'value': _et.STS_LBLS_BPM}, 'TimingStatusLabels-Cte': { 'type': 'string', 'count': len(_et.STS_LBLS_TIMING), 'value': _et.STS_LBLS_TIMING}, @@ -257,8 +257,7 @@ def get_database(self): 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqConfig-Cmd': {'type': 'int', 'value': 0}, - # TODO: - # add commands to sync enable status and limits + # Config devices 'IntlkStateConfig-Cmd': {'type': 'int', 'value': 0} } pvs_database = _csdev.add_pvslist_cte(pvs_database) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d25287926..a3ec27853 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -9,11 +9,8 @@ from ..util import update_bit as _updt_bit from ..thread import RepeaterThread as _Repeat -from ..epics import PV as _PV -from ..epics.threading import CAThread as _CAThread +from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback -from ..envars import VACA_PREFIX as _vaca_prefix -from ..namesys import SiriusPVName as _PVName from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger @@ -70,7 +67,6 @@ def __init__(self, tests=True): 'IntlkEvtIn0-SP', 'IntlkEvtIn0-RB', 'IntlkEvtOut-SP', 'IntlkEvtOut-SP', 'IntlkEvtStatus-Mon']) - # TODO: confirmar com maurício se é essa PV mesmo pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True pvo.add_callback(self._callback_intlk) @@ -279,7 +275,7 @@ def set_enbllist(self, intlk, value): # check size new = _np.array(value, dtype=bool) if self._const.nr_bpms != new.size: - self._update_log(f'ERR: Wrong {intlkname} EnblList size.') + self._update_log(f'ERR:Wrong {intlkname} EnblList size.') return False self._enable_lists[intlk] = new @@ -310,6 +306,8 @@ def set_enbllist(self, intlk, value): # save to autosave files self._save_file(intlk, _np.array([value], dtype=bool), 'enbl') + self._update_log('...done.') + # update readback pv self.run_callbacks(f'{intlkname}EnblList-RB', new) return True @@ -428,7 +426,7 @@ def _acq_config(self): 'ERR:Failed to abort acquisition for ' + f'{self._const.bpm_names[-ret-1]:s}.') return - elif ret > 0: + if ret > 0: self._update_log( 'ERR:Failed to start acquisition for ' + f'{self._const.bpm_names[ret-1]:s}.') @@ -449,7 +447,7 @@ def cmd_state_config(self, value=None): for name, enbl in self._enable_lists.items(): if not self.set_enbllist(name, enbl): self._update_log( - f'ERR: could not configure {name:s} enable list') + f'ERR:Could not configure {name:s} enable list') return False for name, lim in self._limits.items(): @@ -615,9 +613,10 @@ def _callback_intlk(self, pvname, value, **kws): trh.start() def _do_callback_intlk(self, value): - # TODO: confirmar o valor que a PV assume em caso de interlock - if value != 0: - self._update_log('FATAL:Orbit interlock raised by EVG.') + if value == 0: + return + + self._update_log('FATAL:Orbit interlock raised by EVG.') if self._is_dry_run: self._update_log('Waiting a little before rearming (dry run)...') From 48811664258624a86b2bee9be765ffb9ca962e54 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 20 Oct 2023 17:01:06 -0300 Subject: [PATCH 014/309] ORBINTLK.FIX: fix bugs in PV setpoints and checks --- siriuspy/siriuspy/orbintlk/main.py | 67 +++++++++++++++++------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index a3ec27853..e126242fe 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -55,6 +55,7 @@ def __init__(self, tests=True): self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] self._thread_acq = None + self._thread_cb = None # devices and connections self._evg_dev = _EVG(props2init=[ @@ -72,7 +73,7 @@ def __init__(self, tests=True): pvo.add_callback(self._callback_intlk) self._llrf_trig = _Trigger( - devname='SI-Glob:TI-LLRF-PsMtn', props2init=[ + trigname='SI-Glob:TI-LLRF-PsMtn', props2init=[ 'Src-Sel', 'Src-Sts', 'DelayRaw-SP', 'DelayRaw-RB', 'State-Sel', 'State-Sts', @@ -81,7 +82,7 @@ def __init__(self, tests=True): ]) self._orbintlk_trig = _Trigger( - devname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ + trigname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ 'Src-Sel', 'Src-Sts', 'DelayRaw-SP', 'DelayRaw-RB', 'State-Sel', 'State-Sts', @@ -167,9 +168,10 @@ def init_database(self): # enable lists for ilk in ['Pos', 'Ang', 'MinSum']: - okl = self._load_file(ilk, 'enbl') + ilkname = ilk.lower() + okl = self._load_file(ilkname, 'enbl') pvn = f'{ilk}EnblList' - enb = self._enable_lists[ilk] + enb = self._enable_lists[ilkname] self.run_callbacks(pvn+'-SP', enb) if not okl: self.run_callbacks(pvn+'-RB', enb) @@ -356,7 +358,7 @@ def set_intlk_lims(self, intlk_lim, value): # --- reset --- - def cmd_reset(self, state): + def cmd_reset(self, state, value=None): """Reset interlock states.""" # if it is a BPM position, BPM general or a global reset if 'pos' in state or 'all' in state: @@ -400,13 +402,12 @@ def set_acq_nrspls_post(self, value): def cmd_acq_config(self, value=None): """Configure BPM PsMtm acquisition.""" - if self._thread_acq is None or not self._thread_acq.is_alive(): - self._thread_acq = _CAThread(target=self._acq_config, daemon=True) - self._thread_acq.start() - return True - else: + if self._thread_acq and self._thread_acq.is_alive(): self._update_log('WARN:BPM configuration already in progress.') return False + self._thread_acq = _CAThread(target=self._acq_config, daemon=True) + self._thread_acq.start() + return True def _acq_config(self): self._update_log('Aborting BPM acquisition...') @@ -510,36 +511,37 @@ def _check_configs(self): dev = self._orbintlk_dev value = 0b11111111 if dev.connected: + value = _updt_bit(value, 0, 0) # PosEnblSynced val = _np.array_equal( dev.pos_enable, self._enable_lists['pos']) - value = _updt_bit(value, 1, val) + value = _updt_bit(value, 1, not val) # AngEnblSynced val = _np.array_equal( dev.ang_enable, self._enable_lists['ang']) - value = _updt_bit(value, 2, val) + value = _updt_bit(value, 2, not val) # MinSumEnblSynced val = _np.array_equal( dev.minsum_enable, self._enable_lists['minsum']) - value = _updt_bit(value, 3, val) + value = _updt_bit(value, 3, not val) # GlobEnblSynced val = _np.array_equal(dev.gen_enable, self._get_gen_bpm_intlk()) - value = _updt_bit(value, 4, val) + value = _updt_bit(value, 4, not val) # PosLimsSynced okp = True for prp in ['pos_x_min', 'pos_x_max', 'pos_y_min', 'pos_y_max']: okp &= _np.array_equal( getattr(dev, prp+'_thres'), self._limits[prp]) - value = _updt_bit(value, 5, okp) + value = _updt_bit(value, 5, not okp) # AngLimsSynced oka = True for prp in ['ang_x_min', 'ang_x_max', 'ang_y_min', 'ang_y_max']: oka &= _np.array_equal( getattr(dev, prp+'_thres'), self._limits[prp]) - value = _updt_bit(value, 6, oka) + value = _updt_bit(value, 6, not oka) # MinSumLimsSynced oks = _np.array_equal(dev.minsum_thres, self._limits['minsum']) - value = _updt_bit(value, 7, oks) + value = _updt_bit(value, 7, not oks) self._bpm_status = value self.run_callbacks('BPMStatus-Mon', self._bpm_status) @@ -549,38 +551,38 @@ def _check_configs(self): # EVG dev = self._evg_dev if dev.connected: - val = dev['IntlkCtrlEnbl-Sts'] == self._state + val = dev['IntlkCtrlEnbl-Sts'] != self._state value = _updt_bit(value, 1, val) okg = True for prp, val in self._const.EVG_CONFIGS: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') okg &= dev[prp_rb] == val - value = _updt_bit(value, 2, okg) + value = _updt_bit(value, 2, not okg) else: value = 0b111 # Orbit Interlock trigger dev = self._orbintlk_trig if dev.connected: - value = _updt_bit(value, 3, True) - value = _updt_bit(value, 4, not bool(dev['Status-Mon'])) + value = _updt_bit(value, 3, 0) + value = _updt_bit(value, 4, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.ORBINTLKTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 5, oko) + value = _updt_bit(value, 5, not oko) else: value += 0b111 << 3 # LLRF trigger dev = self._llrf_trig oko = False if dev.connected: - value = _updt_bit(value, 6, True) - value = _updt_bit(value, 7, not bool(dev['Status-Mon'])) + value = _updt_bit(value, 6, 0) + value = _updt_bit(value, 7, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.LLRFTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 8, oko) + value = _updt_bit(value, 8, not oko) else: value += 0b111 << 6 @@ -591,9 +593,9 @@ def _check_configs(self): value = 0b11 dev = self._llrf if dev.connected: - value = _updt_bit(value, 0, True) + value = _updt_bit(value, 0, 0) value = _updt_bit( - value, 1, dev['ILK:BEAM:TRIP'] == self._llrf_intlk_state) + value, 1, dev['ILK:BEAM:TRIP'] != self._llrf_intlk_state) self.run_callbacks('LLRFStatus-Mon', value) # check time elapsed @@ -607,10 +609,15 @@ def _check_configs(self): # --- callbacks --- - def _callback_intlk(self, pvname, value, **kws): - trh = _CAThread( + def _callback_intlk(self, value, **kws): + _ = kws + if not self._init: + return + if self._thread_cb and self._thread_cb.is_alive(): + return + self._thread_cb = _CAThread( target=self._do_callback_intlk, args=(value, ), daemon=True) - trh.start() + self._thread_cb.start() def _do_callback_intlk(self, value): if value == 0: From 24f7cb39dcd9fa076bf12676e9ab3ed3a5447f16 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 20 Oct 2023 17:01:39 -0300 Subject: [PATCH 015/309] ORBINTLK.ENH: add minimum checks for BPM acquisitions --- siriuspy/siriuspy/orbintlk/csdev.py | 3 ++- siriuspy/siriuspy/orbintlk/main.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 3ecf8b79c..4ae2bfbfd 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -19,7 +19,8 @@ class ETypes(_csdev.ETypes): STS_LBLS_BPM = ( 'Connected', 'PosEnblSynced', 'AngEnblSynced', 'MinSumEnblSynced', 'GlobEnblSynced', - 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced') + 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced', + 'AcqConfigured') STS_LBLS_TIMING = ( 'EVGConn', 'IntlkEnblSynced', 'EVGConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e126242fe..652d98e45 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -542,6 +542,16 @@ def _check_configs(self): # MinSumLimsSynced oks = _np.array_equal(dev.minsum_thres, self._limits['minsum']) value = _updt_bit(value, 7, not oks) + # AcqConfigured + bpms = self._fambpm_dev.devices + okb = all(d.acq_channel == self._acq_chan for d in bpms) + okb &= all([d.acq_nrsamples_post == self._acq_spost for d in bpms]) + okb &= all([d.acq_nrsamples_pre == self._acq_spre for d in bpms]) + okb &= all( + d.acq_repeat == self._const.AcqRepeat.Normal for d in bpms) + okb &= all( + d.acq_trigger == self._const.AcqTrigTyp.External for d in bpms) + value = _updt_bit(value, 8, not okb) self._bpm_status = value self.run_callbacks('BPMStatus-Mon', self._bpm_status) From 2816791a837634041190c344bb1698494c349f1e Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 16:29:40 -0300 Subject: [PATCH 016/309] DEV.BPM.FIX: fix acq_rate parse for int inputs in mturn_config_acquisition --- siriuspy/siriuspy/devices/bpm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/bpm.py b/siriuspy/siriuspy/devices/bpm.py index ae467cf1a..639ac93c9 100644 --- a/siriuspy/siriuspy/devices/bpm.py +++ b/siriuspy/siriuspy/devices/bpm.py @@ -1121,7 +1121,7 @@ def mturn_config_acquisition( """ if acq_rate in self._csbpm.AcqChan: pass - if acq_rate.lower().startswith('facq'): + elif acq_rate.lower().startswith('facq'): acq_rate = self._csbpm.AcqChan.FAcq elif acq_rate.lower().startswith('fofbpha'): acq_rate = self._csbpm.AcqChan.FOFBPha From daa3d6fb9644b77395a7bdb0c57a7fa086d23421 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 16:30:21 -0300 Subject: [PATCH 017/309] DEV.ORBINTLK.FIX: fix bug left in minsum_enable property --- siriuspy/siriuspy/devices/orbit_interlock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index 799d378c5..b88b3f6ed 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -693,7 +693,7 @@ def minsum_enable(self): enbl (numpy.ndarray, 160): enable state for each BPM. """ - return _np.array([b.gen_enable for b in self._devices]) + return _np.array([b.minsum_enable for b in self._devices]) def set_minsum_enable(self, value, timeout=TIMEOUT): """Set enable state for BPM minimum sum interlock.""" From d13b3a582bbc8e0812c2088d11a36437bf6b6f3e Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:33:00 -0300 Subject: [PATCH 018/309] ORBINTLK.ENH: add Fout and EVG RxEnbl control --- siriuspy/siriuspy/orbintlk/csdev.py | 21 +++++++++++- siriuspy/siriuspy/orbintlk/main.py | 52 +++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 4ae2bfbfd..f31a00531 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -22,7 +22,8 @@ class ETypes(_csdev.ETypes): 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced', 'AcqConfigured') STS_LBLS_TIMING = ( - 'EVGConn', 'IntlkEnblSynced', 'EVGConfig', + 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', + 'FoutsConn', 'FoutsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFTrigConn', 'LLRFTrigStatusOK', 'LLRFTrigConfig', ) @@ -53,7 +54,25 @@ class Const(_csdev.Const): ('IntlkCtrlRepeatTime-SP', 0), ('IntlkEvtIn0-SP', 117), ('IntlkEvtOut-SP', 124), + ('RxEnbl-SP', 0b00011110), ) + FOUTS_CONFIGS = { + 2: ( + ('RxEnbl-SP', 0b01000000), + ), + 3: ( + ('RxEnbl-SP', 0b01001011), + # ('RxEnbl-SP', 0b01111111), + ), + 4: ( + ('RxEnbl-SP', 0b00001111), + # ('RxEnbl-SP', 0b01111111), + ), + 5: ( + ('RxEnbl-SP', 0b00001111), + # ('RxEnbl-SP', 0b00111111), + ), + } ORBINTLKTRIG_CONFIG = ( ('Src-Sel', 4), ('DelayRaw-SP', 0), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 652d98e45..7cfe623d6 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -12,7 +12,7 @@ from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ - EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger + EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device from .csdev import Const as _Const, ETypes as _ETypes @@ -58,6 +58,15 @@ def __init__(self, tests=True): self._thread_cb = None # devices and connections + self._fout_devs = { + idx: _Device( + f'CA-RaTim:TI-Fout-{idx}', + props2init=[ + 'RxEnbl-SP', 'RxEnbl-RB', + ]) + for idx in self._const.FOUTS_CONFIGS + } + self._evg_dev = _EVG(props2init=[ 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts', @@ -67,7 +76,9 @@ def __init__(self, tests=True): 'IntlkTbl16to27-Sel', 'IntlkTbl16to27-Sts', 'IntlkEvtIn0-SP', 'IntlkEvtIn0-RB', 'IntlkEvtOut-SP', 'IntlkEvtOut-SP', - 'IntlkEvtStatus-Mon']) + 'IntlkEvtStatus-Mon', + 'RxEnbl-SP', 'RxEnbl-RB', + ]) pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True pvo.add_callback(self._callback_intlk) @@ -466,6 +477,7 @@ def cmd_state_config(self, value=None): return True def _config_timing(self): + # EVG dev = self._evg_dev for prp, val in self._const.EVG_CONFIGS: dev[prp] = val @@ -473,6 +485,16 @@ def _config_timing(self): if not dev._wait(prp_rb, val): self._update_log(f'ERR:Failed to configure EVG PV {prp:s}') return False + # Fouts + for idx, configs in self._const.FOUTS_CONFIGS.items(): + dev = self._fout_devs[idx] + for prp, val in configs: + dev[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not dev._wait(prp_rb, val): + self._update_log( + f'ERR:Failed to configure Fout {idx} PV {prp:s}') + return False # Orbit Interlock Trigger dev = self._orbintlk_trig for prp, val in self._const.ORBINTLKTRIG_CONFIG: @@ -570,31 +592,41 @@ def _check_configs(self): value = _updt_bit(value, 2, not okg) else: value = 0b111 + # Fouts + devs = self._fout_devs + if all(devs[idx].connected for idx in self._const.FOUTS_CONFIGS): + okg = True + for idx, configs in self._const.FOUTS_CONFIGS.items(): + dev = self._fout_devs[idx] + for prp, val in configs: + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + okg &= dev[prp_rb] == val + value = _updt_bit(value, 4, not okg) + else: + value += 0b11 << 3 # Orbit Interlock trigger dev = self._orbintlk_trig if dev.connected: - value = _updt_bit(value, 3, 0) - value = _updt_bit(value, 4, bool(dev['Status-Mon'])) + value = _updt_bit(value, 6, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.ORBINTLKTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 5, not oko) + value = _updt_bit(value, 7, not oko) else: - value += 0b111 << 3 + value += 0b111 << 5 # LLRF trigger dev = self._llrf_trig oko = False if dev.connected: - value = _updt_bit(value, 6, 0) - value = _updt_bit(value, 7, bool(dev['Status-Mon'])) + value = _updt_bit(value, 9, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.LLRFTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 8, not oko) + value = _updt_bit(value, 10, not oko) else: - value += 0b111 << 6 + value += 0b111 << 8 self._timing_status = value self.run_callbacks('TimingStatus-Mon', self._timing_status) From ad6e8f1d29512b51a14cc249dfc93f8cf9e1628a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:33:10 -0300 Subject: [PATCH 019/309] ORBINTLK.FIX: do not run interlock callback when high level is disabled --- siriuspy/siriuspy/orbintlk/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7cfe623d6..10e4bdd6d 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -653,6 +653,8 @@ def _check_configs(self): def _callback_intlk(self, value, **kws): _ = kws + if not self._state: + return if not self._init: return if self._thread_cb and self._thread_cb.is_alive(): From 6b837f49d561f0309eabc24091db4c82f5cd6b13 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:34:00 -0300 Subject: [PATCH 020/309] ORBINTLK.FIX: fix bugs in load file --- siriuspy/siriuspy/orbintlk/main.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 10e4bdd6d..1b016da71 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -694,17 +694,21 @@ def _update_log(self, msg): # ---------------- File handlers --------------------- - def _load_file(self, intlk_lim, dtype='en'): + def _load_file(self, intlk, dtype='en'): suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' msg = 'enable list' if dtype.startswith('en') else 'limits' - filename = getattr(self._const, intlk_lim + suff) + filename = getattr(self._const, intlk + suff) if not _os.path.isfile(filename): return - okl = self.set_intlk_lims(intlk_lim, _np.loadtxt(filename)) + value = _np.loadtxt(filename) + if dtype.startswith('en'): + okl = self.set_enbllist(intlk, value) + else: + okl = self.set_intlk_lims(intlk, value) if okl: - msg = f'Loaded {intlk_lim} {msg}!' + msg = f'Loaded {intlk} {msg}!' else: - msg = f'ERR:Problem loading {intlk_lim} {msg} from file.' + msg = f'ERR:Problem loading {intlk} {msg} from file.' self._update_log(msg) return okl From a83f2c63c837f5182185f231dddc701202b445b4 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:34:34 -0300 Subject: [PATCH 021/309] ORBINTLK.ENH: enable more events in interlock table --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index f31a00531..ad340503a 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -48,7 +48,7 @@ class Const(_csdev.Const): DEF_TIME2WAIT_DRYRUN = 10 # [s] EVG_CONFIGS = ( - ('IntlkTbl0to15-Sel', 1), + ('IntlkTbl0to15-Sel', 0b010000010000001), ('IntlkTbl16to27-Sel', 0), ('IntlkCtrlRepeat-Sel', 0), ('IntlkCtrlRepeatTime-SP', 0), From e2f020080f7ab302c8ab2c0f20dadd70599b2d36 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:35:47 -0300 Subject: [PATCH 022/309] ORBINTLK.FIX: fix bug in set_enable --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 1b016da71..ca629c1a5 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -254,7 +254,7 @@ def fambpm_dev(self): def set_enable(self, value): """Set orbit interlock state. Configure global BPM interlock enable and EVG interlock enable.""" - if value not in _ETypes.DSBL_ENBL: + if not 0 <= value < len(_ETypes.DSBL_ENBL): return False if value: From 7618f0d1de76d98f92791ac46ff91e1dfcfe9b38 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 23 Oct 2023 17:46:40 -0300 Subject: [PATCH 023/309] ORBINTLK.ENH: add checks for BPM PsMtn trigger --- siriuspy/siriuspy/orbintlk/csdev.py | 9 +++++++- siriuspy/siriuspy/orbintlk/main.py | 36 ++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index ad340503a..8125f37d0 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -25,7 +25,8 @@ class ETypes(_csdev.ETypes): 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', 'FoutsConn', 'FoutsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', - 'LLRFTrigConn', 'LLRFTrigStatusOK', 'LLRFTrigConfig', + 'LLRFPsMtnTrigConn', 'LLRFPsMtnTrigStatusOK', 'LLRFPsMtnTrigConfig', + 'BPMPsMtnTrigConn', 'BPMPsMtnTrigStatusOK', 'BPMPsMtnTrigConfig', ) STS_LBLS_LLRF = ('Connected', 'Configured') @@ -86,6 +87,12 @@ class Const(_csdev.Const): ('State-Sel', 1), ('WidthRaw-SP', 9369), ) + BPMPSMTNTRIG_CONFIG = ( + ('Src-Sel', 5), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 1), + ) AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ca629c1a5..7b5c45c5a 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -92,6 +92,15 @@ def __init__(self, tests=True): 'Status-Mon', ]) + self._bpmpstmn_trig = _Trigger( + trigname='SI-Fam:TI-BPM-PsMtn', props2init=[ + 'Src-Sel', 'Src-Sts', + 'DelayRaw-SP', 'DelayRaw-RB', + 'State-Sel', 'State-Sts', + 'WidthRaw-SP', 'WidthRaw-RB', + 'Status-Mon', + ]) + self._orbintlk_trig = _Trigger( trigname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ 'Src-Sel', 'Src-Sts', @@ -504,14 +513,23 @@ def _config_timing(self): self._update_log( f'ERR:Failed to configure OrbIntlk Trigger PV {prp:s}') return False - # Orbit Interlock Trigger + # LLRF PsMtn Trigger dev = self._llrf_trig for prp, val in self._const.LLRFTRIG_CONFIG: dev[prp] = val prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') if not dev._wait(prp_rb, val): self._update_log( - f'ERR:Failed to configure LLRF Trigger PV {prp:s}') + f'ERR:Failed to configure LLRF PsMtn Trigger PV {prp:s}') + return False + # BPM PsMtn Trigger + dev = self._bpmpstmn_trig + for prp, val in self._const.BPMPSMTNTRIG_CONFIG: + dev[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not dev._wait(prp_rb, val): + self._update_log( + f'ERR:Failed to configure BPM PsMtn Trigger PV {prp:s}') return False return True @@ -615,7 +633,7 @@ def _check_configs(self): value = _updt_bit(value, 7, not oko) else: value += 0b111 << 5 - # LLRF trigger + # LLRF PsMtn trigger dev = self._llrf_trig oko = False if dev.connected: @@ -627,6 +645,18 @@ def _check_configs(self): value = _updt_bit(value, 10, not oko) else: value += 0b111 << 8 + # BPM PsMtn trigger + dev = self._bpmpstmn_trig + oko = False + if dev.connected: + value = _updt_bit(value, 12, bool(dev['Status-Mon'])) + oko = True + for prp, val in self._const.BPMPSMTNTRIG_CONFIG: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + oko &= dev[prp_rb] == val + value = _updt_bit(value, 13, not oko) + else: + value += 0b111 << 11 self._timing_status = value self.run_callbacks('TimingStatus-Mon', self._timing_status) From a8861a77dc4b0db45088e80f9532acb9bd4f1631 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 24 Oct 2023 09:53:55 -0300 Subject: [PATCH 024/309] ORBINTLK.ENH: do not let user set different enable states for BPM pairs --- siriuspy/siriuspy/orbintlk/main.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7b5c45c5a..2e30bba7f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -300,6 +300,12 @@ def set_enbllist(self, intlk, value): self._update_log(f'ERR:Wrong {intlkname} EnblList size.') return False + # check coerence, down/up pair should have same enable state + if not self._check_valid_enablelist(new): + self._update_log('ERR:BPM should be enabled in pairs') + self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') + return False + self._enable_lists[intlk] = new # do not set enable lists and save to file in initialization @@ -544,6 +550,11 @@ def _get_gen_bpm_intlk(self): pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] return _np.logical_or(pos, ang) + def _check_valid_enablelist(self, enbllist): + aux = _np.roll(enbllist, 1) + # check if pairs have the same enable state + return not any(_np.sum(aux.reshape(-1, 2), axis=1) == 1) + def _check_configs(self): _t0 = _time.time() From e09f6fac3a58b506007d7ebd9f22f6e8647495fa Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 24 Oct 2023 09:54:32 -0300 Subject: [PATCH 025/309] ORBINTLK.FIX: fix bug in general state checks --- siriuspy/siriuspy/orbintlk/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 2e30bba7f..5b1e3b82d 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -576,7 +576,9 @@ def _check_configs(self): dev.minsum_enable, self._enable_lists['minsum']) value = _updt_bit(value, 3, not val) # GlobEnblSynced - val = _np.array_equal(dev.gen_enable, self._get_gen_bpm_intlk()) + genval = self._get_gen_bpm_intlk() if self._state else \ + _np.zeros(self._const.nr_bpms, dtype=bool) + val = _np.array_equal(dev.gen_enable, genval) value = _updt_bit(value, 4, not val) # PosLimsSynced okp = True From 32815b1e5c2a4e487bd509447987c59078abcfd1 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 24 Oct 2023 17:04:37 -0300 Subject: [PATCH 026/309] ORBINTLK.FIX: fix limits PV type --- siriuspy/siriuspy/orbintlk/csdev.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 8125f37d0..c3cdee966 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -186,78 +186,78 @@ def get_database(self): # Limits 'PosXMinLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for X'}, 'PosXMinLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for X'}, 'PosXMaxLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for X'}, 'PosXMaxLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for X'}, 'PosYMinLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for Y'}, 'PosYMinLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position minimum limits for Y'}, 'PosYMaxLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for Y'}, 'PosYMaxLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'position maximum limits for Y'}, 'AngXMinLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for X'}, 'AngXMinLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for X'}, 'AngXMaxLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for X'}, 'AngXMaxLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for X'}, 'AngYMinLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for Y'}, 'AngYMinLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle minimum limits for Y'}, 'AngYMaxLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for Y'}, 'AngYMaxLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'angle maximum limits for Y'}, 'MinSumLim-SP': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'minimum sum limits'}, 'MinSumLim-RB': { - 'type': 'int', 'count': self.nr_bpms, + 'type': 'float', 'count': self.nr_bpms, 'value': self.nr_bpms*[0], 'unit': 'minimum sum limits'}, # Reset From 05570b18dbc2f23a8b74bf107be6920c71866370 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 24 Oct 2023 17:05:32 -0300 Subject: [PATCH 027/309] ORBINTLK.ENH: do not let user set different limits for BPM pairs --- siriuspy/siriuspy/orbintlk/main.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 5b1e3b82d..e27fc5e7c 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -358,6 +358,12 @@ def set_intlk_lims(self, intlk_lim, value): self._update_log(f'ERR: Wrong {limname} limits size.') return False + # check coerence, down/up pair should have same limits + if not self._check_valid_limits(new): + self._update_log('ERR:BPM pairs should have equal limits') + self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') + return False + self._limits[intlk_lim] = new # do not set limits and save to file in initialization @@ -555,6 +561,11 @@ def _check_valid_enablelist(self, enbllist): # check if pairs have the same enable state return not any(_np.sum(aux.reshape(-1, 2), axis=1) == 1) + def _check_valid_limits(self, limits): + aux = _np.roll(limits, 1) + # check if pairs have the same limit + return not any(_np.diff(aux.reshape(-1, 2), axis=1) != 0) + def _check_configs(self): _t0 = _time.time() From 0d8bff6f033a930f2605b4edac70b6f49c555d7a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 24 Oct 2023 18:20:45 -0300 Subject: [PATCH 028/309] ORBINTLK.ENH: improve logs when setting enable states and limits --- siriuspy/siriuspy/devices/orbit_interlock.py | 105 +++++++++++-------- siriuspy/siriuspy/orbintlk/main.py | 16 ++- 2 files changed, 76 insertions(+), 45 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index b88b3f6ed..267869560 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -637,25 +637,28 @@ def gen_enable(self): """ return _np.array([b.gen_enable for b in self._devices]) - def set_gen_enable(self, value, timeout=TIMEOUT): + def set_gen_enable(self, value, timeout=TIMEOUT, return_prob=False): """Set enable state for BPM general interlock.""" self._set_devices_propty(self.devices, 'IntlkEn-Sel', value) return self._wait_devices_propty( - self.devices, 'IntlkEn-Sts', value, timeout=timeout) + self.devices, 'IntlkEn-Sts', value, timeout=timeout, + return_prob=return_prob) - def cmd_gen_enable(self, timeout=TIMEOUT): + def cmd_gen_enable(self, timeout=TIMEOUT, return_prob=False): """Enable all BPM general interlock.""" for dev in self.devices: dev.gen_enable = 1 return self._wait_devices_propty( - self.devices, 'IntlkEn-Sts', 1, timeout=timeout) + self.devices, 'IntlkEn-Sts', 1, timeout=timeout, + return_prob=return_prob) - def cmd_gen_disable(self, timeout=TIMEOUT): + def cmd_gen_disable(self, timeout=TIMEOUT, return_prob=False): """Disable all BPM general interlock.""" for dev in self.devices: dev.gen_enable = 0 return self._wait_devices_propty( - self.devices, 'IntlkEn-Sts', 0, timeout=timeout) + self.devices, 'IntlkEn-Sts', 0, timeout=timeout, + return_prob=return_prob) def cmd_reset_gen(self): """Reset all BPM general interlock.""" @@ -695,25 +698,28 @@ def minsum_enable(self): """ return _np.array([b.minsum_enable for b in self._devices]) - def set_minsum_enable(self, value, timeout=TIMEOUT): + def set_minsum_enable(self, value, timeout=TIMEOUT, return_prob=False): """Set enable state for BPM minimum sum interlock.""" self._set_devices_propty(self.devices, 'IntlkMinSumEn-Sel', value) return self._wait_devices_propty( - self.devices, 'IntlkMinSumEn-Sts', value, timeout=timeout) + self.devices, 'IntlkMinSumEn-Sts', value, timeout=timeout, + return_prob=return_prob) - def cmd_minsum_enable(self, timeout=TIMEOUT): + def cmd_minsum_enable(self, timeout=TIMEOUT, return_prob=False): """Enable all BPM minimum sum threshold.""" for dev in self.devices: dev.minsum_enable = 1 return self._wait_devices_propty( - self.devices, 'IntlkMinSumEn-Sts', 1, timeout=timeout) + self.devices, 'IntlkMinSumEn-Sts', 1, timeout=timeout, + return_prob=return_prob) - def cmd_minsum_disable(self, timeout=TIMEOUT): + def cmd_minsum_disable(self, timeout=TIMEOUT, return_prob=False): """Disable all BPM minimum sum threshold.""" for dev in self.devices: dev.minsum_enable = 0 return self._wait_devices_propty( - self.devices, 'IntlkMinSumEn-Sts', 0, timeout=timeout) + self.devices, 'IntlkMinSumEn-Sts', 0, timeout=timeout, + return_prob=return_prob) @property def minsum_thres(self): @@ -724,7 +730,7 @@ def minsum_thres(self): """ return _np.array([b.minsum_thres for b in self._devices]) - def set_minsum_thres(self, value, timeout=TIMEOUT): + def set_minsum_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set minimum sum thresholds. Args: @@ -738,7 +744,8 @@ def set_minsum_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtMinSum-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtMinSum-RB', value, timeout=timeout) + self.devices, 'IntlkLmtMinSum-RB', value, timeout=timeout, + return_prob=return_prob) # --- position interlock --- @@ -752,25 +759,28 @@ def pos_enable(self): """ return _np.array([b.pos_enable for b in self._devices]) - def set_pos_enable(self, value, timeout=TIMEOUT): + def set_pos_enable(self, value, timeout=TIMEOUT, return_prob=False): """Set enable state for BPM position interlock.""" self._set_devices_propty(self.devices, 'IntlkPosEn-Sel', value) return self._wait_devices_propty( - self.devices, 'IntlkPosEn-Sts', value, timeout=timeout) + self.devices, 'IntlkPosEn-Sts', value, timeout=timeout, + return_prob=return_prob) - def cmd_pos_enable(self, timeout=TIMEOUT): + def cmd_pos_enable(self, timeout=TIMEOUT, return_prob=False): """Enable all BPM position interlock.""" for dev in self.devices: dev.pos_enable = 1 return self._wait_devices_propty( - self.devices, 'IntlkPosEn-Sts', 1, timeout=timeout) + self.devices, 'IntlkPosEn-Sts', 1, timeout=timeout, + return_prob=return_prob) - def cmd_pos_disable(self, timeout=TIMEOUT): + def cmd_pos_disable(self, timeout=TIMEOUT, return_prob=False): """Disable all BPM position interlock.""" for dev in self.devices: dev.pos_enable = 0 return self._wait_devices_propty( - self.devices, 'IntlkPosEn-Sts', 0, timeout=timeout) + self.devices, 'IntlkPosEn-Sts', 0, timeout=timeout, + return_prob=return_prob) def cmd_reset_pos(self): """Reset all BPM position interlock.""" @@ -788,7 +798,7 @@ def pos_x_min_thres(self): """ return _np.array([b.pos_x_min_thres for b in self._devices]) - def set_pos_x_min_thres(self, value, timeout=TIMEOUT): + def set_pos_x_min_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set minimum x position thresholds. Args: @@ -802,7 +812,8 @@ def set_pos_x_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMinX-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtPosMinX-RB', value, timeout=timeout) + self.devices, 'IntlkLmtPosMinX-RB', value, timeout=timeout, + return_prob=return_prob) @property def pos_x_max_thres(self): @@ -814,7 +825,7 @@ def pos_x_max_thres(self): """ return _np.array([b.pos_x_max_thres for b in self._devices]) - def set_pos_x_max_thres(self, value, timeout=TIMEOUT): + def set_pos_x_max_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set maximum x position thresholds. Args: @@ -828,7 +839,8 @@ def set_pos_x_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMaxX-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtPosMaxX-RB', value, timeout=timeout) + self.devices, 'IntlkLmtPosMaxX-RB', value, timeout=timeout, + return_prob=return_prob) @property def pos_y_min_thres(self): @@ -840,7 +852,7 @@ def pos_y_min_thres(self): """ return _np.array([b.pos_y_min_thres for b in self._devices]) - def set_pos_y_min_thres(self, value, timeout=TIMEOUT): + def set_pos_y_min_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set minimum y position thresholds. Args: @@ -854,7 +866,8 @@ def set_pos_y_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMinY-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtPosMinY-RB', value, timeout=timeout) + self.devices, 'IntlkLmtPosMinY-RB', value, timeout=timeout, + return_prob=return_prob) @property def pos_y_max_thres(self): @@ -866,7 +879,7 @@ def pos_y_max_thres(self): """ return _np.array([b.pos_y_max_thres for b in self._devices]) - def set_pos_y_max_thres(self, value, timeout=TIMEOUT): + def set_pos_y_max_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set maximum y position thresholds. Args: @@ -880,7 +893,8 @@ def set_pos_y_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtPosMaxY-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtPosMaxY-RB', value, timeout=timeout) + self.devices, 'IntlkLmtPosMaxY-RB', value, timeout=timeout, + return_prob=return_prob) @property def pos_inst_lower(self): @@ -1014,25 +1028,28 @@ def ang_enable(self): """ return _np.array([b.ang_enable for b in self._devices]) - def set_ang_enable(self, value, timeout=TIMEOUT): + def set_ang_enable(self, value, timeout=TIMEOUT, return_prob=False): """Set enable state for BPM angulation interlock.""" self._set_devices_propty(self.devices, 'IntlkAngEn-Sel', value) return self._wait_devices_propty( - self.devices, 'IntlkAngEn-Sts', value, timeout=timeout) + self.devices, 'IntlkAngEn-Sts', value, timeout=timeout, + return_prob=return_prob) - def cmd_ang_enable(self, timeout=TIMEOUT): + def cmd_ang_enable(self, timeout=TIMEOUT, return_prob=False): """Enable all BPM angulation interlock.""" for dev in self.devices: dev.ang_enable = 1 return self._wait_devices_propty( - self.devices, 'IntlkAngEn-Sts', 1, timeout=timeout) + self.devices, 'IntlkAngEn-Sts', 1, timeout=timeout, + return_prob=return_prob) - def cmd_ang_disable(self, timeout=TIMEOUT): + def cmd_ang_disable(self, timeout=TIMEOUT, return_prob=False): """Disable all BPM angulation interlock.""" for dev in self.devices: dev.ang_enable = 0 return self._wait_devices_propty( - self.devices, 'IntlkAngEn-Sts', 0, timeout=timeout) + self.devices, 'IntlkAngEn-Sts', 0, timeout=timeout, + return_prob=return_prob) def cmd_reset_ang(self): """Reset all BPM angulation interlock.""" @@ -1050,7 +1067,7 @@ def ang_x_min_thres(self): """ return _np.array([b.ang_x_min_thres for b in self._devices]) - def set_ang_x_min_thres(self, value, timeout=TIMEOUT): + def set_ang_x_min_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set minimum x angle thresholds. Args: @@ -1064,7 +1081,8 @@ def set_ang_x_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMinX-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtAngMinX-RB', value, timeout=timeout) + self.devices, 'IntlkLmtAngMinX-RB', value, timeout=timeout, + return_prob=return_prob) @property def ang_x_max_thres(self): @@ -1076,7 +1094,7 @@ def ang_x_max_thres(self): """ return _np.array([b.ang_x_max_thres for b in self._devices]) - def set_ang_x_max_thres(self, value, timeout=TIMEOUT): + def set_ang_x_max_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set maximum x angle thresholds. Args: @@ -1090,7 +1108,8 @@ def set_ang_x_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMaxX-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtAngMaxX-RB', value, timeout=timeout) + self.devices, 'IntlkLmtAngMaxX-RB', value, timeout=timeout, + return_prob=return_prob) @property def ang_y_min_thres(self): @@ -1102,7 +1121,7 @@ def ang_y_min_thres(self): """ return _np.array([b.ang_y_min_thres for b in self._devices]) - def set_ang_y_min_thres(self, value, timeout=TIMEOUT): + def set_ang_y_min_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set minimum y angle thresholds. Args: @@ -1116,7 +1135,8 @@ def set_ang_y_min_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMinY-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtAngMinY-RB', value, timeout=timeout) + self.devices, 'IntlkLmtAngMinY-RB', value, timeout=timeout, + return_prob=return_prob) @property def ang_y_max_thres(self): @@ -1128,7 +1148,7 @@ def ang_y_max_thres(self): """ return _np.array([b.ang_y_max_thres for b in self._devices]) - def set_ang_y_max_thres(self, value, timeout=TIMEOUT): + def set_ang_y_max_thres(self, value, timeout=TIMEOUT, return_prob=False): """Set maximum y angle thresholds. Args: @@ -1142,7 +1162,8 @@ def set_ang_y_max_thres(self, value, timeout=TIMEOUT): value = self._handle_thres_input(value) self._set_devices_propty(self.devices, 'IntlkLmtAngMaxY-SP', value) return self._wait_devices_propty( - self.devices, 'IntlkLmtAngMaxY-RB', value, timeout=timeout) + self.devices, 'IntlkLmtAngMaxY-RB', value, timeout=timeout, + return_prob=return_prob) @property def ang_inst_lower(self): diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e27fc5e7c..e01f75a9b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -318,17 +318,24 @@ def set_enbllist(self, intlk, value): # set BPM interlock specific enable state fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') - if not fun(list(value)): + ret = fun(list(value), return_prob=True) + if not ret[0]: self._update_log(f'ERR:Could not set BPM {intlkname}') self._update_log('ERR:interlock enable.') + for item in ret[1]: + self._update_log(f'ERR:Verify:{item}') return False # if interlock is already enabled, update BPM general enable state if self._state and intlk in ['pos', 'ang']: glob_en = self._get_gen_bpm_intlk() - if not self._orbintlk_dev.set_gen_enable(list(glob_en)): + ret = self._orbintlk_dev.set_gen_enable( + list(glob_en), return_prob=True) + if not ret[0]: self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') + for item in ret[1]: + self._update_log(f'ERR:Verify:{item}') return False # save to autosave files @@ -376,9 +383,12 @@ def set_intlk_lims(self, intlk_lim, value): # set BPM interlock limits fun = getattr(self._orbintlk_dev, f'set_{intlk_lim}_thres') - if not fun(list(value)): + ret = fun(list(value), return_prob=True) + if not ret[0]: self._update_log(f'ERR:Could not set BPM {limname}') self._update_log('ERR:interlock limits.') + for item in ret[1]: + self._update_log(f'ERR:Verify:{item}') return False # save to autosave files From 3a47dbe7241edbff0dced16dd96cf1154ddd8565 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 26 Oct 2023 11:12:21 -0300 Subject: [PATCH 029/309] ORBINTLK.FIX: fix BPM PsMtn trigger width --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index c3cdee966..da8304db2 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -91,7 +91,7 @@ class Const(_csdev.Const): ('Src-Sel', 5), ('DelayRaw-SP', 0), ('State-Sel', 1), - ('WidthRaw-SP', 1), + ('WidthRaw-SP', 6), ) AcqChan = _csbpm.AcqChan From 592baa9425b16ec337fa4af2fbc8a855c04ad7b3 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 26 Oct 2023 11:19:43 -0300 Subject: [PATCH 030/309] ORBINTLK.MNT: add note about RxEnbl value --- siriuspy/siriuspy/orbintlk/csdev.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index da8304db2..2a44696bd 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -58,6 +58,8 @@ class Const(_csdev.Const): ('RxEnbl-SP', 0b00011110), ) FOUTS_CONFIGS = { + # NOTE: change RxEnbl when unnecessary + # protection in gateware is removed 2: ( ('RxEnbl-SP', 0b01000000), ), From d91e3538867f59beb0c5fb3544b03809939f5766 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 26 Oct 2023 11:25:07 -0300 Subject: [PATCH 031/309] ORBINTLK.ENH: add feature to watch RTM locked state and reset latchs --- siriuspy/siriuspy/orbintlk/main.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e01f75a9b..db6394099 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -8,6 +8,7 @@ import numpy as _np from ..util import update_bit as _updt_bit +from ..namesys import SiriusPVName as _SiriusPVName from ..thread import RepeaterThread as _Repeat from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback @@ -111,6 +112,18 @@ def __init__(self, tests=True): 'Status-Mon', ]) + self._afcti_devs = { + idx+1: _Device( + f'IA-{idx+1:02}RaBPM:TI-AMCFPGAEVR', + props2init=[ + 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', + ], auto_monitor_mon=True) + for idx in range(20) + } + for dev in self._afcti_devs.values(): + pvo = dev.pv_object('RTMClkLockedLtc-Mon') + pvo.add_callback(self._callback_rtmlock) + self._orbintlk_dev = _OrbitIntlk() self._llrf = _ASLLRF(devname=_ASLLRF.DEVICES.SI, props2init=[ @@ -743,6 +756,16 @@ def _do_callback_intlk(self, value): # reconfigure BPM configuration self.cmd_acq_config() + def _callback_rtmlock(self, pvname, value, **kws): + if value == 1: + return + devidx = int(_SiriusPVName(pvname).sub.split('Ra')[0]) + dev = self._afcti_devs[devidx] + self._update_log(f'WARN:AFC Timing {devidx} raised RTM clock loss') + _time.sleep(1) # sleep a little before reseting + self._update_log(f'WARN:reseting AFC Timing {devidx} lock latchs.') + dev['ClkLockedLtcRst-Cmd'] = 1 + # --- auxiliary log methods --- def _update_log(self, msg): From 8bb6a02dafef13c3cee647f587ce488ac80c02e1 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 27 Oct 2023 13:57:29 -0300 Subject: [PATCH 032/309] ORBINTLK.ENH: add callbacks to check whether the event chain is working --- siriuspy/siriuspy/orbintlk/main.py | 56 +++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index db6394099..086c8a185 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -56,7 +56,8 @@ def __init__(self, tests=True): self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] self._thread_acq = None - self._thread_cb = None + self._thread_cbevg = None + self._thread_cbbpm = None # devices and connections self._fout_devs = { @@ -82,7 +83,7 @@ def __init__(self, tests=True): ]) pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True - pvo.add_callback(self._callback_intlk) + pvo.add_callback(self._callback_evgintlk) self._llrf_trig = _Trigger( trigname='SI-Glob:TI-LLRF-PsMtn', props2init=[ @@ -124,7 +125,17 @@ def __init__(self, tests=True): pvo = dev.pv_object('RTMClkLockedLtc-Mon') pvo.add_callback(self._callback_rtmlock) + self._everf_dev = _Device( + 'RA-RaSIA01:TI-EVE', props2init=['OTP01EvtCnt-Mon', ], + auto_monitor_mon=True) + self._everf_dev.pv_object('OTP01EvtCnt-Mon').wait_for_connection() + self._everf_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] or 0 + self._orbintlk_dev = _OrbitIntlk() + for dev in self._orbintlk_dev.devices: + pvo = dev.pv_object('IntlkLtc-Mon') + pvo.auto_monitor = True + pvo.add_callback(self._callback_bpmintlk) self._llrf = _ASLLRF(devname=_ASLLRF.DEVICES.SI, props2init=[ 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', @@ -728,19 +739,19 @@ def _check_configs(self): # --- callbacks --- - def _callback_intlk(self, value, **kws): + def _callback_evgintlk(self, value, **kws): _ = kws if not self._state: return if not self._init: return - if self._thread_cb and self._thread_cb.is_alive(): + if self._thread_cbevg and self._thread_cbevg.is_alive(): return - self._thread_cb = _CAThread( - target=self._do_callback_intlk, args=(value, ), daemon=True) - self._thread_cb.start() + self._thread_cbevg = _CAThread( + target=self._do_callback_evgintlk, args=(value, ), daemon=True) + self._thread_cbevg.start() - def _do_callback_intlk(self, value): + def _do_callback_evgintlk(self, value): if value == 0: return @@ -766,6 +777,35 @@ def _callback_rtmlock(self, pvname, value, **kws): self._update_log(f'WARN:reseting AFC Timing {devidx} lock latchs.') dev['ClkLockedLtcRst-Cmd'] = 1 + def _callback_bpmintlk(self, pvname, value, **kws): + _ = kws + if not value: + return + if not self._state: + return + if not self._init: + return + if self._thread_cbbpm and self._thread_cbbpm.is_alive(): + return + bpmname = _SiriusPVName(pvname).device_name + self._thread_cbbpm = _CAThread( + target=self._do_callback_bpmintlk, args=(bpmname, ), daemon=True) + self._thread_cbbpm.start() + + def _do_callback_bpmintlk(self, bpmname): + self._update_log(f'FATAL:{bpmname} raised orbit interlock.') + _time.sleep(1) + # verify if RF EVE propagated the event PsMtn + new_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] + if new_evtcnt == self._everf_evtcnt: + self._update_log('ERR:RF EVE did not propagate event PsMtn') + # TODO: should kill the beam in this case? + self._everf_evtcnt = new_evtcnt + # verify if EVG propagated the event Intlk + evgintlksts = self._evg_dev['IntlkEvtStatus-Mon'] + if evgintlksts & 0b1: + self._update_log('WARN:EVG did not propagate event Intlk') + # --- auxiliary log methods --- def _update_log(self, msg): From 84bda4fb36083e3e924ea85c33fd9a5995184273 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 27 Oct 2023 13:58:37 -0300 Subject: [PATCH 033/309] ORBINTLK.ENH: add connection callback on AFC timing to log eventual problems --- siriuspy/siriuspy/orbintlk/main.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 086c8a185..f6bac4eb4 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -124,6 +124,7 @@ def __init__(self, tests=True): for dev in self._afcti_devs.values(): pvo = dev.pv_object('RTMClkLockedLtc-Mon') pvo.add_callback(self._callback_rtmlock) + pvo.connection_callbacks.append(self._conn_callback_rtmlock) self._everf_dev = _Device( 'RA-RaSIA01:TI-EVE', props2init=['OTP01EvtCnt-Mon', ], @@ -777,6 +778,13 @@ def _callback_rtmlock(self, pvname, value, **kws): self._update_log(f'WARN:reseting AFC Timing {devidx} lock latchs.') dev['ClkLockedLtcRst-Cmd'] = 1 + def _conn_callback_rtmlock(self, pvname, conn, **kws): + if conn: + return + devname = _SiriusPVName(pvname).device_name + self._update_log(f'WARN:{devname} disconnected') + # TODO: should kill the beam in this case? + def _callback_bpmintlk(self, pvname, value, **kws): _ = kws if not value: From 441c7c9a4281d5307a66ed8172cb9bf4edf1c2c7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 27 Oct 2023 15:00:53 -0300 Subject: [PATCH 034/309] ORBINTLK.MNT: fix variable names, imrpove logs and cleanup code --- siriuspy/siriuspy/orbintlk/main.py | 47 ++++++++++++------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f6bac4eb4..fd9b2a5d5 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -94,7 +94,7 @@ def __init__(self, tests=True): 'Status-Mon', ]) - self._bpmpstmn_trig = _Trigger( + self._bpmpsmtn_trig = _Trigger( trigname='SI-Fam:TI-BPM-PsMtn', props2init=[ 'Src-Sel', 'Src-Sts', 'DelayRaw-SP', 'DelayRaw-RB', @@ -419,6 +419,8 @@ def set_intlk_lims(self, intlk_lim, value): # save to autosave files self._save_file(intlk_lim, _np.array([value]), 'lim') + self._update_log('...done.') + # update readback pv self.run_callbacks(f'{limname}Lim-RB', new) return True @@ -551,33 +553,20 @@ def _config_timing(self): self._update_log( f'ERR:Failed to configure Fout {idx} PV {prp:s}') return False - # Orbit Interlock Trigger - dev = self._orbintlk_trig - for prp, val in self._const.ORBINTLKTRIG_CONFIG: - dev[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not dev._wait(prp_rb, val): - self._update_log( - f'ERR:Failed to configure OrbIntlk Trigger PV {prp:s}') - return False - # LLRF PsMtn Trigger - dev = self._llrf_trig - for prp, val in self._const.LLRFTRIG_CONFIG: - dev[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not dev._wait(prp_rb, val): - self._update_log( - f'ERR:Failed to configure LLRF PsMtn Trigger PV {prp:s}') - return False - # BPM PsMtn Trigger - dev = self._bpmpstmn_trig - for prp, val in self._const.BPMPSMTNTRIG_CONFIG: - dev[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not dev._wait(prp_rb, val): - self._update_log( - f'ERR:Failed to configure BPM PsMtn Trigger PV {prp:s}') - return False + trig2config = { + self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, + self._llrf_trig: self._const.LLRFTRIG_CONFIG, + self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, + } + for trig, configs in trig2config.items(): + for prp, val in configs: + name = trig.dev + trig.idx + trig[prp] = val + prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') + if not trig._wait(prp_rb, val): + self._update_log( + f'ERR:Failed to configure {name} PV {prp:s}') + return False return True def _config_llrf(self): @@ -705,7 +694,7 @@ def _check_configs(self): else: value += 0b111 << 8 # BPM PsMtn trigger - dev = self._bpmpstmn_trig + dev = self._bpmpsmtn_trig oko = False if dev.connected: value = _updt_bit(value, 12, bool(dev['Status-Mon'])) From 99050678b029b5bf2f32e10b6842a0d0be0dc7dc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 27 Oct 2023 16:22:56 -0300 Subject: [PATCH 035/309] ORBINTLK.FIX: fix bugs in BPM interlock callback --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- siriuspy/siriuspy/orbintlk/main.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 2a44696bd..18ba1de88 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -46,7 +46,7 @@ class Const(_csdev.Const): DEF_TIMESLEEP = 0.1 # [s] DEF_TIMEWAIT = 3 # [s] - DEF_TIME2WAIT_DRYRUN = 10 # [s] + DEF_TIME2WAIT_INTLKREARM = 10 # [s] EVG_CONFIGS = ( ('IntlkTbl0to15-Sel', 0b010000010000001), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index fd9b2a5d5..e4188c2df 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -747,9 +747,8 @@ def _do_callback_evgintlk(self, value): self._update_log('FATAL:Orbit interlock raised by EVG.') - if self._is_dry_run: - self._update_log('Waiting a little before rearming (dry run)...') - _time.sleep(self._const.DEF_TIME2WAIT_DRYRUN) + self._update_log('Waiting a little before rearming...') + _time.sleep(self._const.DEF_TIME2WAIT_INTLKREARM) # reset latch flags for BPM interlock core and EVG self.cmd_reset('all') @@ -791,17 +790,22 @@ def _callback_bpmintlk(self, pvname, value, **kws): def _do_callback_bpmintlk(self, bpmname): self._update_log(f'FATAL:{bpmname} raised orbit interlock.') - _time.sleep(1) + # wait minimum period for RF EVE event count to be updated + _time.sleep(.1) # verify if RF EVE propagated the event PsMtn new_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] if new_evtcnt == self._everf_evtcnt: self._update_log('ERR:RF EVE did not propagate event PsMtn') # TODO: should kill the beam in this case? self._everf_evtcnt = new_evtcnt + # wait minimum period for BPM to update interlock PVs + _time.sleep(2) # verify if EVG propagated the event Intlk evgintlksts = self._evg_dev['IntlkEvtStatus-Mon'] - if evgintlksts & 0b1: + if not evgintlksts & 0b1: self._update_log('WARN:EVG did not propagate event Intlk') + # reset BPM orbit interlock, once EVG callback was not triggered + self.cmd_reset('bpm_all') # --- auxiliary log methods --- From 6a14f4c6371808b266b311b9f52e1969b1c26095 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 27 Oct 2023 16:27:42 -0300 Subject: [PATCH 036/309] ORBINTLK.ENH: change BPM acquisition default settings --- siriuspy/siriuspy/orbintlk/csdev.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 18ba1de88..3eabdeb41 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -271,19 +271,19 @@ def get_database(self): # Acquisition 'PsMtmAcqChannel-Sel': { - 'type': 'enum', 'value': self.AcqChan.FAcq, + 'type': 'enum', 'value': self.AcqChan.TbT, 'enums': self.AcqChan._fields}, 'PsMtmAcqChannel-Sts': { - 'type': 'enum', 'value': self.AcqChan.FAcq, + 'type': 'enum', 'value': self.AcqChan.TbT, 'enums': self.AcqChan._fields}, 'PsMtmAcqSamplesPre-SP': { - 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'type': 'int', 'value': 20000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqSamplesPre-RB': { - 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'type': 'int', 'value': 20000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqSamplesPost-SP': { - 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'type': 'int', 'value': 20000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqSamplesPost-RB': { - 'type': 'int', 'value': 5000, 'lolim': 0, 'hilim': 1_000_000}, + 'type': 'int', 'value': 20000, 'lolim': 0, 'hilim': 1_000_000}, 'PsMtmAcqConfig-Cmd': {'type': 'int', 'value': 0}, # Config devices From b6af91f621c8e1c7cc4ae2f29b10b107187d3dcc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 6 Nov 2023 11:01:41 -0300 Subject: [PATCH 037/309] DEV.TRIG.ENH: add option to set auto_monitor_mon attribute --- siriuspy/siriuspy/devices/timing.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/timing.py b/siriuspy/siriuspy/devices/timing.py index 7a9358ad6..a209df452 100644 --- a/siriuspy/siriuspy/devices/timing.py +++ b/siriuspy/siriuspy/devices/timing.py @@ -271,7 +271,7 @@ class Trigger(_Device): 'StatusLabels-Cte', 'TotalDelay-Mon', 'TotalDelayRaw-Mon', 'WidthRaw-RB', 'WidthRaw-SP') - def __init__(self, trigname, props2init='all'): + def __init__(self, trigname, props2init='all', auto_monitor_mon=False): """Init.""" _database = _get_hl_trigger_database(trigname) all_props = tuple(_database) @@ -282,7 +282,9 @@ def __init__(self, trigname, props2init='all'): else: props2init = list(set(all_props) & set(props2init)) self._source_options = _database['Src-Sel']['enums'] - super().__init__(trigname, props2init=props2init) + super().__init__( + trigname, props2init=props2init, + auto_monitor_mon=auto_monitor_mon) @property def status(self): From 07a24af413b632c2c198780b73669a1b64e9401b Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 6 Nov 2023 11:11:57 -0300 Subject: [PATCH 038/309] ORBINTLK.MNT: fix BPM initial status --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- siriuspy/siriuspy/orbintlk/main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 3eabdeb41..b8b82ca4d 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -145,7 +145,7 @@ def get_database(self): 'Enable-Sts': { 'type': 'enum', 'enums': _et.DSBL_ENBL, 'value': self.DsblEnbl.Dsbl}, - 'BPMStatus-Mon': {'type': 'int', 'value': 0b11111111}, + 'BPMStatus-Mon': {'type': 'int', 'value': 0b111111111}, 'TimingStatus-Mon': {'type': 'int', 'value': 0b111111111}, 'LLRFStatus-Mon': {'type': 'int', 'value': 0b11}, 'BPMStatusLabels-Cte': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e4188c2df..42185262e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -595,7 +595,7 @@ def _check_configs(self): # bpm status dev = self._orbintlk_dev - value = 0b11111111 + value = 0b111111111 if dev.connected: value = _updt_bit(value, 0, 0) # PosEnblSynced From 9aec45e82832e54c78f365eb0c047acb7e8a56e9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 6 Nov 2023 11:23:34 -0300 Subject: [PATCH 039/309] ORBINTLK.ENH: implement timing net reliability checks, kill beam on reliability failures --- siriuspy/siriuspy/orbintlk/csdev.py | 2 + siriuspy/siriuspy/orbintlk/main.py | 187 ++++++++++++++++++++-------- 2 files changed, 136 insertions(+), 53 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index b8b82ca4d..b74d8c989 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -157,6 +157,8 @@ def get_database(self): 'LLRFStatusLabels-Cte': { 'type': 'string', 'count': len(_et.STS_LBLS_LLRF), 'value': _et.STS_LBLS_LLRF}, + 'TimingMonitoredDevices-Mon': { + 'type': 'char', 'count': 1000, 'value': ''}, # Enable lists 'PosEnblList-SP': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 42185262e..263b7822e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -9,11 +9,13 @@ from ..util import update_bit as _updt_bit from ..namesys import SiriusPVName as _SiriusPVName +from ..search import LLTimeSearch as _LLTimeSearch from ..thread import RepeaterThread as _Repeat from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ - EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device + EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device, \ + RFKillBeam as _RFKillBeam from .csdev import Const as _Const, ETypes as _ETypes @@ -58,17 +60,10 @@ def __init__(self, tests=True): self._thread_acq = None self._thread_cbevg = None self._thread_cbbpm = None + self._ti_mon_devs = set() # devices and connections - self._fout_devs = { - idx: _Device( - f'CA-RaTim:TI-Fout-{idx}', - props2init=[ - 'RxEnbl-SP', 'RxEnbl-RB', - ]) - for idx in self._const.FOUTS_CONFIGS - } - + # # EVG self._evg_dev = _EVG(props2init=[ 'IntlkCtrlEnbl-Sel', 'IntlkCtrlEnbl-Sts', 'IntlkCtrlRst-Sel', 'IntlkCtrlRst-Sts', @@ -83,8 +78,53 @@ def __init__(self, tests=True): ]) pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True - pvo.add_callback(self._callback_evgintlk) + pvo.add_callback(self._callback_evg_intlk) + pvo.connection_callbacks.append(self._conn_callback_timing) + + # # Fouts + self._fout_devs = { + idx: _Device( + f'CA-RaTim:TI-Fout-{idx}', + props2init=[ + 'RxEnbl-SP', 'RxEnbl-RB', + 'OUT0RxLocked-Mon', 'OUT1RxLocked-Mon', + 'OUT2RxLocked-Mon', 'OUT3RxLocked-Mon', + 'OUT4RxLocked-Mon', 'OUT5RxLocked-Mon', + 'OUT6RxLocked-Mon', 'OUT7RxLocked-Mon', + ], auto_monitor_mon=True) + for idx in self._const.FOUTS_CONFIGS + } + for dev in self._fout_devs.values(): + for idx in range(8): + pvo = dev.pv_object(f'OUT{idx}RxLocked-Mon') + pvo.add_callback(self._callback_fout_rxlock) + if idx == 0: + pvo.connection_callbacks.append(self._conn_callback_timing) + + # # AFC timing + self._afcti_devs = { + idx+1: _Device( + f'IA-{idx+1:02}RaBPM:TI-AMCFPGAEVR', + props2init=[ + 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', + ], auto_monitor_mon=True) + for idx in range(20) + } + for dev in self._afcti_devs.values(): + pvo = dev.pv_object('RTMClkLockedLtc-Mon') + pvo.add_callback(self._callback_afcti_rtmlock) + pvo.connection_callbacks.append(self._conn_callback_timing) + + # # RF EVE + self._everf_dev = _Device( + 'RA-RaSIA01:TI-EVE', props2init=['OTP01EvtCnt-Mon', ], + auto_monitor_mon=True) + pvo = self._everf_dev.pv_object('OTP01EvtCnt-Mon') + pvo.wait_for_connection() + pvo.connection_callbacks.append(self._conn_callback_timing) + self._everf_evtcnt = pvo.get() or 0 + # # HL triggers self._llrf_trig = _Trigger( trigname='SI-Glob:TI-LLRF-PsMtn', props2init=[ 'Src-Sel', 'Src-Sts', @@ -92,7 +132,7 @@ def __init__(self, tests=True): 'State-Sel', 'State-Sts', 'WidthRaw-SP', 'WidthRaw-RB', 'Status-Mon', - ]) + ], auto_monitor_mon=True) self._bpmpsmtn_trig = _Trigger( trigname='SI-Fam:TI-BPM-PsMtn', props2init=[ @@ -101,7 +141,7 @@ def __init__(self, tests=True): 'State-Sel', 'State-Sts', 'WidthRaw-SP', 'WidthRaw-RB', 'Status-Mon', - ]) + ], auto_monitor_mon=True) self._orbintlk_trig = _Trigger( trigname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ @@ -111,36 +151,14 @@ def __init__(self, tests=True): 'WidthRaw-SP', 'WidthRaw-RB', 'Direction-Sel', 'Direction-Sts', 'Status-Mon', - ]) - - self._afcti_devs = { - idx+1: _Device( - f'IA-{idx+1:02}RaBPM:TI-AMCFPGAEVR', - props2init=[ - 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', - ], auto_monitor_mon=True) - for idx in range(20) - } - for dev in self._afcti_devs.values(): - pvo = dev.pv_object('RTMClkLockedLtc-Mon') - pvo.add_callback(self._callback_rtmlock) - pvo.connection_callbacks.append(self._conn_callback_rtmlock) - - self._everf_dev = _Device( - 'RA-RaSIA01:TI-EVE', props2init=['OTP01EvtCnt-Mon', ], - auto_monitor_mon=True) - self._everf_dev.pv_object('OTP01EvtCnt-Mon').wait_for_connection() - self._everf_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] or 0 + ], auto_monitor_mon=True) + # # BPM devices self._orbintlk_dev = _OrbitIntlk() for dev in self._orbintlk_dev.devices: pvo = dev.pv_object('IntlkLtc-Mon') pvo.auto_monitor = True - pvo.add_callback(self._callback_bpmintlk) - - self._llrf = _ASLLRF(devname=_ASLLRF.DEVICES.SI, props2init=[ - 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', - ]) + pvo.add_callback(self._callback_bpm_intlk) self._fambpm_dev = _FamBPMs( devname=_FamBPMs.DEVICES.SI, ispost_mortem=True, @@ -153,6 +171,14 @@ def __init__(self, tests=True): 'ACQTriggerEvent-Sel', 'ACQTriggerEvent-Sts', 'ACQStatus-Sts']) + # # RF devices + self._llrf = _ASLLRF( + devname=_ASLLRF.DEVICES.SI, + props2init=[ + 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP']) + + self._killbeam = _RFKillBeam() + # pvs to write methods self.map_pv2write = { 'Enable-Sel': self.set_enable, @@ -310,6 +336,9 @@ def set_enable(self, value): self._state = value self.run_callbacks('Enable-Sts', self._state) + + self._update_ti_monitored_devices() + return True # --- enable lists --- @@ -368,6 +397,8 @@ def set_enbllist(self, intlk, value): self._update_log('...done.') + self._update_ti_monitored_devices() + # update readback pv self.run_callbacks(f'{intlkname}EnblList-RB', new) return True @@ -576,6 +607,13 @@ def _config_llrf(self): return False return True + def _get_enabled_sections(self): + enbllist = self._get_gen_bpm_intlk() + aux = _np.roll(enbllist, 1) + subs = _np.where(_np.sum(aux.reshape(20, -1), axis=1) > 0)[0] + subs += 1 + return subs + def _get_gen_bpm_intlk(self): pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] return _np.logical_or(pos, ang) @@ -729,7 +767,7 @@ def _check_configs(self): # --- callbacks --- - def _callback_evgintlk(self, value, **kws): + def _callback_evg_intlk(self, value, **kws): _ = kws if not self._state: return @@ -738,10 +776,10 @@ def _callback_evgintlk(self, value, **kws): if self._thread_cbevg and self._thread_cbevg.is_alive(): return self._thread_cbevg = _CAThread( - target=self._do_callback_evgintlk, args=(value, ), daemon=True) + target=self._do_callback_evg_intlk, args=(value, ), daemon=True) self._thread_cbevg.start() - def _do_callback_evgintlk(self, value): + def _do_callback_evg_intlk(self, value): if value == 0: return @@ -756,24 +794,44 @@ def _do_callback_evgintlk(self, value): # reconfigure BPM configuration self.cmd_acq_config() - def _callback_rtmlock(self, pvname, value, **kws): - if value == 1: + def _callback_fout_rxlock(self, pvname, value, **kws): + if value == 1: # it is ok + return + pvname = _SiriusPVName(pvname) + devidx = int(pvname.idx) + outnam = pvname.propty.split('Rx')[0] + self._update_log(f'FATAL:{outnam} of Fout {devidx} lost lock') + devout = pvname.device_name.substitute(propty_name=outnam) + # verify if this is an orbit interlock reliability failure + shouldkill = devout in self._ti_mon_devs + if shouldkill: + self._update_log('FATAL:Orbit interlock reliability failure') + self._do_killbeam() + + def _callback_afcti_rtmlock(self, pvname, value, **kws): + if value == 1: # it is ok return devidx = int(_SiriusPVName(pvname).sub.split('Ra')[0]) dev = self._afcti_devs[devidx] - self._update_log(f'WARN:AFC Timing {devidx} raised RTM clock loss') + self._update_log(f'WARN:AFC Timing {devidx} raised RTM clock loss,') _time.sleep(1) # sleep a little before reseting self._update_log(f'WARN:reseting AFC Timing {devidx} lock latchs.') dev['ClkLockedLtcRst-Cmd'] = 1 - def _conn_callback_rtmlock(self, pvname, conn, **kws): + def _conn_callback_timing(self, pvname, conn, **kws): if conn: return - devname = _SiriusPVName(pvname).device_name - self._update_log(f'WARN:{devname} disconnected') - # TODO: should kill the beam in this case? + pvname = _SiriusPVName(pvname) + self._update_log(f'FATAL:{pvname.device_name} disconnected') + if not self._state: + return + # verify if this is an orbit interlock reliability failure + shouldkill = pvname.device_name in self._ti_mon_devs + if shouldkill: + self._update_log('FATAL:Orbit interlock reliability failure') + self._do_killbeam() - def _callback_bpmintlk(self, pvname, value, **kws): + def _callback_bpm_intlk(self, pvname, value, **kws): _ = kws if not value: return @@ -785,18 +843,19 @@ def _callback_bpmintlk(self, pvname, value, **kws): return bpmname = _SiriusPVName(pvname).device_name self._thread_cbbpm = _CAThread( - target=self._do_callback_bpmintlk, args=(bpmname, ), daemon=True) + target=self._do_callback_bpm_intlk, args=(bpmname, ), daemon=True) self._thread_cbbpm.start() - def _do_callback_bpmintlk(self, bpmname): + def _do_callback_bpm_intlk(self, bpmname): self._update_log(f'FATAL:{bpmname} raised orbit interlock.') + # send kill beam as fast as possible + self._do_killbeam() # wait minimum period for RF EVE event count to be updated _time.sleep(.1) # verify if RF EVE propagated the event PsMtn new_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] if new_evtcnt == self._everf_evtcnt: - self._update_log('ERR:RF EVE did not propagate event PsMtn') - # TODO: should kill the beam in this case? + self._update_log('WARN:RF EVE did not propagate event PsMtn') self._everf_evtcnt = new_evtcnt # wait minimum period for BPM to update interlock PVs _time.sleep(2) @@ -807,6 +866,28 @@ def _do_callback_bpmintlk(self, bpmname): # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') + def _do_killbeam(self): + # if not in dry run, send kill beam + if not self._is_dry_run: + self._update_log('FATAL:Sending kill beam.') + self._killbeam.cmd_kill_beam() + + def _update_ti_monitored_devices(self): + value = set() + if self._state: + value.add(self._evg_dev.devname) + value.add(self._everf_dev.devname) + for sec in self._get_enabled_sections(): + afcti = f'IA-{sec:02}RaBPM:TI-AMCFPGAEVR' + value.add(afcti) + foutout = _LLTimeSearch.get_trigsrc2fout_mapping()[afcti] + value.add(foutout) + foutdev = _SiriusPVName(foutout).device_name + value.add(foutdev) + + self._ti_mon_devs = value + self.run_callbacks('TimingMonitoredDevices-Mon', '\n'.join(value)) + # --- auxiliary log methods --- def _update_log(self, msg): From d6b3775970ce476c5399894935ba2aaa70593338 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 6 Nov 2023 18:58:23 -0300 Subject: [PATCH 040/309] ORBINTLK.FIX: adapt Fout checks for AFC timing IOC implementation --- siriuspy/siriuspy/orbintlk/main.py | 45 +++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 263b7822e..c4eb22901 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -7,7 +7,7 @@ import numpy as _np -from ..util import update_bit as _updt_bit +from ..util import update_bit as _updt_bit, get_bit as _get_bit from ..namesys import SiriusPVName as _SiriusPVName from ..search import LLTimeSearch as _LLTimeSearch from ..thread import RepeaterThread as _Repeat @@ -59,6 +59,7 @@ def __init__(self, tests=True): self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] self._thread_acq = None self._thread_cbevg = None + self._thread_cbfout = None self._thread_cbbpm = None self._ti_mon_devs = set() @@ -87,19 +88,14 @@ def __init__(self, tests=True): f'CA-RaTim:TI-Fout-{idx}', props2init=[ 'RxEnbl-SP', 'RxEnbl-RB', - 'OUT0RxLocked-Mon', 'OUT1RxLocked-Mon', - 'OUT2RxLocked-Mon', 'OUT3RxLocked-Mon', - 'OUT4RxLocked-Mon', 'OUT5RxLocked-Mon', - 'OUT6RxLocked-Mon', 'OUT7RxLocked-Mon', + 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) for idx in self._const.FOUTS_CONFIGS } for dev in self._fout_devs.values(): - for idx in range(8): - pvo = dev.pv_object(f'OUT{idx}RxLocked-Mon') - pvo.add_callback(self._callback_fout_rxlock) - if idx == 0: - pvo.connection_callbacks.append(self._conn_callback_timing) + pvo = dev.pv_object('RxLockedLtc-Mon') + pvo.add_callback(self._callback_fout_rxlock) + pvo.connection_callbacks.append(self._conn_callback_timing) # # AFC timing self._afcti_devs = { @@ -795,18 +791,35 @@ def _do_callback_evg_intlk(self, value): self.cmd_acq_config() def _callback_fout_rxlock(self, pvname, value, **kws): - if value == 1: # it is ok + if not self._state: + return + if not self._init: return + if value == 0b11111111: # it is ok + return + if self._thread_cbfout and self._thread_cbfout.is_alive(): + return + self._thread_cbfout = _CAThread( + target=self._do_callback_fout_rxlock, args=(value, ), daemon=True) + self._thread_cbfout.start() + + def _do_callback_fout_rxlock(self, pvname, value): pvname = _SiriusPVName(pvname) devidx = int(pvname.idx) - outnam = pvname.propty.split('Rx')[0] - self._update_log(f'FATAL:{outnam} of Fout {devidx} lost lock') - devout = pvname.device_name.substitute(propty_name=outnam) - # verify if this is an orbit interlock reliability failure - shouldkill = devout in self._ti_mon_devs + dev = self._fout_devs[devidx] + shouldkill = False + for bit in range(8): + if _get_bit(value, bit): + continue + outnam = f'OUT{bit}' + self._update_log(f'FATAL:{outnam} of Fout {devidx} lost lock') + devout = pvname.device_name.substitute(propty_name=outnam) + # verify if this is an orbit interlock reliability failure + shouldkill |= devout in self._ti_mon_devs if shouldkill: self._update_log('FATAL:Orbit interlock reliability failure') self._do_killbeam() + dev['RxLockedLtcRst-Cmd'] = 1 def _callback_afcti_rtmlock(self, pvname, value, **kws): if value == 1: # it is ok From aa756674bae1d3d3289b74ceb57c6122504f45dc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 7 Nov 2023 14:01:59 -0300 Subject: [PATCH 041/309] ORBINTLK.MNT: fix docstrings and cleanup code. Thanks to @fernandohds564 and @murilobalves! --- siriuspy/siriuspy/devices/orbit_interlock.py | 4 ++-- siriuspy/siriuspy/orbintlk/csdev.py | 21 +++++-------------- siriuspy/siriuspy/orbintlk/main.py | 22 ++++++++------------ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/siriuspy/siriuspy/devices/orbit_interlock.py b/siriuspy/siriuspy/devices/orbit_interlock.py index 267869560..a4806e071 100644 --- a/siriuspy/siriuspy/devices/orbit_interlock.py +++ b/siriuspy/siriuspy/devices/orbit_interlock.py @@ -127,7 +127,7 @@ def _diff(var1, var2): class BPMOrbitIntlk(BaseOrbitIntlk, _Device): - """This device group the orbit interlock PVs from one BPM.""" + """This device group the orbit interlock PVs from one BPM.""" PROPERTIES_DEFAULT = ( # ============================================================== @@ -142,7 +142,7 @@ class BPMOrbitIntlk(BaseOrbitIntlk, _Device): 'IntlkMinSumEn-Sel', 'IntlkMinSumEn-Sts', # Minimum sum threshold (sum counts in FAcq rate): 'IntlkLmtMinSum-SP', 'IntlkLmtMinSum-RB', - # Instantaneous interlock, dificult to be checked in the current + # Instantaneous interlock, difficult to be checked in the current # gateware implementation 'Intlk-Mon', # Latch interlock, clean only when respective "Clr" PV is triggered diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index b74d8c989..5fa0b77bf 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -60,21 +60,10 @@ class Const(_csdev.Const): FOUTS_CONFIGS = { # NOTE: change RxEnbl when unnecessary # protection in gateware is removed - 2: ( - ('RxEnbl-SP', 0b01000000), - ), - 3: ( - ('RxEnbl-SP', 0b01001011), - # ('RxEnbl-SP', 0b01111111), - ), - 4: ( - ('RxEnbl-SP', 0b00001111), - # ('RxEnbl-SP', 0b01111111), - ), - 5: ( - ('RxEnbl-SP', 0b00001111), - # ('RxEnbl-SP', 0b00111111), - ), + 2: (('RxEnbl-SP', 0b01000000), ), + 3: (('RxEnbl-SP', 0b01001011), ), # 0b01111111 + 4: (('RxEnbl-SP', 0b00001111), ), # 0b01111111 + 5: (('RxEnbl-SP', 0b00001111), ), # 0b00111111 } ORBINTLKTRIG_CONFIG = ( ('Src-Sel', 4), @@ -94,7 +83,7 @@ class Const(_csdev.Const): ('DelayRaw-SP', 0), ('State-Sel', 1), ('WidthRaw-SP', 6), - ) + ) AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c4eb22901..0ae3e977a 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -351,7 +351,7 @@ def set_enbllist(self, intlk, value): return False # check coerence, down/up pair should have same enable state - if not self._check_valid_enablelist(new): + if not self._check_valid_bpmconfig(new): self._update_log('ERR:BPM should be enabled in pairs') self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') return False @@ -418,7 +418,7 @@ def set_intlk_lims(self, intlk_lim, value): return False # check coerence, down/up pair should have same limits - if not self._check_valid_limits(new): + if not self._check_valid_bpmconfig(new): self._update_log('ERR:BPM pairs should have equal limits') self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') return False @@ -456,6 +456,7 @@ def set_intlk_lims(self, intlk_lim, value): def cmd_reset(self, state, value=None): """Reset interlock states.""" + _ = value # if it is a BPM position, BPM general or a global reset if 'pos' in state or 'all' in state: self._orbintlk_dev.cmd_reset_pos() @@ -614,22 +615,17 @@ def _get_gen_bpm_intlk(self): pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] return _np.logical_or(pos, ang) - def _check_valid_enablelist(self, enbllist): - aux = _np.roll(enbllist, 1) - # check if pairs have the same enable state - return not any(_np.sum(aux.reshape(-1, 2), axis=1) == 1) - - def _check_valid_limits(self, limits): - aux = _np.roll(limits, 1) - # check if pairs have the same limit - return not any(_np.diff(aux.reshape(-1, 2), axis=1) != 0) + def _check_valid_bpmconfig(self, config): + aux = _np.roll(config, 1) + # check if pairs have the same config + return not _np.any(_np.diff(aux.reshape(-1, 2), axis=1) != 0) def _check_configs(self): _t0 = _time.time() # bpm status dev = self._orbintlk_dev - value = 0b111111111 + value = (1 << 9) - 1 if dev.connected: value = _updt_bit(value, 0, 0) # PosEnblSynced @@ -744,7 +740,7 @@ def _check_configs(self): self.run_callbacks('TimingStatus-Mon', self._timing_status) # LLRF Status - value = 0b11 + value = (1 << 2) - 1 dev = self._llrf if dev.connected: value = _updt_bit(value, 0, 0) From 67292a3f0462a72010b989621065ec1abb37af39 Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 7 Nov 2023 15:03:47 -0300 Subject: [PATCH 042/309] Adapt IDFF to new IDSearch --- siriuspy/siriuspy/idff/config.py | 57 ++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/siriuspy/siriuspy/idff/config.py b/siriuspy/siriuspy/idff/config.py index 307fe0647..9b1fc6d4c 100644 --- a/siriuspy/siriuspy/idff/config.py +++ b/siriuspy/siriuspy/idff/config.py @@ -11,19 +11,21 @@ class IDFFConfig(_ConfigDBDocument): """Insertion Device Feedforward Configuration.""" - # NOTE: for EPU50 there is a large discrepancy - # between RB/SP/Mon phase values - PPARAM_TOL = 0.5 # [mm] - KPARAM_TOL = 0.1 # [mm] CONFIGDB_TYPE = 'si_idff' def __init__(self, name=None, url=None): """.""" name_ = name or 'idff_' + self.generate_config_name() + self._idname = None self._polarization_definitions = None super().__init__( config_type=IDFFConfig.CONFIGDB_TYPE, name=name_, url=url) + @property + def idname(self): + """Return idname corresponding to IDFFConfig.""" + return self._idname + @property def pparameter_pvname(self): """Return ID pparameter pvname.""" @@ -126,7 +128,7 @@ def create_template_config(idname): polarizations = dict() for polarization in idff['polarizations']: - if polarization == 'none': + if polarization == _IDSearch.POL_NONE_STR: polarizations[polarization] = dict(ptable) else: polarizations[polarization] = dict(ktable) @@ -164,28 +166,23 @@ def __str__(self): def load(self, discarded=False): """.""" super().load(discarded=discarded) + self._find_idname() self._calc_polariz_defs() def get_polarization_state(self, pparameter, kparameter): """Return polarization state based on ID parameteres.""" - poldefs = self._polarization_definitions - if poldefs is None: - raise ValueError('No IDFF configuration defined.') - for pol, val in poldefs.items(): - if pol == 'none': - continue - if val is None or abs(pparameter - val) < IDFFConfig.PPARAM_TOL: - return pol - if abs(kparameter - poldefs['none']) < IDFFConfig.KPARAM_TOL: - return 'none' - return 'not_defined' + idname = self._idname + pol_idx = _IDSearch.conv_idname_2_polarization_state( + idname, pparameter, kparameter) + pol_str = _IDSearch.conv_idname_2_polarizations_sts(idname)[pol_idx] + return pol_str def check_valid_value(self, value): """.""" if not super().check_valid_value(value): return False for pol, table in value['polarizations'].items(): - if pol == 'none': + if pol == _IDSearch.POL_NONE_STR: nrpts = len(table['pparameter']) else: nrpts = len(table['kparameter']) @@ -207,15 +204,39 @@ def _get_corr_pvnames(self, cname1, cname2): def _set_value(self, value): super()._set_value(value) + self._find_idname() self._calc_polariz_defs() def _calc_polariz_defs(self): """.""" + # fill polarization data struct data = self._value['polarizations'] poldefs = dict() for pol, tab in data.items(): - if pol != 'none': + if pol != _IDSearch.POL_NONE_STR: poldefs[pol] = tab['pparameter'] else: poldefs[pol] = tab['kparameter'] self._polarization_definitions = poldefs + + def _find_idname(self): + """.""" + # find associated idname + self._idname = None + pvnames = self._value['pvnames'] + kparameter, pparameter = pvnames['kparameter'], pvnames['pparameter'] + for idname in _IDSearch.get_idnames(): + kparam_propty = _IDSearch.conv_idname_2_kparameter_propty(idname) + pparam_propty = _IDSearch.conv_idname_2_pparameter_propty(idname) + if None in (kparam_propty, pparam_propty): + continue + kparam = idname + ':' + kparam_propty + pparam = idname + ':' + pparam_propty + if kparam == kparameter and pparam == pparameter: + self._idname = idname + break + if self._idname is None: + # could not find idname + raise ValueError( + 'kparameter and pparameter in config are not ' + 'associated with an idname!') From 350cf5013c6aabdfc938f0c7de1939bf888cae9c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 7 Nov 2023 19:42:29 -0300 Subject: [PATCH 043/309] ORBINTLK.ENH: get Fouts, EVG and RF EVE configurations from timing tables --- siriuspy/siriuspy/orbintlk/csdev.py | 74 +++++++++++++++++++++-------- siriuspy/siriuspy/orbintlk/main.py | 37 +++++++++------ 2 files changed, 77 insertions(+), 34 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 5fa0b77bf..ef3789768 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -3,7 +3,8 @@ import os as _os from .. import csdev as _csdev -from ..search import BPMSearch as _BPMSearch +from ..util import ClassProperty as _classproperty +from ..search import BPMSearch as _BPMSearch, LLTimeSearch as _LLTimeSearch from ..namesys import SiriusPVName as _PVName from ..diagbeam.bpm.csdev import Const as _csbpm @@ -46,25 +47,8 @@ class Const(_csdev.Const): DEF_TIMESLEEP = 0.1 # [s] DEF_TIMEWAIT = 3 # [s] - DEF_TIME2WAIT_INTLKREARM = 10 # [s] + DEF_TIME2WAIT_INTLKREARM = 2*60 # [s] - EVG_CONFIGS = ( - ('IntlkTbl0to15-Sel', 0b010000010000001), - ('IntlkTbl16to27-Sel', 0), - ('IntlkCtrlRepeat-Sel', 0), - ('IntlkCtrlRepeatTime-SP', 0), - ('IntlkEvtIn0-SP', 117), - ('IntlkEvtOut-SP', 124), - ('RxEnbl-SP', 0b00011110), - ) - FOUTS_CONFIGS = { - # NOTE: change RxEnbl when unnecessary - # protection in gateware is removed - 2: (('RxEnbl-SP', 0b01000000), ), - 3: (('RxEnbl-SP', 0b01001011), ), # 0b01111111 - 4: (('RxEnbl-SP', 0b00001111), ), # 0b01111111 - 5: (('RxEnbl-SP', 0b00001111), ), # 0b00111111 - } ORBINTLKTRIG_CONFIG = ( ('Src-Sel', 4), ('DelayRaw-SP', 0), @@ -85,6 +69,58 @@ class Const(_csdev.Const): ('WidthRaw-SP', 6), ) + __EVG_CONFIGS = None + __FOUTS_CONFIGS = None + + @_classproperty + def EVG_CONFIGS(cls): + """EVG configurations""" + if cls.__EVG_CONFIGS is not None: + return cls.__EVG_CONFIGS + + # fouts + fout2configs = dict() + for fout, trigsrc in _LLTimeSearch.get_fout2trigsrc_mapping().items(): + outs = { + int(k.strip('OUT')) for k, v in trigsrc.items() if + v.endswith('RaBPM:TI-AMCFPGAEVR') or # SI BPM paths + v.endswith('IA-14RaDiag03:TI-EVE')} # DCCTs path + if not outs: + continue + rxenbl = 0 + for i in outs: + rxenbl += (1 << i) + fout2configs[fout] = (('RxEnbl-SP', rxenbl), ) + cls.__FOUTS_CONFIGS = fout2configs + + # evg + evgouts = set() + for out, fout in _LLTimeSearch.get_evg2fout_mapping().items(): + if fout in fout2configs: + evgouts.add(int(out.strip('OUT'))) + evgrxenbl = 0 + for i in evgouts: + evgrxenbl += (1 << i) + + evgconfigs = ( + ('IntlkTbl0to15-Sel', 0b010000010000001), + ('IntlkTbl16to27-Sel', 0), + ('IntlkCtrlRepeat-Sel', 0), + ('IntlkCtrlRepeatTime-SP', 0), + ('IntlkEvtIn0-SP', 117), + ('IntlkEvtOut-SP', 124), + ('RxEnbl-SP', evgrxenbl), + ) + cls.__EVG_CONFIGS = evgconfigs + + return cls.__EVG_CONFIGS + + @_classproperty + def FOUTS_CONFIGS(cls): + """Fouts configurations.""" + cls.EVG_CONFIGS + return cls.__FOUTS_CONFIGS + AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp AcqRepeat = _csbpm.AcqRepeat diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 0ae3e977a..f5320e7fc 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1,5 +1,6 @@ """High Level Orbit Interlock main application.""" +import re as _re import os as _os import logging as _log import time as _time @@ -9,7 +10,8 @@ from ..util import update_bit as _updt_bit, get_bit as _get_bit from ..namesys import SiriusPVName as _SiriusPVName -from ..search import LLTimeSearch as _LLTimeSearch +from ..search import LLTimeSearch as _LLTimeSearch, \ + HLTimeSearch as _HLTimeSearch from ..thread import RepeaterThread as _Repeat from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback @@ -84,13 +86,13 @@ def __init__(self, tests=True): # # Fouts self._fout_devs = { - idx: _Device( - f'CA-RaTim:TI-Fout-{idx}', + devname: _Device( + devname, props2init=[ 'RxEnbl-SP', 'RxEnbl-RB', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) - for idx in self._const.FOUTS_CONFIGS + for devname in self._const.FOUTS_CONFIGS } for dev in self._fout_devs.values(): pvo = dev.pv_object('RxLockedLtc-Mon') @@ -112,10 +114,16 @@ def __init__(self, tests=True): pvo.connection_callbacks.append(self._conn_callback_timing) # # RF EVE + llrftrig = _SiriusPVName(_HLTimeSearch.get_ll_trigger_names( + 'SI-Glob:TI-LLRF-PsMtn')[0]) + llrftrig_nam = _re.sub(r'[0-9]', '', llrftrig.propty) + llrftrig_idx = int(llrftrig.propty.split(llrftrig_nam)[1]) + self._llrf_evtcnt_pvname = f'{llrftrig_nam}{llrftrig_idx:02}EvtCnt-Mon' self._everf_dev = _Device( - 'RA-RaSIA01:TI-EVE', props2init=['OTP01EvtCnt-Mon', ], + llrftrig.device_name, + props2init=[self._llrf_evtcnt_pvname, ], auto_monitor_mon=True) - pvo = self._everf_dev.pv_object('OTP01EvtCnt-Mon') + pvo = self._everf_dev.pv_object(self._llrf_evtcnt_pvname) pvo.wait_for_connection() pvo.connection_callbacks.append(self._conn_callback_timing) self._everf_evtcnt = pvo.get() or 0 @@ -572,14 +580,14 @@ def _config_timing(self): self._update_log(f'ERR:Failed to configure EVG PV {prp:s}') return False # Fouts - for idx, configs in self._const.FOUTS_CONFIGS.items(): - dev = self._fout_devs[idx] + for devname, configs in self._const.FOUTS_CONFIGS.items(): + dev = self._fout_devs[devname] for prp, val in configs: dev[prp] = val prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') if not dev._wait(prp_rb, val): self._update_log( - f'ERR:Failed to configure Fout {idx} PV {prp:s}') + f'ERR:Failed to configure {devname} PV {prp:s}') return False trig2config = { self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, @@ -690,7 +698,7 @@ def _check_configs(self): value = 0b111 # Fouts devs = self._fout_devs - if all(devs[idx].connected for idx in self._const.FOUTS_CONFIGS): + if all(devs[devn].connected for devn in self._const.FOUTS_CONFIGS): okg = True for idx, configs in self._const.FOUTS_CONFIGS.items(): dev = self._fout_devs[idx] @@ -801,21 +809,20 @@ def _callback_fout_rxlock(self, pvname, value, **kws): def _do_callback_fout_rxlock(self, pvname, value): pvname = _SiriusPVName(pvname) - devidx = int(pvname.idx) - dev = self._fout_devs[devidx] + devname = pvname.device_name shouldkill = False for bit in range(8): if _get_bit(value, bit): continue outnam = f'OUT{bit}' - self._update_log(f'FATAL:{outnam} of Fout {devidx} lost lock') + self._update_log(f'FATAL:{outnam} of {devname} lost lock') devout = pvname.device_name.substitute(propty_name=outnam) # verify if this is an orbit interlock reliability failure shouldkill |= devout in self._ti_mon_devs if shouldkill: self._update_log('FATAL:Orbit interlock reliability failure') self._do_killbeam() - dev['RxLockedLtcRst-Cmd'] = 1 + self._fout_devs[devname]['RxLockedLtcRst-Cmd'] = 1 def _callback_afcti_rtmlock(self, pvname, value, **kws): if value == 1: # it is ok @@ -862,7 +869,7 @@ def _do_callback_bpm_intlk(self, bpmname): # wait minimum period for RF EVE event count to be updated _time.sleep(.1) # verify if RF EVE propagated the event PsMtn - new_evtcnt = self._everf_dev['OTP01EvtCnt-Mon'] + new_evtcnt = self._everf_dev[self._llrf_evtcnt_pvname] if new_evtcnt == self._everf_evtcnt: self._update_log('WARN:RF EVE did not propagate event PsMtn') self._everf_evtcnt = new_evtcnt From 1273c911f85ec129999cf9f3f12b724a7b48a2a1 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 8 Nov 2023 12:30:52 -0300 Subject: [PATCH 044/309] Add DELTA device (not finished) --- siriuspy/siriuspy/devices/idff.py | 36 +++++++---- siriuspy/siriuspy/devices/ids.py | 99 +++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 467c28416..79f033097 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -7,6 +7,7 @@ from .device import Device as _Device, DeviceSet as _DeviceSet from .pwrsupply import PowerSupplyFBP as _PowerSupplyFBP from .ids import WIG as _WIG, APU as _APU, PAPU as _PAPU, EPU as _EPU +from .ids import DELTA as _DELTA class IDFF(_DeviceSet): @@ -33,10 +34,10 @@ def __init__(self, devname): self._kparametername = \ _IDSearch.conv_idname_2_kparameter_propty(devname) - self._devpp, self._devkp, self._devsch, self._devscv, self._devsqs = \ + self._devid, self._devsch, self._devscv, self._devsqs = \ self._create_devices(devname) - devices = [self._devpp, self._devkp] + devices = [self._devid, ] devices += self._devsch devices += self._devscv devices += self._devsqs @@ -90,12 +91,12 @@ def polarizations(self): @property def pparameter_mon(self): """Return pparameter value.""" - return self._devpp[self._pparametername] + return self._devid[self._pparametername] @property def kparameter_mon(self): """Return kparameter value.""" - return self._devkp[self._kparametername] + return self._devid[self._kparametername] @property def idffconfig(self): @@ -235,18 +236,14 @@ def get_polarization_state( def _create_devices(self, devname): param_auto_mon = False - devpp = _Device( + devid = _Device( devname=devname, - props2init=(self._pparametername, ), - auto_monitor_mon=param_auto_mon) - devkp = _Device( - devname=devname, - props2init=(self._kparametername, ), + props2init=(self._pparametername, self._kparametername), auto_monitor_mon=param_auto_mon) devsch = [_PowerSupplyFBP(devname=dev) for dev in self.chnames] devscv = [_PowerSupplyFBP(devname=dev) for dev in self.cvnames] devsqs = [_PowerSupplyFBP(devname=dev) for dev in self.qsnames] - return devpp, devkp, devsch, devscv, devsqs + return devid, devsch, devscv, devsqs class WIGIDFF(IDFF): @@ -290,6 +287,23 @@ def gap_mon(self): return self.kparameter_mon +class DELTAIDFF(IDFF): + """DELTA Feedforward.""" + + class DEVICES(_DELTA.DEVICES): + """.""" + + @property + def polarization_phase_mon(self): + """.""" + return self.pparameter_mon + + @property + def dGV_phase_mon(self): + """.""" + return self.kparameter_mon + + class APUIDFF(_DeviceSet): """APU Feedforward.""" diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index c53d79173..fc413c876 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -3,10 +3,81 @@ import time as _time from ..namesys import SiriusPVName as _SiriusPVName +from ..search import IDSearch as _IDSearch from .device import Device as _Device +class _ID(_Device): + """Generic Insertion Device.""" + + PROPERTIES_DEFAULT = ( + 'Moving-Mon', + 'BeamLineCtrlEnbl-Sel', 'BeamLineCtrlEnbl-Sts', + ) + + def __init__(self, devname, props2init='all', auto_monitor_mon=True): + """.""" + + # call base class constructor + super().__init__( + devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + + @property + def period_length(self): + """Return ID period length [mm].""" + params = _IDSearch.conv_idname_2_parameters(self.devname) + return params.PERIOD_LENGTH + + # --- movement checks --- + + @property + def is_moving(self): + """Return True if phase is changing.""" + return round(self['Moving-Mon']) == 1 + + # --- cmd_beamline and cmd_drive + + def cmd_beamline_ctrl_enable(self, timeout=None): + """Command enable bealine ID control.""" + return self._write_sp('BeamLineCtrlEnbl-Sel', 1, timeout) + + def cmd_beamline_ctrl_disable(self, timeout=None): + """Command disable bealine ID control.""" + return self._write_sp('BeamLineCtrlEnbl-Sel', 0, timeout) + + # --- cmd_wait + + def cmd_wait_move(self, timeout=None): + """Wait for phase movement to complete.""" + _time.sleep(APU._MOVECHECK_SLEEP) + t0_ = _time.time() + while self.is_moving: + _time.sleep(APU._MOVECHECK_SLEEP) + if timeout and _time.time() - t0_ > timeout: + return False + return True + + # --- private methods --- + + def _write_sp(self, propties_sp, values, sp_rb_pvs=None, timeout=None): + timeout = timeout or self._default_timeout + if isinstance(propties_sp, str): + propties_sp = (propties_sp, ) + values = (values, ) + success = True + for propty_sp, value in zip(propties_sp, values): + if sp_rb_pvs is not None and propty_sp in sp_rb_pvs: + propty_rb = propty_sp + else: + propty_rb = \ + propty_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') + self[propty_sp] = value + success &= super()._wait( + propty_rb, value, timeout=timeout, comp='eq') + return success + + class APU(_Device): """APU Insertion Device.""" @@ -834,6 +905,34 @@ def cmd_clear_error(self): pass +class DELTA(_ID): + """DELTA Insertion Device.""" + + class DEVICES: + """Device names.""" + + DELTA52_10SB = 'SI-10SB:ID-DELTA52' + ALL = (DELTA52_10SB, ) + + PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( + 'PolShift-Mon', 'GainShift-Mon', + 'Pol-Mon', + 'ChangePol-Cmd', + ) + + def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): + """.""" + # check if device exists + if devname is None: + devname = self.DEVICES.DELTA52_10SB + if devname not in self.DEVICES.ALL: + raise NotImplementedError(devname) + + # call base class constructor + super().__init__( + devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + + class WIG(_Device): """Wiggler Insertion Device.""" From 5561fa6d0dd91249b495b483a4a4e31a163f2227 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 8 Nov 2023 12:43:03 -0300 Subject: [PATCH 045/309] ORBINLKT.ENH: use timesys search to get LLRF PsMtn low level trigger PV name --- siriuspy/siriuspy/orbintlk/main.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f5320e7fc..51252d26f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -114,13 +114,11 @@ def __init__(self, tests=True): pvo.connection_callbacks.append(self._conn_callback_timing) # # RF EVE - llrftrig = _SiriusPVName(_HLTimeSearch.get_ll_trigger_names( - 'SI-Glob:TI-LLRF-PsMtn')[0]) - llrftrig_nam = _re.sub(r'[0-9]', '', llrftrig.propty) - llrftrig_idx = int(llrftrig.propty.split(llrftrig_nam)[1]) - self._llrf_evtcnt_pvname = f'{llrftrig_nam}{llrftrig_idx:02}EvtCnt-Mon' + trgsrc = _HLTimeSearch.get_ll_trigger_names('SI-Glob:TI-LLRF-PsMtn') + pvname = _LLTimeSearch.get_channel_output_port_pvname(trgsrc[0]) + self._llrf_evtcnt_pvname = f'{pvname}EvtCnt-Mon' self._everf_dev = _Device( - llrftrig.device_name, + pvname.device_name, props2init=[self._llrf_evtcnt_pvname, ], auto_monitor_mon=True) pvo = self._everf_dev.pv_object(self._llrf_evtcnt_pvname) From b75f002b1fe0850ece138a2c4336b44471948a4b Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 8 Nov 2023 13:34:35 -0300 Subject: [PATCH 046/309] Refactor ID devices --- siriuspy/siriuspy/devices/__init__.py | 2 +- siriuspy/siriuspy/devices/ids.py | 105 ++++++-------------------- 2 files changed, 26 insertions(+), 81 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index bc39f5e14..d5ef77cec 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -14,7 +14,7 @@ from .fofb_acq import FOFBCtrlSysId, FOFBPSSysId, FamFOFBSysId, \ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff -from .ids import APU, WIG, PAPU, EPU +from .ids import APU, WIG, PAPU, EPU, DELTA from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index fc413c876..ca0a5755a 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -11,6 +11,9 @@ class _ID(_Device): """Generic Insertion Device.""" + _MOVECHECK_SLEEP = 0.1 # [s] + _DEF_TIMEOUT = 8 # [s] + PROPERTIES_DEFAULT = ( 'Moving-Mon', 'BeamLineCtrlEnbl-Sel', 'BeamLineCtrlEnbl-Sts', @@ -60,14 +63,15 @@ def cmd_wait_move(self, timeout=None): # --- private methods --- - def _write_sp(self, propties_sp, values, sp_rb_pvs=None, timeout=None): - timeout = timeout or self._default_timeout + def _write_sp(self, propties_sp, values, timeout=None, pvs_sp_rb=None): + timeout = timeout or self._DEF_TIMEOUT if isinstance(propties_sp, str): propties_sp = (propties_sp, ) values = (values, ) success = True for propty_sp, value in zip(propties_sp, values): - if sp_rb_pvs is not None and propty_sp in sp_rb_pvs: + if pvs_sp_rb is not None and propty_sp in pvs_sp_rb: + # pv is unique for SP and RB variables. propty_rb = propty_sp else: propty_rb = \ @@ -78,7 +82,7 @@ def _write_sp(self, propties_sp, values, sp_rb_pvs=None, timeout=None): return success -class APU(_Device): +class APU(_ID): """APU Insertion Device.""" class DEVICES: @@ -96,22 +100,16 @@ class DEVICES: _SHORT_SHUT_EYE = 0.1 # [s] _CMD_MOVE_STOP, _CMD_MOVE_START = 1, 3 - _MOVECHECK_SLEEP = 0.1 # [s] - _default_timeout = 8 # [s] + _CMD_MOVE = 3 - PROPERTIES_DEFAULT = ( - 'BeamLineCtrlEnbl-Sel', 'BeamLineCtrlEnbl-Sts', - 'DevCtrl-Cmd', 'Moving-Mon', + PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( + 'DevCtrl-Cmd', 'MaxPhaseSpeed-SP', 'MaxPhaseSpeed-RB', 'PhaseSpeed-SP', 'PhaseSpeed-Mon', 'Phase-SP', 'Phase-Mon', 'Kx-SP', 'Kx-Mon', ) - _DEF_TIMEOUT = 10 # [s] - _CMD_MOVE = 3 - _MOVECHECK_SLEEP = 0.1 # [s] - def __init__(self, devname, props2init='all', auto_monitor_mon=True): """.""" # check if device exists @@ -122,12 +120,6 @@ def __init__(self, devname, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) - @property - def period_length(self): - """Return ID period length [mm].""" - _, length = self.devname.split('APU') - return float(length) - # --- phase speeds ---- @property @@ -193,23 +185,6 @@ def idkx(self, value): """Set APU Kx.""" self['Kx-SP'] = value - # --- movement checks --- - - @property - def is_moving(self): - """Return True if phase is changing.""" - return round(self['Moving-Mon']) == 1 - - # --- cmd_beamline and cmd_drive - - def cmd_beamline_ctrl_enable(self, timeout=None): - """Command enable bealine ID control.""" - return self._write_sp('BeamLineCtrlEnbl-Sel', 1, timeout) - - def cmd_beamline_ctrl_disable(self, timeout=None): - """Command disable bealine ID control.""" - return self._write_sp('BeamLineCtrlEnbl-Sel', 0, timeout) - # --- set methods --- def set_phase(self, phase, timeout=None): @@ -224,22 +199,14 @@ def set_phase_speed_max(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" return self._write_sp('MaxPhaseSpeed-SP', phase_speed_max, timeout) - # --- cmd_wait - - def wait_move(self): - """Wait for phase movement to complete.""" - _time.sleep(APU._MOVECHECK_SLEEP) - while self.is_moving: - _time.sleep(APU._MOVECHECK_SLEEP) - # -- cmd_move - def cmd_move_stop(self, timeout=_default_timeout): + def cmd_move_stop(self, timeout=None): """Send command to stop ID movement.""" self['DevCtrl-Cmd'] = APU._CMD_MOVE_STOP return True - def cmd_move_start(self, timeout=_default_timeout): + def cmd_move_start(self, timeout=None): """Send command to start ID movement.""" self['DevCtrl-Cmd'] = APU._CMD_MOVE_START return True @@ -284,24 +251,12 @@ def move(self, phase, timeout=None): # --- private methods --- def _write_sp(self, propties_sp, values, timeout=None): - timeout = timeout or self._default_timeout - if isinstance(propties_sp, str): - propties_sp = (propties_sp, ) - values = (values, ) - success = True - for propty_sp, value in zip(propties_sp, values): - if propty_sp in ('Phase-SP', 'PhaseSpeed-SP'): - propty_rb = propty_sp - else: - propty_rb = \ - propty_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') - self[propty_sp] = value - success &= super()._wait( - propty_rb, value, timeout=timeout, comp='eq') - return success + pvs_sp_rb = ('Phase-SP', 'PhaseSpeed-SP') + return super()._write_sp( + propties_sp, values, timeout=timeout, pvs_sp_rb=pvs_sp_rb) -class PAPU(_Device): +class PAPU(_ID): """PAPU Insertion Device.""" class DEVICES: @@ -315,14 +270,8 @@ class DEVICES: _SHORT_SHUT_EYE = 0.1 # [s] _default_timeout = 8 # [s] - _properties_papu = ( - 'Home-Cmd', 'EnblPwrPhase-Cmd', 'ClearErr-Cmd', - 'BeamLineCtrl-Mon', # 'Home-Mon', - ) _properties = ( 'PeriodLength-Cte', - 'BeamLineCtrlEnbl-Sel', 'BeamLineCtrlEnbl-Sts', - 'Moving-Mon', 'PwrPhase-Mon', 'EnblAndReleasePhase-Sel', 'EnblAndReleasePhase-Sts', 'AllowedToChangePhase-Mon', @@ -333,7 +282,13 @@ class DEVICES: 'StopPhase-Cmd', 'ChangePhase-Cmd', 'Log-Mon', ) - PROPERTIES_DEFAULT = _properties + _properties_papu + _properties_papu = ( + 'Home-Cmd', 'EnblPwrPhase-Cmd', 'ClearErr-Cmd', + 'BeamLineCtrl-Mon', + ) + + PROPERTIES_DEFAULT = \ + _ID.PROPERTIES_DEFAULT + _properties + _properties_papu def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): """.""" @@ -439,7 +394,7 @@ def is_beamline_ctrl_enabled(self): """Return beamline control enabled state (True|False).""" return self['BeamLineCtrlEnbl-Sts'] != 0 - # --- cmd_beamline and cmd_drive + # --- cmd_drive def cmd_drive_turn_power_on(self, timeout=None): """Command turn phase drive on.""" @@ -449,14 +404,6 @@ def cmd_drive_turn_power_on(self, timeout=None): props_values = {'PwrPhase-Mon': 1} return self._wait_propty_values(props_values, timeout=timeout) - def cmd_beamline_ctrl_enable(self, timeout=None): - """Command enable bealine ID control.""" - return self._write_sp('BeamLineCtrlEnbl-Sel', 1, timeout) - - def cmd_beamline_ctrl_disable(self, timeout=None): - """Command disable bealine ID control.""" - return self._write_sp('BeamLineCtrlEnbl-Sel', 0, timeout) - # --- set methods --- def set_phase(self, phase, timeout=None): @@ -622,8 +569,6 @@ def _write_sp(self, propties_sp, values, timeout=None): success = True for propty_sp, value in zip(propties_sp, values): propty_rb = propty_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') - # if self[propty_rb] == value: - # continue if not self.wait_while_busy(timeout=timeout): return False self[propty_sp] = value From 52120f0de70eafc7ba96c99b19ef04bd5b0436ee Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 8 Nov 2023 13:45:27 -0300 Subject: [PATCH 047/309] ORBINLKT.ENH: get Fout and EVG configs properly, thanks to @fernandohds564! --- siriuspy/siriuspy/orbintlk/csdev.py | 56 +++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index ef3789768..7db9f8edd 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -4,7 +4,8 @@ from .. import csdev as _csdev from ..util import ClassProperty as _classproperty -from ..search import BPMSearch as _BPMSearch, LLTimeSearch as _LLTimeSearch +from ..search import BPMSearch as _BPMSearch, LLTimeSearch as _LLTimeSearch, \ + HLTimeSearch as _HLTimeSearch from ..namesys import SiriusPVName as _PVName from ..diagbeam.bpm.csdev import Const as _csbpm @@ -78,39 +79,48 @@ def EVG_CONFIGS(cls): if cls.__EVG_CONFIGS is not None: return cls.__EVG_CONFIGS - # fouts fout2configs = dict() - for fout, trigsrc in _LLTimeSearch.get_fout2trigsrc_mapping().items(): - outs = { - int(k.strip('OUT')) for k, v in trigsrc.items() if - v.endswith('RaBPM:TI-AMCFPGAEVR') or # SI BPM paths - v.endswith('IA-14RaDiag03:TI-EVE')} # DCCTs path - if not outs: + foutchans = set() + evgchans = set() + evgrxenbl = 0 + for ch in _LLTimeSearch.get_connections_twds_evg(): + if ch.dev not in {'BPM', 'DCCTDig'}: continue - rxenbl = 0 - for i in outs: - rxenbl += (1 << i) - fout2configs[fout] = (('RxEnbl-SP', rxenbl), ) - cls.__FOUTS_CONFIGS = fout2configs + if ch.sec != 'SI': + continue + if ch.dev == 'BPM' and ch.sub.endswith(('SA', 'SB', 'SP')): + continue + fch = _LLTimeSearch.get_fout_channel(ch) + if fch in foutchans: + continue + foutchans.add(fch) + devname = fch.device_name + rxe = fout2configs.get(devname, 0) + rxe += 1 << int(fch.propty[3:]) + fout2configs[devname] = rxe + evgch = _LLTimeSearch.get_evg_channel(fch) + if evgch in evgchans: + continue + evgchans.add(evgch) + evgrxenbl += 1 << int(evgch.propty[3:]) - # evg - evgouts = set() - for out, fout in _LLTimeSearch.get_evg2fout_mapping().items(): - if fout in fout2configs: - evgouts.add(int(out.strip('OUT'))) - evgrxenbl = 0 - for i in evgouts: - evgrxenbl += (1 << i) + fout2configs = { + k: (('RxEnbl-SP', v),) for k, v in fout2configs.items()} + hlevts = _HLTimeSearch.get_hl_events() + evtin = int(hlevts['Intlk'].strip('Evt')) + evtout = int(hlevts['PsMtn'].strip('Evt')) evgconfigs = ( ('IntlkTbl0to15-Sel', 0b010000010000001), ('IntlkTbl16to27-Sel', 0), ('IntlkCtrlRepeat-Sel', 0), ('IntlkCtrlRepeatTime-SP', 0), - ('IntlkEvtIn0-SP', 117), - ('IntlkEvtOut-SP', 124), + ('IntlkEvtIn0-SP', evtin), + ('IntlkEvtOut-SP', evtout), ('RxEnbl-SP', evgrxenbl), ) + + cls.__FOUTS_CONFIGS = fout2configs cls.__EVG_CONFIGS = evgconfigs return cls.__EVG_CONFIGS From 84b9ed8dc896745b2e671abbdf1108fba835441b Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 9 Nov 2023 15:01:05 -0300 Subject: [PATCH 048/309] Add methods to DELTA device --- siriuspy/siriuspy/devices/ids.py | 108 ++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index ca0a5755a..0c1863618 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -26,12 +26,26 @@ def __init__(self, devname, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + @property + def parameters(self): + """Return ID parameters.""" + return _IDSearch.conv_idname_2_parameters(self.devname) + @property def period_length(self): """Return ID period length [mm].""" - params = _IDSearch.conv_idname_2_parameters(self.devname) - return params.PERIOD_LENGTH + return self.parameters.PERIOD_LENGTH + @property + def pparameter_parked(self): + """Return ID parked pparameter value [mm].""" + return self.parameters.PPARAM_PARKED + + @property + def kparameter_parked(self): + """Return ID parked kparameter value [mm].""" + return self.parameters.KPARAM_PARKED + # --- movement checks --- @property @@ -860,9 +874,15 @@ class DEVICES: ALL = (DELTA52_10SB, ) PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( - 'PolShift-Mon', 'GainShift-Mon', + 'PolShift-Mon', 'Pol-Mon', 'ChangePol-Cmd', + 'GainShift-SP', 'GainShift-RB', 'GainShift-Mon', + 'MaxVelo-SP', 'MaxVelo-RB', + 'PolModeVelo-SP', 'PolModeVelo-RB', + 'PolModeAcc-SP', 'PolModeAcc-RB', + 'GainModeVelo-SP', 'GainModeVelo-RB', + 'GainModeAcc-SP', 'GainModeAcc-RB', ) def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): @@ -877,6 +897,88 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + # --- pparameter --- + + @property + def pparameter_speed_max(self): + """Return max pparameter speed readback [mm/s].""" + return self['MaxVelo-RB'] + + @property + def pparameter_speed_max_lims(self): + """Return max pparameter speed limits.""" + ctrl = self.pv_ctrlvars('MaxVelo-SP') + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def pparameter_speed(self): + """Return pparameter speed readback [mm/s].""" + return self['PolModeVelo-RB'] + + @property + def pparameter_min(self): + """Return ID pparameter lower control limit [mm].""" + ctrlvars = self.pv_ctrlvars('PolShift-Mon') + return ctrlvars['lower_ctrl_limit'] + + @property + def pparameter_max(self): + """Return ID pparameter upper control limit [mm].""" + ctrlvars = self.pv_ctrlvars('PolShift-Mon') + return ctrlvars['upper_ctrl_limit'] + + @property + def pparameter_mon(self): + """Return ID pparameter monitor [mm].""" + return self['PolShift-Mon'] + + # --- kparameter --- + + @property + def kparameter_speed_max(self): + """Return max kparameter speed readback [mm/s].""" + return self['MaxVelo-RB'] + + @property + def kparameter_speed_max_lims(self): + """Return max kparameter speed limits.""" + ctrl = self.pv_ctrlvars('MaxVelo-SP') + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def kparameter_speed(self): + """Return kparameter speed readback [mm/s].""" + return self['GainModeVelo-RB'] + + @property + def kparameter(self): + """Return ID kparameter readback [mm].""" + return self['Shift-RB'] + + @kparameter.setter + def kparameter(self, value): + """Set ID kparameter [mm].""" + self['Shift-SP'] = value + + @property + def kparameter_min(self): + """Return ID kparameter lower control limit [mm].""" + ctrlvars = self.pv_ctrlvars('Shift-SP') + return ctrlvars['lower_ctrl_limit'] + + @property + def kparameter_max(self): + """Return ID kparameter upper control limit [mm].""" + ctrlvars = self.pv_ctrlvars('Shift-SP') + return ctrlvars['upper_ctrl_limit'] + + @property + def kparameter_mon(self): + """Return ID kparameter monitor [mm].""" + return self['GainShift-Mon'] + class WIG(_Device): """Wiggler Insertion Device.""" From 2b6a8dd8dac7b54790f662a3783aa680bdc4d474 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 9 Nov 2023 15:04:02 -0300 Subject: [PATCH 049/309] Fix init in devices --- siriuspy/siriuspy/devices/__init__.py | 4 ++-- siriuspy/siriuspy/devices/idff.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index bc39f5e14..0b7127629 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -14,8 +14,8 @@ from .fofb_acq import FOFBCtrlSysId, FOFBPSSysId, FamFOFBSysId, \ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff -from .ids import APU, WIG, PAPU, EPU -from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF +from .ids import APU, WIG, PAPU, EPU, DELTA +from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF, DELTAIDFF from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ BORFRampStandbyHandler, InjSysStandbyHandler, LinacStandbyHandler, \ diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 467c28416..5608614fa 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -12,9 +12,11 @@ class IDFF(_DeviceSet): """Insertion Device Feedforward Device.""" - class DEVICES(_WIG.DEVICES, _PAPU.DEVICES, _EPU.DEVICES): + class DEVICES(_WIG.DEVICES, _PAPU.DEVICES, _EPU.DEVICES, _DELTA.DEVICES): """.""" - ALL = _WIG.DEVICES.ALL + _PAPU.DEVICES.ALL + _EPU.DEVICES.ALL + ALL = \ + _WIG.DEVICES.ALL + _PAPU.DEVICES.ALL + \ + _EPU.DEVICES.ALL + _DELTA.DEVICES.ALL def __init__(self, devname): """.""" From 72039efd6b849415ce00e89ee9bae047756c17b0 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 9 Nov 2023 15:08:35 -0300 Subject: [PATCH 050/309] Fix init in devices --- siriuspy/siriuspy/devices/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index 5754f54d3..0b7127629 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -15,11 +15,7 @@ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff from .ids import APU, WIG, PAPU, EPU, DELTA -<<<<<<< HEAD from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF, DELTAIDFF -======= -from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF ->>>>>>> add-device-delta from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ BORFRampStandbyHandler, InjSysStandbyHandler, LinacStandbyHandler, \ From 9365d4ab367cc878143b3f306a7c3cc1ab91dd72 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 16:24:57 -0300 Subject: [PATCH 051/309] ORBINTLK.MNT: remove unused imports --- siriuspy/siriuspy/orbintlk/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 51252d26f..9a81890b0 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1,6 +1,5 @@ """High Level Orbit Interlock main application.""" -import re as _re import os as _os import logging as _log import time as _time From 2735217797dff2a6b0b4579702239ffb0b5da0be Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 16:25:28 -0300 Subject: [PATCH 052/309] ORBINTLK.MNT: change enable list default value to false --- siriuspy/siriuspy/orbintlk/csdev.py | 12 ++++++------ siriuspy/siriuspy/orbintlk/main.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 7db9f8edd..76ee9d16c 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -198,29 +198,29 @@ def get_database(self): # Enable lists 'PosEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used in orbit position interlock'}, 'PosEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used in orbit position interlock'}, 'AngEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used in orbit angle interlock'}, 'AngEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used in orbit angle interlock'}, 'MinSumEnblList-SP': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used with minimum sum threshold enabled'}, 'MinSumEnblList-RB': { 'type': 'int', 'count': self.nr_bpms, - 'value': self.nr_bpms*[1], + 'value': self.nr_bpms*[0], 'unit': 'BPM used with minimum sum threshold enabled'}, # Limits diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 9a81890b0..82daac405 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -40,9 +40,9 @@ def __init__(self, tests=True): self._bpm_status = self._pvs_database['BPMStatus-Mon']['value'] self._timing_status = self._pvs_database['TimingStatus-Mon']['value'] self._enable_lists = { - 'pos': _np.ones(self._const.nr_bpms, dtype=bool), - 'ang': _np.ones(self._const.nr_bpms, dtype=bool), - 'minsum': _np.ones(self._const.nr_bpms, dtype=bool), + 'pos': _np.zeros(self._const.nr_bpms, dtype=bool), + 'ang': _np.zeros(self._const.nr_bpms, dtype=bool), + 'minsum': _np.zeros(self._const.nr_bpms, dtype=bool), } self._limits = { 'pos_x_min': _np.zeros(self._const.nr_bpms, dtype=int), From d82ba34f0d9ab4ffc21efa83d88be56edafb2a60 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 17:49:34 -0300 Subject: [PATCH 053/309] ORBINTLK.ENH: change to control only necessary RxEnbl bits, --- siriuspy/siriuspy/orbintlk/csdev.py | 17 +++++++++-------- siriuspy/siriuspy/orbintlk/main.py | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 76ee9d16c..149f616f1 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -82,7 +82,7 @@ def EVG_CONFIGS(cls): fout2configs = dict() foutchans = set() evgchans = set() - evgrxenbl = 0 + evgrxenbl = list() for ch in _LLTimeSearch.get_connections_twds_evg(): if ch.dev not in {'BPM', 'DCCTDig'}: continue @@ -95,30 +95,31 @@ def EVG_CONFIGS(cls): continue foutchans.add(fch) devname = fch.device_name - rxe = fout2configs.get(devname, 0) - rxe += 1 << int(fch.propty[3:]) + rxe = fout2configs.get(devname, list()) + rxe.append(int(fch.propty[3:])) fout2configs[devname] = rxe evgch = _LLTimeSearch.get_evg_channel(fch) if evgch in evgchans: continue evgchans.add(evgch) - evgrxenbl += 1 << int(evgch.propty[3:]) + evgrxenbl.append(int(evgch.propty[3:])) fout2configs = { - k: (('RxEnbl-SP', v),) for k, v in fout2configs.items()} + k: [(f'RxEnbl-SP.B{b}', 1) for b in v] + for k, v in fout2configs.items()} hlevts = _HLTimeSearch.get_hl_events() evtin = int(hlevts['Intlk'].strip('Evt')) evtout = int(hlevts['PsMtn'].strip('Evt')) - evgconfigs = ( + evgconfigs = [ ('IntlkTbl0to15-Sel', 0b010000010000001), ('IntlkTbl16to27-Sel', 0), ('IntlkCtrlRepeat-Sel', 0), ('IntlkCtrlRepeatTime-SP', 0), ('IntlkEvtIn0-SP', evtin), ('IntlkEvtOut-SP', evtout), - ('RxEnbl-SP', evgrxenbl), - ) + ] + evgconfigs.extend([(f'RxEnbl-SP.B{b}', 1) for b in evgrxenbl]) cls.__FOUTS_CONFIGS = fout2configs cls.__EVG_CONFIGS = evgconfigs diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 82daac405..2e31fc6c5 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -76,7 +76,14 @@ def __init__(self, tests=True): 'IntlkEvtIn0-SP', 'IntlkEvtIn0-RB', 'IntlkEvtOut-SP', 'IntlkEvtOut-SP', 'IntlkEvtStatus-Mon', - 'RxEnbl-SP', 'RxEnbl-RB', + 'RxEnbl-SP.B0', 'RxEnbl-RB.B0', + 'RxEnbl-SP.B1', 'RxEnbl-RB.B1', + 'RxEnbl-SP.B2', 'RxEnbl-RB.B2', + 'RxEnbl-SP.B3', 'RxEnbl-RB.B3', + 'RxEnbl-SP.B4', 'RxEnbl-RB.B4', + 'RxEnbl-SP.B5', 'RxEnbl-RB.B5', + 'RxEnbl-SP.B6', 'RxEnbl-RB.B6', + 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', ]) pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True @@ -88,7 +95,14 @@ def __init__(self, tests=True): devname: _Device( devname, props2init=[ - 'RxEnbl-SP', 'RxEnbl-RB', + 'RxEnbl-SP.B0', 'RxEnbl-RB.B0', + 'RxEnbl-SP.B1', 'RxEnbl-RB.B1', + 'RxEnbl-SP.B2', 'RxEnbl-RB.B2', + 'RxEnbl-SP.B3', 'RxEnbl-RB.B3', + 'RxEnbl-SP.B4', 'RxEnbl-RB.B4', + 'RxEnbl-SP.B5', 'RxEnbl-RB.B5', + 'RxEnbl-SP.B6', 'RxEnbl-RB.B6', + 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) for devname in self._const.FOUTS_CONFIGS From b9754f1e71d3ad784076ab2f3504ee048add4727 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 17:50:41 -0300 Subject: [PATCH 054/309] ORBINTLK.FIX: fix bug in Fout RxLocked callbacks arguments --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 2e31fc6c5..fa780bfc4 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -815,7 +815,8 @@ def _callback_fout_rxlock(self, pvname, value, **kws): if self._thread_cbfout and self._thread_cbfout.is_alive(): return self._thread_cbfout = _CAThread( - target=self._do_callback_fout_rxlock, args=(value, ), daemon=True) + target=self._do_callback_fout_rxlock, + args=(pvname, value, ), daemon=True) self._thread_cbfout.start() def _do_callback_fout_rxlock(self, pvname, value): From e521a92dfe771a99b6327fe6988dd1f2a90990b2 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 17:51:14 -0300 Subject: [PATCH 055/309] ORBINTLK.FIX: use RxEnbl desired values to check RxLocked desired values --- siriuspy/siriuspy/orbintlk/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index fa780bfc4..ed1db250f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -810,7 +810,10 @@ def _callback_fout_rxlock(self, pvname, value, **kws): return if not self._init: return - if value == 0b11111111: # it is ok + pvname = _SiriusPVName(pvname) + configs = self._const.FOUTS_CONFIGS[pvname.device_name] + bits = [int(c[0][-1]) for c in configs if 'RxEnbl' in c[0]] + if all([_get_bit(value, b) for b in bits]): # all ok return if self._thread_cbfout and self._thread_cbfout.is_alive(): return From ed82512b98d45282230fe5c6b811f6f87aea69ba Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 18:00:18 -0300 Subject: [PATCH 056/309] ORBINTLK.ENH: monitor also EVG RxLocked PV --- siriuspy/siriuspy/orbintlk/main.py | 33 ++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ed1db250f..202a05df0 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -59,7 +59,8 @@ def __init__(self, tests=True): self._acq_spre = self._pvs_database['PsMtmAcqSamplesPre-SP']['value'] self._acq_spost = self._pvs_database['PsMtmAcqSamplesPost-SP']['value'] self._thread_acq = None - self._thread_cbevg = None + self._thread_cbevgilk = None + self._thread_cbevgrx = None self._thread_cbfout = None self._thread_cbbpm = None self._ti_mon_devs = set() @@ -84,11 +85,14 @@ def __init__(self, tests=True): 'RxEnbl-SP.B5', 'RxEnbl-RB.B5', 'RxEnbl-SP.B6', 'RxEnbl-RB.B6', 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', + 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ]) pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True pvo.add_callback(self._callback_evg_intlk) pvo.connection_callbacks.append(self._conn_callback_timing) + pvo = self._evg_dev.pv_object('RxLockedLtc-Mon') + pvo.add_callback(self._callback_evg_rxlock) # # Fouts self._fout_devs = { @@ -784,11 +788,11 @@ def _callback_evg_intlk(self, value, **kws): return if not self._init: return - if self._thread_cbevg and self._thread_cbevg.is_alive(): + if self._thread_cbevgilk and self._thread_cbevgilk.is_alive(): return - self._thread_cbevg = _CAThread( + self._thread_cbevgilk = _CAThread( target=self._do_callback_evg_intlk, args=(value, ), daemon=True) - self._thread_cbevg.start() + self._thread_cbevgilk.start() def _do_callback_evg_intlk(self, value): if value == 0: @@ -818,11 +822,28 @@ def _callback_fout_rxlock(self, pvname, value, **kws): if self._thread_cbfout and self._thread_cbfout.is_alive(): return self._thread_cbfout = _CAThread( - target=self._do_callback_fout_rxlock, + target=self._do_callback_rxlock, args=(pvname, value, ), daemon=True) self._thread_cbfout.start() - def _do_callback_fout_rxlock(self, pvname, value): + def _callback_evg_rxlock(self, pvname, value, **kws): + if not self._state: + return + if not self._init: + return + pvname = _SiriusPVName(pvname) + configs = self._const.EVG_CONFIGS + bits = [int(c[0][-1]) for c in configs if 'RxEnbl' in c[0]] + if all([_get_bit(value, b) for b in bits]): # all ok + return + if self._thread_cbevgrx and self._thread_cbevgrx.is_alive(): + return + self._thread_cbevgrx = _CAThread( + target=self._do_callback_rxlock, + args=(pvname, value, ), daemon=True) + self._thread_cbevgrx.start() + + def _do_callback_rxlock(self, pvname, value): pvname = _SiriusPVName(pvname) devname = pvname.device_name shouldkill = False From fb8fce5db5907e9b9e963ba5631f69039ccdec44 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 18:03:05 -0300 Subject: [PATCH 057/309] ORBINTLK.ENH: do not allow user to update enable list if this implies in a orbit interlock reliability failure --- siriuspy/siriuspy/orbintlk/main.py | 71 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 202a05df0..dc7b93c77 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -337,6 +337,14 @@ def set_enable(self, value): return False if value: + mondevs = self._get_ti_monitored_devices() + if not self._check_devices_status(mondevs): + self._update_log('ERR:Could not enable orbit interlock.') + return False + self._ti_mon_devs = mondevs + self.run_callbacks( + 'TimingMonitoredDevices-Mon', '\n'.join(mondevs)) + glob_en = self._get_gen_bpm_intlk() else: glob_en = _np.zeros(self._const.nr_bpms, dtype=bool) @@ -356,8 +364,6 @@ def set_enable(self, value): self._state = value self.run_callbacks('Enable-Sts', self._state) - self._update_ti_monitored_devices() - return True # --- enable lists --- @@ -379,7 +385,16 @@ def set_enbllist(self, intlk, value): self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') return False + # check if new enable list do not imply in orbit interlock failure + bkup = self._enable_lists[intlk] self._enable_lists[intlk] = new + mondevs = self._get_ti_monitored_devices() + if not self._check_devices_status(mondevs): + self._update_log('ERR:Could not set enable list.') + self._enable_lists[intlk] = bkup + return False + self._ti_mon_devs = mondevs + self.run_callbacks('TimingMonitoredDevices-Mon', '\n'.join(mondevs)) # do not set enable lists and save to file in initialization if not self._init: @@ -416,8 +431,6 @@ def set_enbllist(self, intlk, value): self._update_log('...done.') - self._update_ti_monitored_devices() - # update readback pv self.run_callbacks(f'{intlkname}EnblList-RB', new) return True @@ -634,6 +647,40 @@ def _get_enabled_sections(self): subs += 1 return subs + def _get_ti_monitored_devices(self): + value = set() + if self._state: + value.add(self._everf_dev.devname) + for sec in self._get_enabled_sections(): + afcti = f'IA-{sec:02}RaBPM:TI-AMCFPGAEVR' + value.add(afcti) + foutout = _LLTimeSearch.get_trigsrc2fout_mapping()[afcti] + value.add(foutout) + evgout = _LLTimeSearch.get_evg_channel(foutout) + value.add(evgout) + return value + + def _check_devices_status(self, devices): + for devname in devices: + devname = _SiriusPVName(devname) + out = int(devname.propty[-1]) if devname.propty else None + + dev = self._evg_dev if 'EVG' in devname else \ + self._fout_devs[devname.device_name] if 'Fout' in devname \ + else self._afcti_devs[int(devname.sub[:2])] + + if not dev.connected: + self._update_log(f'ERR:{dev.devname} not connected') + return False + if out and not _get_bit(dev['RxLockedLtc-Mon'], out): + self._update_log(f'ERR:{dev.devname} OUT{out} not locked') + return False + if 'RTMClkLockedLtc-Mon' in dev.properties_in_use and \ + not dev['RTMClkLockedLtc-Mon']: + self._update_log(f'ERR:{dev.devname} RTM Clk not locked') + return False + return True + def _get_gen_bpm_intlk(self): pos, ang = self._enable_lists['pos'], self._enable_lists['ang'] return _np.logical_or(pos, ang) @@ -924,22 +971,6 @@ def _do_killbeam(self): self._update_log('FATAL:Sending kill beam.') self._killbeam.cmd_kill_beam() - def _update_ti_monitored_devices(self): - value = set() - if self._state: - value.add(self._evg_dev.devname) - value.add(self._everf_dev.devname) - for sec in self._get_enabled_sections(): - afcti = f'IA-{sec:02}RaBPM:TI-AMCFPGAEVR' - value.add(afcti) - foutout = _LLTimeSearch.get_trigsrc2fout_mapping()[afcti] - value.add(foutout) - foutdev = _SiriusPVName(foutout).device_name - value.add(foutdev) - - self._ti_mon_devs = value - self.run_callbacks('TimingMonitoredDevices-Mon', '\n'.join(value)) - # --- auxiliary log methods --- def _update_log(self, msg): From 05ed04e3fcd853a00872864dde6c74c9b4b67f03 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 18:05:24 -0300 Subject: [PATCH 058/309] ORBINTLK.ENH: if RxLocked raised a lock loss in a device that is not in use, try to just reset latch --- siriuspy/siriuspy/orbintlk/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index dc7b93c77..a01f9ec58 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -905,7 +905,11 @@ def _do_callback_rxlock(self, pvname, value): if shouldkill: self._update_log('FATAL:Orbit interlock reliability failure') self._do_killbeam() - self._fout_devs[devname]['RxLockedLtcRst-Cmd'] = 1 + else: + # reset rxlock latch + dev = self._evg_dev if 'EVG' in devname \ + else self._fout_devs[devname] + dev['RxLockedLtcRst-Cmd'] = 1 def _callback_afcti_rtmlock(self, pvname, value, **kws): if value == 1: # it is ok From 4fb6178d091ec4fe8049029e60ae3218e0462c2d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 18:29:08 -0300 Subject: [PATCH 059/309] ORBINTLK.ENH: use LLRF soft interlock PV to kill beam --- siriuspy/siriuspy/orbintlk/main.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index a01f9ec58..01edbeb39 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -15,8 +15,7 @@ from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ - EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device, \ - RFKillBeam as _RFKillBeam + EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device from .csdev import Const as _Const, ETypes as _ETypes @@ -194,9 +193,9 @@ def __init__(self, tests=True): self._llrf = _ASLLRF( devname=_ASLLRF.DEVICES.SI, props2init=[ - 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP']) - - self._killbeam = _RFKillBeam() + 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', + 'IntlkSet-Cmd', + ]) # pvs to write methods self.map_pv2write = { @@ -972,8 +971,10 @@ def _do_callback_bpm_intlk(self, bpmname): def _do_killbeam(self): # if not in dry run, send kill beam if not self._is_dry_run: - self._update_log('FATAL:Sending kill beam.') - self._killbeam.cmd_kill_beam() + self._update_log('FATAL:sending soft interlock to LLRF.') + self._llrf['IntlkSet-Cmd'] = 1 + _time.sleep(1) + self._llrf['IntlkSet-Cmd'] = 0 # --- auxiliary log methods --- From 4417343b42c919ee947a7071fb5c56984131a2de Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 18:48:23 -0300 Subject: [PATCH 060/309] ORBINTLK.ENH: add PVs to act on problematic timing devices, remove callback that automatically resets AFC timing lock latchs, --- siriuspy/siriuspy/orbintlk/csdev.py | 2 + siriuspy/siriuspy/orbintlk/main.py | 79 ++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 149f616f1..0187f5f0f 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -306,6 +306,8 @@ def get_database(self): 'ResetBPMAng-Cmd': {'type': 'int', 'value': 0}, 'ResetBPM-Cmd': {'type': 'int', 'value': 0}, 'Reset-Cmd': {'type': 'int', 'value': 0}, + 'ResetTimingLockLatches-Cmd': {'type': 'int', 'value': 0}, + 'ResetAFCTimingRTMClk-Cmd': {'type': 'int', 'value': 0}, # Acquisition 'PsMtmAcqChannel-Sel': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 01edbeb39..6bfefbd01 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -15,7 +15,8 @@ from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ - EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device + EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device, \ + SOFB as _SOFB, HLFOFB as _FOFB from .csdev import Const as _Const, ETypes as _ETypes @@ -121,12 +122,12 @@ def __init__(self, tests=True): f'IA-{idx+1:02}RaBPM:TI-AMCFPGAEVR', props2init=[ 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', + 'RTMClkRst-Cmd', ], auto_monitor_mon=True) for idx in range(20) } for dev in self._afcti_devs.values(): pvo = dev.pv_object('RTMClkLockedLtc-Mon') - pvo.add_callback(self._callback_afcti_rtmlock) pvo.connection_callbacks.append(self._conn_callback_timing) # # RF EVE @@ -197,6 +198,12 @@ def __init__(self, tests=True): 'IntlkSet-Cmd', ]) + # # auxiliary devices + self._fofb = _FOFB( + props2init=['LoopState-Sts', ]) + self._sofb = _SOFB( + _SOFB.DEVICES.SI, props2init=['LoopState-Sts', ]) + # pvs to write methods self.map_pv2write = { 'Enable-Sel': self.set_enable, @@ -221,7 +228,10 @@ def __init__(self, tests=True): 'PsMtmAcqSamplesPre-SP': self.set_acq_nrspls_pre, 'PsMtmAcqSamplesPost-SP': self.set_acq_nrspls_post, 'PsMtmAcqConfig-Cmd': self.cmd_acq_config, - 'IntlkStateConfig-Cmd': self.cmd_state_config} + 'IntlkStateConfig-Cmd': self.cmd_state_config, + 'ResetTimingLockLatches-Cmd': self.cmd_reset_ti_lock_latch, + 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, + } # configuration scanning self.thread_check_configs = _Repeat( @@ -512,6 +522,59 @@ def cmd_reset(self, state, value=None): return True + def cmd_reset_ti_lock_latch(self, value=None): + """Command to reset AFC timing and Fout clock lock latches.""" + _ = value + # try to reset AFC timing clock lock latches, act only in necessary + # devices, return false if fail + for idx, afcti in self._afcti_devs.items(): + if afcti['RTMClkLockedLtc-Mon']: + continue + afcti['ClkLockedLtcRst-Cmd'] = 1 + msg = 'Reset' if afcti._wait('RTMClkLockedLtc-Mon', 1, timeout=3) \ + else 'Could not reset' + self._update_log(f'{msg} AFC Timing {idx} lock latchs.') + if 'not' in msg: + return False + # try to reset Fout rx lock latches, act only in necessary + # devices, return false if fail + for devname, fout in self._fout_devs.items(): + if fout['RxLockedLtc-Mon']: + continue + fout['RxLockedLtcRst-Cmd'] = 1 + msg = 'Reset' if fout._wait('RxLockedLtc-Mon', 1, timeout=3) \ + else 'Could not reset' + self._update_log(f'{msg} {devname} lock latchs.') + if 'not' in msg: + return False + return True + + def cmd_reset_afcti_rtmclk(self, value=None): + """Command to reset AFC timing clocks.""" + _ = value + # do not allow user to reset in case of correction loops closed + if not self._fofb.connected or self._fofb['LoopState-Sts'] or \ + not self._sofb.connected or self._sofb['LoopState-Sts']: + self._update_log('ERR:Open correction loops before ') + self._update_log('ERR:reseting AFC Timing clocks.') + return False + + # try to reset AFC timing clock, act only in necessary + # devices, return false if fail + for idx, afcti in self._afcti_devs.items(): + if afcti['RTMClkLockedLtc-Mon']: + continue + afcti['ClkLockedLtcRst-Cmd'] = 1 + if afcti._wait('RTMClkLockedLtc-Mon', 1, timeout=3): + continue + afcti['RTMClkRst-Cmd'] = 1 + self._update_log(f'Sent reset clock to AFC Timing {idx}.') + + # try to reset latches + self.cmd_reset_ti_lock_latch() + + return True + # --- configure acquisition --- def set_acq_channel(self, value): @@ -910,16 +973,6 @@ def _do_callback_rxlock(self, pvname, value): else self._fout_devs[devname] dev['RxLockedLtcRst-Cmd'] = 1 - def _callback_afcti_rtmlock(self, pvname, value, **kws): - if value == 1: # it is ok - return - devidx = int(_SiriusPVName(pvname).sub.split('Ra')[0]) - dev = self._afcti_devs[devidx] - self._update_log(f'WARN:AFC Timing {devidx} raised RTM clock loss,') - _time.sleep(1) # sleep a little before reseting - self._update_log(f'WARN:reseting AFC Timing {devidx} lock latchs.') - dev['ClkLockedLtcRst-Cmd'] = 1 - def _conn_callback_timing(self, pvname, conn, **kws): if conn: return From 5c02bf13fa2defc3f2edbebbe7855bb4be6e1727 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 19:09:19 -0300 Subject: [PATCH 061/309] ORBINTLK.ENH: add controls for new DCCT triggers --- siriuspy/siriuspy/orbintlk/csdev.py | 13 +++++++++- siriuspy/siriuspy/orbintlk/main.py | 39 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 0187f5f0f..583180556 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -29,6 +29,9 @@ class ETypes(_csdev.ETypes): 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFPsMtnTrigConn', 'LLRFPsMtnTrigStatusOK', 'LLRFPsMtnTrigConfig', 'BPMPsMtnTrigConn', 'BPMPsMtnTrigStatusOK', 'BPMPsMtnTrigConfig', + 'DCCT13C4PsMtnTrigConn', 'DCCT13C4PsMtnTrigStatusOK', + 'DCCT13C4PsMtnTrigConfig', 'DCCT14C4PsMtnTrigConn', + 'DCCT14C4PsMtnTrigStatusOK', 'DCCT14C4PsMtnTrigConfig', ) STS_LBLS_LLRF = ('Connected', 'Configured') @@ -69,6 +72,14 @@ class Const(_csdev.Const): ('State-Sel', 1), ('WidthRaw-SP', 6), ) + DCCT13C4TRIG_CONFIG = ( + ('Src-Sel', 0), + ('State-Sel', 1), + ) + DCCT14C4TRIG_CONFIG = ( + ('Src-Sel', 0), + ('State-Sel', 1), + ) __EVG_CONFIGS = None __FOUTS_CONFIGS = None @@ -182,7 +193,7 @@ def get_database(self): 'type': 'enum', 'enums': _et.DSBL_ENBL, 'value': self.DsblEnbl.Dsbl}, 'BPMStatus-Mon': {'type': 'int', 'value': 0b111111111}, - 'TimingStatus-Mon': {'type': 'int', 'value': 0b111111111}, + 'TimingStatus-Mon': {'type': 'int', 'value': (1 << 19) - 1}, 'LLRFStatus-Mon': {'type': 'int', 'value': 0b11}, 'BPMStatusLabels-Cte': { 'type': 'string', 'count': len(_et.STS_LBLS_BPM), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6bfefbd01..829fd5bfb 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -172,6 +172,19 @@ def __init__(self, tests=True): 'Status-Mon', ], auto_monitor_mon=True) + self._dcct13c4_trig = _Trigger( + trigname='SI-13C4:TI-DCCT-PsMtm', props2init=[ + 'Src-Sel', 'Src-Sts', + 'State-Sel', 'State-Sts', + 'Status-Mon', + ], auto_monitor_mon=True) + self._dcct14c4_trig = _Trigger( + trigname='SI-14C4:TI-DCCT-PsMtm', props2init=[ + 'Src-Sel', 'Src-Sts', + 'State-Sel', 'State-Sts', + 'Status-Mon', + ], auto_monitor_mon=True) + # # BPM devices self._orbintlk_dev = _OrbitIntlk() for dev in self._orbintlk_dev.devices: @@ -683,6 +696,8 @@ def _config_timing(self): self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, self._llrf_trig: self._const.LLRFTRIG_CONFIG, self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, + self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, + self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, } for trig, configs in trig2config.items(): for prp, val in configs: @@ -867,6 +882,30 @@ def _check_configs(self): value = _updt_bit(value, 13, not oko) else: value += 0b111 << 11 + # DCCT 13C4 trigger + dev = self._dcct13c4_trig + oko = False + if dev.connected: + value = _updt_bit(value, 15, bool(dev['Status-Mon'])) + oko = True + for prp, val in self._const.DCCT13C4TRIG_CONFIG: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + oko &= dev[prp_rb] == val + value = _updt_bit(value, 16, not oko) + else: + value += 0b111 << 14 + # DCCT 14C4 trigger + dev = self._dcct14c4_trig + oko = False + if dev.connected: + value = _updt_bit(value, 18, bool(dev['Status-Mon'])) + oko = True + for prp, val in self._const.DCCT14C4TRIG_CONFIG: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + oko &= dev[prp_rb] == val + value = _updt_bit(value, 19, not oko) + else: + value += 0b111 << 17 self._timing_status = value self.run_callbacks('TimingStatus-Mon', self._timing_status) From c5559f17d5ddd4094e355fc200a6be5d8786d8da Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 19:10:50 -0300 Subject: [PATCH 062/309] ORBINTLK.ENH: adapt to new HLTiming IOC version --- siriuspy/siriuspy/orbintlk/csdev.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 583180556..651d4a4e0 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -27,11 +27,11 @@ class ETypes(_csdev.ETypes): 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', 'FoutsConn', 'FoutsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', - 'LLRFPsMtnTrigConn', 'LLRFPsMtnTrigStatusOK', 'LLRFPsMtnTrigConfig', - 'BPMPsMtnTrigConn', 'BPMPsMtnTrigStatusOK', 'BPMPsMtnTrigConfig', - 'DCCT13C4PsMtnTrigConn', 'DCCT13C4PsMtnTrigStatusOK', - 'DCCT13C4PsMtnTrigConfig', 'DCCT14C4PsMtnTrigConn', - 'DCCT14C4PsMtnTrigStatusOK', 'DCCT14C4PsMtnTrigConfig', + 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', + 'BPMPsMtmTrigConn', 'BPMPsMtmTrigStatusOK', 'BPMPsMtmTrigConfig', + 'DCCT13C4PsMtmTrigConn', 'DCCT13C4PsMtmTrigStatusOK', + 'DCCT13C4PsMtmTrigConfig', 'DCCT14C4PsMtmTrigConn', + 'DCCT14C4PsMtmTrigStatusOK', 'DCCT14C4PsMtmTrigConfig', ) STS_LBLS_LLRF = ('Connected', 'Configured') @@ -121,7 +121,7 @@ def EVG_CONFIGS(cls): hlevts = _HLTimeSearch.get_hl_events() evtin = int(hlevts['Intlk'].strip('Evt')) - evtout = int(hlevts['PsMtn'].strip('Evt')) + evtout = int(hlevts['RFKll'].strip('Evt')) evgconfigs = [ ('IntlkTbl0to15-Sel', 0b010000010000001), ('IntlkTbl16to27-Sel', 0), From 488fc67257685e0e06731fb3e9f7790146c9385a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 9 Nov 2023 19:43:19 -0300 Subject: [PATCH 063/309] ORBINTLK.FIX: fix TimingMonitoredDevices-Mon initialization --- siriuspy/siriuspy/orbintlk/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 829fd5bfb..dae12990b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -287,6 +287,9 @@ def init_database(self): self.run_callbacks(pvn+'-SP', enb) if not okl: self.run_callbacks(pvn+'-RB', enb) + self._ti_mon_devs = self._get_ti_monitored_devices() + self.run_callbacks( + 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) # limits for ilk in ['Pos', 'Ang']: From 45a69ddd6d0e41354e530f220499df41a1008a36 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 10:14:02 -0300 Subject: [PATCH 064/309] search.FIX: fix DELTA52 polarization table --- siriuspy/siriuspy/search/id_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index 032dc193d..693e1384c 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -71,10 +71,10 @@ class IDSearch: 3: ('vertical', 25.00), # [mm] }, 'SI-10SB:ID-DELTA52': { - 0: ('vertical', -52.5/2), # [mm] 0: ('circularn', -52.5/4), # [mm] 1: ('horizontal', 0.00), # [mm] 2: ('circularp', +52.5/4), # [mm] + 3: ('vertical', -52.5/2), # [mm] }, } _idname2pol_sts = _copy.deepcopy(_idname2pol_sel) From f36bbb7f4579e7c7cf1075d6b281ac1cd592487d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 10:32:37 -0300 Subject: [PATCH 065/309] idff.FIX: add default value of DELTA52 config --- siriuspy/siriuspy/idff/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/idff/main.py b/siriuspy/siriuspy/idff/main.py index d1bfd9c48..23d37a154 100644 --- a/siriuspy/siriuspy/idff/main.py +++ b/siriuspy/siriuspy/idff/main.py @@ -275,6 +275,8 @@ def _get_default_configname(self): return 'epu50_ref' elif self._const.idname.dev == 'PAPU50': return 'papu50_ref' + elif self._const.idname.dev == 'DELTA52': + return 'delta52_ref' return '' # ----- update pvs methods ----- From 2b848911e125c16432b1c4508ce78e6e992fb506 Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 10 Nov 2023 16:16:28 -0300 Subject: [PATCH 066/309] Implement DELTA device (in progress) --- siriuspy/siriuspy/devices/ids.py | 50 +++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 0c1863618..86f58e452 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -874,15 +874,16 @@ class DEVICES: ALL = (DELTA52_10SB, ) PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( - 'PolShift-Mon', - 'Pol-Mon', - 'ChangePol-Cmd', - 'GainShift-SP', 'GainShift-RB', 'GainShift-Mon', + 'PParam-Mon', + 'Pol-SP', 'Pol-RB', 'Pol-Mon', 'ChangePol-Cmd', + 'KParam-SP', 'KParam-RB', 'KParam-Mon', + 'KValue-SP', 'KValue-RB', 'KValue-Mon', + 'Energy-SP', 'Energy-RB', 'Energy-Mon', 'MaxVelo-SP', 'MaxVelo-RB', - 'PolModeVelo-SP', 'PolModeVelo-RB', - 'PolModeAcc-SP', 'PolModeAcc-RB', - 'GainModeVelo-SP', 'GainModeVelo-RB', - 'GainModeAcc-SP', 'GainModeAcc-RB', + 'PParamVelo-SP', 'PParamVelo-RB', + 'KParamVelo-SP', 'KParamVelo-RB', + 'PParamAcc-SP', 'PParamAcc-RB', + 'KParamAcc-SP', 'KParamAcc-RB', ) def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): @@ -897,6 +898,23 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + + # --- polarization --- + + @property + def polarization(self): + """.""" + return self['Pol-Sts'] + + @polarization.setter + def polarization(self, value): + """.""" + self['Pol-Sel'] = value + + def polarization_mon(self): + """.""" + return self['Pol-Mon'] + # --- pparameter --- @property @@ -979,6 +997,22 @@ def kparameter_mon(self): """Return ID kparameter monitor [mm].""" return self['GainShift-Mon'] + def cmd_set_pparameter_speed_max(self, phase_speed_max, timeout=None): + """Command to set ID max cruise pparam speed for movement [mm/s].""" + return self._write_sp('MaxVelo-SP', phase_speed_max, timeout) + + def cmd_set_kparameter_speed_max(self, phase_speed_max, timeout=None): + """Command to set ID max cruise kparam speed for movement [mm/s].""" + return self._write_sp('MaxVelo-SP', phase_speed_max, timeout) + + def cmd_set_pparameter_speed(self, phase_speed_max, timeout=None): + """Command to set ID pparam speed for movement [mm/s].""" + return self._write_sp('PParamVelo-SP', phase_speed_max, timeout) + + def cmd_set_kparameter_speed(self, phase_speed_max, timeout=None): + """Command to set ID kparam speed for movement [mm/s].""" + return self._write_sp('KParamVelo-SP', phase_speed_max, timeout) + class WIG(_Device): """Wiggler Insertion Device.""" From 2ab7b2f675fa11294291a202f169aca080472c03 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 16:47:04 -0300 Subject: [PATCH 067/309] ORBINTLK.FIX: continue adapting to new version of timing IOCs --- siriuspy/siriuspy/orbintlk/csdev.py | 14 +++++++++++--- siriuspy/siriuspy/orbintlk/main.py | 14 +++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 651d4a4e0..b5a5b3dd8 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -75,10 +75,12 @@ class Const(_csdev.Const): DCCT13C4TRIG_CONFIG = ( ('Src-Sel', 0), ('State-Sel', 1), + ('Log-Sel', 0) ) DCCT14C4TRIG_CONFIG = ( ('Src-Sel', 0), ('State-Sel', 1), + ('Log-Sel', 0) ) __EVG_CONFIGS = None @@ -120,15 +122,21 @@ def EVG_CONFIGS(cls): for k, v in fout2configs.items()} hlevts = _HLTimeSearch.get_hl_events() - evtin = int(hlevts['Intlk'].strip('Evt')) + evtin0 = int(hlevts['Intlk'].strip('Evt')) + evtin2 = int(hlevts['DCT13'].strip('Evt')) + evtin3 = int(hlevts['DCT14'].strip('Evt')) evtout = int(hlevts['RFKll'].strip('Evt')) evgconfigs = [ - ('IntlkTbl0to15-Sel', 0b010000010000001), + ('IntlkTbl0to15-Sel', 0b000000010000001), ('IntlkTbl16to27-Sel', 0), ('IntlkCtrlRepeat-Sel', 0), ('IntlkCtrlRepeatTime-SP', 0), - ('IntlkEvtIn0-SP', evtin), + ('IntlkEvtIn0-SP', evtin0), + ('IntlkEvtIn1-SP', 118), + ('IntlkEvtIn2-SP', evtin2), + ('IntlkEvtIn3-SP', evtin3), ('IntlkEvtOut-SP', evtout), + ('IntlkLogEnbl-SP', 0b11111111), ] evgconfigs.extend([(f'RxEnbl-SP.B{b}', 1) for b in evgrxenbl]) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index dae12990b..561782df8 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -131,7 +131,7 @@ def __init__(self, tests=True): pvo.connection_callbacks.append(self._conn_callback_timing) # # RF EVE - trgsrc = _HLTimeSearch.get_ll_trigger_names('SI-Glob:TI-LLRF-PsMtn') + trgsrc = _HLTimeSearch.get_ll_trigger_names('SI-Glob:TI-LLRF-PsMtm') pvname = _LLTimeSearch.get_channel_output_port_pvname(trgsrc[0]) self._llrf_evtcnt_pvname = f'{pvname}EvtCnt-Mon' self._everf_dev = _Device( @@ -145,7 +145,7 @@ def __init__(self, tests=True): # # HL triggers self._llrf_trig = _Trigger( - trigname='SI-Glob:TI-LLRF-PsMtn', props2init=[ + trigname='SI-Glob:TI-LLRF-PsMtm', props2init=[ 'Src-Sel', 'Src-Sts', 'DelayRaw-SP', 'DelayRaw-RB', 'State-Sel', 'State-Sts', @@ -154,7 +154,7 @@ def __init__(self, tests=True): ], auto_monitor_mon=True) self._bpmpsmtn_trig = _Trigger( - trigname='SI-Fam:TI-BPM-PsMtn', props2init=[ + trigname='SI-Fam:TI-BPM-PsMtm', props2init=[ 'Src-Sel', 'Src-Sts', 'DelayRaw-SP', 'DelayRaw-RB', 'State-Sel', 'State-Sts', @@ -861,7 +861,7 @@ def _check_configs(self): value = _updt_bit(value, 7, not oko) else: value += 0b111 << 5 - # LLRF PsMtn trigger + # LLRF PsMtm trigger dev = self._llrf_trig oko = False if dev.connected: @@ -873,7 +873,7 @@ def _check_configs(self): value = _updt_bit(value, 10, not oko) else: value += 0b111 << 8 - # BPM PsMtn trigger + # BPM PsMtm trigger dev = self._bpmpsmtn_trig oko = False if dev.connected: @@ -1049,10 +1049,10 @@ def _do_callback_bpm_intlk(self, bpmname): self._do_killbeam() # wait minimum period for RF EVE event count to be updated _time.sleep(.1) - # verify if RF EVE propagated the event PsMtn + # verify if RF EVE propagated the event PsMtm new_evtcnt = self._everf_dev[self._llrf_evtcnt_pvname] if new_evtcnt == self._everf_evtcnt: - self._update_log('WARN:RF EVE did not propagate event PsMtn') + self._update_log('WARN:RF EVE did not propagate event PsMtm') self._everf_evtcnt = new_evtcnt # wait minimum period for BPM to update interlock PVs _time.sleep(2) From 55e7efe24b013776b3a982cc66bb34ed70bc638c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 16:50:55 -0300 Subject: [PATCH 068/309] ORBINLKT.ENH: handle RxEnbl according to enable list --- siriuspy/siriuspy/orbintlk/csdev.py | 25 ++---- siriuspy/siriuspy/orbintlk/main.py | 114 ++++++++++++++++++---------- 2 files changed, 80 insertions(+), 59 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index b5a5b3dd8..dfb95e616 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -84,7 +84,7 @@ class Const(_csdev.Const): ) __EVG_CONFIGS = None - __FOUTS_CONFIGS = None + __FOUTS_2_MON = None @_classproperty def EVG_CONFIGS(cls): @@ -92,8 +92,7 @@ def EVG_CONFIGS(cls): if cls.__EVG_CONFIGS is not None: return cls.__EVG_CONFIGS - fout2configs = dict() - foutchans = set() + fouts = set() evgchans = set() evgrxenbl = list() for ch in _LLTimeSearch.get_connections_twds_evg(): @@ -104,23 +103,13 @@ def EVG_CONFIGS(cls): if ch.dev == 'BPM' and ch.sub.endswith(('SA', 'SB', 'SP')): continue fch = _LLTimeSearch.get_fout_channel(ch) - if fch in foutchans: - continue - foutchans.add(fch) - devname = fch.device_name - rxe = fout2configs.get(devname, list()) - rxe.append(int(fch.propty[3:])) - fout2configs[devname] = rxe + fouts.add(fch.device_name) evgch = _LLTimeSearch.get_evg_channel(fch) if evgch in evgchans: continue evgchans.add(evgch) evgrxenbl.append(int(evgch.propty[3:])) - fout2configs = { - k: [(f'RxEnbl-SP.B{b}', 1) for b in v] - for k, v in fout2configs.items()} - hlevts = _HLTimeSearch.get_hl_events() evtin0 = int(hlevts['Intlk'].strip('Evt')) evtin2 = int(hlevts['DCT13'].strip('Evt')) @@ -140,16 +129,16 @@ def EVG_CONFIGS(cls): ] evgconfigs.extend([(f'RxEnbl-SP.B{b}', 1) for b in evgrxenbl]) - cls.__FOUTS_CONFIGS = fout2configs + cls.__FOUTS_2_MON = fouts cls.__EVG_CONFIGS = evgconfigs return cls.__EVG_CONFIGS @_classproperty - def FOUTS_CONFIGS(cls): - """Fouts configurations.""" + def FOUTS_2_MON(cls): + """Fouts to be monitored.""" cls.EVG_CONFIGS - return cls.__FOUTS_CONFIGS + return cls.__FOUTS_2_MON AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 561782df8..ac6859547 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -61,7 +61,7 @@ def __init__(self, tests=True): self._thread_acq = None self._thread_cbevgilk = None self._thread_cbevgrx = None - self._thread_cbfout = None + self._thread_cbfout = {fout: None for fout in self._const.FOUTS_2_MON} self._thread_cbbpm = None self._ti_mon_devs = set() @@ -77,6 +77,7 @@ def __init__(self, tests=True): 'IntlkEvtIn0-SP', 'IntlkEvtIn0-RB', 'IntlkEvtOut-SP', 'IntlkEvtOut-SP', 'IntlkEvtStatus-Mon', + 'RxEnbl-SP', 'RxEnbl-RB', 'RxEnbl-SP.B0', 'RxEnbl-RB.B0', 'RxEnbl-SP.B1', 'RxEnbl-RB.B1', 'RxEnbl-SP.B2', 'RxEnbl-RB.B2', @@ -99,6 +100,7 @@ def __init__(self, tests=True): devname: _Device( devname, props2init=[ + 'RxEnbl-SP', 'RxEnbl-RB', 'RxEnbl-SP.B0', 'RxEnbl-RB.B0', 'RxEnbl-SP.B1', 'RxEnbl-RB.B1', 'RxEnbl-SP.B2', 'RxEnbl-RB.B2', @@ -109,7 +111,7 @@ def __init__(self, tests=True): 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) - for devname in self._const.FOUTS_CONFIGS + for devname in self._const.FOUTS_2_MON } for dev in self._fout_devs.values(): pvo = dev.pv_object('RxLockedLtc-Mon') @@ -411,15 +413,19 @@ def set_enbllist(self, intlk, value): return False # check if new enable list do not imply in orbit interlock failure - bkup = self._enable_lists[intlk] + bkup_enbllist = self._enable_lists[intlk] + bkup_timondev = self._ti_mon_devs self._enable_lists[intlk] = new - mondevs = self._get_ti_monitored_devices() - if not self._check_devices_status(mondevs): + self._ti_mon_devs = self._get_ti_monitored_devices() + self._config_fout_rxenbl() + if not self._check_devices_status(self._ti_mon_devs): self._update_log('ERR:Could not set enable list.') - self._enable_lists[intlk] = bkup + self._enable_lists[intlk] = bkup_enbllist + self._ti_mon_devs = bkup_timondev + self._config_fout_rxenbl() return False - self._ti_mon_devs = mondevs - self.run_callbacks('TimingMonitoredDevices-Mon', '\n'.join(mondevs)) + self.run_callbacks( + 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) # do not set enable lists and save to file in initialization if not self._init: @@ -685,16 +691,10 @@ def _config_timing(self): if not dev._wait(prp_rb, val): self._update_log(f'ERR:Failed to configure EVG PV {prp:s}') return False - # Fouts - for devname, configs in self._const.FOUTS_CONFIGS.items(): - dev = self._fout_devs[devname] - for prp, val in configs: - dev[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not dev._wait(prp_rb, val): - self._update_log( - f'ERR:Failed to configure {devname} PV {prp:s}') - return False + # Fout + if not self._config_fout_rxenbl(): + return False + # triggers trig2config = { self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, self._llrf_trig: self._const.LLRFTRIG_CONFIG, @@ -713,6 +713,31 @@ def _config_timing(self): return False return True + def _config_fout_rxenbl(self): + # disable all rxenbl + for fout in self._fout_devs.values(): + fout['RxEnbl-SP'] = 0 + if not fout._wait('RxEnbl-RB', 0): + self._update_log( + f'ERR:Failed to disable {fout.devname} RxEnbl') + return False + + # enable only necessary rxenbl + for dev in self._ti_mon_devs: + if 'Fout' not in dev: + continue + devname = _SiriusPVName(dev) + bit = int(dev[-1]) + fout = self._fout_devs[devname.device_name] + fout[f'RxEnbl-SP.B{bit}'] = 1 + fout['RxLockedLtcRst-Cmd'] = 1 + if not fout._wait(f'RxEnbl-SP.B{bit}', 1): + self._update_log( + f'ERR:Failed to configure {devname} RxEnbl.B{bit}') + return False + + return True + def _config_llrf(self): self._llrf['ILK:BEAM:TRIP:S'] = self._llrf_intlk_state if not self._llrf._wait('ILK:BEAM:TRIP', self._llrf_intlk_state): @@ -840,13 +865,13 @@ def _check_configs(self): value = 0b111 # Fouts devs = self._fout_devs - if all(devs[devn].connected for devn in self._const.FOUTS_CONFIGS): + if all(devs[devn].connected for devn in self._const.FOUTS_2_MON): okg = True - for idx, configs in self._const.FOUTS_CONFIGS.items(): - dev = self._fout_devs[idx] - for prp, val in configs: - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - okg &= dev[prp_rb] == val + for devname in self._ti_mon_devs: + if 'Fout' not in devname: + continue + dev = self._fout_devs[_SiriusPVName(devname).device_name] + okg &= dev[f'RxEnbl-RB.B{int(devname[-1])}'] value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 @@ -965,17 +990,13 @@ def _callback_fout_rxlock(self, pvname, value, **kws): return if not self._init: return - pvname = _SiriusPVName(pvname) - configs = self._const.FOUTS_CONFIGS[pvname.device_name] - bits = [int(c[0][-1]) for c in configs if 'RxEnbl' in c[0]] - if all([_get_bit(value, b) for b in bits]): # all ok + nam = _SiriusPVName(pvname).device_name + if self._thread_cbfout[nam] and self._thread_cbfout[nam].is_alive(): return - if self._thread_cbfout and self._thread_cbfout.is_alive(): - return - self._thread_cbfout = _CAThread( + self._thread_cbfout[nam] = _CAThread( target=self._do_callback_rxlock, args=(pvname, value, ), daemon=True) - self._thread_cbfout.start() + self._thread_cbfout[nam].start() def _callback_evg_rxlock(self, pvname, value, **kws): if not self._state: @@ -997,15 +1018,26 @@ def _callback_evg_rxlock(self, pvname, value, **kws): def _do_callback_rxlock(self, pvname, value): pvname = _SiriusPVName(pvname) devname = pvname.device_name - shouldkill = False - for bit in range(8): - if _get_bit(value, bit): - continue - outnam = f'OUT{bit}' - self._update_log(f'FATAL:{outnam} of {devname} lost lock') - devout = pvname.device_name.substitute(propty_name=outnam) - # verify if this is an orbit interlock reliability failure - shouldkill |= devout in self._ti_mon_devs + if pvname.dev == 'EVG': + shouldkill = False + for bit in range(8): + if _get_bit(value, bit): + continue + outnam = f'OUT{bit}' + self._update_log(f'FATAL:{outnam} of {devname} lost lock') + devout = devname.substitute(propty_name=outnam) + # verify if this is an orbit interlock reliability failure + shouldkill |= devout in self._ti_mon_devs + else: + out = None + for dev in self._ti_mon_devs: + if 'Fout' not in dev: + continue + dev = _SiriusPVName(dev) + if dev.device_name == devname: + out = int(dev.propty_name[-1]) + break + shouldkill = out is not None and not _get_bit(value, out) if shouldkill: self._update_log('FATAL:Orbit interlock reliability failure') self._do_killbeam() From e6d42f62995f8694b424eb76820b28f2d45c12f6 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 16:51:53 -0300 Subject: [PATCH 069/309] ORINTLK.FIX: fix bug in connection callback checks --- siriuspy/siriuspy/orbintlk/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ac6859547..10ff88146 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1055,7 +1055,9 @@ def _conn_callback_timing(self, pvname, conn, **kws): if not self._state: return # verify if this is an orbit interlock reliability failure - shouldkill = pvname.device_name in self._ti_mon_devs + shouldkill = False + for dev in self._ti_mon_devs: + shouldkill |= _SiriusPVName(dev).device_name == pvname.device_name if shouldkill: self._update_log('FATAL:Orbit interlock reliability failure') self._do_killbeam() From 24f3193a91802a143528783af62bbd4493786b71 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 17:18:32 -0300 Subject: [PATCH 070/309] ORBINTLK.MNT: fix logs --- siriuspy/siriuspy/orbintlk/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 10ff88146..4a61dc79f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -554,7 +554,7 @@ def cmd_reset_ti_lock_latch(self, value=None): continue afcti['ClkLockedLtcRst-Cmd'] = 1 msg = 'Reset' if afcti._wait('RTMClkLockedLtc-Mon', 1, timeout=3) \ - else 'Could not reset' + else 'ERR:Could not reset' self._update_log(f'{msg} AFC Timing {idx} lock latchs.') if 'not' in msg: return False @@ -565,7 +565,7 @@ def cmd_reset_ti_lock_latch(self, value=None): continue fout['RxLockedLtcRst-Cmd'] = 1 msg = 'Reset' if fout._wait('RxLockedLtc-Mon', 1, timeout=3) \ - else 'Could not reset' + else 'ERR:Could not reset' self._update_log(f'{msg} {devname} lock latchs.') if 'not' in msg: return False From ef8113186ff473c8dcc1d023fe2adf9335576541 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 21:02:32 -0300 Subject: [PATCH 071/309] ORBINTLK.FIX: fix Fout RxEnbl control --- siriuspy/siriuspy/orbintlk/csdev.py | 5 ++- siriuspy/siriuspy/orbintlk/main.py | 58 ++++++++++++----------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index dfb95e616..32d924d6a 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -82,6 +82,9 @@ class Const(_csdev.Const): ('State-Sel', 1), ('Log-Sel', 0) ) + FOUT2_CONFIGS = ( + ('RxEnbl-SP', 0b01000001), + ) __EVG_CONFIGS = None __FOUTS_2_MON = None @@ -96,7 +99,7 @@ def EVG_CONFIGS(cls): evgchans = set() evgrxenbl = list() for ch in _LLTimeSearch.get_connections_twds_evg(): - if ch.dev not in {'BPM', 'DCCTDig'}: + if ch.dev != 'BPM': continue if ch.sec != 'SI': continue diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 4a61dc79f..fa02b8905 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -101,22 +101,20 @@ def __init__(self, tests=True): devname, props2init=[ 'RxEnbl-SP', 'RxEnbl-RB', - 'RxEnbl-SP.B0', 'RxEnbl-RB.B0', - 'RxEnbl-SP.B1', 'RxEnbl-RB.B1', - 'RxEnbl-SP.B2', 'RxEnbl-RB.B2', - 'RxEnbl-SP.B3', 'RxEnbl-RB.B3', - 'RxEnbl-SP.B4', 'RxEnbl-RB.B4', - 'RxEnbl-SP.B5', 'RxEnbl-RB.B5', - 'RxEnbl-SP.B6', 'RxEnbl-RB.B6', - 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) for devname in self._const.FOUTS_2_MON } - for dev in self._fout_devs.values(): + self._fout2rxenbl = dict() + for devname, dev in self._fout_devs.items(): pvo = dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_fout_rxlock) pvo.connection_callbacks.append(self._conn_callback_timing) + self._fout2rxenbl[devname] = 0 + + self._fout_dcct_dev = _Device( + 'CA-RaTim:TI-Fout-2', + props2init=['RxEnbl-SP', 'RxEnbl-RB']) # # AFC timing self._afcti_devs = { @@ -714,27 +712,21 @@ def _config_timing(self): return True def _config_fout_rxenbl(self): - # disable all rxenbl - for fout in self._fout_devs.values(): - fout['RxEnbl-SP'] = 0 - if not fout._wait('RxEnbl-RB', 0): - self._update_log( - f'ERR:Failed to disable {fout.devname} RxEnbl') - return False - - # enable only necessary rxenbl - for dev in self._ti_mon_devs: - if 'Fout' not in dev: + fout2rx = dict() + for chn in self._ti_mon_devs: + if 'Fout' not in chn: continue - devname = _SiriusPVName(dev) - bit = int(dev[-1]) - fout = self._fout_devs[devname.device_name] - fout[f'RxEnbl-SP.B{bit}'] = 1 - fout['RxLockedLtcRst-Cmd'] = 1 - if not fout._wait(f'RxEnbl-SP.B{bit}', 1): - self._update_log( - f'ERR:Failed to configure {devname} RxEnbl.B{bit}') - return False + devname = chn.device_name + out = int(chn.propty_name[-1]) + rx = fout2rx.get(devname, 0) + rx += 1 << out + + for fout, rxenbl in fout2rx.items(): + self._fout2rxenbl[fout] = rxenbl + dev = self._fout_devs[fout] + dev['RxEnbl-SP'] = rxenbl + dev._wait('RxEnbl-RB', rxenbl) + dev['RxLockedLtcRst-Cmd'] = 1 return True @@ -867,11 +859,9 @@ def _check_configs(self): devs = self._fout_devs if all(devs[devn].connected for devn in self._const.FOUTS_2_MON): okg = True - for devname in self._ti_mon_devs: - if 'Fout' not in devname: - continue - dev = self._fout_devs[_SiriusPVName(devname).device_name] - okg &= dev[f'RxEnbl-RB.B{int(devname[-1])}'] + for devname, rxenbl in self._fout2rxenbl.items(): + dev = self._fout_devs[devname] + okg &= dev['RxEnbl-RB'] == rxenbl value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 From 6d59e5567e97be2a73dba9ea1a10e4e42c6a9972 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 21:12:40 -0300 Subject: [PATCH 072/309] ORBINTLK.ENH: implement feature to lock timing and LLRF configurations --- siriuspy/siriuspy/orbintlk/csdev.py | 4 + siriuspy/siriuspy/orbintlk/main.py | 121 ++++++++++++++++++---------- 2 files changed, 83 insertions(+), 42 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 32d924d6a..73f2618cf 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -319,6 +319,10 @@ def get_database(self): 'Reset-Cmd': {'type': 'int', 'value': 0}, 'ResetTimingLockLatches-Cmd': {'type': 'int', 'value': 0}, 'ResetAFCTimingRTMClk-Cmd': {'type': 'int', 'value': 0}, + 'RetryLock-Cmd': {'type': 'int', 'value': 0}, + 'IsLocking-Mon': { + 'type': 'enum', 'value': self.OffOn.On, + 'enums': self.OffOn._fields} # Acquisition 'PsMtmAcqChannel-Sel': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index fa02b8905..eeae523fc 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -64,6 +64,8 @@ def __init__(self, tests=True): self._thread_cbfout = {fout: None for fout in self._const.FOUTS_2_MON} self._thread_cbbpm = None self._ti_mon_devs = set() + self._lock_fails_cnt = dict() + self._lock_suspend = False # devices and connections # # EVG @@ -88,12 +90,20 @@ def __init__(self, tests=True): 'RxEnbl-SP.B7', 'RxEnbl-RB.B7', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ]) + # interlock callback pvo = self._evg_dev.pv_object('IntlkEvtStatus-Mon') pvo.auto_monitor = True pvo.add_callback(self._callback_evg_intlk) pvo.connection_callbacks.append(self._conn_callback_timing) + # rxlock callback pvo = self._evg_dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_evg_rxlock) + # lock callback + for propty_sp, desired_val in self._const.EVG_CONFIGS.items(): + propty_rb = propty_sp.replace('SP', 'RB').replace('Sel', 'Sts') + pvo = self._evg_dev.pv_object(propty_rb) + pvo.add_callback(_part( + self._callback_lock, self._evg_dev, propty_sp, desired_val)) # # Fouts self._fout_devs = { @@ -110,11 +120,19 @@ def __init__(self, tests=True): pvo = dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_fout_rxlock) pvo.connection_callbacks.append(self._conn_callback_timing) + pvo = dev.pv_object('RxEnbl-RB') + pvo.add_callback(self._callback_fout_lock) self._fout2rxenbl[devname] = 0 self._fout_dcct_dev = _Device( 'CA-RaTim:TI-Fout-2', props2init=['RxEnbl-SP', 'RxEnbl-RB']) + for propty_sp, desired_val in self._const.FOUT2_CONFIGS.items(): + propty_rb = propty_sp.replace('SP', 'RB').replace('Sel', 'Sts') + pvo = self._fout_dcct_dev.pv_object(propty_rb) + pvo.add_callback(_part( + self._callback_lock, self._fout_dcct_dev, + propty_sp, desired_val)) # # AFC timing self._afcti_devs = { @@ -185,6 +203,20 @@ def __init__(self, tests=True): 'Status-Mon', ], auto_monitor_mon=True) + trig2config = { + self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, + self._llrf_trig: self._const.LLRFTRIG_CONFIG, + self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, + self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, + self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, + } + for trig, configs in trig2config.items(): + for prop_sp, desired_val in configs.items(): + prop_rb = prop_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') + pvo = trig.pv_object(prop_rb) + pvo.add_callback( + _part(self._callback_lock, trig, prop_sp, desired_val)) + # # BPM devices self._orbintlk_dev = _OrbitIntlk() for dev in self._orbintlk_dev.devices: @@ -210,6 +242,10 @@ def __init__(self, tests=True): 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'IntlkSet-Cmd', ]) + pvo = self._llrf.pv_object('ILK:BEAM:TRIP') + pvo.add_callback(_part( + self._callback_lock, self._llrf, + 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) # # auxiliary devices self._fofb = _FOFB( @@ -244,6 +280,7 @@ def __init__(self, tests=True): 'IntlkStateConfig-Cmd': self.cmd_state_config, 'ResetTimingLockLatches-Cmd': self.cmd_reset_ti_lock_latch, 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, + 'RetryLock-Cmd': self.cmd_retry_lock, } # configuration scanning @@ -272,6 +309,7 @@ def init_database(self): 'PsMtmAcqSamplesPost-SP': self._acq_spost, 'PsMtmAcqSamplesPost-RB': self._acq_spost, 'PsMtmAcqConfig-Cmd': 0, + 'IsLocking-Mon': not self._lock_suspend, } for pvn, val in pvn2vals.items(): self.run_callbacks(pvn, val) @@ -595,6 +633,12 @@ def cmd_reset_afcti_rtmclk(self, value=None): return True + def cmd_retry_lock(self, value=None): + """Command to retry lock configurations.""" + self._lock_suspend = False + self.run_callbacks('IsLocking-Mon', not self._lock_suspend) + return True + # --- configure acquisition --- def set_acq_channel(self, value): @@ -674,41 +718,6 @@ def cmd_state_config(self, value=None): if not self.set_enable(self._state): return False - if not self._config_timing(): - return False - if not self._config_llrf(): - return False - return True - - def _config_timing(self): - # EVG - dev = self._evg_dev - for prp, val in self._const.EVG_CONFIGS: - dev[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not dev._wait(prp_rb, val): - self._update_log(f'ERR:Failed to configure EVG PV {prp:s}') - return False - # Fout - if not self._config_fout_rxenbl(): - return False - # triggers - trig2config = { - self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, - self._llrf_trig: self._const.LLRFTRIG_CONFIG, - self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, - self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, - self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, - } - for trig, configs in trig2config.items(): - for prp, val in configs: - name = trig.dev + trig.idx - trig[prp] = val - prp_rb = prp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not trig._wait(prp_rb, val): - self._update_log( - f'ERR:Failed to configure {name} PV {prp:s}') - return False return True def _config_fout_rxenbl(self): @@ -730,13 +739,6 @@ def _config_fout_rxenbl(self): return True - def _config_llrf(self): - self._llrf['ILK:BEAM:TRIP:S'] = self._llrf_intlk_state - if not self._llrf._wait('ILK:BEAM:TRIP', self._llrf_intlk_state): - self._update_log('ERR:Failed to configure LLRF.') - return False - return True - def _get_enabled_sections(self): enbllist = self._get_gen_bpm_intlk() aux = _np.roll(enbllist, 1) @@ -1095,6 +1097,41 @@ def _do_killbeam(self): _time.sleep(1) self._llrf['IntlkSet-Cmd'] = 0 + def _callback_lock( + self, device, propty_sp, desired_value, pvname, value, **kwargs): + thread = _CAThread( + target=self._do_callback_lock, + args=(device, propty_sp, desired_value, pvname, value), + daemon=True) + thread.start() + + def _callback_fout_lock(self, pvname, value, **kwargs): + devname = _SiriusPVName(pvname).device_name + desired_value = self._fout2rxenbl[devname] + device = self._fout_devs[devname] + thread = _CAThread( + target=self._do_callback_lock, + args=(device, 'RxEnbl-SP', desired_value, pvname, value), + daemon=True) + thread.start() + + def _do_callback_lock( + self, device, propty_sp, desired_value, pvname, value): + if self._lock_suspend: + return + cnt = self._lock_fails_cnt.get(pvname, 0) + if value != desired_value: + self._lock_fails_cnt[pvname] = cnt + 1 + device[propty] = desired_value + else: + self._lock_fails_cnt[pvname] = 0 + if self._lock_fails_cnt[pvname] >= 10: + self._update_log(f'FATAL:Fail to lock {pvname}') + self._update_log(f'FATAL:Orbit interlock reliability failure') + self._do_killbeam() + self._lock_suspend = True + self.run_callbacks('IsLocking-Mon', not self._lock_suspend) + # --- auxiliary log methods --- def _update_log(self, msg): From c6c104346f8523cc5c14c7b6cabf35dd8ea1f238 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 10 Nov 2023 21:41:36 -0300 Subject: [PATCH 073/309] ORBINTLK.FIX: fix buf left in Const --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 73f2618cf..81ff79bcf 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -322,7 +322,7 @@ def get_database(self): 'RetryLock-Cmd': {'type': 'int', 'value': 0}, 'IsLocking-Mon': { 'type': 'enum', 'value': self.OffOn.On, - 'enums': self.OffOn._fields} + 'enums': self.OffOn._fields}, # Acquisition 'PsMtmAcqChannel-Sel': { From ceab1935339ce86613f1412c6cacfee933388180 Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 10 Nov 2023 22:19:58 -0300 Subject: [PATCH 074/309] Refactor ID device classes --- siriuspy/siriuspy/devices/device.py | 6 +- siriuspy/siriuspy/devices/ids.py | 260 +++++++++++++++++++++------- 2 files changed, 201 insertions(+), 65 deletions(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 8823a16d3..87941a9fe 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -229,12 +229,16 @@ def comp_(val): return True timeout = _DEF_TIMEOUT if timeout is None else timeout + timeout = 0 if timeout <= 0 else timeout ntrials = int(timeout/_TINY_INTERVAL) for _ in range(ntrials): _time.sleep(_TINY_INTERVAL) if comp_(value): return True - return False + if comp_(value): + return True + else: + return False def _wait_float( self, propty, value, rel_tol=0.0, abs_tol=0.1, timeout=None): diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 0c1863618..d62c51a8e 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -11,6 +11,7 @@ class _ID(_Device): """Generic Insertion Device.""" + _SHORT_SHUT_EYE = 0.1 # [s] _MOVECHECK_SLEEP = 0.1 # [s] _DEF_TIMEOUT = 8 # [s] @@ -21,7 +22,6 @@ class _ID(_Device): def __init__(self, devname, props2init='all', auto_monitor_mon=True): """.""" - # call base class constructor super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) @@ -40,12 +40,12 @@ def period_length(self): def pparameter_parked(self): """Return ID parked pparameter value [mm].""" return self.parameters.PPARAM_PARKED - + @property def kparameter_parked(self): """Return ID parked kparameter value [mm].""" return self.parameters.KPARAM_PARKED - + # --- movement checks --- @property @@ -65,6 +65,12 @@ def cmd_beamline_ctrl_disable(self, timeout=None): # --- cmd_wait + def wait_while_busy(self, timeout=None): + """Command wait within timeout while ID control is busy.""" + return True + + # --- cmd_wait + def cmd_wait_move(self, timeout=None): """Wait for phase movement to complete.""" _time.sleep(APU._MOVECHECK_SLEEP) @@ -77,6 +83,18 @@ def cmd_wait_move(self, timeout=None): # --- private methods --- + def _move_start(self, cmd_propty, timeout=None): + timeout = timeout or self._DEF_TIMEOUT + + # wait for not busy state + if not self.wait_while_busy(timeout=timeout): + return False + + # send move command + self[cmd_propty] = 1 + + return True + def _write_sp(self, propties_sp, values, timeout=None, pvs_sp_rb=None): timeout = timeout or self._DEF_TIMEOUT if isinstance(propties_sp, str): @@ -95,6 +113,16 @@ def _write_sp(self, propties_sp, values, timeout=None, pvs_sp_rb=None): propty_rb, value, timeout=timeout, comp='eq') return success + def _wait_propty(self, propty, value, timeout=None): + """.""" + t0_ = _time.time() + timeout = timeout if timeout is not None else self._DEF_TIMEOUT + while self[propty] != value: + _time.sleep(self._SHORT_SHUT_EYE) + if _time.time() - t0_ > timeout: + return False + return True + class APU(_ID): """APU Insertion Device.""" @@ -112,7 +140,6 @@ class DEVICES: TOLERANCE_PHASE = 0.01 # [mm] - _SHORT_SHUT_EYE = 0.1 # [s] _CMD_MOVE_STOP, _CMD_MOVE_START = 1, 3 _CMD_MOVE = 3 @@ -282,7 +309,6 @@ class DEVICES: TOLERANCE_PHASE = 0.01 # [mm] _SHORT_SHUT_EYE = 0.1 # [s] - _default_timeout = 8 # [s] _properties = ( 'PeriodLength-Cte', @@ -456,12 +482,6 @@ def cmd_move_disable(self, timeout=None): """Command to disable and break ID phase and gap movements.""" return self.cmd_move_phase_disable(timeout=timeout) - # --- cmd_wait - - def wait_while_busy(self, timeout=None): - """Command wait within timeout while ID control is busy.""" - return True - def wait_move_start(self, timeout=None): """Command wait until movement starts or timeout.""" time_init = _time.time() @@ -474,7 +494,7 @@ def wait_move_start(self, timeout=None): def cmd_move_stop(self, timeout=None): """Command to interrupt and then enable phase movements.""" - timeout = timeout or self._default_timeout + timeout = timeout or self._DEF_TIMEOUT # wait for not busy state if not self.wait_while_busy(timeout=timeout): @@ -563,20 +583,8 @@ def cmd_clear_error(self): # --- private methods --- - def _move_start(self, cmd_propty, timeout=None): - timeout = timeout or self._default_timeout - - # wait for not busy state - if not self.wait_while_busy(timeout=timeout): - return False - - # send move command - self[cmd_propty] = 1 - - return True - def _write_sp(self, propties_sp, values, timeout=None): - timeout = timeout or self._default_timeout + timeout = timeout or self._DEF_TIMEOUT if isinstance(propties_sp, str): propties_sp = (propties_sp, ) values = (values, ) @@ -591,7 +599,7 @@ def _write_sp(self, propties_sp, values, timeout=None): return success def _wait_propty_values(self, props_values, timeout=None, comp='eq'): - timeout = timeout if timeout is not None else self._default_timeout + timeout = timeout if timeout is not None else self._DEF_TIMEOUT time0 = _time.time() for propty, value in props_values.items(): timeout_left = max(0, timeout - (_time.time() - time0)) @@ -789,7 +797,7 @@ def cmd_move_disable(self, timeout=None): def wait_while_busy(self, timeout=None): """Command wait within timeout while ID control is busy.""" - timeout = timeout or self._default_timeout + timeout = timeout or self._DEF_TIMEOUT time_init = _time.time() while self.is_busy: _time.sleep(min(self._SHORT_SHUT_EYE, timeout)) @@ -852,7 +860,7 @@ def move(self, phase, gap, timeout=None): print(f'wait_time: {_time.time() - time_init:.3f} s') print() return False - _time.sleep(EPU._SHORT_SHUT_EYE) + _time.sleep(self._SHORT_SHUT_EYE) # successfull movement at this point return True @@ -874,15 +882,17 @@ class DEVICES: ALL = (DELTA52_10SB, ) PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( - 'PolShift-Mon', - 'Pol-Mon', + 'Pol-Sel', 'Pol-Sts', 'Pol-Mon', 'ChangePol-Cmd', - 'GainShift-SP', 'GainShift-RB', 'GainShift-Mon', 'MaxVelo-SP', 'MaxVelo-RB', - 'PolModeVelo-SP', 'PolModeVelo-RB', - 'PolModeAcc-SP', 'PolModeAcc-RB', - 'GainModeVelo-SP', 'GainModeVelo-RB', - 'GainModeAcc-SP', 'GainModeAcc-RB', + 'ParkedPparameter-Cte', + 'PParam-SP', 'PParam-RB', 'PParam-Mon', + 'PParamVelo-SP', 'PParamVelo-RB', + 'PParamAcc-SP', 'PParamAcc-RB', + 'ParkedKparameter-Cte', + 'KParam-SP', 'KParam-RB', 'KParam-Mon', + 'KParamVelo-SP', 'KParamVelo-RB', + 'KParamAcc-SP', 'KParamAcc-RB', ) def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): @@ -897,8 +907,30 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + # --- polarization --- + + @property + def polarization(self): + """Return ID polarization.""" + return self['Pol-Sts'] + + @polarization.setter + def polarization(self, value): + """Set ID polarization.""" + self['Pol-Sel'] = value + + @property + def polarization_mon(self): + """Return ID polarization monitor.""" + return self['Pol-Mon'] + # --- pparameter --- + @property + def pparameter_parked(self): + """Return ID parked pparameter value [mm].""" + return self['ParkedPparameter-Cte'] + @property def pparameter_speed_max(self): """Return max pparameter speed readback [mm/s].""" @@ -914,27 +946,43 @@ def pparameter_speed_max_lims(self): @property def pparameter_speed(self): """Return pparameter speed readback [mm/s].""" - return self['PolModeVelo-RB'] + return self['PParamVelo-RB'] @property - def pparameter_min(self): + def pparameter_lims(self): """Return ID pparameter lower control limit [mm].""" - ctrlvars = self.pv_ctrlvars('PolShift-Mon') - return ctrlvars['lower_ctrl_limit'] + ctrl = self.pv_ctrlvars('PParam-Mon') + return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] @property - def pparameter_max(self): - """Return ID pparameter upper control limit [mm].""" - ctrlvars = self.pv_ctrlvars('PolShift-Mon') - return ctrlvars['upper_ctrl_limit'] + def pparameter(self): + """Return ID pparameter readback [mm].""" + return self['KParam-RB'] @property def pparameter_mon(self): """Return ID pparameter monitor [mm].""" - return self['PolShift-Mon'] - + return self['PParam-Mon'] + + def set_pparameter(self, kparam, timeout=None): + """Set ID target pparameter for movement [mm].""" + return self._write_sp('PParam-SP', kparam, timeout) + + def set_pparameter_speed(self, pparam_speed, timeout=None): + """Command to set ID cruise pparam speed for movement [mm/s].""" + return self._write_sp('PParamVelo-SP', pparam_speed, timeout) + + def set_pparameter_speed_max(self, pparam_speed_max, timeout=None): + """Command to set ID max cruise pparam speed for movement [mm/s].""" + return self._write_sp('MaxVelo-SP', pparam_speed_max, timeout) + # --- kparameter --- + @property + def kparameter_parked(self): + """Return ID parked kparameter value [mm].""" + return self['ParkedKparameter-Cte'] + @property def kparameter_speed_max(self): """Return max kparameter speed readback [mm/s].""" @@ -950,34 +998,118 @@ def kparameter_speed_max_lims(self): @property def kparameter_speed(self): """Return kparameter speed readback [mm/s].""" - return self['GainModeVelo-RB'] - - @property - def kparameter(self): - """Return ID kparameter readback [mm].""" - return self['Shift-RB'] - - @kparameter.setter - def kparameter(self, value): - """Set ID kparameter [mm].""" - self['Shift-SP'] = value + return self['KParamVelo-RB'] @property - def kparameter_min(self): + def kparameter_lims(self): """Return ID kparameter lower control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Shift-SP') - return ctrlvars['lower_ctrl_limit'] + ctrl = self.pv_ctrlvars('KParam-Mon') + return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] @property - def kparameter_max(self): - """Return ID kparameter upper control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Shift-SP') - return ctrlvars['upper_ctrl_limit'] + def kparameter(self): + """Return ID kparameter readback [mm].""" + return self['KParam-RB'] @property def kparameter_mon(self): """Return ID kparameter monitor [mm].""" - return self['GainShift-Mon'] + return self['KParam-Mon'] + + # --- set methods --- + + def set_kparameter(self, kparam, timeout=None): + """Command to set ID target kparameter for movement [mm].""" + return self._write_sp('KParam-SP', kparam, timeout) + + def set_kparameter_speed(self, kparam_speed, timeout=None): + """Command to set ID cruise kparam speed for movement [mm/s].""" + return self._write_sp('KParamVelo-SP', kparam_speed, timeout) + + def set_kparameter_speed_max(self, kparam_speed_max, timeout=None): + """Command to set ID max cruise kparam speed for movement [mm/s].""" + return self._write_sp('MaxVelo-SP', kparam_speed_max, timeout) + + # --- commands --- + + def cmd_move_start(self, timeout=None): + """Command to start movement.""" + success = True + success &= self.cmd_move_pparam_start(timeout=timeout) + success &= self.cmd_move_kparam_start(timeout=timeout) + return success + + def cmd_move_pparam_start(self, timeout=None): + """Command to start Pparameter movement.""" + return self._move_start('ChangePparam-Cmd', timeout=timeout) + + def cmd_move_kparam_start(self, timeout=None): + """Command to start Kparameter movement.""" + return self._move_start('ChangeKparam-Cmd', timeout=timeout) + + def cmd_change_polarization_start(self, timeout=None): + """Change polarization.""" + _ = timeout + self['ChangePol-Cmd'] = 1 + + def cmd_move_park(self, timeout=None): + """Move ID to parked config.""" + return self.move( + self.pparameter_parked, self.kparameter_parked, timeout=timeout) + + def move(self, pparam, kparam, timeout=None): + """Command to set and start pparam and kparam movements.""" + # calc ETA + dtime_phase = abs(pparam - self.pparameter_mon) / self.pparameter_speed + dtime_gap = abs(kparam - self.kparameter_mon) / self.kparameter_speed + dtime_max = max(dtime_phase, dtime_gap) + + # additional percentual in ETA + tol_gap = 0.01 # [mm] + tol_phase = 0.01 # [mm] + tol_dtime = 300 # [%] + tol_factor = (1 + tol_dtime/100) + tol_total = tol_factor * dtime_max + 5 + + # set target phase and gap + if not self.set_pparameter(phase=pparam, timeout=timeout): + return False + if not self.set_kparameter(gap=kparam, timeout=timeout): + return False + + # command move start + if not self.cmd_move_pparam_start(timeout=timeout): + return False + if not self.cmd_move_kparam_start(timeout=timeout): + return False + + # wait for movement within reasonable time + time_init = _time.time() + while \ + abs(self.kparameter_mon - kparam) > tol_gap or \ + abs(self.pparameter_mon - pparam) > tol_phase or \ + self.is_moving: + if _time.time() - time_init > tol_total: + print(f'tol_total: {tol_total:.3f} s') + print(f'wait_time: {_time.time() - time_init:.3f} s') + print() + return False + _time.sleep(self._SHORT_SHUT_EYE) + + # successfull movement at this point + return True + + def change_polarization(self, polarization, timeout=None): + """.""" + t0_ = _time.time() + # set desired polarization + if not self._write_sp('Pol-Sel', polarization, timeout=timeout): + return False + # send change polarization command + self['ChangePol-Cmd'] = 1 + timeout -= _time.time() - t0_ + # wait for polarization value within timeout + return self._wait('Pol-Mon', polarization, timeout=timeout, comp='eq') class WIG(_Device): From d376318807d2c8795c9817b23f09cc2689e8b752 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 11 Nov 2023 20:57:06 -0300 Subject: [PATCH 075/309] DEV.INJSYS.FIX: fix bug left in BOPSRampStandbyHandler.cmd_turn_off --- siriuspy/siriuspy/devices/injsys.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/injsys.py b/siriuspy/siriuspy/devices/injsys.py index df1471aca..aa42b05a5 100644 --- a/siriuspy/siriuspy/devices/injsys.py +++ b/siriuspy/siriuspy/devices/injsys.py @@ -241,8 +241,8 @@ def cmd_turn_off(self): # wait for PS change opmode retval = self._wait_devices_propty( self._psdevs, 'OpMode-Sts', - [_PSConst.States.SlowRef, _PSConst.States.Off], - comp='contains', timeout=3, return_prob=True) + len(self._psdevs)*[[_PSConst.States.SlowRef, _PSConst.States.Off]], + comp=lambda x, y: x in y, timeout=3, return_prob=True) if not retval[0]: text = 'Check for BO PS to be in OpMode SlowRef '\ 'timed out without success! Verify BO PS!' From 0200d20fe5dffb2db484e455db2d84171289dfa5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 11 Nov 2023 21:06:10 -0300 Subject: [PATCH 076/309] injctrl.MNT: increase egun bias check tolerance --- siriuspy/siriuspy/injctrl/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index 0adcb0172..6acec9e67 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -513,7 +513,7 @@ def _set_egunbias(self, value): self.run_callbacks('BiasVoltCmdSts-Mon', _Const.IdleRunning.Running) self._update_log(f'Setting EGun Bias voltage to {value:.2f}V...') - if not self.egun_dev.bias.set_voltage(value, tol=0.005*value): + if not self.egun_dev.bias.set_voltage(value, tol=0.007*value): self._update_log('ERR:Could not set EGun Bias voltage.') else: self._update_log(f'Set EGun Bias voltage: {value:.2f}V.') From a60318704435627eec76632bc2c4fd367cb58834 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 11 Nov 2023 21:28:51 -0300 Subject: [PATCH 077/309] DEV.RF.MNT: update SI RF according to new amplifier tower PV names --- siriuspy/siriuspy/devices/rf.py | 78 +++++++++++++-------------------- 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/siriuspy/siriuspy/devices/rf.py b/siriuspy/siriuspy/devices/rf.py index 6fed30d10..a293db0b9 100644 --- a/siriuspy/siriuspy/devices/rf.py +++ b/siriuspy/siriuspy/devices/rf.py @@ -1264,12 +1264,12 @@ class SILLRFPreAmp(_Device): class DEVICES: """Devices names.""" - SIA01 = 'RA-RaSIA01:RF-LLRFPreAmp-1' - ALL = (SIA01, ) + SSA1 = 'RA-ToSIA03:RF-CtrlPanel' + SSA2 = 'RA-ToSIA04:RF-CtrlPanel' + ALL = (SSA1, SSA2) PROPERTIES_DEFAULT = ( - 'PINSw1Enbl-Cmd', 'PINSw1Dsbl-Cmd', 'PINSw1-Mon', - 'PINSw2Enbl-Cmd', 'PINSw2Dsbl-Cmd', 'PINSw2-Mon', + 'PINSwEnbl-Cmd', 'PINSwDsbl-Cmd', 'PINSwSts-Mon', ) def __init__(self, devname='', props2init='all'): @@ -1279,40 +1279,22 @@ def __init__(self, devname='', props2init='all'): raise NotImplementedError(devname) super().__init__(devname, props2init=props2init) - def cmd_enable_pinsw_1(self, timeout=None, wait_mon=True): + def cmd_enable_pinsw(self, timeout=None, wait_mon=True): """Enable PINSw 1.""" - self['PINSw1Enbl-Cmd'] = 1 - _time.sleep(1) - self['PINSw1Enbl-Cmd'] = 0 - if wait_mon: - return self._wait('PINSw1-Mon', 1, timeout=timeout) - return True - - def cmd_enable_pinsw_2(self, timeout=None, wait_mon=True): - """Enable PINSw 2.""" - self['PINSw2Enbl-Cmd'] = 1 + self['PINSwEnbl-Cmd'] = 1 _time.sleep(1) - self['PINSw2Enbl-Cmd'] = 0 + self['PINSwEnbl-Cmd'] = 0 if wait_mon: - return self._wait('PINSw2-Mon', 1, timeout=timeout) + return self._wait('PINSwSts-Mon', 1, timeout=timeout) return True - def cmd_disable_pinsw_1(self, timeout=None, wait_mon=True): + def cmd_disable_pinsw(self, timeout=None, wait_mon=True): """Disable PINSw 1.""" - self['PINSw1Dsbl-Cmd'] = 1 - _time.sleep(1) - self['PINSw1Dsbl-Cmd'] = 0 - if wait_mon: - return self._wait('PINSw1-Mon', 0, timeout=timeout) - return True - - def cmd_disable_pinsw_2(self, timeout=None, wait_mon=True): - """Disable PINSw 2.""" - self['PINSw2Dsbl-Cmd'] = 1 + self['PINSwDsbl-Cmd'] = 1 _time.sleep(1) - self['PINSw2Dsbl-Cmd'] = 0 + self['PINSwDsbl-Cmd'] = 0 if wait_mon: - return self._wait('PINSw2-Mon', 0, timeout=timeout) + return self._wait('PINSwSts-Mon', 0, timeout=timeout) return True @@ -1361,12 +1343,12 @@ class SIRFDCAmp(_Device): class DEVICES: """Devices names.""" - SSA1 = 'RA-ToSIA01:RF-TDKSource' - SSA2 = 'RA-ToSIA02:RF-TDKSource' + SSA1 = 'RA-ToSIA03:RF-TDKSource' + SSA2 = 'RA-ToSIA04:RF-TDKSource' ALL = (SSA1, SSA2) PROPERTIES_DEFAULT = ( - 'PwrDCEnbl-Sel', 'PwrDCDsbl-Sel', 'PwrDC-Sts', + 'PwrDCEnbl-Cmd', 'PwrDCDsbl-Cmd', 'PwrDC-Mon', ) def __init__(self, devname, props2init='all'): @@ -1376,20 +1358,20 @@ def __init__(self, devname, props2init='all'): def cmd_enable(self, timeout=None, wait_mon=True): """Enable.""" - self['PwrDCEnbl-Sel'] = 1 + self['PwrDCEnbl-Cmd'] = 1 _time.sleep(1) - self['PwrDCEnbl-Sel'] = 0 + self['PwrDCEnbl-Cmd'] = 0 if wait_mon: - return self._wait('PwrDC-Sts', 1, timeout=timeout) + return self._wait('PwrDC-Mon', 1, timeout=timeout) return True def cmd_disable(self, timeout=None, wait_mon=True): """Disable.""" - self['PwrDCDsbl-Sel'] = 1 + self['PwrDCDsbl-Cmd'] = 1 _time.sleep(1) - self['PwrDCDsbl-Sel'] = 0 + self['PwrDCDsbl-Cmd'] = 0 if wait_mon: - return self._wait('PwrDC-Sts', 0, timeout=timeout) + return self._wait('PwrDC-Mon', 0, timeout=timeout) return True @@ -1438,12 +1420,12 @@ class SIRFACAmp(_Device): class DEVICES: """Devices names.""" - SSA1 = 'RA-ToSIA01:RF-ACPanel' - SSA2 = 'RA-ToSIA02:RF-ACPanel' + SSA1 = 'RA-ToSIA03:RF-ACPanel' + SSA2 = 'RA-ToSIA04:RF-ACPanel' ALL = (SSA1, SSA2) PROPERTIES_DEFAULT = ( - 'PwrACEnbl-Sel', 'PwrACDsbl-Sel', 'PwrAC-Sts', + 'PwrACEnbl-Cmd', 'PwrACDsbl-Cmd', 'PwrAC-Mon', ) def __init__(self, devname, props2init='all'): @@ -1453,20 +1435,20 @@ def __init__(self, devname, props2init='all'): def cmd_enable(self, timeout=None, wait_mon=True): """Enable.""" - self['PwrACEnbl-Sel'] = 1 + self['PwrACEnbl-Cmd'] = 1 _time.sleep(1) - self['PwrACEnbl-Sel'] = 0 + self['PwrACEnbl-Cmd'] = 0 if wait_mon: - return self._wait('PwrAC-Sts', 1, timeout=timeout) + return self._wait('PwrAC-Mon', 1, timeout=timeout) return True def cmd_disable(self, timeout=None, wait_mon=True): """Disable.""" - self['PwrACDsbl-Sel'] = 1 + self['PwrACDsbl-Cmd'] = 1 _time.sleep(1) - self['PwrACDsbl-Sel'] = 0 + self['PwrACDsbl-Cmd'] = 0 if wait_mon: - return self._wait('PwrAC-Sts', 0, timeout=timeout) + return self._wait('PwrAC-Mon', 0, timeout=timeout) return True From 1f01f7261b174d11702d396b66844dc309199bbe Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 12 Nov 2023 05:36:26 -0300 Subject: [PATCH 078/309] injctrl.FIX: fix bug left in Egun Bias check tolerance --- siriuspy/siriuspy/injctrl/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index 6acec9e67..38d1783a4 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -513,7 +513,7 @@ def _set_egunbias(self, value): self.run_callbacks('BiasVoltCmdSts-Mon', _Const.IdleRunning.Running) self._update_log(f'Setting EGun Bias voltage to {value:.2f}V...') - if not self.egun_dev.bias.set_voltage(value, tol=0.007*value): + if not self.egun_dev.bias.set_voltage(value, tol=abs(0.005*value)): self._update_log('ERR:Could not set EGun Bias voltage.') else: self._update_log(f'Set EGun Bias voltage: {value:.2f}V.') From 3cce8b95b5532f1e6c9f3737c75c5ad47c539ecc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 13 Nov 2023 09:17:48 -0300 Subject: [PATCH 079/309] DEV.RF: fix bug left in SILLRFPreAmp.__init__ --- siriuspy/siriuspy/devices/rf.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/rf.py b/siriuspy/siriuspy/devices/rf.py index a293db0b9..75c9963d9 100644 --- a/siriuspy/siriuspy/devices/rf.py +++ b/siriuspy/siriuspy/devices/rf.py @@ -1272,9 +1272,7 @@ class DEVICES: 'PINSwEnbl-Cmd', 'PINSwDsbl-Cmd', 'PINSwSts-Mon', ) - def __init__(self, devname='', props2init='all'): - if not devname: - devname = SILLRFPreAmp.DEVICES.SIA01 + def __init__(self, devname, props2init='all'): if devname not in SILLRFPreAmp.DEVICES.ALL: raise NotImplementedError(devname) super().__init__(devname, props2init=props2init) From 5d2207416a216806085a9a6f8a546ccce99b5002 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 13 Nov 2023 09:44:12 -0300 Subject: [PATCH 080/309] Fix ID-related classes --- siriuspy/siriuspy/idff/config.py | 84 ++++++++++++++++++++++----- siriuspy/siriuspy/search/id_search.py | 8 +-- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/siriuspy/siriuspy/idff/config.py b/siriuspy/siriuspy/idff/config.py index 9b1fc6d4c..2a9662bc7 100644 --- a/siriuspy/siriuspy/idff/config.py +++ b/siriuspy/siriuspy/idff/config.py @@ -26,6 +26,13 @@ def idname(self): """Return idname corresponding to IDFFConfig.""" return self._idname + @idname.setter + def idname(self, value): + """Set idname.""" + if value not in _IDSearch.get_idnames(): + raise ValueError(f'{value} is not a valid idname!') + self._idname = value + @property def pparameter_pvname(self): """Return ID pparameter pvname.""" @@ -178,19 +185,69 @@ def get_polarization_state(self, pparameter, kparameter): return pol_str def check_valid_value(self, value): - """.""" - if not super().check_valid_value(value): - return False - for pol, table in value['polarizations'].items(): - if pol == _IDSearch.POL_NONE_STR: - nrpts = len(table['pparameter']) - else: - nrpts = len(table['kparameter']) - for key, value_ in table.items(): - if key in ('kparameter', 'pparameter'): - continue - if len(value_) != nrpts: - return False + """Check consistency of SI_IDFF configuration.""" + configs = value['polarizations'] + pvnames = { + key: value for key, value in value['pvnames'].items() + if key not in ('pparameter', 'kparameter')} + corrlabels = set(pvnames.keys()) + + # check pvnames in configs + pvsconfig = set(pvnames.values()) + getch = _IDSearch.conv_idname_2_idff_chnames + getcv = _IDSearch.conv_idname_2_idff_cvnames + getqs = _IDSearch.conv_idname_2_idff_qsnames + chnames = [corr + ':Current-SP' for corr in getch(self.idname)] + cvnames = [corr + ':Current-SP' for corr in getcv(self.idname)] + qsnames = [corr + ':Current-SP' for corr in getqs(self.idname)] + pvsidsearch = set(chnames + cvnames + qsnames) + symm_diff = pvsconfig ^ pvsidsearch + + if symm_diff: + raise ValueError('List of pvnames in config is not consistent') + + # check polarizations in configs + pconfig = set(configs.keys()) - set((_IDSearch.POL_NONE_STR, )) + pidsearch = set(_IDSearch.conv_idname_2_polarizations(self.idname)) + symm_diff = pconfig ^ pidsearch + + if symm_diff: + raise ValueError( + 'List of polarizations in config is not consistent') + + # check polarization tables consistency + for polarization, table in configs.items(): + corrtable = { + key: value for key, value in table.items() + if key not in ('pparameter', 'kparameter')} + + # check 'pparameter' + if 'pparameter' not in table: + raise ValueError( + 'Missing pparameter in polarization configuration.') + + # check 'kparameter' + if 'kparameter' not in table: + raise ValueError( + 'Missing kparameter in polarization configuration.') + + # check corr label list + corrlabels_config = set(corrtable.keys()) + symm_diff = corrlabels ^ corrlabels_config + if symm_diff: + raise ValueError( + 'List of corrlabels in config is not consistent') + + # check nrpts in tables + param = 'pparameter' if polarization == 'none' else 'kparameter' + nrpts_corrtables = {len(table) for table in corrtable.values()} + nrpts_kparameter = set([len(table[param]), ]) + symm_diff = nrpts_corrtables ^ nrpts_kparameter + + if symm_diff: + raise ValueError( + 'Corrector tables and kparameter list in config ' + 'are not consistent') return True def _get_corr_pvnames(self, cname1, cname2): @@ -232,6 +289,7 @@ def _find_idname(self): continue kparam = idname + ':' + kparam_propty pparam = idname + ':' + pparam_propty + if kparam == kparameter and pparam == pparameter: self._idname = idname break diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index 693e1384c..918448697 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -105,8 +105,8 @@ class IDSearch: 'polarizations': tuple( item[0] for item in _idname2pol_sts['SI-10SB:ID-DELTA52'].values()), - 'pparameter': 'SI-10SB:ID-DELTA52:PolShift-Mon', - 'kparameter': 'SI-10SB:ID-DELTA52:GainShift-Mon', + 'pparameter': 'SI-10SB:ID-DELTA52:PParam-Mon', + 'kparameter': 'SI-10SB:ID-DELTA52:KParam-Mon', 'ch1': 'SI-10SB:PS-CH-1:Current-SP', # upstream 'ch2': 'SI-10SB:PS-CH-2:Current-SP', # downstream 'cv1': 'SI-10SB:PS-CV-1:Current-SP', @@ -136,7 +136,7 @@ class IDSearch: @staticmethod def get_idnames(filters=None): """Return a sorted and filtered list of all ID names.""" - idnames_list = list(IDSearch._idname2beamline.keys()) + idnames_list = list(IDSearch._idname_2_idff.keys()) idnames = _Filter.process_filters(idnames_list, filters=filters) return sorted(idnames) @@ -229,7 +229,7 @@ def conv_idname_2_idff_qsnames(idname): def conv_idname_2_polarizations(idname): """Return ID polarizations (sel).""" pols = IDSearch._idname2pol_sel[idname] - return tuple(pol[0] for pol in pols) + return tuple(pol[0] for pol in pols.values()) @staticmethod def conv_idname_2_polarizations_sts(idname): From 609d6f0c1a0099aea1107233b85b3d126b714563 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 13 Nov 2023 10:24:36 -0300 Subject: [PATCH 081/309] Add PVs to device DELTA --- siriuspy/siriuspy/devices/idff.py | 1 + siriuspy/siriuspy/devices/ids.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 5b06e5edd..72fb8d72b 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -15,6 +15,7 @@ class IDFF(_DeviceSet): class DEVICES(_WIG.DEVICES, _PAPU.DEVICES, _EPU.DEVICES, _DELTA.DEVICES): """.""" + ALL = \ _WIG.DEVICES.ALL + _PAPU.DEVICES.ALL + \ _EPU.DEVICES.ALL + _DELTA.DEVICES.ALL diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index d62c51a8e..81f632aa1 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -887,10 +887,12 @@ class DEVICES: 'MaxVelo-SP', 'MaxVelo-RB', 'ParkedPparameter-Cte', 'PParam-SP', 'PParam-RB', 'PParam-Mon', + 'ChangePParam-Cmd', 'PParamVelo-SP', 'PParamVelo-RB', 'PParamAcc-SP', 'PParamAcc-RB', 'ParkedKparameter-Cte', 'KParam-SP', 'KParam-RB', 'KParam-Mon', + 'ChangeKParam-Cmd', 'KParamVelo-SP', 'KParamVelo-RB', 'KParamAcc-SP', 'KParamAcc-RB', ) @@ -1041,11 +1043,11 @@ def cmd_move_start(self, timeout=None): def cmd_move_pparam_start(self, timeout=None): """Command to start Pparameter movement.""" - return self._move_start('ChangePparam-Cmd', timeout=timeout) + return self._move_start('ChangePParam-Cmd', timeout=timeout) def cmd_move_kparam_start(self, timeout=None): """Command to start Kparameter movement.""" - return self._move_start('ChangeKparam-Cmd', timeout=timeout) + return self._move_start('ChangeKParam-Cmd', timeout=timeout) def cmd_change_polarization_start(self, timeout=None): """Change polarization.""" From 97992017698b3efa9701f9a5c171e898549f2c24 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 13 Nov 2023 12:45:24 -0300 Subject: [PATCH 082/309] DEV.FIX: fix bug in Device.properties --- siriuspy/siriuspy/devices/device.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 8823a16d3..942bd47a7 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -78,19 +78,20 @@ def devname(self): @property def properties_in_use(self): """Return properties that were already added to the PV list.""" - return sorted(self._pvs.keys()) + return tuple(sorted(self._pvs.keys())) @property def properties_added(self): """Return properties that were added to the PV list that are not in PROPERTIES_DEFAULT.""" - return sorted( - set(self.properties_in_use) - set(self.PROPERTIES_DEFAULT)) + return tuple(sorted( + set(self.properties_in_use) - set(self.PROPERTIES_DEFAULT))) @property def properties_all(self): """Return all properties of the device, connected or not.""" - return sorted(set(self.PROPERTIES_DEFAULT + self.properties_in_use)) + return tuple(sorted( + set(self.PROPERTIES_DEFAULT + self.properties_in_use))) @property def simulators(self): From dcd0221a55edb6567d31177ad112ca82c47eb30a Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 13 Nov 2023 13:35:06 -0300 Subject: [PATCH 083/309] DEV.BPMSEQ.BUG: fix problems found during tests with beam. --- siriuspy/siriuspy/devices/bpm_eq.py | 106 +++++++++++++++++----------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index dd4634d68..c65bc5852 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -38,7 +38,19 @@ def __init__(self, devname=None, bpmnames=None, logger=None): self._acq_timeout = 30 super().__init__( devname=devname, bpmnames=bpmnames, ispost_mortem=False, - props2init=[], mturn_signals2acq='ABCD') + mturn_signals2acq='ABCD', props2init=[ + 'SwDirGainA-RB', 'SwDirGainB-RB', 'SwDirGainC-RB', + 'SwDirGainD-RB', 'SwInvGainA-RB', 'SwInvGainB-RB', + 'SwInvGainC-RB', 'SwInvGainD-RB', 'SwDirGainA-SP', + 'SwInvGainA-SP', 'SwDirGainB-SP', 'SwInvGainB-SP', + 'SwDirGainC-SP', 'SwInvGainC-SP', 'SwDirGainD-SP', + 'SwInvGainD-SP', 'ACQTriggerEvent-Sel', 'ACQStatus-Sts', + 'GEN_AArrayData', 'GEN_BArrayData', 'GEN_CArrayData', + 'GEN_DArrayData', 'ACQTriggerRep-Sel', 'ACQChannel-Sel', + 'ACQTrigger-Sel', 'ACQSamplesPre-SP', 'ACQSamplesPost-SP', + 'INFOHarmonicNumber-RB', 'INFOTbTRate-RB', 'SwDivClk-RB', + 'ACQChannel-Sts', 'INFOFOFBRate-RB', 'PosKx-RB', 'PosKy-RB', + 'PosXOffset-RB', 'PosYOffset-RB']) self.currinfo = _CurrInfoSI(props2init=['Current-Mon', ]) self.trigger = Trigger( 'SI-Fam:TI-BPM', props2init=['Src-Sel', 'Src-Sts']) @@ -171,7 +183,7 @@ def get_current_gains(self): gaind = [getattr(bpm, f'gain_direct_{a}') for a in 'abcd'] gaini = [getattr(bpm, f'gain_inverse_{a}') for a in 'abcd'] gains.append([gaind, gaini]) - gains = _np.array(gains).swapaxes(-1, -2) + gains = _np.array(gains).swapaxes(0, 1).swapaxes(0, -1) return gains def set_gains(self, gains): @@ -188,16 +200,16 @@ def set_gains(self, gains): """ nbpm = len(self.bpms) - shape = (nbpm, 4, 2) + shape = (4, nbpm, 2) if not isinstance(gains, _np.ndarray): gains = _np.full(shape, gains) if gains.shape != shape: raise ValueError(f'Wrong shape for gains. Must be {shape}') - for i, bpm in enumerate(self.bpms): - gns = gains[i] - for j, ant in enumerate('abcd'): - g = gns[j] + for j, ant in enumerate('abcd'): + gns = gains[j] + for i, bpm in enumerate(self.bpms): + g = gns[i] setattr(bpm, f'gain_direct_{ant}', g[0]) setattr(bpm, f'gain_inverse_{ant}', g[1]) @@ -216,7 +228,7 @@ def acquire_bpm_data(self): self.data['gains_init'] = self.get_current_gains() init_source = self.trigger.source - self.trigger.source = self.trigger.source_options.index('Clock3') + ini_dly = self.trigger.delay_raw try: self._do_acquire() except Exception as err: @@ -224,6 +236,7 @@ def acquire_bpm_data(self): self._log(f'ERR:{str(err)}') self.trigger.source = init_source + self.trigger.delay_raw = ini_dly self.set_gains(self.data['gains_init']) self._log('Acquisition Finished!') @@ -231,7 +244,7 @@ def _do_acquire(self): if self._acq_strategy == self.AcqStrategies.AssumeOrder: self.set_gains(self.MAX_MULTIPLIER) else: - gains = _np.full((len(self.bpms), 4, 2), self.MAX_MULTIPLIER) + gains = _np.full((4, len(self.bpms), 2), self.MAX_MULTIPLIER) gains[:, :, 1] *= self._acq_inverse_reduced_gain self.set_gains(gains) self.data['acq_strategy'] = self._acq_strategy @@ -241,7 +254,9 @@ def _do_acquire(self): self._log('Preparing BPMs') ret = self.cmd_mturn_acq_abort() if ret > 0: - self._log(f'ERR: BPM {ret-1} did not abort previous acquistion.') + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not abort ' + 'previous acquistion.') return self.mturn_reset_flags_and_update_initial_timestamps() @@ -249,13 +264,18 @@ def _do_acquire(self): nr_points_after=self._acq_nrpoints, nr_points_before=0, acq_rate='FOFB', repeat=False, external=True) if ret > 0: - self._log(f'ERR: BPM {ret-1} did not start acquistion.') + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not start acquistion.') return + self.trigger.delay_raw = 0 + self.trigger.source = self.trigger.source_options.index('Clock3') + self._log('Waiting BPMs to update') ret = self.mturn_wait_update(timeout=self._acq_timeout) if ret > 0: - self._log(f'ERR: BPM {ret-1} did not update in time.') + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not update in time.') return elif ret < 0: self._log(f'ERR: Problem with acquisition. Error code {ret}') @@ -289,7 +309,7 @@ def _do_acquire(self): _time.sleep(0.1) self.data['antennas'] = _np.array( - self.get_mturn_signals()).swapaxes(1, 0) + self.get_mturn_signals()).swapaxes(-1, -2) # --------- Methods for processing ------------ @@ -337,20 +357,20 @@ def calc_switching_levels( elif ants.shape[-1] != trunc: ants = ants[:, :, :trunc] self._log(f'WARN:Truncating data at {trunc} points') - ants = ants.reshape(nbpm, nant, -1, lsemicyc*2) + ants = ants.reshape(nant, nbpm, -1, lsemicyc*2) ants = ants.mean(axis=2) self._log('Calculating switching levels.') self._log( f'AcqStrategy is {self.AcqStrategies._fields[acq_strategy]}.') if acq_strategy == self.AcqStrategies.AssumeOrder: - ants = ants.reshape(nbpm, nant, 2, lsemicyc) + ants = ants.reshape(nant, nbpm, 2, lsemicyc) mean = ants.mean(axis=-1) idp = _np.tile(_np.arange(lsemicyc), (nbpm, 1)) idn = idp + lsemicyc else: # Try to find out the two states by looking at different levels in # the sum of the four antennas of each BPM. - dts = ants.sum(axis=1) + dts = ants.sum(axis=0) idcs = dts - dts.mean(axis=-1)[..., None] > 0 idp = idcs.nonzero() # direct idn = (~idcs).nonzero() # inverse @@ -360,11 +380,11 @@ def calc_switching_levels( self._log( 'ERR: Could not identify switching states appropriately.') return - mean = _np.zeros((nbpm, nant, 2)) - dtp = ants[idp[0], :, idp[1]].reshape(nbpm, lsemicyc, nant) - dtn = ants[idn[0], :, idn[1]].reshape(nbpm, lsemicyc, nant) - mean[:, :, 0] = dtp.mean(axis=1) - mean[:, :, 1] = dtn.mean(axis=1) + mean = _np.zeros((nant, nbpm, 2)) + dtp = ants[:, idp[0], idp[1]].reshape(nant, nbpm, lsemicyc) + dtn = ants[:, idn[0], idn[1]].reshape(nant, nbpm, lsemicyc) + mean[:, :, 0] = dtp.mean(axis=-1) + mean[:, :, 1] = dtn.mean(axis=-1) # Re-scale the inverse state data to match the direct state: scl = self.MAX_MULTIPLIER / acq_inverse_reduced_gain mean[:, :, 1] *= scl @@ -394,12 +414,12 @@ def calc_gains(self, mean): min_ant = min_ant[:, :, None] elif self._proc_method == self.ProcMethods.AABS: # equalize the 4 antennas for both semicycles - min_ant = mean.min(axis=-1).min(axis=-1) - min_ant = min_ant[:, None, None] + min_ant = mean.min(axis=0).min(axis=-1) + min_ant = min_ant[None, :, None] elif self._proc_method == self.ProcMethods.AAES: # equalize the 4 antennas for each semicycle - min_ant = mean.min(axis=1) - min_ant = min_ant[:, None, :] + min_ant = mean.min(axis=0) + min_ant = min_ant[None, :, :] min_ant *= maxm gains = self.round_gains(min_ant / mean) self.data['proc_method'] = self._proc_method @@ -408,6 +428,7 @@ def calc_gains(self, mean): def estimate_orbit_variation(self): """Estimate orbit variation between old and new gains.""" + self._log('Estimating Orbit Variation.') mean = self.data.get('antennas_mean') gains_init = self.data.get('gains_init') gains_new = self.data.get('gains_new') @@ -467,10 +488,10 @@ def plot_gains(self): 4, 2, figsize=(9, 8), sharex=True, sharey=True) ants = 'ABCD' for i in range(4): - ldo = axs[i, 0].plot(gini[:, i, 0])[0] - lio = axs[i, 1].plot(gini[:, i, 1], color=ldo.get_color())[0] - ldn = axs[i, 0].plot(gnew[:, i, 0])[0] - lin = axs[i, 1].plot(gnew[:, i, 1], color=ldn.get_color())[0] + ldo = axs[i, 0].plot(gini[i, :, 0])[0] + lio = axs[i, 1].plot(gini[i, :, 1], color=ldo.get_color())[0] + ldn = axs[i, 0].plot(gnew[i, :, 0])[0] + lin = axs[i, 1].plot(gnew[i, :, 1], color=ldn.get_color())[0] if not i: ldo.set_label('Old') ldn.set_label('New') @@ -510,6 +531,8 @@ def plot_antennas_mean(self): """.""" posx_gain = self.data.get('posx_gain') posy_gain = self.data.get('posx_gain') + posx_offs = self.data.get('posx_offset') + posy_offs = self.data.get('posx_offset') gacq = self.data.get('gains_acq') gini = self.data.get('gains_init') gnew = self.data.get('gains_new') @@ -534,13 +557,14 @@ def plot_antennas_mean(self): val = antm * gain for i in range(4): ax = axs[i, j] - ld = ax.plot(val[:, i, 0], 'o-')[0] - li = ax.plot(val[:, i, 1], 'o-')[0] + ld = ax.plot(val[i, :, 0], 'o-')[0] + li = ax.plot(val[i, :, 1], 'o-')[0] if not i and not j: ld.set_label('Direct') li.set_label('Inverse') - posx, posy = self._estimate_orbit(antm, gain, posx_gain, posy_gain) - sum_ = val.sum(axis=1) + posx, posy = self._estimate_orbit( + antm, gain, posx_gain, posy_gain, posx_offs, posy_offs) + sum_ = val.sum(axis=0) axs[4, j].plot(posx[:, 0], 'o-') axs[4, j].plot(posx[:, 1], 'o-') axs[5, j].plot(posy[:, 0], 'o-') @@ -565,20 +589,20 @@ def _estimate_orbit( self, mean, gains, posx_gain, posy_gain, posx_offset, posy_offset): ant = mean * gains # Get pairs of antennas - ac = ant[:, ::2] - bd = ant[:, 1::2] + ac = ant[::2] + bd = ant[1::2] # Calculate difference over sum for each pair - dovs_ac = _np.diff(ac, axis=1).squeeze() / ac.sum(axis=1) - dovs_bd = _np.diff(bd, axis=1).squeeze() / bd.sum(axis=1) + dovs_ac = _np.diff(ac, axis=0).squeeze() / ac.sum(axis=0) + dovs_bd = _np.diff(bd, axis=0).squeeze() / bd.sum(axis=0) # Get the positions: posx = (dovs_ac - dovs_bd) posy = (dovs_ac + dovs_bd) # Apply Position gains and factor of two missing in previous step - posx *= posx_gain[:, None] / 2 / 1e3 - posy *= posy_gain[:, None] / 2 / 1e3 + posx *= posx_gain[:, None] / 2 + posy *= posy_gain[:, None] / 2 # Subtract offsets: - posx -= posx_offset - posy -= posy_offset + posx -= posx_offset[:, None] + posy -= posy_offset[:, None] return posx, posy def _log(self, message, *args, level='INFO', **kwrgs): From 2d2d3c9b8d0f4feb99eed5afd78dbba087db8a37 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 13 Nov 2023 14:38:21 -0300 Subject: [PATCH 084/309] Fix PV names in device DELTA --- siriuspy/siriuspy/devices/ids.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 81f632aa1..6fc2a6230 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -885,12 +885,12 @@ class DEVICES: 'Pol-Sel', 'Pol-Sts', 'Pol-Mon', 'ChangePol-Cmd', 'MaxVelo-SP', 'MaxVelo-RB', - 'ParkedPparameter-Cte', + 'ParkedPParam-Cte', 'PParam-SP', 'PParam-RB', 'PParam-Mon', 'ChangePParam-Cmd', 'PParamVelo-SP', 'PParamVelo-RB', 'PParamAcc-SP', 'PParamAcc-RB', - 'ParkedKparameter-Cte', + 'ParkedKParam-Cte', 'KParam-SP', 'KParam-RB', 'KParam-Mon', 'ChangeKParam-Cmd', 'KParamVelo-SP', 'KParamVelo-RB', @@ -931,7 +931,7 @@ def polarization_mon(self): @property def pparameter_parked(self): """Return ID parked pparameter value [mm].""" - return self['ParkedPparameter-Cte'] + return self['ParkedPParam-Cte'] @property def pparameter_speed_max(self): @@ -983,7 +983,7 @@ def set_pparameter_speed_max(self, pparam_speed_max, timeout=None): @property def kparameter_parked(self): """Return ID parked kparameter value [mm].""" - return self['ParkedKparameter-Cte'] + return self['ParkedKParam-Cte'] @property def kparameter_speed_max(self): From 1489f88640c9226da3647d71248a465be6e329a5 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 13 Nov 2023 16:40:07 -0300 Subject: [PATCH 085/309] DEV.BPMEQ.ENH: Add methods for checking equalization. --- siriuspy/siriuspy/devices/bpm_eq.py | 99 ++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index c65bc5852..9cebb7f84 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -32,7 +32,7 @@ def __init__(self, devname=None, bpmnames=None, logger=None): if logger is not None: self.logger = logger self._proc_method = self.ProcMethods.EABS - self._acq_strategy = self.AcqStrategies.AssumeOrder + self._acq_strategy = self.AcqStrategies.AcqInvRedGain self._acq_inverse_reduced_gain = self.round_gains(0.95) self._acq_nrpoints = 2000 self._acq_timeout = 30 @@ -311,6 +311,71 @@ def _do_acquire(self): self.data['antennas'] = _np.array( self.get_mturn_signals()).swapaxes(-1, -2) + def acquire_data_for_checking(self): + """.""" + self._log('Starting Acquisition.') + + init_source = self.trigger.source + ini_dly = self.trigger.delay_raw + try: + self._do_acquire_for_check() + except Exception as err: + self._log('ERR:Problem with acquisition:') + self._log(f'ERR:{str(err)}') + + self.trigger.source = init_source + self.trigger.delay_raw = ini_dly + self._log('Acquisition Finished!') + + def _do_acquire_for_check(self): + # acquire antennas data in FOFB rate + self._log('Preparing BPMs') + ret = self.cmd_mturn_acq_abort() + if ret > 0: + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not abort ' + 'previous acquistion.') + return + + fswtc = self.get_switching_frequency(1) + fsamp = self.get_sampling_frequency(1) + nrpts = int(fsamp / fswtc) + + self.mturn_reset_flags_and_update_initial_timestamps() + ret = self.mturn_config_acquisition( + nr_points_after=nrpts, nr_points_before=0, + acq_rate='FOFB', repeat=False, external=True) + if ret > 0: + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not start acquistion.') + return + + self.trigger.delay_raw = 0 + self.trigger.source = self.trigger.source_options.index('Clock3') + + self._log('Waiting BPMs to update') + ret = self.mturn_wait_update(timeout=self._acq_timeout) + if ret > 0: + self._log( + f'ERR: BPM {self.bpm_names[ret-1]} did not update in time.') + return + elif ret < 0: + self._log(f'ERR: Problem with acquisition. Error code {ret}') + return + self._log('BPMs updated.') + + self._log('Acquiring data.') + if None in {fsamp, fswtc}: + self._log('ERR: Not all BPMs are configured equally.') + return + elif fsamp % (2*fswtc): + self._log('ERR: Sampling freq is not multiple of switching freq.') + return + + _time.sleep(0.1) + self.data['antennas_for_check'] = _np.array( + self.get_mturn_signals()).swapaxes(-1, -2) + # --------- Methods for processing ------------ def process_data(self): @@ -365,8 +430,10 @@ def calc_switching_levels( if acq_strategy == self.AcqStrategies.AssumeOrder: ants = ants.reshape(nant, nbpm, 2, lsemicyc) mean = ants.mean(axis=-1) - idp = _np.tile(_np.arange(lsemicyc), (nbpm, 1)) - idn = idp + lsemicyc + # Inverse comes first!: + mean = mean[:, :, ::-1] + idn = _np.tile(_np.arange(lsemicyc), (nbpm, 1)) + idp = idn + lsemicyc else: # Try to find out the two states by looking at different levels in # the sum of the four antennas of each BPM. @@ -583,6 +650,32 @@ def plot_antennas_mean(self): fig.tight_layout() return fig, axs + def plot_antennas_for_check(self): + """.""" + antd = self.data.get('antennas_for_check') + if antd is None: + self._log('ERR:Must acquire data for check first.') + return None, None + + fig, axs = _mplt.subplots( + 4, 1, figsize=(6, 8), sharex=True, sharey=True) + ants = 'ABCD' + mean = antd.mean(axis=-1)[:, :, None] + antd = antd / mean - 1 + nbpm = antd.shape[1] + for j in range(nbpm): + cor = _mplt.cm.jet(j/(nbpm-1)) + for i in range(4): + axs[i].plot(antd[i, j], 'o-', color=cor) + if not j: + axs[i].set_ylabel(ants[i] + ' [%]') + axs[i].grid(True, alpha=0.5, ls='--', lw=1) + + axs[0].set_title('Relative Variation') + axs[-1].set_xlabel('Samples') + fig.tight_layout() + return fig, axs + # ------- auxiliary methods ---------- def _estimate_orbit( From 0c9f4236abef6256e80f5a59b6e41fdbb559eef5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 13 Nov 2023 20:02:23 -0300 Subject: [PATCH 086/309] ORBINTLK.FIX: fix bugs and improve device lock feature --- siriuspy/siriuspy/orbintlk/csdev.py | 4 - siriuspy/siriuspy/orbintlk/main.py | 255 +++++++++++++++++++--------- 2 files changed, 172 insertions(+), 87 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 81ff79bcf..32d924d6a 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -319,10 +319,6 @@ def get_database(self): 'Reset-Cmd': {'type': 'int', 'value': 0}, 'ResetTimingLockLatches-Cmd': {'type': 'int', 'value': 0}, 'ResetAFCTimingRTMClk-Cmd': {'type': 'int', 'value': 0}, - 'RetryLock-Cmd': {'type': 'int', 'value': 0}, - 'IsLocking-Mon': { - 'type': 'enum', 'value': self.OffOn.On, - 'enums': self.OffOn._fields}, # Acquisition 'PsMtmAcqChannel-Sel': { diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index eeae523fc..3a4280036 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -8,7 +8,7 @@ import numpy as _np from ..util import update_bit as _updt_bit, get_bit as _get_bit -from ..namesys import SiriusPVName as _SiriusPVName +from ..namesys import SiriusPVName as _PVName from ..search import LLTimeSearch as _LLTimeSearch, \ HLTimeSearch as _HLTimeSearch from ..thread import RepeaterThread as _Repeat @@ -64,7 +64,7 @@ def __init__(self, tests=True): self._thread_cbfout = {fout: None for fout in self._const.FOUTS_2_MON} self._thread_cbbpm = None self._ti_mon_devs = set() - self._lock_fails_cnt = dict() + self._lock_threads = dict() self._lock_suspend = False # devices and connections @@ -98,12 +98,6 @@ def __init__(self, tests=True): # rxlock callback pvo = self._evg_dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_evg_rxlock) - # lock callback - for propty_sp, desired_val in self._const.EVG_CONFIGS.items(): - propty_rb = propty_sp.replace('SP', 'RB').replace('Sel', 'Sts') - pvo = self._evg_dev.pv_object(propty_rb) - pvo.add_callback(_part( - self._callback_lock, self._evg_dev, propty_sp, desired_val)) # # Fouts self._fout_devs = { @@ -120,19 +114,11 @@ def __init__(self, tests=True): pvo = dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_fout_rxlock) pvo.connection_callbacks.append(self._conn_callback_timing) - pvo = dev.pv_object('RxEnbl-RB') - pvo.add_callback(self._callback_fout_lock) self._fout2rxenbl[devname] = 0 self._fout_dcct_dev = _Device( 'CA-RaTim:TI-Fout-2', props2init=['RxEnbl-SP', 'RxEnbl-RB']) - for propty_sp, desired_val in self._const.FOUT2_CONFIGS.items(): - propty_rb = propty_sp.replace('SP', 'RB').replace('Sel', 'Sts') - pvo = self._fout_dcct_dev.pv_object(propty_rb) - pvo.add_callback(_part( - self._callback_lock, self._fout_dcct_dev, - propty_sp, desired_val)) # # AFC timing self._afcti_devs = { @@ -203,20 +189,6 @@ def __init__(self, tests=True): 'Status-Mon', ], auto_monitor_mon=True) - trig2config = { - self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, - self._llrf_trig: self._const.LLRFTRIG_CONFIG, - self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, - self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, - self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, - } - for trig, configs in trig2config.items(): - for prop_sp, desired_val in configs.items(): - prop_rb = prop_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') - pvo = trig.pv_object(prop_rb) - pvo.add_callback( - _part(self._callback_lock, trig, prop_sp, desired_val)) - # # BPM devices self._orbintlk_dev = _OrbitIntlk() for dev in self._orbintlk_dev.devices: @@ -242,10 +214,6 @@ def __init__(self, tests=True): 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'IntlkSet-Cmd', ]) - pvo = self._llrf.pv_object('ILK:BEAM:TRIP') - pvo.add_callback(_part( - self._callback_lock, self._llrf, - 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) # # auxiliary devices self._fofb = _FOFB( @@ -280,7 +248,6 @@ def __init__(self, tests=True): 'IntlkStateConfig-Cmd': self.cmd_state_config, 'ResetTimingLockLatches-Cmd': self.cmd_reset_ti_lock_latch, 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, - 'RetryLock-Cmd': self.cmd_retry_lock, } # configuration scanning @@ -309,7 +276,6 @@ def init_database(self): 'PsMtmAcqSamplesPost-SP': self._acq_spost, 'PsMtmAcqSamplesPost-RB': self._acq_spost, 'PsMtmAcqConfig-Cmd': 0, - 'IsLocking-Mon': not self._lock_suspend, } for pvn, val in pvn2vals.items(): self.run_callbacks(pvn, val) @@ -350,6 +316,71 @@ def init_database(self): self._update_log('Started.') self._init = True + self._init_devices_lock() + + def _init_devices_lock(self): + # EVG + for propty_sp, desired_val in self._const.EVG_CONFIGS.items(): + propty_rb = _PVName.from_sp2rb(propty_sp) + pvo = self._evg_dev.pv_object(propty_rb) + pvo.add_callback(_part( + self._callback_lock, self._evg_dev, propty_sp, desired_val)) + + # BPM Fouts + for devname, dev in self._fout_devs.items(): + pvo = dev.pv_object('RxEnbl-RB') + pvo.add_callback(self._callback_fout_lock) + + # DCCT Fout + for propty_sp, desired_val in self._const.FOUT2_CONFIGS.items(): + propty_rb = _PVName.from_sp2rb(propty_sp) + pvo = self._fout_dcct_dev.pv_object(propty_rb) + pvo.add_callback(_part( + self._callback_lock, self._fout_dcct_dev, + propty_sp, desired_val)) + + # triggers + trig2config = { + self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, + self._llrf_trig: self._const.LLRFTRIG_CONFIG, + self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, + self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, + self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, + } + for trig, configs in trig2config.items(): + for prop_sp, desired_val in configs.items(): + prop_rb = _PVName.from_sp2rb(prop_sp) + pvo = trig.pv_object(prop_rb) + pvo.add_callback( + _part(self._callback_lock, trig, prop_sp, desired_val)) + + # LLRF + pvo = self._llrf.pv_object('ILK:BEAM:TRIP') + pvo.add_callback(_part( + self._callback_lock, self._llrf, + 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) + + # BPM devices + prop2lock = [ + 'IntlkEn-Sts', + 'IntlkMinSumEn-Sts', + 'IntlkLmtMinSum-RB', + 'IntlkPosEn-Sts', + 'IntlkLmtPosMaxX-RB', + 'IntlkLmtPosMinX-RB', + 'IntlkLmtPosMaxY-RB', + 'IntlkLmtPosMinY-RB', + 'IntlkAngEn-Sts', + 'IntlkLmtAngMaxX-RB', + 'IntlkLmtAngMinX-RB', + 'IntlkLmtAngMaxY-RB', + 'IntlkLmtAngMinY-RB', + ] + for dev in self._orbintlk_dev.devices: + for prop in prop2lock: + pvo = dev.pv_object(prop) + pvo.add_callback(self._callback_bpm_lock) + @property def pvs_database(self): """Return pvs_database.""" @@ -633,12 +664,6 @@ def cmd_reset_afcti_rtmclk(self, value=None): return True - def cmd_retry_lock(self, value=None): - """Command to retry lock configurations.""" - self._lock_suspend = False - self.run_callbacks('IsLocking-Mon', not self._lock_suspend) - return True - # --- configure acquisition --- def set_acq_channel(self, value): @@ -761,7 +786,7 @@ def _get_ti_monitored_devices(self): def _check_devices_status(self, devices): for devname in devices: - devname = _SiriusPVName(devname) + devname = _PVName(devname) out = int(devname.propty[-1]) if devname.propty else None dev = self._evg_dev if 'EVG' in devname else \ @@ -948,7 +973,7 @@ def _check_configs(self): 'Configuration check took more than planned... ' '{0:.3f}/{1:.3f} s'.format(ttook, tplanned)) - # --- callbacks --- + # --- interlock methods --- def _callback_evg_intlk(self, value, **kws): _ = kws @@ -982,7 +1007,7 @@ def _callback_fout_rxlock(self, pvname, value, **kws): return if not self._init: return - nam = _SiriusPVName(pvname).device_name + nam = _PVName(pvname).device_name if self._thread_cbfout[nam] and self._thread_cbfout[nam].is_alive(): return self._thread_cbfout[nam] = _CAThread( @@ -995,7 +1020,7 @@ def _callback_evg_rxlock(self, pvname, value, **kws): return if not self._init: return - pvname = _SiriusPVName(pvname) + pvname = _PVName(pvname) configs = self._const.EVG_CONFIGS bits = [int(c[0][-1]) for c in configs if 'RxEnbl' in c[0]] if all([_get_bit(value, b) for b in bits]): # all ok @@ -1008,10 +1033,10 @@ def _callback_evg_rxlock(self, pvname, value, **kws): self._thread_cbevgrx.start() def _do_callback_rxlock(self, pvname, value): - pvname = _SiriusPVName(pvname) + pvname = _PVName(pvname) devname = pvname.device_name if pvname.dev == 'EVG': - shouldkill = False + is_failure = False for bit in range(8): if _get_bit(value, bit): continue @@ -1019,20 +1044,20 @@ def _do_callback_rxlock(self, pvname, value): self._update_log(f'FATAL:{outnam} of {devname} lost lock') devout = devname.substitute(propty_name=outnam) # verify if this is an orbit interlock reliability failure - shouldkill |= devout in self._ti_mon_devs + is_failure |= devout in self._ti_mon_devs else: out = None for dev in self._ti_mon_devs: if 'Fout' not in dev: continue - dev = _SiriusPVName(dev) + dev = _PVName(dev) if dev.device_name == devname: out = int(dev.propty_name[-1]) break - shouldkill = out is not None and not _get_bit(value, out) - if shouldkill: + is_failure = out is not None and not _get_bit(value, out) + if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') - self._do_killbeam() + self._handle_reliability_failure() else: # reset rxlock latch dev = self._evg_dev if 'EVG' in devname \ @@ -1042,17 +1067,17 @@ def _do_callback_rxlock(self, pvname, value): def _conn_callback_timing(self, pvname, conn, **kws): if conn: return - pvname = _SiriusPVName(pvname) + pvname = _PVName(pvname) self._update_log(f'FATAL:{pvname.device_name} disconnected') if not self._state: return # verify if this is an orbit interlock reliability failure - shouldkill = False + is_failure = False for dev in self._ti_mon_devs: - shouldkill |= _SiriusPVName(dev).device_name == pvname.device_name - if shouldkill: + is_failure |= _PVName(dev).device_name == pvname.device_name + if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') - self._do_killbeam() + self._handle_reliability_failure() def _callback_bpm_intlk(self, pvname, value, **kws): _ = kws @@ -1064,7 +1089,7 @@ def _callback_bpm_intlk(self, pvname, value, **kws): return if self._thread_cbbpm and self._thread_cbbpm.is_alive(): return - bpmname = _SiriusPVName(pvname).device_name + bpmname = _PVName(pvname).device_name self._thread_cbbpm = _CAThread( target=self._do_callback_bpm_intlk, args=(bpmname, ), daemon=True) self._thread_cbbpm.start() @@ -1072,7 +1097,7 @@ def _callback_bpm_intlk(self, pvname, value, **kws): def _do_callback_bpm_intlk(self, bpmname): self._update_log(f'FATAL:{bpmname} raised orbit interlock.') # send kill beam as fast as possible - self._do_killbeam() + self._handle_reliability_failure() # wait minimum period for RF EVE event count to be updated _time.sleep(.1) # verify if RF EVE propagated the event PsMtm @@ -1089,48 +1114,112 @@ def _do_callback_bpm_intlk(self, bpmname): # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') - def _do_killbeam(self): - # if not in dry run, send kill beam - if not self._is_dry_run: - self._update_log('FATAL:sending soft interlock to LLRF.') - self._llrf['IntlkSet-Cmd'] = 1 - _time.sleep(1) - self._llrf['IntlkSet-Cmd'] = 0 + # --- reliability failure methods --- + + def _check_minsum_requirement(self): + monit_sum = self._sofb['SlowSumRaw-Mon'] + facq_sum = monit_sum * self._monitsum2intlksum_factor + return _np.all(facq_sum > self._limits['minsum']) + + def _handle_reliability_failure(self): + # if in dry run, do not kill RF + if self._is_dry_run: + return + # if minimum sum condition is not satisfied, do not kill RF + if not self._check_minsum_requirement(): + return + # send soft interlock to RF + self._update_log('FATAL:sending soft interlock to LLRF.') + self._llrf['IntlkSet-Cmd'] = 1 + _time.sleep(1) + self._llrf['IntlkSet-Cmd'] = 0 + + # --- device lock methods --- def _callback_lock( self, device, propty_sp, desired_value, pvname, value, **kwargs): thread = _CAThread( - target=self._do_callback_lock, + target=self._start_lock_thread, args=(device, propty_sp, desired_value, pvname, value), daemon=True) thread.start() def _callback_fout_lock(self, pvname, value, **kwargs): - devname = _SiriusPVName(pvname).device_name + devname = _PVName(pvname).device_name desired_value = self._fout2rxenbl[devname] device = self._fout_devs[devname] thread = _CAThread( - target=self._do_callback_lock, + target=self._start_lock_thread, args=(device, 'RxEnbl-SP', desired_value, pvname, value), daemon=True) thread.start() - def _do_callback_lock( + def _callback_bpm_lock(self, pvname, value, **kws): + pvname = _PVName(pvname) + devname = pvname.device_name + propty_rb = pvname.propty + propty_sp = _PVName.from_sp2rb(propty_rb) + devidx = self._orbintlk_dev.BPM_NAMES.index(devname) + device = self._orbintlk_dev.devices[devidx] + if propty_rb.endswith('En-Sts'): + entyp = 'pos' if 'Pos' in propty_rb else \ + 'ang' if 'Ang' in propty_rb else 'minsum' + desired_value = self._enable_lists[entyp][devidx] + elif 'Lmt' in propty_rb: + limcls = 'pos' if 'Pos' in propty_rb else \ + 'ang' if 'Ang' in propty_rb else 'minsum' + limpln = '_x_' if 'X' in propty_rb else '_y_' if 'Y' in propty_rb else '' + limtyp = 'min' if 'Min' in propty_rb \ + else 'max' if 'Max' in propty_rb else '' + limname = f'{limcls}{limpln}{limtyp}' + desired_value = self._limits[limname][devidx] + + device = self._fout_devs[devname] + thread = _CAThread( + target=self._start_lock_thread, + args=(device, propty_sp, desired_value, pvname, value), + daemon=True) + thread.start() + + def _start_lock_thread( self, device, propty_sp, desired_value, pvname, value): if self._lock_suspend: return - cnt = self._lock_fails_cnt.get(pvname, 0) - if value != desired_value: - self._lock_fails_cnt[pvname] = cnt + 1 - device[propty] = desired_value - else: - self._lock_fails_cnt[pvname] = 0 - if self._lock_fails_cnt[pvname] >= 10: + + # if there is already a lock thread, return + thread = self._lock_threads.get(pvname, None) + if thread is not None or thread.is_alive(): + return + + # else, create lock thread with 10 attempts to lock PV + interval = 1 / 50 # little sleep to avoid CPU load + thread = _Repeat( + interval, self._do_lock, + args=(device, propty_sp, desired_value, pvname, value), + deamon=True, niter=10, is_cathread=True) + self._lock_threads[pvname] = thread + thread.start() + + def _do_lock(self, device, propty_sp, desired_value, pvname, value): + thread = self._lock_threads[pvname] + + # if value is equal desired, stop thread + if value == desired_value: + thread.stop() + + # else, apply is value as desired + propty_rb = _PVName(pvname).propty + device[propty_sp] = desired_value + + # if readback reached desired value, stop thread + if device._wait(propty_rb, desired_value, timeout=0.11): + thread.stop() + + # if this was the last iteration, raise a reliability failure + if thread.cur_iter == thread.niters-1: self._update_log(f'FATAL:Fail to lock {pvname}') - self._update_log(f'FATAL:Orbit interlock reliability failure') - self._do_killbeam() - self._lock_suspend = True - self.run_callbacks('IsLocking-Mon', not self._lock_suspend) + self._update_log('FATAL:Orbit interlock reliability failure') + self._handle_reliability_failure() # --- auxiliary log methods --- @@ -1145,7 +1234,7 @@ def _update_log(self, msg): _log.info(msg) self.run_callbacks('Log-Mon', msg) - # ---------------- File handlers --------------------- + # --- file handlers --- def _load_file(self, intlk, dtype='en'): suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' From a3c1c457b987664dd8e5c9afea0f5ea381fcb5d9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 13 Nov 2023 20:03:26 -0300 Subject: [PATCH 087/309] ORBINTLK.ENH: change reliability failure handler to send kill RF only when minimum sum is satisfied --- siriuspy/siriuspy/orbintlk/main.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 3a4280036..f95bf7745 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -205,7 +205,14 @@ def __init__(self, tests=True): 'ACQTriggerRep-Sel', 'ACQTriggerRep-Sts', 'ACQTrigger-Sel', 'ACQTrigger-Sts', 'ACQTriggerEvent-Sel', 'ACQTriggerEvent-Sts', - 'ACQStatus-Sts']) + 'ACQStatus-Sts', + 'INFOFAcqRate-RB', 'INFOMONITRate-RB']) + self._monit_rate, self._facq_rate = None, None + self._monitsum2intlksum_factor = 1 + pvo = self._fambpm_dev.devices[0].pv_object('INFOMONITRate-RB') + pvo.add_callback(self._callback_get_bpm_rates) + pvo = self._fambpm_dev.devices[0].pv_object('INFOFAcqRate-RB') + pvo.add_callback(self._callback_get_bpm_rates) # # RF devices self._llrf = _ASLLRF( @@ -219,7 +226,8 @@ def __init__(self, tests=True): self._fofb = _FOFB( props2init=['LoopState-Sts', ]) self._sofb = _SOFB( - _SOFB.DEVICES.SI, props2init=['LoopState-Sts', ]) + _SOFB.DEVICES.SI, + props2init=['LoopState-Sts', 'SlowSumRaw-Mon']) # pvs to write methods self.map_pv2write = { @@ -1114,6 +1122,21 @@ def _do_callback_bpm_intlk(self, bpmname): # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') + def _callback_get_bpm_rates(self, pvname, value, **kws): + if value is None: + return + if 'MONIT' in pvname: + self._monit_rate = value + elif 'FAcq' in pvname: + self._facq_rate = value + monit = self._monit_rate + facq = self._facq_rate + if None in [monit, facq]: + return + frac = monit/facq + factor = 2**_np.ceil(_np.log2(frac)) / frac + self._monitsum2intlksum_factor = factor + # --- reliability failure methods --- def _check_minsum_requirement(self): From 7278d2890436447c419f7d3d212af68d99885624 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 12:44:29 -0300 Subject: [PATCH 088/309] ORBINLKT.FIX: fix bugs in devices lock feature --- siriuspy/siriuspy/orbintlk/main.py | 69 ++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f95bf7745..88e842c23 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -65,6 +65,7 @@ def __init__(self, tests=True): self._thread_cbbpm = None self._ti_mon_devs = set() self._lock_threads = dict() + self._lock_failures = set() self._lock_suspend = False # devices and connections @@ -208,7 +209,7 @@ def __init__(self, tests=True): 'ACQStatus-Sts', 'INFOFAcqRate-RB', 'INFOMONITRate-RB']) self._monit_rate, self._facq_rate = None, None - self._monitsum2intlksum_factor = 1 + self._monitsum2intlksum_factor = 0 pvo = self._fambpm_dev.devices[0].pv_object('INFOMONITRate-RB') pvo.add_callback(self._callback_get_bpm_rates) pvo = self._fambpm_dev.devices[0].pv_object('INFOFAcqRate-RB') @@ -228,6 +229,7 @@ def __init__(self, tests=True): self._sofb = _SOFB( _SOFB.DEVICES.SI, props2init=['LoopState-Sts', 'SlowSumRaw-Mon']) + self._sofb.pv_object('SlowSumRaw-Mon').auto_monitor = True # pvs to write methods self.map_pv2write = { @@ -327,20 +329,28 @@ def init_database(self): self._init_devices_lock() def _init_devices_lock(self): + self._update_log('Waiting 5s to start locking...') + _time.sleep(5) + + conntimeout = self._const.DEF_TIMEOUT + # EVG - for propty_sp, desired_val in self._const.EVG_CONFIGS.items(): + self._evg_dev.wait_for_connection(timeout=conntimeout) + for propty_sp, desired_val in self._const.EVG_CONFIGS: propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._evg_dev.pv_object(propty_rb) pvo.add_callback(_part( self._callback_lock, self._evg_dev, propty_sp, desired_val)) # BPM Fouts - for devname, dev in self._fout_devs.items(): + for dev in self._fout_devs.values(): + dev.wait_for_connection(timeout=conntimeout) pvo = dev.pv_object('RxEnbl-RB') pvo.add_callback(self._callback_fout_lock) # DCCT Fout - for propty_sp, desired_val in self._const.FOUT2_CONFIGS.items(): + self._fout_dcct_dev.wait_for_connection(timeout=conntimeout) + for propty_sp, desired_val in self._const.FOUT2_CONFIGS: propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._fout_dcct_dev.pv_object(propty_rb) pvo.add_callback(_part( @@ -356,13 +366,15 @@ def _init_devices_lock(self): self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, } for trig, configs in trig2config.items(): - for prop_sp, desired_val in configs.items(): + trig.wait_for_connection(timeout=conntimeout) + for prop_sp, desired_val in configs: prop_rb = _PVName.from_sp2rb(prop_sp) pvo = trig.pv_object(prop_rb) pvo.add_callback( _part(self._callback_lock, trig, prop_sp, desired_val)) # LLRF + self._llrf.wait_for_connection(timeout=conntimeout) pvo = self._llrf.pv_object('ILK:BEAM:TRIP') pvo.add_callback(_part( self._callback_lock, self._llrf, @@ -385,6 +397,7 @@ def _init_devices_lock(self): 'IntlkLmtAngMinY-RB', ] for dev in self._orbintlk_dev.devices: + dev.wait_for_connection(timeout=conntimeout) for prop in prop2lock: pvo = dev.pv_object(prop) pvo.add_callback(self._callback_bpm_lock) @@ -1139,17 +1152,40 @@ def _callback_get_bpm_rates(self, pvname, value, **kws): # --- reliability failure methods --- - def _check_minsum_requirement(self): - monit_sum = self._sofb['SlowSumRaw-Mon'] + def _check_minsum_requirement(self, monit_sum=None): + if monit_sum is None: + monit_sum = self._sofb['SlowSumRaw-Mon'] facq_sum = monit_sum * self._monitsum2intlksum_factor return _np.all(facq_sum > self._limits['minsum']) + def _callback_monitor_sum(self, value, cb_info, **kws): + # remove callback if is not anymore in a reliability failure + if not self._lock_failures: + cb_info[1].remove_callback(cb_info[0]) + + # check whether sum value is higher than minsum + if not self._check_minsum_requirement(value): + return + + # if sum is higher than minsum and there is lock failures, + # handle orbit interlock reliability failure + self._update_log('FATAL:Orbit interlock reliability failure') + for pvn in self._lock_failures: + self._update_log(f'FATAL:Fail to lock {pvn}') + self._handle_reliability_failure() + # and remove callback + cb_info[1].remove_callback(cb_info[0]) + def _handle_reliability_failure(self): # if in dry run, do not kill RF if self._is_dry_run: + self._update_log('WARN:Dry run running, will not handle') + self._update_log('WARN:reliability failure.') return - # if minimum sum condition is not satisfied, do not kill RF + # if minimum sum condition is not satisfied, only monitor sum if not self._check_minsum_requirement(): + pvo = self._sofb.pv_object('SlowSumRaw-Mon') + pvo.add_callback(self._callback_monitor_sum) return # send soft interlock to RF self._update_log('FATAL:sending soft interlock to LLRF.') @@ -1191,13 +1227,13 @@ def _callback_bpm_lock(self, pvname, value, **kws): elif 'Lmt' in propty_rb: limcls = 'pos' if 'Pos' in propty_rb else \ 'ang' if 'Ang' in propty_rb else 'minsum' - limpln = '_x_' if 'X' in propty_rb else '_y_' if 'Y' in propty_rb else '' - limtyp = 'min' if 'Min' in propty_rb \ - else 'max' if 'Max' in propty_rb else '' + limpln = '_x_' if 'X' in propty_rb else \ + '_y_' if 'Y' in propty_rb else '' + limtyp = '' if 'MinSum' in propty_rb \ + else 'max' if 'Max' in propty_rb else 'min' limname = f'{limcls}{limpln}{limtyp}' desired_value = self._limits[limname][devidx] - device = self._fout_devs[devname] thread = _CAThread( target=self._start_lock_thread, args=(device, propty_sp, desired_value, pvname, value), @@ -1211,7 +1247,7 @@ def _start_lock_thread( # if there is already a lock thread, return thread = self._lock_threads.get(pvname, None) - if thread is not None or thread.is_alive(): + if thread is not None and thread.is_alive(): return # else, create lock thread with 10 attempts to lock PV @@ -1219,7 +1255,7 @@ def _start_lock_thread( thread = _Repeat( interval, self._do_lock, args=(device, propty_sp, desired_value, pvname, value), - deamon=True, niter=10, is_cathread=True) + niter=10, is_cathread=True) self._lock_threads[pvname] = thread thread.start() @@ -1228,6 +1264,8 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): # if value is equal desired, stop thread if value == desired_value: + if pvname in self._lock_failures: + self._lock_failures.remove(pvname) thread.stop() # else, apply is value as desired @@ -1236,10 +1274,13 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): # if readback reached desired value, stop thread if device._wait(propty_rb, desired_value, timeout=0.11): + if pvname in self._lock_failures: + self._lock_failures.remove(pvname) thread.stop() # if this was the last iteration, raise a reliability failure if thread.cur_iter == thread.niters-1: + self._lock_failures.add(pvname) self._update_log(f'FATAL:Fail to lock {pvname}') self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() From be7e447c7d59ed5854ed4453090499bea5786306 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 19:44:19 -0300 Subject: [PATCH 089/309] ORBINLKT.FIX: fix more bugs in device lock feature --- siriuspy/siriuspy/orbintlk/main.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 88e842c23..56cfb1889 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -341,12 +341,14 @@ def _init_devices_lock(self): pvo = self._evg_dev.pv_object(propty_rb) pvo.add_callback(_part( self._callback_lock, self._evg_dev, propty_sp, desired_val)) + pvo.run_callbacks() # BPM Fouts for dev in self._fout_devs.values(): dev.wait_for_connection(timeout=conntimeout) pvo = dev.pv_object('RxEnbl-RB') pvo.add_callback(self._callback_fout_lock) + pvo.run_callbacks() # DCCT Fout self._fout_dcct_dev.wait_for_connection(timeout=conntimeout) @@ -356,6 +358,7 @@ def _init_devices_lock(self): pvo.add_callback(_part( self._callback_lock, self._fout_dcct_dev, propty_sp, desired_val)) + pvo.run_callbacks() # triggers trig2config = { @@ -372,6 +375,7 @@ def _init_devices_lock(self): pvo = trig.pv_object(prop_rb) pvo.add_callback( _part(self._callback_lock, trig, prop_sp, desired_val)) + pvo.run_callbacks() # LLRF self._llrf.wait_for_connection(timeout=conntimeout) @@ -379,6 +383,7 @@ def _init_devices_lock(self): pvo.add_callback(_part( self._callback_lock, self._llrf, 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) + pvo.run_callbacks() # BPM devices prop2lock = [ @@ -396,11 +401,12 @@ def _init_devices_lock(self): 'IntlkLmtAngMaxY-RB', 'IntlkLmtAngMinY-RB', ] + self._orbintlk_dev.wait_for_connection(timeout=conntimeout) for dev in self._orbintlk_dev.devices: - dev.wait_for_connection(timeout=conntimeout) for prop in prop2lock: pvo = dev.pv_object(prop) pvo.add_callback(self._callback_bpm_lock) + pvo.run_callbacks() @property def pvs_database(self): @@ -1217,7 +1223,7 @@ def _callback_bpm_lock(self, pvname, value, **kws): pvname = _PVName(pvname) devname = pvname.device_name propty_rb = pvname.propty - propty_sp = _PVName.from_sp2rb(propty_rb) + propty_sp = _PVName.from_rb2sp(propty_rb) devidx = self._orbintlk_dev.BPM_NAMES.index(devname) device = self._orbintlk_dev.devices[devidx] if propty_rb.endswith('En-Sts'): From 2e889e3f6717bbbeed14377010b35297ff99381c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 20:40:49 -0300 Subject: [PATCH 090/309] ORBINTLK.FIX: fix LLRF device lock --- siriuspy/siriuspy/orbintlk/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 56cfb1889..e37b2eb1f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1274,8 +1274,11 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): self._lock_failures.remove(pvname) thread.stop() - # else, apply is value as desired - propty_rb = _PVName(pvname).propty + # else, apply value as desired + if device == self._llrf: + propty_rb = propty_sp.replace(':S', '') + else: + propty_rb = _PVName(pvname).propty device[propty_sp] = desired_value # if readback reached desired value, stop thread From 775f5520829cbd6ba5c6ca0e6a76e3e6d47c3597 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 20:56:25 -0300 Subject: [PATCH 091/309] ORBINTLK.FIX: fix bug in Fouts lock --- siriuspy/siriuspy/orbintlk/main.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e37b2eb1f..d56756416 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -777,14 +777,15 @@ def _config_fout_rxenbl(self): for chn in self._ti_mon_devs: if 'Fout' not in chn: continue - devname = chn.device_name + fout = chn.device_name out = int(chn.propty_name[-1]) - rx = fout2rx.get(devname, 0) + rx = fout2rx.get(fout, 0) rx += 1 << out + fout2rx[fout] = rx - for fout, rxenbl in fout2rx.items(): + for fout, dev in self._fout_devs.items(): + rxenbl = fout2rx.get(fout, 0) self._fout2rxenbl[fout] = rxenbl - dev = self._fout_devs[fout] dev['RxEnbl-SP'] = rxenbl dev._wait('RxEnbl-RB', rxenbl) dev['RxLockedLtcRst-Cmd'] = 1 From f5935f8b28a51e17b54eb2822944d88b3e30e536 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:07:24 -0300 Subject: [PATCH 092/309] ORBINTLK.FIX: wait for Fout to reset RxLockedLtc --- siriuspy/siriuspy/orbintlk/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d56756416..b5df2353b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -789,6 +789,7 @@ def _config_fout_rxenbl(self): dev['RxEnbl-SP'] = rxenbl dev._wait('RxEnbl-RB', rxenbl) dev['RxLockedLtcRst-Cmd'] = 1 + dev._wait('RxLockedLtc-Mon', 1) return True From 96c84185766018812ed01fbb38f742ec6b3ce6cc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:10:11 -0300 Subject: [PATCH 093/309] ORBINLKT.FIX: only wait for latch reset when Rx is enabled --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index b5df2353b..7347f6464 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -789,7 +789,8 @@ def _config_fout_rxenbl(self): dev['RxEnbl-SP'] = rxenbl dev._wait('RxEnbl-RB', rxenbl) dev['RxLockedLtcRst-Cmd'] = 1 - dev._wait('RxLockedLtc-Mon', 1) + if rxenbl: + dev._wait('RxLockedLtc-Mon', 1) return True From e54a72ca4c9fae110f70a8b1dfb5fb28d33b423d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:14:26 -0300 Subject: [PATCH 094/309] ORBINTLK.FIX: fix bug in BPM general interlock enable lock --- siriuspy/siriuspy/orbintlk/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7347f6464..bd00b6f1c 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1231,8 +1231,13 @@ def _callback_bpm_lock(self, pvname, value, **kws): device = self._orbintlk_dev.devices[devidx] if propty_rb.endswith('En-Sts'): entyp = 'pos' if 'Pos' in propty_rb else \ - 'ang' if 'Ang' in propty_rb else 'minsum' - desired_value = self._enable_lists[entyp][devidx] + 'ang' if 'Ang' in propty_rb else \ + 'minsum' if 'MinSum' in propty_rb else \ + 'gen' + if entyp == 'gen': + desired_value = self._get_gen_bpm_intlk()[devidx] + else: + desired_value = self._enable_lists[entyp][devidx] elif 'Lmt' in propty_rb: limcls = 'pos' if 'Pos' in propty_rb else \ 'ang' if 'Ang' in propty_rb else 'minsum' From 0f2768c764cc47547337f6df0cd355143709923b Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:24:20 -0300 Subject: [PATCH 095/309] ORBINLKT.FIX: monitor Fout RxLockedLtc-Mon PV --- siriuspy/siriuspy/orbintlk/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index bd00b6f1c..cdba99b60 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -919,6 +919,7 @@ def _check_configs(self): for devname, rxenbl in self._fout2rxenbl.items(): dev = self._fout_devs[devname] okg &= dev['RxEnbl-RB'] == rxenbl + okg &= dev['RxLockedLtc-Mon'] value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 From 38b0d81b350c7bd4b7770f90e0c5b829438a5b84 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:31:31 -0300 Subject: [PATCH 096/309] ORBINTLK.FIX: fix BPM general interlock lock value when state is disabled --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index cdba99b60..d8deb52e0 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1236,7 +1236,8 @@ def _callback_bpm_lock(self, pvname, value, **kws): 'minsum' if 'MinSum' in propty_rb else \ 'gen' if entyp == 'gen': - desired_value = self._get_gen_bpm_intlk()[devidx] + desired_value = self._get_gen_bpm_intlk()[devidx] \ + if self._state else 0 else: desired_value = self._enable_lists[entyp][devidx] elif 'Lmt' in propty_rb: From e9a14f451ad5fff89dc5ff1ad9f48ea14230bb0b Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:32:57 -0300 Subject: [PATCH 097/309] ORBINLKT.FIX: fix Fouts RxLockedLtc-Mon check value --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d8deb52e0..7cd3345fd 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -919,7 +919,7 @@ def _check_configs(self): for devname, rxenbl in self._fout2rxenbl.items(): dev = self._fout_devs[devname] okg &= dev['RxEnbl-RB'] == rxenbl - okg &= dev['RxLockedLtc-Mon'] + okg &= dev['RxLockedLtc-Mon'] == rxenbl value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 From d8d1f00cd1d1a1591536dfe5b77e41dd6d1088c8 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:43:32 -0300 Subject: [PATCH 098/309] ORBINTLK.FIX: remove RxLockedLtcRst-Cmd on RxLockedLtc callback --- siriuspy/siriuspy/orbintlk/main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7cd3345fd..793e81bc6 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1089,11 +1089,6 @@ def _do_callback_rxlock(self, pvname, value): if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() - else: - # reset rxlock latch - dev = self._evg_dev if 'EVG' in devname \ - else self._fout_devs[devname] - dev['RxLockedLtcRst-Cmd'] = 1 def _conn_callback_timing(self, pvname, conn, **kws): if conn: From 8299c8391326914580ca814818a8f8dfe05610f5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:46:14 -0300 Subject: [PATCH 099/309] ORBINTLK.MNT: improve logging --- siriuspy/siriuspy/orbintlk/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 793e81bc6..af910654e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -408,6 +408,8 @@ def _init_devices_lock(self): pvo.add_callback(self._callback_bpm_lock) pvo.run_callbacks() + self._update_log('...lock running.') + @property def pvs_database(self): """Return pvs_database.""" From 26582fab5b6cb60c77e949c1dfb717e32cc8cb26 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 21:59:41 -0300 Subject: [PATCH 100/309] ORBINLKT.FIX: fix bug left in ResetTimingLockLatches-Cmd PV --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index af910654e..b8b2cb1ef 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -660,7 +660,8 @@ def cmd_reset_ti_lock_latch(self, value=None): if fout['RxLockedLtc-Mon']: continue fout['RxLockedLtcRst-Cmd'] = 1 - msg = 'Reset' if fout._wait('RxLockedLtc-Mon', 1, timeout=3) \ + rxv = self._fout2rxenbl + msg = 'Reset' if fout._wait('RxLockedLtc-Mon', rxv, timeout=3) \ else 'ERR:Could not reset' self._update_log(f'{msg} {devname} lock latchs.') if 'not' in msg: From 1d8a23a9e161653a6e296470a5f1185c5851e60c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 22:10:13 -0300 Subject: [PATCH 101/309] ORBINTLK.FIX: remove checks on internal enable state once now configurations are locked --- siriuspy/siriuspy/orbintlk/main.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index b8b2cb1ef..c05d72f59 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1011,8 +1011,6 @@ def _check_configs(self): def _callback_evg_intlk(self, value, **kws): _ = kws - if not self._state: - return if not self._init: return if self._thread_cbevgilk and self._thread_cbevgilk.is_alive(): @@ -1037,8 +1035,6 @@ def _do_callback_evg_intlk(self, value): self.cmd_acq_config() def _callback_fout_rxlock(self, pvname, value, **kws): - if not self._state: - return if not self._init: return nam = _PVName(pvname).device_name @@ -1050,8 +1046,6 @@ def _callback_fout_rxlock(self, pvname, value, **kws): self._thread_cbfout[nam].start() def _callback_evg_rxlock(self, pvname, value, **kws): - if not self._state: - return if not self._init: return pvname = _PVName(pvname) @@ -1098,8 +1092,6 @@ def _conn_callback_timing(self, pvname, conn, **kws): return pvname = _PVName(pvname) self._update_log(f'FATAL:{pvname.device_name} disconnected') - if not self._state: - return # verify if this is an orbit interlock reliability failure is_failure = False for dev in self._ti_mon_devs: @@ -1112,8 +1104,6 @@ def _callback_bpm_intlk(self, pvname, value, **kws): _ = kws if not value: return - if not self._state: - return if not self._init: return if self._thread_cbbpm and self._thread_cbbpm.is_alive(): @@ -1190,6 +1180,9 @@ def _handle_reliability_failure(self): self._update_log('WARN:Dry run running, will not handle') self._update_log('WARN:reliability failure.') return + if not self._state: + self._update_log('WARN:Orbit interlock is not enabled.') + return # if minimum sum condition is not satisfied, only monitor sum if not self._check_minsum_requirement(): pvo = self._sofb.pv_object('SlowSumRaw-Mon') From c4745c01b59c6decc59005820c4e56e6c85730b0 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 22:13:28 -0300 Subject: [PATCH 102/309] ORBINTLK.FIX: fix bug left in ResetTimingLockLatches-Cmd PV --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c05d72f59..6d8927491 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -660,7 +660,7 @@ def cmd_reset_ti_lock_latch(self, value=None): if fout['RxLockedLtc-Mon']: continue fout['RxLockedLtcRst-Cmd'] = 1 - rxv = self._fout2rxenbl + rxv = self._fout2rxenbl[devname] msg = 'Reset' if fout._wait('RxLockedLtc-Mon', rxv, timeout=3) \ else 'ERR:Could not reset' self._update_log(f'{msg} {devname} lock latchs.') From 470bfb8b5f4b5962c6c3d057881a947b226589dc Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 14 Nov 2023 22:22:16 -0300 Subject: [PATCH 103/309] ORBINTLK.FIX: fix race condition in set_enable method --- siriuspy/siriuspy/orbintlk/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6d8927491..f3df6f46c 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -471,9 +471,13 @@ def set_enable(self, value): glob_en = self._get_gen_bpm_intlk() else: glob_en = _np.zeros(self._const.nr_bpms, dtype=bool) + + bkup = int(self._state) + self._state = value if not self._orbintlk_dev.set_gen_enable(list(glob_en)): self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') + self._state = bkup return False self._update_log('Configured BPM general interlock enable.') @@ -481,10 +485,10 @@ def set_enable(self, value): if not self._evg_dev._wait( 'IntlkCtrlEnbl-Sts', value, timeout=self._const.DEF_TIMEOUT): self._update_log('ERR:Could not set EVG interlock enable.') + self._state = bkup return False self._update_log('Configured EVG interlock enable.') - self._state = value self.run_callbacks('Enable-Sts', self._state) return True From 8b22e92d78c5acae9c4aa2065eddec99149b2116 Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Thu, 16 Nov 2023 09:38:05 -0300 Subject: [PATCH 104/309] DEV.EQBPM.DOC: fix docstrings according to new array orders. --- siriuspy/siriuspy/devices/bpm_eq.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index 9cebb7f84..fbf14fd5f 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -170,10 +170,10 @@ def get_current_gains(self): """Return Current BPM gains as 3D numpy array. Returns: - numpy.ndarray (nrbpms, 4, 2): 3D numpy array with gains. - - The first index vary the BPMs, in the default high level + numpy.ndarray (4, nrbpms, 2): 3D numpy array with gains. + - The first index vary the antennas: 'A', 'B', 'C', 'D'; + - The second index vary the BPMs, in the default high level convention order; - - The second index vary the antennas: 'A', 'B', 'C', 'D'; - The last index refers to the type of the gain in the following order: 'Direct', 'Inverse'; @@ -190,7 +190,7 @@ def set_gains(self, gains): """Set gains matrix to BPMs. Args: - gains (float or numpy.ndarray, (nrbpms, 4, 2)): gain matrix. In + gains (float or numpy.ndarray, (4, nrbpms, 2)): gain matrix. In the same format as the one provided by get_current_gains method. If a float is provided, then this same gain will be applied to all BPMs. @@ -393,7 +393,7 @@ def calc_switching_levels( """Calculate average signal for each antenna in both switching states. Args: - antennas (numpy.ndarray, (nrbpms, 4, N)): Antennas data. + antennas (numpy.ndarray, (4, nrbpms, N)): Antennas data. fsamp (float, optional): Sampling frequency. Defaults to 4. fswtc (float, optional): Switching frequency. Defaults to 1. acq_strategy (int, optional): Whether we should assume states @@ -405,7 +405,7 @@ def calc_switching_levels( antennas gain during acquisition. Defaults to 0.95. Returns: - mean (numpy.ndarray, nrbpms, 4, 2): The levels of each switching + mean (numpy.ndarray, (4, nrbpms, 2)): The levels of each switching state for each antenna. """ From 4b3251452c5c5a4d7ad6726e789f62f8d2d4b408 Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 16 Nov 2023 13:17:04 -0300 Subject: [PATCH 105/309] DEV.FAMBPM.MNT: Move FamBPMs to a new module. --- siriuspy/siriuspy/devices/__init__.py | 7 +- siriuspy/siriuspy/devices/bpm.py | 462 +------------------------ siriuspy/siriuspy/devices/bpm_eq.py | 2 +- siriuspy/siriuspy/devices/bpm_fam.py | 470 ++++++++++++++++++++++++++ 4 files changed, 476 insertions(+), 465 deletions(-) create mode 100644 siriuspy/siriuspy/devices/bpm_fam.py diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index 7d1f0cf2c..682e117e8 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -2,10 +2,11 @@ from .afc_acq_core import AFCPhysicalTrigger, AFCACQLogicalTrigger from .bbb import BunchbyBunch -from .bpm import BPM, FamBPMs +from .bpm import BPM +from .bpm_fam import FamBPMs from .bpm_eq import EqualizeBPMs -from .currinfo import CurrInfoTranspEff, CurrInfoLinear, \ - CurrInfoBO, CurrInfoSI, CurrInfoAS +from .currinfo import CurrInfoTranspEff, CurrInfoLinear, CurrInfoBO, \ + CurrInfoSI, CurrInfoAS from .dcct import DCCT from .device import Device, DeviceSet from .egun import EGBias, EGFilament, EGHVPS, EGTriggerPS, EGPulsePS, EGun diff --git a/siriuspy/siriuspy/devices/bpm.py b/siriuspy/siriuspy/devices/bpm.py index 9236d864f..b9deb19be 100644 --- a/siriuspy/siriuspy/devices/bpm.py +++ b/siriuspy/siriuspy/devices/bpm.py @@ -1,16 +1,13 @@ """BPM devices.""" -import sys import time as _time # from threading import Event as _Flag import numpy as _np -from copy import deepcopy as _dcopy -from .device import Device as _Device, DeviceSet as _DeviceSet +from .device import Device as _Device from ..diagbeam.bpm.csdev import Const as _csbpm from ..search import BPMSearch as _BPMSearch -from ..namesys import SiriusPVName as _PVName class BPM(_Device): @@ -979,460 +976,3 @@ def get_propname(self, prop): def _get_pvname(self, propty): propty = self.get_propname(propty) return super()._get_pvname(propty) - - -class FamBPMs(_DeviceSet): - """Family of BPMs. - - Parameters - ---------- - devname (str, optional) - Device name. If not provided, defaults to DEVICES.SI. - Determine the list of BPM names. - bpmnames ((list, tuple), optional) - BPM names list. If provided, it takes priority over 'devname' - parameter. Defaults to None. - ispost_mortem (bool, optional) - Whether to control PM acquisition core. Defaults to False. - """ - - TIMEOUT = 10 - RFFEATT_MAX = 30 - PROPERTIES_ACQ = BPM.PROPERTIES_ACQ - PROPERTIES_DEFAULT = BPM.PROPERTIES_DEFAULT - ALL_MTURN_SIGNALS2ACQ = ('A', 'B', 'C', 'D', 'X', 'Y', 'Q', 'S') - - class DEVICES: - """.""" - - SI = 'SI-Fam:DI-BPM' - BO = 'BO-Fam:DI-BPM' - ALL = (BO, SI) - - def __init__( - self, devname=None, bpmnames=None, ispost_mortem=False, - props2init='all', mturn_signals2acq=('X', 'Y')): - """.""" - if devname is None: - devname = self.DEVICES.SI - if devname not in self.DEVICES.ALL: - raise ValueError('Wrong value for devname') - - devname = _PVName(devname) - bpm_names = bpmnames or _BPMSearch.get_names( - filters={'sec': devname.sec, 'dev': devname.dev}) - self._ispost_mortem = ispost_mortem - - self._mturn_signals2acq = list(mturn_signals2acq) - self.bpms = [BPM( - dev, auto_monitor_mon=False, ispost_mortem=ispost_mortem, - props2init=props2init) for dev in bpm_names] - - super().__init__(self.bpms[:], devname=devname) - self._bpm_names = bpm_names - self._csbpm = self.bpms[0].csdata - self._initial_timestamps = None - - self._mturn_flags = dict() - # NOTE: ACQCount-Mon need to be fixed on BPM's IOC - # for bpm in devs: - # pvo = bpm.pv_object('ACQCount-Mon') - # pvo.auto_monitor = True - # self._mturn_flags[pvo.pvname] = _Flag() - # pvo.add_callback(self._mturn_set_flag) - - @property - def bpm_names(self): - """Return BPM names.""" - return self._bpm_names - - @property - def csbpm(self): - """Return control system BPM constants class.""" - return self._csbpm - - @property - def mturn_signals2acq(self): - """Return which signals will be acquired by get_mturn_signals.""" - return _dcopy(self._mturn_signals2acq) - - @mturn_signals2acq.setter - def mturn_signals2acq(self, sigs): - sigs = [s.upper() for s in sigs] - diff = set(sigs) - set(self.ALL_MTURN_SIGNALS2ACQ) - if diff: - raise ValueError('The following signals do not exist: '+str(diff)) - self._mturn_signals2acq = sigs - - def set_attenuation(self, value=RFFEATT_MAX, timeout=TIMEOUT): - """.""" - for bpm in self: - bpm.rffe_att = value - - mstr = '' - okall = True - t0 = _time.time() - for bpm in self: - tout = timeout - (_time.time() - t0) - if not bpm._wait('RFFEAtt-RB', value, timeout=tout): - okall = False - mstr += ( - f'\n{bpm.devname:<20s}: ' + - f'rb {bpm.rffe_att:.0f} != sp {value:.0f}') - - print('RFFE attenuation set confirmed in all BPMs', end='') - print(', except:' + mstr if mstr else '.') - return okall - - def get_slow_orbit(self): - """Get slow orbit vectors. - - Returns: - orbx (numpy.ndarray, 160): Horizontal Orbit. - orby (numpy.ndarray, 160): Vertical Orbit. - - """ - orbx, orby = [], [] - for bpm in self.bpms: - orbx.append(bpm.posx) - orby.append(bpm.posy) - orbx = _np.array(orbx) - orby = _np.array(orby) - return orbx, orby - - def get_mturn_signals(self): - """Get Multiturn signals matrices. - - Returns: - list: Each component of the list is an numpy.ndarray with shape - (N, 160), containing the values for the signals acquired. - - """ - sigs = [[] for _ in self._mturn_signals2acq] - - mini = int(sys.maxsize) # a very large integer - for bpm in self.bpms: - for i, sn in enumerate(self._mturn_signals2acq): - sn = 'sum' if sn == 'S' else sn.lower() - name = 'mt_' + ('ampl' if sn in 'abcd' else 'pos') + sn - sigs[i].append(getattr(bpm, name)) - mini = min(mini, _np.min([s[-1].size for s in sigs])) - - for i, sig in enumerate(sigs): - for j, s in enumerate(sig): - sig[j] = s[:mini] - sigs[i] = _np.array(sig).T - return sigs - - def get_mturn_timestamps(self): - """Get Multiturn data timestamps. - - Returns: - tsmps (numpy.ndarray, (160, N)): The i-th row has the timestamp of - the i-th bpm for the N aquired signals. - - """ - tsmps = _np.zeros( - (len(self.bpms), len(self._mturn_signals2acq)), dtype=float) - for i, bpm in enumerate(self.bpms): - for j, s in enumerate(self._mturn_signals2acq): - s = 'SUM' if s == 'S' else s - pvo = bpm.pv_object(f'GEN_{s}ArrayData') - tv = pvo.get_timevars(timeout=self.TIMEOUT) - tsmps[i, j] = pvo.timestamp if tv is None else tv['timestamp'] - return tsmps - - def get_sampling_frequency(self, rf_freq: float, acq_rate='') -> float: - """Return the sampling frequency of the acquisition. - - Args: - rf_freq (float): RF frequency. - acq_rate (str, optional): acquisition rate. Defaults to ''. - If empty string, it gets the configured acq. rate on BPMs - - Returns: - float: acquisition frequency. - - """ - fs_bpms = { - dev.get_sampling_frequency(rf_freq, acq_rate) - for dev in self.bpms} - if len(fs_bpms) == 1: - return fs_bpms.pop() - else: - print('BPMs are not configured with the same ACQChannel.') - return None - - def get_switching_frequency(self, rf_freq: float) -> float: - """Return the switching frequency. - - Args: - rf_freq (float): RF frequency. - - Returns: - float: switching frequency. - - """ - fsw_bpms = { - dev.get_switching_frequency(rf_freq) for dev in self.bpms} - if len(fsw_bpms) == 1: - return fsw_bpms.pop() - else: - print('BPMs are not configured with the same SwMode.') - return None - - def mturn_config_acquisition( - self, nr_points_after: int, nr_points_before=0, - acq_rate='FAcq', repeat=True, external=True) -> int: - """Configure acquisition for BPMs. - - Args: - nr_points_after (int): number of points after trigger. - nr_points_before (int): number of points after trigger. - Defaults to 0. - acq_rate (str, optional): Acquisition rate ('TbT', 'TbTPha', - 'FOFB', 'FOFBPha', 'FAcq', 'ADC', 'ADCSwp'). - Defaults to 'FAcq'. - repeat (bool, optional): Whether or not acquisition should be - repetitive. Defaults to True. - external (bool, optional): Whether or not external trigger should - be used. Defaults to True. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - <0: Index of the first BPM which did not stop last acq. plus 1. - >0: Index of the first BPM which is not ready for acq. plus 1. - - """ - if acq_rate.lower().startswith('facq'): - acq_rate = self._csbpm.AcqChan.FAcq - elif acq_rate.lower().startswith('fofbpha'): - acq_rate = self._csbpm.AcqChan.FOFBPha - elif acq_rate.lower().startswith('fofb'): - acq_rate = self._csbpm.AcqChan.FOFB - elif acq_rate.lower().startswith('tbtpha'): - acq_rate = self._csbpm.AcqChan.TbTPha - elif acq_rate.lower().startswith('tbt'): - acq_rate = self._csbpm.AcqChan.TbT - elif acq_rate.lower().startswith('adcswp'): - acq_rate = self._csbpm.AcqChan.ADCSwp - elif acq_rate.lower().startswith('adc'): - acq_rate = self._csbpm.AcqChan.ADC - else: - raise ValueError(acq_rate + ' is not a valid acquisition rate.') - - if repeat: - repeat = self._csbpm.AcqRepeat.Repetitive - else: - repeat = self._csbpm.AcqRepeat.Normal - - if external: - trig = self._csbpm.AcqTrigTyp.External - else: - trig = self._csbpm.AcqTrigTyp.Now - - ret = self.cmd_mturn_acq_abort() - if ret > 0: - return -ret - - for bpm in self.bpms: - bpm.acq_repeat = repeat - bpm.acq_channel = acq_rate - bpm.acq_trigger = trig - bpm.acq_nrsamples_pre = nr_points_before - bpm.acq_nrsamples_post = nr_points_after - - return self.cmd_mturn_acq_start() - - def cmd_mturn_acq_abort(self, wait=True, timeout=10) -> int: - """Abort BPMs acquistion. - - Args: - wait (bool, optional): whether or not to wait BPMs get ready. - Defaults to True. - timeout (int, optional): Time to wait. Defaults to 10. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - >0: Index of the first BPM which did not update plus 1. - - """ - for bpm in self.bpms: - bpm.acq_ctrl = self._csbpm.AcqEvents.Abort - - if wait: - return self.wait_acquisition_finish(timeout=timeout) - return 0 - - def wait_acquisition_finish(self, timeout=10) -> int: - """Wait for all BPMs to be ready for acquisition. - - Args: - timeout (int, optional): Time to wait. Defaults to 10. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - >0: Index of the first BPM which did not update plus 1. - - """ - for i, bpm in enumerate(self.bpms): - t0_ = _time.time() - if not bpm.wait_acq_finish(timeout): - return i + 1 - timeout -= _time.time() - t0_ - return 0 - - def cmd_mturn_acq_start(self, wait=True, timeout=10) -> int: - """Start BPMs acquisition. - - Args: - wait (bool, optional): whether or not to wait BPMs get ready. - Defaults to True. - timeout (int, optional): Time to wait. Defaults to 10. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - >0: Index of the first BPM which did not update plus 1. - - """ - for bpm in self.bpms: - bpm.acq_ctrl = self._csbpm.AcqEvents.Start - if wait: - return self.wait_acquisition_start(timeout=timeout) - return 0 - - def wait_acquisition_start(self, timeout=10) -> bool: - """Wait for all BPMs to be ready for acquisition. - - Args: - timeout (int, optional): Time to wait. Defaults to 10. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - >0: Index of the first BPM which did not update plus 1. - - """ - for i, bpm in enumerate(self.bpms): - t0_ = _time.time() - if not bpm.wait_acq_start(timeout): - return i + 1 - timeout -= _time.time() - t0_ - return 0 - - def set_switching_mode(self, mode='direct'): - """Set switching mode of BPMS. - - Args: - mode ((str, int), optional): Desired mode, must be in - {'direct', 'switching', 1, 3}. Defaults to 'direct'. - - Raises: - ValueError: When mode is not in {'direct', 'switching', 1, 3}. - - """ - if mode not in ('direct', 'switching', 1, 3): - raise ValueError('Value must be in ("direct", "switching", 1, 3).') - - for bpm in self.bpms: - bpm.switching_mode = mode - - def mturn_update_initial_timestamps(self): - """Call this method before acquisition to get orbit for comparison.""" - self._initial_timestamps = self.get_mturn_timestamps() - - def mturn_reset_flags(self): - """Reset Multiturn flags to wait for a new orbit update.""" - for flag in self._mturn_flags.values(): - flag.clear() - - def mturn_reset_flags_and_update_initial_timestamps(self): - """Set initial state to wait for orbit acquisition to start.""" - self.mturn_reset_flags() - self.mturn_update_initial_timestamps() - - def mturn_wait_update_flags(self, timeout=10): - """Wait for all acquisition flags to be updated. - - Args: - timeout (int, optional): Time to wait. Defaults to 10. - - Returns: - int: code describing what happened: - =0: BPMs are ready. - >0: Index of the first BPM which did not update plus 1. - - """ - for i, flag in enumerate(self._mturn_flags.values()): - t00 = _time.time() - if not flag.wait(timeout=timeout): - return i + 1 - timeout -= _time.time() - t00 - timeout = max(timeout, 0) - return 0 - - def mturn_wait_update_timestamps(self, timeout=10) -> int: - """Call this method after acquisition to check if data was updated. - - For this method to work it is necessary to call - mturn_update_initial_timestamps - before the acquisition starts, so that a reference for comparison is - created. - - Args: - timeout (int, optional): Waiting timeout. Defaults to 10. - - Returns: - int: code describing what happened: - -2: size of timestamps changed in relation to initial timestamp - -1: initial timestamps were not defined; - =0: data updated. - >0: index of the first BPM which did not update plus 1. - - """ - if self._initial_timestamps is None: - return -1 - - tsmp0 = self._initial_timestamps - while timeout > 0: - t00 = _time.time() - tsmp = self.get_mturn_timestamps() - if tsmp.size != tsmp0.size: - return -2 - errors = _np.any(_np.equal(tsmp, tsmp0), axis=1) - if not _np.any(errors): - return 0 - _time.sleep(0.1) - timeout -= _time.time() - t00 - - return int(_np.nonzero(errors)[0][0])+1 - - def mturn_wait_update(self, timeout=10) -> int: - """Combine all methods to wait update data. - - Args: - timeout (int, optional): Waiting timeout. Defaults to 10. - - Returns: - int: code describing what happened: - -2: size of timestamps changed in relation to initial timestamp - -1: initial timestamps were not defined; - =0: data updated. - >0: index of the first BPM which did not update plus 1. - - """ - t00 = _time.time() - ret = self.mturn_wait_update_flags(timeout) - if ret > 0: - return ret - timeout -= _time.time() - t00 - - return self.mturn_wait_update_timestamps(timeout) - - def _mturn_set_flag(self, pvname, **kwargs): - _ = kwargs - self._mturn_flags[pvname].set() diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index 00ca864b5..694ab1c58 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -7,7 +7,7 @@ from mathphys.functions import save_pickle as _savep, load_pickle as _loadp, \ get_namedtuple as _namedtuple -from .bpm import FamBPMs as _FamBPMs +from .bpm_fam import FamBPMs as _FamBPMs from .timing import Trigger from .currinfo import CurrInfoSI as _CurrInfoSI diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py new file mode 100644 index 000000000..1f67a51fe --- /dev/null +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -0,0 +1,470 @@ +"""FamBPM deviceSet.""" + +import sys +import time as _time +# from threading import Event as _Flag + +import numpy as _np +from copy import deepcopy as _dcopy + +from .device import DeviceSet as _DeviceSet +from ..search import BPMSearch as _BPMSearch +from ..namesys import SiriusPVName as _PVName +from .bpm import BPM + + +class FamBPMs(_DeviceSet): + """Family of BPMs. + + Parameters + ---------- + devname (str, optional) + Device name. If not provided, defaults to DEVICES.SI. + Determine the list of BPM names. + bpmnames ((list, tuple), optional) + BPM names list. If provided, it takes priority over 'devname' + parameter. Defaults to None. + ispost_mortem (bool, optional) + Whether to control PM acquisition core. Defaults to False. + """ + + TIMEOUT = 10 + RFFEATT_MAX = 30 + PROPERTIES_ACQ = BPM.PROPERTIES_ACQ + PROPERTIES_DEFAULT = BPM.PROPERTIES_DEFAULT + ALL_MTURN_SIGNALS2ACQ = ('A', 'B', 'C', 'D', 'X', 'Y', 'Q', 'S') + + class DEVICES: + """.""" + + SI = 'SI-Fam:DI-BPM' + BO = 'BO-Fam:DI-BPM' + ALL = (BO, SI) + + def __init__( + self, devname=None, bpmnames=None, ispost_mortem=False, + props2init='all', mturn_signals2acq=('X', 'Y')): + """.""" + if devname is None: + devname = self.DEVICES.SI + if devname not in self.DEVICES.ALL: + raise ValueError('Wrong value for devname') + + devname = _PVName(devname) + bpm_names = bpmnames or _BPMSearch.get_names( + filters={'sec': devname.sec, 'dev': devname.dev}) + self._ispost_mortem = ispost_mortem + + self._mturn_signals2acq = list(mturn_signals2acq) + self.bpms = [BPM( + dev, auto_monitor_mon=False, ispost_mortem=ispost_mortem, + props2init=props2init) for dev in bpm_names] + + super().__init__(self.bpms[:], devname=devname) + self._bpm_names = bpm_names + self._csbpm = self.bpms[0].csdata + self._initial_timestamps = None + + self._mturn_flags = dict() + # NOTE: ACQCount-Mon need to be fixed on BPM's IOC + # for bpm in devs: + # pvo = bpm.pv_object('ACQCount-Mon') + # pvo.auto_monitor = True + # self._mturn_flags[pvo.pvname] = _Flag() + # pvo.add_callback(self._mturn_set_flag) + + @property + def bpm_names(self): + """Return BPM names.""" + return self._bpm_names + + @property + def csbpm(self): + """Return control system BPM constants class.""" + return self._csbpm + + @property + def mturn_signals2acq(self): + """Return which signals will be acquired by get_mturn_signals.""" + return _dcopy(self._mturn_signals2acq) + + @mturn_signals2acq.setter + def mturn_signals2acq(self, sigs): + sigs = [s.upper() for s in sigs] + diff = set(sigs) - set(self.ALL_MTURN_SIGNALS2ACQ) + if diff: + raise ValueError('The following signals do not exist: '+str(diff)) + self._mturn_signals2acq = sigs + + def set_attenuation(self, value=RFFEATT_MAX, timeout=TIMEOUT): + """.""" + for bpm in self: + bpm.rffe_att = value + + mstr = '' + okall = True + t0 = _time.time() + for bpm in self: + tout = timeout - (_time.time() - t0) + if not bpm._wait('RFFEAtt-RB', value, timeout=tout): + okall = False + mstr += ( + f'\n{bpm.devname:<20s}: ' + + f'rb {bpm.rffe_att:.0f} != sp {value:.0f}') + + print('RFFE attenuation set confirmed in all BPMs', end='') + print(', except:' + mstr if mstr else '.') + return okall + + def get_slow_orbit(self): + """Get slow orbit vectors. + + Returns: + orbx (numpy.ndarray, 160): Horizontal Orbit. + orby (numpy.ndarray, 160): Vertical Orbit. + + """ + orbx, orby = [], [] + for bpm in self.bpms: + orbx.append(bpm.posx) + orby.append(bpm.posy) + orbx = _np.array(orbx) + orby = _np.array(orby) + return orbx, orby + + def get_mturn_signals(self): + """Get Multiturn signals matrices. + + Returns: + list: Each component of the list is an numpy.ndarray with shape + (N, 160), containing the values for the signals acquired. + + """ + sigs = [[] for _ in self._mturn_signals2acq] + + mini = int(sys.maxsize) # a very large integer + for bpm in self.bpms: + for i, sn in enumerate(self._mturn_signals2acq): + sn = 'sum' if sn == 'S' else sn.lower() + name = 'mt_' + ('ampl' if sn in 'abcd' else 'pos') + sn + sigs[i].append(getattr(bpm, name)) + mini = min(mini, _np.min([s[-1].size for s in sigs])) + + for i, sig in enumerate(sigs): + for j, s in enumerate(sig): + sig[j] = s[:mini] + sigs[i] = _np.array(sig).T + return sigs + + def get_mturn_timestamps(self): + """Get Multiturn data timestamps. + + Returns: + tsmps (numpy.ndarray, (160, N)): The i-th row has the timestamp of + the i-th bpm for the N aquired signals. + + """ + tsmps = _np.zeros( + (len(self.bpms), len(self._mturn_signals2acq)), dtype=float) + for i, bpm in enumerate(self.bpms): + for j, s in enumerate(self._mturn_signals2acq): + s = 'SUM' if s == 'S' else s + pvo = bpm.pv_object(f'GEN_{s}ArrayData') + tv = pvo.get_timevars(timeout=self.TIMEOUT) + tsmps[i, j] = pvo.timestamp if tv is None else tv['timestamp'] + return tsmps + + def get_sampling_frequency(self, rf_freq: float, acq_rate='') -> float: + """Return the sampling frequency of the acquisition. + + Args: + rf_freq (float): RF frequency. + acq_rate (str, optional): acquisition rate. Defaults to ''. + If empty string, it gets the configured acq. rate on BPMs + + Returns: + float: acquisition frequency. + + """ + fs_bpms = { + dev.get_sampling_frequency(rf_freq, acq_rate) + for dev in self.bpms} + if len(fs_bpms) == 1: + return fs_bpms.pop() + else: + print('BPMs are not configured with the same ACQChannel.') + return None + + def get_switching_frequency(self, rf_freq: float) -> float: + """Return the switching frequency. + + Args: + rf_freq (float): RF frequency. + + Returns: + float: switching frequency. + + """ + fsw_bpms = { + dev.get_switching_frequency(rf_freq) for dev in self.bpms} + if len(fsw_bpms) == 1: + return fsw_bpms.pop() + else: + print('BPMs are not configured with the same SwMode.') + return None + + def mturn_config_acquisition( + self, nr_points_after: int, nr_points_before=0, + acq_rate='FAcq', repeat=True, external=True) -> int: + """Configure acquisition for BPMs. + + Args: + nr_points_after (int): number of points after trigger. + nr_points_before (int): number of points after trigger. + Defaults to 0. + acq_rate (str, optional): Acquisition rate ('TbT', 'TbTPha', + 'FOFB', 'FOFBPha', 'FAcq', 'ADC', 'ADCSwp'). + Defaults to 'FAcq'. + repeat (bool, optional): Whether or not acquisition should be + repetitive. Defaults to True. + external (bool, optional): Whether or not external trigger should + be used. Defaults to True. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + <0: Index of the first BPM which did not stop last acq. plus 1. + >0: Index of the first BPM which is not ready for acq. plus 1. + + """ + if acq_rate.lower().startswith('facq'): + acq_rate = self._csbpm.AcqChan.FAcq + elif acq_rate.lower().startswith('fofbpha'): + acq_rate = self._csbpm.AcqChan.FOFBPha + elif acq_rate.lower().startswith('fofb'): + acq_rate = self._csbpm.AcqChan.FOFB + elif acq_rate.lower().startswith('tbtpha'): + acq_rate = self._csbpm.AcqChan.TbTPha + elif acq_rate.lower().startswith('tbt'): + acq_rate = self._csbpm.AcqChan.TbT + elif acq_rate.lower().startswith('adcswp'): + acq_rate = self._csbpm.AcqChan.ADCSwp + elif acq_rate.lower().startswith('adc'): + acq_rate = self._csbpm.AcqChan.ADC + else: + raise ValueError(acq_rate + ' is not a valid acquisition rate.') + + if repeat: + repeat = self._csbpm.AcqRepeat.Repetitive + else: + repeat = self._csbpm.AcqRepeat.Normal + + if external: + trig = self._csbpm.AcqTrigTyp.External + else: + trig = self._csbpm.AcqTrigTyp.Now + + ret = self.cmd_mturn_acq_abort() + if ret > 0: + return -ret + + for bpm in self.bpms: + bpm.acq_repeat = repeat + bpm.acq_channel = acq_rate + bpm.acq_trigger = trig + bpm.acq_nrsamples_pre = nr_points_before + bpm.acq_nrsamples_post = nr_points_after + + return self.cmd_mturn_acq_start() + + def cmd_mturn_acq_abort(self, wait=True, timeout=10) -> int: + """Abort BPMs acquistion. + + Args: + wait (bool, optional): whether or not to wait BPMs get ready. + Defaults to True. + timeout (int, optional): Time to wait. Defaults to 10. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + >0: Index of the first BPM which did not update plus 1. + + """ + for bpm in self.bpms: + bpm.acq_ctrl = self._csbpm.AcqEvents.Abort + + if wait: + return self.wait_acquisition_finish(timeout=timeout) + return 0 + + def wait_acquisition_finish(self, timeout=10) -> int: + """Wait for all BPMs to be ready for acquisition. + + Args: + timeout (int, optional): Time to wait. Defaults to 10. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + >0: Index of the first BPM which did not update plus 1. + + """ + for i, bpm in enumerate(self.bpms): + t0_ = _time.time() + if not bpm.wait_acq_finish(timeout): + return i + 1 + timeout -= _time.time() - t0_ + return 0 + + def cmd_mturn_acq_start(self, wait=True, timeout=10) -> int: + """Start BPMs acquisition. + + Args: + wait (bool, optional): whether or not to wait BPMs get ready. + Defaults to True. + timeout (int, optional): Time to wait. Defaults to 10. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + >0: Index of the first BPM which did not update plus 1. + + """ + for bpm in self.bpms: + bpm.acq_ctrl = self._csbpm.AcqEvents.Start + if wait: + return self.wait_acquisition_start(timeout=timeout) + return 0 + + def wait_acquisition_start(self, timeout=10) -> bool: + """Wait for all BPMs to be ready for acquisition. + + Args: + timeout (int, optional): Time to wait. Defaults to 10. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + >0: Index of the first BPM which did not update plus 1. + + """ + for i, bpm in enumerate(self.bpms): + t0_ = _time.time() + if not bpm.wait_acq_start(timeout): + return i + 1 + timeout -= _time.time() - t0_ + return 0 + + def set_switching_mode(self, mode='direct'): + """Set switching mode of BPMS. + + Args: + mode ((str, int), optional): Desired mode, must be in + {'direct', 'switching', 1, 3}. Defaults to 'direct'. + + Raises: + ValueError: When mode is not in {'direct', 'switching', 1, 3}. + + """ + if mode not in ('direct', 'switching', 1, 3): + raise ValueError('Value must be in ("direct", "switching", 1, 3).') + + for bpm in self.bpms: + bpm.switching_mode = mode + + def mturn_update_initial_timestamps(self): + """Call this method before acquisition to get orbit for comparison.""" + self._initial_timestamps = self.get_mturn_timestamps() + + def mturn_reset_flags(self): + """Reset Multiturn flags to wait for a new orbit update.""" + for flag in self._mturn_flags.values(): + flag.clear() + + def mturn_reset_flags_and_update_initial_timestamps(self): + """Set initial state to wait for orbit acquisition to start.""" + self.mturn_reset_flags() + self.mturn_update_initial_timestamps() + + def mturn_wait_update_flags(self, timeout=10): + """Wait for all acquisition flags to be updated. + + Args: + timeout (int, optional): Time to wait. Defaults to 10. + + Returns: + int: code describing what happened: + =0: BPMs are ready. + >0: Index of the first BPM which did not update plus 1. + + """ + for i, flag in enumerate(self._mturn_flags.values()): + t00 = _time.time() + if not flag.wait(timeout=timeout): + return i + 1 + timeout -= _time.time() - t00 + timeout = max(timeout, 0) + return 0 + + def mturn_wait_update_timestamps(self, timeout=10) -> int: + """Call this method after acquisition to check if data was updated. + + For this method to work it is necessary to call + mturn_update_initial_timestamps + before the acquisition starts, so that a reference for comparison is + created. + + Args: + timeout (int, optional): Waiting timeout. Defaults to 10. + + Returns: + int: code describing what happened: + -2: size of timestamps changed in relation to initial timestamp + -1: initial timestamps were not defined; + =0: data updated. + >0: index of the first BPM which did not update plus 1. + + """ + if self._initial_timestamps is None: + return -1 + + tsmp0 = self._initial_timestamps + while timeout > 0: + t00 = _time.time() + tsmp = self.get_mturn_timestamps() + if tsmp.size != tsmp0.size: + return -2 + errors = _np.any(_np.equal(tsmp, tsmp0), axis=1) + if not _np.any(errors): + return 0 + _time.sleep(0.1) + timeout -= _time.time() - t00 + + return int(_np.nonzero(errors)[0][0])+1 + + def mturn_wait_update(self, timeout=10) -> int: + """Combine all methods to wait update data. + + Args: + timeout (int, optional): Waiting timeout. Defaults to 10. + + Returns: + int: code describing what happened: + -2: size of timestamps changed in relation to initial timestamp + -1: initial timestamps were not defined; + =0: data updated. + >0: index of the first BPM which did not update plus 1. + + """ + t00 = _time.time() + ret = self.mturn_wait_update_flags(timeout) + if ret > 0: + return ret + timeout -= _time.time() - t00 + + return self.mturn_wait_update_timestamps(timeout) + + def _mturn_set_flag(self, pvname, **kwargs): + _ = kwargs + self._mturn_flags[pvname].set() From a708c9641471d30ed053f28bc8442db8ea825d05 Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Thu, 16 Nov 2023 14:50:01 -0300 Subject: [PATCH 106/309] DEV.BPMEQ.BUG: Fix position calculation. --- siriuspy/siriuspy/devices/bpm_eq.py | 50 +++++++++++++---------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index fbf14fd5f..95b8266f0 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -499,18 +499,17 @@ def estimate_orbit_variation(self): mean = self.data.get('antennas_mean') gains_init = self.data.get('gains_init') gains_new = self.data.get('gains_new') - posx_gain = self.data.get('posx_gain') - posy_gain = self.data.get('posy_gain') - posx_offset = self.data.get('posx_offset', _np.zeros(len(self.bpms))) - posy_offset = self.data.get('posy_offset', _np.zeros(len(self.bpms))) - + gainx = self.data.get('posx_gain') + gainy = self.data.get('posy_gain') + offx = self.data.get('posx_offset', _np.zeros(len(self.bpms))) + offy = self.data.get('posy_offset', _np.zeros(len(self.bpms))) if gains_new is None: self._log('ERR:Missing info. Acquire and process data first.') orbx_init, orby_init = self._estimate_orbit( - mean, gains_init, posx_gain, posy_gain, posx_offset, posy_offset) + mean, gains_init, gainx, gainy, offx, offy) orbx_new, orby_new = self._estimate_orbit( - mean, gains_new, posx_gain, posy_gain, posx_offset, posy_offset) + mean, gains_new, gainx, gainy, offx, offy) # Get the average over both semicycles self.data['orbx_init'] = orbx_init.mean(axis=-1) self.data['orby_init'] = orby_init.mean(axis=-1) @@ -596,10 +595,10 @@ def plot_semicycle_indices(self): def plot_antennas_mean(self): """.""" - posx_gain = self.data.get('posx_gain') - posy_gain = self.data.get('posx_gain') - posx_offs = self.data.get('posx_offset') - posy_offs = self.data.get('posx_offset') + gainx = self.data.get('posx_gain') + gainy = self.data.get('posx_gain') + offx = self.data.get('posx_offset') + offy = self.data.get('posx_offset') gacq = self.data.get('gains_acq') gini = self.data.get('gains_init') gnew = self.data.get('gains_new') @@ -630,7 +629,7 @@ def plot_antennas_mean(self): ld.set_label('Direct') li.set_label('Inverse') posx, posy = self._estimate_orbit( - antm, gain, posx_gain, posy_gain, posx_offs, posy_offs) + antm, gain, gainx, gainy, offx, offy) sum_ = val.sum(axis=0) axs[4, j].plot(posx[:, 0], 'o-') axs[4, j].plot(posx[:, 1], 'o-') @@ -678,24 +677,21 @@ def plot_antennas_for_check(self): # ------- auxiliary methods ---------- - def _estimate_orbit( - self, mean, gains, posx_gain, posy_gain, posx_offset, posy_offset): - ant = mean * gains - # Get pairs of antennas - ac = ant[::2] - bd = ant[1::2] + @staticmethod + def _estimate_orbit(mean, gains, gainx, gainy, offx, offy): + a, b, c, d = mean * gains # Calculate difference over sum for each pair - dovs_ac = _np.diff(ac, axis=0).squeeze() / ac.sum(axis=0) - dovs_bd = _np.diff(bd, axis=0).squeeze() / bd.sum(axis=0) + a_c = (a-c) / (a+c) + b_d = (b-d) / (b+d) # Get the positions: - posx = (dovs_ac - dovs_bd) - posy = (dovs_ac + dovs_bd) - # Apply Position gains and factor of two missing in previous step - posx *= posx_gain[:, None] / 2 - posy *= posy_gain[:, None] / 2 + posx = (a_c - b_d) / 2 + posy = (a_c + b_d) / 2 + # Apply position gains: + posx *= gainx[:, None] + posy *= gainy[:, None] # Subtract offsets: - posx -= posx_offset[:, None] - posy -= posy_offset[:, None] + posx -= offx[:, None] + posy -= offy[:, None] return posx, posy def _log(self, message, *args, level='INFO', **kwrgs): From 22d1fc3b5642237f57801dac253202132d9152ac Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 16 Nov 2023 23:16:48 -0300 Subject: [PATCH 107/309] Refactor ID devices --- siriuspy/siriuspy/devices/device.py | 30 +- siriuspy/siriuspy/devices/dvf.py | 2 +- siriuspy/siriuspy/devices/ids.py | 866 +++++++++++++++----------- siriuspy/siriuspy/search/id_search.py | 42 ++ 4 files changed, 561 insertions(+), 379 deletions(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 87941a9fe..a1b9b915e 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -225,27 +225,33 @@ def comp_(val): if isinstance(comp, str): comp = getattr(_opr, comp) - if comp_(value): - return True - timeout = _DEF_TIMEOUT if timeout is None else timeout timeout = 0 if timeout <= 0 else timeout - ntrials = int(timeout/_TINY_INTERVAL) - for _ in range(ntrials): + t0_ = _time.time() + while not comp_(value): + if _time.time() - t0_ > timeout: + return False _time.sleep(_TINY_INTERVAL) - if comp_(value): - return True - if comp_(value): - return True - else: - return False + return True def _wait_float( self, propty, value, rel_tol=0.0, abs_tol=0.1, timeout=None): """Wait until float value gets close enough of desired value.""" - func = _partial(_math.isclose, abs_tol=abs_tol, rel_tol=rel_tol) + isc = _np.isclose if isinstance(value, _np.ndarray) else _math.isclose + func = _partial(isc, abs_tol=abs_tol, rel_tol=rel_tol) return self._wait(propty, value, comp=func, timeout=timeout) + def _wait_set(self, props_values, timeout=None, comp='eq'): + timeout = _DEF_TIMEOUT if timeout is None else timeout + t0_ = _time.time() + for propty, value in props_values.items(): + timeout_left = max(0, timeout - (_time.time() - t0_)) + if timeout_left == 0: + return False + if not self._wait(propty, value, timeout=timeout_left, comp=comp): + return False + return True + def _get_pvname(self, propty): dev = self._devname pref = _VACA_PREFIX + ('-' if _VACA_PREFIX else '') diff --git a/siriuspy/siriuspy/devices/dvf.py b/siriuspy/siriuspy/devices/dvf.py index 7f9c594d2..1e9917360 100644 --- a/siriuspy/siriuspy/devices/dvf.py +++ b/siriuspy/siriuspy/devices/dvf.py @@ -420,7 +420,7 @@ def cmd_cam_roi_set(self, offsetx, offsety, width, height, timeout=None): """Set cam image ROI and reset aquisition.""" c_width, c_height = self.cam_width, self.cam_height n_width, n_height = int(width), int(height) - + if not self.cmd_acquire_off(timeout=timeout): return False if n_width < c_width: diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 6fc2a6230..0c03892a6 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -12,7 +12,6 @@ class _ID(_Device): """Generic Insertion Device.""" _SHORT_SHUT_EYE = 0.1 # [s] - _MOVECHECK_SLEEP = 0.1 # [s] _DEF_TIMEOUT = 8 # [s] PROPERTIES_DEFAULT = ( @@ -20,12 +19,48 @@ class _ID(_Device): 'BeamLineCtrlEnbl-Sel', 'BeamLineCtrlEnbl-Sts', ) + class PARAM_PVS: + """.""" + + # --- GENERAL --- + PERIOD_LEN_CTE = 'PeriodLength-Cte' + START_PARKING_CMD = 'StartParking-Cmd' + # --- PPARAM --- + PPARAM_SP = 'PParam-SP' + PPARAM_RB = 'PParam-RB' + PPARAM_MON = 'PParam-Mon' + PPARAM_PARKED_CTE = 'PParamParked-Cte' + PPARAM_MAXVELO_SP = 'MaxVelo-SP' + PPARAM_MAXVELO_RB = 'MaxVelo-RB' + PPARAM_VELO_SP = 'PParamVelo-SP' + PPARAM_VELO_RB = 'PParamVelo-RB' + PPARAM_VELO_MON = None + PPARAM_CHANGE_CMD = 'PParamChange-Cmd' + # --- KPARAM --- + KPARAM_SP = 'KParam-SP' + KPARAM_RB = 'KParam-RB' + KPARAM_MON = 'KParam-Mon' + KPARAM_PARKED_CTE = 'KParamParked-Cte' + KPARAM_MAXVELO_SP = 'MaxVelo-SP' + KPARAM_MAXVELO_RB = 'MaxVelo-RB' + KPARAM_VELO_SP = 'KParamVelo-SP' + KPARAM_VELO_RB = 'KParamVelo-RB' + KPARAM_VELO_MON = None + KPARAM_CHANGE_CMD = 'KParamChange-Cmd' + # --- POL --- + POL_SEL = 'Pol-Sel' + POL_STS = 'Pol-Sts' + POL_MON = 'Pol-Mon' + POL_CHANGE_CMD = 'PolChange-Cmd' + def __init__(self, devname, props2init='all', auto_monitor_mon=True): """.""" # call base class constructor super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + # --- general --- + @property def parameters(self): """Return ID parameters.""" @@ -34,25 +69,191 @@ def parameters(self): @property def period_length(self): """Return ID period length [mm].""" - return self.parameters.PERIOD_LENGTH + if self.PARAM_PVS.PERIOD_LEN_CTE in self.properties_all: + return self[self.PARAM_PVS.PERIOD_LEN_CTE] + else: + return self.parameters.PERIOD_LENGTH + + # --- polarization --- + + @property + def polarization(self): + """Return ID polarization.""" + if self.PARAM_PVS.POL_STS in self.properties_all: + return self[self.PARAM_PVS.POL_STS] + else: + return _IDSearch.POL_UNDEF_STR + + @polarization.setter + def polarization(self, value): + """Set ID polarization.""" + if self.PARAM_PVS.POL_SEL in self.properties_all: + self[self.PARAM_PVS.POL_SEL] = value + else: + raise TypeError('ID type does not define polarizations!') + + @property + def polarization_mon(self): + """Return ID polarization monitor.""" + if self.PARAM_PVS.POL_MON in self.properties_all: + self[self.PARAM_PVS.POL_MON] + else: + return _IDSearch.POL_UNDEF_STR + + # --- pparameter --- @property def pparameter_parked(self): """Return ID parked pparameter value [mm].""" - return self.parameters.PPARAM_PARKED + if self.PARAM_PVS.PPARAM_PARKED_CTE in self.properties_all: + return self[self.PARAM_PVS.PPARAM_PARKED_CTE] + else: + return self.parameters.PPARAM_PARKED + + @property + def pparameter_speed_max(self): + """Return max pparameter speed readback [mm/s].""" + return self[self.PARAM_PVS.PPARAM_MAXVELO_RB] + + @pparameter_speed_max.setter + def pparameter_speed_max(self, value): + """Set max pparameter speed readback [mm/s].""" + self[self.PARAM_PVS.PPARAM_MAXVELO_SP] = value + + @property + def pparameter_speed_max_lims(self): + """Return max pparameter speed limits.""" + ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_MAXVELO_SP) + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def pparameter_speed(self): + """Return pparameter speed readback [mm/s].""" + return self[self.PARAM_PVS.PPARAM_VELO_SP] + + @property + def pparameter_lims(self): + """Return ID pparameter lower control limit [mm].""" + ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_SP) + return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + + @property + def pparameter(self): + """Return ID pparameter readback [mm].""" + return self[self.PARAM_PVS.PPARAM_RB] + + @pparameter.setter + def pparameter(self, value): + """Set ID pparameter value [mm].""" + self[self.PARAM_PVS.PPARAM_SP] = value + + @property + def pparameter_mon(self): + """Return ID pparameter monitor [mm].""" + return self[self.PARAM_PVS.PPARAM_MON] + + def pparameter_set(self, pparam, timeout=None): + """Set ID target pparameter for movement [mm].""" + return self._write_sp(self.PARAM_PVS.PPARAM_SP, pparam, timeout) + + def pparameter_speed_set(self, pparam_speed, timeout=None): + """Command to set ID cruise pparam speed for movement [mm/s].""" + return self._write_sp( + self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed, timeout) + + def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): + """Command to set ID max cruise pparam speed for movement [mm/s].""" + return self._write_sp( + self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed_max, timeout) + + # --- kparameter --- @property def kparameter_parked(self): """Return ID parked kparameter value [mm].""" - return self.parameters.KPARAM_PARKED + if self.PARAM_PVS.KPARAM_PARKED_CTE in self.properties_all: + return self[self.PARAM_PVS.KPARAM_PARKED_CTE] + else: + return self.parameters.KPARAM_PARKED - # --- movement checks --- + @property + def kparameter_speed_max(self): + """Return max kparameter speed readback [mm/s].""" + return self[self.PARAM_PVS.KPARAM_MAXVELO_RB] + + @kparameter_speed_max.setter + def kparameter_speed_max(self, value): + """Set max kparameter speed readback [mm/s].""" + self[self.PARAM_PVS.KPARAM_MAXVELO_SP] = value + + @property + def kparameter_speed_max_lims(self): + """Return max kparameter speed limits.""" + ctrl = self.pv_ctrlvars(self.PARAM_PVS.KPARAM_MAXVELO_SP) + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def kparameter_speed(self): + """Return kparameter speed readback [mm/s].""" + return self[self.PARAM_PVS.KPARAM_VELO_SP] + + @property + def kparameter_speed_mon(self): + """Return kparameter speed monitor [mm/s].""" + if self.PARAM_PVS.KPARAM_VELO_MON in self.properties_all: + return self[self.PARAM_PVS.KPARAM_VELO_MON] + else: + raise TypeError('ID does not have speed_mon PV!') + + @property + def kparameter_lims(self): + """Return ID kparameter lower control limit [mm].""" + ctrl = self.pv_ctrlvars(self.PARAM_PVS.KPARAM_SP) + return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + + @property + def kparameter(self): + """Return ID kparameter readback [mm].""" + return self[self.PARAM_PVS.KPARAM_RB] + + @kparameter.setter + def kparameter(self, value): + """Set ID kparameter value [mm].""" + self[self.PARAM_PVS.KPARAM_SP] = value + + @property + def kparameter_mon(self): + """Return ID kparameter monitor [mm].""" + return self[self.PARAM_PVS.KPARAM_MON] + + def kparameter_set(self, kparam, timeout=None): + """Set ID target kparameter for movement [mm].""" + return self._write_sp(self.PARAM_PVS.KPARAM_SP, kparam, timeout) + + def kparameter_speed_set(self, kparam_speed, timeout=None): + """Command to set ID cruise kparam speed for movement [mm/s].""" + return self._write_sp( + self.PARAM_PVS.KPARAM_VELO_SP, kparam_speed, timeout) + + def kparameter_speed_max_set(self, kparam_speed_max, timeout=None): + """Command to set ID max cruise kparam speed for movement [mm/s].""" + return self._write_sp( + self.PARAM_PVS.KPARAM_MAXVELO_SP, kparam_speed_max, timeout) + + # --- checks --- @property def is_moving(self): """Return True if phase is changing.""" return round(self['Moving-Mon']) == 1 + @property + def is_beamline_ctrl_enabled(self): + """Return beamline control enabled state (True|False).""" + return self['BeamLineCtrlEnbl-Sts'] != 0 + # --- cmd_beamline and cmd_drive def cmd_beamline_ctrl_enable(self, timeout=None): @@ -69,18 +270,149 @@ def wait_while_busy(self, timeout=None): """Command wait within timeout while ID control is busy.""" return True - # --- cmd_wait + def cmd_wait_move_start(self, timeout=None): + """Wait for movement to start.""" + return self._wait('Moving-Mon', 1, timeout) - def cmd_wait_move(self, timeout=None): - """Wait for phase movement to complete.""" - _time.sleep(APU._MOVECHECK_SLEEP) - t0_ = _time.time() - while self.is_moving: - _time.sleep(APU._MOVECHECK_SLEEP) - if timeout and _time.time() - t0_ > timeout: + def cmd_wait_move_finish(self, timeout=None): + """Wait for movement to finish.""" + return self._wait('Moving-Mon', 0, timeout) + + # --- cmd_move --- + + def cmd_move_disable(self): + """Command to disable and break ID movements.""" + return True + + def cmd_move_enable(self): + """Command to enable ID movements.""" + return True + + def cmd_move_stop(self, timeout=None): + """Command to interrupt and then enable phase movements.""" + timeout = timeout or self._DEF_TIMEOUT + + # wait for not busy state + if not self.wait_while_busy(timeout=timeout): + return False + + # send stop command + self.cmd_move_disable() + + # check for successful stop + if not self.wait_while_busy(timeout=timeout): + return False + if not self.cmd_wait_move_finish(timeout=timeout): + return False + + # enable movement again + if not self.cmd_move_enable(timeout=timeout): + return False + + return True + + def cmd_move_start(self, timeout=None): + """Command to start movement.""" + success = True + success &= self.cmd_move_pparameter_start(timeout=timeout) + success &= self.cmd_move_kparameter_start(timeout=timeout) + return success + + def cmd_move_pparameter_start(self, timeout=None): + """Command to start Pparameter movement.""" + return self._move_start( + self.PARAM_PVS.PPARAM_CHANGE_CMD, timeout=timeout) + + def cmd_move_kparameter_start(self, timeout=None): + """Command to start Kparameter movement.""" + return self._move_start( + self.PARAM_PVS.KPARAM_CHANGE_CMD, timeout=timeout) + + def cmd_change_polarization_start(self, timeout=None): + """Change polarization.""" + return self._move_start( + self.PARAM_PVS.POL_CHANGE_CMD, timeout=timeout) + + def cmd_move_park(self, timeout=None): + """Move ID to parked config.""" + return self._move_start( + self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) + + def cmd_move(self, pparam, kparam, timeout=None): + """Command to set and start pparam and kparam movements.""" + # calc ETA + dtime_kparam = \ + abs(kparam - self.kparameter_mon) / self.kparameter_speed + dtime_pparam = 0 if pparam is None else \ + abs(pparam - self.pparameter_mon) / self.pparameter_speed + dtime_max = max(dtime_kparam, dtime_pparam) + + # additional percentual in ETA + tol_kparam = self.parameters.KPARAM_TOL # [mm] + tol_pparam = self.parameters.PPARAM_TOL # [mm] + tol_dtime = 300 # [%] + tol_factor = (1 + tol_dtime/100) + tol_total = tol_factor * dtime_max + 5 + + # set target phase and gap + if not self.pparameter_set(phase=pparam, timeout=timeout): + return False + if not self.kparameter_set(gap=kparam, timeout=timeout): + return False + + # command move start + if not self.cmd_move_pparameter_start(timeout=timeout): + return False + if not self.cmd_move_kparameter_start(timeout=timeout): + return False + + # wait for movement within reasonable time + time_init = _time.time() + while True: + condk = abs(self.kparameter_mon - kparam) <= tol_kparam + if dtime_pparam == 0: + if condk and not self.is_moving: + break + else: + condp = abs(self.pparameter_mon - pparam) <= tol_pparam + if condk and condp and not self.is_moving: + break + if _time.time() - time_init > tol_total: + print(f'tol_total: {tol_total:.3f} s') + print(f'wait_time: {_time.time() - time_init:.3f} s') + print() return False + _time.sleep(self._SHORT_SHUT_EYE) + + # successfull movement at this point return True + def cmd_change_polarization(self, polarization, timeout=None): + """.""" + if self.PARAM_PVS.POL_SEL not in self.properties_all: + return True + if self.PARAM_PVS.POL_MON not in self.properties_all: + return True + + t0_ = _time.time() + + # set desired polarization + if not self._write_sp( + self.PARAM_PVS.POL_SEL, polarization, timeout=timeout): + return False + t1_ = _time.time() + timeout = max(0, timeout - (t1_ - t0_)) + + # send change polarization command + if not self.cmd_change_polarization_start(timeout=timeout): + return False + t2_ = _time.time() + timeout = max(0, timeout - (t2_ - t0_)) + + # wait for polarization value within timeout + return self._wait( + self.PARAM_PVS.POL_MON, polarization, timeout=timeout, comp='eq') + # --- private methods --- def _move_start(self, cmd_propty, timeout=None): @@ -90,8 +422,9 @@ def _move_start(self, cmd_propty, timeout=None): if not self.wait_while_busy(timeout=timeout): return False - # send move command - self[cmd_propty] = 1 + if cmd_propty in self.properties_all: + # send move command + self[cmd_propty] = 1 return True @@ -138,7 +471,41 @@ class DEVICES: ALL = ( APU22_06SB, APU22_07SP, APU22_08SB, APU22_09SA, APU58_11SP, ) - TOLERANCE_PHASE = 0.01 # [mm] + class PARAM_PVS: + """.""" + + # --- GENERAL --- + PERIOD_LEN_CTE = None + START_PARKING_CMD = None + # --- PPARAM --- + PPARAM_SP = None + PPARAM_RB = None + PPARAM_MON = None + PPARAM_PARKED_CTE = None + PPARAM_MAXVELO_SP = None + PPARAM_MAXVELO_RB = None + PPARAM_VELO_SP = None + PPARAM_VELO_RB = None + PPARAM_VELO_MON = None + PPARAM_CHANGE_CMD = None + # --- KPARAM --- + KPARAM_SP = 'Phase-SP' + KPARAM_RB = 'Phase-SP' # There is no Phase-RB! + KPARAM_MON = 'Phase-Mon' + KPARAM_PARKED_CTE = None + KPARAM_MAXVELO_SP = 'MaxPhaseSpeed-SP' + KPARAM_MAXVELO_RB = 'MaxPhaseSpeed-RB' + KPARAM_VELO_SP = 'PhaseSpeed-SP' + KPARAM_VELO_RB = 'PhaseSpeed-RB' + KPARAM_VELO_MON = 'PhaseSpeed-Mon' + KPARAM_CHANGE_CMD = 'DevCtrl-Cmd' + # --- POL --- + POL_SEL = None + POL_STS = None + POL_MON = None + POL_CHANGE_CMD = None + + TOLERANCE_PHASE = 0.01 # [mm] # TODO: this should be in IDSearch _CMD_MOVE_STOP, _CMD_MOVE_START = 1, 3 _CMD_MOVE = 3 @@ -166,53 +533,39 @@ def __init__(self, devname, props2init='all', auto_monitor_mon=True): @property def phase_speed(self): """Return phase speed [mm/s].""" - return self['PhaseSpeed-RB'] + return self.kparameter_speed @property def phase_speed_mon(self): """Return phase speed monitor [mm/s].""" - return self['PhaseSpeed-Mon'] + return self.kparameter_speed_mon @property def phase_speed_max(self): """Return max phase speed readback [mm/s].""" - return self['MaxPhaseSpeed-RB'] + return self.kparameter_speed_max @property def phase_speed_max_lims(self): """Return max phase speed limits.""" - ctrl = self.pv_ctrlvars('MaxPhaseSpeed-SP') - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims + return self.kparameter_speed_max_lims # --- phase --- - @property - def phase_parked(self): - """Return ID parked phase value [mm].""" - return self.period_length / 2 - @property def phase(self): """Return APU phase [mm].""" - return self['Phase-SP'] + return self.kparameter @property - def phase_min(self): + def phase_lims(self): """Return ID phase lower control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Phase-SP') - return ctrlvars['lower_ctrl_limit'] - - @property - def phase_max(self): - """Return ID phase upper control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Phase-SP') - return ctrlvars['upper_ctrl_limit'] + return self.kparameter_lims @property def phase_mon(self): """Return APU phase [mm].""" - return self['Phase-Mon'] + return self.kparameter_mon # --- Kparam methods --- @@ -230,11 +583,11 @@ def idkx(self, value): def set_phase(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" - return self._write_sp('Phase-SP', phase, timeout) + return self.kparameter_set(phase, timeout) def set_phase_speed(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" - return self._write_sp('PhaseSpeed-SP', phase_speed, timeout) + return self.kparameter_speed_set(phase_speed, timeout) def set_phase_speed_max(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" @@ -244,12 +597,12 @@ def set_phase_speed_max(self, phase_speed_max, timeout=None): def cmd_move_stop(self, timeout=None): """Send command to stop ID movement.""" - self['DevCtrl-Cmd'] = APU._CMD_MOVE_STOP + self['DevCtrl-Cmd'] = self._CMD_MOVE_STOP return True def cmd_move_start(self, timeout=None): """Send command to start ID movement.""" - self['DevCtrl-Cmd'] = APU._CMD_MOVE_START + self['DevCtrl-Cmd'] = self._CMD_MOVE_START return True def cmd_move_park(self, timeout=None): @@ -306,6 +659,40 @@ class DEVICES: PAPU50_17SA = 'SI-17SA:ID-PAPU50' ALL = (PAPU50_17SA, ) + class PARAM_PVS: + """.""" + + # --- GENERAL --- + PERIOD_LEN_CTE = 'PeriodLength-Cte' + START_PARKING_CMD = None + # --- PPARAM --- + PPARAM_SP = None + PPARAM_RB = None + PPARAM_MON = None + PPARAM_PARKED_CTE = None + PPARAM_MAXVELO_SP = None + PPARAM_MAXVELO_RB = None + PPARAM_VELO_SP = None + PPARAM_VELO_RB = None + PPARAM_VELO_MON = None + PPARAM_CHANGE_CMD = None + # --- KPARAM --- + KPARAM_SP = 'Phase-SP' + KPARAM_RB = 'Phase-RB' + KPARAM_MON = 'Phase-Mon' + KPARAM_PARKED_CTE = 'ParkedPhase-Cte' + KPARAM_MAXVELO_SP = 'MaxPhaseSpeed-SP' + KPARAM_MAXVELO_RB = 'MaxPhaseSpeed-RB' + KPARAM_VELO_SP = 'PhaseSpeed-SP' + KPARAM_VELO_RB = 'PhaseSpeed-RB' + KPARAM_VELO_MON = 'PhaseSpeed-Mon' + KPARAM_CHANGE_CMD = 'ChangePhase-Cmd' + # --- POL --- + POL_SEL = None + POL_STS = None + POL_MON = None + POL_CHANGE_CMD = None + TOLERANCE_PHASE = 0.01 # [mm] _SHORT_SHUT_EYE = 0.1 # [s] @@ -357,17 +744,17 @@ def log_mon(self): @property def phase_speed(self): """Return phase speed readback [mm/s].""" - return self['PhaseSpeed-RB'] + return self.kparameter_speed @property def phase_speed_mon(self): """Return phase speed monitor [mm/s].""" - return self['PhaseSpeed-Mon'] + return self.kparameter_speed_mon @property def phase_speed_max(self): """Return max phase speed readback [mm/s].""" - return self['MaxPhaseSpeed-RB'] + return self.kparameter_speed_max @property def phase_speed_max_lims(self): @@ -381,29 +768,22 @@ def phase_speed_max_lims(self): @property def phase_parked(self): """Return ID parked phase value [mm].""" - return self['ParkedPhase-Cte'] + return self.kparameter_parked @property def phase(self): """Return ID phase readback [mm].""" - return self['Phase-RB'] + return self.kparameter @property - def phase_min(self): - """Return ID phase lower control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Phase-SP') - return ctrlvars['lower_ctrl_limit'] - - @property - def phase_max(self): - """Return ID phase upper control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Phase-SP') - return ctrlvars['upper_ctrl_limit'] + def phase_lims(self): + """Return ID phase limits [mm].""" + return self.kparameter_lims @property def phase_mon(self): """Return ID phase monitor [mm].""" - return self['Phase-Mon'] + return self.kparameter_mon # --- drive checks --- @@ -429,11 +809,6 @@ def is_homing(self): """Return whether ID is in homing procedure (True|False).""" return self['Home-Mon'] != 0 - @property - def is_beamline_ctrl_enabled(self): - """Return beamline control enabled state (True|False).""" - return self['BeamLineCtrlEnbl-Sts'] != 0 - # --- cmd_drive def cmd_drive_turn_power_on(self, timeout=None): @@ -448,15 +823,15 @@ def cmd_drive_turn_power_on(self, timeout=None): def set_phase(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" - return self._write_sp('Phase-SP', phase, timeout) + return self.kparameter_set(phase, timeout) def set_phase_speed(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" - return self._write_sp('PhaseSpeed-SP', phase_speed, timeout) + return self.kparameter_speed_set(phase_speed, timeout) def set_phase_speed_max(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" - return self._write_sp('MaxPhaseSpeed-SP', phase_speed_max, timeout) + return self.kparameter_speed_max_set(phase_speed_max, timeout) # --- cmd_move disable/enable --- @@ -482,88 +857,16 @@ def cmd_move_disable(self, timeout=None): """Command to disable and break ID phase and gap movements.""" return self.cmd_move_phase_disable(timeout=timeout) - def wait_move_start(self, timeout=None): - """Command wait until movement starts or timeout.""" - time_init = _time.time() - while not self.is_moving: - if timeout is not None and _time.time() - time_init > timeout: - return False - return True - # -- cmd_move - def cmd_move_stop(self, timeout=None): - """Command to interrupt and then enable phase movements.""" - timeout = timeout or self._DEF_TIMEOUT - - # wait for not busy state - if not self.wait_while_busy(timeout=timeout): - return False - - # send stop command - self.cmd_move_disable() - - # check for successful stop - if not self.wait_while_busy(timeout=timeout): - return False - - success = True - success &= super()._wait('Moving-Mon', 0, timeout=timeout) - - if not success: - return False - - # enable movement again - status = self.cmd_move_enable(timeout=timeout) - - return status - - def cmd_move_start(self, timeout=None): - """Command to start movement.""" - success = True - success &= self.cmd_move_phase_start(timeout=timeout) - return success - def cmd_move_phase_start(self, timeout=None): """Command to start phase movement.""" - return self._move_start('ChangePhase-Cmd', timeout=timeout) + return self.cmd_move_kparameter_start(timeout=timeout) def cmd_move_park(self, timeout=None): """Command to set and start ID movement to parked config.""" - return self.move(self.phase_parked, timeout=timeout) - - def move(self, phase, timeout=None): - """Command to set and start phase movements.""" - # calc ETA - dtime_max = abs(phase - self.phase_mon) / self.phase_speed - - # additional percentual in ETA - tol_dtime = 300 # [%] - tol_factor = (1 + tol_dtime/100) - tol_total = tol_factor * dtime_max + 5 - - # set target phase and gap - if not self.set_phase(phase=phase, timeout=timeout): - return False - - # command move start - if not self.cmd_move_phase_start(timeout=timeout): - return False - - # wait for movement within reasonable time - time_init = _time.time() - while \ - abs(self.phase_mon - phase) > self.TOLERANCE_PHASE or \ - self.is_moving: - if _time.time() - time_init > tol_total: - print(f'tol_total: {tol_total:.3f} s') - print(f'wait_time: {_time.time() - time_init:.3f} s') - print() - return False - _time.sleep(self._SHORT_SHUT_EYE) - - # successfull movement at this point - return True + return self.cmd_move( + pparam=None, kparam=self.phase_parked, timeout=timeout) # --- cmd_reset @@ -581,35 +884,6 @@ def cmd_clear_error(self): """Command to clear errors.""" self['ClearErr-Cmd'] = 1 - # --- private methods --- - - def _write_sp(self, propties_sp, values, timeout=None): - timeout = timeout or self._DEF_TIMEOUT - if isinstance(propties_sp, str): - propties_sp = (propties_sp, ) - values = (values, ) - success = True - for propty_sp, value in zip(propties_sp, values): - propty_rb = propty_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') - if not self.wait_while_busy(timeout=timeout): - return False - self[propty_sp] = value - success &= super()._wait( - propty_rb, value, timeout=timeout, comp='eq') - return success - - def _wait_propty_values(self, props_values, timeout=None, comp='eq'): - timeout = timeout if timeout is not None else self._DEF_TIMEOUT - time0 = _time.time() - for propty, value in props_values.items(): - timeout_left = max(0, timeout - (_time.time() - time0)) - if timeout_left == 0: - return False - if not super()._wait( - propty, value, timeout=timeout_left, comp=comp): - return False - return True - class EPU(PAPU): """EPU Insertion Device.""" @@ -747,7 +1021,7 @@ def cmd_drive_turn_power_on(self, timeout=None): return True self['EnblPwrAll-Cmd'] = 1 props_values = {'PwrPhase-Mon': 1, 'PwrGap-Mon': 1} - return self._wait_propty_values(props_values, timeout=timeout) + return self._wait_set(props_values, timeout=timeout) # --- set methods --- @@ -882,19 +1156,27 @@ class DEVICES: ALL = (DELTA52_10SB, ) PROPERTIES_DEFAULT = _ID.PROPERTIES_DEFAULT + ( + 'CSDVirtPos-Mon', 'CSEVirtPos-Mon', + 'CIEVirtPos-Mon', 'CIDVirtPos-Mon', + 'IsOperational-Mon', 'MotorsEnbld-Mon', + 'Alarm-Mon', 'Intlk-Mon', 'IntlkBits-Mon', 'IntlkLabels-Cte', + 'ConsistentSetPoints-Mon', 'PLCState-Mon', 'Pol-Sel', 'Pol-Sts', 'Pol-Mon', - 'ChangePol-Cmd', + 'PolChange-Cmd', + 'KValue-SP', 'KValue-RB', 'KValue-Mon', + 'Energy-SP', 'Energy-RB', 'Energy-Mon', 'MaxVelo-SP', 'MaxVelo-RB', - 'ParkedPParam-Cte', + 'PParamParked-Cte', 'PParam-SP', 'PParam-RB', 'PParam-Mon', - 'ChangePParam-Cmd', + 'PParamChange-Cmd', 'PParamVelo-SP', 'PParamVelo-RB', 'PParamAcc-SP', 'PParamAcc-RB', - 'ParkedKParam-Cte', + 'KParamParked-Cte', 'KParam-SP', 'KParam-RB', 'KParam-Mon', - 'ChangeKParam-Cmd', + 'KParamChange-Cmd', 'KParamVelo-SP', 'KParamVelo-RB', 'KParamAcc-SP', 'KParamAcc-RB', + 'StartParking-Cmd', ) def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): @@ -909,212 +1191,64 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) - # --- polarization --- + # --- cassette positions --- @property - def polarization(self): - """Return ID polarization.""" - return self['Pol-Sts'] + def pos_csd_mon(self): + """Return longitudinal position of CSD [mm]. - @polarization.setter - def polarization(self, value): - """Set ID polarization.""" - self['Pol-Sel'] = value + cassette positions x (PParam, KParam): + pos_cid = PParam + pos_cse = PParam + KParam + pos_csd = KParam + pos_cie = 0 + """ + return self['CSDVirtPos-Mon'] @property - def polarization_mon(self): - """Return ID polarization monitor.""" - return self['Pol-Mon'] + def pos_cse_mon(self): + """Return longitudinal position of CSE [mm]. - # --- pparameter --- + cassette positions x (PParam, KParam): + pos_cid = PParam + pos_cse = PParam + KParam + pos_csd = KParam + pos_cie = 0 + """ + return self['CSEVirtPos-Mon'] @property - def pparameter_parked(self): - """Return ID parked pparameter value [mm].""" - return self['ParkedPParam-Cte'] + def pos_cie_mon(self): + """Return longitudinal position of CIE [mm]. - @property - def pparameter_speed_max(self): - """Return max pparameter speed readback [mm/s].""" - return self['MaxVelo-RB'] + cassette positions x (PParam, KParam): + pos_cid = PParam + pos_cse = PParam + KParam + pos_csd = KParam + pos_cie = 0 + """ + return self['CIEVirtPos-Mon'] @property - def pparameter_speed_max_lims(self): - """Return max pparameter speed limits.""" - ctrl = self.pv_ctrlvars('MaxVelo-SP') - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims + def pos_cid_mon(self): + """Return longitudinal position of CID [mm]. - @property - def pparameter_speed(self): - """Return pparameter speed readback [mm/s].""" - return self['PParamVelo-RB'] + cassette positions x (PParam, KParam): + pos_cid = PParam + pos_cse = PParam + KParam + pos_csd = KParam + pos_cie = 0 + """ + return self['CIDVirtPos-Mon'] - @property - def pparameter_lims(self): - """Return ID pparameter lower control limit [mm].""" - ctrl = self.pv_ctrlvars('PParam-Mon') - return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - - @property - def pparameter(self): - """Return ID pparameter readback [mm].""" - return self['KParam-RB'] - - @property - def pparameter_mon(self): - """Return ID pparameter monitor [mm].""" - return self['PParam-Mon'] - - def set_pparameter(self, kparam, timeout=None): - """Set ID target pparameter for movement [mm].""" - return self._write_sp('PParam-SP', kparam, timeout) - - def set_pparameter_speed(self, pparam_speed, timeout=None): - """Command to set ID cruise pparam speed for movement [mm/s].""" - return self._write_sp('PParamVelo-SP', pparam_speed, timeout) - - def set_pparameter_speed_max(self, pparam_speed_max, timeout=None): - """Command to set ID max cruise pparam speed for movement [mm/s].""" - return self._write_sp('MaxVelo-SP', pparam_speed_max, timeout) - - # --- kparameter --- - - @property - def kparameter_parked(self): - """Return ID parked kparameter value [mm].""" - return self['ParkedKParam-Cte'] - - @property - def kparameter_speed_max(self): - """Return max kparameter speed readback [mm/s].""" - return self['MaxVelo-RB'] - - @property - def kparameter_speed_max_lims(self): - """Return max kparameter speed limits.""" - ctrl = self.pv_ctrlvars('MaxVelo-SP') - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims - - @property - def kparameter_speed(self): - """Return kparameter speed readback [mm/s].""" - return self['KParamVelo-RB'] - - @property - def kparameter_lims(self): - """Return ID kparameter lower control limit [mm].""" - ctrl = self.pv_ctrlvars('KParam-Mon') - return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - - @property - def kparameter(self): - """Return ID kparameter readback [mm].""" - return self['KParam-RB'] - - @property - def kparameter_mon(self): - """Return ID kparameter monitor [mm].""" - return self['KParam-Mon'] - - # --- set methods --- - - def set_kparameter(self, kparam, timeout=None): - """Command to set ID target kparameter for movement [mm].""" - return self._write_sp('KParam-SP', kparam, timeout) - - def set_kparameter_speed(self, kparam_speed, timeout=None): - """Command to set ID cruise kparam speed for movement [mm/s].""" - return self._write_sp('KParamVelo-SP', kparam_speed, timeout) - - def set_kparameter_speed_max(self, kparam_speed_max, timeout=None): - """Command to set ID max cruise kparam speed for movement [mm/s].""" - return self._write_sp('MaxVelo-SP', kparam_speed_max, timeout) - - # --- commands --- - - def cmd_move_start(self, timeout=None): - """Command to start movement.""" - success = True - success &= self.cmd_move_pparam_start(timeout=timeout) - success &= self.cmd_move_kparam_start(timeout=timeout) - return success - - def cmd_move_pparam_start(self, timeout=None): - """Command to start Pparameter movement.""" - return self._move_start('ChangePParam-Cmd', timeout=timeout) - - def cmd_move_kparam_start(self, timeout=None): - """Command to start Kparameter movement.""" - return self._move_start('ChangeKParam-Cmd', timeout=timeout) - - def cmd_change_polarization_start(self, timeout=None): - """Change polarization.""" - _ = timeout - self['ChangePol-Cmd'] = 1 - - def cmd_move_park(self, timeout=None): - """Move ID to parked config.""" - return self.move( - self.pparameter_parked, self.kparameter_parked, timeout=timeout) - - def move(self, pparam, kparam, timeout=None): - """Command to set and start pparam and kparam movements.""" - # calc ETA - dtime_phase = abs(pparam - self.pparameter_mon) / self.pparameter_speed - dtime_gap = abs(kparam - self.kparameter_mon) / self.kparameter_speed - dtime_max = max(dtime_phase, dtime_gap) - - # additional percentual in ETA - tol_gap = 0.01 # [mm] - tol_phase = 0.01 # [mm] - tol_dtime = 300 # [%] - tol_factor = (1 + tol_dtime/100) - tol_total = tol_factor * dtime_max + 5 - - # set target phase and gap - if not self.set_pparameter(phase=pparam, timeout=timeout): - return False - if not self.set_kparameter(gap=kparam, timeout=timeout): - return False - - # command move start - if not self.cmd_move_pparam_start(timeout=timeout): - return False - if not self.cmd_move_kparam_start(timeout=timeout): - return False - - # wait for movement within reasonable time - time_init = _time.time() - while \ - abs(self.kparameter_mon - kparam) > tol_gap or \ - abs(self.pparameter_mon - pparam) > tol_phase or \ - self.is_moving: - if _time.time() - time_init > tol_total: - print(f'tol_total: {tol_total:.3f} s') - print(f'wait_time: {_time.time() - time_init:.3f} s') - print() - return False - _time.sleep(self._SHORT_SHUT_EYE) - - # successfull movement at this point - return True + # --- cmd_wait - def change_polarization(self, polarization, timeout=None): - """.""" - t0_ = _time.time() - # set desired polarization - if not self._write_sp('Pol-Sel', polarization, timeout=timeout): - return False - # send change polarization command - self['ChangePol-Cmd'] = 1 - timeout -= _time.time() - t0_ - # wait for polarization value within timeout - return self._wait('Pol-Mon', polarization, timeout=timeout, comp='eq') + def wait_while_busy(self, timeout=None): + """Command wait within timeout while ID control is busy.""" + return self.cmd_wait_move_finish(timeout) -class WIG(_Device): +class WIG(_ID): """Wiggler Insertion Device.""" class DEVICES: diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index 918448697..d23eb0912 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -44,6 +44,30 @@ class IDSearch: ) _idname2params = { + 'SI-06SB:ID-APU22': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 22, + 0, 11, 11, 0, 0.1, + None, None, None, None)), + 'SI-07SP:ID-APU22': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 22, + 0, 11, 11, 0, 0.1, + None, None, None, None)), + 'SI-08SB:ID-APU22': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 22, + 0, 11, 11, 0, 0.1, + None, None, None, None)), + 'SI-09SA:ID-APU22': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 22, + 0, 11, 11, 0, 0.1, + None, None, None, None)), # NOTE: for EPU50 there is a large discrepancy # between RB/SP/Mon phase values 'SI-10SB:ID-EPU50': _get_namedtuple( @@ -58,6 +82,24 @@ class IDSearch: 52.5, -52.5/2, +52.5/2, 0, 0, 0.1, -52.5/2, +52.5/2, 0, 0.1)), + 'SI-11SP:ID-APU58': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 58, + 0, 29, 29, 0, 0.1, + None, None, None, None)), + 'SI-14SB:ID-WIG180': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 180, + 49.73, 49.73, 150, 150, 0.1, + None, None, None, None)), + 'SI-17SA:ID-PAPU50': _get_namedtuple( + 'IDParameters', + _idparam_fields, ( + 50, + 0, 25, 25, 0, 0.1, + None, None, None, None)), } POL_NONE_STR = 'none' From 1c252ac7cd2a1f0674c6d61bb756bd8b6792701e Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 17 Nov 2023 11:29:03 -0300 Subject: [PATCH 108/309] ORBINLKT.FIX: fix bug in RxLockedLtc-Mon check when configuring Fout RxEnbl --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f3df6f46c..c1a23b1d5 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -797,7 +797,7 @@ def _config_fout_rxenbl(self): dev._wait('RxEnbl-RB', rxenbl) dev['RxLockedLtcRst-Cmd'] = 1 if rxenbl: - dev._wait('RxLockedLtc-Mon', 1) + dev._wait('RxLockedLtc-Mon', rxenbl) return True From 8a9f69f6d9547d119db2ad6b3613d0fdab9deea9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 17 Nov 2023 11:29:57 -0300 Subject: [PATCH 109/309] ORBINTLK.MNT: sort TimingMonitoredDevices-Mon PV --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c1a23b1d5..96d29a5cb 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -819,7 +819,7 @@ def _get_ti_monitored_devices(self): value.add(foutout) evgout = _LLTimeSearch.get_evg_channel(foutout) value.add(evgout) - return value + return sorted(value) def _check_devices_status(self, devices): for devname in devices: From da42f2727baabfd213ddc1e9321f33a0b2bb2f9c Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 17 Nov 2023 17:36:49 -0300 Subject: [PATCH 110/309] Fix bugs in device and id_search --- siriuspy/siriuspy/devices/device.py | 9 +++++---- siriuspy/siriuspy/search/id_search.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 826abf542..5d2c12e18 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -78,19 +78,20 @@ def devname(self): @property def properties_in_use(self): """Return properties that were already added to the PV list.""" - return sorted(self._pvs.keys()) + return tuple(sorted(self._pvs.keys())) @property def properties_added(self): """Return properties that were added to the PV list that are not in PROPERTIES_DEFAULT.""" - return sorted( - set(self.properties_in_use) - set(self.PROPERTIES_DEFAULT)) + return tuple(sorted( + set(self.properties_in_use) - set(self.PROPERTIES_DEFAULT))) @property def properties_all(self): """Return all properties of the device, connected or not.""" - return sorted(set(self.PROPERTIES_DEFAULT + self.properties_in_use)) + return tuple(sorted(set( + self.PROPERTIES_DEFAULT + self.properties_in_use))) @property def simulators(self): diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index d23eb0912..987d75c81 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -309,7 +309,7 @@ def conv_idname_2_polarization_pparameter(idname, pol): if isinstance(pol, int): return pols[pol][1] elif isinstance(pol, str): - for _, (pol_name, pol_pparam) in pols: + for pol_name, pol_pparam in pols.values(): if pol == pol_name: return pol_pparam raise ValueError(f'Invalid polarization string "{pol}"') From 7da2b087423916649645d7ade7cea0714099799d Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 21 Nov 2023 10:16:49 -0300 Subject: [PATCH 111/309] Add indep. KParam and PParam movements to DELTA --- siriuspy/siriuspy/devices/ids.py | 135 ++++++++++++++++++++------ siriuspy/siriuspy/search/id_search.py | 2 +- 2 files changed, 109 insertions(+), 28 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 0c03892a6..2186dc7d2 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -58,6 +58,10 @@ def __init__(self, devname, props2init='all', auto_monitor_mon=True): # call base class constructor super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + self._pols_sel_str = \ + _IDSearch.conv_idname_2_polarizations(self.devname) + self._pols_sts_str = \ + _IDSearch.conv_idname_2_polarizations_sts(self.devname) # --- general --- @@ -82,12 +86,20 @@ def polarization(self): if self.PARAM_PVS.POL_STS in self.properties_all: return self[self.PARAM_PVS.POL_STS] else: - return _IDSearch.POL_UNDEF_STR + return self._pols_sts_str.index(_IDSearch.POL_UNDEF_STR) + + @property + def polarization_str(self): + """Return ID polarization string.""" + pol_idx = self.polarization + return self._pols_sts_str[pol_idx] @polarization.setter def polarization(self, value): """Set ID polarization.""" if self.PARAM_PVS.POL_SEL in self.properties_all: + if isinstance(value, str): + value = self._pols_sel_str.index(value) self[self.PARAM_PVS.POL_SEL] = value else: raise TypeError('ID type does not define polarizations!') @@ -96,7 +108,7 @@ def polarization(self, value): def polarization_mon(self): """Return ID polarization monitor.""" if self.PARAM_PVS.POL_MON in self.properties_all: - self[self.PARAM_PVS.POL_MON] + return self[self.PARAM_PVS.POL_MON] else: return _IDSearch.POL_UNDEF_STR @@ -115,11 +127,6 @@ def pparameter_speed_max(self): """Return max pparameter speed readback [mm/s].""" return self[self.PARAM_PVS.PPARAM_MAXVELO_RB] - @pparameter_speed_max.setter - def pparameter_speed_max(self, value): - """Set max pparameter speed readback [mm/s].""" - self[self.PARAM_PVS.PPARAM_MAXVELO_SP] = value - @property def pparameter_speed_max_lims(self): """Return max pparameter speed limits.""" @@ -143,11 +150,6 @@ def pparameter(self): """Return ID pparameter readback [mm].""" return self[self.PARAM_PVS.PPARAM_RB] - @pparameter.setter - def pparameter(self, value): - """Set ID pparameter value [mm].""" - self[self.PARAM_PVS.PPARAM_SP] = value - @property def pparameter_mon(self): """Return ID pparameter monitor [mm].""" @@ -165,7 +167,7 @@ def pparameter_speed_set(self, pparam_speed, timeout=None): def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): """Command to set ID max cruise pparam speed for movement [mm/s].""" return self._write_sp( - self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed_max, timeout) + self.PARAM_PVS.PPARAM_MAXVELO_SP, pparam_speed_max, timeout) # --- kparameter --- @@ -182,11 +184,6 @@ def kparameter_speed_max(self): """Return max kparameter speed readback [mm/s].""" return self[self.PARAM_PVS.KPARAM_MAXVELO_RB] - @kparameter_speed_max.setter - def kparameter_speed_max(self, value): - """Set max kparameter speed readback [mm/s].""" - self[self.PARAM_PVS.KPARAM_MAXVELO_SP] = value - @property def kparameter_speed_max_lims(self): """Return max kparameter speed limits.""" @@ -218,11 +215,6 @@ def kparameter(self): """Return ID kparameter readback [mm].""" return self[self.PARAM_PVS.KPARAM_RB] - @kparameter.setter - def kparameter(self, value): - """Set ID kparameter value [mm].""" - self[self.PARAM_PVS.KPARAM_SP] = value - @property def kparameter_mon(self): """Return ID kparameter monitor [mm].""" @@ -353,11 +345,12 @@ def cmd_move(self, pparam, kparam, timeout=None): tol_dtime = 300 # [%] tol_factor = (1 + tol_dtime/100) tol_total = tol_factor * dtime_max + 5 + print('time: ', tol_total) # set target phase and gap - if not self.pparameter_set(phase=pparam, timeout=timeout): + if not self.pparameter_set(pparam, timeout=timeout): return False - if not self.kparameter_set(gap=kparam, timeout=timeout): + if not self.kparameter_set(kparam, timeout=timeout): return False # command move start @@ -442,8 +435,12 @@ def _write_sp(self, propties_sp, values, timeout=None, pvs_sp_rb=None): propty_rb = \ propty_sp.replace('-SP', '-RB').replace('-Sel', '-Sts') self[propty_sp] = value - success &= super()._wait( - propty_rb, value, timeout=timeout, comp='eq') + if isinstance(value, float): + success &= super()._wait_float( + propty_rb, value, timeout=timeout) + else: + success &= super()._wait( + propty_rb, value, timeout=timeout, comp='eq') return success def _wait_propty(self, propty, value, timeout=None): @@ -1191,6 +1188,11 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + @property + def is_operational(self): + """Return True if ID is operational.""" + return self['IsOperational-Mon'] != 0 + # --- cassette positions --- @property @@ -1247,6 +1249,85 @@ def wait_while_busy(self, timeout=None): """Command wait within timeout while ID control is busy.""" return self.cmd_wait_move_finish(timeout) + def cmd_move_pparam(self, pparam, timeout=None): + """Command to set and start pparam and kparam movements.""" + # calc ETA + dtime_max = abs(pparam - self.pparameter_mon) / self.pparameter_speed + + # additional percentual in ETA + tol_pparam = self.parameters.PPARAM_TOL # [mm] + tol_dtime = 300 # [%] + tol_factor = (1 + tol_dtime/100) + tol_total = tol_factor * dtime_max + 5 + print('time: ', tol_total) + + # set target phase and gap + if not self.pparameter_set(pparam, timeout=timeout): + return False + + # command move start + if not self.cmd_move_pparameter_start(timeout=timeout): + return False + + # wait for movement within reasonable time + time_init = _time.time() + while True: + condp = abs(self.pparameter_mon - pparam) <= tol_pparam + if condp and not self.is_moving: + break + if _time.time() - time_init > tol_total: + print(f'tol_total: {tol_total:.3f} s') + print(f'wait_time: {_time.time() - time_init:.3f} s') + print() + return False + _time.sleep(self._SHORT_SHUT_EYE) + + # successfull movement at this point + return True + + def cmd_move_kparam(self, kparam, timeout=None): + """Command to set and start pparam and kparam movements.""" + # calc ETA + dtime_max = abs(kparam - self.kparameter_mon) / self.kparameter_speed + + # additional percentual in ETA + tol_kparam = self.parameters.KPARAM_TOL # [mm] + tol_dtime = 300 # [%] + tol_factor = (1 + tol_dtime/100) + tol_total = tol_factor * dtime_max + 5 + print('time: ', tol_total) + + # set target phase and gap + if not self.kparameter_set(kparam, timeout=timeout): + return False + + # command move start + if not self.cmd_move_kparameter_start(timeout=timeout): + return False + + # wait for movement within reasonable time + time_init = _time.time() + while True: + condk = abs(self.kparameter_mon - kparam) <= tol_kparam + if condk and not self.is_moving: + break + if _time.time() - time_init > tol_total: + print(f'tol_total: {tol_total:.3f} s') + print(f'wait_time: {_time.time() - time_init:.3f} s') + print() + return False + _time.sleep(self._SHORT_SHUT_EYE) + + # successfull movement at this point + return True + + def cmd_move(self, pparam ,kparam, timeout=None): + """.""" + if not self.cmd_move_pparam(pparam, timeout): + return False + if not self.cmd_move_kparam(kparam, timeout): + return False + return True class WIG(_ID): """Wiggler Insertion Device.""" diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index 987d75c81..fc21b8270 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -277,7 +277,7 @@ def conv_idname_2_polarizations(idname): def conv_idname_2_polarizations_sts(idname): """Return ID polarizations (sts).""" pols = IDSearch._idname2pol_sts[idname] - return tuple(pol[0] for pol in pols) + return tuple(pol[0] for pol in pols.values()) @staticmethod def conv_idname_2_polarization_state(idname, pparameter, kparameter): From 845f8f86c013b4c44b2586e70d015ef21239c3d5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 21 Nov 2023 11:00:48 -0300 Subject: [PATCH 112/309] ORBINTLK.ENH: fix slowness issue in enable list and limit setpoint --- siriuspy/siriuspy/orbintlk/main.py | 41 +++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 96d29a5cb..fcc7434bb 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -11,7 +11,8 @@ from ..namesys import SiriusPVName as _PVName from ..search import LLTimeSearch as _LLTimeSearch, \ HLTimeSearch as _HLTimeSearch -from ..thread import RepeaterThread as _Repeat +from ..thread import RepeaterThread as _Repeat, \ + LoopQueueThread as _LoopQueueThread from ..epics import CAThread as _CAThread from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ @@ -67,6 +68,8 @@ def __init__(self, tests=True): self._lock_threads = dict() self._lock_failures = set() self._lock_suspend = False + self._set_queue = _LoopQueueThread() + self._set_queue.start() # devices and connections # # EVG @@ -497,6 +500,14 @@ def set_enable(self, value): def set_enbllist(self, intlk, value): """Set enable list for interlock type.""" + if self._state: + self._update_log('ERR:Disable interlock before changing') + self._update_log('ERR:enable lists.') + return False + self._set_queue.put((self._do_set_enbllist, (intlk, value))) + return True + + def _do_set_enbllist(self, intlk, value): intlkname = intlk.capitalize().replace('sum', 'Sum') self._update_log(f'Setting {intlkname} EnblList...') @@ -504,12 +515,16 @@ def set_enbllist(self, intlk, value): new = _np.array(value, dtype=bool) if self._const.nr_bpms != new.size: self._update_log(f'ERR:Wrong {intlkname} EnblList size.') + self.run_callbacks( + f'{intlkname}EnblList-SP', self._enable_lists[intlk]) return False # check coerence, down/up pair should have same enable state if not self._check_valid_bpmconfig(new): self._update_log('ERR:BPM should be enabled in pairs') self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') + self.run_callbacks( + f'{intlkname}EnblList-SP', self._enable_lists[intlk]) return False # check if new enable list do not imply in orbit interlock failure @@ -523,6 +538,7 @@ def set_enbllist(self, intlk, value): self._enable_lists[intlk] = bkup_enbllist self._ti_mon_devs = bkup_timondev self._config_fout_rxenbl() + self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) return False self.run_callbacks( 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) @@ -537,24 +553,26 @@ def set_enbllist(self, intlk, value): # set BPM interlock specific enable state fun = getattr(self._orbintlk_dev, f'set_{intlk}_enable') - ret = fun(list(value), return_prob=True) + ret = fun(list(value), timeout=3, return_prob=True) if not ret[0]: self._update_log(f'ERR:Could not set BPM {intlkname}') self._update_log('ERR:interlock enable.') for item in ret[1]: self._update_log(f'ERR:Verify:{item}') + self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) return False # if interlock is already enabled, update BPM general enable state if self._state and intlk in ['pos', 'ang']: glob_en = self._get_gen_bpm_intlk() ret = self._orbintlk_dev.set_gen_enable( - list(glob_en), return_prob=True) + list(glob_en), timeout=3, return_prob=True) if not ret[0]: self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') for item in ret[1]: self._update_log(f'ERR:Verify:{item}') + self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) return False # save to autosave files @@ -570,6 +588,14 @@ def set_enbllist(self, intlk, value): def set_intlk_lims(self, intlk_lim, value): """Set limits for interlock type.""" + if self._state: + self._update_log('ERR:Disable interlock before changing') + self._update_log('ERR:interlock thresholds.') + return False + self._set_queue.put((self._do_set_intlk_lims, (intlk_lim, value))) + return True + + def _do_set_intlk_lims(self, intlk_lim, value): parts = intlk_lim.split('_') if len(parts) > 1: ilk, pln, lim = parts @@ -582,12 +608,14 @@ def set_intlk_lims(self, intlk_lim, value): new = _np.array(value, dtype=int) if self._const.nr_bpms != new.size: self._update_log(f'ERR: Wrong {limname} limits size.') + self.run_callbacks(f'{limname}Lim-SP', self._limits[intlk_lim]) return False # check coerence, down/up pair should have same limits if not self._check_valid_bpmconfig(new): self._update_log('ERR:BPM pairs should have equal limits') self._update_log('ERR:(M1/M2,C1-1/C1-2,C2/C3-1,C3-2/C4)') + self.run_callbacks(f'{limname}Lim-SP', self._limits[intlk_lim]) return False self._limits[intlk_lim] = new @@ -602,12 +630,13 @@ def set_intlk_lims(self, intlk_lim, value): # set BPM interlock limits fun = getattr(self._orbintlk_dev, f'set_{intlk_lim}_thres') - ret = fun(list(value), return_prob=True) + ret = fun(list(value), timeout=3, return_prob=True) if not ret[0]: self._update_log(f'ERR:Could not set BPM {limname}') self._update_log('ERR:interlock limits.') for item in ret[1]: self._update_log(f'ERR:Verify:{item}') + self.run_callbacks(f'{limname}Lim-SP', self._limits[intlk_lim]) return False # save to autosave files @@ -794,10 +823,10 @@ def _config_fout_rxenbl(self): rxenbl = fout2rx.get(fout, 0) self._fout2rxenbl[fout] = rxenbl dev['RxEnbl-SP'] = rxenbl - dev._wait('RxEnbl-RB', rxenbl) + dev._wait('RxEnbl-RB', rxenbl, timeout=1) dev['RxLockedLtcRst-Cmd'] = 1 if rxenbl: - dev._wait('RxLockedLtc-Mon', rxenbl) + dev._wait('RxLockedLtc-Mon', rxenbl, timeout=1) return True From c97956eb09b6749d370e88dbdf5fa29a8160b31e Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 22 Nov 2023 10:01:17 -0300 Subject: [PATCH 113/309] TIM.ENH: handle cases where 2 trigger sources are on the same leaf. --- siriuspy/siriuspy/search/ll_time_search.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/search/ll_time_search.py b/siriuspy/siriuspy/search/ll_time_search.py index eeae9cb38..db80cd11b 100644 --- a/siriuspy/siriuspy/search/ll_time_search.py +++ b/siriuspy/siriuspy/search/ll_time_search.py @@ -360,7 +360,11 @@ def has_log(cls, ll_trigger): @classmethod def get_trigger_name(cls, channel): """Get name of the trigger associated with channel.""" - chan_tree = cls.get_device_tree(channel) + # Look for trigger source from EVG down to channel. + # This is important to handle cases where 2 trigger sources are on the + # same leaf of the tree, such as the redundancy trigger for the orbit + # interlock. + chan_tree = cls.get_device_tree(channel)[::-1] for up_chan in chan_tree: if up_chan.device_name in cls._trig_src_devs: return up_chan From 3da677b0951f15a260686ea8d5576ee2e763b703 Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 22 Nov 2023 10:01:54 -0300 Subject: [PATCH 114/309] TIM.ENH: Generalize Const.EvtLL to get all events from csconst tables. --- siriuspy/siriuspy/timesys/csdev.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/timesys/csdev.py b/siriuspy/siriuspy/timesys/csdev.py index 6e511514d..f33dde0e9 100644 --- a/siriuspy/siriuspy/timesys/csdev.py +++ b/siriuspy/siriuspy/timesys/csdev.py @@ -67,12 +67,7 @@ class Const(_csdev.Const): __EvtHL2LLMap = None __EvtLL2HLMap = None - - evt_ll_codes = list(range(64)) + [117, 124, 125, 126, 132] - evt_ll_names = ['Evt{0:02d}'.format(i) for i in evt_ll_codes] - EvtLL = _csdev.Const.register( - 'EventsLL', evt_ll_names, values=evt_ll_codes) - del evt_ll_codes, evt_ll_names # cleanup class namespace + __EvtLL = None ClkHL2LLMap = { 'Clock0': 'Clk0', 'Clock1': 'Clk1', @@ -90,10 +85,17 @@ class Const(_csdev.Const): @_classproperty def EvtHL2LLMap(cls): """.""" - if cls.__EvtHL2LLMap is None: - cls.__EvtHL2LLMap = _HLTimeSearch.get_hl_events() - cls.__EvtLL2HLMap = { - val: key for key, val in cls.__EvtHL2LLMap.items()} + if cls.__EvtHL2LLMap is not None: + return cls.__EvtHL2LLMap + + emap = _HLTimeSearch.get_hl_events() + cls.__EvtHL2LLMap = emap + cls.__EvtLL2HLMap = {val: key for key, val in emap.items()} + + names = sorted({f'Evt{i:02d}' for i in range(64)} | set(emap.values())) + codes = [int(n[3:]) for n in names] + codes, names = list(zip(*sorted(zip(codes, names)))) + cls.__EvtLL = _csdev.Const.register('EventsLL', names, values=codes) return cls.__EvtHL2LLMap @_classproperty @@ -102,6 +104,12 @@ def EvtLL2HLMap(cls): cls.EvtHL2LLMap return cls.__EvtLL2HLMap + @_classproperty + def EvtLL(cls): + """.""" + cls.EvtHL2LLMap + return cls.__EvtLL + def get_event_database(evt_num=0, prefix=None): """Return event_database.""" From 91d41aff8241ea831bd480812a974074afeece21 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 22 Nov 2023 14:39:26 -0300 Subject: [PATCH 115/309] Refactor cmd_move methods in ID devices --- siriuspy/siriuspy/devices/ids.py | 174 ++++++++++++------------------- 1 file changed, 65 insertions(+), 109 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index cff4b8d9e..3ab42d0f5 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -145,49 +145,76 @@ def pparameter_parked(self): @property def pparameter_speed_max(self): """Return max pparameter speed readback [mm/s].""" - return self[self.PARAM_PVS.PPARAM_MAXVELO_RB] + if self.PARAM_PVS.PPARAM_MAXVELO_RB is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_MAXVELO_RB] @property def pparameter_speed_max_lims(self): """Return max pparameter speed limits.""" - ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_MAXVELO_SP) - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims + if self.PARAM_PVS.PPARAM_MAXVELO_RB is None: + return None + else: + ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_MAXVELO_SP) + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims @property def pparameter_speed(self): """Return pparameter speed readback [mm/s].""" - return self[self.PARAM_PVS.PPARAM_VELO_SP] + if self.PARAM_PVS.PPARAM_VELO_RB is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_VELO_SP] @property def pparameter_lims(self): """Return ID pparameter lower control limit [mm].""" - ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_SP) - return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + if self.PARAM_PVS.PPARAM_VELO_SP is None: + return None + else: + ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_SP) + return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] @property def pparameter(self): """Return ID pparameter readback [mm].""" - return self[self.PARAM_PVS.PPARAM_RB] + if self.PARAM_PVS.PPARAM_RB is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_RB] @property def pparameter_mon(self): """Return ID pparameter monitor [mm].""" - return self[self.PARAM_PVS.PPARAM_MON] + if self.PARAM_PVS.PPARAM_MON is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_MON] def pparameter_set(self, pparam, timeout=None): """Set ID target pparameter for movement [mm].""" - return self._write_sp(self.PARAM_PVS.PPARAM_SP, pparam, timeout) + if self.PARAM_PVS.PPARAM_SP is None: + return True + else: + return self._write_sp(self.PARAM_PVS.PPARAM_SP, pparam, timeout) def pparameter_speed_set(self, pparam_speed, timeout=None): - """Command to set ID cruise pparam speed for movement [mm/s].""" - return self._write_sp( - self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed, timeout) + """Command to set ID cruise pparameterspeed for movement [mm/s].""" + if self.PARAM_PVS.PPARAM_VELO_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed, timeout) def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): """Command to set ID max cruise pparam speed for movement [mm/s].""" - return self._write_sp( - self.PARAM_PVS.PPARAM_MAXVELO_SP, pparam_speed_max, timeout) + if self.PARAM_PVS.PPARAM_MAXVELO_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.PPARAM_MAXVELO_SP, pparam_speed_max, timeout) # --- kparameter --- @@ -355,8 +382,8 @@ def cmd_change_polarization_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Move ID to parked config.""" - return self._move_start( - self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) + pparam, kparam = self.pparameter, self.kparameter + return self.cmd_move(pparam, kparam, timeout) def cmd_move_pparameter(self, pparam, timeout=None): """Command to set and start pparam movement.""" @@ -366,10 +393,15 @@ def cmd_move_kparameter(self, kparam, timeout=None): """Command to set and start kparam movement.""" return self.cmd_move(None, kparam, timeout) - def cmd_move(self, pparam, kparam, timeout=None): + def cmd_move(self, pparam=None, kparam=None, timeout=None): """Command to set and start pparam and kparam movements.""" + if self.PARAM_PVS.PPARAM_SP is None: + pparam = None + else: + pparam = self.pparameter if pparam is None else pparam + kparam = self.kparameter if kparam is None else kparam + # calc ETA - pparam = None if self.PARAM_PVS.PPARAM_SP is None else pparam dtime_kparam = 0 if kparam is None else \ abs(kparam - self.kparameter_mon) / self.kparameter_speed dtime_pparam = 0 if pparam is None else \ @@ -611,42 +643,6 @@ def cmd_move_start(self, timeout=None): self['DevCtrl-Cmd'] = self._CMD_MOVE_START return True - def cmd_move_park(self, timeout=None): - """Command to set and start ID movement to parked config.""" - return self.move(self.phase_parked, timeout=timeout) - - def move(self, phase, timeout=None): - """Command to set and start phase movements.""" - # calc ETA - dtime_max = abs(phase - self.phase_mon) / self.phase_speed - - # additional percentual in ETA - tol_dtime = 300 # [%] - tol_factor = (1 + tol_dtime/100) - tol_total = tol_factor * dtime_max + 5 - - # set target phase and gap - if not self.set_phase(phase=phase, timeout=timeout): - return False - - # command move start - if not self.cmd_move_start(timeout=timeout): - return False - - # wait for movement within reasonable time - time_init = _time.time() - while self.is_moving and \ - abs(self.phase_mon - phase) > self.kparameter_tol: - if _time.time() - time_init > tol_total: - print(f'tol_total: {tol_total:.3f} s') - print(f'wait_time: {_time.time() - time_init:.3f} s') - print() - return False - _time.sleep(self._SHORT_SHUT_EYE) - - # successfull movement at this point - return True - # --- private methods --- def _write_sp(self, propties_sp, values, timeout=None): @@ -1094,53 +1090,6 @@ def cmd_move_gap_start(self, timeout=None): """Command to start gap movement.""" return self._move_start('ChangeGap-Cmd', timeout=timeout) - def cmd_move_park(self, timeout=None): - """Command to set and start ID movement to parked config.""" - return self.move( - self.phase_parked, self.gap_parked, timeout=timeout) - - def move(self, phase, gap, timeout=None): - """Command to set and start phase and gap movements.""" - # calc ETA - dtime_phase = abs(phase - self.phase_mon) / self.phase_speed - dtime_gap = abs(gap - self.gap_mon) / self.gap_speed - dtime_max = max(dtime_phase, dtime_gap) - - # additional percentual in ETA - tol_gap = 0.01 # [mm] - tol_phase = 0.01 # [mm] - tol_dtime = 300 # [%] - tol_factor = (1 + tol_dtime/100) - tol_total = tol_factor * dtime_max + 5 - - # set target phase and gap - if not self.set_phase(phase=phase, timeout=timeout): - return False - if not self.set_gap(gap=gap, timeout=timeout): - return False - - # command move start - if not self.cmd_move_phase_start(timeout=timeout): - return False - if not self.cmd_move_gap_start(timeout=timeout): - return False - - # wait for movement within reasonable time - time_init = _time.time() - while \ - abs(self.gap_mon - gap) > tol_gap or \ - abs(self.phase_mon - phase) > tol_phase or \ - self.is_moving: - if _time.time() - time_init > tol_total: - print(f'tol_total: {tol_total:.3f} s') - print(f'wait_time: {_time.time() - time_init:.3f} s') - print() - return False - _time.sleep(self._SHORT_SHUT_EYE) - - # successfull movement at this point - return True - # --- other cmds --- def cmd_clear_error(self): @@ -1268,17 +1217,24 @@ def pos_cid_mon(self): """ return self['CIDVirtPos-Mon'] - # --- cmd_wait + # --- cmd_move - def wait_while_busy(self, timeout=None): - """Command wait within timeout while ID control is busy.""" - return self.cmd_wait_move_finish(timeout) + def cmd_move_start(self, timeout=None): + """Command to start movement.""" + pparam, kparam = self.pparameter, self.kparameter + return self.cmd_move(pparam, kparam, timeout) + + def cmd_move_park(self, timeout=None): + """Move ID to parked config.""" + return self._move_start( + self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) - def cmd_move(self, pparam, kparam, timeout=None): + def cmd_move(self, pparam=None, kparam=None, timeout=None): """Command to set and start pparam and kparam movements.""" + pparam = self.pparameter if pparam is None else pparam + kparam = self.kparameter if kparam is None else kparam # check if polarization change is needed - if pparam is not None and \ - abs(pparam - self.pparameter_mon) > self.pparameter_tol: + if abs(pparam - self.pparameter_mon) > self.pparameter_tol: # first move to K=0 t0_ = _time.time() if not self.cmd_move_kparameter(kparam=0, timeout=timeout): From 8845787510e5b9496495727ffb47a7d3200d0bab Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 22 Nov 2023 18:49:59 -0300 Subject: [PATCH 116/309] search.FIX: fix bug in IDSearch.conv_idname_2_polarization_state --- siriuspy/siriuspy/search/id_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index dc2c4df95..8c61e253b 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -304,7 +304,7 @@ def conv_idname_2_polarization_state(idname, pparameter, kparameter): pols_sts = IDSearch._idname2pol_sts[idname] # check if polarization is defined - for pol_idx, pol in pols_sts: + for pol_idx, pol in pols_sts.items(): _, pol_phase = pol if abs(pparameter - pol_phase) <= params.PPARAM_TOL: return pol_idx From fe39ea3ee9b7ff770616fce04d29842cc9f1ff83 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 22 Nov 2023 18:51:41 -0300 Subject: [PATCH 117/309] idff.MNT: fix import order --- siriuspy/siriuspy/idff/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/idff/main.py b/siriuspy/siriuspy/idff/main.py index 23d37a154..ff49f36c5 100644 --- a/siriuspy/siriuspy/idff/main.py +++ b/siriuspy/siriuspy/idff/main.py @@ -8,9 +8,6 @@ import epics as _epics import numpy as _np -if _find_spec('PRUserial485') is not None: - from PRUserial485 import EthBridgeClient as _EthBridgeClient - from ..util import update_bit as _updt_bit from ..callbacks import Callback as _Callback from ..clientconfigdb import ConfigDBException as _ConfigDBException @@ -20,6 +17,9 @@ from .csdev import IDFFConst as _Const, ETypes as _ETypes +if _find_spec('PRUserial485') is not None: + from PRUserial485 import EthBridgeClient as _EthBridgeClient + class App(_Callback): """Main application for handling IDFF.""" From 4dd00cad1107d6bb9be59055d2af26fb2f05ffe2 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 23 Nov 2023 12:17:42 -0300 Subject: [PATCH 118/309] Fix IDSearch --- siriuspy/siriuspy/search/id_search.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index dc2c4df95..1a3d23d5c 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -80,8 +80,8 @@ class IDSearch: 'IDParameters', _idparam_fields, ( 52.5, - -52.5/2, +52.5/2, 0, 0, 0.1, - -52.5/2, +52.5/2, 0, 0.1)), + -52.5/2, +52.5/2, 0, 0, 0.020, + -52.5/2, +52.5/2, 0, 0.010)), 'SI-11SP:ID-APU58': _get_namedtuple( 'IDParameters', _idparam_fields, ( @@ -304,7 +304,7 @@ def conv_idname_2_polarization_state(idname, pparameter, kparameter): pols_sts = IDSearch._idname2pol_sts[idname] # check if polarization is defined - for pol_idx, pol in pols_sts: + for pol_idx, pol in pols_sts.items(): _, pol_phase = pol if abs(pparameter - pol_phase) <= params.PPARAM_TOL: return pol_idx From 6d262b6b8c2e4c3ab9e62f788d3a041caf9890d6 Mon Sep 17 00:00:00 2001 From: gabriel Date: Thu, 23 Nov 2023 12:39:17 -0300 Subject: [PATCH 119/309] standardize epu and papu properties and methods --- siriuspy/siriuspy/devices/ids.py | 74 +++++++++++--------------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 3ab42d0f5..3c6f91f94 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -64,7 +64,7 @@ class _ID(_Device): PROPERTIES_DEFAULT = \ tuple(set(value for key, value in _inspect.getmembers(PARAM_PVS) \ if not key.startswith('_') and value is not None)) - + def __init__(self, devname, props2init='all', auto_monitor_mon=True): """.""" # call base class constructor @@ -225,7 +225,7 @@ def kparameter_tol(self): return self.parameters.KPARAM_TOL else: return self[self.PARAM_PVS.KPARAM_TOL_RB] - + @property def kparameter_parked(self): """Return ID parked kparameter value [mm].""" @@ -261,7 +261,7 @@ def kparameter_speed_mon(self): @property def kparameter_lims(self): - """Return ID kparameter lower control limit [mm].""" + """Return ID kparameter control limits [mm].""" ctrl = self.pv_ctrlvars(self.PARAM_PVS.KPARAM_SP) return [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] @@ -689,7 +689,7 @@ class DEVICES: tuple(set(value for key, value in _inspect.getmembers(PARAM_PVS) \ if not key.startswith('_') and value is not None)) + \ _properties + _properties_papu - + def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): """.""" # check if device exists @@ -702,11 +702,6 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) - @property - def period_length(self): - """Return ID period length [mm].""" - return self['PeriodLength-Cte'] - @property def log_mon(self): """Return ID Log.""" @@ -838,8 +833,7 @@ def cmd_move_phase_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Command to set and start ID movement to parked config.""" - return self.cmd_move( - pparam=None, kparam=self.phase_parked, timeout=timeout) + return self.cmd_move_park(timeout) # --- cmd_reset @@ -924,56 +918,47 @@ def status(self): # --- gap speeds ---- - @property - def gap_parked(self): - """Return ID parked gap value [mm].""" - return self['ParkedGap-Cte'] - @property def gap_speed(self): """Return gap speed readback [mm/s].""" - return self['GapSpeed-RB'] + return self.kparameter_speed @property def gap_speed_mon(self): """Return gap speed monitor [mm/s].""" - return self['GapSpeed-Mon'] + return self.kparameter_speed_mon @property def gap_speed_max(self): """Return max gap speed readback [mm/s].""" - return self['MaxGapSpeed-RB'] + return self.kparameter_speed_max @property def gap_speed_max_lims(self): """Return max gap speed limits.""" - ctrl = self.pv_ctrlvars('MaxGapSpeed-SP') - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims + return self.kparameter_speed_max_lims # --- gap --- @property - def gap(self): - """Return ID gap readback [mm].""" - return self['Gap-RB'] + def gap_parked(self): + """Return ID parked gap value [mm].""" + return self.kparameter_parked @property - def gap_min(self): - """Return ID gap lower control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Gap-SP') - return ctrlvars['lower_ctrl_limit'] + def gap(self): + """Return ID gap readback [mm].""" + return self.kparameter @property - def gap_max(self): - """Return ID gap upper control limit [mm].""" - ctrlvars = self.pv_ctrlvars('Gap-SP') - return ctrlvars['upper_ctrl_limit'] + def gap_lims(self): + """Return ID gap control limits [mm].""" + return self.kparameter_lims @property def gap_mon(self): """Return ID gap monitor [mm].""" - return self['Gap-Mon'] + return self.kparameter_mon # --- drive checks --- @@ -1024,16 +1009,16 @@ def cmd_drive_turn_power_on(self, timeout=None): # --- set methods --- def set_gap(self, gap, timeout=None): - """Command to set ID target gap for movement [mm].""" - return self._write_sp('Gap-SP', gap, timeout) + """Set ID target gap for movement [mm].""" + return self.kparameter_set(gap, timeout) def set_gap_speed(self, gap_speed, timeout=None): - """Command to set ID cruise gap speed for movement [mm/s].""" - return self._write_sp('GapSpeed-SP', gap_speed, timeout) + """Set ID cruise gap speed for movement [mm/s].""" + return self.kparameter_speed_set(gap_speed, timeout) def set_gap_speed_max(self, gap_speed_max, timeout=None): - """Command to set ID max cruise gap speed for movement [mm/s].""" - return self._write_sp('MaxGapSpeed-SP', gap_speed_max, timeout) + """Set ID max cruise gap speed for movement [mm/s].""" + return self.kparameter_speed_max_set(gap_speed_max, timeout) # --- cmd_move disable/enable --- @@ -1079,16 +1064,9 @@ def wait_while_busy(self, timeout=None): # -- cmd_move - def cmd_move_start(self, timeout=None): - """Command to start movement.""" - success = True - success &= self.cmd_move_gap_start(timeout=timeout) - success &= self.cmd_move_phase_start(timeout=timeout) - return success - def cmd_move_gap_start(self, timeout=None): """Command to start gap movement.""" - return self._move_start('ChangeGap-Cmd', timeout=timeout) + return self.cmd_move_kparameter_start(timeout) # --- other cmds --- From b4b8e59d4e2dbdbc0d74fa049ea74dced471cab5 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 23 Nov 2023 13:09:07 -0300 Subject: [PATCH 120/309] Fix one method in EPU device --- siriuspy/siriuspy/devices/ids.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 3c6f91f94..dfe2b0f7c 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -833,7 +833,7 @@ def cmd_move_phase_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Command to set and start ID movement to parked config.""" - return self.cmd_move_park(timeout) + return super().cmd_move_park(timeout) # --- cmd_reset @@ -1008,15 +1008,15 @@ def cmd_drive_turn_power_on(self, timeout=None): # --- set methods --- - def set_gap(self, gap, timeout=None): + def gap_set(self, gap, timeout=None): """Set ID target gap for movement [mm].""" return self.kparameter_set(gap, timeout) - def set_gap_speed(self, gap_speed, timeout=None): + def gap_speed_set(self, gap_speed, timeout=None): """Set ID cruise gap speed for movement [mm/s].""" return self.kparameter_speed_set(gap_speed, timeout) - def set_gap_speed_max(self, gap_speed_max, timeout=None): + def gap_speed_max_set(self, gap_speed_max, timeout=None): """Set ID max cruise gap speed for movement [mm/s].""" return self.kparameter_speed_max_set(gap_speed_max, timeout) From 29810c5255cffd4cd368cb871bf36363e793fc7d Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 23 Nov 2023 14:13:54 -0300 Subject: [PATCH 121/309] Improve IDFF device init --- siriuspy/siriuspy/devices/idff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 72fb8d72b..dda9a0b72 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -28,7 +28,7 @@ def __init__(self, devname): if devname not in IDFF.DEVICES.ALL: raise NotImplementedError(devname) - self._devname = _SiriusPVName(devname) # needed for _create_devices + self._devname = devname # needed for _create_devices self._idffconfig = _IDFFConfig() self._pparametername = \ From 9c6d6715a1feaadcafdc43f6cfbf58a3ccd97aa3 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 23 Nov 2023 16:06:31 -0300 Subject: [PATCH 122/309] Add __str__ to ids._PARAM_PVS --- siriuspy/siriuspy/devices/ids.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index dfe2b0f7c..1bfa5968e 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -52,6 +52,15 @@ class _PARAM_PVS: POL_MON = None POL_CHANGE_CMD = None + def __str__(self): + """Print parameters.""" + str_ = '' + strf = '{}: {}' + for key, value in _inspect.getmembers(self): + if not key.startswith('_') and value is not None: + lstr = strf.format(key, value) + str_ += lstr if str_ == '' else '\n' + lstr + return str_ class _ID(_Device): """Generic Insertion Device.""" From 07e1b3a99e497caf98ac6a19d7bf8f024a8f94fb Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 24 Nov 2023 12:31:55 -0300 Subject: [PATCH 123/309] Update ID devices and IDSearch --- siriuspy/siriuspy/devices/ids.py | 109 ++++++++++++-------------- siriuspy/siriuspy/search/id_search.py | 10 +-- 2 files changed, 56 insertions(+), 63 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 1bfa5968e..034fafdde 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -107,13 +107,19 @@ def polarization(self): if self.PARAM_PVS.POL_STS in self.properties_all: return self[self.PARAM_PVS.POL_STS] else: - return self._pols_sts_str.index(_IDSearch.POL_UNDEF_STR) + if _IDSearch.POL_UNDEF_STR in self._pols_sts_str: + return self._pols_sts_str.index(_IDSearch.POL_UNDEF_STR) + else: + return None @property def polarization_str(self): """Return ID polarization string.""" pol_idx = self.polarization - return self._pols_sts_str[pol_idx] + if pol_idx is None: + return None + else: + return self._pols_sts_str[pol_idx] @polarization.setter def polarization(self, value): @@ -122,8 +128,6 @@ def polarization(self, value): if isinstance(value, str): value = self._pols_sel_str.index(value) self[self.PARAM_PVS.POL_SEL] = value - else: - raise TypeError('ID type does not define polarizations!') @property def polarization_mon(self): @@ -131,7 +135,7 @@ def polarization_mon(self): if self.PARAM_PVS.POL_MON in self.properties_all: return self[self.PARAM_PVS.POL_MON] else: - return _IDSearch.POL_UNDEF_STR + return None # --- pparameter --- @@ -561,9 +565,7 @@ class DEVICES: PROPERTIES_DEFAULT = \ tuple(set(value for key, value in _inspect.getmembers(PARAM_PVS) \ - if not key.startswith('_') and value is not None)) + ( - 'Kx-SP', 'Kx-Mon', - ) + if not key.startswith('_') and value is not None)) def __init__(self, devname, props2init='all', auto_monitor_mon=True): """.""" @@ -577,16 +579,6 @@ def __init__(self, devname, props2init='all', auto_monitor_mon=True): # --- phase speeds ---- - @property - def phase_speed(self): - """Return phase speed [mm/s].""" - return self.kparameter_speed - - @property - def phase_speed_mon(self): - """Return phase speed monitor [mm/s].""" - return self.kparameter_speed_mon - @property def phase_speed_max(self): """Return max phase speed readback [mm/s].""" @@ -597,12 +589,22 @@ def phase_speed_max_lims(self): """Return max phase speed limits.""" return self.kparameter_speed_max_lims + @property + def phase_speed(self): + """Return phase speed [mm/s].""" + return self.kparameter_speed + + @property + def phase_speed_mon(self): + """Return phase speed monitor [mm/s].""" + return self.kparameter_speed_mon + # --- phase --- @property - def phase(self): - """Return APU phase [mm].""" - return self.kparameter + def phase_parked(self): + """Return ID parked phase value [mm].""" + return self.kparameter_parked @property def phase_lims(self): @@ -610,33 +612,26 @@ def phase_lims(self): return self.kparameter_lims @property - def phase_mon(self): + def phase(self): """Return APU phase [mm].""" - return self.kparameter_mon - - # --- Kparam methods --- + return self.kparameter @property - def idkx(self): - """Return APU Kx.""" - return self['Kx-SP'] - - @idkx.setter - def idkx(self, value): - """Set APU Kx.""" - self['Kx-SP'] = value + def phase_mon(self): + """Return APU phase [mm].""" + return self.kparameter_mon # --- set methods --- - def set_phase(self, phase, timeout=None): + def phase_set(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" return self.kparameter_set(phase, timeout) - def set_phase_speed(self, phase_speed, timeout=None): + def phase_speed_set(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" return self.kparameter_speed_set(phase_speed, timeout) - def set_phase_speed_max(self, phase_speed_max, timeout=None): + def phase_speed_max_set(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" return self._write_sp('MaxPhaseSpeed-SP', phase_speed_max, timeout) @@ -718,6 +713,16 @@ def log_mon(self): # --- phase speeds ---- + @property + def phase_speed_max(self): + """Return max phase speed readback [mm/s].""" + return self.kparameter_speed_max + + @property + def phase_speed_max_lims(self): + """Return max phase speed limits.""" + return self.kparameter_speed_max_lims + @property def phase_speed(self): """Return phase speed readback [mm/s].""" @@ -728,18 +733,6 @@ def phase_speed_mon(self): """Return phase speed monitor [mm/s].""" return self.kparameter_speed_mon - @property - def phase_speed_max(self): - """Return max phase speed readback [mm/s].""" - return self.kparameter_speed_max - - @property - def phase_speed_max_lims(self): - """Return max phase speed limits.""" - ctrl = self.pv_ctrlvars('MaxPhaseSpeed-SP') - lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] - return lims - # --- phase --- @property @@ -747,16 +740,16 @@ def phase_parked(self): """Return ID parked phase value [mm].""" return self.kparameter_parked - @property - def phase(self): - """Return ID phase readback [mm].""" - return self.kparameter - @property def phase_lims(self): """Return ID phase limits [mm].""" return self.kparameter_lims + @property + def phase(self): + """Return ID phase readback [mm].""" + return self.kparameter + @property def phase_mon(self): """Return ID phase monitor [mm].""" @@ -779,7 +772,7 @@ def is_move_phase_enabled(self): @property def is_moving(self): """Return is moving state (True|False).""" - return self['Moving-Mon'] != 0 + return self[self.PARAM_PVS.IS_MOVING] != 0 @property def is_homing(self): @@ -798,15 +791,15 @@ def cmd_drive_turn_power_on(self, timeout=None): # --- set methods --- - def set_phase(self, phase, timeout=None): + def phase_set(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" return self.kparameter_set(phase, timeout) - def set_phase_speed(self, phase_speed, timeout=None): + def phase_speed_set(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" return self.kparameter_speed_set(phase_speed, timeout) - def set_phase_speed_max(self, phase_speed_max, timeout=None): + def phase_speed_max_set(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" return self.kparameter_speed_max_set(phase_speed_max, timeout) @@ -1152,7 +1145,7 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): @property def is_operational(self): """Return True if ID is operational.""" - return self['IsOperational-Mon'] != 0 + return self['IsOperational-Mon'] == 0 # 0 : 'OK' # --- cassette positions --- diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index 1a3d23d5c..e2ed17e1a 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -48,25 +48,25 @@ class IDSearch: 'IDParameters', _idparam_fields, ( 22, - 0, 11, 11, 0, 0.1, + 0, 11, 11, 0, 0.01, None, None, None, None)), 'SI-07SP:ID-APU22': _get_namedtuple( 'IDParameters', _idparam_fields, ( 22, - 0, 11, 11, 0, 0.1, + 0, 11, 11, 0, 0.01, None, None, None, None)), 'SI-08SB:ID-APU22': _get_namedtuple( 'IDParameters', _idparam_fields, ( 22, - 0, 11, 11, 0, 0.1, + 0, 11, 11, 0, 0.01, None, None, None, None)), 'SI-09SA:ID-APU22': _get_namedtuple( 'IDParameters', _idparam_fields, ( 22, - 0, 11, 11, 0, 0.1, + 0, 11, 11, 0, 0.01, None, None, None, None)), # NOTE: for EPU50 there is a large discrepancy # between RB/SP/Mon phase values @@ -86,7 +86,7 @@ class IDSearch: 'IDParameters', _idparam_fields, ( 58, - 0, 29, 29, 0, 0.1, + 0, 29, 29, 0, 0.01, None, None, None, None)), 'SI-14SB:ID-WIG180': _get_namedtuple( 'IDParameters', From d1753915264e95ec1040e14c42945b64a8eb52c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Mon, 27 Nov 2023 12:05:22 -0300 Subject: [PATCH 124/309] CONFDB.TIM.FIX: remove FPGAClk-Cte PVs from config. The value for these PVs is copied from the EVG during startup [1], and should remain constant during operation, otherwise the timing board will lose sync. Furthermore, the AFC IOC will forbid writes to "readonly" PVs in the future [2]. [1] https://github.com/lnls-dig/afc-epics-ioc/blob/b2de36d9e939f064d44d8614aca84811e456dd80/utcaApp/Db/afc_timing.template#L6 [2] https://github.com/lnls-dig/afc-epics-ioc/blob/b2de36d9e939f064d44d8614aca84811e456dd80/iocBoot/iocutca/apply_asg.cmd --- .../clientconfigdb/types/global_config.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/global_config.py b/siriuspy/siriuspy/clientconfigdb/types/global_config.py index 1ffd915c2..62f73194c 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/global_config.py +++ b/siriuspy/siriuspy/clientconfigdb/types/global_config.py @@ -230,29 +230,6 @@ def get_dict(): ['AS-RaMO:TI-EVG:FOFBSDelayType-Sel', 0, 0.0], ['AS-RaMO:TI-EVG:FOFBSMode-Sel', 0, 0.0], - # AMCFPGAEVRs - ['IA-01RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-02RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-03RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-04RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-05RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-06RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-07RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-08RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-09RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-10RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-11RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-12RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-13RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-14RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-15RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-16RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-17RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-18RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-19RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-20RaBPM:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - ['IA-20RaBPMTL:TI-AMCFPGAEVR:FPGAClk-Cte', 124916500, 0.0], - # Triggers ['AS-Fam:TI-Scrn-TBBO:DelayRaw-SP', 0, 0], ['AS-Fam:TI-Scrn-TBBO:WidthRaw-SP', 0, 0.0], From e7d761e5af604c71e0c3d883be5570114f3ae8d1 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 27 Nov 2023 22:20:06 -0300 Subject: [PATCH 125/309] Fix bugs in ID devices --- siriuspy/siriuspy/devices/device.py | 12 ++- siriuspy/siriuspy/devices/ids.py | 119 +++++++++++++++------------- 2 files changed, 72 insertions(+), 59 deletions(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 8c121a9db..1f6cd3341 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -225,12 +225,16 @@ def comp_(val): if isinstance(comp, str): comp = getattr(_opr, comp) - timeout = _DEF_TIMEOUT if timeout is None else timeout - timeout = 0 if timeout <= 0 else timeout + if not isinstance(timeout, str) and timeout != 'never': + timeout = _DEF_TIMEOUT if timeout is None else timeout + timeout = 0 if timeout <= 0 else timeout t0_ = _time.time() while not comp_(value): - if _time.time() - t0_ > timeout: - return False + if isinstance(timeout, str) and timeout == 'never': + pass + else: + if _time.time() - t0_ > timeout: + return False _time.sleep(_TINY_INTERVAL) return True diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 034fafdde..07dc4afb1 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -62,6 +62,7 @@ def __str__(self): str_ += lstr if str_ == '' else '\n' + lstr return str_ + class _ID(_Device): """Generic Insertion Device.""" @@ -356,8 +357,8 @@ def cmd_move_stop(self, timeout=None): if not self.wait_while_busy(timeout=timeout): return False - # send stop command - self.cmd_move_disable() + # # send stop command + # self.cmd_move_disable() # check for successful stop if not self.wait_while_busy(timeout=timeout): @@ -365,9 +366,9 @@ def cmd_move_stop(self, timeout=None): if not self.cmd_wait_move_finish(timeout=timeout): return False - # enable movement again - if not self.cmd_move_enable(timeout=timeout): - return False + # # enable movement again + # if not self.cmd_move_enable(timeout=timeout): + # return False return True @@ -395,7 +396,7 @@ def cmd_change_polarization_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Move ID to parked config.""" - pparam, kparam = self.pparameter, self.kparameter + pparam, kparam = self.pparameter_parked, self.kparameter_parked return self.cmd_move(pparam, kparam, timeout) def cmd_move_pparameter(self, pparam, timeout=None): @@ -410,8 +411,8 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): """Command to set and start pparam and kparam movements.""" if self.PARAM_PVS.PPARAM_SP is None: pparam = None - else: - pparam = self.pparameter if pparam is None else pparam + # else: + # pparam = self.pparameter if pparam is None else pparam kparam = self.kparameter if kparam is None else kparam # calc ETA @@ -445,7 +446,7 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): time_init = _time.time() while True: condk = True if kparam is None else \ - abs(self.kparameter_mon - kparam) <= tol_kparam + abs(abs(self.kparameter_mon) - abs(kparam)) <= tol_kparam condp = True if pparam is None else \ abs(self.pparameter_mon - pparam) <= tol_pparam if condp and condk and not self.is_moving: @@ -488,7 +489,7 @@ def cmd_change_polarization(self, polarization, timeout=None): # --- private methods --- - def _move_start(self, cmd_propty, timeout=None): + def _move_start(self, cmd_propty, timeout=None, cmd_value=1): timeout = timeout or self._DEF_TIMEOUT # wait for not busy state @@ -497,7 +498,7 @@ def _move_start(self, cmd_propty, timeout=None): if cmd_propty in self.properties_all: # send move command - self[cmd_propty] = 1 + self[cmd_propty] = cmd_value return True @@ -642,10 +643,10 @@ def cmd_move_stop(self, timeout=None): self['DevCtrl-Cmd'] = self._CMD_MOVE_STOP return True - def cmd_move_start(self, timeout=None): - """Send command to start ID movement.""" - self['DevCtrl-Cmd'] = self._CMD_MOVE_START - return True + # def cmd_move_start(self, timeout=None): + # """Send command to start ID movement.""" + # self['DevCtrl-Cmd'] = self._CMD_MOVE_START + # return True # --- private methods --- @@ -654,6 +655,10 @@ def _write_sp(self, propties_sp, values, timeout=None): return super()._write_sp( propties_sp, values, timeout=timeout, pvs_sp_rb=pvs_sp_rb) + def _move_start( + self, cmd_propty, timeout=None, cmd_value=_CMD_MOVE_START): + return super()._move_start(cmd_propty, timeout, cmd_value) + class PAPU(_ID): """PAPU Insertion Device.""" @@ -833,9 +838,9 @@ def cmd_move_phase_start(self, timeout=None): """Command to start phase movement.""" return self.cmd_move_kparameter_start(timeout=timeout) - def cmd_move_park(self, timeout=None): - """Command to set and start ID movement to parked config.""" - return super().cmd_move_park(timeout) + # def cmd_move_park(self, timeout=None): + # """Command to set and start ID movement to parked config.""" + # return super().cmd_move_park(timeout) # --- cmd_reset @@ -1118,9 +1123,10 @@ class DEVICES: PARAM_PVS.POL_MON = 'Pol-Mon' PARAM_PVS.POL_CHANGE_CMD = 'PolChange-Cmd' - PROPERTIES_DEFAULT = \ - tuple(set(value for key, value in _inspect.getmembers(PARAM_PVS) \ - if not key.startswith('_') and value is not None)) + ( + PROPERTIES_DEFAULT = tuple(set( + value for key, value in _inspect.getmembers(PARAM_PVS) + if not key.startswith('_') and value is not None)) + PROPERTIES_DEFAULT = PROPERTIES_DEFAULT + ( 'CSDVirtPos-Mon', 'CSEVirtPos-Mon', 'CIEVirtPos-Mon', 'CIDVirtPos-Mon', 'IsOperational-Mon', 'MotorsEnbld-Mon', @@ -1199,40 +1205,43 @@ def pos_cid_mon(self): # --- cmd_move - def cmd_move_start(self, timeout=None): - """Command to start movement.""" - pparam, kparam = self.pparameter, self.kparameter - return self.cmd_move(pparam, kparam, timeout) - - def cmd_move_park(self, timeout=None): - """Move ID to parked config.""" - return self._move_start( - self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) - - def cmd_move(self, pparam=None, kparam=None, timeout=None): - """Command to set and start pparam and kparam movements.""" - pparam = self.pparameter if pparam is None else pparam - kparam = self.kparameter if kparam is None else kparam - # check if polarization change is needed - if abs(pparam - self.pparameter_mon) > self.pparameter_tol: - # first move to K=0 - t0_ = _time.time() - if not self.cmd_move_kparameter(kparam=0, timeout=timeout): - return False - t1_ = _time.time() - timeout = timeout if timeout is None else \ - max(0, timeout - (t1_ - t0_)) - # then change pparam - t0_ = _time.time() - if not self.cmd_move_pparameter(pparam=pparam, timeout=timeout): - return False - t1_ = _time.time() - timeout = timeout if timeout is None else \ - max(0, timeout - (t1_ - t0_)) - # finally move to desired kparam - if not self.cmd_move_kparameter(kparam=kparam, timeout=timeout): - return False - return True + # def cmd_move_start(self, timeout=None): + # """Command to start movement.""" + # pparam, kparam = self.pparameter, self.kparameter + # return self.cmd_move(pparam, kparam, timeout) + + # def cmd_move_park(self, timeout=None): + # """Move ID to parked config.""" + # return self._move_start( + # self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) + + # def cmd_move(self, pparam=None, kparam=None, timeout=None): + # """Command to set and start pparam and kparam movements.""" + # pparam = self.pparameter if pparam is None else pparam + # kparam = self.kparameter if kparam is None else kparam + # # check if polarization change is needed + # if abs(pparam - self.pparameter_mon) > self.pparameter_tol: + # # first move to K=0 + # t0_ = _time.time() + # if not super().cmd_move( + # pparam=None, kparam=0, timeout=timeout): + # return False + # t1_ = _time.time() + # timeout = timeout if timeout is None else \ + # max(0, timeout - (t1_ - t0_)) + # # then change pparam + # t0_ = _time.time() + # if not super().cmd_move( + # pparam=pparam, kparam=None, timeout=timeout): + # return False + # t1_ = _time.time() + # timeout = timeout if timeout is None else \ + # max(0, timeout - (t1_ - t0_)) + # # finally move to desired kparam + # if not super().cmd_move( + # pparam=None, kparam=kparam, timeout=timeout): + # return False + # return True class WIG(_ID): From 119c50e8c3d2a2e4cc0fa171fd66fc9fe052bf2a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 09:47:12 -0300 Subject: [PATCH 126/309] ORBINTLK.ENH: add new BPMMonitoredDevices-Mon PV --- siriuspy/siriuspy/orbintlk/csdev.py | 2 + siriuspy/siriuspy/orbintlk/main.py | 61 ++++++++++++++++------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 32d924d6a..3bdd12aba 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -204,6 +204,8 @@ def get_database(self): 'LLRFStatusLabels-Cte': { 'type': 'string', 'count': len(_et.STS_LBLS_LLRF), 'value': _et.STS_LBLS_LLRF}, + 'BPMMonitoredDevices-Mon': { + 'type': 'char', 'count': 1000, 'value': ''}, 'TimingMonitoredDevices-Mon': { 'type': 'char', 'count': 1000, 'value': ''}, diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index fcc7434bb..151d6421e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -64,7 +64,8 @@ def __init__(self, tests=True): self._thread_cbevgrx = None self._thread_cbfout = {fout: None for fout in self._const.FOUTS_2_MON} self._thread_cbbpm = None - self._ti_mon_devs = set() + self._bpm_mon_devs = list() + self._ti_mon_devs = list() self._lock_threads = dict() self._lock_failures = set() self._lock_suspend = False @@ -304,7 +305,9 @@ def init_database(self): self.run_callbacks(pvn+'-SP', enb) if not okl: self.run_callbacks(pvn+'-RB', enb) - self._ti_mon_devs = self._get_ti_monitored_devices() + self._bpm_mon_devs, self._ti_mon_devs = self._get_monitored_devices() + self.run_callbacks( + 'BPMMonitoredDevices-Mon', '\n'.join(self._bpm_mon_devs)) self.run_callbacks( 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) @@ -463,20 +466,16 @@ def set_enable(self, value): return False if value: - mondevs = self._get_ti_monitored_devices() - if not self._check_devices_status(mondevs): + if not self._check_ti_devices_status(self._ti_mon_devs): self._update_log('ERR:Could not enable orbit interlock.') return False - self._ti_mon_devs = mondevs - self.run_callbacks( - 'TimingMonitoredDevices-Mon', '\n'.join(mondevs)) - glob_en = self._get_gen_bpm_intlk() else: glob_en = _np.zeros(self._const.nr_bpms, dtype=bool) bkup = int(self._state) self._state = value + if not self._orbintlk_dev.set_gen_enable(list(glob_en)): self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') @@ -529,17 +528,20 @@ def _do_set_enbllist(self, intlk, value): # check if new enable list do not imply in orbit interlock failure bkup_enbllist = self._enable_lists[intlk] - bkup_timondev = self._ti_mon_devs + bkup_bpmmon, bkup_timon = self._bpm_mon_devs, self._ti_mon_devs self._enable_lists[intlk] = new - self._ti_mon_devs = self._get_ti_monitored_devices() + self._bpm_mon_devs, self._ti_mon_devs = \ + self._get_monitored_devices() self._config_fout_rxenbl() - if not self._check_devices_status(self._ti_mon_devs): + if not self._check_ti_devices_status(self._ti_mon_devs): self._update_log('ERR:Could not set enable list.') self._enable_lists[intlk] = bkup_enbllist - self._ti_mon_devs = bkup_timondev + self._bpm_mon_devs, self._ti_mon_devs = bkup_bpmmon, bkup_timon self._config_fout_rxenbl() self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) return False + self.run_callbacks( + 'BPMMonitoredDevices-Mon', '\n'.join(self._bpm_mon_devs)) self.run_callbacks( 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) @@ -830,27 +832,30 @@ def _config_fout_rxenbl(self): return True - def _get_enabled_sections(self): + def _get_monitored_devices(self): enbllist = self._get_gen_bpm_intlk() - aux = _np.roll(enbllist, 1) - subs = _np.where(_np.sum(aux.reshape(20, -1), axis=1) > 0)[0] - subs += 1 - return subs - def _get_ti_monitored_devices(self): - value = set() - if self._state: - value.add(self._everf_dev.devname) - for sec in self._get_enabled_sections(): - afcti = f'IA-{sec:02}RaBPM:TI-AMCFPGAEVR' - value.add(afcti) + # bpms + idcs = _np.where(enbllist)[0] + bpmdevs = [self._const.bpm_names[i] for i in idcs] + + # timing + tidevs = set() + tidevs.add(self._everf_dev.devname) + aux = _np.roll(enbllist, 1) + subsecs = _np.where(_np.sum(aux.reshape(20, -1), axis=1) > 0)[0] + subsecs += 1 + for sub in subsecs: + afcti = f'IA-{sub:02}RaBPM:TI-AMCFPGAEVR' + tidevs.add(afcti) foutout = _LLTimeSearch.get_trigsrc2fout_mapping()[afcti] - value.add(foutout) + tidevs.add(foutout) evgout = _LLTimeSearch.get_evg_channel(foutout) - value.add(evgout) - return sorted(value) + tidevs.add(evgout) + + return bpmdevs, sorted(tidevs) - def _check_devices_status(self, devices): + def _check_ti_devices_status(self, devices): for devname in devices: devname = _PVName(devname) out = int(devname.propty[-1]) if devname.propty else None From 8bb2133e317ca09fccccb34f404b27eab277f3db Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 09:48:56 -0300 Subject: [PATCH 127/309] ORBINLKT.ENH: add status bits to monitor DCCT Fout --- siriuspy/siriuspy/orbintlk/csdev.py | 3 +- siriuspy/siriuspy/orbintlk/main.py | 44 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 3bdd12aba..1fa40f163 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -25,7 +25,8 @@ class ETypes(_csdev.ETypes): 'AcqConfigured') STS_LBLS_TIMING = ( 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', - 'FoutsConn', 'FoutsConfig', + 'FoutsBPMConn', 'FoutsBPMConfig', + 'FoutsDCCTConn', 'FoutsDCCTConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', 'BPMPsMtmTrigConn', 'BPMPsMtmTrigStatusOK', 'BPMPsMtmTrigConfig', diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 151d6421e..f450c7940 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -953,7 +953,7 @@ def _check_configs(self): value = _updt_bit(value, 2, not okg) else: value = 0b111 - # Fouts + # BPM Fouts devs = self._fout_devs if all(devs[devn].connected for devn in self._const.FOUTS_2_MON): okg = True @@ -964,65 +964,77 @@ def _check_configs(self): value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 + # DCCT Fouts + dev = self._fout_dcct_dev + if dev.connected: + okg = True + for prp, val in self._const.FOUT2_CONFIGS: + prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + okg &= dev[prp_rb] == val + if 'RxEnbl' in prp: + okg &= dev['RxLockedLtc-Mon'] == val + value = _updt_bit(value, 6, not okg) + else: + value += 0b11 << 5 # Orbit Interlock trigger dev = self._orbintlk_trig if dev.connected: - value = _updt_bit(value, 6, bool(dev['Status-Mon'])) + value = _updt_bit(value, 8, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.ORBINTLKTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 7, not oko) + value = _updt_bit(value, 9, not oko) else: - value += 0b111 << 5 + value += 0b111 << 7 # LLRF PsMtm trigger dev = self._llrf_trig oko = False if dev.connected: - value = _updt_bit(value, 9, bool(dev['Status-Mon'])) + value = _updt_bit(value, 11, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.LLRFTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 10, not oko) + value = _updt_bit(value, 12, not oko) else: - value += 0b111 << 8 + value += 0b111 << 10 # BPM PsMtm trigger dev = self._bpmpsmtn_trig oko = False if dev.connected: - value = _updt_bit(value, 12, bool(dev['Status-Mon'])) + value = _updt_bit(value, 14, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.BPMPSMTNTRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 13, not oko) + value = _updt_bit(value, 15, not oko) else: - value += 0b111 << 11 + value += 0b111 << 13 # DCCT 13C4 trigger dev = self._dcct13c4_trig oko = False if dev.connected: - value = _updt_bit(value, 15, bool(dev['Status-Mon'])) + value = _updt_bit(value, 17, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.DCCT13C4TRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 16, not oko) + value = _updt_bit(value, 18, not oko) else: - value += 0b111 << 14 + value += 0b111 << 16 # DCCT 14C4 trigger dev = self._dcct14c4_trig oko = False if dev.connected: - value = _updt_bit(value, 18, bool(dev['Status-Mon'])) + value = _updt_bit(value, 20, bool(dev['Status-Mon'])) oko = True for prp, val in self._const.DCCT14C4TRIG_CONFIG: prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') oko &= dev[prp_rb] == val - value = _updt_bit(value, 19, not oko) + value = _updt_bit(value, 21, not oko) else: - value += 0b111 << 17 + value += 0b111 << 19 self._timing_status = value self.run_callbacks('TimingStatus-Mon', self._timing_status) From 8184a83a55b85a1a76873dc59eda3ae2ae151ff7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 09:56:01 -0300 Subject: [PATCH 128/309] ORBINTLK.ENH: control LLRF manual interlock bypass state --- siriuspy/siriuspy/orbintlk/main.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f450c7940..4f726deee 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -224,7 +224,7 @@ def __init__(self, tests=True): devname=_ASLLRF.DEVICES.SI, props2init=[ 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', - 'IntlkSet-Cmd', + 'ILK:MAN:S', 'ILK:MAN', 'IntlkSet-Cmd', ]) # # auxiliary devices @@ -389,6 +389,10 @@ def _init_devices_lock(self): pvo.add_callback(_part( self._callback_lock, self._llrf, 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) + pvo = self._llrf.pv_object('ILK:MAN') + pvo.add_callback(_part( + self._callback_lock, self._llrf, + 'ILK:MAN:S', self._llrf_intlk_state)) pvo.run_callbacks() # BPM devices @@ -1044,8 +1048,9 @@ def _check_configs(self): dev = self._llrf if dev.connected: value = _updt_bit(value, 0, 0) - value = _updt_bit( - value, 1, dev['ILK:BEAM:TRIP'] != self._llrf_intlk_state) + okc = dev['ILK:BEAM:TRIP'] == self._llrf_intlk_state + okc &= dev['ILK:MAN'] == self._llrf_intlk_state + value = _updt_bit(value, 1, not okc) self.run_callbacks('LLRFStatus-Mon', value) # check time elapsed From e3fe56b7cba3873df50b3937b6fa2c7749478145 Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 1 Dec 2023 13:02:44 -0300 Subject: [PATCH 129/309] Update ID device classes --- siriuspy/siriuspy/devices/ids.py | 58 +++----------------------------- 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 07dc4afb1..b29a4c1e6 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -411,8 +411,6 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): """Command to set and start pparam and kparam movements.""" if self.PARAM_PVS.PPARAM_SP is None: pparam = None - # else: - # pparam = self.pparameter if pparam is None else pparam kparam = self.kparameter if kparam is None else kparam # calc ETA @@ -445,12 +443,12 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): # wait for movement within reasonable time time_init = _time.time() while True: - condk = True if kparam is None else \ + k_pos_ok = True if kparam is None else \ abs(abs(self.kparameter_mon) - abs(kparam)) <= tol_kparam - condp = True if pparam is None else \ + p_pos_ok = True if pparam is None else \ abs(self.pparameter_mon - pparam) <= tol_pparam - if condp and condk and not self.is_moving: - break + if p_pos_ok and k_pos_ok and not self.is_moving: + return True if _time.time() - time_init > tol_total: print(f'tol_total: {tol_total:.3f} s') print(f'wait_time: {_time.time() - time_init:.3f} s') @@ -458,9 +456,6 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): return False _time.sleep(self._SHORT_SHUT_EYE) - # successfull movement at this point - return True - def cmd_change_polarization(self, polarization, timeout=None): """.""" if self.PARAM_PVS.POL_SEL not in self.properties_all: @@ -643,11 +638,6 @@ def cmd_move_stop(self, timeout=None): self['DevCtrl-Cmd'] = self._CMD_MOVE_STOP return True - # def cmd_move_start(self, timeout=None): - # """Send command to start ID movement.""" - # self['DevCtrl-Cmd'] = self._CMD_MOVE_START - # return True - # --- private methods --- def _write_sp(self, propties_sp, values, timeout=None): @@ -1203,46 +1193,6 @@ def pos_cid_mon(self): """ return self['CIDVirtPos-Mon'] - # --- cmd_move - - # def cmd_move_start(self, timeout=None): - # """Command to start movement.""" - # pparam, kparam = self.pparameter, self.kparameter - # return self.cmd_move(pparam, kparam, timeout) - - # def cmd_move_park(self, timeout=None): - # """Move ID to parked config.""" - # return self._move_start( - # self.PARAM_PVS.START_PARKING_CMD, timeout=timeout) - - # def cmd_move(self, pparam=None, kparam=None, timeout=None): - # """Command to set and start pparam and kparam movements.""" - # pparam = self.pparameter if pparam is None else pparam - # kparam = self.kparameter if kparam is None else kparam - # # check if polarization change is needed - # if abs(pparam - self.pparameter_mon) > self.pparameter_tol: - # # first move to K=0 - # t0_ = _time.time() - # if not super().cmd_move( - # pparam=None, kparam=0, timeout=timeout): - # return False - # t1_ = _time.time() - # timeout = timeout if timeout is None else \ - # max(0, timeout - (t1_ - t0_)) - # # then change pparam - # t0_ = _time.time() - # if not super().cmd_move( - # pparam=pparam, kparam=None, timeout=timeout): - # return False - # t1_ = _time.time() - # timeout = timeout if timeout is None else \ - # max(0, timeout - (t1_ - t0_)) - # # finally move to desired kparam - # if not super().cmd_move( - # pparam=None, kparam=kparam, timeout=timeout): - # return False - # return True - class WIG(_ID): """Wiggler Insertion Device.""" From 425c397e9ba2503fddb99b1bbdbdb13a0eb4c4d5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 09:57:18 -0300 Subject: [PATCH 130/309] ORBINTLK.ENH: lock delta redundancy EVR configurations --- siriuspy/siriuspy/orbintlk/csdev.py | 7 +++++++ siriuspy/siriuspy/orbintlk/main.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 1fa40f163..cbfb28b25 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -83,6 +83,13 @@ class Const(_csdev.Const): ('State-Sel', 1), ('Log-Sel', 0) ) + INTLKREDEVR_CONFIGS = ( + ('DevEnbl-Sel', 1), + ('DIN0State-Sel', 1), + ('DIN0Evt-SP', 118), + ('DIN0Polarity-Sel', 0), + ('DIN0Log-Sel', 0), + ) FOUT2_CONFIGS = ( ('RxEnbl-SP', 0b01000001), ) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 4f726deee..c9c3d8599 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -152,6 +152,17 @@ def __init__(self, tests=True): pvo.connection_callbacks.append(self._conn_callback_timing) self._everf_evtcnt = pvo.get() or 0 + # # delta redundancy EVR + self._evrdelta_dev = _Device( + 'IA-10RaBPM:TI-EVR', + props2init=[ + 'DevEnbl-Sel', 'DevEnbl-Sts', + 'DIN0State-Sel', 'DIN0State-Sts', + 'DIN0Evt-SP', 'DIN0Evt-RB', + 'DIN0Polarity-Sel', 'DIN0Polarity-Sts', + 'DIN0Log-Sel', 'DIN0Log-RB', + ]) + # # HL triggers self._llrf_trig = _Trigger( trigname='SI-Glob:TI-LLRF-PsMtm', props2init=[ @@ -366,6 +377,16 @@ def _init_devices_lock(self): propty_sp, desired_val)) pvo.run_callbacks() + # interlock redundancy EVR + self._evrdelta_dev.wait_for_connection(timeout=conntimeout) + for propty_sp, desired_val in self._const.INTLKREDEVR_CONFIGS: + propty_rb = _PVName.from_sp2rb(propty_sp) + pvo = self._evrdelta_dev.pv_object(propty_rb) + pvo.add_callback(_part( + self._callback_lock, self._evrdelta_dev, + propty_sp, desired_val)) + pvo.run_callbacks() + # triggers trig2config = { self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, From 674cb7cc9ee8671c464ef7ee9932a406715dc304 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 14:50:12 -0300 Subject: [PATCH 131/309] ORBINTLK.ENH: lock AFC physical and logical triggers --- siriuspy/siriuspy/orbintlk/csdev.py | 23 ++++++++ siriuspy/siriuspy/orbintlk/main.py | 82 ++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index cbfb28b25..800795241 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -93,6 +93,29 @@ class Const(_csdev.Const): FOUT2_CONFIGS = ( ('RxEnbl-SP', 0b01000001), ) + AFCPHYTRIG_CONFIGS = ( + ('Dir-Sel', 0), + ('DirPol-Sel', 1), + ('TrnLen-SP', 20), + ) + SIBPMLOGTRIG_CONFIGS = ( + ('TRIGGER4TrnSrc-Sel', 1), + ('TRIGGER4TrnOutSel-SP', 2), + ('TRIGGER_PM0RcvSrc-Sel', 0), + ('TRIGGER_PM0RcvInSel-SP', 2), + ('TRIGGER_PM1RcvSrc-Sel', 0), + ('TRIGGER_PM1RcvInSel-SP', 2), + ('TRIGGER_PM6RcvSrc-Sel', 0), + ('TRIGGER_PM6RcvInSel-SP', 2), + ('TRIGGER_PM7RcvSrc-Sel', 0), + ('TRIGGER_PM7RcvInSel-SP', 2), + ('TRIGGER_PM11RcvSrc-Sel', 0), + ('TRIGGER_PM11RcvInSel-SP', 2), + ('TRIGGER_PM12RcvSrc-Sel', 0), + ('TRIGGER_PM12RcvInSel-SP', 2), + ('TRIGGER_PM14RcvSrc-Sel', 0), + ('TRIGGER_PM14RcvInSel-SP', 2), + ) __EVG_CONFIGS = None __FOUTS_2_MON = None diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c9c3d8599..1ac35bcc2 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -17,7 +17,7 @@ from ..callbacks import Callback as _Callback from ..devices import OrbitInterlock as _OrbitIntlk, FamBPMs as _FamBPMs, \ EVG as _EVG, ASLLRF as _ASLLRF, Trigger as _Trigger, Device as _Device, \ - SOFB as _SOFB, HLFOFB as _FOFB + SOFB as _SOFB, HLFOFB as _FOFB, AFCPhysicalTrigger as _AFCPhysicalTrigger from .csdev import Const as _Const, ETypes as _ETypes @@ -222,13 +222,45 @@ def __init__(self, tests=True): 'ACQTrigger-Sel', 'ACQTrigger-Sts', 'ACQTriggerEvent-Sel', 'ACQTriggerEvent-Sts', 'ACQStatus-Sts', - 'INFOFAcqRate-RB', 'INFOMONITRate-RB']) + 'INFOFAcqRate-RB', 'INFOMONITRate-RB', + 'TRIGGER4TrnSrc-Sel', 'TRIGGER4TrnSrc-Sts', + 'TRIGGER4TrnOutSel-SP', 'TRIGGER4TrnOutSel-RB', + 'TRIGGER_PM0RcvSrc-Sel', 'TRIGGER_PM0RcvSrc-Sts', + 'TRIGGER_PM0RcvInSel-SP', 'TRIGGER_PM0RcvInSel-RB', + 'TRIGGER_PM1RcvSrc-Sel', 'TRIGGER_PM1RcvSrc-Sts', + 'TRIGGER_PM1RcvInSel-SP', 'TRIGGER_PM1RcvInSel-RB', + 'TRIGGER_PM6RcvSrc-Sel', 'TRIGGER_PM6RcvSrc-Sts', + 'TRIGGER_PM6RcvInSel-SP', 'TRIGGER_PM6RcvInSel-RB', + 'TRIGGER_PM7RcvSrc-Sel', 'TRIGGER_PM7RcvSrc-Sts', + 'TRIGGER_PM7RcvInSel-SP', 'TRIGGER_PM7RcvInSel-RB', + 'TRIGGER_PM11RcvSrc-Sel', 'TRIGGER_PM11RcvSrc-Sts', + 'TRIGGER_PM11RcvInSel-SP', 'TRIGGER_PM11RcvInSel-RB', + 'TRIGGER_PM12RcvSrc-Sel', 'TRIGGER_PM12RcvSrc-Sts', + 'TRIGGER_PM12RcvInSel-SP', 'TRIGGER_PM12RcvInSel-RB', + 'TRIGGER_PM14RcvSrc-Sel', 'TRIGGER_PM14RcvSrc-Sts', + 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB']) self._monit_rate, self._facq_rate = None, None self._monitsum2intlksum_factor = 0 - pvo = self._fambpm_dev.devices[0].pv_object('INFOMONITRate-RB') - pvo.add_callback(self._callback_get_bpm_rates) - pvo = self._fambpm_dev.devices[0].pv_object('INFOFAcqRate-RB') - pvo.add_callback(self._callback_get_bpm_rates) + for idx, dev in enumerate(self._fambpm_dev.devices): + pvo = dev.pv_object('INFOMONITRate-RB') + if idx == 0: + pvo.add_callback(self._callback_get_bpm_rates) + pvo = dev.pv_object('INFOFAcqRate-RB') + pvo.add_callback(self._callback_get_bpm_rates) + pvo.connection_callbacks.append(self._conn_callback_bpm) + + # # AFC physical trigger devices + phytrig_names = list() + for afcti, cratemap in _LLTimeSearch.get_crates_mapping().items(): + if '20RaBPMTL' in afcti: + continue + phytrig_names.extend(cratemap) + self._phytrig_devs = [ + _AFCPhysicalTrigger(dev, 4, props2init=[ + 'Dir-Sel', 'Dir-Sts', + 'DirPol-Sel', 'DirPol-Sts', + 'TrnLen-SP', 'TrnLen-RB']) + for dev in phytrig_names] # # RF devices self._llrf = _ASLLRF( @@ -417,8 +449,8 @@ def _init_devices_lock(self): pvo.run_callbacks() # BPM devices + # lock BPM interlock enable and limits prop2lock = [ - 'IntlkEn-Sts', 'IntlkMinSumEn-Sts', 'IntlkLmtMinSum-RB', 'IntlkPosEn-Sts', @@ -431,6 +463,7 @@ def _init_devices_lock(self): 'IntlkLmtAngMinX-RB', 'IntlkLmtAngMaxY-RB', 'IntlkLmtAngMinY-RB', + 'IntlkEn-Sts', ] self._orbintlk_dev.wait_for_connection(timeout=conntimeout) for dev in self._orbintlk_dev.devices: @@ -439,6 +472,30 @@ def _init_devices_lock(self): pvo.add_callback(self._callback_bpm_lock) pvo.run_callbacks() + # lock BPM logical triggers + self._fambpm_dev.wait_for_connection(timeout=conntimeout) + for dev in self._fambpm_dev.devices: + for prop_sp, desired_val in self._const.SIBPMLOGTRIG_CONFIGS: + prop_rb = _PVName.from_sp2rb(prop_sp) + pvo = dev.pv_object(prop_rb) + pvo.add_callback( + _part(self._callback_lock, dev, prop_sp, desired_val)) + pvo.run_callbacks() + + # lock AFC physical triggers + for dev in self._phytrig_devs: + dev.wait_for_connection(timeout=conntimeout) + for prop_sp, desired_val in self._const.AFCPHYTRIG_CONFIGS: + # only lock polarity of other AFC physical triggers + if dev.devname not in self._const.bpm_names and \ + prop_sp != 'DirPol-Sel': + continue + prop_rb = _PVName.from_sp2rb(prop_sp) + pvo = dev.pv_object(prop_rb) + pvo.add_callback( + _part(self._callback_lock, dev, prop_sp, desired_val)) + pvo.run_callbacks() + self._update_log('...lock running.') @property @@ -1224,6 +1281,17 @@ def _callback_get_bpm_rates(self, pvname, value, **kws): factor = 2**_np.ceil(_np.log2(frac)) / frac self._monitsum2intlksum_factor = factor + def _conn_callback_bpm(self, pvname, conn, **kws): + _ = kws + if conn: + return + devname = _PVName(pvname).device_name + self._update_log(f'WARN:{devname} disconnected') + is_failure = devname in self._bpm_mon_devs + if is_failure: + self._update_log('FATAL:Orbit interlock reliability failure') + self._handle_reliability_failure() + # --- reliability failure methods --- def _check_minsum_requirement(self, monit_sum=None): From b9604ea8e132ff2dfad3db0267fdcd095560aeb7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 10:06:11 -0300 Subject: [PATCH 132/309] ORBINTLK.FIX: do not write to devices on IOC initialization --- siriuspy/siriuspy/orbintlk/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 1ac35bcc2..94ffc6fa7 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -608,6 +608,12 @@ def _do_set_enbllist(self, intlk, value): f'{intlkname}EnblList-SP', self._enable_lists[intlk]) return False + # do not write to devices and save to file in initialization + if not self._init: + # update readback pv + self.run_callbacks(f'{intlkname}EnblList-RB', new) + return True + # check if new enable list do not imply in orbit interlock failure bkup_enbllist = self._enable_lists[intlk] bkup_bpmmon, bkup_timon = self._bpm_mon_devs, self._ti_mon_devs @@ -627,12 +633,6 @@ def _do_set_enbllist(self, intlk, value): self.run_callbacks( 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) - # do not set enable lists and save to file in initialization - if not self._init: - # update readback pv - self.run_callbacks(f'{intlkname}EnblList-RB', new) - return True - # handle device enable configuration # set BPM interlock specific enable state From 24c7fbdfebdc64e9c3c7249f2814208b1580cc88 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 10:07:02 -0300 Subject: [PATCH 133/309] ORBINTLK.FIX: do not write BPM general interlock enable when setting minimum sum threshold --- siriuspy/siriuspy/orbintlk/main.py | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 94ffc6fa7..7d6c9fe8f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -615,23 +615,24 @@ def _do_set_enbllist(self, intlk, value): return True # check if new enable list do not imply in orbit interlock failure - bkup_enbllist = self._enable_lists[intlk] - bkup_bpmmon, bkup_timon = self._bpm_mon_devs, self._ti_mon_devs - self._enable_lists[intlk] = new - self._bpm_mon_devs, self._ti_mon_devs = \ - self._get_monitored_devices() - self._config_fout_rxenbl() - if not self._check_ti_devices_status(self._ti_mon_devs): - self._update_log('ERR:Could not set enable list.') - self._enable_lists[intlk] = bkup_enbllist - self._bpm_mon_devs, self._ti_mon_devs = bkup_bpmmon, bkup_timon + if intlk in ['pos', 'ang']: + bkup_enbllist = self._enable_lists[intlk] + bkup_bpmmon, bkup_timon = self._bpm_mon_devs, self._ti_mon_devs + self._enable_lists[intlk] = new + self._bpm_mon_devs, self._ti_mon_devs = \ + self._get_monitored_devices() self._config_fout_rxenbl() - self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) - return False - self.run_callbacks( - 'BPMMonitoredDevices-Mon', '\n'.join(self._bpm_mon_devs)) - self.run_callbacks( - 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) + if not self._check_ti_devices_status(self._ti_mon_devs): + self._update_log('ERR:Could not set enable list.') + self._enable_lists[intlk] = bkup_enbllist + self._bpm_mon_devs, self._ti_mon_devs = bkup_bpmmon, bkup_timon + self._config_fout_rxenbl() + self.run_callbacks(f'{intlkname}EnblList-SP', bkup_enbllist) + return False + self.run_callbacks( + 'BPMMonitoredDevices-Mon', '\n'.join(self._bpm_mon_devs)) + self.run_callbacks( + 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) # handle device enable configuration From 26152d50ad3c536b556ad599637c5fd1b313d50c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 10:07:58 -0300 Subject: [PATCH 134/309] ORBINTLK.FIX: wait enable list setpoints in IOC initialization before setting internal init flag --- siriuspy/siriuspy/orbintlk/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7d6c9fe8f..3f5fc37ab 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -372,9 +372,14 @@ def init_database(self): if not okl: self.run_callbacks('MinSumLim-RB', val) + # wait while enable list and limits setpoint queue to be empty + while self._set_queue.qsize() > 0: + _time.sleep(0.5) + self._update_log('Started.') self._init = True + # start locking devices self._init_devices_lock() def _init_devices_lock(self): From e400d396563156f2df5810d661800a44ee8f3193 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:25:06 -0300 Subject: [PATCH 135/309] ORBINTLK.ENH: lock EVG interlock enable state --- siriuspy/siriuspy/orbintlk/main.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 3f5fc37ab..91a284d3e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -396,6 +396,10 @@ def _init_devices_lock(self): pvo.add_callback(_part( self._callback_lock, self._evg_dev, propty_sp, desired_val)) pvo.run_callbacks() + # lock interlock enable state + pvo = self._evg_dev.pv_object('IntlkCtrlEnbl-Sts') + pvo.add_callback(self._callback_evg_lock_intlk) + pvo.run_callbacks() # BPM Fouts for dev in self._fout_devs.values(): @@ -1354,6 +1358,15 @@ def _callback_lock( daemon=True) thread.start() + def _callback_evg_lock_intlk(self, pvname, value, **kwargs): + thread = _CAThread( + target=self._start_lock_thread, + args=( + self._evg_dev, 'IntlkCtrlEnbl-Sel', self._state, + pvname, value), + daemon=True) + thread.start() + def _callback_fout_lock(self, pvname, value, **kwargs): devname = _PVName(pvname).device_name desired_value = self._fout2rxenbl[devname] From 6f24d0227c89546880385a43c6c75fce200adbfd Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:26:14 -0300 Subject: [PATCH 136/309] ORBINTLK.ENH: for DELTA52 subsector (10), consider a failure only if redundant EVR is also not locked --- siriuspy/siriuspy/orbintlk/main.py | 33 ++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 91a284d3e..ac589ced2 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1212,23 +1212,40 @@ def _do_callback_rxlock(self, pvname, value): if _get_bit(value, bit): continue outnam = f'OUT{bit}' - self._update_log(f'FATAL:{outnam} of {devname} lost lock') + self._update_log(f'FATAL:{outnam} of {devname} not locked') devout = devname.substitute(propty_name=outnam) # verify if this is an orbit interlock reliability failure is_failure |= devout in self._ti_mon_devs else: - out = None + is_failure = False for dev in self._ti_mon_devs: + # verify fouts if 'Fout' not in dev: continue dev = _PVName(dev) + # if the fout from callback is a monitored one if dev.device_name == devname: - out = int(dev.propty_name[-1]) - break - is_failure = out is not None and not _get_bit(value, out) - if is_failure: - self._update_log('FATAL:Orbit interlock reliability failure') - self._handle_reliability_failure() + # verify if the monitored outs are locked + outnam = dev.propty_name + out = int(outnam[-1]) + if _get_bit(value, out): + continue + # if not, it is a reliability failure + is_failure = True + self._update_log(f'ERR:{outnam} of {devname} not locked') + if not is_failure: + return + # specifically for delta subsector (10), consider a failure only if + # redundancy timing path is also not locked + trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname][out] + if int(trigsrc.sub[0:2]) == 10: + rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] + is_failure &= not _get_bit(rxlock, 0) # out 0 + + if not is_failure: + return + self._update_log('FATAL:Orbit interlock reliability failure') + self._handle_reliability_failure() def _conn_callback_timing(self, pvname, conn, **kws): if conn: From cdba4d2ef3760aee8804cfc97bb61a81565d0a9d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:27:30 -0300 Subject: [PATCH 137/309] ORBINTLK.WIP: add attribute with BPM pair distances to be used in angle setpoint --- siriuspy/siriuspy/orbintlk/csdev.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 800795241..1099aed65 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -1,6 +1,7 @@ """Define PVs, constants and properties of High Level Orbit Interlock app.""" import os as _os +import numpy as _np from .. import csdev as _csdev from ..util import ClassProperty as _classproperty @@ -190,6 +191,14 @@ def __init__(self): # bpm position along the ring self.bpm_pos = _BPMSearch.get_positions(self.bpm_names) + # bpm distance for each BPM pair + aux_pos = _np.roll(self.bpm_pos, 1) + bpm_dist = _np.diff(aux_pos)[::2] + # copy same distance from next high beta section to injection section + bpm_dist[0] = bpm_dist[4*4] + bpm_dist = _np.repeat(bpm_dist, 2) + self.bpm_dist = _np.roll(bpm_dist, -1) + # bpm number self.nr_bpms = len(self.bpm_names) From 93093260ce628a9fa00f08272027632970ca0452 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:28:56 -0300 Subject: [PATCH 138/309] ORBINTLK.ENH: remove condition on dry-run state --- siriuspy/siriuspy/orbintlk/main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ac589ced2..0d75a797b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1346,11 +1346,6 @@ def _callback_monitor_sum(self, value, cb_info, **kws): cb_info[1].remove_callback(cb_info[0]) def _handle_reliability_failure(self): - # if in dry run, do not kill RF - if self._is_dry_run: - self._update_log('WARN:Dry run running, will not handle') - self._update_log('WARN:reliability failure.') - return if not self._state: self._update_log('WARN:Orbit interlock is not enabled.') return From 5dae174b0a9c2ceb0e0e41384898e480cb7ed743 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:30:59 -0300 Subject: [PATCH 139/309] ORBINTLK.FIX: do not add several callbacks to Sum PV when minimum sum is not satisfied in reliability failure handler --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 0d75a797b..c93115d35 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1352,7 +1352,8 @@ def _handle_reliability_failure(self): # if minimum sum condition is not satisfied, only monitor sum if not self._check_minsum_requirement(): pvo = self._sofb.pv_object('SlowSumRaw-Mon') - pvo.add_callback(self._callback_monitor_sum) + if not pvo.callbacks(): + pvo.add_callback(self._callback_monitor_sum) return # send soft interlock to RF self._update_log('FATAL:sending soft interlock to LLRF.') From e4e41fb103e6d1b5314e564e427165542a161edb Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 1 Dec 2023 17:32:39 -0300 Subject: [PATCH 140/309] ORBINTLK.MNT: code cleanup in file helper methods --- siriuspy/siriuspy/orbintlk/main.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c93115d35..79d4f5589 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1487,9 +1487,7 @@ def _update_log(self, msg): # --- file handlers --- def _load_file(self, intlk, dtype='en'): - suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' - msg = 'enable list' if dtype.startswith('en') else 'limits' - filename = getattr(self._const, intlk + suff) + filename, desc = self._get_file_info(intlk, dtype) if not _os.path.isfile(filename): return value = _np.loadtxt(filename) @@ -1498,20 +1496,28 @@ def _load_file(self, intlk, dtype='en'): else: okl = self.set_intlk_lims(intlk, value) if okl: - msg = f'Loaded {intlk} {msg}!' + msg = f'Loaded {intlk} {desc} from auto save!' else: - msg = f'ERR:Problem loading {intlk} {msg} from file.' + msg = f'ERR:Problem loading {intlk} {desc} from file.' self._update_log(msg) return okl def _save_file(self, intlk, value, dtype): - suff = '_enbl_fname' if dtype.startswith('en') else '_lim_fname' - msg = 'enable list' if dtype.startswith('en') else 'limits' + filename, desc = self._get_file_info(intlk, dtype) try: - filename = getattr(self._const, intlk+suff) path = _os.path.split(filename)[0] _os.makedirs(path, exist_ok=True) _np.savetxt(filename, value) except FileNotFoundError: self._update_log( - f'WARN:Could not save {intlk} {msg} to file.') + f'WARN:Could not save {intlk} {desc} to file.') + + def _get_file_info(self, intlk, dtype): + if dtype.startswith(('en', 'lim')): + desc = 'enable list' if dtype.startswith('en') else 'limits' + suff = '_enbl' if dtype.startswith('en') else '_lim' + fname = intlk + suff + else: + raise ValueError(f'file info not defined for {intlk} and {dtype}') + filename = getattr(self._const, fname + '_fname') + return filename, desc From 9c6a9a4e475953cd9b55ca5016fbc507aa6f0176 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 18:32:55 -0300 Subject: [PATCH 141/309] clientweb.MNT: adapt crates mapping parsing to new version of microTCA-vs-BPMs-mapping files --- siriuspy/siriuspy/clientweb/implementation.py | 2 +- siriuspy/siriuspy/optics/lattice_survey.py | 2 +- siriuspy/siriuspy/search/ll_time_search.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/clientweb/implementation.py b/siriuspy/siriuspy/clientweb/implementation.py index d914ddef4..ffc9684fb 100644 --- a/siriuspy/siriuspy/clientweb/implementation.py +++ b/siriuspy/siriuspy/clientweb/implementation.py @@ -140,7 +140,7 @@ def crates_mapping(timeout=_TIMEOUT): txt = '' for fi in files: for time in read_url(url + fi, timeout=timeout).splitlines(): - txt += '{0:20s}'.format(fi[6:13]) + time + '\n' + txt += f'{time:<40s}' + f'{fi[6:13]:>10s}\n' txt += '\n\n' return txt diff --git a/siriuspy/siriuspy/optics/lattice_survey.py b/siriuspy/siriuspy/optics/lattice_survey.py index 30c94c905..e3c708b9a 100644 --- a/siriuspy/siriuspy/optics/lattice_survey.py +++ b/siriuspy/siriuspy/optics/lattice_survey.py @@ -237,7 +237,7 @@ def _get_all_bpms(): line = line.strip() if not line or line[0] == '#': continue # empty line - _, dev, *_ = line.split() + dev, *_ = line.split() dev = _PVName(dev) if dev.dev in ('BPM', 'PBPM'): bpms.add(dev) diff --git a/siriuspy/siriuspy/search/ll_time_search.py b/siriuspy/siriuspy/search/ll_time_search.py index eeae9cb38..84a3c54be 100644 --- a/siriuspy/siriuspy/search/ll_time_search.py +++ b/siriuspy/siriuspy/search/ll_time_search.py @@ -477,7 +477,7 @@ def _get_crates_mapping(cls): line = line.strip() if not line or line[0] == '#': continue # empty line - crate, dev, *_ = line.split() + dev, *_, crate = line.split() dev = _PVName(dev) if crate not in mapping and dev.dev == 'AMCFPGAEVR': crates[crate] = dev From b1d696539bb7f8f1eeea2051f89a1fae160bec85 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 19:13:58 -0300 Subject: [PATCH 142/309] ORBINTLK.ENH: improve BPM interlock log --- siriuspy/siriuspy/orbintlk/main.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 79d4f5589..d5e5b70fd 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1264,17 +1264,34 @@ def _callback_bpm_intlk(self, pvname, value, **kws): _ = kws if not value: return - if not self._init: - return + # launch thread to log interlock details + _CAThread( + target=self._log_bpm_intlk, + args=(_PVName(pvname).device_name, ), + daemon=True).start() + # launch thread to send interlock to RF as a backup if self._thread_cbbpm and self._thread_cbbpm.is_alive(): return - bpmname = _PVName(pvname).device_name self._thread_cbbpm = _CAThread( - target=self._do_callback_bpm_intlk, args=(bpmname, ), daemon=True) + target=self._do_callback_bpm_intlk, daemon=True) self._thread_cbbpm.start() - def _do_callback_bpm_intlk(self, bpmname): - self._update_log(f'FATAL:{bpmname} raised orbit interlock.') + def _log_bpm_intlk(self, bpmname): + # log which interlock flag was raised + self._update_log(f'FATAL:{bpmname} raised interlock.') + props = [ + 'IntlkPosLowerLtcX-Mon', 'IntlkPosUpperLtcX-Mon', + 'IntlkPosLowerLtcY-Mon', 'IntlkPosUpperLtcY-Mon', + 'IntlkAngLowerLtcX-Mon', 'IntlkAngUpperLtcX-Mon', + 'IntlkAngLowerLtcY-Mon', 'IntlkAngUpperLtcY-Mon', + ] + for prop in props: + idx = self._const.bpm_names.index(bpmname) + intlk, pln = prop.split('-')[0].split('Intlk')[1].split('Ltc') + if self._orbintlk_dev.devices[idx][prop]: + self._update_log(f'FATAL:{bpmname} > {intlk} {pln}') + + def _do_callback_bpm_intlk(self): # send kill beam as fast as possible self._handle_reliability_failure() # wait minimum period for RF EVE event count to be updated From 0c676836fff997b256378f39c167a6ce4ab74cc5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 20:15:51 -0300 Subject: [PATCH 143/309] ORBINTLK.FIX: consider ACQStatus PV in BPM acquisition monitoring checks --- siriuspy/siriuspy/orbintlk/csdev.py | 1 + siriuspy/siriuspy/orbintlk/main.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 1099aed65..aa3bcfba7 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -178,6 +178,7 @@ def FOUTS_2_MON(cls): AcqChan = _csbpm.AcqChan AcqTrigTyp = _csbpm.AcqTrigTyp AcqRepeat = _csbpm.AcqRepeat + AcqStates = _csbpm.AcqStates def __init__(self): """Class constructor.""" diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d5e5b70fd..6891519c6 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1026,6 +1026,8 @@ def _check_configs(self): d.acq_repeat == self._const.AcqRepeat.Normal for d in bpms) okb &= all( d.acq_trigger == self._const.AcqTrigTyp.External for d in bpms) + okb &= all( + d.acq_status == self._const.AcqStates.External_Trig for d in bpms) value = _updt_bit(value, 8, not okb) self._bpm_status = value From 3ea8eed824296f6f5843678d3cc86104d0c6821b Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 20:23:44 -0300 Subject: [PATCH 144/309] ORBINTLK.ENH: add callback to HL triggers Status, consider reliability failure if Status not ok --- siriuspy/siriuspy/orbintlk/csdev.py | 60 +++++------ siriuspy/siriuspy/orbintlk/main.py | 154 ++++++++-------------------- 2 files changed, 75 insertions(+), 139 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index aa3bcfba7..941b6b005 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -55,35 +55,37 @@ class Const(_csdev.Const): DEF_TIME2WAIT_INTLKREARM = 2*60 # [s] - ORBINTLKTRIG_CONFIG = ( - ('Src-Sel', 4), - ('DelayRaw-SP', 0), - ('State-Sel', 1), - ('WidthRaw-SP', 1), - ('Direction-Sel', 1), - ) - LLRFTRIG_CONFIG = ( - ('Src-Sel', 5), - ('DelayRaw-SP', 0), - ('State-Sel', 1), - ('WidthRaw-SP', 9369), - ) - BPMPSMTNTRIG_CONFIG = ( - ('Src-Sel', 5), - ('DelayRaw-SP', 0), - ('State-Sel', 1), - ('WidthRaw-SP', 6), - ) - DCCT13C4TRIG_CONFIG = ( - ('Src-Sel', 0), - ('State-Sel', 1), - ('Log-Sel', 0) - ) - DCCT14C4TRIG_CONFIG = ( - ('Src-Sel', 0), - ('State-Sel', 1), - ('Log-Sel', 0) - ) + HLTRIG_2_CONFIG = [ + ('SI-Fam:TI-BPM-OrbIntlk', ( + ('Src-Sel', 4), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 1), + ('Direction-Sel', 1)) + ), + ('SI-Glob:TI-LLRF-PsMtm', ( + ('Src-Sel', 5), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 9369)) + ), + ('SI-Fam:TI-BPM-PsMtm', ( + ('Src-Sel', 5), + ('DelayRaw-SP', 0), + ('State-Sel', 1), + ('WidthRaw-SP', 6)) + ), + ('SI-13C4:TI-DCCT-PsMtm', ( + ('Src-Sel', 0), + ('State-Sel', 1), + ('Log-Sel', 0)) + ), + ('SI-14C4:TI-DCCT-PsMtm', ( + ('Src-Sel', 0), + ('State-Sel', 1), + ('Log-Sel', 0)) + ), + ] INTLKREDEVR_CONFIGS = ( ('DevEnbl-Sel', 1), ('DIN0State-Sel', 1), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6891519c6..6221d3d00 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -164,46 +164,21 @@ def __init__(self, tests=True): ]) # # HL triggers - self._llrf_trig = _Trigger( - trigname='SI-Glob:TI-LLRF-PsMtm', props2init=[ - 'Src-Sel', 'Src-Sts', - 'DelayRaw-SP', 'DelayRaw-RB', - 'State-Sel', 'State-Sts', - 'WidthRaw-SP', 'WidthRaw-RB', - 'Status-Mon', - ], auto_monitor_mon=True) - - self._bpmpsmtn_trig = _Trigger( - trigname='SI-Fam:TI-BPM-PsMtm', props2init=[ - 'Src-Sel', 'Src-Sts', - 'DelayRaw-SP', 'DelayRaw-RB', - 'State-Sel', 'State-Sts', - 'WidthRaw-SP', 'WidthRaw-RB', - 'Status-Mon', - ], auto_monitor_mon=True) - - self._orbintlk_trig = _Trigger( - trigname='SI-Fam:TI-BPM-OrbIntlk', props2init=[ - 'Src-Sel', 'Src-Sts', - 'DelayRaw-SP', 'DelayRaw-RB', - 'State-Sel', 'State-Sts', - 'WidthRaw-SP', 'WidthRaw-RB', - 'Direction-Sel', 'Direction-Sts', - 'Status-Mon', - ], auto_monitor_mon=True) - - self._dcct13c4_trig = _Trigger( - trigname='SI-13C4:TI-DCCT-PsMtm', props2init=[ - 'Src-Sel', 'Src-Sts', - 'State-Sel', 'State-Sts', - 'Status-Mon', - ], auto_monitor_mon=True) - self._dcct14c4_trig = _Trigger( - trigname='SI-14C4:TI-DCCT-PsMtm', props2init=[ - 'Src-Sel', 'Src-Sts', - 'State-Sel', 'State-Sts', - 'Status-Mon', - ], auto_monitor_mon=True) + self._hltrig_devs = dict() + for trigname, configs in self._const.HLTRIG_2_CONFIG: + props2init = list() + for prop, _ in configs: + props2init.append(prop) + props2init.append(_PVName.from_sp2rb(prop)) + props2init.append('Status-Mon') + self._hltrig_devs[trigname] = _Trigger( + trigname=trigname, + props2init=props2init, + auto_monitor_mon=True) + if 'DCCT' in trigname: + continue + pvo = self._hltrig_devs[trigname].pv_object('Status-Mon') + pvo.add_callback(self._callback_hltrig_status) # # BPM devices self._orbintlk_dev = _OrbitIntlk() @@ -429,20 +404,14 @@ def _init_devices_lock(self): pvo.run_callbacks() # triggers - trig2config = { - self._orbintlk_trig: self._const.ORBINTLKTRIG_CONFIG, - self._llrf_trig: self._const.LLRFTRIG_CONFIG, - self._bpmpsmtn_trig: self._const.BPMPSMTNTRIG_CONFIG, - self._dcct13c4_trig: self._const.DCCT13C4TRIG_CONFIG, - self._dcct14c4_trig: self._const.DCCT14C4TRIG_CONFIG, - } - for trig, configs in trig2config.items(): - trig.wait_for_connection(timeout=conntimeout) + for trigname, configs in self._const.HLTRIG_2_CONFIG: + trigdev = self._hltrig_devs[trigname] + trigdev.wait_for_connection(timeout=conntimeout) for prop_sp, desired_val in configs: prop_rb = _PVName.from_sp2rb(prop_sp) - pvo = trig.pv_object(prop_rb) + pvo = trigdev.pv_object(prop_rb) pvo.add_callback( - _part(self._callback_lock, trig, prop_sp, desired_val)) + _part(self._callback_lock, trigdev, prop_sp, desired_val)) pvo.run_callbacks() # LLRF @@ -1070,65 +1039,20 @@ def _check_configs(self): value = _updt_bit(value, 6, not okg) else: value += 0b11 << 5 - # Orbit Interlock trigger - dev = self._orbintlk_trig - if dev.connected: - value = _updt_bit(value, 8, bool(dev['Status-Mon'])) - oko = True - for prp, val in self._const.ORBINTLKTRIG_CONFIG: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') - oko &= dev[prp_rb] == val - value = _updt_bit(value, 9, not oko) - else: - value += 0b111 << 7 - # LLRF PsMtm trigger - dev = self._llrf_trig - oko = False - if dev.connected: - value = _updt_bit(value, 11, bool(dev['Status-Mon'])) - oko = True - for prp, val in self._const.LLRFTRIG_CONFIG: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') - oko &= dev[prp_rb] == val - value = _updt_bit(value, 12, not oko) - else: - value += 0b111 << 10 - # BPM PsMtm trigger - dev = self._bpmpsmtn_trig - oko = False - if dev.connected: - value = _updt_bit(value, 14, bool(dev['Status-Mon'])) - oko = True - for prp, val in self._const.BPMPSMTNTRIG_CONFIG: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') - oko &= dev[prp_rb] == val - value = _updt_bit(value, 15, not oko) - else: - value += 0b111 << 13 - # DCCT 13C4 trigger - dev = self._dcct13c4_trig - oko = False - if dev.connected: - value = _updt_bit(value, 17, bool(dev['Status-Mon'])) - oko = True - for prp, val in self._const.DCCT13C4TRIG_CONFIG: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') - oko &= dev[prp_rb] == val - value = _updt_bit(value, 18, not oko) - else: - value += 0b111 << 16 - # DCCT 14C4 trigger - dev = self._dcct14c4_trig - oko = False - if dev.connected: - value = _updt_bit(value, 20, bool(dev['Status-Mon'])) - oko = True - for prp, val in self._const.DCCT14C4TRIG_CONFIG: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') - oko &= dev[prp_rb] == val - value = _updt_bit(value, 21, not oko) - else: - value += 0b111 << 19 + # HL triggers + bit = 7 + for trigname, configs in self._const.HLTRIG_2_CONFIG: + dev = self._hltrig_devs[trigname] + if dev.connected: + value = _updt_bit(value, bit+1, bool(dev['Status-Mon'])) + oko = True + for prp, val in configs: + prp_rb = _PVName.from_sp2rb(prp) + oko &= dev[prp_rb] == val + value = _updt_bit(value, bit+2, not oko) + else: + value += 0b111 << bit + bit += 3 self._timing_status = value self.run_callbacks('TimingStatus-Mon', self._timing_status) @@ -1338,6 +1262,16 @@ def _conn_callback_bpm(self, pvname, conn, **kws): self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() + def _callback_hltrig_status(self, pvname, value, **kws): + _ = kws + if not value: + return + # if status is not ok, it is a reliability failure + trigname = _PVName(pvname).device_name + self._update_log(f'FATAL:{trigname} Status not ok') + self._update_log('FATAL:Orbit interlock reliability failure') + self._handle_reliability_failure() + # --- reliability failure methods --- def _check_minsum_requirement(self, monit_sum=None): From 47d646c594dd2ba76360c0fe6ed5e6407f3d93a9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 20:40:13 -0300 Subject: [PATCH 145/309] ORBINTLK.MNT: cleanup code and improve logging --- siriuspy/siriuspy/orbintlk/main.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6221d3d00..541785712 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1176,12 +1176,12 @@ def _do_callback_rxlock(self, pvname, value): def _conn_callback_timing(self, pvname, conn, **kws): if conn: return - pvname = _PVName(pvname) - self._update_log(f'FATAL:{pvname.device_name} disconnected') + devname = _PVName(pvname).device_name + self._update_log(f'FATAL:{devname} disconnected') # verify if this is an orbit interlock reliability failure is_failure = False for dev in self._ti_mon_devs: - is_failure |= _PVName(dev).device_name == pvname.device_name + is_failure |= _PVName(dev).device_name == devname if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() @@ -1232,7 +1232,7 @@ def _do_callback_bpm_intlk(self): # verify if EVG propagated the event Intlk evgintlksts = self._evg_dev['IntlkEvtStatus-Mon'] if not evgintlksts & 0b1: - self._update_log('WARN:EVG did not propagate event Intlk') + self._update_log('ERR:EVG did not propagate event Intlk') # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') @@ -1444,9 +1444,10 @@ def _load_file(self, intlk, dtype='en'): if not _os.path.isfile(filename): return value = _np.loadtxt(filename) + okl = True if dtype.startswith('en'): okl = self.set_enbllist(intlk, value) - else: + elif dtype.startswith('lim'): okl = self.set_intlk_lims(intlk, value) if okl: msg = f'Loaded {intlk} {desc} from auto save!' From dd7d3302cb9096836080f6d08eb2dd724e04bfe7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 23:36:56 -0300 Subject: [PATCH 146/309] ORBINTLK.MNT: remove checks on RF EVE --- siriuspy/siriuspy/orbintlk/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 541785712..1249cac40 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -149,7 +149,6 @@ def __init__(self, tests=True): auto_monitor_mon=True) pvo = self._everf_dev.pv_object(self._llrf_evtcnt_pvname) pvo.wait_for_connection() - pvo.connection_callbacks.append(self._conn_callback_timing) self._everf_evtcnt = pvo.get() or 0 # # delta redundancy EVR @@ -902,7 +901,7 @@ def _get_monitored_devices(self): # timing tidevs = set() - tidevs.add(self._everf_dev.devname) + tidevs.add(self._evg_dev.devname) aux = _np.roll(enbllist, 1) subsecs = _np.where(_np.sum(aux.reshape(20, -1), axis=1) > 0)[0] subsecs += 1 From e92a8f464597230b5be3cb99f9145d89c0605eaf Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sat, 2 Dec 2023 23:38:19 -0300 Subject: [PATCH 147/309] ORBINTLK.MNT: improve logging when checking timing devices state --- siriuspy/siriuspy/orbintlk/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 1249cac40..ed904676e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -922,7 +922,11 @@ def _check_ti_devices_status(self, devices): dev = self._evg_dev if 'EVG' in devname else \ self._fout_devs[devname.device_name] if 'Fout' in devname \ - else self._afcti_devs[int(devname.sub[:2])] + else self._afcti_devs[int(devname.sub[:2])] \ + if 'AMCFPGA' in devname else None + if dev is None: + self._update_log(f'ERR:Could not verify {devname} state.') + return False if not dev.connected: self._update_log(f'ERR:{dev.devname} not connected') From 6509a1263a6ec7f1ced462961c84598c731f055d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 00:22:52 -0300 Subject: [PATCH 148/309] ORBINTLK.FIX: fix bugs left in enable list setpoint --- siriuspy/siriuspy/orbintlk/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ed904676e..45ba65670 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -585,17 +585,19 @@ def _do_set_enbllist(self, intlk, value): f'{intlkname}EnblList-SP', self._enable_lists[intlk]) return False + bkup_enbllist = self._enable_lists[intlk] + self._enable_lists[intlk] = new + # do not write to devices and save to file in initialization if not self._init: + self._update_log('...done.') # update readback pv self.run_callbacks(f'{intlkname}EnblList-RB', new) return True # check if new enable list do not imply in orbit interlock failure if intlk in ['pos', 'ang']: - bkup_enbllist = self._enable_lists[intlk] bkup_bpmmon, bkup_timon = self._bpm_mon_devs, self._ti_mon_devs - self._enable_lists[intlk] = new self._bpm_mon_devs, self._ti_mon_devs = \ self._get_monitored_devices() self._config_fout_rxenbl() @@ -684,6 +686,7 @@ def _do_set_intlk_lims(self, intlk_lim, value): # do not set limits and save to file in initialization if not self._init: + self._update_log('...done.') # update readback pv self.run_callbacks(f'{limname}Lim-RB', new) return True From 6d3a797cb74a888c2c580079a88252c6948bc4c6 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 01:03:29 -0300 Subject: [PATCH 149/309] ORBINTLK.FIX: fix Fout RxEnbl initial check value --- siriuspy/siriuspy/orbintlk/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 45ba65670..784e4a7a3 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -327,6 +327,7 @@ def init_database(self): 'BPMMonitoredDevices-Mon', '\n'.join(self._bpm_mon_devs)) self.run_callbacks( 'TimingMonitoredDevices-Mon', '\n'.join(self._ti_mon_devs)) + self._config_fout_rxenbl() # limits for ilk in ['Pos', 'Ang']: @@ -887,6 +888,8 @@ def _config_fout_rxenbl(self): for fout, dev in self._fout_devs.items(): rxenbl = fout2rx.get(fout, 0) self._fout2rxenbl[fout] = rxenbl + if not self._init: + continue dev['RxEnbl-SP'] = rxenbl dev._wait('RxEnbl-RB', rxenbl, timeout=1) dev['RxLockedLtcRst-Cmd'] = 1 From 4d4b71bc4746163abbd7800cca50d5add99adbbb Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 01:40:05 -0300 Subject: [PATCH 150/309] ORBINTLK.ENH: move Enable setpoint to setpoint queue --- siriuspy/siriuspy/orbintlk/main.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 784e4a7a3..ecbcfe4e3 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -522,12 +522,18 @@ def fambpm_dev(self): def set_enable(self, value): """Set orbit interlock state. Configure global BPM interlock enable and EVG interlock enable.""" + self._set_queue.put((self._do_set_enable, (value, ))) + return True + + def _do_set_enable(self, value): if not 0 <= value < len(_ETypes.DSBL_ENBL): + self.run_callbacks('Enable-Sel', self._state) return False if value: if not self._check_ti_devices_status(self._ti_mon_devs): self._update_log('ERR:Could not enable orbit interlock.') + self.run_callbacks('Enable-Sel', self._state) return False glob_en = self._get_gen_bpm_intlk() else: @@ -540,6 +546,7 @@ def set_enable(self, value): self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') self._state = bkup + self.run_callbacks('Enable-Sel', self._state) return False self._update_log('Configured BPM general interlock enable.') @@ -548,6 +555,7 @@ def set_enable(self, value): 'IntlkCtrlEnbl-Sts', value, timeout=self._const.DEF_TIMEOUT): self._update_log('ERR:Could not set EVG interlock enable.') self._state = bkup + self.run_callbacks('Enable-Sel', self._state) return False self._update_log('Configured EVG interlock enable.') From c9f941540a471f5587bab1bea7c6c71ea62a43af Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 01:40:45 -0300 Subject: [PATCH 151/309] ORBINTLK.FIX: wait queue to end tasks properly --- siriuspy/siriuspy/orbintlk/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ecbcfe4e3..d1849a38d 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -348,8 +348,7 @@ def init_database(self): self.run_callbacks('MinSumLim-RB', val) # wait while enable list and limits setpoint queue to be empty - while self._set_queue.qsize() > 0: - _time.sleep(0.5) + self._set_queue.join() self._update_log('Started.') self._init = True From 20eda83299c3e67587386279fd3bc8860100f233 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:04:36 -0300 Subject: [PATCH 152/309] ORBINTLK.ENH: change way we get MONIT to FAcq factor for BPM Sum --- siriuspy/siriuspy/orbintlk/main.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d1849a38d..252ce02b3 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -213,14 +213,9 @@ def __init__(self, tests=True): 'TRIGGER_PM12RcvInSel-SP', 'TRIGGER_PM12RcvInSel-RB', 'TRIGGER_PM14RcvSrc-Sel', 'TRIGGER_PM14RcvSrc-Sts', 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB']) - self._monit_rate, self._facq_rate = None, None self._monitsum2intlksum_factor = 0 for idx, dev in enumerate(self._fambpm_dev.devices): pvo = dev.pv_object('INFOMONITRate-RB') - if idx == 0: - pvo.add_callback(self._callback_get_bpm_rates) - pvo = dev.pv_object('INFOFAcqRate-RB') - pvo.add_callback(self._callback_get_bpm_rates) pvo.connection_callbacks.append(self._conn_callback_bpm) # # AFC physical trigger devices @@ -1252,20 +1247,18 @@ def _do_callback_bpm_intlk(self): # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') - def _callback_get_bpm_rates(self, pvname, value, **kws): - if value is None: - return - if 'MONIT' in pvname: - self._monit_rate = value - elif 'FAcq' in pvname: - self._facq_rate = value - monit = self._monit_rate - facq = self._facq_rate + def _get_bpm_rates_factor(self): + if self._monitsum2intlksum_factor: + return self._monitsum2intlksum_factor + monit = self._fambpm_dev.devices[0]['INFOMONITRate-RB'] + facq = self._fambpm_dev.devices[0]['INFOFAcqRate-RB'] + if None in [monit, facq]: - return + return 0 frac = monit/facq factor = 2**_np.ceil(_np.log2(frac)) / frac self._monitsum2intlksum_factor = factor + return self._monitsum2intlksum_factor def _conn_callback_bpm(self, pvname, conn, **kws): _ = kws @@ -1293,7 +1286,7 @@ def _callback_hltrig_status(self, pvname, value, **kws): def _check_minsum_requirement(self, monit_sum=None): if monit_sum is None: monit_sum = self._sofb['SlowSumRaw-Mon'] - facq_sum = monit_sum * self._monitsum2intlksum_factor + facq_sum = monit_sum * self._get_bpm_rates_factor() return _np.all(facq_sum > self._limits['minsum']) def _callback_monitor_sum(self, value, cb_info, **kws): From ba56c9e95a891e529bf95c16782534984b438c8f Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:05:14 -0300 Subject: [PATCH 153/309] ORBINTLK.FIX: fix bug on checking Sum PVs callbacks --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 252ce02b3..4b21bbb8f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1314,7 +1314,7 @@ def _handle_reliability_failure(self): # if minimum sum condition is not satisfied, only monitor sum if not self._check_minsum_requirement(): pvo = self._sofb.pv_object('SlowSumRaw-Mon') - if not pvo.callbacks(): + if not pvo.callbacks: pvo.add_callback(self._callback_monitor_sum) return # send soft interlock to RF From 0641729e6cd8160781b58e82b71db37fd13cb23d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:06:04 -0300 Subject: [PATCH 154/309] ORBINTLK.MNT: change IA-10RaBPM:TI-EVR log configuration --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 941b6b005..4210fe2e5 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -91,7 +91,7 @@ class Const(_csdev.Const): ('DIN0State-Sel', 1), ('DIN0Evt-SP', 118), ('DIN0Polarity-Sel', 0), - ('DIN0Log-Sel', 0), + ('DIN0Log-Sel', 1), ) FOUT2_CONFIGS = ( ('RxEnbl-SP', 0b01000001), From 3648cdd82b87b1958b235a86014b561ea857deaf Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:07:47 -0300 Subject: [PATCH 155/309] ORBINTLK.ENH: disable lock when interlock is disabled --- siriuspy/siriuspy/orbintlk/csdev.py | 6 + siriuspy/siriuspy/orbintlk/main.py | 210 +++++++++++++++++++--------- 2 files changed, 151 insertions(+), 65 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 4210fe2e5..d3d96e44a 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -96,6 +96,12 @@ class Const(_csdev.Const): FOUT2_CONFIGS = ( ('RxEnbl-SP', 0b01000001), ) + AFCTI_CONFIGS = ( + ('RTMPhasePropGain-SP', 100), + ('RTMPhaseIntgGain-SP', 1), + ('RTMFreqPropGain-SP', 1), + ('RTMFreqIntgGain-SP', 128), + ) AFCPHYTRIG_CONFIGS = ( ('Dir-Sel', 0), ('DirPol-Sel', 1), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 4b21bbb8f..f0b53ccb3 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -68,7 +68,11 @@ def __init__(self, tests=True): self._ti_mon_devs = list() self._lock_threads = dict() self._lock_failures = set() - self._lock_suspend = False + self._lock_suspend = True + self._lock_pvs = { + k: list() for k in + ['EVG', 'Fouts', 'EVRRedun', 'AFCTI', 'HLTriggers', + 'LLRF', 'BPM', 'AFCPhysTriggers']} self._set_queue = _LoopQueueThread() self._set_queue.start() @@ -132,6 +136,10 @@ def __init__(self, tests=True): props2init=[ 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', 'RTMClkRst-Cmd', + 'RTMPhasePropGain-SP', 'RTMPhasePropGain-RB', + 'RTMPhaseIntgGain-SP', 'RTMPhaseIntgGain-RB', + 'RTMFreqPropGain-SP', 'RTMFreqPropGain-RB', + 'RTMFreqIntgGain-SP', 'RTMFreqIntgGain-RB', ], auto_monitor_mon=True) for idx in range(20) } @@ -348,79 +356,131 @@ def init_database(self): self._update_log('Started.') self._init = True - # start locking devices - self._init_devices_lock() - - def _init_devices_lock(self): - self._update_log('Waiting 5s to start locking...') - _time.sleep(5) - - conntimeout = self._const.DEF_TIMEOUT - - # EVG - self._evg_dev.wait_for_connection(timeout=conntimeout) + # start init lock devices + self._lock_temp_pvs = set() + self._enable_lock(init=True) + + def _enable_lock(self, init=False): + if not init: + self._lock_suspend = False + self._handle_lock_evg_configs(init) + self._handle_lock_fouts(init) + self._handle_lock_redundancy_evr(init) + self._handle_lock_afcti(init) + self._handle_lock_hltriggers(init) + self._handle_lock_llrf(init) + self._handle_lock_bpm_configs(init) + self._handle_lock_afcphytrigs(init) + if init: + self._handle_lock_evg_enable(init) + self._handle_lock_bpm_enable(init) + + def _disable_lock(self): + self._lock_temp_pvs = set() + self._lock_suspend = True + + def _handle_lock_evg_configs(self, init=False): + self._evg_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for propty_sp, desired_val in self._const.EVG_CONFIGS: propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._evg_dev.pv_object(propty_rb) - pvo.add_callback(_part( - self._callback_lock, self._evg_dev, propty_sp, desired_val)) - pvo.run_callbacks() + if init: + self._lock_pvs['EVG'].append(pvo.pvname) + pvo.add_callback(_part( + self._callback_lock, self._evg_dev, propty_sp, desired_val)) + else: + pvo.run_callbacks() + + def _handle_lock_evg_enable(self, init=False): # lock interlock enable state pvo = self._evg_dev.pv_object('IntlkCtrlEnbl-Sts') - pvo.add_callback(self._callback_evg_lock_intlk) - pvo.run_callbacks() + if init: + pvo.add_callback(self._callback_evg_lock_intlk) + else: + pvo.run_callbacks() + def _handle_lock_fouts(self, init=False): # BPM Fouts for dev in self._fout_devs.values(): - dev.wait_for_connection(timeout=conntimeout) + dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) pvo = dev.pv_object('RxEnbl-RB') - pvo.add_callback(self._callback_fout_lock) - pvo.run_callbacks() + if init: + self._lock_pvs['Fouts'].append(pvo.pvname) + pvo.add_callback(self._callback_fout_lock) + else: + pvo.run_callbacks() # DCCT Fout - self._fout_dcct_dev.wait_for_connection(timeout=conntimeout) + self._fout_dcct_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for propty_sp, desired_val in self._const.FOUT2_CONFIGS: propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._fout_dcct_dev.pv_object(propty_rb) - pvo.add_callback(_part( - self._callback_lock, self._fout_dcct_dev, - propty_sp, desired_val)) - pvo.run_callbacks() + if init: + self._lock_pvs['Fouts'].append(pvo.pvname) + pvo.add_callback(_part( + self._callback_lock, self._fout_dcct_dev, + propty_sp, desired_val)) + else: + pvo.run_callbacks() - # interlock redundancy EVR - self._evrdelta_dev.wait_for_connection(timeout=conntimeout) + def _handle_lock_redundancy_evr(self, init=False): + self._evrdelta_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for propty_sp, desired_val in self._const.INTLKREDEVR_CONFIGS: propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._evrdelta_dev.pv_object(propty_rb) - pvo.add_callback(_part( - self._callback_lock, self._evrdelta_dev, - propty_sp, desired_val)) - pvo.run_callbacks() + if init: + self._lock_pvs['EVRRedun'].append(pvo.pvname) + pvo.add_callback(_part( + self._callback_lock, self._evrdelta_dev, + propty_sp, desired_val)) + else: + pvo.run_callbacks() - # triggers + def _handle_lock_afcti(self, init=False): + for dev in self._afcti_devs.values(): + dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) + for propty_sp, desired_val in self._const.AFCTI_CONFIGS: + propty_rb = _PVName.from_sp2rb(propty_sp) + pvo = dev.pv_object(propty_rb) + if init: + self._lock_pvs['AFCTI'].append(pvo.pvname) + pvo.add_callback(_part( + self._callback_lock, dev, propty_sp, desired_val)) + else: + pvo.run_callbacks() + + def _handle_lock_hltriggers(self, init=False): for trigname, configs in self._const.HLTRIG_2_CONFIG: trigdev = self._hltrig_devs[trigname] - trigdev.wait_for_connection(timeout=conntimeout) + trigdev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for prop_sp, desired_val in configs: prop_rb = _PVName.from_sp2rb(prop_sp) pvo = trigdev.pv_object(prop_rb) - pvo.add_callback( - _part(self._callback_lock, trigdev, prop_sp, desired_val)) - pvo.run_callbacks() + if init: + self._lock_pvs['HLTriggers'].append(pvo.pvname) + pvo.add_callback( + _part(self._callback_lock, trigdev, prop_sp, desired_val)) + else: + pvo.run_callbacks() + + def _handle_lock_llrf(self, init=False): + self._llrf.wait_for_connection(timeout=self._const.DEF_TIMEOUT) + pvo_beamtrip = self._llrf.pv_object('ILK:BEAM:TRIP') + pvo_manintlk = self._llrf.pv_object('ILK:MAN') + if init: + self._lock_pvs['LLRF'].append(pvo_beamtrip.pvname) + pvo_beamtrip.add_callback(_part( + self._callback_lock, self._llrf, + 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) + self._lock_pvs['LLRF'].append(pvo_manintlk.pvname) + pvo_manintlk.add_callback(_part( + self._callback_lock, self._llrf, + 'ILK:MAN:S', self._llrf_intlk_state)) + else: + pvo_beamtrip.run_callbacks() + pvo_manintlk.run_callbacks() - # LLRF - self._llrf.wait_for_connection(timeout=conntimeout) - pvo = self._llrf.pv_object('ILK:BEAM:TRIP') - pvo.add_callback(_part( - self._callback_lock, self._llrf, - 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) - pvo = self._llrf.pv_object('ILK:MAN') - pvo.add_callback(_part( - self._callback_lock, self._llrf, - 'ILK:MAN:S', self._llrf_intlk_state)) - pvo.run_callbacks() - - # BPM devices + def _handle_lock_bpm_configs(self, init=False): # lock BPM interlock enable and limits prop2lock = [ 'IntlkMinSumEn-Sts', @@ -435,40 +495,55 @@ def _init_devices_lock(self): 'IntlkLmtAngMinX-RB', 'IntlkLmtAngMaxY-RB', 'IntlkLmtAngMinY-RB', - 'IntlkEn-Sts', ] - self._orbintlk_dev.wait_for_connection(timeout=conntimeout) + self._orbintlk_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for dev in self._orbintlk_dev.devices: for prop in prop2lock: pvo = dev.pv_object(prop) - pvo.add_callback(self._callback_bpm_lock) - pvo.run_callbacks() + if init: + self._lock_pvs['BPM'].append(pvo.pvname) + pvo.add_callback(self._callback_bpm_lock) + else: + pvo.run_callbacks() # lock BPM logical triggers - self._fambpm_dev.wait_for_connection(timeout=conntimeout) + self._fambpm_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for dev in self._fambpm_dev.devices: for prop_sp, desired_val in self._const.SIBPMLOGTRIG_CONFIGS: prop_rb = _PVName.from_sp2rb(prop_sp) pvo = dev.pv_object(prop_rb) - pvo.add_callback( - _part(self._callback_lock, dev, prop_sp, desired_val)) + if init: + self._lock_pvs['BPM'].append(pvo.pvname) + pvo.add_callback( + _part(self._callback_lock, dev, prop_sp, desired_val)) + else: + pvo.run_callbacks() + + def _handle_lock_bpm_enable(self, init=False): + self._orbintlk_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) + for dev in self._orbintlk_dev.devices: + pvo = dev.pv_object('IntlkEn-Sts') + if init: + pvo.add_callback(self._callback_bpm_lock) + else: pvo.run_callbacks() - # lock AFC physical triggers + def _handle_lock_afcphytrigs(self, init=False): for dev in self._phytrig_devs: - dev.wait_for_connection(timeout=conntimeout) + dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for prop_sp, desired_val in self._const.AFCPHYTRIG_CONFIGS: - # only lock polarity of other AFC physical triggers + # only lock polarity of other AFC physical triggers than SI BPM if dev.devname not in self._const.bpm_names and \ prop_sp != 'DirPol-Sel': continue prop_rb = _PVName.from_sp2rb(prop_sp) pvo = dev.pv_object(prop_rb) - pvo.add_callback( - _part(self._callback_lock, dev, prop_sp, desired_val)) - pvo.run_callbacks() - - self._update_log('...lock running.') + if init: + self._lock_pvs['AFCPhysTriggers'].append(pvo.pvname) + pvo.add_callback( + _part(self._callback_lock, dev, prop_sp, desired_val)) + else: + pvo.run_callbacks() @property def pvs_database(self): @@ -536,6 +611,11 @@ def _do_set_enable(self, value): bkup = int(self._state) self._state = value + if self._state: + self._enable_lock() + else: + self._disable_lock() + if not self._orbintlk_dev.set_gen_enable(list(glob_en)): self._update_log('ERR:Could not set BPM general') self._update_log('ERR:interlock enable.') @@ -1387,7 +1467,7 @@ def _callback_bpm_lock(self, pvname, value, **kws): def _start_lock_thread( self, device, propty_sp, desired_value, pvname, value): - if self._lock_suspend: + if self._lock_suspend and pvname not in self._lock_temp_pvs: return # if there is already a lock thread, return From 2a5380718a952ed51d73b8c45b78275442c85993 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:13:58 -0300 Subject: [PATCH 156/309] ORBINTLK.FIX: fix keyerror in Fout RxLocked callback --- siriuspy/siriuspy/orbintlk/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f0b53ccb3..6c0af7349 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1254,8 +1254,9 @@ def _do_callback_rxlock(self, pvname, value): return # specifically for delta subsector (10), consider a failure only if # redundancy timing path is also not locked - trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname][out] - if int(trigsrc.sub[0:2]) == 10: + trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname] + trigsrc_at_out = trigsrc[f'OUT{out}'] + if trigsrc_at_out.sub[0:2] == '10': rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] is_failure &= not _get_bit(rxlock, 0) # out 0 From f5cc211dc893b18a56cc70c15f76c0dabf202a58 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:21:13 -0300 Subject: [PATCH 157/309] ORBINTLK.FIX: verify all Fout OUTs in RxLock callback --- siriuspy/siriuspy/orbintlk/main.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6c0af7349..ad1accda3 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1234,7 +1234,7 @@ def _do_callback_rxlock(self, pvname, value): # verify if this is an orbit interlock reliability failure is_failure |= devout in self._ti_mon_devs else: - is_failure = False + is_failure, outs_in_failure = False, set() for dev in self._ti_mon_devs: # verify fouts if 'Fout' not in dev: @@ -1249,16 +1249,16 @@ def _do_callback_rxlock(self, pvname, value): continue # if not, it is a reliability failure is_failure = True + outs_in_failure.add(out) self._update_log(f'ERR:{outnam} of {devname} not locked') - if not is_failure: - return # specifically for delta subsector (10), consider a failure only if # redundancy timing path is also not locked trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname] - trigsrc_at_out = trigsrc[f'OUT{out}'] - if trigsrc_at_out.sub[0:2] == '10': - rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] - is_failure &= not _get_bit(rxlock, 0) # out 0 + for out in outs_in_failure: + trigsrcout = trigsrc[f'OUT{out}'] + if trigsrcout.sub[0:2] == '10': + rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] + is_failure &= not _get_bit(rxlock, 0) # out 0 if not is_failure: return From cbaf74f9c9a00c87bd8784d205f84468945988e5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:26:28 -0300 Subject: [PATCH 158/309] DEV.ENH: catch CA exceptions when setting PV value in Device.__setitem__ --- siriuspy/siriuspy/devices/device.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 41031f7e4..c109037b0 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -200,7 +200,10 @@ def __getitem__(self, propty): def __setitem__(self, propty, value): """Set value of property.""" pvobj = self.pv_object(propty) - pvobj.value = value + try: + pvobj.value = value + except (_ChannelAccessGetFailure, _CASeverityException): + print('Could not set value of {}'.format(pvobj.pvname)) # --- private methods --- def _create_pv(self, propty): From 5514d9c41732004ba41886d4b3629082bcaefc38 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 02:38:53 -0300 Subject: [PATCH 159/309] ORBINTLK.FIX: only consider redundancy EVR state for subsector 10 --- siriuspy/siriuspy/orbintlk/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ad1accda3..f6aed4e33 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1254,9 +1254,9 @@ def _do_callback_rxlock(self, pvname, value): # specifically for delta subsector (10), consider a failure only if # redundancy timing path is also not locked trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname] - for out in outs_in_failure: - trigsrcout = trigsrc[f'OUT{out}'] - if trigsrcout.sub[0:2] == '10': + if len(outs_in_failure) == 1: + out = outs_in_failure.pop() + if trigsrc[f'OUT{out}'].sub[0:2] == '10': rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] is_failure &= not _get_bit(rxlock, 0) # out 0 From c598f13d56b3962d958176f0d9b71cb2d467e582 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 09:25:17 -0300 Subject: [PATCH 160/309] ORBINTLK.FIX: only write when necessary on lock --- siriuspy/siriuspy/orbintlk/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f6aed4e33..ad28e7bfc 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1493,12 +1493,14 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): if pvname in self._lock_failures: self._lock_failures.remove(pvname) thread.stop() + return # else, apply value as desired if device == self._llrf: propty_rb = propty_sp.replace(':S', '') else: propty_rb = _PVName(pvname).propty + self._update_log(f'WARN:Locking {pvname}') device[propty_sp] = desired_value # if readback reached desired value, stop thread @@ -1506,6 +1508,7 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): if pvname in self._lock_failures: self._lock_failures.remove(pvname) thread.stop() + return # if this was the last iteration, raise a reliability failure if thread.cur_iter == thread.niters-1: From 226f94b253fdbeba2cff91bcaef36c4f1ae1dcc2 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 10:24:29 -0300 Subject: [PATCH 161/309] ORBINTLK.ENH: add log message verifying if Beam Trip flag was raised by LLRF interlock --- siriuspy/siriuspy/orbintlk/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ad28e7bfc..049062a21 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -243,9 +243,10 @@ def __init__(self, tests=True): self._llrf = _ASLLRF( devname=_ASLLRF.DEVICES.SI, props2init=[ - 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', + 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'FASTINLK-MON', 'ILK:MAN:S', 'ILK:MAN', 'IntlkSet-Cmd', ]) + self._llrf.pv_object('FASTINLK-MON').auto_monitor = True # # auxiliary devices self._fofb = _FOFB( @@ -1327,6 +1328,8 @@ def _do_callback_bpm_intlk(self): self._update_log('ERR:EVG did not propagate event Intlk') # reset BPM orbit interlock, once EVG callback was not triggered self.cmd_reset('bpm_all') + if not self._llrf['FASTINLK-MON'] & (1 << 12): + self._update_log('ERR:LLRF did not received RFKill event') def _get_bpm_rates_factor(self): if self._monitsum2intlksum_factor: From 0b277f45715dcdf7c6baa92b15698cb09aeed617 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 10:28:39 -0300 Subject: [PATCH 162/309] ORBINTLK.ENH: monitor AFC Timing configurations --- siriuspy/siriuspy/orbintlk/csdev.py | 1 + siriuspy/siriuspy/orbintlk/main.py | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index d3d96e44a..5d4e9af46 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -28,6 +28,7 @@ class ETypes(_csdev.ETypes): 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', 'FoutsBPMConn', 'FoutsBPMConfig', 'FoutsDCCTConn', 'FoutsDCCTConfig', + 'AFCTimingConn', 'AFCTimingConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', 'BPMPsMtmTrigConn', 'BPMPsMtmTrigStatusOK', 'BPMPsMtmTrigConfig', diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 049062a21..166b4b981 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1103,7 +1103,7 @@ def _check_configs(self): value = _updt_bit(value, 1, val) okg = True for prp, val in self._const.EVG_CONFIGS: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val value = _updt_bit(value, 2, not okg) else: @@ -1124,15 +1124,25 @@ def _check_configs(self): if dev.connected: okg = True for prp, val in self._const.FOUT2_CONFIGS: - prp_rb = prp.replace('-Sel', '-Sts').replace('-SP', '-RB') + prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val if 'RxEnbl' in prp: okg &= dev['RxLockedLtc-Mon'] == val value = _updt_bit(value, 6, not okg) else: value += 0b11 << 5 + # AFC timing + if all(dev.connected for dev in self._afcti_devs.values()): + okg = True + for dev in self._afcti_devs.values(): + for prp, val in self._const.AFCTI_CONFIGS: + prp_rb = _PVName.from_sp2rb(prp) + okg &= dev[prp_rb] == val + value = _updt_bit(value, 8, not okg) + else: + value += 0b11 << 7 # HL triggers - bit = 7 + bit = 9 for trigname, configs in self._const.HLTRIG_2_CONFIG: dev = self._hltrig_devs[trigname] if dev.connected: From 160e29eeb66e6d658066034f569bef5015e90d9e Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 10:48:29 -0300 Subject: [PATCH 163/309] ORBINTLK.ENH: monitor AFC logical and physical trigger configurations --- siriuspy/siriuspy/orbintlk/csdev.py | 3 ++- siriuspy/siriuspy/orbintlk/main.py | 31 +++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 5d4e9af46..76c650d43 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -23,12 +23,13 @@ class ETypes(_csdev.ETypes): 'Connected', 'PosEnblSynced', 'AngEnblSynced', 'MinSumEnblSynced', 'GlobEnblSynced', 'PosLimsSynced', 'AngLimsSynced', 'MinSumLimsSynced', - 'AcqConfigured') + 'AcqConfigured', 'LogTrigConfig') STS_LBLS_TIMING = ( 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', 'FoutsBPMConn', 'FoutsBPMConfig', 'FoutsDCCTConn', 'FoutsDCCTConfig', 'AFCTimingConn', 'AFCTimingConfig', + 'AFCPhysTrigsConn', 'AFCPhysTrigsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', 'BPMPsMtmTrigConn', 'BPMPsMtmTrigStatusOK', 'BPMPsMtmTrigConfig', diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 166b4b981..151a8cbe4 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -222,7 +222,7 @@ def __init__(self, tests=True): 'TRIGGER_PM14RcvSrc-Sel', 'TRIGGER_PM14RcvSrc-Sts', 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB']) self._monitsum2intlksum_factor = 0 - for idx, dev in enumerate(self._fambpm_dev.devices): + for dev in self._fambpm_dev.devices: pvo = dev.pv_object('INFOMONITRate-RB') pvo.connection_callbacks.append(self._conn_callback_bpm) @@ -1042,10 +1042,9 @@ def _check_configs(self): _t0 = _time.time() # bpm status - dev = self._orbintlk_dev - value = (1 << 9) - 1 - if dev.connected: - value = _updt_bit(value, 0, 0) + value = 0 + if self._orbintlk_dev.connected and self._fambpm_dev.connected: + dev = self._orbintlk_dev # PosEnblSynced val = _np.array_equal( dev.pos_enable, self._enable_lists['pos']) @@ -1090,6 +1089,13 @@ def _check_configs(self): okb &= all( d.acq_status == self._const.AcqStates.External_Trig for d in bpms) value = _updt_bit(value, 8, not okb) + # LogTrigConfigured + okl = True + for bpm in self._fambpm_dev.devices: + for prp, val in self._const.SIBPMLOGTRIG_CONFIGS: + prp_rb = _PVName.from_sp2rb(prp) + okl &= bpm[prp_rb] == val + value = _updt_bit(value, 9, not okl) self._bpm_status = value self.run_callbacks('BPMStatus-Mon', self._bpm_status) @@ -1141,8 +1147,21 @@ def _check_configs(self): value = _updt_bit(value, 8, not okg) else: value += 0b11 << 7 + # AFC Physical triggers + if all(dev.connected for dev in self._phytrig_devs): + okg = True + for dev in self._phytrig_devs: + for prp, val in self._const.AFCPHYTRIG_CONFIGS: + if dev.devname not in self._const.bpm_names and \ + prp != 'DirPol-Sel': + continue + prp_rb = _PVName.from_sp2rb(prp) + okg &= dev[prp_rb] == val + value = _updt_bit(value, 10, not okg) + else: + value += 0b11 << 9 # HL triggers - bit = 9 + bit = 11 for trigname, configs in self._const.HLTRIG_2_CONFIG: dev = self._hltrig_devs[trigname] if dev.connected: From 0517c9606889fa3c25996471ccdaed47ff8e18d2 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 11:55:26 -0300 Subject: [PATCH 164/309] ORBINTLK.ENH: add auxiliary commands to configure devices --- siriuspy/siriuspy/orbintlk/csdev.py | 9 ++- siriuspy/siriuspy/orbintlk/main.py | 115 ++++++++++++++++++++++------ 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 76c650d43..ccc5f594b 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -391,7 +391,14 @@ def get_database(self): 'PsMtmAcqConfig-Cmd': {'type': 'int', 'value': 0}, # Config devices - 'IntlkStateConfig-Cmd': {'type': 'int', 'value': 0} + 'ConfigEVG-Cmd': {'type': 'int', 'value': 0}, + 'ConfigFouts-Cmd': {'type': 'int', 'value': 0}, + 'ConfigDeltaRedunEVR-Cmd': {'type': 'int', 'value': 0}, + 'ConfigAFCTiming-Cmd': {'type': 'int', 'value': 0}, + 'ConfigHLTriggers-Cmd': {'type': 'int', 'value': 0}, + 'ConfigLLRFIntlk-Cmd': {'type': 'int', 'value': 0}, + 'ConfigBPMs-Cmd': {'type': 'int', 'value': 0}, + 'ConfigAFCPhyTrigs-Cmd': {'type': 'int', 'value': 0}, } pvs_database = _csdev.add_pvslist_cte(pvs_database) return pvs_database diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 151a8cbe4..30505f07f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -280,9 +280,16 @@ def __init__(self, tests=True): 'PsMtmAcqSamplesPre-SP': self.set_acq_nrspls_pre, 'PsMtmAcqSamplesPost-SP': self.set_acq_nrspls_post, 'PsMtmAcqConfig-Cmd': self.cmd_acq_config, - 'IntlkStateConfig-Cmd': self.cmd_state_config, 'ResetTimingLockLatches-Cmd': self.cmd_reset_ti_lock_latch, 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, + 'ConfigEVG-Cmd': self.cmd_config_evg, + 'ConfigFouts-Cmd': self.cmd_config_fouts, + 'ConfigDeltaRedunEVR-Cmd': self.cmd_config_deltaevr, + 'ConfigAFCTiming-Cmd': self.cmd_config_afcti, + 'ConfigHLTriggers-Cmd': self.cmd_config_hltrigs, + 'ConfigLLRFIntlk-Cmd': self.cmd_config_llrf, + 'ConfigBPMs-Cmd': self.cmd_config_bpms, + 'ConfigAFCPhyTrigs-Cmd': self.cmd_config_phytrigs, } # configuration scanning @@ -876,7 +883,7 @@ def cmd_reset_afcti_rtmclk(self, value=None): return True - # --- configure acquisition --- + # --- BPM acquisition --- def set_acq_channel(self, value): """Set BPM PsMtm acquisition channel.""" @@ -930,32 +937,96 @@ def _acq_config(self): return self._update_log('...done!') - # --- status methods --- + # --- devices configurations --- - def cmd_state_config(self, value=None): - """Configure Interlock State according to setpoints. + def cmd_config_evg(self, value): + """Configure EVG according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['EVG']) + self._handle_lock_evg_configs() + self._lock_temp_pvs.clear() - Args: - value (int, optional): Not used. Defaults to None. + def cmd_config_fouts(self, value): + """Configure Fouts according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['Fouts']) + self._handle_lock_fouts() + self._lock_temp_pvs.clear() - Returns: - bool: True if configuration worked. - """ - for name, enbl in self._enable_lists.items(): - if not self.set_enbllist(name, enbl): - self._update_log( - f'ERR:Could not configure {name:s} enable list') - return False + def cmd_config_deltaevr(self, value): + """Configure Delta EVR according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['EVRRedun']) + self._handle_lock_redundancy_evr() + self._lock_temp_pvs.clear() - for name, lim in self._limits.items(): - if not self.set_intlk_lims(name, lim): - self._update_log( - f'ERR:Could not configure {name:s} limit') - return False + def cmd_config_afcti(self, value): + """Configure all AFC timing according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + # do not allow user configurate loop params in case of + # correction loops closed + if not self._fofb.connected or self._fofb['LoopState-Sts'] or \ + not self._sofb.connected or self._sofb['LoopState-Sts']: + self._update_log('ERR:Open correction loops before ') + self._update_log('ERR:configuring AFC Timing RTM loop.') + return False + self._lock_temp_pvs.update(self._lock_pvs['AFCTI']) + self._handle_lock_afcti() + self._lock_temp_pvs.clear() - if not self.set_enable(self._state): + def cmd_config_hltrigs(self, value): + """Configure HL triggers according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') return False - return True + self._lock_temp_pvs.update(self._lock_pvs['HLTriggers']) + self._handle_lock_hltriggers() + self._lock_temp_pvs.clear() + + def cmd_config_llrf(self, value): + """Configure LLRF interlock according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['LLRF']) + self._handle_lock_llrf() + self._lock_temp_pvs.clear() + + def cmd_config_bpms(self, value): + """Configure BPMs according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['BPM']) + self._handle_lock_bpm_configs() + self._lock_temp_pvs.clear() + + def cmd_config_phytrigs(self, value): + """Configure physical triggers according to lock configurations.""" + _ = value + if self._state: + self._update_log('ERR:Disable interlock before continue.') + return False + self._lock_temp_pvs.update(self._lock_pvs['AFCPhysTriggers']) + self._handle_lock_afcphytrigs() + self._lock_temp_pvs.clear() + + # --- status methods --- def _config_fout_rxenbl(self): fout2rx = dict() From 603d44e60f79b8aff40139bf0ad51608a13cbfef Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 12:25:25 -0300 Subject: [PATCH 165/309] ORBINTLK.ENH: change ResetTimingLockLatches command to reset DCCT Fout too --- siriuspy/siriuspy/orbintlk/main.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 30505f07f..49b45b72a 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -127,7 +127,10 @@ def __init__(self, tests=True): self._fout_dcct_dev = _Device( 'CA-RaTim:TI-Fout-2', - props2init=['RxEnbl-SP', 'RxEnbl-RB']) + props2init=[ + 'RxEnbl-SP', 'RxEnbl-RB', + 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', + ], auto_monitor_mon=True) # # AFC timing self._afcti_devs = { @@ -843,7 +846,7 @@ def cmd_reset_ti_lock_latch(self, value=None): self._update_log(f'{msg} AFC Timing {idx} lock latchs.') if 'not' in msg: return False - # try to reset Fout rx lock latches, act only in necessary + # try to reset BPM Fout rx lock latches, act only in necessary # devices, return false if fail for devname, fout in self._fout_devs.items(): if fout['RxLockedLtc-Mon']: @@ -855,6 +858,17 @@ def cmd_reset_ti_lock_latch(self, value=None): self._update_log(f'{msg} {devname} lock latchs.') if 'not' in msg: return False + # try to reset DCCT Fout rx lock latches if necessary, return false if fail + dev = self._fout_dcct_dev + if dev['RxLockedLtc-Mon']: + return True + dev['RxLockedLtcRst-Cmd'] = 1 + rxv = dev['RxEnbl-RB'] + msg = 'Reset' if dev._wait('RxLockedLtc-Mon', rxv, timeout=3) \ + else 'ERR:Could not reset' + self._update_log(f'{msg} {dev.devname} lock latchs.') + if 'not' in msg: + return False return True def cmd_reset_afcti_rtmclk(self, value=None): From fad7afb1bc3840c37dcc3c16c961dcdbbb9612a8 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 12:30:10 -0300 Subject: [PATCH 166/309] ORBINTLK.FIX: fix RxLocked checks in ResetTimingLockLatches command --- siriuspy/siriuspy/orbintlk/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 49b45b72a..e5de2cdc2 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -849,10 +849,10 @@ def cmd_reset_ti_lock_latch(self, value=None): # try to reset BPM Fout rx lock latches, act only in necessary # devices, return false if fail for devname, fout in self._fout_devs.items(): - if fout['RxLockedLtc-Mon']: + rxv = self._fout2rxenbl[devname] + if fout['RxLockedLtc-Mon'] == rxv: continue fout['RxLockedLtcRst-Cmd'] = 1 - rxv = self._fout2rxenbl[devname] msg = 'Reset' if fout._wait('RxLockedLtc-Mon', rxv, timeout=3) \ else 'ERR:Could not reset' self._update_log(f'{msg} {devname} lock latchs.') @@ -860,10 +860,10 @@ def cmd_reset_ti_lock_latch(self, value=None): return False # try to reset DCCT Fout rx lock latches if necessary, return false if fail dev = self._fout_dcct_dev - if dev['RxLockedLtc-Mon']: + rxv = dev['RxEnbl-RB'] + if dev['RxLockedLtc-Mon'] == rxv: return True dev['RxLockedLtcRst-Cmd'] = 1 - rxv = dev['RxEnbl-RB'] msg = 'Reset' if dev._wait('RxLockedLtc-Mon', rxv, timeout=3) \ else 'ERR:Could not reset' self._update_log(f'{msg} {dev.devname} lock latchs.') From 8da4b9d77cbf1ba17c3e5d1550526270523e66e8 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 15:15:14 -0300 Subject: [PATCH 167/309] ORBINTLK.MNT: increase sleep time between lock attempts --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e5de2cdc2..d9e2062cb 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1594,7 +1594,7 @@ def _start_lock_thread( return # else, create lock thread with 10 attempts to lock PV - interval = 1 / 50 # little sleep to avoid CPU load + interval = 1 / 10 # little sleep to avoid CPU load thread = _Repeat( interval, self._do_lock, args=(device, propty_sp, desired_value, pvname, value), From 106b6407e5702847d8bcdbf84bdc5654c3e0c057 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 15:22:16 -0300 Subject: [PATCH 168/309] ORBINTLK.ENH: monitor interlock redundancy EVR --- siriuspy/siriuspy/orbintlk/csdev.py | 1 + siriuspy/siriuspy/orbintlk/main.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index ccc5f594b..43c3e5ddd 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -29,6 +29,7 @@ class ETypes(_csdev.ETypes): 'FoutsBPMConn', 'FoutsBPMConfig', 'FoutsDCCTConn', 'FoutsDCCTConfig', 'AFCTimingConn', 'AFCTimingConfig', + 'EVRIntlkRedundancyConn', 'EVRIntlkRedundancyConfig', 'AFCPhysTrigsConn', 'AFCPhysTrigsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d9e2062cb..6fe81f917 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1232,6 +1232,15 @@ def _check_configs(self): value = _updt_bit(value, 8, not okg) else: value += 0b11 << 7 + # Delta Interlock Redundancy EVR + if self._evrdelta_dev.connected: + okg = True + for prp, val in self._const.INTLKREDEVR_CONFIGS: + prp_rb = _PVName.from_sp2rb(prp) + okg &= dev[prp_rb] == val + value = _updt_bit(value, 10, not okg) + else: + value += 0b11 << 9 # AFC Physical triggers if all(dev.connected for dev in self._phytrig_devs): okg = True @@ -1242,11 +1251,11 @@ def _check_configs(self): continue prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val - value = _updt_bit(value, 10, not okg) + value = _updt_bit(value, 12, not okg) else: - value += 0b11 << 9 + value += 0b11 << 11 # HL triggers - bit = 11 + bit = 13 for trigname, configs in self._const.HLTRIG_2_CONFIG: dev = self._hltrig_devs[trigname] if dev.connected: From c0bf1e28e9e280daf89b1690b7958a44ab4b1dbd Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 15:28:06 -0300 Subject: [PATCH 169/309] ORBINTLK.FIX: fix PV name in Delta EVR device --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6fe81f917..ef6299495 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -170,7 +170,7 @@ def __init__(self, tests=True): 'DIN0State-Sel', 'DIN0State-Sts', 'DIN0Evt-SP', 'DIN0Evt-RB', 'DIN0Polarity-Sel', 'DIN0Polarity-Sts', - 'DIN0Log-Sel', 'DIN0Log-RB', + 'DIN0Log-Sel', 'DIN0Log-Sts', ]) # # HL triggers From 460770fde4cde0a6bff35c874073678bf2b6d733 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 15:50:40 -0300 Subject: [PATCH 170/309] ORBINTLK.FIX: turn on EVG RxLocked PV auto_monitor --- siriuspy/siriuspy/orbintlk/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ef6299495..48efac41b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -106,6 +106,7 @@ def __init__(self, tests=True): pvo.connection_callbacks.append(self._conn_callback_timing) # rxlock callback pvo = self._evg_dev.pv_object('RxLockedLtc-Mon') + pvo.auto_monitor = True pvo.add_callback(self._callback_evg_rxlock) # # Fouts From e2571a901cfced10947523c2219fcf6d6e6bee6f Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 15:51:22 -0300 Subject: [PATCH 171/309] ORBINTLK.FIX: fix bug introduced in timing checks --- siriuspy/siriuspy/orbintlk/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 48efac41b..0e33a0da8 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1233,8 +1233,9 @@ def _check_configs(self): value = _updt_bit(value, 8, not okg) else: value += 0b11 << 7 - # Delta Interlock Redundancy EVR - if self._evrdelta_dev.connected: + # Delta Interlock Redundancy EVR + dev = self._evrdelta_dev + if dev.connected: okg = True for prp, val in self._const.INTLKREDEVR_CONFIGS: prp_rb = _PVName.from_sp2rb(prp) From c56dba44d1bd00bf0a11e4b7bea97f711433c457 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 16:48:43 -0300 Subject: [PATCH 172/309] ORBINTLK.FIX: wait lock threads to finish on auxiliary commands --- siriuspy/siriuspy/orbintlk/main.py | 51 ++++++++++++++++-------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 0e33a0da8..b9e91677a 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -960,9 +960,8 @@ def cmd_config_evg(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['EVG']) - self._handle_lock_evg_configs() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_evg_configs, 'EVG') + return True def cmd_config_fouts(self, value): """Configure Fouts according to lock configurations.""" @@ -970,9 +969,8 @@ def cmd_config_fouts(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['Fouts']) - self._handle_lock_fouts() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_fouts, 'Fouts') + return True def cmd_config_deltaevr(self, value): """Configure Delta EVR according to lock configurations.""" @@ -980,9 +978,8 @@ def cmd_config_deltaevr(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['EVRRedun']) - self._handle_lock_redundancy_evr() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_redundancy_evr, 'EVRRedun') + return True def cmd_config_afcti(self, value): """Configure all AFC timing according to lock configurations.""" @@ -997,9 +994,8 @@ def cmd_config_afcti(self, value): self._update_log('ERR:Open correction loops before ') self._update_log('ERR:configuring AFC Timing RTM loop.') return False - self._lock_temp_pvs.update(self._lock_pvs['AFCTI']) - self._handle_lock_afcti() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_afcti, 'AFCTI') + return True def cmd_config_hltrigs(self, value): """Configure HL triggers according to lock configurations.""" @@ -1007,9 +1003,8 @@ def cmd_config_hltrigs(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['HLTriggers']) - self._handle_lock_hltriggers() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_hltriggers, 'HLTriggers') + return True def cmd_config_llrf(self, value): """Configure LLRF interlock according to lock configurations.""" @@ -1017,9 +1012,8 @@ def cmd_config_llrf(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['LLRF']) - self._handle_lock_llrf() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_llrf, 'LLRF') + return True def cmd_config_bpms(self, value): """Configure BPMs according to lock configurations.""" @@ -1027,9 +1021,8 @@ def cmd_config_bpms(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['BPM']) - self._handle_lock_bpm_configs() - self._lock_temp_pvs.clear() + self._do_auxiliary_cmd(self._handle_lock_bpm_configs, 'BPM') + return True def cmd_config_phytrigs(self, value): """Configure physical triggers according to lock configurations.""" @@ -1037,8 +1030,20 @@ def cmd_config_phytrigs(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._lock_temp_pvs.update(self._lock_pvs['AFCPhysTriggers']) - self._handle_lock_afcphytrigs() + self._do_auxiliary_cmd( + self._handle_lock_afcphytrigs, 'AFCPhysTriggers') + return True + + def _do_auxiliary_cmd(self, func, pvgroup): + self._lock_temp_pvs.update(self._lock_pvs[pvgroup]) + func() + for pvn in self._lock_temp_pvs: + if pvn not in self._lock_threads: + continue + _time.sleep(0.02) + thread = self._lock_threads[pvn] + if thread.is_alive(): + thread.join() self._lock_temp_pvs.clear() # --- status methods --- From 205560012cfcbf3e30c9a5f03714f668648fee2c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 17:11:19 -0300 Subject: [PATCH 173/309] ORBINTLK.FIX: fix bug in lock thread for devices with properties in devname --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index b9e91677a..d6e237b93 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1632,7 +1632,7 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): if device == self._llrf: propty_rb = propty_sp.replace(':S', '') else: - propty_rb = _PVName(pvname).propty + propty_rb = _PVName.from_sp2rb(propty_sp) self._update_log(f'WARN:Locking {pvname}') device[propty_sp] = desired_value From ed0dc95ed653ca405ecd6e726d7d4b814028829a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 17:26:48 -0300 Subject: [PATCH 174/309] ORBINTLK.ENH: change BPM and AFC physical triggers auxiliary commands to not wait for checks --- siriuspy/siriuspy/orbintlk/main.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d6e237b93..3b7d367de 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1021,7 +1021,16 @@ def cmd_config_bpms(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd(self._handle_lock_bpm_configs, 'BPM') + + for name, enbl in self._enable_lists.items(): + self.set_enbllist(name, enbl) + + for name, lim in self._limits.items(): + self.set_intlk_lims(name, lim) + + for dev in self._fambpm_dev.devices: + for prop, desired_val in self._const.SIBPMLOGTRIG_CONFIGS: + dev[prop] = desired_val return True def cmd_config_phytrigs(self, value): @@ -1030,8 +1039,9 @@ def cmd_config_phytrigs(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd( - self._handle_lock_afcphytrigs, 'AFCPhysTriggers') + for dev in self._phytrig_devs: + for prop, desired_val in self._const.AFCPHYTRIG_CONFIGS: + dev[prop] = desired_val return True def _do_auxiliary_cmd(self, func, pvgroup): From b4120a30b10fbd35156f0b45345aae200b7abc71 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Sun, 3 Dec 2023 17:38:10 -0300 Subject: [PATCH 175/309] ORBINTLK.MNT: reduce wait time to rearm acquisitions to 30s --- siriuspy/siriuspy/orbintlk/csdev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 43c3e5ddd..0291b36e6 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -56,7 +56,7 @@ class Const(_csdev.Const): DEF_TIMESLEEP = 0.1 # [s] DEF_TIMEWAIT = 3 # [s] - DEF_TIME2WAIT_INTLKREARM = 2*60 # [s] + DEF_TIME2WAIT_INTLKREARM = 30 # [s] HLTRIG_2_CONFIG = [ ('SI-Fam:TI-BPM-OrbIntlk', ( From c6efef9977e860e99670debf80e0939624ac4b85 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 12:10:19 -0300 Subject: [PATCH 176/309] ORBINTLK.MNT: remove trailing spaces --- siriuspy/siriuspy/orbintlk/main.py | 56 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 3b7d367de..596e466a8 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -70,8 +70,8 @@ def __init__(self, tests=True): self._lock_failures = set() self._lock_suspend = True self._lock_pvs = { - k: list() for k in - ['EVG', 'Fouts', 'EVRRedun', 'AFCTI', 'HLTriggers', + k: list() for k in + ['EVG', 'Fouts', 'EVRRedun', 'AFCTI', 'HLTriggers', 'LLRF', 'BPM', 'AFCPhysTriggers']} self._set_queue = _LoopQueueThread() self._set_queue.start() @@ -140,10 +140,10 @@ def __init__(self, tests=True): props2init=[ 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', 'RTMClkRst-Cmd', - 'RTMPhasePropGain-SP', 'RTMPhasePropGain-RB', - 'RTMPhaseIntgGain-SP', 'RTMPhaseIntgGain-RB', - 'RTMFreqPropGain-SP', 'RTMFreqPropGain-RB', - 'RTMFreqIntgGain-SP', 'RTMFreqIntgGain-RB', + 'RTMPhasePropGain-SP', 'RTMPhasePropGain-RB', + 'RTMPhaseIntgGain-SP', 'RTMPhaseIntgGain-RB', + 'RTMFreqPropGain-SP', 'RTMFreqPropGain-RB', + 'RTMFreqIntgGain-SP', 'RTMFreqIntgGain-RB', ], auto_monitor_mon=True) for idx in range(20) } @@ -164,7 +164,7 @@ def __init__(self, tests=True): self._everf_evtcnt = pvo.get() or 0 # # delta redundancy EVR - self._evrdelta_dev = _Device( + self._evrdelta_dev = _Device( # TODO: change to use new hltrigger 'IA-10RaBPM:TI-EVR', props2init=[ 'DevEnbl-Sel', 'DevEnbl-Sts', @@ -184,7 +184,7 @@ def __init__(self, tests=True): props2init.append('Status-Mon') self._hltrig_devs[trigname] = _Trigger( trigname=trigname, - props2init=props2init, + props2init=props2init, auto_monitor_mon=True) if 'DCCT' in trigname: continue @@ -247,10 +247,10 @@ def __init__(self, tests=True): self._llrf = _ASLLRF( devname=_ASLLRF.DEVICES.SI, props2init=[ - 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'FASTINLK-MON', + 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'FASTINLK-MON', 'ILK:MAN:S', 'ILK:MAN', 'IntlkSet-Cmd', ]) - self._llrf.pv_object('FASTINLK-MON').auto_monitor = True + self._llrf.pv_object('FASTINLK-MON').auto_monitor = True # # auxiliary devices self._fofb = _FOFB( @@ -286,14 +286,14 @@ def __init__(self, tests=True): 'PsMtmAcqConfig-Cmd': self.cmd_acq_config, 'ResetTimingLockLatches-Cmd': self.cmd_reset_ti_lock_latch, 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, - 'ConfigEVG-Cmd': self.cmd_config_evg, - 'ConfigFouts-Cmd': self.cmd_config_fouts, - 'ConfigDeltaRedunEVR-Cmd': self.cmd_config_deltaevr, - 'ConfigAFCTiming-Cmd': self.cmd_config_afcti, - 'ConfigHLTriggers-Cmd': self.cmd_config_hltrigs, - 'ConfigLLRFIntlk-Cmd': self.cmd_config_llrf, - 'ConfigBPMs-Cmd': self.cmd_config_bpms, - 'ConfigAFCPhyTrigs-Cmd': self.cmd_config_phytrigs, + 'ConfigEVG-Cmd': self.cmd_config_evg, + 'ConfigFouts-Cmd': self.cmd_config_fouts, + 'ConfigDeltaRedunEVR-Cmd': self.cmd_config_deltaevr, + 'ConfigAFCTiming-Cmd': self.cmd_config_afcti, + 'ConfigHLTriggers-Cmd': self.cmd_config_hltrigs, + 'ConfigLLRFIntlk-Cmd': self.cmd_config_llrf, + 'ConfigBPMs-Cmd': self.cmd_config_bpms, + 'ConfigAFCPhyTrigs-Cmd': self.cmd_config_phytrigs, } # configuration scanning @@ -371,7 +371,7 @@ def init_database(self): # start init lock devices self._lock_temp_pvs = set() self._enable_lock(init=True) - + def _enable_lock(self, init=False): if not init: self._lock_suspend = False @@ -390,7 +390,7 @@ def _enable_lock(self, init=False): def _disable_lock(self): self._lock_temp_pvs = set() self._lock_suspend = True - + def _handle_lock_evg_configs(self, init=False): self._evg_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for propty_sp, desired_val in self._const.EVG_CONFIGS: @@ -402,7 +402,7 @@ def _handle_lock_evg_configs(self, init=False): self._callback_lock, self._evg_dev, propty_sp, desired_val)) else: pvo.run_callbacks() - + def _handle_lock_evg_enable(self, init=False): # lock interlock enable state pvo = self._evg_dev.pv_object('IntlkCtrlEnbl-Sts') @@ -474,7 +474,7 @@ def _handle_lock_hltriggers(self, init=False): _part(self._callback_lock, trigdev, prop_sp, desired_val)) else: pvo.run_callbacks() - + def _handle_lock_llrf(self, init=False): self._llrf.wait_for_connection(timeout=self._const.DEF_TIMEOUT) pvo_beamtrip = self._llrf.pv_object('ILK:BEAM:TRIP') @@ -605,7 +605,7 @@ def set_enable(self, value): Configure global BPM interlock enable and EVG interlock enable.""" self._set_queue.put((self._do_set_enable, (value, ))) return True - + def _do_set_enable(self, value): if not 0 <= value < len(_ETypes.DSBL_ENBL): self.run_callbacks('Enable-Sel', self._state) @@ -987,7 +987,7 @@ def cmd_config_afcti(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - # do not allow user configurate loop params in case of + # do not allow user configurate loop params in case of # correction loops closed if not self._fofb.connected or self._fofb['LoopState-Sts'] or \ not self._sofb.connected or self._sofb['LoopState-Sts']: @@ -1027,7 +1027,7 @@ def cmd_config_bpms(self, value): for name, lim in self._limits.items(): self.set_intlk_lims(name, lim) - + for dev in self._fambpm_dev.devices: for prop, desired_val in self._const.SIBPMLOGTRIG_CONFIGS: dev[prop] = desired_val @@ -1116,7 +1116,7 @@ def _check_ti_devices_status(self, devices): if 'AMCFPGA' in devname else None if dev is None: self._update_log(f'ERR:Could not verify {devname} state.') - return False + return False if not dev.connected: self._update_log(f'ERR:{dev.devname} not connected') @@ -1425,8 +1425,8 @@ def _callback_bpm_intlk(self, pvname, value, **kws): return # launch thread to log interlock details _CAThread( - target=self._log_bpm_intlk, - args=(_PVName(pvname).device_name, ), + target=self._log_bpm_intlk, + args=(_PVName(pvname).device_name, ), daemon=True).start() # launch thread to send interlock to RF as a backup if self._thread_cbbpm and self._thread_cbbpm.is_alive(): From 74ffe1cba7788139bfdc14719902be720eb4568f Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 12:11:03 -0300 Subject: [PATCH 177/309] ORBINTLK.FIX: do not respond to EVG interlock callbacks when disabled --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 596e466a8..21350d990 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1312,7 +1312,7 @@ def _check_configs(self): def _callback_evg_intlk(self, value, **kws): _ = kws - if not self._init: + if not self._state: return if self._thread_cbevgilk and self._thread_cbevgilk.is_alive(): return From 9fe98ac7ba91dab4c031398679e86f5c42e76f3f Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 4 Dec 2023 12:43:45 -0300 Subject: [PATCH 178/309] Update _ID device class --- siriuspy/siriuspy/devices/ids.py | 80 +++++++++++++++++++------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index b29a4c1e6..951677c5c 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -325,20 +325,39 @@ def cmd_beamline_ctrl_disable(self, timeout=None): """Command disable bealine ID control.""" return self._write_sp('BeamLineCtrlEnbl-Sel', 0, timeout) - # --- cmd_wait + # --- wait def wait_while_busy(self, timeout=None): """Command wait within timeout while ID control is busy.""" return True - def cmd_wait_move_start(self, timeout=None): + def wait_move_start(self, timeout=None): """Wait for movement to start.""" return self._wait('Moving-Mon', 1, timeout) - def cmd_wait_move_finish(self, timeout=None): + def wait_move_finish(self, timeout=None): """Wait for movement to finish.""" return self._wait('Moving-Mon', 0, timeout) + def wait_move_config(self, pparam, kparam, timeout): + """.""" + tol_kparam, tol_pparam = self.kparameter_tol, self.pparameter_tol + # wait for movement within reasonable time + time_init = _time.time() + while True: + k_pos_ok = True if kparam is None else \ + abs(abs(self.kparameter_mon) - abs(kparam)) <= tol_kparam + p_pos_ok = True if pparam is None else \ + abs(self.pparameter_mon - pparam) <= tol_pparam + if p_pos_ok and k_pos_ok and not self.is_moving: + return True + if _time.time() - time_init > timeout: + print(f'tol_total: {timeout:.3f} s') + print(f'wait_time: {_time.time() - time_init:.3f} s') + print() + return False + _time.sleep(self._SHORT_SHUT_EYE) + # --- cmd_move --- def cmd_move_disable(self): @@ -363,7 +382,7 @@ def cmd_move_stop(self, timeout=None): # check for successful stop if not self.wait_while_busy(timeout=timeout): return False - if not self.cmd_wait_move_finish(timeout=timeout): + if not self.wait_move_finish(timeout=timeout): return False # # enable movement again @@ -399,62 +418,57 @@ def cmd_move_park(self, timeout=None): pparam, kparam = self.pparameter_parked, self.kparameter_parked return self.cmd_move(pparam, kparam, timeout) - def cmd_move_pparameter(self, pparam, timeout=None): + def cmd_move_pparameter(self, pparam=None, timeout=None): """Command to set and start pparam movement.""" + pparam = self.pparameter if pparam is None else pparam return self.cmd_move(pparam, None, timeout) - def cmd_move_kparameter(self, kparam, timeout=None): + def cmd_move_kparameter(self, kparam=None, timeout=None): """Command to set and start kparam movement.""" + kparam = self.kparameter if kparam is None else kparam return self.cmd_move(None, kparam, timeout) def cmd_move(self, pparam=None, kparam=None, timeout=None): """Command to set and start pparam and kparam movements.""" if self.PARAM_PVS.PPARAM_SP is None: pparam = None - kparam = self.kparameter if kparam is None else kparam - - # calc ETA - dtime_kparam = 0 if kparam is None else \ - abs(kparam - self.kparameter_mon) / self.kparameter_speed - dtime_pparam = 0 if pparam is None else \ - abs(pparam - self.pparameter_mon) / self.pparameter_speed - dtime_max = max(dtime_kparam, dtime_pparam) - # additional percentual in ETA - tol_kparam, tol_pparam = self.kparameter_tol, self.pparameter_tol - tol_total = 4.0 * dtime_max + 5 - - # set target phase and gap + # set target pparam and kparam + t0_ = _time.time() if pparam is not None and \ not self.pparameter_set(pparam, timeout=timeout): return False if kparam is not None and \ not self.kparameter_set(kparam, timeout=timeout): return False + t1_ = _time.time() + if timeout is not None: + timeout = max(timeout - (t1_ - t0_), 0) # command move start + t0_ = _time.time() if pparam is not None and \ not self.cmd_move_pparameter_start(timeout=timeout): return False if kparam is not None and \ not self.cmd_move_kparameter_start(timeout=timeout): return False + t1_ = _time.time() + if timeout is not None: + timeout = max(timeout - (t1_ - t0_), 0) + + # calc ETA + dtime_kparam = 0 if kparam is None else \ + abs(kparam - self.kparameter_mon) / self.kparameter_speed + dtime_pparam = 0 if pparam is None else \ + abs(pparam - self.pparameter_mon) / self.pparameter_speed + dtime_max = max(dtime_kparam, dtime_pparam) + # additional percentual in ETA + dtime = 4.0 * dtime_max + 5 + timeout = dtime if timeout is None else max(dtime - timeout, 0) # wait for movement within reasonable time - time_init = _time.time() - while True: - k_pos_ok = True if kparam is None else \ - abs(abs(self.kparameter_mon) - abs(kparam)) <= tol_kparam - p_pos_ok = True if pparam is None else \ - abs(self.pparameter_mon - pparam) <= tol_pparam - if p_pos_ok and k_pos_ok and not self.is_moving: - return True - if _time.time() - time_init > tol_total: - print(f'tol_total: {tol_total:.3f} s') - print(f'wait_time: {_time.time() - time_init:.3f} s') - print() - return False - _time.sleep(self._SHORT_SHUT_EYE) + return self.wait_move_config(pparam, kparam, timeout) def cmd_change_polarization(self, polarization, timeout=None): """.""" From aa53d46c8b8a7af6e2aaed386badab43e5eff8d4 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 4 Dec 2023 13:00:13 -0300 Subject: [PATCH 179/309] Add methods in device _ID --- siriuspy/siriuspy/devices/ids.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 951677c5c..3f233adf6 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -17,6 +17,7 @@ class _PARAM_PVS: IS_MOVING = 'Moving-Mon' BLCTRL_ENBL_SEL = 'BeamLineCtrlEnbl-Sel' BLCTRL_ENBL_STS = 'BeamLineCtrlEnbl-Sts' + MOVE_ABORT = None # --- PPARAM --- PPARAM_SP = None @@ -368,6 +369,11 @@ def cmd_move_enable(self): """Command to enable ID movements.""" return True + def cmd_move_abort(self): + """.""" + if self.PARAM_PVS.MOVE_ABORT is not None: + self[self.PARAM_PVS.MOVE_ABORT] = 1 + def cmd_move_stop(self, timeout=None): """Command to interrupt and then enable phase movements.""" timeout = timeout or self._DEF_TIMEOUT @@ -376,8 +382,11 @@ def cmd_move_stop(self, timeout=None): if not self.wait_while_busy(timeout=timeout): return False - # # send stop command - # self.cmd_move_disable() + # send abort command + self.cmd_move_abort() + + # send disable command + self.cmd_move_disable() # check for successful stop if not self.wait_while_busy(timeout=timeout): @@ -385,9 +394,9 @@ def cmd_move_stop(self, timeout=None): if not self.wait_move_finish(timeout=timeout): return False - # # enable movement again - # if not self.cmd_move_enable(timeout=timeout): - # return False + # enable movement again + if not self.cmd_move_enable(timeout=timeout): + return False return True @@ -415,8 +424,13 @@ def cmd_change_polarization_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Move ID to parked config.""" - pparam, kparam = self.pparameter_parked, self.kparameter_parked - return self.cmd_move(pparam, kparam, timeout) + if self.PARAM_PVS.START_PARKING_CMD is not None: + self[self.PARAM_PVS.START_PARKING_CMD] = 1 + pparam, kparam = self.pparameter_parked, self.kparameter_parked + return self.wait_move_config(pparam, kparam) + else: + pparam, kparam = self.pparameter_parked, self.kparameter_parked + return self.cmd_move(pparam, kparam, timeout) def cmd_move_pparameter(self, pparam=None, timeout=None): """Command to set and start pparam movement.""" @@ -1100,6 +1114,7 @@ class DEVICES: PARAM_PVS.PERIOD_LEN_CTE = 'PeriodLength-Cte' PARAM_PVS.IS_MOVING = 'Moving-Mon' PARAM_PVS.START_PARKING_CMD = 'StartParking-Cmd' + PARAM_PVS.MOVE_ABORT = 'Abort-Cmd' PARAM_PVS.PPARAM_SP = 'PParam-SP' PARAM_PVS.PPARAM_RB = 'PParam-RB' PARAM_PVS.PPARAM_MON = 'PParam-Mon' From 769d087be2084a3a310b5aa215839543b71f4836 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 4 Dec 2023 13:51:20 -0300 Subject: [PATCH 180/309] Update device ID --- siriuspy/siriuspy/devices/ids.py | 41 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 3f233adf6..cbd82f3e0 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -395,7 +395,7 @@ def cmd_move_stop(self, timeout=None): return False # enable movement again - if not self.cmd_move_enable(timeout=timeout): + if not self.cmd_move_enable(): return False return True @@ -424,12 +424,13 @@ def cmd_change_polarization_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Move ID to parked config.""" + pparam, kparam = self.pparameter_parked, self.kparameter_parked + timeout = self._calc_eta(pparam, kparam) if timeout is None \ + else timeout if self.PARAM_PVS.START_PARKING_CMD is not None: self[self.PARAM_PVS.START_PARKING_CMD] = 1 - pparam, kparam = self.pparameter_parked, self.kparameter_parked - return self.wait_move_config(pparam, kparam) + return self.wait_move_config(pparam, kparam, timeout) else: - pparam, kparam = self.pparameter_parked, self.kparameter_parked return self.cmd_move(pparam, kparam, timeout) def cmd_move_pparameter(self, pparam=None, timeout=None): @@ -472,14 +473,8 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): timeout = max(timeout - (t1_ - t0_), 0) # calc ETA - dtime_kparam = 0 if kparam is None else \ - abs(kparam - self.kparameter_mon) / self.kparameter_speed - dtime_pparam = 0 if pparam is None else \ - abs(pparam - self.pparameter_mon) / self.pparameter_speed - dtime_max = max(dtime_kparam, dtime_pparam) - # additional percentual in ETA - dtime = 4.0 * dtime_max + 5 - timeout = dtime if timeout is None else max(dtime - timeout, 0) + eta = self._calc_eta(pparam, kparam) + timeout = eta if timeout is None else max(eta - timeout, 0) # wait for movement within reasonable time return self.wait_move_config(pparam, kparam, timeout) @@ -557,6 +552,22 @@ def _wait_propty(self, propty, value, timeout=None): return False return True + def _calc_eta(self, pparam, kparam): + """.""" + # calc ETA + dtime_kparam = 0 if kparam is None else \ + abs(kparam - self.kparameter_mon) / self.kparameter_speed + dtime_pparam = 0 if pparam is None else \ + abs(pparam - self.pparameter_mon) / self.pparameter_speed + dtime_max = self._calc_eta_select_time(dtime_kparam, dtime_pparam) + # additional percentual in ETA + eta = 4.0 * dtime_max + 5 + return eta + + @staticmethod + def _calc_eta_select_time(dtime_kparam, dtime_pparam): + return dtime_kparam + dtime_pparam + class APU(_ID): """APU Insertion Device.""" @@ -1099,6 +1110,12 @@ def cmd_clear_error(self): """Command to clear errors.""" pass + # --- private methods --- + + @staticmethod + def _calc_eta_select_time(dtime_kparam, dtime_pparam): + return max(dtime_kparam, dtime_pparam) + class DELTA(_ID): """DELTA Insertion Device.""" From 593628af91e1f89e2b178c732154760995899110 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 16:53:49 -0300 Subject: [PATCH 181/309] ORBINTLK.ENH: add DevEnbl PV to AFC Timing lock list --- siriuspy/siriuspy/orbintlk/csdev.py | 1 + siriuspy/siriuspy/orbintlk/main.py | 1 + 2 files changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 0291b36e6..068e055c8 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -100,6 +100,7 @@ class Const(_csdev.Const): ('RxEnbl-SP', 0b01000001), ) AFCTI_CONFIGS = ( + ('DevEnbl-Sel', 1), ('RTMPhasePropGain-SP', 100), ('RTMPhaseIntgGain-SP', 1), ('RTMFreqPropGain-SP', 1), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 21350d990..3d88a2fa9 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -138,6 +138,7 @@ def __init__(self, tests=True): idx+1: _Device( f'IA-{idx+1:02}RaBPM:TI-AMCFPGAEVR', props2init=[ + 'DevEnbl-Sel', 'DevEnbl-Sts', 'RTMClkLockedLtc-Mon', 'ClkLockedLtcRst-Cmd', 'RTMClkRst-Cmd', 'RTMPhasePropGain-SP', 'RTMPhasePropGain-RB', From 632f9b896270808f18f7a762dda716e01e529190 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 4 Dec 2023 19:06:29 -0300 Subject: [PATCH 182/309] DEV.DELTA.BUG: Fix logic in calculation of timeout. --- siriuspy/siriuspy/devices/ids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index cbd82f3e0..465ab5abb 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -474,7 +474,7 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): # calc ETA eta = self._calc_eta(pparam, kparam) - timeout = eta if timeout is None else max(eta - timeout, 0) + timeout = eta if timeout is None else timeout # wait for movement within reasonable time return self.wait_move_config(pparam, kparam, timeout) From 0b8e0237e663adeb21cad6c23fc9b5c7941a8a58 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 4 Dec 2023 19:07:05 -0300 Subject: [PATCH 183/309] DEV.DELTA.MNT: Reduce factor in prediction of ETA to 1.5. --- siriuspy/siriuspy/devices/ids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 465ab5abb..580881aec 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -561,7 +561,7 @@ def _calc_eta(self, pparam, kparam): abs(pparam - self.pparameter_mon) / self.pparameter_speed dtime_max = self._calc_eta_select_time(dtime_kparam, dtime_pparam) # additional percentual in ETA - eta = 4.0 * dtime_max + 5 + eta = 1.5 * dtime_max + 5 return eta @staticmethod From 3c33fe9693a249dfc3bfe54928413d3931efbcc8 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 19:07:21 -0300 Subject: [PATCH 184/309] ORBINTLK.ENH: control IA-10RaBPM:TI-EVR using new high level trigger --- siriuspy/siriuspy/orbintlk/csdev.py | 33 ++++++++---------- siriuspy/siriuspy/orbintlk/main.py | 54 +++-------------------------- 2 files changed, 18 insertions(+), 69 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 068e055c8..385490b7c 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -29,9 +29,10 @@ class ETypes(_csdev.ETypes): 'FoutsBPMConn', 'FoutsBPMConfig', 'FoutsDCCTConn', 'FoutsDCCTConfig', 'AFCTimingConn', 'AFCTimingConfig', - 'EVRIntlkRedundancyConn', 'EVRIntlkRedundancyConfig', 'AFCPhysTrigsConn', 'AFCPhysTrigsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', + 'OrbIntlkRedTrigConn', 'OrbIntlkRedTrigStatusOK', + 'OrbIntlkRedTrigConfig', 'LLRFPsMtmTrigConn', 'LLRFPsMtmTrigStatusOK', 'LLRFPsMtmTrigConfig', 'BPMPsMtmTrigConn', 'BPMPsMtmTrigStatusOK', 'BPMPsMtmTrigConfig', 'DCCT13C4PsMtmTrigConn', 'DCCT13C4PsMtmTrigStatusOK', @@ -64,38 +65,33 @@ class Const(_csdev.Const): ('DelayRaw-SP', 0), ('State-Sel', 1), ('WidthRaw-SP', 1), - ('Direction-Sel', 1)) - ), + ('Direction-Sel', 1))), + ('SI-Fam:TI-OrbIntlkRedundancy', ( + ('Src-Sel', 0), + ('State-Sel', 1), + ('Polarity-Sts', 0), + ('Log-Sel', 1))), ('SI-Glob:TI-LLRF-PsMtm', ( ('Src-Sel', 5), ('DelayRaw-SP', 0), ('State-Sel', 1), - ('WidthRaw-SP', 9369)) - ), + ('WidthRaw-SP', 9369))), ('SI-Fam:TI-BPM-PsMtm', ( ('Src-Sel', 5), ('DelayRaw-SP', 0), ('State-Sel', 1), - ('WidthRaw-SP', 6)) - ), + ('WidthRaw-SP', 6))), ('SI-13C4:TI-DCCT-PsMtm', ( ('Src-Sel', 0), ('State-Sel', 1), - ('Log-Sel', 0)) - ), + ('Polarity-Sts', 0), + ('Log-Sel', 0))), ('SI-14C4:TI-DCCT-PsMtm', ( ('Src-Sel', 0), ('State-Sel', 1), - ('Log-Sel', 0)) - ), + ('Polarity-Sts', 0), + ('Log-Sel', 0))), ] - INTLKREDEVR_CONFIGS = ( - ('DevEnbl-Sel', 1), - ('DIN0State-Sel', 1), - ('DIN0Evt-SP', 118), - ('DIN0Polarity-Sel', 0), - ('DIN0Log-Sel', 1), - ) FOUT2_CONFIGS = ( ('RxEnbl-SP', 0b01000001), ) @@ -395,7 +391,6 @@ def get_database(self): # Config devices 'ConfigEVG-Cmd': {'type': 'int', 'value': 0}, 'ConfigFouts-Cmd': {'type': 'int', 'value': 0}, - 'ConfigDeltaRedunEVR-Cmd': {'type': 'int', 'value': 0}, 'ConfigAFCTiming-Cmd': {'type': 'int', 'value': 0}, 'ConfigHLTriggers-Cmd': {'type': 'int', 'value': 0}, 'ConfigLLRFIntlk-Cmd': {'type': 'int', 'value': 0}, diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 3d88a2fa9..4dacae5fc 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -71,7 +71,7 @@ def __init__(self, tests=True): self._lock_suspend = True self._lock_pvs = { k: list() for k in - ['EVG', 'Fouts', 'EVRRedun', 'AFCTI', 'HLTriggers', + ['EVG', 'Fouts', 'AFCTI', 'HLTriggers', 'LLRF', 'BPM', 'AFCPhysTriggers']} self._set_queue = _LoopQueueThread() self._set_queue.start() @@ -164,17 +164,6 @@ def __init__(self, tests=True): pvo.wait_for_connection() self._everf_evtcnt = pvo.get() or 0 - # # delta redundancy EVR - self._evrdelta_dev = _Device( # TODO: change to use new hltrigger - 'IA-10RaBPM:TI-EVR', - props2init=[ - 'DevEnbl-Sel', 'DevEnbl-Sts', - 'DIN0State-Sel', 'DIN0State-Sts', - 'DIN0Evt-SP', 'DIN0Evt-RB', - 'DIN0Polarity-Sel', 'DIN0Polarity-Sts', - 'DIN0Log-Sel', 'DIN0Log-Sts', - ]) - # # HL triggers self._hltrig_devs = dict() for trigname, configs in self._const.HLTRIG_2_CONFIG: @@ -187,10 +176,9 @@ def __init__(self, tests=True): trigname=trigname, props2init=props2init, auto_monitor_mon=True) - if 'DCCT' in trigname: - continue - pvo = self._hltrig_devs[trigname].pv_object('Status-Mon') - pvo.add_callback(self._callback_hltrig_status) + if 'LLRF' in trigname or 'OrbIntlkRedundancy' in trigname: + pvo = self._hltrig_devs[trigname].pv_object('Status-Mon') + pvo.add_callback(self._callback_hltrig_status) # # BPM devices self._orbintlk_dev = _OrbitIntlk() @@ -289,7 +277,6 @@ def __init__(self, tests=True): 'ResetAFCTimingRTMClk-Cmd': self.cmd_reset_afcti_rtmclk, 'ConfigEVG-Cmd': self.cmd_config_evg, 'ConfigFouts-Cmd': self.cmd_config_fouts, - 'ConfigDeltaRedunEVR-Cmd': self.cmd_config_deltaevr, 'ConfigAFCTiming-Cmd': self.cmd_config_afcti, 'ConfigHLTriggers-Cmd': self.cmd_config_hltrigs, 'ConfigLLRFIntlk-Cmd': self.cmd_config_llrf, @@ -378,7 +365,6 @@ def _enable_lock(self, init=False): self._lock_suspend = False self._handle_lock_evg_configs(init) self._handle_lock_fouts(init) - self._handle_lock_redundancy_evr(init) self._handle_lock_afcti(init) self._handle_lock_hltriggers(init) self._handle_lock_llrf(init) @@ -436,19 +422,6 @@ def _handle_lock_fouts(self, init=False): else: pvo.run_callbacks() - def _handle_lock_redundancy_evr(self, init=False): - self._evrdelta_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) - for propty_sp, desired_val in self._const.INTLKREDEVR_CONFIGS: - propty_rb = _PVName.from_sp2rb(propty_sp) - pvo = self._evrdelta_dev.pv_object(propty_rb) - if init: - self._lock_pvs['EVRRedun'].append(pvo.pvname) - pvo.add_callback(_part( - self._callback_lock, self._evrdelta_dev, - propty_sp, desired_val)) - else: - pvo.run_callbacks() - def _handle_lock_afcti(self, init=False): for dev in self._afcti_devs.values(): dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) @@ -973,15 +946,6 @@ def cmd_config_fouts(self, value): self._do_auxiliary_cmd(self._handle_lock_fouts, 'Fouts') return True - def cmd_config_deltaevr(self, value): - """Configure Delta EVR according to lock configurations.""" - _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False - self._do_auxiliary_cmd(self._handle_lock_redundancy_evr, 'EVRRedun') - return True - def cmd_config_afcti(self, value): """Configure all AFC timing according to lock configurations.""" _ = value @@ -1249,16 +1213,6 @@ def _check_configs(self): value = _updt_bit(value, 8, not okg) else: value += 0b11 << 7 - # Delta Interlock Redundancy EVR - dev = self._evrdelta_dev - if dev.connected: - okg = True - for prp, val in self._const.INTLKREDEVR_CONFIGS: - prp_rb = _PVName.from_sp2rb(prp) - okg &= dev[prp_rb] == val - value = _updt_bit(value, 10, not okg) - else: - value += 0b11 << 9 # AFC Physical triggers if all(dev.connected for dev in self._phytrig_devs): okg = True From c96abbf14e4fc060950f05ea7028b0b62d1f8b6c Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 4 Dec 2023 19:13:17 -0300 Subject: [PATCH 185/309] DEV.DELTA.ENH: implement _calc_eta for DELTA, considering the negative values of kparam in phase circularp. --- siriuspy/siriuspy/devices/ids.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 580881aec..ebc8d1409 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -139,6 +139,15 @@ def polarization_mon(self): else: return None + @property + def polarization_mon_str(self): + """Return ID polarization string.""" + pol_idx = self.polarization_mon + if pol_idx is None: + return None + else: + return self._pols_sts_str[pol_idx] + # --- pparameter --- @property @@ -1239,6 +1248,12 @@ def pos_cid_mon(self): """ return self['CIDVirtPos-Mon'] + def _calc_eta(self, pparam, kparam): + """.""" + if self.polarization_mon_str == 'circularp': + kparam = -kparam + return super()._calc_eta(pparam, kparam) + class WIG(_ID): """Wiggler Insertion Device.""" From 95a172610deb9e2a372cd6b12df5dcbc9653d264 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 4 Dec 2023 19:24:46 -0300 Subject: [PATCH 186/309] DEV.DELTA.FIX: account for kparam=None in _calc_eta. --- siriuspy/siriuspy/devices/ids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index ebc8d1409..ee7fe1e9f 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1250,7 +1250,7 @@ def pos_cid_mon(self): def _calc_eta(self, pparam, kparam): """.""" - if self.polarization_mon_str == 'circularp': + if kparam is not None and self.polarization_mon_str == 'circularp': kparam = -kparam return super()._calc_eta(pparam, kparam) From d4788a2f95059a3883a5fccef6c2e8bffe5c8c37 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 22:48:19 -0300 Subject: [PATCH 187/309] ORBINTLK.ENH: standardize control of Fouts and create redundancy table to be possible to remove hardcoded comparisons --- siriuspy/siriuspy/orbintlk/csdev.py | 24 +++-- siriuspy/siriuspy/orbintlk/main.py | 134 ++++++++++++---------------- 2 files changed, 74 insertions(+), 84 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 385490b7c..c12e73925 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -26,8 +26,7 @@ class ETypes(_csdev.ETypes): 'AcqConfigured', 'LogTrigConfig') STS_LBLS_TIMING = ( 'EVGConn', 'EVGIntlkEnblSynced', 'EVGConfig', - 'FoutsBPMConn', 'FoutsBPMConfig', - 'FoutsDCCTConn', 'FoutsDCCTConfig', + 'FoutsConn', 'FoutsConfig', 'AFCTimingConn', 'AFCTimingConfig', 'AFCPhysTrigsConn', 'AFCPhysTrigsConfig', 'OrbIntlkTrigConn', 'OrbIntlkTrigStatusOK', 'OrbIntlkTrigConfig', @@ -92,9 +91,9 @@ class Const(_csdev.Const): ('Polarity-Sts', 0), ('Log-Sel', 0))), ] - FOUT2_CONFIGS = ( - ('RxEnbl-SP', 0b01000001), - ) + FOUTSFIXED_RXENBL = { + 'CA-RaTim:TI-Fout-2': 0b01000001, + } AFCTI_CONFIGS = ( ('DevEnbl-Sel', 1), ('RTMPhasePropGain-SP', 100), @@ -125,6 +124,9 @@ class Const(_csdev.Const): ('TRIGGER_PM14RcvSrc-Sel', 0), ('TRIGGER_PM14RcvInSel-SP', 2), ) + REDUNDANCY_TABLE = { + 'IA-10RaBPM:TI-AMCFPGAEVR': 'IA-10RaBPM:TI-EVR', + } __EVG_CONFIGS = None __FOUTS_2_MON = None @@ -190,6 +192,18 @@ def FOUTS_2_MON(cls): def __init__(self): """Class constructor.""" + # crates mapping + self.crates_map = _LLTimeSearch.get_crates_mapping() + + # trigger source to fout out mapping + self.trigsrc2fout_map = _LLTimeSearch.get_trigsrc2fout_mapping() + + # interlock redundancy table for fout outs + self.intlkr_fouttable = { + self.trigsrc2fout_map[k]: self.trigsrc2fout_map[v] + for k, v in self.REDUNDANCY_TABLE.items()} + self.intlkr_fouttable.update( + {v: k for k, v in self.intlkr_fouttable.items()}) # bpm names and nicknames self.bpm_names = _BPMSearch.get_names({'sec': 'SI', 'dev': 'BPM'}) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 4dacae5fc..d54f0ceb1 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -110,6 +110,8 @@ def __init__(self, tests=True): pvo.add_callback(self._callback_evg_rxlock) # # Fouts + foutnames = list(self._const.FOUTS_2_MON) + \ + list(self._const.FOUTSFIXED_RXENBL.keys()) self._fout_devs = { devname: _Device( devname, @@ -117,21 +119,14 @@ def __init__(self, tests=True): 'RxEnbl-SP', 'RxEnbl-RB', 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', ], auto_monitor_mon=True) - for devname in self._const.FOUTS_2_MON - } + for devname in foutnames} self._fout2rxenbl = dict() for devname, dev in self._fout_devs.items(): pvo = dev.pv_object('RxLockedLtc-Mon') pvo.add_callback(self._callback_fout_rxlock) pvo.connection_callbacks.append(self._conn_callback_timing) - self._fout2rxenbl[devname] = 0 - - self._fout_dcct_dev = _Device( - 'CA-RaTim:TI-Fout-2', - props2init=[ - 'RxEnbl-SP', 'RxEnbl-RB', - 'RxLockedLtc-Mon', 'RxLockedLtcRst-Cmd', - ], auto_monitor_mon=True) + rxenbl = self._const.FOUTSFIXED_RXENBL.get(devname, 0) + self._fout2rxenbl[devname] = rxenbl # # AFC timing self._afcti_devs = { @@ -221,7 +216,7 @@ def __init__(self, tests=True): # # AFC physical trigger devices phytrig_names = list() - for afcti, cratemap in _LLTimeSearch.get_crates_mapping().items(): + for afcti, cratemap in self._const.crates_map.items(): if '20RaBPMTL' in afcti: continue phytrig_names.extend(cratemap) @@ -399,7 +394,6 @@ def _handle_lock_evg_enable(self, init=False): pvo.run_callbacks() def _handle_lock_fouts(self, init=False): - # BPM Fouts for dev in self._fout_devs.values(): dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) pvo = dev.pv_object('RxEnbl-RB') @@ -409,19 +403,6 @@ def _handle_lock_fouts(self, init=False): else: pvo.run_callbacks() - # DCCT Fout - self._fout_dcct_dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) - for propty_sp, desired_val in self._const.FOUT2_CONFIGS: - propty_rb = _PVName.from_sp2rb(propty_sp) - pvo = self._fout_dcct_dev.pv_object(propty_rb) - if init: - self._lock_pvs['Fouts'].append(pvo.pvname) - pvo.add_callback(_part( - self._callback_lock, self._fout_dcct_dev, - propty_sp, desired_val)) - else: - pvo.run_callbacks() - def _handle_lock_afcti(self, init=False): for dev in self._afcti_devs.values(): dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) @@ -833,17 +814,6 @@ def cmd_reset_ti_lock_latch(self, value=None): self._update_log(f'{msg} {devname} lock latchs.') if 'not' in msg: return False - # try to reset DCCT Fout rx lock latches if necessary, return false if fail - dev = self._fout_dcct_dev - rxv = dev['RxEnbl-RB'] - if dev['RxLockedLtc-Mon'] == rxv: - return True - dev['RxLockedLtcRst-Cmd'] = 1 - msg = 'Reset' if dev._wait('RxLockedLtc-Mon', rxv, timeout=3) \ - else 'ERR:Could not reset' - self._update_log(f'{msg} {dev.devname} lock latchs.') - if 'not' in msg: - return False return True def cmd_reset_afcti_rtmclk(self, value=None): @@ -1029,12 +999,17 @@ def _config_fout_rxenbl(self): if 'Fout' not in chn: continue fout = chn.device_name - out = int(chn.propty_name[-1]) + outnam = chn.propty_name + if not outnam: + continue + out = int(outnam[-1]) rx = fout2rx.get(fout, 0) rx += 1 << out fout2rx[fout] = rx for fout, dev in self._fout_devs.items(): + if fout in self._const.FOUTSFIXED_RXENBL: + continue rxenbl = fout2rx.get(fout, 0) self._fout2rxenbl[fout] = rxenbl if not self._init: @@ -1063,17 +1038,27 @@ def _get_monitored_devices(self): for sub in subsecs: afcti = f'IA-{sub:02}RaBPM:TI-AMCFPGAEVR' tidevs.add(afcti) - foutout = _LLTimeSearch.get_trigsrc2fout_mapping()[afcti] + foutout = self._const.trigsrc2fout_map[afcti] tidevs.add(foutout) + fout = _PVName(foutout).device_name + tidevs.add(fout) evgout = _LLTimeSearch.get_evg_channel(foutout) tidevs.add(evgout) + if afcti in self._const.REDUNDANCY_TABLE: + afctir = self._const.REDUNDANCY_TABLE[afcti] + tidevs.add(afctir) + foutoutr = self._const.trigsrc2fout_map[afcti] + tidevs.add(foutoutr) + foutr = _PVName(foutoutr).device_name + tidevs.add(foutr) + evgoutr = _LLTimeSearch.get_evg_channel(foutoutr) + tidevs.add(evgoutr) return bpmdevs, sorted(tidevs) def _check_ti_devices_status(self, devices): for devname in devices: devname = _PVName(devname) - out = int(devname.propty[-1]) if devname.propty else None dev = self._evg_dev if 'EVG' in devname else \ self._fout_devs[devname.device_name] if 'Fout' in devname \ @@ -1086,11 +1071,12 @@ def _check_ti_devices_status(self, devices): if not dev.connected: self._update_log(f'ERR:{dev.devname} not connected') return False - if out and not _get_bit(dev['RxLockedLtc-Mon'], out): - self._update_log(f'ERR:{dev.devname} OUT{out} not locked') - return False - if 'RTMClkLockedLtc-Mon' in dev.properties_in_use and \ - not dev['RTMClkLockedLtc-Mon']: + elif 'Fout' in devname: + out = int(devname.propty[-1]) if devname.propty else None + if out is not None and not _get_bit(dev['RxLockedLtc-Mon'], out): + self._update_log(f'ERR:{dev.devname} OUT{out} not locked') + return False + elif 'AMCFPGA' in devname and not dev['RTMClkLockedLtc-Mon']: self._update_log(f'ERR:{dev.devname} RTM Clk not locked') return False return True @@ -1180,9 +1166,8 @@ def _check_configs(self): value = _updt_bit(value, 2, not okg) else: value = 0b111 - # BPM Fouts - devs = self._fout_devs - if all(devs[devn].connected for devn in self._const.FOUTS_2_MON): + # Fouts + if all(dev.connected for dev in self._fout_devs.values()): okg = True for devname, rxenbl in self._fout2rxenbl.items(): dev = self._fout_devs[devname] @@ -1191,18 +1176,6 @@ def _check_configs(self): value = _updt_bit(value, 4, not okg) else: value += 0b11 << 3 - # DCCT Fouts - dev = self._fout_dcct_dev - if dev.connected: - okg = True - for prp, val in self._const.FOUT2_CONFIGS: - prp_rb = _PVName.from_sp2rb(prp) - okg &= dev[prp_rb] == val - if 'RxEnbl' in prp: - okg &= dev['RxLockedLtc-Mon'] == val - value = _updt_bit(value, 6, not okg) - else: - value += 0b11 << 5 # AFC timing if all(dev.connected for dev in self._afcti_devs.values()): okg = True @@ -1210,9 +1183,9 @@ def _check_configs(self): for prp, val in self._const.AFCTI_CONFIGS: prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val - value = _updt_bit(value, 8, not okg) + value = _updt_bit(value, 6, not okg) else: - value += 0b11 << 7 + value += 0b11 << 5 # AFC Physical triggers if all(dev.connected for dev in self._phytrig_devs): okg = True @@ -1223,11 +1196,11 @@ def _check_configs(self): continue prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val - value = _updt_bit(value, 12, not okg) + value = _updt_bit(value, 8, not okg) else: - value += 0b11 << 11 + value += 0b11 << 7 # HL triggers - bit = 13 + bit = 9 for trigname, configs in self._const.HLTRIG_2_CONFIG: dev = self._hltrig_devs[trigname] if dev.connected: @@ -1325,12 +1298,12 @@ def _do_callback_rxlock(self, pvname, value): if _get_bit(value, bit): continue outnam = f'OUT{bit}' - self._update_log(f'FATAL:{outnam} of {devname} not locked') + self._update_log(f'WARN:{outnam} of {devname} not locked') devout = devname.substitute(propty_name=outnam) # verify if this is an orbit interlock reliability failure is_failure |= devout in self._ti_mon_devs else: - is_failure, outs_in_failure = False, set() + outs_in_failure = set() for dev in self._ti_mon_devs: # verify fouts if 'Fout' not in dev: @@ -1340,21 +1313,26 @@ def _do_callback_rxlock(self, pvname, value): if dev.device_name == devname: # verify if the monitored outs are locked outnam = dev.propty_name + if not outnam: + continue out = int(outnam[-1]) if _get_bit(value, out): continue # if not, it is a reliability failure - is_failure = True outs_in_failure.add(out) - self._update_log(f'ERR:{outnam} of {devname} not locked') - # specifically for delta subsector (10), consider a failure only if - # redundancy timing path is also not locked - trigsrc = _LLTimeSearch.get_fout2trigsrc_mapping()[devname] - if len(outs_in_failure) == 1: - out = outs_in_failure.pop() - if trigsrc[f'OUT{out}'].sub[0:2] == '10': - rxlock = self._fout_dcct_dev['RxLockedLtc-Mon'] - is_failure &= not _get_bit(rxlock, 0) # out 0 + self._update_log(f'WARN:{outnam} of {devname} not locked') + # verify redundancy pairs, failure only if both are in failure + aux_var_loop = outs_in_failure.copy() + for out in aux_var_loop: + outnam = f'OUT{out}' + devout = devname.substitute(propty_name=outnam) + if devout in self._const.intlkr_fouttable: + pair = self._const.intlkr_fouttable[devout] + if self._fout_devs[pair]['RxLockedLtc-Mon']: + outs_in_failure.pop(out) + else: + self._update_log(f'WARN:{outnam} of {pair} not locked') + is_failure = bool(outs_in_failure) if not is_failure: return @@ -1367,9 +1345,7 @@ def _conn_callback_timing(self, pvname, conn, **kws): devname = _PVName(pvname).device_name self._update_log(f'FATAL:{devname} disconnected') # verify if this is an orbit interlock reliability failure - is_failure = False - for dev in self._ti_mon_devs: - is_failure |= _PVName(dev).device_name == devname + is_failure = devname in self._ti_mon_devs if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() From c38d9b2a0b565f177cc30f261575f43a966e4b02 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 22:53:04 -0300 Subject: [PATCH 188/309] ORBINTLK.FIX: change list of BPM monitored devices to consider all AFC physical triggers of monitored crates This change is necessary, once when an AFC board is disconnected, this can block signals from BPM to be propagated. --- siriuspy/siriuspy/orbintlk/main.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d54f0ceb1..ef13aba4f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -210,9 +210,6 @@ def __init__(self, tests=True): 'TRIGGER_PM14RcvSrc-Sel', 'TRIGGER_PM14RcvSrc-Sts', 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB']) self._monitsum2intlksum_factor = 0 - for dev in self._fambpm_dev.devices: - pvo = dev.pv_object('INFOMONITRate-RB') - pvo.connection_callbacks.append(self._conn_callback_bpm) # # AFC physical trigger devices phytrig_names = list() @@ -226,6 +223,9 @@ def __init__(self, tests=True): 'DirPol-Sel', 'DirPol-Sts', 'TrnLen-SP', 'TrnLen-RB']) for dev in phytrig_names] + for dev in self._phytrig_devs: + pvo = dev.pv_object('Dir-Sel') + pvo.connection_callbacks.append(self._conn_callback_afcphystrigs) # # RF devices self._llrf = _ASLLRF( @@ -1024,18 +1024,15 @@ def _config_fout_rxenbl(self): def _get_monitored_devices(self): enbllist = self._get_gen_bpm_intlk() - - # bpms - idcs = _np.where(enbllist)[0] - bpmdevs = [self._const.bpm_names[i] for i in idcs] - - # timing - tidevs = set() - tidevs.add(self._evg_dev.devname) aux = _np.roll(enbllist, 1) subsecs = _np.where(_np.sum(aux.reshape(20, -1), axis=1) > 0)[0] subsecs += 1 + + tidevs = set() + tidevs.add(self._evg_dev.devname) + bpmdevs = set() for sub in subsecs: + # timing afcti = f'IA-{sub:02}RaBPM:TI-AMCFPGAEVR' tidevs.add(afcti) foutout = self._const.trigsrc2fout_map[afcti] @@ -1053,6 +1050,8 @@ def _get_monitored_devices(self): tidevs.add(foutr) evgoutr = _LLTimeSearch.get_evg_channel(foutoutr) tidevs.add(evgoutr) + # bpm + bpmdevs.update(self._const.crates_map[afcti]) return bpmdevs, sorted(tidevs) @@ -1415,13 +1414,14 @@ def _get_bpm_rates_factor(self): self._monitsum2intlksum_factor = factor return self._monitsum2intlksum_factor - def _conn_callback_bpm(self, pvname, conn, **kws): + def _conn_callback_afcphystrigs(self, pvname, conn, **kws): _ = kws if conn: return devname = _PVName(pvname).device_name - self._update_log(f'WARN:{devname} disconnected') is_failure = devname in self._bpm_mon_devs + flag = 'ERR' if is_failure else 'WARN' + self._update_log(f'{flag}:{devname} disconnected') if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() From fb024ca209e2f6e222688350bc6f4ad7f850c0d4 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 22:58:55 -0300 Subject: [PATCH 189/309] ORBINTLK.ENH: do not try to lock PVs from devices that are not between monitored devices This is to avoid reliability failures caused by lock attempts during IOC recovery (when we lose connection), when the IOC is of a device that is not between the monitored ones --- siriuspy/siriuspy/orbintlk/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ef13aba4f..e7503552a 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1544,6 +1544,12 @@ def _start_lock_thread( self, device, propty_sp, desired_value, pvname, value): if self._lock_suspend and pvname not in self._lock_temp_pvs: return + + # do not try to lock devices that are not in list of monitored devices + devname = _PVName(pvname).device_name + if devname not in self._ti_mon_devs and \ + devname not in self._bpm_mon_devs: + return # if there is already a lock thread, return thread = self._lock_threads.get(pvname, None) From f82364e5f376da1f15ec3c032788220d7f9a0c4b Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 23:00:13 -0300 Subject: [PATCH 190/309] ORBINTLK.FIX: write only to polarity PVs of physical triggers that are not in orbit interlock --- siriuspy/siriuspy/orbintlk/main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e7503552a..e30324b36 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -976,6 +976,10 @@ def cmd_config_phytrigs(self, value): return False for dev in self._phytrig_devs: for prop, desired_val in self._const.AFCPHYTRIG_CONFIGS: + # only lock polarity of other AFC physical triggers than SI BPM + if dev.devname not in self._const.bpm_names and \ + prop != 'DirPol-Sel': + continue dev[prop] = desired_val return True From 2ab50eb0d021b7b150e3cc5aadbef966a340fc49 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 4 Dec 2023 23:40:49 -0300 Subject: [PATCH 191/309] ORBINTLK.FIX: reimplement auxiliary commands to only send setpoints, do not try to lock or to wait for readbacks --- siriuspy/siriuspy/orbintlk/main.py | 74 +++++++++++++++++------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index e30324b36..6120e947f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -69,10 +69,6 @@ def __init__(self, tests=True): self._lock_threads = dict() self._lock_failures = set() self._lock_suspend = True - self._lock_pvs = { - k: list() for k in - ['EVG', 'Fouts', 'AFCTI', 'HLTriggers', - 'LLRF', 'BPM', 'AFCPhysTriggers']} self._set_queue = _LoopQueueThread() self._set_queue.start() @@ -352,7 +348,6 @@ def init_database(self): self._init = True # start init lock devices - self._lock_temp_pvs = set() self._enable_lock(init=True) def _enable_lock(self, init=False): @@ -370,7 +365,6 @@ def _enable_lock(self, init=False): self._handle_lock_bpm_enable(init) def _disable_lock(self): - self._lock_temp_pvs = set() self._lock_suspend = True def _handle_lock_evg_configs(self, init=False): @@ -379,7 +373,6 @@ def _handle_lock_evg_configs(self, init=False): propty_rb = _PVName.from_sp2rb(propty_sp) pvo = self._evg_dev.pv_object(propty_rb) if init: - self._lock_pvs['EVG'].append(pvo.pvname) pvo.add_callback(_part( self._callback_lock, self._evg_dev, propty_sp, desired_val)) else: @@ -398,7 +391,6 @@ def _handle_lock_fouts(self, init=False): dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) pvo = dev.pv_object('RxEnbl-RB') if init: - self._lock_pvs['Fouts'].append(pvo.pvname) pvo.add_callback(self._callback_fout_lock) else: pvo.run_callbacks() @@ -410,7 +402,6 @@ def _handle_lock_afcti(self, init=False): propty_rb = _PVName.from_sp2rb(propty_sp) pvo = dev.pv_object(propty_rb) if init: - self._lock_pvs['AFCTI'].append(pvo.pvname) pvo.add_callback(_part( self._callback_lock, dev, propty_sp, desired_val)) else: @@ -424,7 +415,6 @@ def _handle_lock_hltriggers(self, init=False): prop_rb = _PVName.from_sp2rb(prop_sp) pvo = trigdev.pv_object(prop_rb) if init: - self._lock_pvs['HLTriggers'].append(pvo.pvname) pvo.add_callback( _part(self._callback_lock, trigdev, prop_sp, desired_val)) else: @@ -435,11 +425,9 @@ def _handle_lock_llrf(self, init=False): pvo_beamtrip = self._llrf.pv_object('ILK:BEAM:TRIP') pvo_manintlk = self._llrf.pv_object('ILK:MAN') if init: - self._lock_pvs['LLRF'].append(pvo_beamtrip.pvname) pvo_beamtrip.add_callback(_part( self._callback_lock, self._llrf, 'ILK:BEAM:TRIP:S', self._llrf_intlk_state)) - self._lock_pvs['LLRF'].append(pvo_manintlk.pvname) pvo_manintlk.add_callback(_part( self._callback_lock, self._llrf, 'ILK:MAN:S', self._llrf_intlk_state)) @@ -468,7 +456,6 @@ def _handle_lock_bpm_configs(self, init=False): for prop in prop2lock: pvo = dev.pv_object(prop) if init: - self._lock_pvs['BPM'].append(pvo.pvname) pvo.add_callback(self._callback_bpm_lock) else: pvo.run_callbacks() @@ -480,7 +467,6 @@ def _handle_lock_bpm_configs(self, init=False): prop_rb = _PVName.from_sp2rb(prop_sp) pvo = dev.pv_object(prop_rb) if init: - self._lock_pvs['BPM'].append(pvo.pvname) pvo.add_callback( _part(self._callback_lock, dev, prop_sp, desired_val)) else: @@ -506,7 +492,6 @@ def _handle_lock_afcphytrigs(self, init=False): prop_rb = _PVName.from_sp2rb(prop_sp) pvo = dev.pv_object(prop_rb) if init: - self._lock_pvs['AFCPhysTriggers'].append(pvo.pvname) pvo.add_callback( _part(self._callback_lock, dev, prop_sp, desired_val)) else: @@ -904,7 +889,11 @@ def cmd_config_evg(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd(self._handle_lock_evg_configs, 'EVG') + if not self._evg_dev.connected: + self._update_log('ERR:EVG disconnected.') + return False + for propty_sp, desired_val in self._const.EVG_CONFIGS: + self._evg_dev[propty_sp] = desired_val return True def cmd_config_fouts(self, value): @@ -913,7 +902,14 @@ def cmd_config_fouts(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd(self._handle_lock_fouts, 'Fouts') + for devname, dev in self._fout_devs.items(): + if not dev.connected: + self._update_log(f'ERR:{devname} disconnected.') + continue + desired_value = self._fout2rxenbl[devname] + dev['RxEnbl-SP'] = desired_value + dev._wait('RxEnbl-RB', desired_value, timeout=1) + dev['RxLockedLtcRst-Cmd'] = 1 return True def cmd_config_afcti(self, value): @@ -929,7 +925,13 @@ def cmd_config_afcti(self, value): self._update_log('ERR:Open correction loops before ') self._update_log('ERR:configuring AFC Timing RTM loop.') return False - self._do_auxiliary_cmd(self._handle_lock_afcti, 'AFCTI') + for dev in self._afcti_devs.values(): + if not dev.connected: + self._update_log(f'ERR:{dev.devname} disconnected.') + continue + for propty_sp, desired_val in self._const.AFCTI_CONFIGS: + dev[propty_sp] = desired_val + dev['ClkLockedLtcRst-Cmd'] = 1 return True def cmd_config_hltrigs(self, value): @@ -938,7 +940,13 @@ def cmd_config_hltrigs(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd(self._handle_lock_hltriggers, 'HLTriggers') + for trigname, configs in self._const.HLTRIG_2_CONFIG: + trigdev = self._hltrig_devs[trigname] + if not trigdev.connected: + self._update_log(f'ERR:{trigname} disconnected.') + continue + for prop_sp, desired_val in configs: + trigdev[prop_sp] = desired_val return True def cmd_config_llrf(self, value): @@ -947,7 +955,11 @@ def cmd_config_llrf(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False - self._do_auxiliary_cmd(self._handle_lock_llrf, 'LLRF') + if not self._llrf.connected: + self._update_log(f'ERR:LLRF disconnected.') + return False + self._llrf['ILK:BEAM:TRIP'] = self._llrf_intlk_state + self._llrf['ILK:MAN'] = self._llrf_intlk_state return True def cmd_config_bpms(self, value): @@ -956,6 +968,11 @@ def cmd_config_bpms(self, value): if self._state: self._update_log('ERR:Disable interlock before continue.') return False + + if not self._orbintlk_dev.connected: + for dev in self._orbintlk_dev.devices: + self._update_log(f'ERR:{dev.devname} disconnected.') + return False for name, enbl in self._enable_lists.items(): self.set_enbllist(name, enbl) @@ -975,6 +992,9 @@ def cmd_config_phytrigs(self, value): self._update_log('ERR:Disable interlock before continue.') return False for dev in self._phytrig_devs: + if not dev.connected: + self._update_log(f'ERR:{dev.devname} disconnected.') + continue for prop, desired_val in self._const.AFCPHYTRIG_CONFIGS: # only lock polarity of other AFC physical triggers than SI BPM if dev.devname not in self._const.bpm_names and \ @@ -983,18 +1003,6 @@ def cmd_config_phytrigs(self, value): dev[prop] = desired_val return True - def _do_auxiliary_cmd(self, func, pvgroup): - self._lock_temp_pvs.update(self._lock_pvs[pvgroup]) - func() - for pvn in self._lock_temp_pvs: - if pvn not in self._lock_threads: - continue - _time.sleep(0.02) - thread = self._lock_threads[pvn] - if thread.is_alive(): - thread.join() - self._lock_temp_pvs.clear() - # --- status methods --- def _config_fout_rxenbl(self): @@ -1546,7 +1554,7 @@ def _callback_bpm_lock(self, pvname, value, **kws): def _start_lock_thread( self, device, propty_sp, desired_value, pvname, value): - if self._lock_suspend and pvname not in self._lock_temp_pvs: + if self._lock_suspend: return # do not try to lock devices that are not in list of monitored devices From ebb44ac1a3f0f943d5d61a023d907dd2a6692acf Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:05:55 -0300 Subject: [PATCH 192/309] ORBINTLK.FIX: only write to EVG if needed --- siriuspy/siriuspy/orbintlk/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 6120e947f..157a435c8 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -893,6 +893,9 @@ def cmd_config_evg(self, value): self._update_log('ERR:EVG disconnected.') return False for propty_sp, desired_val in self._const.EVG_CONFIGS: + propty_rb = _PVName.from_sp2rb(propty_sp) + if self._evg_dev[propty_rb] == desired_val: + continue self._evg_dev[propty_sp] = desired_val return True From 8f1b7dc1e8c6df7dec9636720683c89c1b04e7f2 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:09:16 -0300 Subject: [PATCH 193/309] ORBINTLK.FIX: wait a little between setpoints to EVG --- siriuspy/siriuspy/orbintlk/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 157a435c8..f397ee842 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -897,6 +897,7 @@ def cmd_config_evg(self, value): if self._evg_dev[propty_rb] == desired_val: continue self._evg_dev[propty_sp] = desired_val + _time.sleep(0.2) return True def cmd_config_fouts(self, value): From 10de3c26e5e9ccb637331d08adbbc3bd0457d40a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:17:12 -0300 Subject: [PATCH 194/309] ORBINTLK.FIX: wait for EVG records to be processed --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index f397ee842..25645ef17 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -896,7 +896,8 @@ def cmd_config_evg(self, value): propty_rb = _PVName.from_sp2rb(propty_sp) if self._evg_dev[propty_rb] == desired_val: continue - self._evg_dev[propty_sp] = desired_val + pvo = self._evg_dev.pv_object(propty_sp) + pvo.put(desired_val, wait=True) _time.sleep(0.2) return True From caa1edfa67927830f44b2339e4ddbc6122323349 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:28:42 -0300 Subject: [PATCH 195/309] ORBINTLK.FIX: update internal callback object to include Fout-2 --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 25645ef17..3f0b106e4 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -62,7 +62,6 @@ def __init__(self, tests=True): self._thread_acq = None self._thread_cbevgilk = None self._thread_cbevgrx = None - self._thread_cbfout = {fout: None for fout in self._const.FOUTS_2_MON} self._thread_cbbpm = None self._bpm_mon_devs = list() self._ti_mon_devs = list() @@ -108,6 +107,7 @@ def __init__(self, tests=True): # # Fouts foutnames = list(self._const.FOUTS_2_MON) + \ list(self._const.FOUTSFIXED_RXENBL.keys()) + self._thread_cbfout = {fout: None for fout in foutnames} self._fout_devs = { devname: _Device( devname, From e390e01fa6bd03a1409c539b9f13bc198a105aab Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:29:37 -0300 Subject: [PATCH 196/309] ORBINTLK.FIX: fix HL triggers polarity PVs --- siriuspy/siriuspy/orbintlk/csdev.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index c12e73925..343dbdbac 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -68,7 +68,7 @@ class Const(_csdev.Const): ('SI-Fam:TI-OrbIntlkRedundancy', ( ('Src-Sel', 0), ('State-Sel', 1), - ('Polarity-Sts', 0), + ('Polarity-Sel', 0), ('Log-Sel', 1))), ('SI-Glob:TI-LLRF-PsMtm', ( ('Src-Sel', 5), @@ -83,12 +83,12 @@ class Const(_csdev.Const): ('SI-13C4:TI-DCCT-PsMtm', ( ('Src-Sel', 0), ('State-Sel', 1), - ('Polarity-Sts', 0), + ('Polarity-Sel', 0), ('Log-Sel', 0))), ('SI-14C4:TI-DCCT-PsMtm', ( ('Src-Sel', 0), ('State-Sel', 1), - ('Polarity-Sts', 0), + ('Polarity-Sel', 0), ('Log-Sel', 0))), ] FOUTSFIXED_RXENBL = { From fe9a5d0ac66ecaf023178188bb6f0cc2b1ad05ff Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:48:03 -0300 Subject: [PATCH 197/309] ORBINTLK.FIX: remove unneeded check for redundancy devices --- siriuspy/siriuspy/orbintlk/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 3f0b106e4..2c1566ad0 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1081,8 +1081,7 @@ def _check_ti_devices_status(self, devices): else self._afcti_devs[int(devname.sub[:2])] \ if 'AMCFPGA' in devname else None if dev is None: - self._update_log(f'ERR:Could not verify {devname} state.') - return False + return True if not dev.connected: self._update_log(f'ERR:{dev.devname} not connected') From e625e82080f20656658a913a74fad79d0857908d Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 09:52:20 -0300 Subject: [PATCH 198/309] ORBINTLK.MNT: sort BPM monitored devices PV --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 2c1566ad0..a5bb6b183 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1070,7 +1070,7 @@ def _get_monitored_devices(self): # bpm bpmdevs.update(self._const.crates_map[afcti]) - return bpmdevs, sorted(tidevs) + return sorted(bpmdevs), sorted(tidevs) def _check_ti_devices_status(self, devices): for devname in devices: From bb3147eaf44bfb28ba3de72eae4b9e24af3b4217 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 10:29:16 -0300 Subject: [PATCH 199/309] ORBINTLK.FIX: lock also high level triggers --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index a5bb6b183..470f90a03 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1564,7 +1564,8 @@ def _start_lock_thread( # do not try to lock devices that are not in list of monitored devices devname = _PVName(pvname).device_name if devname not in self._ti_mon_devs and \ - devname not in self._bpm_mon_devs: + devname not in self._bpm_mon_devs and \ + devname not in self._hltrig_devs: return # if there is already a lock thread, return From b694e43c9fd161636d8b21fd237660ff28c24016 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 10:40:00 -0300 Subject: [PATCH 200/309] ORBINTLK.FIX: fix bug in Fout RxLocked callback and log message for timing connection callback --- siriuspy/siriuspy/orbintlk/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 470f90a03..5057d5e42 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1343,7 +1343,8 @@ def _do_callback_rxlock(self, pvname, value): devout = devname.substitute(propty_name=outnam) if devout in self._const.intlkr_fouttable: pair = self._const.intlkr_fouttable[devout] - if self._fout_devs[pair]['RxLockedLtc-Mon']: + devpair = _PVName(pair).device_name + if self._fout_devs[devpair]['RxLockedLtc-Mon']: outs_in_failure.pop(out) else: self._update_log(f'WARN:{outnam} of {pair} not locked') @@ -1358,9 +1359,10 @@ def _conn_callback_timing(self, pvname, conn, **kws): if conn: return devname = _PVName(pvname).device_name - self._update_log(f'FATAL:{devname} disconnected') # verify if this is an orbit interlock reliability failure is_failure = devname in self._ti_mon_devs + flag = 'FATAL' if is_failure else 'WARN' + self._update_log(f'{flag}:{devname} disconnected') if is_failure: self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() From e06a62b0af610025891b1e106e55568ffd10a1ee Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 10:45:37 -0300 Subject: [PATCH 201/309] ORBINTLK.FIX: fix bug in Fout RxLocked callback --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 5057d5e42..b503a2806 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1345,7 +1345,7 @@ def _do_callback_rxlock(self, pvname, value): pair = self._const.intlkr_fouttable[devout] devpair = _PVName(pair).device_name if self._fout_devs[devpair]['RxLockedLtc-Mon']: - outs_in_failure.pop(out) + outs_in_failure.remove(out) else: self._update_log(f'WARN:{outnam} of {pair} not locked') is_failure = bool(outs_in_failure) From 9fd8b9a74555bd0ba2bbcb446dc6ca03f27a1df6 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 11:26:49 -0300 Subject: [PATCH 202/309] ORBINTLK.FIX: remove dependency on minimum sum --- siriuspy/siriuspy/orbintlk/main.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index b503a2806..213946666 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1462,34 +1462,10 @@ def _check_minsum_requirement(self, monit_sum=None): facq_sum = monit_sum * self._get_bpm_rates_factor() return _np.all(facq_sum > self._limits['minsum']) - def _callback_monitor_sum(self, value, cb_info, **kws): - # remove callback if is not anymore in a reliability failure - if not self._lock_failures: - cb_info[1].remove_callback(cb_info[0]) - - # check whether sum value is higher than minsum - if not self._check_minsum_requirement(value): - return - - # if sum is higher than minsum and there is lock failures, - # handle orbit interlock reliability failure - self._update_log('FATAL:Orbit interlock reliability failure') - for pvn in self._lock_failures: - self._update_log(f'FATAL:Fail to lock {pvn}') - self._handle_reliability_failure() - # and remove callback - cb_info[1].remove_callback(cb_info[0]) - def _handle_reliability_failure(self): if not self._state: self._update_log('WARN:Orbit interlock is not enabled.') return - # if minimum sum condition is not satisfied, only monitor sum - if not self._check_minsum_requirement(): - pvo = self._sofb.pv_object('SlowSumRaw-Mon') - if not pvo.callbacks: - pvo.add_callback(self._callback_monitor_sum) - return # send soft interlock to RF self._update_log('FATAL:sending soft interlock to LLRF.') self._llrf['IntlkSet-Cmd'] = 1 From 864b11f6db280ec1d2cf24e57a9fdedaf95b8f04 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 11:32:50 -0300 Subject: [PATCH 203/309] ORBINTLK.FIX: remove auxiliary commands condition on state --- siriuspy/siriuspy/orbintlk/main.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 213946666..8fe1ba03e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -886,9 +886,6 @@ def _acq_config(self): def cmd_config_evg(self, value): """Configure EVG according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False if not self._evg_dev.connected: self._update_log('ERR:EVG disconnected.') return False @@ -904,9 +901,6 @@ def cmd_config_evg(self, value): def cmd_config_fouts(self, value): """Configure Fouts according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False for devname, dev in self._fout_devs.items(): if not dev.connected: self._update_log(f'ERR:{devname} disconnected.') @@ -920,9 +914,6 @@ def cmd_config_fouts(self, value): def cmd_config_afcti(self, value): """Configure all AFC timing according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False # do not allow user configurate loop params in case of # correction loops closed if not self._fofb.connected or self._fofb['LoopState-Sts'] or \ @@ -942,9 +933,6 @@ def cmd_config_afcti(self, value): def cmd_config_hltrigs(self, value): """Configure HL triggers according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False for trigname, configs in self._const.HLTRIG_2_CONFIG: trigdev = self._hltrig_devs[trigname] if not trigdev.connected: @@ -957,9 +945,6 @@ def cmd_config_hltrigs(self, value): def cmd_config_llrf(self, value): """Configure LLRF interlock according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False if not self._llrf.connected: self._update_log(f'ERR:LLRF disconnected.') return False @@ -970,10 +955,6 @@ def cmd_config_llrf(self, value): def cmd_config_bpms(self, value): """Configure BPMs according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False - if not self._orbintlk_dev.connected: for dev in self._orbintlk_dev.devices: self._update_log(f'ERR:{dev.devname} disconnected.') @@ -993,9 +974,6 @@ def cmd_config_bpms(self, value): def cmd_config_phytrigs(self, value): """Configure physical triggers according to lock configurations.""" _ = value - if self._state: - self._update_log('ERR:Disable interlock before continue.') - return False for dev in self._phytrig_devs: if not dev.connected: self._update_log(f'ERR:{dev.devname} disconnected.') From 5efc26b5b369cacb2d072af1b18bb2bf9d4ac9ef Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 11:52:06 -0300 Subject: [PATCH 204/309] ORBINTLK.FIX: fix timing monitored device list --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 8fe1ba03e..744726d31 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1039,7 +1039,7 @@ def _get_monitored_devices(self): if afcti in self._const.REDUNDANCY_TABLE: afctir = self._const.REDUNDANCY_TABLE[afcti] tidevs.add(afctir) - foutoutr = self._const.trigsrc2fout_map[afcti] + foutoutr = self._const.trigsrc2fout_map[afctir] tidevs.add(foutoutr) foutr = _PVName(foutoutr).device_name tidevs.add(foutr) From ed06f99691cbe8ac52fef218ff5a62dc8a4e3b0a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 12:06:21 -0300 Subject: [PATCH 205/309] ORBINTLK.ENH: add callback to check BPM PLL status --- siriuspy/siriuspy/orbintlk/main.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 744726d31..d92e66a70 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -204,8 +204,13 @@ def __init__(self, tests=True): 'TRIGGER_PM12RcvSrc-Sel', 'TRIGGER_PM12RcvSrc-Sts', 'TRIGGER_PM12RcvInSel-SP', 'TRIGGER_PM12RcvInSel-RB', 'TRIGGER_PM14RcvSrc-Sel', 'TRIGGER_PM14RcvSrc-Sts', - 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB']) + 'TRIGGER_PM14RcvInSel-SP', 'TRIGGER_PM14RcvInSel-RB', + 'ADCAD9510PllStatus-Mon']) self._monitsum2intlksum_factor = 0 + for dev in self._fambpm_dev.devices: + pvo = dev.pv_object('ADCAD9510PllStatus-Mon') + pvo.auto_monitor = True + pvo.add_callback(self._callback_bpm_adclock) # # AFC physical trigger devices phytrig_names = list() @@ -1410,6 +1415,19 @@ def _get_bpm_rates_factor(self): self._monitsum2intlksum_factor = factor return self._monitsum2intlksum_factor + def _callback_bpm_adclock(self, pvname, value, **kws): + _ = kws + if value == 1: + return + devname = _PVName(pvname).device_name + is_failure = devname in self._bpm_mon_devs and \ + devname in self._const.bpm_names + flag = 'FATAL' if is_failure else 'WARN' + self._update_log(f'{flag}:{devname} lost PLL lock') + if is_failure: + self._update_log('FATAL:Orbit interlock reliability failure') + self._handle_reliability_failure() + def _conn_callback_afcphystrigs(self, pvname, conn, **kws): _ = kws if conn: From bf37793982124ee67a2b879065839298a9d29596 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 12:14:56 -0300 Subject: [PATCH 206/309] ORBINTLK.ENH: disable bypass --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d92e66a70..ce8e6f647 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -27,7 +27,7 @@ class App(_Callback): SCAN_FREQUENCY = 1 # [Hz] - def __init__(self, tests=True): + def __init__(self, tests=False): """Class constructor.""" super().__init__() self._is_dry_run = tests From 95fb59a7bdbf272b42734236f421f0755ae9b963 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 12:24:15 -0300 Subject: [PATCH 207/309] ORBINTLK.FIX: fix bug in LLRF config auxiliary command --- siriuspy/siriuspy/orbintlk/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index ce8e6f647..d698594d1 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -953,8 +953,8 @@ def cmd_config_llrf(self, value): if not self._llrf.connected: self._update_log(f'ERR:LLRF disconnected.') return False - self._llrf['ILK:BEAM:TRIP'] = self._llrf_intlk_state - self._llrf['ILK:MAN'] = self._llrf_intlk_state + self._llrf['ILK:BEAM:TRIP:S'] = self._llrf_intlk_state + self._llrf['ILK:MAN:S'] = self._llrf_intlk_state return True def cmd_config_bpms(self, value): From 60f3fe02385afd04de1b226e06eac5790557cae3 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 13:09:01 -0300 Subject: [PATCH 208/309] ORBINTLK.FIX: lock physical trigger configurations correctly --- siriuspy/siriuspy/orbintlk/main.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d698594d1..d4bbcb25c 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -491,8 +491,7 @@ def _handle_lock_afcphytrigs(self, init=False): dev.wait_for_connection(timeout=self._const.DEF_TIMEOUT) for prop_sp, desired_val in self._const.AFCPHYTRIG_CONFIGS: # only lock polarity of other AFC physical triggers than SI BPM - if dev.devname not in self._const.bpm_names and \ - prop_sp != 'DirPol-Sel': + if not self._check_lock_phytrig_prop(dev, prop_sp): continue prop_rb = _PVName.from_sp2rb(prop_sp) pvo = dev.pv_object(prop_rb) @@ -985,8 +984,7 @@ def cmd_config_phytrigs(self, value): continue for prop, desired_val in self._const.AFCPHYTRIG_CONFIGS: # only lock polarity of other AFC physical triggers than SI BPM - if dev.devname not in self._const.bpm_names and \ - prop != 'DirPol-Sel': + if not self._check_lock_phytrig_prop(dev, prop): continue dev[prop] = desired_val return True @@ -1088,6 +1086,12 @@ def _check_valid_bpmconfig(self, config): # check if pairs have the same config return not _np.any(_np.diff(aux.reshape(-1, 2), axis=1) != 0) + def _check_lock_phytrig_prop(self, dev, prop): + devname = _PVName(dev.devname).device_name + if devname in self._const.bpm_names: + return True + return prop == 'DirPol-Sel' + def _check_configs(self): _t0 = _time.time() @@ -1189,8 +1193,7 @@ def _check_configs(self): okg = True for dev in self._phytrig_devs: for prp, val in self._const.AFCPHYTRIG_CONFIGS: - if dev.devname not in self._const.bpm_names and \ - prp != 'DirPol-Sel': + if not self._check_lock_phytrig_prop(dev, prp): continue prp_rb = _PVName.from_sp2rb(prp) okg &= dev[prp_rb] == val From decffdbd766a42363e9e771cbf7201432a7a2ea6 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 17:17:56 -0300 Subject: [PATCH 209/309] ORBINTLK.FIX: fix RF EVE EvtCnt pvname and improve log message. Thanks to @ericonr! --- siriuspy/siriuspy/orbintlk/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index d4bbcb25c..4ee99f0e9 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -146,7 +146,7 @@ def __init__(self, tests=False): # # RF EVE trgsrc = _HLTimeSearch.get_ll_trigger_names('SI-Glob:TI-LLRF-PsMtm') pvname = _LLTimeSearch.get_channel_output_port_pvname(trgsrc[0]) - self._llrf_evtcnt_pvname = f'{pvname}EvtCnt-Mon' + self._llrf_evtcnt_pvname = f'{pvname.propty}EvtCnt-Mon' self._everf_dev = _Device( pvname.device_name, props2init=[self._llrf_evtcnt_pvname, ], @@ -1389,10 +1389,10 @@ def _do_callback_bpm_intlk(self): self._handle_reliability_failure() # wait minimum period for RF EVE event count to be updated _time.sleep(.1) - # verify if RF EVE propagated the event PsMtm + # verify if RF EVE counted the event PsMtm new_evtcnt = self._everf_dev[self._llrf_evtcnt_pvname] if new_evtcnt == self._everf_evtcnt: - self._update_log('WARN:RF EVE did not propagate event PsMtm') + self._update_log('WARN:RF EVE did counted event PsMtm') self._everf_evtcnt = new_evtcnt # wait minimum period for BPM to update interlock PVs _time.sleep(2) From a2fd9c8c97f52d9b2004864edac6be68acd90b3a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 17:58:45 -0300 Subject: [PATCH 210/309] orbintlk.MNT: return IOC to dry run --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 4ee99f0e9..c9ca88539 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -27,7 +27,7 @@ class App(_Callback): SCAN_FREQUENCY = 1 # [Hz] - def __init__(self, tests=False): + def __init__(self, tests=True): """Class constructor.""" super().__init__() self._is_dry_run = tests From 5a0a56b37bdfc433838131c7796c9db3ea06b7d9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 5 Dec 2023 18:29:54 -0300 Subject: [PATCH 211/309] Update version to 2.84.0 --- siriuspy/siriuspy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/VERSION b/siriuspy/siriuspy/VERSION index 3478b1da0..b52112ac5 100644 --- a/siriuspy/siriuspy/VERSION +++ b/siriuspy/siriuspy/VERSION @@ -1 +1 @@ -2.83.1 +2.84.0 From 39de79cc761870fe49c75464c1a6e831825c0d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Wed, 6 Dec 2023 08:09:12 -0300 Subject: [PATCH 212/309] orbintlk.FIX: fix typo in warning message. --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c9ca88539..730a3f866 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1392,7 +1392,7 @@ def _do_callback_bpm_intlk(self): # verify if RF EVE counted the event PsMtm new_evtcnt = self._everf_dev[self._llrf_evtcnt_pvname] if new_evtcnt == self._everf_evtcnt: - self._update_log('WARN:RF EVE did counted event PsMtm') + self._update_log('WARN:RF EVE did not count event PsMtm') self._everf_evtcnt = new_evtcnt # wait minimum period for BPM to update interlock PVs _time.sleep(2) From 0258f7d3ea9a27292215773c6abac3187202efdd Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 6 Dec 2023 09:29:35 -0300 Subject: [PATCH 213/309] Update IDSearch and ID devices --- siriuspy/siriuspy/devices/ids.py | 6 ++++++ siriuspy/siriuspy/search/id_search.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index ee7fe1e9f..0cad34938 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -29,6 +29,8 @@ class _PARAM_PVS: PPARAM_VELO_SP = None PPARAM_VELO_RB = None PPARAM_VELO_MON = None + PPARAM_ACC_SP = None + PPARAM_ACC_RB = None PPARAM_TOL_SP = None PPARAM_TOL_RB = None PPARAM_CHANGE_CMD = None @@ -43,6 +45,8 @@ class _PARAM_PVS: KPARAM_VELO_SP = None KPARAM_VELO_RB = None KPARAM_VELO_MON = None + KPARAM_ACC_SP = None + KPARAM_ACC_RB = None KPARAM_TOL_SP = None KPARAM_TOL_RB = None KPARAM_CHANGE_CMD = None @@ -1149,6 +1153,8 @@ class DEVICES: PARAM_PVS.PPARAM_MAXVELO_RB = 'MaxVelo-RB' PARAM_PVS.PPARAM_VELO_SP = 'PParamVelo-SP' PARAM_PVS.PPARAM_VELO_RB = 'PParamVelo-RB' + PARAM_PVS.PPARAM_ACC_SP = 'PParamAcc-SP' + PARAM_PVS.PPARAM_ACC_RB = 'PParamAcc-RB' PARAM_PVS.PPARAM_TOL_SP = 'PolTol-SP' PARAM_PVS.PPARAM_TOL_RB = 'PolTol-RB' PARAM_PVS.PPARAM_CHANGE_CMD = 'PParamChange-Cmd' diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index e2ed17e1a..9dd00df9e 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -306,6 +306,8 @@ def conv_idname_2_polarization_state(idname, pparameter, kparameter): # check if polarization is defined for pol_idx, pol in pols_sts.items(): _, pol_phase = pol + if pol_phase is None: # ignore none and undef configs + continue if abs(pparameter - pol_phase) <= params.PPARAM_TOL: return pol_idx From a2f1f70fdb3bdfeb4628dec250d7b0f0c411d31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Wed, 6 Dec 2023 09:57:22 -0300 Subject: [PATCH 214/309] orbintlk.MNT: de-duplicate FATAL log messages. It was necessary to add a default argument to _handle_reliability_failure so it could handle the BPM interlock event without printing a misleading message. --- siriuspy/siriuspy/orbintlk/main.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c9ca88539..dae25b040 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1338,7 +1338,6 @@ def _do_callback_rxlock(self, pvname, value): if not is_failure: return - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() def _conn_callback_timing(self, pvname, conn, **kws): @@ -1350,7 +1349,6 @@ def _conn_callback_timing(self, pvname, conn, **kws): flag = 'FATAL' if is_failure else 'WARN' self._update_log(f'{flag}:{devname} disconnected') if is_failure: - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() def _callback_bpm_intlk(self, pvname, value, **kws): @@ -1386,7 +1384,7 @@ def _log_bpm_intlk(self, bpmname): def _do_callback_bpm_intlk(self): # send kill beam as fast as possible - self._handle_reliability_failure() + self._handle_reliability_failure(is_failure=False) # wait minimum period for RF EVE event count to be updated _time.sleep(.1) # verify if RF EVE counted the event PsMtm @@ -1428,7 +1426,6 @@ def _callback_bpm_adclock(self, pvname, value, **kws): flag = 'FATAL' if is_failure else 'WARN' self._update_log(f'{flag}:{devname} lost PLL lock') if is_failure: - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() def _conn_callback_afcphystrigs(self, pvname, conn, **kws): @@ -1440,7 +1437,6 @@ def _conn_callback_afcphystrigs(self, pvname, conn, **kws): flag = 'ERR' if is_failure else 'WARN' self._update_log(f'{flag}:{devname} disconnected') if is_failure: - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() def _callback_hltrig_status(self, pvname, value, **kws): @@ -1450,7 +1446,6 @@ def _callback_hltrig_status(self, pvname, value, **kws): # if status is not ok, it is a reliability failure trigname = _PVName(pvname).device_name self._update_log(f'FATAL:{trigname} Status not ok') - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() # --- reliability failure methods --- @@ -1461,7 +1456,9 @@ def _check_minsum_requirement(self, monit_sum=None): facq_sum = monit_sum * self._get_bpm_rates_factor() return _np.all(facq_sum > self._limits['minsum']) - def _handle_reliability_failure(self): + def _handle_reliability_failure(self, is_failure=True): + if is_failure: + self._update_log('FATAL:Orbit interlock reliability failure') if not self._state: self._update_log('WARN:Orbit interlock is not enabled.') return @@ -1588,7 +1585,6 @@ def _do_lock(self, device, propty_sp, desired_value, pvname, value): if thread.cur_iter == thread.niters-1: self._lock_failures.add(pvname) self._update_log(f'FATAL:Fail to lock {pvname}') - self._update_log('FATAL:Orbit interlock reliability failure') self._handle_reliability_failure() # --- auxiliary log methods --- From 7398eaea0226b6ae7eee5c22083de1de39e7c7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Wed, 6 Dec 2023 10:05:06 -0300 Subject: [PATCH 215/309] orbintlk.ENH: control all timing RTM PLL parameters. Setting the PhaseNavg or PhaseDiv parameters to anything other than 0 can compromise the loop stability, so care should be taken to enforce this value. --- siriuspy/siriuspy/orbintlk/csdev.py | 2 ++ siriuspy/siriuspy/orbintlk/main.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 343dbdbac..b6420c4da 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -100,6 +100,8 @@ class Const(_csdev.Const): ('RTMPhaseIntgGain-SP', 1), ('RTMFreqPropGain-SP', 1), ('RTMFreqIntgGain-SP', 128), + ('RTMPhaseNavg-SP', 0), + ('RTMPhaseDiv-SP', 0), ) AFCPHYTRIG_CONFIGS = ( ('Dir-Sel', 0), diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c9ca88539..91e39963c 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -136,6 +136,8 @@ def __init__(self, tests=True): 'RTMPhaseIntgGain-SP', 'RTMPhaseIntgGain-RB', 'RTMFreqPropGain-SP', 'RTMFreqPropGain-RB', 'RTMFreqIntgGain-SP', 'RTMFreqIntgGain-RB', + 'RTMPhaseNavg-SP', 'RTMPhaseNavg-RB', + 'RTMPhaseDiv-SP', 'RTMPhaseDiv-RB', ], auto_monitor_mon=True) for idx in range(20) } From 119d2e4290119ca688e7b56cf0a8d1a25e5fb2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Wed, 6 Dec 2023 11:54:43 -0300 Subject: [PATCH 216/309] orbintlk.MNT: don't hardcode ItlkR event. --- siriuspy/siriuspy/orbintlk/csdev.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 343dbdbac..e63eece23 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -157,6 +157,7 @@ def EVG_CONFIGS(cls): hlevts = _HLTimeSearch.get_hl_events() evtin0 = int(hlevts['Intlk'].strip('Evt')) + evtin1 = int(hlevts['ItlkR'].strip('Evt')) evtin2 = int(hlevts['DCT13'].strip('Evt')) evtin3 = int(hlevts['DCT14'].strip('Evt')) evtout = int(hlevts['RFKll'].strip('Evt')) @@ -166,7 +167,7 @@ def EVG_CONFIGS(cls): ('IntlkCtrlRepeat-Sel', 0), ('IntlkCtrlRepeatTime-SP', 0), ('IntlkEvtIn0-SP', evtin0), - ('IntlkEvtIn1-SP', 118), + ('IntlkEvtIn1-SP', evtin1), ('IntlkEvtIn2-SP', evtin2), ('IntlkEvtIn3-SP', evtin3), ('IntlkEvtOut-SP', evtout), From 9f4a2932635848f9f6831114110fd3667f3ccfb7 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 6 Dec 2023 13:57:53 -0300 Subject: [PATCH 217/309] Implement Acceleration methods in ID devices --- siriuspy/siriuspy/devices/ids.py | 106 ++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 0cad34938..c50294c4e 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -24,6 +24,8 @@ class _PARAM_PVS: PPARAM_RB = None PPARAM_MON = None PPARAM_PARKED_CTE = None + PPARAM_MAXACC_SP = None + PPARAM_MAXACC_RB = None PPARAM_MAXVELO_SP = None PPARAM_MAXVELO_RB = None PPARAM_VELO_SP = None @@ -40,6 +42,8 @@ class _PARAM_PVS: KPARAM_RB = None KPARAM_MON = None KPARAM_PARKED_CTE = None + KPARAM_MAXACC_SP = None + KPARAM_MAXACC_RB = None KPARAM_MAXVELO_SP = None KPARAM_MAXVELO_RB = None KPARAM_VELO_SP = None @@ -196,6 +200,40 @@ def pparameter_speed(self): else: return self[self.PARAM_PVS.PPARAM_VELO_SP] + @property + def pparameter_speed_mon(self): + """Return pparameter speed monitor [mm/s].""" + if self.PARAM_PVS.PPARAM_VELO_MON is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_VELO_MON] + + @property + def pparameter_accel_max(self): + """Return maximum pparameter acceleration [mm/s²].""" + if self.PARAM_PVS.PPARAM_MAXACC_RB is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_MAXACC_RB] + + @property + def pparameter_accel_max_lims(self): + """Return max pparameter accel limits.""" + if self.PARAM_PVS.PPARAM_MAXACC_RB is None: + return None + else: + ctrl = self.pv_ctrlvars(self.PARAM_PVS.PPARAM_MAXACC_SP) + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def pparameter_accel(self): + """Return pparameter acceleration [mm/s²].""" + if self.PARAM_PVS.PPARAM_ACC_RB is None: + return None + else: + return self[self.PARAM_PVS.PPARAM_ACC_RB] + @property def pparameter_lims(self): """Return ID pparameter lower control limit [mm].""" @@ -244,6 +282,22 @@ def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): return self._write_sp( self.PARAM_PVS.PPARAM_MAXVELO_SP, pparam_speed_max, timeout) + def pparameter_accel_set(self, pparam_accel, timeout=None): + """Command to set ID pparam accel for movement [mm/s²].""" + if self.PARAM_PVS.PPARAM_ACC_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.PPARAM_ACC_SP, pparam_accel, timeout) + + def pparameter_accel_max_set(self, pparam_accel_max, timeout=None): + """Command to set ID max cruise pparam accel for movement [mm/s²].""" + if self.PARAM_PVS.PPARAM_MAXACC_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.PPARAM_MAXACC_SP, pparam_accel_max, timeout) + # --- kparameter --- @property @@ -282,10 +336,36 @@ def kparameter_speed(self): @property def kparameter_speed_mon(self): """Return kparameter speed monitor [mm/s].""" - if self.PARAM_PVS.KPARAM_VELO_MON in self.properties_all: + if self.PARAM_PVS.KPARAM_VELO_MON is None: + return None + else: return self[self.PARAM_PVS.KPARAM_VELO_MON] + + @property + def kparameter_accel_max(self): + """Return maximum kparameter acceleration [mm/s²].""" + if self.PARAM_PVS.KPARAM_MAXACC_RB is None: + return None + else: + return self[self.PARAM_PVS.KPARAM_MAXACC_RB] + + @property + def kparameter_accel_max_lims(self): + """Return max kparameter accel limits.""" + if self.PARAM_PVS.KPARAM_MAXACC_RB is None: + return None + else: + ctrl = self.pv_ctrlvars(self.PARAM_PVS.KPARAM_MAXACC_SP) + lims = [ctrl['lower_ctrl_limit'], ctrl['upper_ctrl_limit']] + return lims + + @property + def kparameter_accel(self): + """Return kparameter acceleration [mm/s²].""" + if self.PARAM_PVS.KPARAM_ACC_RB is None: + return None else: - raise TypeError('ID does not have speed_mon PV!') + return self[self.PARAM_PVS.KPARAM_ACC_RB] @property def kparameter_lims(self): @@ -317,6 +397,22 @@ def kparameter_speed_max_set(self, kparam_speed_max, timeout=None): return self._write_sp( self.PARAM_PVS.KPARAM_MAXVELO_SP, kparam_speed_max, timeout) + def kparameter_accel_set(self, kparam_accel, timeout=None): + """Command to set ID kparam accel for movement [mm/s²].""" + if self.PARAM_PVS.KPARAM_ACC_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.KPARAM_ACC_SP, kparam_accel, timeout) + + def kparameter_accel_max_set(self, kparam_accel_max, timeout=None): + """Command to set ID max cruise kparam accel for movement [mm/s²].""" + if self.PARAM_PVS.KPARAM_MAXACC_SP is None: + return True + else: + return self._write_sp( + self.PARAM_PVS.KPARAM_MAXACC_SP, kparam_accel_max, timeout) + # --- checks --- @property @@ -1149,6 +1245,8 @@ class DEVICES: PARAM_PVS.PPARAM_RB = 'PParam-RB' PARAM_PVS.PPARAM_MON = 'PParam-Mon' PARAM_PVS.PPARAM_PARKED_CTE = 'PParamParked-Cte' + PARAM_PVS.PPARAM_MAXACC_SP = 'MaxAcc-SP' + PARAM_PVS.PPARAM_MAXACC_RB = 'MaxAcc-RB' PARAM_PVS.PPARAM_MAXVELO_SP = 'MaxVelo-SP' PARAM_PVS.PPARAM_MAXVELO_RB = 'MaxVelo-RB' PARAM_PVS.PPARAM_VELO_SP = 'PParamVelo-SP' @@ -1162,10 +1260,14 @@ class DEVICES: PARAM_PVS.KPARAM_RB = 'KParam-RB' PARAM_PVS.KPARAM_MON = 'KParam-Mon' PARAM_PVS.KPARAM_PARKED_CTE = 'KParamParked-Cte' + PARAM_PVS.KPARAM_MAXACC_SP = 'MaxAcc-SP' + PARAM_PVS.KPARAM_MAXACC_RB = 'MaxAcc-RB' PARAM_PVS.KPARAM_MAXVELO_SP = 'MaxVelo-SP' PARAM_PVS.KPARAM_MAXVELO_RB = 'MaxVelo-RB' PARAM_PVS.KPARAM_VELO_SP = 'KParamVelo-SP' PARAM_PVS.KPARAM_VELO_RB = 'KParamVelo-RB' + PARAM_PVS.KPARAM_ACC_SP = 'KParamAcc-SP' + PARAM_PVS.KPARAM_ACC_RB = 'KParamAcc-RB' PARAM_PVS.KPARAM_TOL_SP = 'PosTol-SP' PARAM_PVS.KPARAM_TOL_RB = 'PosTol-RB' PARAM_PVS.KPARAM_CHANGE_CMD = 'KParamChange-Cmd' From b02743550f2d091b2c778c463276727b168448bc Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 6 Dec 2023 20:20:04 -0300 Subject: [PATCH 218/309] Refactor movement ETA calculation in ID devices --- siriuspy/siriuspy/devices/ids.py | 114 ++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index c50294c4e..161fd4d1d 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -2,6 +2,7 @@ import time as _time import inspect as _inspect +import numpy as _np from ..search import IDSearch as _IDSearch @@ -259,6 +260,13 @@ def pparameter_mon(self): else: return self[self.PARAM_PVS.PPARAM_MON] + @property + def pparameter_move_eta(self): + """Return estimated moving time to reach pparameter RB position.""" + # NOTE: the IOC may provide this as PV in the future + pparam_eta, _ = self.calc_move_eta(self.pparameter, None) + return pparam_eta + def pparameter_set(self, pparam, timeout=None): """Set ID target pparameter for movement [mm].""" if self.PARAM_PVS.PPARAM_SP is None: @@ -383,6 +391,13 @@ def kparameter_mon(self): """Return ID kparameter monitor [mm].""" return self[self.PARAM_PVS.KPARAM_MON] + @property + def kparameter_move_eta(self): + """Return estimated moving time to reach kparameter RB position.""" + # NOTE: the IOC may provide this as PV in the future + _, kparam_eta = self.calc_move_eta(None, self.kparameter) + return kparam_eta + def kparameter_set(self, kparam, timeout=None): """Set ID target kparameter for movement [mm].""" return self._write_sp(self.PARAM_PVS.KPARAM_SP, kparam, timeout) @@ -534,13 +549,19 @@ def cmd_change_polarization_start(self, timeout=None): def cmd_move_park(self, timeout=None): """Move ID to parked config.""" pparam, kparam = self.pparameter_parked, self.kparameter_parked - timeout = self._calc_eta(pparam, kparam) if timeout is None \ - else timeout - if self.PARAM_PVS.START_PARKING_CMD is not None: + if self.PARAM_PVS.START_PARKING_CMD is None: + # composed pparam and kparam movement by this class + return self.cmd_move(pparam, kparam, timeout) + else: + # composed pparam and kparam movement by IOC + # first set param RBs for ETA computation and PVs consistency + if not self.pparameter_set(pparam): + return False + if not self.kparameter_set(kparam): + return False + timeout = self.calc_move_timeout(None, None, timeout) self[self.PARAM_PVS.START_PARKING_CMD] = 1 return self.wait_move_config(pparam, kparam, timeout) - else: - return self.cmd_move(pparam, kparam, timeout) def cmd_move_pparameter(self, pparam=None, timeout=None): """Command to set and start pparam movement.""" @@ -553,7 +574,13 @@ def cmd_move_kparameter(self, kparam=None, timeout=None): return self.cmd_move(None, kparam, timeout) def cmd_move(self, pparam=None, kparam=None, timeout=None): - """Command to set and start pparam and kparam movements.""" + """Command to set and start pparam and kparam movements. + + Args + pparam : target pparameter value + kparam : target kparameter value + timeout : additional timeout beyond movement ETA. [s] + """ if self.PARAM_PVS.PPARAM_SP is None: pparam = None @@ -581,11 +608,10 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): if timeout is not None: timeout = max(timeout - (t1_ - t0_), 0) - # calc ETA - eta = self._calc_eta(pparam, kparam) - timeout = eta if timeout is None else timeout + # calc timeout + timeout = self._calc_move_timeout(None, None, timeout) - # wait for movement within reasonable time + # wait for movement within timeout based on movement ETA return self.wait_move_config(pparam, kparam, timeout) def cmd_change_polarization(self, polarization, timeout=None): @@ -614,6 +640,46 @@ def cmd_change_polarization(self, polarization, timeout=None): return self._wait( self.PARAM_PVS.POL_MON, polarization, timeout=timeout, comp='eq') + def calc_move_eta(self, pparam_goal=None, kparam_goal=None): + """Estimate moving time for each parameter separately.""" + # pparameter + param_goal, param_val = pparam_goal, self.pparameter_mon + param_tol = self.pparameter_tol + param_vel, param_acc = self.pparameter_speed, self.pparameter_accel + if None not in (param_goal, param_val): + dparam = abs(param_goal - param_val) + dparam = 0 if dparam < param_tol else dparam + pparam_eta = _ID._calc_move_eta_model(dparam, param_vel, param_acc) + else: + pparam_eta = 0.0 + + # kparameter + param_goal, param_val = kparam_goal, self.kparameter_mon + param_tol = self.kparameter_tol + param_vel, param_acc = self.kparameter_speed, self.kparameter_accel + if None not in (param_goal, param_val): + dparam = abs(abs(param_goal) - abs(param_val)) # abs for DELTA + dparam = 0 if dparam < param_tol else dparam + kparam_eta = _ID._calc_move_eta_model(dparam, param_vel, param_acc) + else: + kparam_eta = 0.0 + + return pparam_eta, kparam_eta + + def calc_move_eta_composed(self, pparam_eta, kparam_eta): + # model: here pparam and kparam as serial in time + eta = pparam_eta + kparam_eta + return eta + + def calc_move_timeout( + self, pparam_goal=None, kparam_goal=None, timeout=None): + # calc timeout + pparam_eta, kparam_eta = self.calc_move_eta(pparam_goal, kparam_goal) + eta = self.calc_move_eta_composed(pparam_eta, kparam_eta) + eta = 1.1 * eta + 0.5 # add safety margins + timeout = eta if timeout is None else eta + timeout + return timeout + # --- private methods --- def _move_start(self, cmd_propty, timeout=None, cmd_value=1): @@ -661,21 +727,21 @@ def _wait_propty(self, propty, value, timeout=None): return False return True - def _calc_eta(self, pparam, kparam): - """.""" - # calc ETA - dtime_kparam = 0 if kparam is None else \ - abs(kparam - self.kparameter_mon) / self.kparameter_speed - dtime_pparam = 0 if pparam is None else \ - abs(pparam - self.pparameter_mon) / self.pparameter_speed - dtime_max = self._calc_eta_select_time(dtime_kparam, dtime_pparam) - # additional percentual in ETA - eta = 1.5 * dtime_max + 5 - return eta - @staticmethod - def _calc_eta_select_time(dtime_kparam, dtime_pparam): - return dtime_kparam + dtime_pparam + def _calc_move_eta_model(dparam, param_vel, param_acc=None): + """Moving time model.""" + # constant acceleration model: + # linear ramp up + cruise velocity + linear ramp down + # assume param_acc = 1 mm/s² if no acceleration is provided + param_acc = 1 if param_acc is None else param_acc + maxvel_ramp = _np.sqrt(param_acc * dparam) + maxvel_ramp = min(maxvel_ramp, param_vel) + dtime_ramp = 2 * maxvel_ramp / param_acc + dparam_ramp = maxvel_ramp**2 / param_acc + dparam_plateau = dparam - dparam_ramp + dtime_plateau = dparam_plateau / param_vel + dtime_total = dtime_ramp + dtime_plateau + return dtime_total class APU(_ID): From 7d2d5e22b8619f0204d00bf104894b92a0e52235 Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Thu, 7 Dec 2023 16:46:55 -0300 Subject: [PATCH 219/309] Alarms and offset of SSA towers 1 and 2 temporarly removed and added calibration coefficient for SSA towers 3 and 4 --- .../siriuspy/clientconfigdb/types/as_rf.py | 125 ++++++++++++------ 1 file changed, 81 insertions(+), 44 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index 51a578752..a3482f3de 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -452,50 +452,87 @@ def get_dict(): _pvs_si_rfssa = [ - ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr1 - ['RA-ToSIA01:OffsetConfig:UpperReflectedPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:LowerIncidentPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:LowerReflectedPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:InputIncidentPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:InputReflectedPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:OutputIncidentPower', 0, 0.0], - ['RA-ToSIA01:OffsetConfig:OutputReflectedPower', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr - # SSA tower 1 - ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLow', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:InnerPowerLimHigh', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:InnerPowerLimLow', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents - # SSA tower 1 - ['RA-ToSIA01:AlarmConfig:CurrentLimHigh', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:CurrentLimLow', 0, 0.0], - ['RA-ToSIA01:AlarmConfig:CurrentLimLoLo', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr2 - ['RA-ToSIA02:OffsetConfig:UpperReflectedPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:LowerIncidentPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:LowerReflectedPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:InputIncidentPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:InputReflectedPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:OutputIncidentPower', 0, 0.0], - ['RA-ToSIA02:OffsetConfig:OutputReflectedPower', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr - # SSA tower 2 - ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLow', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:InnerPowerLimHigh', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:InnerPowerLimLow', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents - # SSA tower 2 - ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], - ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # NOTE: Alarms and offset of SSA towers 1 & 2 temporaly removed + # ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr1 + # ['RA-ToSIA01:OffsetConfig:UpperReflectedPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:LowerIncidentPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:LowerReflectedPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:InputIncidentPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:InputReflectedPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:OutputIncidentPower', 0, 0.0], + # ['RA-ToSIA01:OffsetConfig:OutputReflectedPower', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 1 + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLow', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLow', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 1 + # ['RA-ToSIA01:AlarmConfig:CurrentLimHigh', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:CurrentLimLow', 0, 0.0], + # ['RA-ToSIA01:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr2 + # ['RA-ToSIA02:OffsetConfig:UpperReflectedPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:LowerIncidentPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:LowerReflectedPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:InputIncidentPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:InputReflectedPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:OutputIncidentPower', 0, 0.0], + # ['RA-ToSIA02:OffsetConfig:OutputReflectedPower', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 2 + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLow', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLow', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 2 + # ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], + # ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr3 + # ['RA-ToSIA03:OffsetConfig:UpperReflectedPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:LowerIncidentPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:LowerReflectedPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:InputIncidentPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:InputReflectedPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:OutputIncidentPower', 0, 0.0], + # ['RA-ToSIA03:OffsetConfig:OutputReflectedPower', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 3 + # ['RA-ToSIA03:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:InnerPowerLimLow', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 3 + # ['RA-ToSIA03:AlarmConfig:CurrentLimHigh', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:CurrentLimLow', 0, 0.0], + # ['RA-ToSIA03:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr4 + # ['RA-ToSIA04:OffsetConfig:UpperReflectedPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:LowerIncidentPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:LowerReflectedPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:InputIncidentPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:InputReflectedPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:OutputIncidentPower', 0, 0.0], + # ['RA-ToSIA04:OffsetConfig:OutputReflectedPower', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 4 + # ['RA-ToSIA04:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:InnerPowerLimLow', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 4 + # ['RA-ToSIA04:AlarmConfig:CurrentLimHigh', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:CurrentLimLow', 0, 0.0], + # ['RA-ToSIA04:AlarmConfig:CurrentLimLoLo', 0, 0.0], + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 In Pwr Fwd Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 In Pwr Rev Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 Out Pwr Fwd Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 Out Pwr Rev Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 In Pwr Fwd Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 In Pwr Rev Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 Out Pwr Fwd Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 Out Pwr Rev Cal Coeff ] From e65824d8dccb7d6392ff2d088ea1ffb2c9518fbf Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 7 Dec 2023 17:28:13 -0300 Subject: [PATCH 220/309] orbintlk.FIX: send LLRF reset after manual interlock when in dry run --- siriuspy/siriuspy/orbintlk/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 730a3f866..157f2e0d5 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -233,7 +233,7 @@ def __init__(self, tests=True): devname=_ASLLRF.DEVICES.SI, props2init=[ 'ILK:BEAM:TRIP:S', 'ILK:BEAM:TRIP', 'FASTINLK-MON', - 'ILK:MAN:S', 'ILK:MAN', 'IntlkSet-Cmd', + 'ILK:MAN:S', 'ILK:MAN', 'IntlkSet-Cmd', 'Reset-Cmd', ]) self._llrf.pv_object('FASTINLK-MON').auto_monitor = True @@ -1470,6 +1470,11 @@ def _handle_reliability_failure(self): self._llrf['IntlkSet-Cmd'] = 1 _time.sleep(1) self._llrf['IntlkSet-Cmd'] = 0 + if self._is_dry_run: + _time.sleep(1) + self._llrf['Reset-Cmd'] = 1 + _time.sleep(1) + self._llrf['Reset-Cmd'] = 0 # --- device lock methods --- @@ -1537,7 +1542,7 @@ def _start_lock_thread( self, device, propty_sp, desired_value, pvname, value): if self._lock_suspend: return - + # do not try to lock devices that are not in list of monitored devices devname = _PVName(pvname).device_name if devname not in self._ti_mon_devs and \ From 060664b724dd2e60c5a2fca1e29179fe1f5c0f7a Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Thu, 7 Dec 2023 17:39:09 -0300 Subject: [PATCH 221/309] orbintlk.MNT: increase wait time before rearming FDL acquisition --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 157f2e0d5..aedbfd685 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1471,7 +1471,8 @@ def _handle_reliability_failure(self): _time.sleep(1) self._llrf['IntlkSet-Cmd'] = 0 if self._is_dry_run: - _time.sleep(1) + # wait a little and rearming FDL acquisition + _time.sleep(self._const.DEF_TIME2WAIT_INTLKREARM) self._llrf['Reset-Cmd'] = 1 _time.sleep(1) self._llrf['Reset-Cmd'] = 0 From 1578617de40a81226b6f3479bb784ae94237c32d Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 7 Dec 2023 20:19:25 -0300 Subject: [PATCH 222/309] Fix method in device DELTA --- siriuspy/siriuspy/devices/ids.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 161fd4d1d..d2e2e753a 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1042,10 +1042,6 @@ def cmd_move_phase_start(self, timeout=None): """Command to start phase movement.""" return self.cmd_move_kparameter_start(timeout=timeout) - # def cmd_move_park(self, timeout=None): - # """Command to set and start ID movement to parked config.""" - # return super().cmd_move_park(timeout) - # --- cmd_reset def cmd_device_reset(self, timeout=None): @@ -1279,18 +1275,17 @@ def cmd_move_gap_start(self, timeout=None): """Command to start gap movement.""" return self.cmd_move_kparameter_start(timeout) + def calc_move_eta_composed(self, pparam_eta, kparam_eta): + # model: here pparam and kparam as parallel in time + eta = max(pparam_eta, kparam_eta) + return eta + # --- other cmds --- def cmd_clear_error(self): """Command to clear errors.""" pass - # --- private methods --- - - @staticmethod - def _calc_eta_select_time(dtime_kparam, dtime_pparam): - return max(dtime_kparam, dtime_pparam) - class DELTA(_ID): """DELTA Insertion Device.""" @@ -1422,11 +1417,12 @@ def pos_cid_mon(self): """ return self['CIDVirtPos-Mon'] - def _calc_eta(self, pparam, kparam): - """.""" - if kparam is not None and self.polarization_mon_str == 'circularp': - kparam = -kparam - return super()._calc_eta(pparam, kparam) + def calc_move_eta(self, pparam_goal=None, kparam_goal=None): + """Estimate moving time for each parameter separately.""" + pol_mon_str = self.polarization_mon_str + if kparam_goal is not None and pol_mon_str == 'circularp': + kparam_goal = -kparam_goal + return super().calc_move_eta(pparam_goal, kparam_goal) class WIG(_ID): From 208f49bbb06f5a0486b3220992c3dfd4e75cf11c Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 8 Dec 2023 17:08:19 -0300 Subject: [PATCH 223/309] Add IDFactory, normalizer methid in PwrSupply device --- siriuspy/siriuspy/devices/__init__.py | 4 +- siriuspy/siriuspy/devices/idff.py | 97 +++++--------------------- siriuspy/siriuspy/devices/ids.py | 27 +++++++ siriuspy/siriuspy/devices/pwrsupply.py | 12 ++++ siriuspy/siriuspy/idff/config.py | 14 ++-- siriuspy/siriuspy/search/id_search.py | 2 + 6 files changed, 69 insertions(+), 87 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index f4bc24cb3..373f0be08 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -16,8 +16,8 @@ from .fofb_acq import FOFBCtrlSysId, FOFBPSSysId, FamFOFBSysId, \ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff -from .ids import APU, WIG, PAPU, EPU, DELTA -from .idff import IDFF, WIGIDFF, PAPUIDFF, EPUIDFF, APUIDFF, DELTAIDFF +from .ids import APU, WIG, PAPU, EPU, DELTA, IDFactory +from .idff import IDFF from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ BORFRampStandbyHandler, InjSysStandbyHandler, LinacStandbyHandler, \ diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index dda9a0b72..7426574d7 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -6,20 +6,15 @@ from .device import Device as _Device, DeviceSet as _DeviceSet from .pwrsupply import PowerSupplyFBP as _PowerSupplyFBP -from .ids import WIG as _WIG, APU as _APU, PAPU as _PAPU, EPU as _EPU -from .ids import DELTA as _DELTA +from .ids import IDFactory as _IDFactory class IDFF(_DeviceSet): """Insertion Device Feedforward Device.""" - class DEVICES(_WIG.DEVICES, _PAPU.DEVICES, _EPU.DEVICES, _DELTA.DEVICES): + class DEVICES(_IDFactory.DEVICES): """.""" - ALL = \ - _WIG.DEVICES.ALL + _PAPU.DEVICES.ALL + \ - _EPU.DEVICES.ALL + _DELTA.DEVICES.ALL - def __init__(self, devname): """.""" devname = _SiriusPVName(devname) @@ -61,6 +56,11 @@ def qsnames(self): """Return QS corrector power supply names.""" return _IDSearch.conv_idname_2_idff_qsnames(self.devname) + @property + def iddev(self): + """Return ID device.""" + return self._devid + @property def chdevs(self): """Return CH corrector power supply devices.""" @@ -91,6 +91,11 @@ def polarizations(self): """Return list of possible light polarizations for the ID.""" return _IDSearch.conv_idname_2_polarizations(self.devname) + @property + def polarization_mon(self): + """Return current ID polarization as a string (or None).""" + return self.iddev.polarization_str + @property def pparameter_mon(self): """Return pparameter value.""" @@ -233,13 +238,15 @@ def get_polarization_state( kparameter_value = self.kparameter_mon if None in (pparameter_value, kparameter_value): return None, pparameter_value, kparameter_value - polarization = self.idffconfig.get_polarization_state( - pparameter=pparameter_value, kparameter=kparameter_value) + polarization = self.polarization_mon + if polarization is None: + polarization = self.idffconfig.get_polarization_state( + pparameter=pparameter_value, kparameter=kparameter_value) return polarization, pparameter_value, kparameter_value def _create_devices(self, devname): param_auto_mon = False - devid = _Device( + devid = _IDFactory.create( devname=devname, props2init=(self._pparametername, self._kparametername), auto_monitor_mon=param_auto_mon) @@ -247,73 +254,3 @@ def _create_devices(self, devname): devscv = [_PowerSupplyFBP(devname=dev) for dev in self.cvnames] devsqs = [_PowerSupplyFBP(devname=dev) for dev in self.qsnames] return devid, devsch, devscv, devsqs - - -class WIGIDFF(IDFF): - """Wiggler Feedforward.""" - - class DEVICES(_WIG.DEVICES): - """.""" - - @property - def gap_mon(self): - """.""" - return self.kparameter_mon - - -class PAPUIDFF(IDFF): - """PAPU Feedforward.""" - - class DEVICES(_PAPU.DEVICES): - """.""" - - @property - def phase_mon(self): - """.""" - return self.pparameter_mon - - -class EPUIDFF(IDFF): - """EPU Feedforward.""" - - class DEVICES(_EPU.DEVICES): - """.""" - - @property - def phase_mon(self): - """.""" - return self.pparameter_mon - - @property - def gap_mon(self): - """.""" - return self.kparameter_mon - - -class DELTAIDFF(IDFF): - """DELTA Feedforward.""" - - class DEVICES(_DELTA.DEVICES): - """.""" - - @property - def polarization_phase_mon(self): - """.""" - return self.pparameter_mon - - @property - def dGV_phase_mon(self): - """.""" - return self.kparameter_mon - - -class APUIDFF(_DeviceSet): - """APU Feedforward.""" - - class DEVICES(_APU.DEVICES): - """.""" - - @property - def phase_mon(self): - """.""" - return self.kparameter_mon diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index ee7fe1e9f..9d11d9b7b 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1278,3 +1278,30 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): # call base class constructor super().__init__( devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) + + +class IDFactory(): + """.""" + + class DEVICES( + APU.DEVICES, PAPU.DEVICES, EPU.DEVICES, DELTA.DEVICES, WIG.DEVICES): + """Device names.""" + + ALL = APU.DEVICES.ALL + PAPU.DEVICES.ALL + \ + EPU.DEVICES.ALL + DELTA.DEVICES.ALL + WIG.DEVICES.ALL + + @staticmethod + def create(devname, **kwargs): + """.""" + if devname in APU.DEVICES.ALL: + return APU(devname, **kwargs) + elif devname in PAPU.DEVICES.ALL: + return PAPU(devname, **kwargs) + elif devname in EPU.DEVICES.ALL: + return EPU(devname, **kwargs) + elif devname in DELTA.DEVICES.ALL: + return DELTA(devname, **kwargs) + elif devname in WIG.DEVICES.ALL: + return WIG(devname, **kwargs) + else: + raise NotImplementedError(devname) diff --git a/siriuspy/siriuspy/devices/pwrsupply.py b/siriuspy/siriuspy/devices/pwrsupply.py index de856bfd7..b16291637 100644 --- a/siriuspy/siriuspy/devices/pwrsupply.py +++ b/siriuspy/siriuspy/devices/pwrsupply.py @@ -10,6 +10,7 @@ MAX_WFMSIZE_FBP as _MAX_WFMSIZE_FBP, \ MAX_WFMSIZE_OTHERS as _MAX_WFMSIZE_OTHERS from ..pwrsupply.psctrl.pscstatus import PSCStatus as _PSCStatus +from ..magnet.factory import NormalizerFactory as _NormFactory from .device import Device as _Device from .timing import Trigger as _Trigger @@ -106,6 +107,12 @@ def __init__(self, devname, auto_monitor_mon=False, props2init='all'): # private attribute with strength setpoint pv object self._strength_sp_pv = self.pv_object(self._strength_sp_propty) + try: + maname = devname.substitute(dis='MA') + self._normalizer = _NormFactory.create(maname) + except: + self._normalizer = None + @property def pstype(self): """Return type of magnet(s) excited by power supply device.""" @@ -141,6 +148,11 @@ def is_magps(self): """Return True if device is a Sirius magnet power supply.""" return self._is_pulsed + @property + def normalizer(self): + """Return Normalizer object for current and strength conversions.""" + return self._normalizer + @property def strength_property(self): """Return Strength name.""" diff --git a/siriuspy/siriuspy/idff/config.py b/siriuspy/siriuspy/idff/config.py index 2a9662bc7..d618ca3cd 100644 --- a/siriuspy/siriuspy/idff/config.py +++ b/siriuspy/siriuspy/idff/config.py @@ -130,15 +130,18 @@ def create_template_config(idname): ptable['pparameter'] = [0, 0] ptable['kparameter'] = 0 ktable = dict(ctable) - ktable['pparameter'] = 0 ktable['kparameter'] = [0, 0] + pol2pparam = _IDSearch.conv_idname_2_polarization_pparameter polarizations = dict() - for polarization in idff['polarizations']: - if polarization == _IDSearch.POL_NONE_STR: - polarizations[polarization] = dict(ptable) + for pol in idff['polarizations']: + if pol == _IDSearch.POL_UNDEF_STR: + continue + if pol == _IDSearch.POL_NONE_STR: + polarizations[pol] = dict(ptable) else: - polarizations[polarization] = dict(ktable) + ktable['pparameter'] = pol2pparam(idname, pol) + polarizations[pol] = dict(ktable) template_config = dict( description=description, pvnames=pvnames, @@ -152,6 +155,7 @@ def __str__(self): value = self.value if value is None: return stg + stg += f'\ndescription: {value["description"]}' stg += '\n--- pvnames ---' pvnames = ''.join( diff --git a/siriuspy/siriuspy/search/id_search.py b/siriuspy/siriuspy/search/id_search.py index e2ed17e1a..9dd00df9e 100644 --- a/siriuspy/siriuspy/search/id_search.py +++ b/siriuspy/siriuspy/search/id_search.py @@ -306,6 +306,8 @@ def conv_idname_2_polarization_state(idname, pparameter, kparameter): # check if polarization is defined for pol_idx, pol in pols_sts.items(): _, pol_phase = pol + if pol_phase is None: # ignore none and undef configs + continue if abs(pparameter - pol_phase) <= params.PPARAM_TOL: return pol_idx From ec1d5086c22c44b390ebf79d3ac57e9bc6bc81e6 Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Mon, 11 Dec 2023 09:47:45 -0300 Subject: [PATCH 224/309] Changes to reduce the length up to 80 columns --- .../siriuspy/clientconfigdb/types/as_rf.py | 69 +++++++------------ 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index a3482f3de..8e35d46c3 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -1,5 +1,8 @@ """AS RF configuration.""" from copy import deepcopy as _dcopy +import numpy as _np + +az = _np.zeros(1,5) # NOTE: absolute imports are necessary here due to how # CONFIG_TYPES in __init__.py is built. @@ -453,7 +456,7 @@ def get_dict(): _pvs_si_rfssa = [ # NOTE: Alarms and offset of SSA towers 1 & 2 temporaly removed - # ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr1 + # ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr1 # ['RA-ToSIA01:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerReflectedPower', 0, 0.0], @@ -461,7 +464,8 @@ def get_dict(): # ['RA-ToSIA01:OffsetConfig:InputReflectedPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:OutputIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 1 + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr + # SSA tower 1 # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], @@ -469,11 +473,12 @@ def get_dict(): # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 1 + # ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents + # SSA tower 1 # ['RA-ToSIA01:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:CurrentLimLoLo', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr2 + # ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr2 # ['RA-ToSIA02:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerReflectedPower', 0, 0.0], @@ -481,7 +486,8 @@ def get_dict(): # ['RA-ToSIA02:OffsetConfig:InputReflectedPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:OutputIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 2 + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr + # SSA tower 2 # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], @@ -489,50 +495,21 @@ def get_dict(): # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 2 + # ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents + # SSA tower 2 # ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr3 - # ['RA-ToSIA03:OffsetConfig:UpperReflectedPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:LowerIncidentPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:LowerReflectedPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:InputIncidentPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:InputReflectedPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:OutputIncidentPower', 0, 0.0], - # ['RA-ToSIA03:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 3 - # ['RA-ToSIA03:AlarmConfig:InnerPowerLimHigh', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:InnerPowerLimLow', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 3 - # ['RA-ToSIA03:AlarmConfig:CurrentLimHigh', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:CurrentLimLow', 0, 0.0], - # ['RA-ToSIA03:AlarmConfig:CurrentLimLoLo', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr4 - # ['RA-ToSIA04:OffsetConfig:UpperReflectedPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:LowerIncidentPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:LowerReflectedPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:InputIncidentPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:InputReflectedPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:OutputIncidentPower', 0, 0.0], - # ['RA-ToSIA04:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # Alarms lims pwr SSA tower 4 - # ['RA-ToSIA04:AlarmConfig:InnerPowerLimHigh', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:InnerPowerLimLow', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents SSA tower 4 - # ['RA-ToSIA04:AlarmConfig:CurrentLimHigh', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:CurrentLimLow', 0, 0.0], - # ['RA-ToSIA04:AlarmConfig:CurrentLimLoLo', 0, 0.0], - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 In Pwr Fwd Cal Coeff - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 In Pwr Rev Cal Coeff - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 Out Pwr Fwd Cal Coeff - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA3 Out Pwr Rev Cal Coeff - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 In Pwr Fwd Cal Coeff - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 In Pwr Rev Cal Coeff - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 Out Pwr Fwd Cal Coeff - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.array([0, 0, 0, 0, 0]), 0.0], #SSA4 Out Pwr Rev Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.az, 0.0], # SSA3 Pwr + # Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.az, 0.0], #SSA4 Pwr + #Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.az, 0.0], ] From 9d48fe8057c9d079613054101a584758196eae7b Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Mon, 11 Dec 2023 09:52:01 -0300 Subject: [PATCH 225/309] np zeros function argument typo --- siriuspy/siriuspy/clientconfigdb/types/as_rf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index 8e35d46c3..460b44c2a 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -2,7 +2,7 @@ from copy import deepcopy as _dcopy import numpy as _np -az = _np.zeros(1,5) +az = _np.zeros((1,5)) # NOTE: absolute imports are necessary here due to how # CONFIG_TYPES in __init__.py is built. From 921bc2f9fb5b66154117bbfa2015870c37b81354 Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Mon, 11 Dec 2023 09:59:38 -0300 Subject: [PATCH 226/309] auxiliary variable declaration corrected --- siriuspy/siriuspy/clientconfigdb/types/as_rf.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index 460b44c2a..32125e4f3 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -500,16 +500,16 @@ def get_dict(): # ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.az, 0.0], # SSA3 Pwr + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], # SSA3 Pwr # Cal Coeff - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.az, 0.0], - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.az, 0.0], - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.az, 0.0], - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', _np.az, 0.0], #SSA4 Pwr + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], #SSA4 Pwr #Cal Coeff - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', _np.az, 0.0], - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', _np.az, 0.0], - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', _np.az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], ] From 5ec128f527892c07cebde2298770c7bd286ffbee Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 11 Dec 2023 12:41:19 -0300 Subject: [PATCH 227/309] orbintlk.MNT: change reliability failure log messages to warning when state is not on --- siriuspy/siriuspy/orbintlk/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index dae25b040..4ca7a281f 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1458,7 +1458,8 @@ def _check_minsum_requirement(self, monit_sum=None): def _handle_reliability_failure(self, is_failure=True): if is_failure: - self._update_log('FATAL:Orbit interlock reliability failure') + flag = 'FATAL' if self._state else 'WARN' + self._update_log(f'{flag}:Orbit interlock reliability failure') if not self._state: self._update_log('WARN:Orbit interlock is not enabled.') return From 0a2dfd3f8166d189582872ae51bb0aec434e1234 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 11 Dec 2023 12:55:25 -0300 Subject: [PATCH 228/309] Update version to 2.85.0 --- siriuspy/siriuspy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/VERSION b/siriuspy/siriuspy/VERSION index b52112ac5..af8717366 100644 --- a/siriuspy/siriuspy/VERSION +++ b/siriuspy/siriuspy/VERSION @@ -1 +1 @@ -2.84.0 +2.85.0 From 7ff02ae5eac2dc6c54e5c4a8f6eeb0bbc5378dc7 Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Mon, 11 Dec 2023 18:32:37 -0300 Subject: [PATCH 229/309] 1D array for calibration PVs and comments changed --- .../siriuspy/clientconfigdb/types/as_rf.py | 212 +++++++++++------- 1 file changed, 133 insertions(+), 79 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index 32125e4f3..d509784e4 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -2,7 +2,7 @@ from copy import deepcopy as _dcopy import numpy as _np -az = _np.zeros((1,5)) +az = _np.zeros(5) # NOTE: absolute imports are necessary here due to how # CONFIG_TYPES in __init__.py is built. @@ -27,7 +27,8 @@ def get_dict(): # delay [s] the client should wait before setting the next PV. _pvs_bo_llrf = [ - ['BR-RF-DLLRF-01:ILK:REVSSA1:S', 0.0, 0.0], # Interlock disable + # Interlock disable + ['BR-RF-DLLRF-01:ILK:REVSSA1:S', 0.0, 0.0], ['BR-RF-DLLRF-01:ILK:REVSSA2:S', 0, 0.0], ['BR-RF-DLLRF-01:ILK:REVSSA3:S', 0, 0.0], ['BR-RF-DLLRF-01:ILK:REVSSA4:S', 0, 0.0], @@ -54,10 +55,14 @@ def get_dict(): ['BR-RF-DLLRF-01:ILK:RFIN14:S', 0, 0.0], ['BR-RF-DLLRF-01:ILK:RFIN15:S', 0, 0.0], ['BR-RF-DLLRF-01:ILK:BEAM:TRIP:S', 0, 0.0], - ['BR-RF-DLLRF-01:SWITCHES:S', 0, 0.0], # End switches logic - ['BR-RF-DLLRF-01:TRIPINVERT:S', 0, 0.0], # Beam trip logic - ['BR-RF-DLLRF-01:VACINVERT:S', 0, 0.0], # Vacuum sensor logic - ['BR-RF-DLLRF-01:LIMIT:REVSSA1:S', 0, 0.0], # Pwr intlck threshold [mV] + # End switches logic + ['BR-RF-DLLRF-01:SWITCHES:S', 0, 0.0], + # Beam trip logic + ['BR-RF-DLLRF-01:TRIPINVERT:S', 0, 0.0], + # Vacuum sensor logic + ['BR-RF-DLLRF-01:VACINVERT:S', 0, 0.0], + # Pwr interlock threshold + ['BR-RF-DLLRF-01:LIMIT:REVSSA1:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:LIMIT:REVSSA2:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:LIMIT:REVSSA3:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:LIMIT:REVSSA4:S', 0, 0.0], # [mV] @@ -74,8 +79,10 @@ def get_dict(): ['BR-RF-DLLRF-01:LIMIT:RFIN13:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:LIMIT:RFIN14:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:LIMIT:RFIN15:S', 0, 0.0], # [mV] - ['BR-RF-DLLRF-01:ILK:DELAY:S', 0, 0.0], # [μs] Interlock delay - ['BR-RF-DLLRF-01:mV:AL:REF-SP.DRVH', 0, 0.0], # Settings PVs values lims + # Interlock delay + ['BR-RF-DLLRF-01:ILK:DELAY:S', 0, 0.0], # [μs] + # Settings PVs values lims + ['BR-RF-DLLRF-01:mV:AL:REF-SP.DRVH', 0, 0.0], ['BR-RF-DLLRF-01:mV:AL:REF-SP.DRVL', 0, 0.0], ['BR-RF-DLLRF-01:mV:RAMP:AMP:TOP-SP.DRVH', 0, 0.0], ['BR-RF-DLLRF-01:mV:RAMP:AMP:TOP-SP.DRVL', 0, 0.0], @@ -83,13 +90,18 @@ def get_dict(): ['BR-RF-DLLRF-01:mV:RAMP:AMP:BOT-SP.DRVL', 0, 0.0], ['BR-RF-DLLRF-01:OLGAIN:S.DRVH', 0, 0.0], ['BR-RF-DLLRF-01:OLGAIN:S.DRVL', 0, 0.0], - ['BR-RF-DLLRF-01:SL:KP:S.DRVH', 0, 0.0], # kp limit high - ['BR-RF-DLLRF-01:SL:KP:S.DRVL', 0, 0.0], # kp limit low - ['BO-05D:VA-CCG-RFC:FastRelay-SP', 0, 0.0], # Pressure threshold - ['BR-RF-DLLRF-01:AUTOCOND:S', 0, 0.0], # Pressure Lock power increase + # kp limit high + ['BR-RF-DLLRF-01:SL:KP:S.DRVH', 0, 0.0], + # kp limit low + ['BR-RF-DLLRF-01:SL:KP:S.DRVL', 0, 0.0], + # Pressure threshold + ['BO-05D:VA-CCG-RFC:FastRelay-SP', 0, 0.0], + # Pressure Lock power increase + ['BR-RF-DLLRF-01:AUTOCOND:S', 0, 0.0], ['BR-RF-DLLRF-01:EPS:S', 0, 0.0], ['BR-RF-DLLRF-01:FIM:S', 0, 0.0], - ['BR-RF-DLLRF-01:PHSH:CAV:S', 0, 0.0], # [°] # ADC Phase and Gain + # ADC Phase and Gain + ['BR-RF-DLLRF-01:PHSH:CAV:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:FWDCAV:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:FWDSSA1:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:FWDSSA2:S', 0, 0.0], # [°] @@ -100,7 +112,8 @@ def get_dict(): ['BR-RF-DLLRF-01:GAIN:FWDSSA2:S', 0, 0.0], ['BR-RF-DLLRF-01:GAIN:FWDSSA3:S', 0, 0.0], ['BR-RF-DLLRF-01:GAIN:FWDSSA4:S', 0, 0.0], - ['BR-RF-DLLRF-01:PHSH:SSA1:S', 0, 0.0], # [°] # DAC Phse and Gain + # DAC Phse and Gain + ['BR-RF-DLLRF-01:PHSH:SSA1:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:SSA2:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:SSA3:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:PHSH:SSA4:S', 0, 0.0], # [°] @@ -108,7 +121,8 @@ def get_dict(): ['BR-RF-DLLRF-01:GAIN:SSA2:S', 0, 0.0], ['BR-RF-DLLRF-01:GAIN:SSA3:S', 0, 0.0], ['BR-RF-DLLRF-01:GAIN:SSA4:S', 0, 0.0], - ['BR-RF-DLLRF-01:SL:KP:S', 0, 0.0], # Loops parameters + # Loops parameters + ['BR-RF-DLLRF-01:SL:KP:S', 0, 0.0], ['BR-RF-DLLRF-01:SL:KI:S', 0, 0.0], ['BR-RF-DLLRF-01:SL:PILIMIT:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:SL:SEL:S', 0, 0.0], @@ -122,12 +136,18 @@ def get_dict(): ['BR-RF-DLLRF-01:PL:KP:S', 0, 0.0], ['BR-RF-DLLRF-01:PL:KI:S', 0, 0.0], ['BR-RF-DLLRF-01:PL:SEL:S', 0, 0.0], - ['BR-RF-DLLRF-01:MODE:S', 0, 0.0], # Loop mode - ['BR-RF-DLLRF-01:FWMIN:AMPPHS:S', 0, 0.0], # [mV] # Min forward power - ['BR-RF-DLLRF-01:mV:AMPREF:MIN:S', 0, 0.0], # [mV] # Min amplitude ref. - ['BR-RF-DLLRF-01:PHSREF:MIN:S', 0, 0.0], # [°] # Min phase ref. - ['BR-RF-DLLRF-01:OLGAIN:S', 0, 0.0], # Open loop gain - ['BR-RF-DLLRF-01:TUNE:POS:S', 0, 0.0], # Tuning loop config + # Loop mode + ['BR-RF-DLLRF-01:MODE:S', 0, 0.0], + # Min forward power + ['BR-RF-DLLRF-01:FWMIN:AMPPHS:S', 0, 0.0], # [mV] + # Min amplitude ref + ['BR-RF-DLLRF-01:mV:AMPREF:MIN:S', 0, 0.0], # [mV] + # Min phase ref + ['BR-RF-DLLRF-01:PHSREF:MIN:S', 0, 0.0], # [°] + # Open loop gain + ['BR-RF-DLLRF-01:OLGAIN:S', 0, 0.0], + # Tuning loop config + ['BR-RF-DLLRF-01:TUNE:POS:S', 0, 0.0], ['BR-RF-DLLRF-01:TUNE:FWMIN:S', 0, 0.0], # [mV] ['BR-RF-DLLRF-01:TUNE:MARGIN:HI:S', 0, 0.0], # [°] ['BR-RF-DLLRF-01:TUNE:MARGIN:LO:S', 0, 0.0], # [°] @@ -137,13 +157,16 @@ def get_dict(): ['BR-RF-DLLRF-01:TUNE:FILT:S', 0, 0.0], ['BR-RF-DLLRF-01:TUNE:TRIG:S', 0, 0.0], ['BR-RF-DLLRF-01:TUNE:TOPRAMP:S', 0, 0.0], - ['BR-RF-DLLRF-01:FF:POS:S', 0, 0.0], # Field Flatness loop config + # Field Flatness loop config + ['BR-RF-DLLRF-01:FF:POS:S', 0, 0.0], ['BR-RF-DLLRF-01:FF:DEADBAND:S', 0, 0.0], # [%] ['BR-RF-DLLRF-01:FF:GAIN:CELL2:S', 0, 0.0], ['BR-RF-DLLRF-01:FF:GAIN:CELL4:S', 0, 0.0], - ['BR-RF-DLLRF-01:freq:cond:S', 0, 0.0], # [Hz] # Pulsed mode config + # Pulsed mode config + ['BR-RF-DLLRF-01:freq:cond:S', 0, 0.0], # [Hz] ['BR-RF-DLLRF-01:freq:duty:S', 0, 0.0], # [%] - ['BR-RF-DLLRF-01:RmpTs1-SP', 0, 0.0], # [ms] # Ramp mode config + # Ramp mode config + ['BR-RF-DLLRF-01:RmpTs1-SP', 0, 0.0], # [ms] ['BR-RF-DLLRF-01:RmpTs2-SP', 0, 0.0], # [ms] ['BR-RF-DLLRF-01:RmpTs3-SP', 0, 0.0], # [ms] ['BR-RF-DLLRF-01:RmpTs4-SP', 0, 0.0], # [ms] @@ -155,16 +178,18 @@ def get_dict(): ['BR-RF-DLLRF-01:DisableRampDown:S', 0, 0.0], ['BR-RF-DLLRF-01:FDL:FrameQty-SP', 0, 0.0], ['BR-RF-DLLRF-01:FDL:REARM', 0, 0.0], - ['RA-RaBO01:RF-CavPlDrivers:DrEnbl-Sel', 0, 0.0], # Enable plungers step - # motor drivers - ['BR-RF-DLLRF-01:PHSH:ADC:S', 0, 0.0], # Enable ADC phase and gain - ['BR-RF-DLLRF-01:PHSH:DAC:S', 0, 0.0], # Enable DAC phase and gain + # Enable plungers step motor drivers + ['RA-RaBO01:RF-CavPlDrivers:DrEnbl-Sel', 0, 0.0], + # Enable ADC phase and gain + ['BR-RF-DLLRF-01:PHSH:ADC:S', 0, 0.0], + # Enable DAC phase and gain + ['BR-RF-DLLRF-01:PHSH:DAC:S', 0, 0.0], ] _pvs_bo_rfssa = [ - ['RA-ToBO:OffsetConfig:UpperIncidentPower', 0, 0.0], # [dB] Offsets - # SSA Tower + # SSA tower offsets + ['RA-ToBO:OffsetConfig:UpperIncidentPower', 0, 0.0], # [dB] ['RA-ToBO:OffsetConfig:UpperReflectedPower', 0, 0.0], # [dB] ['RA-ToBO:OffsetConfig:LowerIncidentPower', 0, 0.0], # [dB] ['RA-ToBO:OffsetConfig:LowerReflectedPower', 0, 0.0], # [dB] @@ -172,8 +197,8 @@ def get_dict(): ['RA-ToBO:OffsetConfig:InputReflectedPower', 0, 0.0], # [dB] ['RA-ToBO:OffsetConfig:OutputIncidentPower', 0, 0.0], # [dB] ['RA-ToBO:OffsetConfig:OutputReflectedPower', 0, 0.0], # [dB] - ['RA-ToBO:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # [dBm] Alarms limits - # power SSA tower + # SSA tower pwr alarm limits + ['RA-ToBO:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # [dBm] ['RA-ToBO:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], # [dBm] ['RA-ToBO:AlarmConfig:GeneralPowerLimLow', 0, 0.0], # [dBm] ['RA-ToBO:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], # [dBm] @@ -181,8 +206,8 @@ def get_dict(): ['RA-ToBO:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # [dBm] ['RA-ToBO:AlarmConfig:InnerPowerLimLow', 0, 0.0], # [dBm] ['RA-ToBO:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], # [dBm] - ['RA-ToBO:AlarmConfig:CurrentLimHiHi', 0, 0.0], # [A] Alarms limits - # currents SSA tower + # SSA tower current alarm limits + ['RA-ToBO:AlarmConfig:CurrentLimHiHi', 0, 0.0], # [A] ['RA-ToBO:AlarmConfig:CurrentLimHigh', 0, 0.0], # [A] ['RA-ToBO:AlarmConfig:CurrentLimLow', 0, 0.0], # [A] ['RA-ToBO:AlarmConfig:CurrentLimLoLo', 0, 0.0], # [A] @@ -190,7 +215,8 @@ def get_dict(): _pvs_bo_rfcal = [ - ['BR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], # Offsets and conv coeffs + # Offsets and conv coeffs + ['BR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C2:S', 0, 0.0], @@ -310,13 +336,14 @@ def get_dict(): ['BR-RF-DLLRF-01:OLG:FWDSSA1:Const:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:OLG:FWDSSA1:Const:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:OLG:FWDSSA1:Const:C4:S', 0, 0.0], - ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff0-SP', 0, 0.0], # Conv coeffs for - # Voltage Gap calc + # Conv coeffs for gap voltage calc + ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff0-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff1-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff2-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff3-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:AmpVCav2HwCoeff4-SP', 0, 0.0], - ['BO-05D:RF-P5Cav:Rsh-SP', 0, 0.0], # Cavity Shunt impedance + # Cavity Shunt impedance + ['BO-05D:RF-P5Cav:Rsh-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff0-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff1-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff2-SP', 0, 0.0], @@ -326,7 +353,8 @@ def get_dict(): _pvs_si_llrf = [ - ['SR-RF-DLLRF-01:ILK:REVSSA1:S', 0, 0.0], # Interlock disable + # Interlock disable + ['SR-RF-DLLRF-01:ILK:REVSSA1:S', 0, 0.0], ['SR-RF-DLLRF-01:ILK:REVSSA2:S', 0, 0.0], ['SR-RF-DLLRF-01:ILK:REVSSA3:S', 0, 0.0], ['SR-RF-DLLRF-01:ILK:REVSSA4:S', 0, 0.0], @@ -353,10 +381,14 @@ def get_dict(): ['SR-RF-DLLRF-01:ILK:RFIN14:S', 0, 0.0], ['SR-RF-DLLRF-01:ILK:RFIN15:S', 0, 0.0], ['SR-RF-DLLRF-01:ILK:BEAM:TRIP:S', 0, 0.0], - ['SR-RF-DLLRF-01:SWITCHES:S', 0, 0.0], # End switches logic - ['SR-RF-DLLRF-01:TRIPINVERT:S', 0, 0.0], # Beam trip logic - ['SR-RF-DLLRF-01:VACINVERT:S', 0, 0.0], # Vacuum sensor logic - ['SR-RF-DLLRF-01:LIMIT:REVSSA1:S', 0, 0.0], # [mV] Pwr intlck threshold + # End switches logic + ['SR-RF-DLLRF-01:SWITCHES:S', 0, 0.0], + # Beam trip logic + ['SR-RF-DLLRF-01:TRIPINVERT:S', 0, 0.0], + # Vacuum sensor logic + ['SR-RF-DLLRF-01:VACINVERT:S', 0, 0.0], + # Pwr interlock threshold + ['SR-RF-DLLRF-01:LIMIT:REVSSA1:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:LIMIT:REVSSA2:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:LIMIT:REVSSA3:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:LIMIT:REVSSA4:S', 0, 0.0], # [mV] @@ -373,17 +405,21 @@ def get_dict(): ['SR-RF-DLLRF-01:LIMIT:RFIN13:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:LIMIT:RFIN14:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:LIMIT:RFIN15:S', 0, 0.0], # [mV] - ['SR-RF-DLLRF-01:ILK:DELAY:S', 0, 0.0], # [μs] # Interlock delay - ['SR-RF-DLLRF-01:mV:AL:REF-SP.DRVH', 0, 0.0], # [mV] Set PVs value lims + # Interlock delay + ['SR-RF-DLLRF-01:ILK:DELAY:S', 0, 0.0], # [μs] + # Set PVs value lims + ['SR-RF-DLLRF-01:mV:AL:REF-SP.DRVH', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:mV:AL:REF-SP.DRVL', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:OLGAIN:S.DRVH', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:OLGAIN:S.DRVL', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:SL:KP:S.DRVH', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:SL:KP:S.DRVL', 0, 0.0], # [mV] - ['SR-RF-DLLRF-01:AUTOCOND:S', 0, 0.0], # Pressure Lock power increase + # Pressure Lock power increase + ['SR-RF-DLLRF-01:AUTOCOND:S', 0, 0.0], ['SR-RF-DLLRF-01:EPS:S', 0, 0.0], ['SR-RF-DLLRF-01:FIM:S', 0, 0.0], - ['SR-RF-DLLRF-01:PHSH:CAV:S', 0, 0.0], # [°] ADC Phase and Gain + # ADC Phase and Gain + ['SR-RF-DLLRF-01:PHSH:CAV:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:FWDCAV:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:FWDSSA1:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:FWDSSA2:S', 0, 0.0], # [°] @@ -394,7 +430,8 @@ def get_dict(): ['SR-RF-DLLRF-01:GAIN:FWDSSA2:S', 0, 0.0], ['SR-RF-DLLRF-01:GAIN:FWDSSA3:S', 0, 0.0], ['SR-RF-DLLRF-01:GAIN:FWDSSA4:S', 0, 0.0], - ['SR-RF-DLLRF-01:PHSH:SSA1:S', 0, 0.0], # [°] DAC Phse and Gain + # DAC Phse and Gain + ['SR-RF-DLLRF-01:PHSH:SSA1:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:SSA2:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:SSA3:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:PHSH:SSA4:S', 0, 0.0], # [°] @@ -402,7 +439,8 @@ def get_dict(): ['SR-RF-DLLRF-01:GAIN:SSA2:S', 0, 0.0], ['SR-RF-DLLRF-01:GAIN:SSA3:S', 0, 0.0], ['SR-RF-DLLRF-01:GAIN:SSA4:S', 0, 0.0], - ['SR-RF-DLLRF-01:SL:KP:S', 0, 0.0], # Loops parameters + # Loops parameters + ['SR-RF-DLLRF-01:SL:KP:S', 0, 0.0], ['SR-RF-DLLRF-01:SL:KI:S', 0, 0.0], ['SR-RF-DLLRF-01:SL:PILIMIT:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:SL:SEL:S', 0, 0.0], @@ -416,13 +454,20 @@ def get_dict(): ['SR-RF-DLLRF-01:PL:KP:S', 0, 0.0], ['SR-RF-DLLRF-01:PL:KI:S', 0, 0.0], ['SR-RF-DLLRF-01:PL:SEL:S', 0, 0.0], - ['SR-RF-DLLRF-01:MODE:S', 0, 0.0], # Loop mode - ['SR-RF-DLLRF-01:FWMIN:AMPPHS:S', 0, 0.0], # [mV] Min forward power - ['SR-RF-DLLRF-01:mV:AMPREF:MIN:S', 0, 0.0], # [mV] Min amplitude reference - ['SR-RF-DLLRF-01:PHSREF:MIN:S', 0, 0.0], # [°] Min phase reference - ['SR-RF-DLLRF-01:OLGAIN:S', 0, 0.0], # Open loop gain - ['SR-RF-DLLRF-01:PL:REF:S', 0, 0.0], # [°] Phase ref - ['SR-RF-DLLRF-01:TUNE:POS:S', 0, 0.0], # Tuning loop config + # Loop mode + ['SR-RF-DLLRF-01:MODE:S', 0, 0.0], + # Min forward power + ['SR-RF-DLLRF-01:FWMIN:AMPPHS:S', 0, 0.0], # [mV] + # Min amplitude reference + ['SR-RF-DLLRF-01:mV:AMPREF:MIN:S', 0, 0.0], # [mV] + # Min phase reference + ['SR-RF-DLLRF-01:PHSREF:MIN:S', 0, 0.0], # [°] + # Open loop gain + ['SR-RF-DLLRF-01:OLGAIN:S', 0, 0.0], + # Phase ref + ['SR-RF-DLLRF-01:PL:REF:S', 0, 0.0], # [°] + # Tuning loop config + ['SR-RF-DLLRF-01:TUNE:POS:S', 0, 0.0], ['SR-RF-DLLRF-01:TUNE:FWMIN:S', 0, 0.0], # [mV] ['SR-RF-DLLRF-01:TUNE:MARGIN:HI:S', 0, 0.0], # [°] ['SR-RF-DLLRF-01:TUNE:MARGIN:LO:S', 0, 0.0], # [°] @@ -432,12 +477,14 @@ def get_dict(): ['SR-RF-DLLRF-01:TUNE:FILT:S', 0, 0.0], ['SR-RF-DLLRF-01:TUNE:TRIG:S', 0, 0.0], ['SR-RF-DLLRF-01:TUNE:TOPRAMP:S', 0, 0.0], - ['SR-RF-DLLRF-01:FF:POS:S', 0, 0.0], # Field Flatness loop config + # Field Flatness loop config + ['SR-RF-DLLRF-01:FF:POS:S', 0, 0.0], ['SR-RF-DLLRF-01:FF:DEADBAND:S', 0, 0.0], # [%] ['SR-RF-DLLRF-01:FF:GAIN:CELL2:S', 0, 0.0], ['SR-RF-DLLRF-01:FF:GAIN:CELL4:S', 0, 0.0], ['SR-RF-DLLRF-01:COND:DC:S', 0, 0.0], # [%] - ['SR-RF-DLLRF-01:RmpTs1-SP', 0, 0.0], # [ms] Ramp mode config + # Ramp mode config + ['SR-RF-DLLRF-01:RmpTs1-SP', 0, 0.0], # [ms] ['SR-RF-DLLRF-01:RmpTs2-SP', 0, 0.0], # [ms] ['SR-RF-DLLRF-01:RmpTs3-SP', 0, 0.0], # [ms] ['SR-RF-DLLRF-01:RmpTs4-SP', 0, 0.0], # [ms] @@ -449,14 +496,17 @@ def get_dict(): ['SR-RF-DLLRF-01:DisableRampDown:S', 0, 0.0], ['SR-RF-DLLRF-01:FDL:FrameQty-SP', 0, 0.0], ['SR-RF-DLLRF-01:FDL:REARM', 0, 0.0], - ['SR-RF-DLLRF-01:PHSH:ADC:S', 0, 0.0], # Enable ADC phase and gain - ['SR-RF-DLLRF-01:PHSH:DAC:S', 0, 0.0], # Enable DAC phase and gain + # Enable ADC phase and gain + ['SR-RF-DLLRF-01:PHSH:ADC:S', 0, 0.0], + # Enable DAC phase and gain + ['SR-RF-DLLRF-01:PHSH:DAC:S', 0, 0.0], ] _pvs_si_rfssa = [ # NOTE: Alarms and offset of SSA towers 1 & 2 temporaly removed - # ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr1 + # SSA tower 1 offsets + # ['RA-ToSIA01:OffsetConfig:UpperIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerReflectedPower', 0, 0.0], @@ -464,8 +514,8 @@ def get_dict(): # ['RA-ToSIA01:OffsetConfig:InputReflectedPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:OutputIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr - # SSA tower 1 + # SSA tower 1 pwr alarm limits + # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], @@ -473,12 +523,13 @@ def get_dict(): # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents - # SSA tower 1 + # SSA tower 1 current alarm limits + # ['RA-ToSIA01:AlarmConfig:CurrentLimHiHi', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:CurrentLimLoLo', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # Offsets SSA Twr2 + # SSA tower 2 offsets + # ['RA-ToSIA02:OffsetConfig:UpperIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerReflectedPower', 0, 0.0], @@ -486,8 +537,8 @@ def get_dict(): # ['RA-ToSIA02:OffsetConfig:InputReflectedPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:OutputIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:OutputReflectedPower', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # Alarms lims pwr - # SSA tower 2 + # SSA tower 2 pwr alarm limits + # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], @@ -495,18 +546,18 @@ def get_dict(): # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # Alarms lims currents - # SSA tower 2 + # SSA tower 2 current alarm limits + # ['RA-ToSIA02:AlarmConfig:CurrentLimHiHi', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], - ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], # SSA3 Pwr - # Cal Coeff + # SSA3 Pwr Cal Coeff + ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], - ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], #SSA4 Pwr - #Cal Coeff + # SSA4 Pwr Cal Coeff + ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], ['RA-ToSIA04:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], @@ -514,7 +565,8 @@ def get_dict(): _pvs_si_rfcav = [ - ['SI-02SB:RF-P7Cav:Disc1FlwRt-Mon', 0, 0.0], # [L/h] CavP7 water flowrate + # CavP7 water flow rate + ['SI-02SB:RF-P7Cav:Disc1FlwRt-Mon', 0, 0.0], # [L/h] ['SI-02SB:RF-P7Cav:Cell1FlwRt-Mon', 0, 0.0], # [L/h] ['SI-02SB:RF-P7Cav:Disc2FlwRt-Mon', 0, 0.0], # [L/h] ['SI-02SB:RF-P7Cav:Cell2FlwRt-Mon', 0, 0.0], # [L/h] @@ -533,7 +585,8 @@ def get_dict(): _pvs_si_rfcal = [ - ['SR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], # [dB] Offsets and conv coeffs + # Offsets and conv coeffs + ['SR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], # [dB] ['SR-RF-DLLRF-01:CAV:Const:Raw-U:C0:S', 0, 0.0], ['SR-RF-DLLRF-01:CAV:Const:Raw-U:C1:S', 0, 0.0], ['SR-RF-DLLRF-01:CAV:Const:Raw-U:C2:S', 0, 0.0], @@ -653,13 +706,14 @@ def get_dict(): ['SR-RF-DLLRF-01:OLG:FWDSSA1:Const:C2:S', 0, 0.0], ['SR-RF-DLLRF-01:OLG:FWDSSA1:Const:C3:S', 0, 0.0], ['SR-RF-DLLRF-01:OLG:FWDSSA1:Const:C4:S', 0, 0.0], - ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff0-SP', 0, 0.0], # Conv coeffs for - # Voltage Gap calc + # Conv coeffs for gap voltage calc + ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff0-SP', 0, 0.0], ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff1-SP', 0, 0.0], ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff2-SP', 0, 0.0], ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff3-SP', 0, 0.0], ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff4-SP', 0, 0.0], - ['SI-02SB:RF-P7Cav:Rsh-SP', 0, 0.0], # [Ohm] # Cavity Shunt impedance + # Cavity Shunt impedance + ['SI-02SB:RF-P7Cav:Rsh-SP', 0, 0.0], # [Ohm] ] From 72d9a64d821f9cbb0b45f4cfdc02c8954096e9d3 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 11 Dec 2023 19:44:22 -0300 Subject: [PATCH 230/309] Fix problem with polarization_mon --- siriuspy/siriuspy/devices/idff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 7426574d7..d73532cf9 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -94,7 +94,7 @@ def polarizations(self): @property def polarization_mon(self): """Return current ID polarization as a string (or None).""" - return self.iddev.polarization_str + return self.iddev.polarization_mon_str @property def pparameter_mon(self): From 5dc031b0e8042f99293593d5c752d53aa22ebab2 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 11 Dec 2023 20:49:05 -0300 Subject: [PATCH 231/309] Fix calculate_setpoints in IDFFConfig and IDFF device --- siriuspy/siriuspy/devices/idff.py | 4 +++- siriuspy/siriuspy/idff/config.py | 17 +++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 7426574d7..f5744d929 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -140,10 +140,12 @@ def calculate_setpoints( if polarization not in self.idffconfig.polarizations: raise ValueError('Polarization is not compatible with ID.') + if pparameter_value is None: + pparameter_value = self.pparameter_mon if kparameter_value is None: kparameter_value = self.kparameter_mon setpoints = self.idffconfig.calculate_setpoints( - polarization, kparameter_value) + polarization, pparameter_value, kparameter_value) return setpoints, polarization, pparameter_value, kparameter_value def implement_setpoints( diff --git a/siriuspy/siriuspy/idff/config.py b/siriuspy/siriuspy/idff/config.py index d618ca3cd..47edacf26 100644 --- a/siriuspy/siriuspy/idff/config.py +++ b/siriuspy/siriuspy/idff/config.py @@ -86,22 +86,27 @@ def value(self, value): """Set configuration.""" self._set_value(value) - def calculate_setpoints(self, polarization, kparameter_value): + def calculate_setpoints( + self, polarization, pparameter_value, kparameter_value): """Return correctors setpoints for a particular ID config. - The parameter 'kparameter' can be a gap or phase value, - depending on the insertion device. + 'pparameter' is the ID phase which defines polarization. + 'kparameter' can be a gap or phase value, depending on the ID. """ if self._value: setpoints = dict() idff = self._value['polarizations'][polarization] - kparameter_values = idff['kparameter'] + if polarization == 'none': + params = idff['pparameter'] + param_value = pparameter_value + else: + params = idff['kparameter'] + param_value = kparameter_value setpoints = dict() for corrlabel, table in idff.items(): if corrlabel not in ('pparameter', 'kparameter'): # linear interpolation - setpoint = _np.interp( - kparameter_value, kparameter_values, table) + setpoint = _np.interp(param_value, params, table) corr_pvname = self._value['pvnames'][corrlabel] setpoints[corr_pvname] = setpoint return setpoints From 69e01f4dd4f32da3009c3e4fa1c0cfec7c6daaf9 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 11 Dec 2023 21:44:44 -0300 Subject: [PATCH 232/309] orbintlk.ENH: remove dry run --- siriuspy/siriuspy/orbintlk/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index c9ca88539..4ee99f0e9 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -27,7 +27,7 @@ class App(_Callback): SCAN_FREQUENCY = 1 # [Hz] - def __init__(self, tests=True): + def __init__(self, tests=False): """Class constructor.""" super().__init__() self._is_dry_run = tests From 1f7a3440a25506b9fdbbc1c8b9371072faba772e Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 12 Dec 2023 12:25:53 -0300 Subject: [PATCH 233/309] Update IDFactory --- siriuspy/siriuspy/devices/idff.py | 13 ++++++++----- siriuspy/siriuspy/devices/ids.py | 21 +++++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index f5744d929..b0447c9fe 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -26,9 +26,9 @@ def __init__(self, devname): self._devname = devname # needed for _create_devices self._idffconfig = _IDFFConfig() + self._pol_mon = _IDFactory.get_idclass(devname).PARAM_PVS.POL_MON self._pparametername = \ _IDSearch.conv_idname_2_pparameter_propty(devname) - self._kparametername = \ _IDSearch.conv_idname_2_kparameter_propty(devname) @@ -247,11 +247,14 @@ def get_polarization_state( return polarization, pparameter_value, kparameter_value def _create_devices(self, devname): - param_auto_mon = False + if self._pol_mon: + props2init = ( + self._pparametername, self._kparametername, self._pol_mon) + else: + props2init = (self._pparametername, self._kparametername) devid = _IDFactory.create( - devname=devname, - props2init=(self._pparametername, self._kparametername), - auto_monitor_mon=param_auto_mon) + devname=devname, props2init=props2init, + auto_monitor_mon=False) devsch = [_PowerSupplyFBP(devname=dev) for dev in self.chnames] devscv = [_PowerSupplyFBP(devname=dev) for dev in self.cvnames] devsqs = [_PowerSupplyFBP(devname=dev) for dev in self.qsnames] diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 9d11d9b7b..93f924052 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1292,16 +1292,25 @@ class DEVICES( @staticmethod def create(devname, **kwargs): + """.""" + IDClass = IDFactory.get_idclass(devname) + if IDClass: + return IDClass(devname, **kwargs) + else: + raise NotImplementedError(devname) + + @staticmethod + def get_idclass(devname): """.""" if devname in APU.DEVICES.ALL: - return APU(devname, **kwargs) + return APU elif devname in PAPU.DEVICES.ALL: - return PAPU(devname, **kwargs) + return PAPU elif devname in EPU.DEVICES.ALL: - return EPU(devname, **kwargs) + return EPU elif devname in DELTA.DEVICES.ALL: - return DELTA(devname, **kwargs) + return DELTA elif devname in WIG.DEVICES.ALL: - return WIG(devname, **kwargs) + return WIG else: - raise NotImplementedError(devname) + return None From f75b9dcb92503926fff7b1bfabd26408807b74f0 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 11 Dec 2023 19:44:22 -0300 Subject: [PATCH 234/309] Fix problem with polarization_mon --- siriuspy/siriuspy/devices/idff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index b0447c9fe..b7655c3dc 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -94,7 +94,7 @@ def polarizations(self): @property def polarization_mon(self): """Return current ID polarization as a string (or None).""" - return self.iddev.polarization_str + return self.iddev.polarization_mon_str @property def pparameter_mon(self): From 6ff6f45038b09fa44ced4aa0c29f5818fa0eba35 Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 12 Dec 2023 18:59:50 -0300 Subject: [PATCH 235/309] Refactor IDFactory --- siriuspy/siriuspy/devices/__init__.py | 2 +- siriuspy/siriuspy/devices/idff.py | 16 +++++++--------- siriuspy/siriuspy/devices/ids.py | 25 +++++++++++++------------ 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index 373f0be08..9019a31c5 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -16,7 +16,7 @@ from .fofb_acq import FOFBCtrlSysId, FOFBPSSysId, FamFOFBSysId, \ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff -from .ids import APU, WIG, PAPU, EPU, DELTA, IDFactory +from .ids import APU, WIG, PAPU, EPU, DELTA, ID from .idff import IDFF from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index b7655c3dc..236cc6835 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -6,13 +6,13 @@ from .device import Device as _Device, DeviceSet as _DeviceSet from .pwrsupply import PowerSupplyFBP as _PowerSupplyFBP -from .ids import IDFactory as _IDFactory +from .ids import ID as _ID class IDFF(_DeviceSet): """Insertion Device Feedforward Device.""" - class DEVICES(_IDFactory.DEVICES): + class DEVICES(_ID.DEVICES): """.""" def __init__(self, devname): @@ -26,7 +26,7 @@ def __init__(self, devname): self._devname = devname # needed for _create_devices self._idffconfig = _IDFFConfig() - self._pol_mon = _IDFactory.get_idclass(devname).PARAM_PVS.POL_MON + self._pol_mon = _ID.get_idclass(devname).PARAM_PVS.POL_MON self._pparametername = \ _IDSearch.conv_idname_2_pparameter_propty(devname) self._kparametername = \ @@ -247,12 +247,10 @@ def get_polarization_state( return polarization, pparameter_value, kparameter_value def _create_devices(self, devname): - if self._pol_mon: - props2init = ( - self._pparametername, self._kparametername, self._pol_mon) - else: - props2init = (self._pparametername, self._kparametername) - devid = _IDFactory.create( + params = ( + self._pparametername, self._kparametername, self._pol_mon) + props2init = tuple(param for param in params if param is not None) + devid = _ID( devname=devname, props2init=props2init, auto_monitor_mon=False) devsch = [_PowerSupplyFBP(devname=dev) for dev in self.chnames] diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 93f924052..85483bd8a 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1280,20 +1280,21 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) -class IDFactory(): - """.""" - - class DEVICES( - APU.DEVICES, PAPU.DEVICES, EPU.DEVICES, DELTA.DEVICES, WIG.DEVICES): - """Device names.""" +class ID(_ID): + """Insertion Device.""" - ALL = APU.DEVICES.ALL + PAPU.DEVICES.ALL + \ - EPU.DEVICES.ALL + DELTA.DEVICES.ALL + WIG.DEVICES.ALL - - @staticmethod - def create(devname, **kwargs): + class DEVICES: + APU = APU.DEVICES + PAPU = PAPU.DEVICES + EPU = EPU.DEVICES + DELTA = DELTA.DEVICES + WIG = WIG.DEVICES + ALL = APU.ALL + PAPU.ALL + \ + EPU.ALL + DELTA.ALL + WIG.ALL + + def __new__(cls, devname, **kwargs): """.""" - IDClass = IDFactory.get_idclass(devname) + IDClass = ID.get_idclass(devname) if IDClass: return IDClass(devname, **kwargs) else: From c59ca1c95919462f1fd780fd7e32ba024afe5716 Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 12 Dec 2023 19:20:30 -0300 Subject: [PATCH 236/309] Fix normalizer in device PwrSupply --- siriuspy/siriuspy/devices/pwrsupply.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/pwrsupply.py b/siriuspy/siriuspy/devices/pwrsupply.py index b16291637..b1679e3f6 100644 --- a/siriuspy/siriuspy/devices/pwrsupply.py +++ b/siriuspy/siriuspy/devices/pwrsupply.py @@ -108,7 +108,9 @@ def __init__(self, devname, auto_monitor_mon=False, props2init='all'): self._strength_sp_pv = self.pv_object(self._strength_sp_propty) try: - maname = devname.substitute(dis='MA') + name = devname.substitute(dis='MA') + if name.dev == 'B1B2' or (name.sec == 'BO' and name.dev == 'B'): + maname = name.substitute(idx='') self._normalizer = _NormFactory.create(maname) except: self._normalizer = None From 7a5c40c68bdf3efd9ddc21e855e42ed660f06f68 Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 13 Dec 2023 08:24:57 -0300 Subject: [PATCH 237/309] DEV.IDS.STY: Fix style of `set_` methods of devices classes. --- siriuspy/siriuspy/devices/ids.py | 62 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index d2e2e753a..5f48bcbd5 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -267,14 +267,14 @@ def pparameter_move_eta(self): pparam_eta, _ = self.calc_move_eta(self.pparameter, None) return pparam_eta - def pparameter_set(self, pparam, timeout=None): + def set_pparameter(self, pparam, timeout=None): """Set ID target pparameter for movement [mm].""" if self.PARAM_PVS.PPARAM_SP is None: return True else: return self._write_sp(self.PARAM_PVS.PPARAM_SP, pparam, timeout) - def pparameter_speed_set(self, pparam_speed, timeout=None): + def set_pparameter_speed(self, pparam_speed, timeout=None): """Command to set ID cruise pparameterspeed for movement [mm/s].""" if self.PARAM_PVS.PPARAM_VELO_SP is None: return True @@ -282,7 +282,7 @@ def pparameter_speed_set(self, pparam_speed, timeout=None): return self._write_sp( self.PARAM_PVS.PPARAM_VELO_SP, pparam_speed, timeout) - def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): + def set_pparameter_speed_max(self, pparam_speed_max, timeout=None): """Command to set ID max cruise pparam speed for movement [mm/s].""" if self.PARAM_PVS.PPARAM_MAXVELO_SP is None: return True @@ -290,7 +290,7 @@ def pparameter_speed_max_set(self, pparam_speed_max, timeout=None): return self._write_sp( self.PARAM_PVS.PPARAM_MAXVELO_SP, pparam_speed_max, timeout) - def pparameter_accel_set(self, pparam_accel, timeout=None): + def set_pparameter_accel(self, pparam_accel, timeout=None): """Command to set ID pparam accel for movement [mm/s²].""" if self.PARAM_PVS.PPARAM_ACC_SP is None: return True @@ -298,7 +298,7 @@ def pparameter_accel_set(self, pparam_accel, timeout=None): return self._write_sp( self.PARAM_PVS.PPARAM_ACC_SP, pparam_accel, timeout) - def pparameter_accel_max_set(self, pparam_accel_max, timeout=None): + def set_pparameter_accel_max(self, pparam_accel_max, timeout=None): """Command to set ID max cruise pparam accel for movement [mm/s²].""" if self.PARAM_PVS.PPARAM_MAXACC_SP is None: return True @@ -398,21 +398,21 @@ def kparameter_move_eta(self): _, kparam_eta = self.calc_move_eta(None, self.kparameter) return kparam_eta - def kparameter_set(self, kparam, timeout=None): + def set_kparameter(self, kparam, timeout=None): """Set ID target kparameter for movement [mm].""" return self._write_sp(self.PARAM_PVS.KPARAM_SP, kparam, timeout) - def kparameter_speed_set(self, kparam_speed, timeout=None): + def set_kparameter_speed(self, kparam_speed, timeout=None): """Command to set ID cruise kparam speed for movement [mm/s].""" return self._write_sp( self.PARAM_PVS.KPARAM_VELO_SP, kparam_speed, timeout) - def kparameter_speed_max_set(self, kparam_speed_max, timeout=None): + def set_kparameter_speed_max(self, kparam_speed_max, timeout=None): """Command to set ID max cruise kparam speed for movement [mm/s].""" return self._write_sp( self.PARAM_PVS.KPARAM_MAXVELO_SP, kparam_speed_max, timeout) - def kparameter_accel_set(self, kparam_accel, timeout=None): + def set_kparameter_accel(self, kparam_accel, timeout=None): """Command to set ID kparam accel for movement [mm/s²].""" if self.PARAM_PVS.KPARAM_ACC_SP is None: return True @@ -420,7 +420,7 @@ def kparameter_accel_set(self, kparam_accel, timeout=None): return self._write_sp( self.PARAM_PVS.KPARAM_ACC_SP, kparam_accel, timeout) - def kparameter_accel_max_set(self, kparam_accel_max, timeout=None): + def set_kparameter_accel_max(self, kparam_accel_max, timeout=None): """Command to set ID max cruise kparam accel for movement [mm/s²].""" if self.PARAM_PVS.KPARAM_MAXACC_SP is None: return True @@ -555,9 +555,9 @@ def cmd_move_park(self, timeout=None): else: # composed pparam and kparam movement by IOC # first set param RBs for ETA computation and PVs consistency - if not self.pparameter_set(pparam): + if not self.set_pparameter(pparam): return False - if not self.kparameter_set(kparam): + if not self.set_kparameter(kparam): return False timeout = self.calc_move_timeout(None, None, timeout) self[self.PARAM_PVS.START_PARKING_CMD] = 1 @@ -587,10 +587,10 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): # set target pparam and kparam t0_ = _time.time() if pparam is not None and \ - not self.pparameter_set(pparam, timeout=timeout): + not self.set_pparameter(pparam, timeout=timeout): return False if kparam is not None and \ - not self.kparameter_set(kparam, timeout=timeout): + not self.set_kparameter(kparam, timeout=timeout): return False t1_ = _time.time() if timeout is not None: @@ -833,15 +833,15 @@ def phase_mon(self): # --- set methods --- - def phase_set(self, phase, timeout=None): + def set_phase(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" - return self.kparameter_set(phase, timeout) + return self.set_kparameter(phase, timeout) - def phase_speed_set(self, phase_speed, timeout=None): + def set_phase_speed(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" - return self.kparameter_speed_set(phase_speed, timeout) + return self.set_kparameter_speed(phase_speed, timeout) - def phase_speed_max_set(self, phase_speed_max, timeout=None): + def set_phase_speed_max(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" return self._write_sp('MaxPhaseSpeed-SP', phase_speed_max, timeout) @@ -1000,17 +1000,17 @@ def cmd_drive_turn_power_on(self, timeout=None): # --- set methods --- - def phase_set(self, phase, timeout=None): + def set_phase(self, phase, timeout=None): """Command to set ID target phase for movement [mm].""" - return self.kparameter_set(phase, timeout) + return self.set_kparameter(phase, timeout) - def phase_speed_set(self, phase_speed, timeout=None): + def set_phase_speed(self, phase_speed, timeout=None): """Command to set ID cruise phase speed for movement [mm/s].""" - return self.kparameter_speed_set(phase_speed, timeout) + return self.set_kparameter_speed(phase_speed, timeout) - def phase_speed_max_set(self, phase_speed_max, timeout=None): + def set_phase_speed_max(self, phase_speed_max, timeout=None): """Command to set ID max cruise phase speed for movement [mm/s].""" - return self.kparameter_speed_max_set(phase_speed_max, timeout) + return self.set_kparameter_speed_max(phase_speed_max, timeout) # --- cmd_move disable/enable --- @@ -1215,17 +1215,17 @@ def cmd_drive_turn_power_on(self, timeout=None): # --- set methods --- - def gap_set(self, gap, timeout=None): + def set_gap(self, gap, timeout=None): """Set ID target gap for movement [mm].""" - return self.kparameter_set(gap, timeout) + return self.set_kparameter(gap, timeout) - def gap_speed_set(self, gap_speed, timeout=None): + def set_gap_speed(self, gap_speed, timeout=None): """Set ID cruise gap speed for movement [mm/s].""" - return self.kparameter_speed_set(gap_speed, timeout) + return self.set_kparameter_speed(gap_speed, timeout) - def gap_speed_max_set(self, gap_speed_max, timeout=None): + def set_gap_speed_max(self, gap_speed_max, timeout=None): """Set ID max cruise gap speed for movement [mm/s].""" - return self.kparameter_speed_max_set(gap_speed_max, timeout) + return self.set_kparameter_speed_max(gap_speed_max, timeout) # --- cmd_move disable/enable --- From 7987af1c7da9f144caa5b540a8ce11bf14daf195 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 13 Dec 2023 12:37:52 -0300 Subject: [PATCH 238/309] Update _create_devices in device IDFF --- siriuspy/siriuspy/devices/idff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 236cc6835..41730cbe8 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -26,7 +26,6 @@ def __init__(self, devname): self._devname = devname # needed for _create_devices self._idffconfig = _IDFFConfig() - self._pol_mon = _ID.get_idclass(devname).PARAM_PVS.POL_MON self._pparametername = \ _IDSearch.conv_idname_2_pparameter_propty(devname) self._kparametername = \ @@ -247,8 +246,9 @@ def get_polarization_state( return polarization, pparameter_value, kparameter_value def _create_devices(self, devname): + pol_mon = _ID.get_idclass(devname).PARAM_PVS.POL_MON params = ( - self._pparametername, self._kparametername, self._pol_mon) + self._pparametername, self._kparametername, pol_mon) props2init = tuple(param for param in params if param is not None) devid = _ID( devname=devname, props2init=props2init, From 8fa8e4d80e68e1265aa80089e74cfbded1a3904f Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 13 Dec 2023 13:05:34 -0300 Subject: [PATCH 239/309] Adapt Device methods naming to concensus standard --- siriuspy/siriuspy/devices/energy.py | 8 ++++---- siriuspy/siriuspy/devices/psconv.py | 4 ++-- siriuspy/siriuspy/devices/syncd.py | 4 ++-- siriuspy/siriuspy/simul/simps.py | 4 ++-- siriuspy/siriuspy/simul/simulator.py | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/siriuspy/siriuspy/devices/energy.py b/siriuspy/siriuspy/devices/energy.py index d50afe7d5..ff155c323 100644 --- a/siriuspy/siriuspy/devices/energy.py +++ b/siriuspy/siriuspy/devices/energy.py @@ -35,22 +35,22 @@ def __init__(self, devname): @property def energy(self): """Return Ref-Mon energy.""" - return self.value_get('EnergyRef-Mon') + return self.get_value('EnergyRef-Mon') @energy.setter def energy(self, value): """Set energy.""" - self.value_set('Energy-SP', value) + self.set_value('Energy-SP', value) @property def energy_sp(self): """Return -SP energy.""" - return self.value_get('Energy-SP') + return self.get_value('Energy-SP') @property def energy_mon(self): """Return -Mon energy.""" - return self.value_get('Energy-Mon') + return self.get_value('Energy-Mon') @staticmethod def _get_dipole_devnames(devname): diff --git a/siriuspy/siriuspy/devices/psconv.py b/siriuspy/siriuspy/devices/psconv.py index be49e0b73..d182a4cf7 100644 --- a/siriuspy/siriuspy/devices/psconv.py +++ b/siriuspy/siriuspy/devices/psconv.py @@ -38,12 +38,12 @@ def property_sync(self): @property def value(self): """Return property value.""" - return self.value_get(self.property_sync) + return self.get_value(self.property_sync) @value.setter def value(self, current): """Set property value.""" - self.value_set(self.property_sync, current) + self.set_value(self.property_sync, current) @property def limits(self): diff --git a/siriuspy/siriuspy/devices/syncd.py b/siriuspy/siriuspy/devices/syncd.py index c1c280e06..2af03779e 100644 --- a/siriuspy/siriuspy/devices/syncd.py +++ b/siriuspy/siriuspy/devices/syncd.py @@ -47,7 +47,7 @@ def synchronized(self): return False return True - def value_get(self, propty): + def get_value(self, propty): """Return property value.""" if not self.connected: return @@ -61,7 +61,7 @@ def value_get(self, propty): return return sum(values) / len(values) - def value_set(self, propty, value): + def set_value(self, propty, value): """Set property.""" if not self.connected: return diff --git a/siriuspy/siriuspy/simul/simps.py b/siriuspy/siriuspy/simul/simps.py index 69de78171..928470345 100644 --- a/siriuspy/siriuspy/simul/simps.py +++ b/siriuspy/siriuspy/simul/simps.py @@ -75,7 +75,7 @@ def get_pwrstate(self, pvname): if pvn not in self: # If PwrState-Sts not simulated, assume it to be On. return _Const.PwrStateSts.On - return self.pv_value_get(pvn) + return self.get_pv_value(pvn) @staticmethod def conv_psname2typemodel(psname): @@ -136,7 +136,7 @@ def callback_update(self, **kwargs): else: setpoints = dict() for sp_pvname in self._setpoint_pvs: - setpoints[sp_pvname] = self.pv_value_get(sp_pvname) + setpoints[sp_pvname] = self.get_pv_value(sp_pvname) # synchronize Current PVs for sp_pvname, sp_value in setpoints.items(): diff --git a/siriuspy/siriuspy/simul/simulator.py b/siriuspy/siriuspy/simul/simulator.py index c598a15ce..ca99b1ac5 100644 --- a/siriuspy/siriuspy/simul/simulator.py +++ b/siriuspy/siriuspy/simul/simulator.py @@ -98,7 +98,7 @@ def values(self): """Return dict with pvnames and associated values of simulator.""" vals = dict() for pvname in self._pvs: - vals[pvname] = self.pv_value_get(pvname) + vals[pvname] = self.get_pv_value(pvname) return vals def pv_check(self, pvname): @@ -109,7 +109,7 @@ def pv_check(self, pvname): return True return False - def pv_value_get(self, pvname): + def get_pv_value(self, pvname): """Get SimPV value without invoking simulator callback.""" return self._pvs[pvname].get_sim() From b2b06ff2708fb1347321fd7a435fd1e16f4927d5 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 13 Dec 2023 14:56:23 -0300 Subject: [PATCH 240/309] Add IDBase device --- siriuspy/siriuspy/devices/__init__.py | 2 +- siriuspy/siriuspy/devices/ids.py | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/devices/__init__.py b/siriuspy/siriuspy/devices/__init__.py index 9019a31c5..3c2ebd9db 100644 --- a/siriuspy/siriuspy/devices/__init__.py +++ b/siriuspy/siriuspy/devices/__init__.py @@ -16,7 +16,7 @@ from .fofb_acq import FOFBCtrlSysId, FOFBPSSysId, FamFOFBSysId, \ FOFBCtrlLamp, FOFBPSLamp, FamFOFBLamp from .ict import ICT, TranspEff -from .ids import APU, WIG, PAPU, EPU, DELTA, ID +from .ids import IDBase, APU, WIG, PAPU, EPU, DELTA, ID from .idff import IDFF from .injctrl import InjCtrl from .injsys import PUMagsStandbyHandler, BOPSRampStandbyHandler, \ diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 70467f051..6ca60823d 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -73,8 +73,8 @@ def __str__(self): return str_ -class _ID(_Device): - """Generic Insertion Device.""" +class IDBase(_Device): + """Base Insertion Device.""" _SHORT_SHUT_EYE = 0.1 # [s] _DEF_TIMEOUT = 8 # [s] @@ -649,7 +649,7 @@ def calc_move_eta(self, pparam_goal=None, kparam_goal=None): if None not in (param_goal, param_val): dparam = abs(param_goal - param_val) dparam = 0 if dparam < param_tol else dparam - pparam_eta = _ID._calc_move_eta_model(dparam, param_vel, param_acc) + pparam_eta = IDBase._calc_move_eta_model(dparam, param_vel, param_acc) else: pparam_eta = 0.0 @@ -660,7 +660,7 @@ def calc_move_eta(self, pparam_goal=None, kparam_goal=None): if None not in (param_goal, param_val): dparam = abs(abs(param_goal) - abs(param_val)) # abs for DELTA dparam = 0 if dparam < param_tol else dparam - kparam_eta = _ID._calc_move_eta_model(dparam, param_vel, param_acc) + kparam_eta = IDBase._calc_move_eta_model(dparam, param_vel, param_acc) else: kparam_eta = 0.0 @@ -744,7 +744,8 @@ def _calc_move_eta_model(dparam, param_vel, param_acc=None): return dtime_total -class APU(_ID): + +class APU(IDBase): """APU Insertion Device.""" class DEVICES: @@ -864,7 +865,7 @@ def _move_start( return super()._move_start(cmd_propty, timeout, cmd_value) -class PAPU(_ID): +class PAPU(IDBase): """PAPU Insertion Device.""" class DEVICES: @@ -1287,7 +1288,7 @@ def cmd_clear_error(self): pass -class DELTA(_ID): +class DELTA(IDBase): """DELTA Insertion Device.""" class DEVICES: @@ -1425,7 +1426,7 @@ def calc_move_eta(self, pparam_goal=None, kparam_goal=None): return super().calc_move_eta(pparam_goal, kparam_goal) -class WIG(_ID): +class WIG(IDBase): """Wiggler Insertion Device.""" class DEVICES: @@ -1450,7 +1451,7 @@ def __init__(self, devname=None, props2init='all', auto_monitor_mon=True): devname, props2init=props2init, auto_monitor_mon=auto_monitor_mon) -class ID(_ID): +class ID(IDBase): """Insertion Device.""" class DEVICES: From 694c2f02410fdaa61dcae2decab66d673ebbbfc6 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 13 Dec 2023 15:54:35 -0300 Subject: [PATCH 241/309] Add error log to VLInterlockCtrl device --- siriuspy/siriuspy/devices/intlkctrl.py | 154 +++++++++++++++++-------- 1 file changed, 104 insertions(+), 50 deletions(-) diff --git a/siriuspy/siriuspy/devices/intlkctrl.py b/siriuspy/siriuspy/devices/intlkctrl.py index 0397bfde1..40779903d 100644 --- a/siriuspy/siriuspy/devices/intlkctrl.py +++ b/siriuspy/siriuspy/devices/intlkctrl.py @@ -149,86 +149,136 @@ def __init__(self, devname=None, props2init='all', **kwargs): devname = self.DEVICES.CAX if devname not in self.DEVICES.ALL: raise NotImplementedError(devname) + self._error_log = '' super().__init__(devname, props2init=props2init, **kwargs) + @property + def error_log(self): + """Return error log for last check method invoked.""" + return self._error_log + @property def is_hutchA_intlk_search_done(self): """.""" - return self['A:PPS01:SEARCH_OK'] == 1 + status_ok = self['A:PPS01:SEARCH_OK'] == 1 + if not status_ok: + self._error_log = 'hutch A interlock search not Ok.' + return status_ok @property def is_hutchB_intlk_search_done(self): """.""" - return self['B:PPS01:SEARCH_OK'] == 1 + status_ok = self['B:PPS01:SEARCH_OK'] == 1 + if not status_ok: + self._error_log = 'hutch B interlock search not Ok.' + return status_ok @property def is_machine_gamma_enabled(self): """.""" - return self['M:PPS01:HABILITACAO_MAQUINA'] == 1 + status_ok = self['M:PPS01:HABILITACAO_MAQUINA'] == 1 + if not status_ok: + self._error_log = 'machine gamma not enabled.' + return status_ok @property def is_frontend_gamma_shutter_opened(self): """.""" - return self['F:PPS01:GS_X_STATUS'] == 0 + status_ok = self['F:PPS01:GS_X_STATUS'] == 0 + if not status_ok: + self._error_log = 'front-end gamma shutter not opened.' + return status_ok @property def is_frontend_photon_shutter_opened(self): """.""" - return self['F:PPS01:PS_STATUS'] == 0 + status_ok = self['F:PPS01:PS_STATUS'] == 0 + if not status_ok: + self._error_log = 'front-end photon shutter not opened.' + return status_ok @property def is_hutchA_gamma_shutter_opened(self): """.""" - return self['A:PPS01:PG_STATUS'] == 0 + status_ok = self['A:PPS01:PG_STATUS'] == 0 + if not status_ok: + self._error_log = 'hutch A gamma shutter not opened.' + return status_ok @property def is_hutchA_eps_dvf_pos_ok(self): """.""" - return bool(self['A:EPS01:StatusPos']) + status_ok = bool(self['A:EPS01:StatusPos']) + if not status_ok: + self._error_log = 'hutch A EPS DVF position not Ok.' + return status_ok @property def is_hutchA_eps_temperatures_ok(self): """.""" - return bool(self['A:EPS01:StatusTemp']) + status_ok = bool(self['A:EPS01:StatusTemp']) + if not status_ok: + self._error_log = 'hutch A EPS temperatures not Ok.' + return status_ok @property def is_hutchA_eps_vacuum_ok(self): """.""" - return bool(self['A:EPS01:StatusVac']) + status_ok = bool(self['A:EPS01:StatusVac']) + if not status_ok: + self._error_log = 'hutch A EPS vacuum not Ok.' + return status_ok @property def is_hutchB_eps_vacuum_ok(self): """.""" - return bool(self['B:EPS01:StatusVac']) + status_ok = bool(self['B:EPS01:StatusVac']) + if not status_ok: + self._error_log = 'hutch B EPS vacuum not Ok.' + return status_ok @property def is_frontend_eps_mirror_pos_ok(self): """.""" - return bool(self['F:EPS01:StatusPos']) + status_ok = bool(self['F:EPS01:StatusPos']) + if not status_ok: + self._error_log = 'front-end EPS mirror position not Ok.' + return status_ok @property def is_frontend_eps_temperatures_ok(self): """.""" - return bool(self['F:EPS01:StatusTemp']) + status_ok = bool(self['F:EPS01:StatusTemp']) + if not status_ok: + self._error_log = 'front-end EPS temperatures not Ok.' + return status_ok @property def is_frontend_eps_vacuum_ok(self): """.""" - return bool(self['F:EPS01:StatusVac']) + status_ok = bool(self['F:EPS01:StatusVac']) + if not status_ok: + self._error_log = 'front-end EPS vacuum not Ok.' + return status_ok @property def is_frontend_gatevalves_opened(self): """.""" if not bool(self['A:EPS01:GV5open']): + self._error_log = 'front-end gatevalve A:EPS01:GV5 not opened.' return False if not bool(self['F:EPS01:GV4open']): + self._error_log = 'front-end gatevalve F:EPS01:GV4 not opened.' return False if not bool(self['F:EPS01:GV3open']): + self._error_log = 'front-end gatevalve F:EPS01:GV3 not opened.' return False # NOTE: GV2open not installed yet. # if not bool(self['F:EPS01:GV2open']): + # self._error_log = 'front-end gatevalve F:EPS01:GV2 not opened.' # return False if not bool(self['F:EPS01:GV1open']): + self._error_log = 'front-end gatevalve F:EPS01:GV1 not opened.' return False return True @@ -251,8 +301,10 @@ def is_frontend_gatevalves_closed(self): def is_hutchB_gatevalves_opened(self): """.""" if not bool(self['B:EPS01:GV7open']): + self._error_log = 'hutch B gatevalve B:EPS01:GV7 not opened.' return False if not bool(self['A:EPS01:GV6open']): + self._error_log = 'hutch B gatevalve B:EPS01:GV6 not opened.' return False return True @@ -268,68 +320,70 @@ def is_hutchB_gatevalves_closed(self): @property def is_frontend_shutter_eps_permission_ok(self): """.""" - return bool(self['F:PPS01:HABILITACAO_EPS_GS_X']) + status_ok = bool(self['F:PPS01:HABILITACAO_EPS_GS_X']) + if not status_ok: + self._error_log = 'front-end shutter EPS permission not Ok.' + return status_ok @property def is_hutchA_shutter_eps_permission_ok(self): """.""" - return bool(self['A:PPS01:HABILITACAO_EPS']) + status_ok = bool(self['A:PPS01:HABILITACAO_EPS']) + if not status_ok: + self._error_log = 'hutch A EPS permission not Ok.' + return status_ok @property def is_frontend_eps_ok(self): """.""" - state = True - state &= self.is_frontend_eps_mirror_pos_ok - state &= self.is_frontend_eps_temperatures_ok - state &= self.is_frontend_eps_vacuum_ok - return state + if self.is_frontend_eps_mirror_pos_ok and \ + self.is_frontend_eps_mirror_pos_ok and \ + self.is_frontend_eps_temperatures_ok and \ + self.is_frontend_eps_vacuum_ok: + return True + else: + return False @property def is_hutchA_eps_ok(self): """.""" - state = True - state &= self.is_hutchA_eps_dvf_pos_ok - state &= self.is_hutchA_eps_temperatures_ok - state &= self.is_hutchA_eps_vacuum_ok - return state + if self.is_hutchA_eps_dvf_pos_ok and \ + self.is_hutchA_eps_temperatures_ok and \ + self.is_hutchA_eps_vacuum_ok: + return True + else: + return False @property def is_hutchB_eps_ok(self): """.""" - state = True - state &= self.is_hutchB_eps_vacuum_ok - return state + return self.is_hutchB_eps_vacuum_ok @property def is_beamline_eps_ok(self): """.""" - state = True - state &= self.is_frontend_eps_ok - state &= self.is_hutchA_eps_ok - state &= self.is_hutchB_eps_ok - return state + if self.is_frontend_eps_ok and \ + self.is_hutchA_eps_ok and \ + self.is_hutchB_eps_ok: + return True + else: + return False @property def is_beamline_opened(self): """Return whether BL is opened.""" - if not self.is_hutchA_intlk_search_done: - return False - if not self.is_hutchB_intlk_search_done: - return False - if not self.is_machine_gamma_enabled: - return False - if not self.is_beamline_eps_ok: - return False - if not self.is_frontend_shutter_eps_permission_ok: - return False - if not self.is_hutchA_shutter_eps_permission_ok: - return False - if not self.is_frontend_gamma_shutter_opened or \ - not self.is_frontend_photon_shutter_opened: - return False - if not self.is_hutchA_gamma_shutter_opened: + if self.is_hutchA_intlk_search_done and \ + self.is_hutchB_intlk_search_done and \ + self.is_machine_gamma_enabled and \ + self.is_beamline_eps_ok and \ + self.is_frontend_shutter_eps_permission_ok and \ + self.is_hutchA_shutter_eps_permission_ok and \ + self.is_frontend_gamma_shutter_opened and \ + self.is_frontend_photon_shutter_opened and \ + self.is_hutchA_gamma_shutter_opened: + return True + else: return False - return True def cmd_beamline_eps_reset(self): """.""" From 0f9b821ddeaf76eacd6d80c622b5c4da3c163feb Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 14 Dec 2023 17:45:28 -0300 Subject: [PATCH 242/309] Fix err_log in BLInterlockCtrl --- siriuspy/siriuspy/devices/intlkctrl.py | 157 +++++++++++-------------- 1 file changed, 70 insertions(+), 87 deletions(-) diff --git a/siriuspy/siriuspy/devices/intlkctrl.py b/siriuspy/siriuspy/devices/intlkctrl.py index 40779903d..39899de5d 100644 --- a/siriuspy/siriuspy/devices/intlkctrl.py +++ b/siriuspy/siriuspy/devices/intlkctrl.py @@ -157,128 +157,111 @@ def error_log(self): """Return error log for last check method invoked.""" return self._error_log + def _check_set_error_log(self, cond, msg): + if not cond: + self._set_error_log(msg) + return False + else: + self._set_error_log('Ok') + return True + @property def is_hutchA_intlk_search_done(self): """.""" - status_ok = self['A:PPS01:SEARCH_OK'] == 1 - if not status_ok: - self._error_log = 'hutch A interlock search not Ok.' - return status_ok + msg = 'hutch A interlock search not Ok.' + return self._check_set_error_log(self['A:PPS01:SEARCH_OK'] == 1, msg) @property def is_hutchB_intlk_search_done(self): """.""" - status_ok = self['B:PPS01:SEARCH_OK'] == 1 - if not status_ok: - self._error_log = 'hutch B interlock search not Ok.' - return status_ok + msg = 'hutch B interlock search not Ok.' + return self._check_set_error_log(self['B:PPS01:SEARCH_OK'] == 1, msg) @property def is_machine_gamma_enabled(self): """.""" - status_ok = self['M:PPS01:HABILITACAO_MAQUINA'] == 1 - if not status_ok: - self._error_log = 'machine gamma not enabled.' - return status_ok + msg = 'machine gamma not enabled.' + return self._check_set_error_log( + self['M:PPS01:HABILITACAO_MAQUINA'] == 1, msg) @property def is_frontend_gamma_shutter_opened(self): """.""" - status_ok = self['F:PPS01:GS_X_STATUS'] == 0 - if not status_ok: - self._error_log = 'front-end gamma shutter not opened.' - return status_ok + msg = 'front-end gamma shutter not opened.' + return self._check_set_error_log(self['F:PPS01:GS_X_STATUS'] == 0, msg) @property def is_frontend_photon_shutter_opened(self): """.""" - status_ok = self['F:PPS01:PS_STATUS'] == 0 - if not status_ok: - self._error_log = 'front-end photon shutter not opened.' - return status_ok + msg = 'front-end photon shutter not opened.' + return self._check_set_error_log(self['F:PPS01:PS_STATUS'] == 0, msg) @property def is_hutchA_gamma_shutter_opened(self): """.""" - status_ok = self['A:PPS01:PG_STATUS'] == 0 - if not status_ok: - self._error_log = 'hutch A gamma shutter not opened.' - return status_ok + msg = 'hutch A gamma shutter not opened.' + return self._check_set_error_log(self['A:PPS01:PG_STATUS'] == 0, msg) @property def is_hutchA_eps_dvf_pos_ok(self): """.""" - status_ok = bool(self['A:EPS01:StatusPos']) - if not status_ok: - self._error_log = 'hutch A EPS DVF position not Ok.' - return status_ok + msg = 'hutch A EPS DVF position not Ok.' + return self._check_set_error_log(bool(self['A:EPS01:StatusPos']), msg) @property def is_hutchA_eps_temperatures_ok(self): """.""" - status_ok = bool(self['A:EPS01:StatusTemp']) - if not status_ok: - self._error_log = 'hutch A EPS temperatures not Ok.' - return status_ok + msg = 'hutch A EPS temperatures not Ok.' + return self._check_set_error_log(bool(self['A:EPS01:StatusTemp']), msg) @property def is_hutchA_eps_vacuum_ok(self): """.""" - status_ok = bool(self['A:EPS01:StatusVac']) - if not status_ok: - self._error_log = 'hutch A EPS vacuum not Ok.' - return status_ok + msg = 'hutch A EPS vacuum not Ok.' + return self._check_set_error_log(bool(self['A:EPS01:StatusVac']), msg) @property def is_hutchB_eps_vacuum_ok(self): """.""" - status_ok = bool(self['B:EPS01:StatusVac']) - if not status_ok: - self._error_log = 'hutch B EPS vacuum not Ok.' - return status_ok + msg = 'hutch B EPS vacuum not Ok.' + return self._check_set_error_log(bool(self['B:EPS01:StatusVac']), msg) @property def is_frontend_eps_mirror_pos_ok(self): """.""" - status_ok = bool(self['F:EPS01:StatusPos']) - if not status_ok: - self._error_log = 'front-end EPS mirror position not Ok.' - return status_ok + msg = 'front-end EPS mirror position not Ok.' + return self._check_set_error_log(bool(self['F:EPS01:StatusPos']), msg) @property def is_frontend_eps_temperatures_ok(self): """.""" - status_ok = bool(self['F:EPS01:StatusTemp']) - if not status_ok: - self._error_log = 'front-end EPS temperatures not Ok.' - return status_ok + msg = 'front-end EPS temperatures not Ok.' + return self._check_set_error_log(bool(self['F:EPS01:StatusTemp']), msg) @property def is_frontend_eps_vacuum_ok(self): """.""" - status_ok = bool(self['F:EPS01:StatusVac']) - if not status_ok: - self._error_log = 'front-end EPS vacuum not Ok.' - return status_ok + msg = 'front-end EPS vacuum not Ok.' + return self._check_set_error_log(bool(self['F:EPS01:StatusVac']), msg) @property def is_frontend_gatevalves_opened(self): """.""" - if not bool(self['A:EPS01:GV5open']): - self._error_log = 'front-end gatevalve A:EPS01:GV5 not opened.' + msg = 'front-end gatevalve A:EPS01:GV5 not opened.' + if not self._check_set_error_log(bool(self['A:EPS01:GV5open']), msg): return False - if not bool(self['F:EPS01:GV4open']): - self._error_log = 'front-end gatevalve F:EPS01:GV4 not opened.' + msg = 'front-end gatevalve F:EPS01:GV4 not opened.' + if not self._check_set_error_log(bool(self['F:EPS01:GV4open']), msg): return False - if not bool(self['F:EPS01:GV3open']): - self._error_log = 'front-end gatevalve F:EPS01:GV3 not opened.' + msg = 'front-end gatevalve F:EPS01:GV3 not opened.' + if not self._check_set_error_log(bool(self['F:EPS01:GV3open']), msg): return False # NOTE: GV2open not installed yet. - # if not bool(self['F:EPS01:GV2open']): - # self._error_log = 'front-end gatevalve F:EPS01:GV2 not opened.' + # msg = 'front-end gatevalve F:EPS01:GV2 not opened.' + # if not self._check_set_error_log(bool(self['F:EPS01:GV2open']), msg): # return False - if not bool(self['F:EPS01:GV1open']): - self._error_log = 'front-end gatevalve F:EPS01:GV1 not opened.' + msg = 'front-end gatevalve F:EPS01:GV1 not opened.' + if not self._check_set_error_log(bool(self['F:EPS01:GV1open']), msg): return False return True @@ -300,11 +283,11 @@ def is_frontend_gatevalves_closed(self): @property def is_hutchB_gatevalves_opened(self): """.""" - if not bool(self['B:EPS01:GV7open']): - self._error_log = 'hutch B gatevalve B:EPS01:GV7 not opened.' + msg = 'hutch B gatevalve B:EPS01:GV7 not opened.' + if not self._check_set_error_log(bool(self['B:EPS01:GV7open']), msg): return False - if not bool(self['A:EPS01:GV6open']): - self._error_log = 'hutch B gatevalve B:EPS01:GV6 not opened.' + msg = 'hutch B gatevalve B:EPS01:GV6 not opened.' + if not self._check_set_error_log(bool(self['A:EPS01:GV6open']), msg): return False return True @@ -320,18 +303,16 @@ def is_hutchB_gatevalves_closed(self): @property def is_frontend_shutter_eps_permission_ok(self): """.""" - status_ok = bool(self['F:PPS01:HABILITACAO_EPS_GS_X']) - if not status_ok: - self._error_log = 'front-end shutter EPS permission not Ok.' - return status_ok + msg = 'front-end shutter EPS permission not Ok.' + return self._check_set_error_log( + bool(self['F:PPS01:HABILITACAO_EPS_GS_X']), msg) @property def is_hutchA_shutter_eps_permission_ok(self): """.""" - status_ok = bool(self['A:PPS01:HABILITACAO_EPS']) - if not status_ok: - self._error_log = 'hutch A EPS permission not Ok.' - return status_ok + msg = 'hutch A EPS permission not Ok.' + return self._check_set_error_log( + bool(self['A:PPS01:HABILITACAO_EPS']), msg) @property def is_frontend_eps_ok(self): @@ -401,7 +382,6 @@ def cmd_frontend_gatevalves_open(self, timeout=None): t0 = _time.time() while not self.is_frontend_gatevalves_opened: if _time.time() - t0 > timeout: - print('open frontend gatevalve timeout reached!') return False _time.sleep(0.5) @@ -419,7 +399,7 @@ def cmd_hutchB_gatevalves_open(self, timeout=None): t0 = _time.time() while not self.is_hutchB_gatevalves_opened: if _time.time() - t0 > timeout: - print('open hutchB gatevalve timeout reached!') + print(self.error_log) return False _time.sleep(0.5) @@ -440,7 +420,7 @@ def cmd_frontend_gamma_and_photon_open(self, timeout=None): not self.is_frontend_gamma_shutter_opened or \ not self.is_frontend_photon_shutter_opened: if _time.time() - t0 > timeout: - print('open frontend shutter timeout reached!') + print(self.error_log) return False _time.sleep(0.5) @@ -480,7 +460,7 @@ def cmd_hutchA_photon_open(self, timeout=None): t0 = _time.time() while not self.is_hutchA_gamma_shutter_opened: if _time.time() - t0 > timeout: - print('open hutchA photon shutter timeout reached!') + print(self.error_log) return False _time.sleep(0.5) @@ -507,47 +487,44 @@ def cmd_hutchA_photon_close(self, timeout=None): def cmd_beamline_open(self): """.""" if not self.is_hutchA_intlk_search_done: - print('hutchA search is not done!') + print(self.error_log) return False if not self.is_hutchB_intlk_search_done: - print('hutchB search is not done!') + print(self.error_log) return False if not self.is_machine_gamma_enabled: - print('machine gamma signal not enabled.') + print(self.error_log) return False # check and reset EPS if not self.is_beamline_eps_ok: - print('beamline eps reset') self.cmd_beamline_eps_reset() t0 = _time.time() while not self.is_beamline_eps_ok: if _time.time() - t0 > self.TIMEOUT_EPS_RESET: - print('eps reset timeout reached!') + print(self.error_log) return False _time.sleep(0.5) # check frontend shutter permission and open gatevalves for hutchA if not self.is_frontend_shutter_eps_permission_ok: - print('open frontend and hutchA gatevalves') # open frontend and hutchA gatevalves self.cmd_frontend_gatevalves_open() t0 = _time.time() while not self.is_frontend_gatevalves_opened: if _time.time() - t0 > self.TIMEOUT_GATEVALVE: - msg = 'open frontend and hutchA gatevalve timeout reached!' - print(msg) + print(self.error_log) return False _time.sleep(0.5) # check hutchA shutter permission and open gatevalves for hutchB if not self.is_hutchA_shutter_eps_permission_ok: - print('open hutchB gatevalves') is_ok = self.cmd_hutchB_gatevalves_open( timeout=self.TIMEOUT_GATEVALVE) if not is_ok: + print(self.error_log) return False # open frontend gamma and photon shutter @@ -555,12 +532,18 @@ def cmd_beamline_open(self): is_ok = self.cmd_frontend_gamma_and_photon_open( timeout=self.TIMEOUT_SHUTTER) if not is_ok: + print(self.error_log) return False # open hutchA photon shutter print('open hutchA photon shutter') is_ok = self.cmd_hutchA_photon_open(timeout=self.TIMEOUT_SHUTTER) if not is_ok: + print(self.error_log) return False return True + + def _set_error_log(self, msg): + # NOTE: should we prefix the msg with timestamp? + self._error_log = msg From 04e304d141d4edf14edb14d2cb36df5ac9360060 Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 15 Dec 2023 08:43:18 -0300 Subject: [PATCH 243/309] Rearrange order of methods in BLInterlockCtrl --- siriuspy/siriuspy/devices/intlkctrl.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/siriuspy/siriuspy/devices/intlkctrl.py b/siriuspy/siriuspy/devices/intlkctrl.py index 39899de5d..05a4b8402 100644 --- a/siriuspy/siriuspy/devices/intlkctrl.py +++ b/siriuspy/siriuspy/devices/intlkctrl.py @@ -157,14 +157,6 @@ def error_log(self): """Return error log for last check method invoked.""" return self._error_log - def _check_set_error_log(self, cond, msg): - if not cond: - self._set_error_log(msg) - return False - else: - self._set_error_log('Ok') - return True - @property def is_hutchA_intlk_search_done(self): """.""" @@ -547,3 +539,12 @@ def cmd_beamline_open(self): def _set_error_log(self, msg): # NOTE: should we prefix the msg with timestamp? self._error_log = msg + + def _check_set_error_log(self, cond, msg_fail, msg_succeed=None): + msg_succeed = 'OK' if msg_succeed is None else msg_succeed + if not cond: + self._set_error_log(msg_fail) + return False + else: + self._set_error_log(msg_succeed) + return True From e8c5fd8bd5ab9f817aa4f823b7e101669f02289d Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 15 Dec 2023 08:46:39 -0300 Subject: [PATCH 244/309] Update check_set_error_log in BLInterlockCtrl --- siriuspy/siriuspy/devices/intlkctrl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/intlkctrl.py b/siriuspy/siriuspy/devices/intlkctrl.py index 05a4b8402..e6e5c75db 100644 --- a/siriuspy/siriuspy/devices/intlkctrl.py +++ b/siriuspy/siriuspy/devices/intlkctrl.py @@ -79,6 +79,8 @@ class BLInterlockCtrl(_Device): TIMEOUT_SHUTTER = 7 # [s] TIMEOUT_EPS_RESET = 3 # [s] + _DEF_MSG_SUCCESS = 'Ok' + class DEVICES: """Devices names.""" @@ -149,7 +151,7 @@ def __init__(self, devname=None, props2init='all', **kwargs): devname = self.DEVICES.CAX if devname not in self.DEVICES.ALL: raise NotImplementedError(devname) - self._error_log = '' + self._error_log = self._DEF_MSG_SUCCESS super().__init__(devname, props2init=props2init, **kwargs) @property @@ -541,7 +543,8 @@ def _set_error_log(self, msg): self._error_log = msg def _check_set_error_log(self, cond, msg_fail, msg_succeed=None): - msg_succeed = 'OK' if msg_succeed is None else msg_succeed + msg_succeed = BLInterlockCtrl._DEF_MSG_SUCCESS if msg_succeed is None \ + else msg_succeed if not cond: self._set_error_log(msg_fail) return False From 898d89eb5869aa771eafe155fa022fb4f5ea3cdf Mon Sep 17 00:00:00 2001 From: ximenes Date: Fri, 15 Dec 2023 17:35:07 -0300 Subject: [PATCH 245/309] Remove PSSOFB from IDFF --- siriuspy/siriuspy/idff/csdev.py | 55 +++++--- siriuspy/siriuspy/idff/main.py | 224 ++++++++++++-------------------- 2 files changed, 120 insertions(+), 159 deletions(-) diff --git a/siriuspy/siriuspy/idff/csdev.py b/siriuspy/siriuspy/idff/csdev.py index 26f93ae17..a6600f8f9 100644 --- a/siriuspy/siriuspy/idff/csdev.py +++ b/siriuspy/siriuspy/idff/csdev.py @@ -14,8 +14,7 @@ class ETypes(_csdev.ETypes): OPEN_CLOSED = ('Open', 'Closed') STS_LBLS_CORR = ( - 'Connected', 'PwrStateOn', 'OpModeConfigured', - 'SOFBModeConfigured') + 'Connected', 'PwrStateOn', 'OpModeConfigured') _et = ETypes @@ -30,7 +29,12 @@ class IDFFConst(_csdev.Const): StsLblsCorr = _csdev.Const.register( 'StsLblsCorr', _et.STS_LBLS_CORR) - DEFAULT_LOOP_FREQ = 5 # [Hz] + DEFAULT_CORR_STATUS = 0b11111111 + DEFAULT_LOOP_FREQ_MIN = 0.001 # [Hz] + DEFAULT_LOOP_FREQ_MAX = 100 # [Hz] + DEFAULT_LOOP_FREQ = 10 # [Hz] + DEFAULT_LOOP_STATE = LoopState.Open + DEFAULT_CONTROL_QS = _csdev.Const.DsblEnbl.Enbl def __init__(self, idname): """Init.""" @@ -51,41 +55,58 @@ def get_propty_database(self): 'Log-Mon': {'type': 'string', 'value': 'Starting...'}, 'LoopState-Sel': { 'type': 'enum', 'enums': _et.OPEN_CLOSED, - 'value': self.LoopState.Open}, + 'value': self.DEFAULT_LOOP_STATE}, 'LoopState-Sts': { 'type': 'enum', 'enums': _et.OPEN_CLOSED, - 'value': self.LoopState.Open}, + 'value': self.DEFAULT_LOOP_STATE}, 'LoopFreq-SP': { 'type': 'float', 'value': self.DEFAULT_LOOP_FREQ, - 'unit': 'Hz', 'prec': 3, 'lolim': 1e-3, 'hilim': 60}, + 'unit': 'Hz', 'prec': 3, + 'lolim': self.DEFAULT_LOOP_FREQ_MIN, + 'hilim': self.DEFAULT_LOOP_FREQ_MAX}, 'LoopFreq-RB': { 'type': 'float', 'value': self.DEFAULT_LOOP_FREQ, - 'unit': 'Hz', 'prec': 3, 'lolim': 1e-3, 'hilim': 60}, + 'unit': 'Hz', 'prec': 3, + 'lolim': self.DEFAULT_LOOP_FREQ_MIN, + 'hilim': self.DEFAULT_LOOP_FREQ_MAX}, 'Polarization-Mon': {'type': 'string', 'value': 'none'}, 'ConfigName-SP': {'type': 'string', 'value': ''}, 'ConfigName-RB': {'type': 'string', 'value': ''}, - 'SOFBMode-Sel': { - 'type': 'enum', 'enums': _et.DSBL_ENBL, - 'value': self.DsblEnbl.Dsbl, 'unit': 'sofbmode'}, - 'SOFBMode-Sts': { - 'type': 'enum', 'enums': _et.DSBL_ENBL, - 'value': self.DsblEnbl.Dsbl, 'unit': 'sofbmode'}, 'CorrConfig-Cmd': {'type': 'int', 'value': 0}, - 'CorrStatus-Mon': {'type': 'int', 'value': 0b1111}, + 'CorrStatus-Mon': { + 'type': 'int', 'value': self.DEFAULT_CORR_STATUS}, 'CorrStatusLabels-Cte': { 'type': 'string', 'count': len(self.StsLblsCorr._fields), - 'value': self.StsLblsCorr._fields} + 'value': self.StsLblsCorr._fields}, + 'CorrCH1Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, + 'CorrCH2Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, + 'CorrCV1Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, + 'CorrCV2Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, } if self.has_qscorrs: dbase.update({ 'ControlQS-Sel': { 'type': 'enum', 'enums': _et.DSBL_ENBL, - 'value': self.DsblEnbl.Enbl, + 'value': self.DEFAULT_CONTROL_QS, 'unit': 'If QS are included in loop'}, 'ControlQS-Sts': { 'type': 'enum', 'enums': _et.DSBL_ENBL, - 'value': self.DsblEnbl.Enbl, + 'value': self.DEFAULT_CONTROL_QS, 'unit': 'If QS are included in loop'}, + 'CorrQS1Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, + 'CorrQS2Current-Mon': { + 'type': 'float', 'value': 0, + 'unit': 'A', 'prec': 3}, }) dbase = _csdev.add_pvslist_cte(dbase) return dbase diff --git a/siriuspy/siriuspy/idff/main.py b/siriuspy/siriuspy/idff/main.py index ff49f36c5..d70267f8e 100644 --- a/siriuspy/siriuspy/idff/main.py +++ b/siriuspy/siriuspy/idff/main.py @@ -3,7 +3,6 @@ import os as _os import logging as _log import time as _time -from importlib.util import find_spec as _find_spec import epics as _epics import numpy as _np @@ -12,14 +11,9 @@ from ..callbacks import Callback as _Callback from ..clientconfigdb import ConfigDBException as _ConfigDBException from ..devices import IDFF as _IDFF -from ..pwrsupply.pssofb import PSConnSOFB as _PSConnSOFB -from ..pwrsupply.pssofb import PSNamesSOFB as _PSNamesSOFB from .csdev import IDFFConst as _Const, ETypes as _ETypes -if _find_spec('PRUserial485') is not None: - from PRUserial485 import EthBridgeClient as _EthBridgeClient - class App(_Callback): """Main application for handling IDFF.""" @@ -33,18 +27,16 @@ def __init__(self, idname): self._pvs_prefix = self._const.idffname self._pvs_database = self._const.get_propty_database() - self._loop_state = _Const.DsblEnbl.Dsbl + self._loop_state = _Const.DEFAULT_LOOP_STATE self._loop_freq = _Const.DEFAULT_LOOP_FREQ - self._control_qs = _Const.DsblEnbl.Dsbl + self._control_qs = _Const.DEFAULT_CONTROL_QS self._polarization = 'none' self._config_name = '' self.read_autosave_file() + # IDFF object with IDFF config self._idff = _IDFF(idname) - self._pssofb_isused = self._pvs_database['SOFBMode-Sts']['value'] - self._pssofb, self._bsmp_devs = self._pssofb_init(idname) - # load idff in configdb self._load_config(self._config_name) @@ -54,13 +46,13 @@ def __init__(self, idname): 'LoopFreq-SP': self.set_loop_freq, 'ControlQS-Sel': self.set_control_qs, 'ConfigName-SP': self.set_config_name, - 'SOFBMode-Sel': self.set_sofb_mode, 'CorrConfig-Cmd': self.cmd_corrconfig, } self._quit = False + self._corr_setpoints = None self._thread_ff = _epics.ca.CAThread( - target=self._do_ff, daemon=True) + target=self.main_idff_loop, daemon=True) self._thread_ff.start() def init_database(self): @@ -73,10 +65,8 @@ def init_database(self): 'ConfigName-SP': self._config_name, 'ConfigName-RB': self._config_name, 'Polarization-Mon': self._polarization, - 'SOFBMode-Sel': self._pssofb_isused, - 'SOFBMode-Sts': self._pssofb_isused, 'CorrConfig-Cmd': 0, - 'CorrStatus-Mon': 0b1111, + 'CorrStatus-Mon': _Const.DEFAULT_CORR_STATUS, } if self._const.has_qscorrs: pvn2vals.update({ @@ -102,6 +92,7 @@ def process(self, interval): # check correctors state periodically _t0 = _time.time() self._update_corr_status() + self._update_corr_setpoints() dtime = _time.time() - _t0 sleep_time = interval - dtime # sleep @@ -138,10 +129,11 @@ def set_loop_state(self, value): def set_loop_freq(self, value): """Set loop frequency.""" - if not 1e-3 <= value < 60: + fmin, fmax = _Const.DEFAULT_LOOP_FREQ_MIN, _Const.DEFAULT_LOOP_FREQ_MAX + if not fmin <= value < fmax: return False self._loop_freq = value - self._update_log(f'Loop frequency updated to {value:.2f}Hz.') + self._update_log(f'Loop frequency updated to {value:.3f}Hz.') self.run_callbacks('LoopFreq-RB', value) return True @@ -169,36 +161,11 @@ def set_config_name(self, value): self.run_callbacks('ConfigName-RB', value) return True - def set_sofb_mode(self, value): - """Set whether to use SOFBMode.""" - if not 0 <= value < len(_ETypes.DSBL_ENBL): - return False - - if self._loop_state == self._const.LoopState.Closed: - self._update_log('ERR:Open loop before changing configuration.') - return False - - if not self._idff_prepare_corrs_state(value): - self._update_log( - ('ERR:Could not configure IDFF correctors ' - 'when changing SOFBMode.')) - return False - - self._pssofb_isused = bool(value) - status = 'enabled' if self._pssofb_isused else 'disabled' - self._update_log(f'SOFBMode {status}.') - self.run_callbacks('SOFBMode-Sts', value) - - return True - def cmd_corrconfig(self, _): """Command to reconfigure power supplies to desired state.""" if self._loop_state == self._const.LoopState.Closed: self._update_log('ERR:Open loop before configure correctors.') return False - if self._pssofb_isused: - self._update_log('ERR:Turn off PSSOFB mode before configure.') - return False corrdevs = self._idff.chdevs + self._idff.cvdevs + self._idff.qsdevs for dev in corrdevs: @@ -211,15 +178,6 @@ def cmd_corrconfig(self, _): return True - def _load_config(self, config_name): - try: - self._idff.load_config(config_name) - self._update_log(f'Updated configuration: {config_name}.') - except (ValueError, _ConfigDBException) as err: - self._update_log('ERR:'+str(err)) - return False - return True - @property def quit(self): """Quit and shutdown threads.""" @@ -229,7 +187,37 @@ def quit(self): def quit(self, value): if value: self._quit = value - self._pssofb.threads_shutdown() + + def main_idff_loop(self): + while not self._quit: + # updating interval + tplanned = 1.0/self._loop_freq + + # initial time + _t0 = _time.time() + + # check IDFF device connection + if not self._idff.connected: + self._do_sleep(_t0, tplanned) + continue + + # update polarization state + self._do_update_polarization() + + # return if loop is not closed + if not self._loop_state: + self._do_sleep(_t0, tplanned) + continue + + # correctors value calculation + self._do_update_correctors() + + # setpoints implementation + if self._corr_setpoints: + self._do_implement_correctors() + + # sleep unused time or signal overtime to stdout + self._do_sleep(_t0, tplanned) # ----- log auxiliary methods ----- @@ -279,6 +267,15 @@ def _get_default_configname(self): return 'delta52_ref' return '' + def _load_config(self, config_name): + try: + self._idff.load_config(config_name) + self._update_log(f'Updated configuration: {config_name}.') + except (ValueError, _ConfigDBException) as err: + self._update_log('ERR:'+str(err)) + return False + return True + # ----- update pvs methods ----- def _do_sleep(self, time0, tplanned): @@ -298,63 +295,30 @@ def _do_update_polarization(self): self.run_callbacks('Polarization-Mon', new_pol) def _do_update_correctors(self): - corrdevs = None - if self._control_qs == self._const.DsblEnbl.Dsbl: - corrdevs = self._idff.chdevs + self._idff.cvdevs try: - # ret = self._idff.calculate_setpoints() - # setpoints, polarization, *parameters = ret + self._corr_setpoints = self._idff.calculate_setpoints() + # setpoints, polarization, *parameters = self._corr_setpoints # pparameter_value, kparameter_value = parameters # print('pparameter: ', pparameter_value) # print('kparameter: ', kparameter_value) # print('polarization: ', polarization) # print('setpoints: ', setpoints) # print() - if self._pssofb_isused: - # calc setpoints - ret = self._idff.calculate_setpoints() - setpoints, *_ = ret - - # built curr_sp vector - curr_sp = self._pssfob_get_current_setpoint( - setpoints, corrdevs) - - # apply curr_sp to pssofb - self._pssofb.bsmp_sofb_current_set_update((curr_sp, )) - else: - # use PS IOCs (IDFF) to implement setpoints - self._idff.implement_setpoints(corrdevs=corrdevs) - except ValueError as err: self._update_log('ERR:'+str(err)) - def _do_ff(self): - # updating loop - while not self._quit: - # updating interval - tplanned = 1.0/self._loop_freq - - # initial time - _t0 = _time.time() - - # check IDFF device connection - if not self._idff.connected: - self._do_sleep(_t0, tplanned) - continue - - # update polarization state - self._do_update_polarization() - - # return if loop is not closed - if not self._loop_state: - self._do_sleep(_t0, tplanned) - continue - - # correctors setpoint implementation - self._do_update_correctors() + def _do_implement_correctors(self): + corrdevs = None + if self._control_qs == self._const.DsblEnbl.Dsbl: + corrdevs = self._idff.chdevs + self._idff.cvdevs + try: + # use PS IOCs (IDFF) to implement setpoints + setpoints = self._corr_setpoints + self._idff.implement_setpoints( + setpoints=setpoints, corrdevs=corrdevs) - # sleep unused time or signal overtime to stdout - self._do_sleep(_t0, tplanned) + except ValueError as err: + self._update_log('ERR:'+str(err)) def _update_corr_status(self): """Update CorrStatus-Mon PV.""" @@ -368,56 +332,32 @@ def _update_corr_status(self): status = _updt_bit(status, 1, 1) if any(d.opmode != d.OPMODE_STS.SlowRef for d in devs): status = _updt_bit(status, 2, 1) - if any(d.sofbmode != self._pssofb_isused for d in devs): - status = _updt_bit(status, 3, 1) else: - status = 0b111 + status = _Const.DEFAULT_CORR_STATUS self.run_callbacks('CorrStatus-Mon', status) - # ----- idff ----- - - def _idff_prepare_corrs_state(self, pssofb_isused): + def _update_corr_setpoints(self): + """Update corrector setpoint PVs.""" + setpoints, *_ = self._corr_setpoints + idff = self._idff + corrnames = idff.chnames + idff.cvnames + idff.qsnames + corrlabels = ('CH1', 'CH2', 'CV1', 'CV2', 'QS1', 'QS2') + for corrlabel, corrname in zip(corrlabels, corrnames): + for corr_pvname in setpoints: + if corrname in corr_pvname: + pvname = 'Corr' + corrlabel + 'Current-Mon' + value = setpoints[corr_pvname] + self.run_callbacks(pvname, value) + + # ----- idff preparation ----- + + def _idff_prepare_corrs_state(self): """Configure PSSOFB mode state .""" if not self._idff.wait_for_connection(): return False corrdevs = self._idff.chdevs + self._idff.cvdevs + self._idff.qsdevs for dev in corrdevs: - if pssofb_isused: - if not dev.cmd_sofbmode_enable(timeout=App.DEF_PS_TIMEOUT): - return False - else: - if not dev.cmd_sofbmode_disable(timeout=App.DEF_PS_TIMEOUT): - return False + if not dev.cmd_sofbmode_disable(timeout=App.DEF_PS_TIMEOUT): + return False return True - - # ----- pssofb ----- - - def _pssofb_init(self, idname): - """Create PSSOFB connections to control correctors.""" - # bbbnames - bbbnames = _PSNamesSOFB.get_bbbnames(idname) - - # create pssofb object - pssofb = _PSConnSOFB( - ethbridgeclnt_class=_EthBridgeClient, - bbbnames=bbbnames, - sofb_update_iocs=True, - acc=idname) - - # build bsmpid -> psname dict - bsmp_devs = dict() - for devices in pssofb.bbb2devs.values(): - for devname, bsmpid in devices: - bsmp_devs[bsmpid] = devname - - return pssofb, bsmp_devs - - def _pssfob_get_current_setpoint(self, setpoints, corrdevs): - """Convert IDFF dict setpoints to PSSOFB list setpoints.""" - current_sp = _np.ones(len(setpoints)) * _np.nan - devnames = [dev.devname for dev in corrdevs] - for bsmpid, devname in self._bsmp_devs.items(): - if devname in devnames: - current_sp[bsmpid - 1] = setpoints[devname] - return current_sp From 5dc29a0f484b2246fd0fdb99dcbe6dee67064428 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 18 Dec 2023 09:34:04 -0300 Subject: [PATCH 246/309] Simplify if condition in intlkctrl method. --- siriuspy/siriuspy/devices/intlkctrl.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/siriuspy/siriuspy/devices/intlkctrl.py b/siriuspy/siriuspy/devices/intlkctrl.py index e6e5c75db..81babf0f1 100644 --- a/siriuspy/siriuspy/devices/intlkctrl.py +++ b/siriuspy/siriuspy/devices/intlkctrl.py @@ -347,18 +347,15 @@ def is_beamline_eps_ok(self): @property def is_beamline_opened(self): """Return whether BL is opened.""" - if self.is_hutchA_intlk_search_done and \ - self.is_hutchB_intlk_search_done and \ - self.is_machine_gamma_enabled and \ - self.is_beamline_eps_ok and \ - self.is_frontend_shutter_eps_permission_ok and \ - self.is_hutchA_shutter_eps_permission_ok and \ - self.is_frontend_gamma_shutter_opened and \ - self.is_frontend_photon_shutter_opened and \ - self.is_hutchA_gamma_shutter_opened: - return True - else: - return False + return self.is_hutchA_intlk_search_done and \ + self.is_hutchB_intlk_search_done and \ + self.is_machine_gamma_enabled and \ + self.is_beamline_eps_ok and \ + self.is_frontend_shutter_eps_permission_ok and \ + self.is_hutchA_shutter_eps_permission_ok and \ + self.is_frontend_gamma_shutter_opened and \ + self.is_frontend_photon_shutter_opened and \ + self.is_hutchA_gamma_shutter_opened def cmd_beamline_eps_reset(self): """.""" From 6c4ccac1ddae6e82d1d9f0020e16392b7be7afb3 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:01:47 -0300 Subject: [PATCH 247/309] DEV.FAMBPM.MNT: Use logging module. --- siriuspy/siriuspy/devices/bpm_fam.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 16940ea2a..1b0b66f11 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -1,5 +1,6 @@ """FamBPM deviceSet.""" +import logging as _log import sys import time as _time # from threading import Event as _Flag @@ -112,8 +113,10 @@ def set_attenuation(self, value=RFFEATT_MAX, timeout=TIMEOUT): f'\n{bpm.devname:<20s}: ' + f'rb {bpm.rffe_att:.0f} != sp {value:.0f}') - print('RFFE attenuation set confirmed in all BPMs', end='') - print(', except:' + mstr if mstr else '.') + stg = ', except:' if mstr else '.' + _log.info('RFFE attenuation set confirmed in all BPMs%s', stg) + if mstr: + _log.info(mstr) return okall def get_slow_orbit(self): @@ -192,7 +195,7 @@ def get_sampling_frequency(self, rf_freq: float, acq_rate='') -> float: if len(fs_bpms) == 1: return fs_bpms.pop() else: - print('BPMs are not configured with the same ACQChannel.') + _log.warning('BPMs are not configured with the same ACQChannel.') return None def get_switching_frequency(self, rf_freq: float) -> float: @@ -210,7 +213,7 @@ def get_switching_frequency(self, rf_freq: float) -> float: if len(fsw_bpms) == 1: return fsw_bpms.pop() else: - print('BPMs are not configured with the same SwMode.') + _log.warning('BPMs are not configured with the same SwMode.') return None def mturn_config_acquisition( From 2a313c6f82d18143d2301f9ffa35812495fc7d46 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:02:39 -0300 Subject: [PATCH 248/309] DEV.FAMBPM.MNT: Sort imports and fix docstring. --- siriuspy/siriuspy/devices/bpm_fam.py | 49 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 1b0b66f11..3cc1ff744 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -3,31 +3,20 @@ import logging as _log import sys import time as _time -# from threading import Event as _Flag +from copy import deepcopy as _dcopy import numpy as _np -from copy import deepcopy as _dcopy -from .device import DeviceSet as _DeviceSet -from ..search import BPMSearch as _BPMSearch from ..namesys import SiriusPVName as _PVName +from ..search import BPMSearch as _BPMSearch from .bpm import BPM +from .device import DeviceSet as _DeviceSet + +# from threading import Event as _Flag class FamBPMs(_DeviceSet): - """Family of BPMs. - - Parameters - ---------- - devname (str, optional) - Device name. If not provided, defaults to DEVICES.SI. - Determine the list of BPM names. - bpmnames ((list, tuple), optional) - BPM names list. If provided, it takes priority over 'devname' - parameter. Defaults to None. - ispost_mortem (bool, optional) - Whether to control PM acquisition core. Defaults to False. - """ + """.""" TIMEOUT = 10 RFFEATT_MAX = 30 @@ -45,7 +34,31 @@ class DEVICES: def __init__( self, devname=None, bpmnames=None, ispost_mortem=False, props2init='all', mturn_signals2acq=('X', 'Y')): - """.""" + """Family of BPMs. + + Args: + devname (str, optional): Device name. If not provided, defaults to + DEVICES.SI. Determine the list of BPM names. + bpmnames ((list, tuple), optional): BPM names list. If provided, + it takes priority over 'devname' parameter. Defaults to None. + ispost_mortem (bool, optional): Whether to control PM acquisition + core. Defaults to False. + props2init (str|list|tuple, optional): list of properties to + initialize in object creation. If a string is passed, it can + be either "all" or "acq". Defaults to "all". + mturn_signals2acq (str|list|tuple, optional): Which signals to + acquire. Signals can be defined by: + X: x position; + Y: y position; + S: antennas sum signal; + Q: skew position; + A: amplitude of antenna A; + B: amplitude of antenna B; + C: amplitude of antenna C; + D: amplitude of antenna D. + Defaults to "XY". + + """ if devname is None: devname = self.DEVICES.SI if devname not in self.DEVICES.ALL: From 62fbfdde924e93993b1c0fd5c186304299494ddd Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:05:07 -0300 Subject: [PATCH 249/309] DEV.FAMBPM.ENH: standardize method names and API. --- siriuspy/siriuspy/devices/bpm_fam.py | 124 +++++++++++++++------------ 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 3cc1ff744..63f2202a3 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -85,7 +85,7 @@ def __init__( # pvo = bpm.pv_object('ACQCount-Mon') # pvo.auto_monitor = True # self._mturn_flags[pvo.pvname] = _Flag() - # pvo.add_callback(self._mturn_set_flag) + # pvo.add_callback(self._set_mturn_flag) @property def bpm_names(self): @@ -176,14 +176,14 @@ def get_mturn_timestamps(self): """Get Multiturn data timestamps. Returns: - tsmps (numpy.ndarray, (160, N)): The i-th row has the timestamp of - the i-th bpm for the N aquired signals. + tsmps (numpy.ndarray, (N, 160)): The i-th column has the timestamp + of the i-th bpm for the N aquired signals. """ tsmps = _np.zeros( - (len(self.bpms), len(self._mturn_signals2acq)), dtype=float) - for i, bpm in enumerate(self.bpms): - for j, s in enumerate(self._mturn_signals2acq): + (len(self._mturn_signals2acq), len(self.bpms)), dtype=float) + for i, s in enumerate(self._mturn_signals2acq): + for j, bpm in enumerate(self.bpms): s = 'SUM' if s == 'S' else s pvo = bpm.pv_object(f'GEN_{s}ArrayData') tv = pvo.get_timevars(timeout=self.TIMEOUT) @@ -229,7 +229,7 @@ def get_switching_frequency(self, rf_freq: float) -> float: _log.warning('BPMs are not configured with the same SwMode.') return None - def mturn_config_acquisition( + def config_mturn_acquisition( self, nr_points_after: int, nr_points_before=0, acq_rate='FAcq', repeat=True, external=True) -> int: """Configure acquisition for BPMs. @@ -253,49 +253,42 @@ def mturn_config_acquisition( >0: Index of the first BPM which is not ready for acq. plus 1. """ - if acq_rate in self._csbpm.AcqChan: - pass - elif acq_rate.lower().startswith('facq'): - acq_rate = self._csbpm.AcqChan.FAcq - elif acq_rate.lower().startswith('fofbpha'): - acq_rate = self._csbpm.AcqChan.FOFBPha - elif acq_rate.lower().startswith('fofb'): - acq_rate = self._csbpm.AcqChan.FOFB - elif acq_rate.lower().startswith('tbtpha'): - acq_rate = self._csbpm.AcqChan.TbTPha - elif acq_rate.lower().startswith('tbt'): - acq_rate = self._csbpm.AcqChan.TbT - elif acq_rate.lower().startswith('adcswp'): - acq_rate = self._csbpm.AcqChan.ADCSwp - elif acq_rate.lower().startswith('adc'): - acq_rate = self._csbpm.AcqChan.ADC - else: - raise ValueError(acq_rate + ' is not a valid acquisition rate.') - + dic = { + 'facq': self._csbpm.AcqChan.FAcq, + 'fofbpha': self._csbpm.AcqChan.FOFBPha, + 'fofb': self._csbpm.AcqChan.FOFB, + 'tbtpha': self._csbpm.AcqChan.TbTPha, + 'tbt': self._csbpm.AcqChan.TbT, + 'adcswp': self._csbpm.AcqChan.ADCSwp, + 'adc': self._csbpm.AcqChan.ADC, + } + acq_rate = dic.get(acq_rate.lower(), acq_rate) + if acq_rate not in self._csbpm.AcqChan: + raise ValueError( + str(acq_rate) + ' is not a valid acquisition rate.') + + rep = self._csbpm.AcqRepeat.Normal if repeat: - repeat = self._csbpm.AcqRepeat.Repetitive - else: - repeat = self._csbpm.AcqRepeat.Normal + rep = self._csbpm.AcqRepeat.Repetitive + trig = self._csbpm.AcqTrigTyp.Now if external: trig = self._csbpm.AcqTrigTyp.External - else: - trig = self._csbpm.AcqTrigTyp.Now - ret = self.cmd_mturn_acq_abort() + ret = self.cmd_abort_mturn_acquisition() if ret > 0: return -ret for bpm in self.bpms: - bpm.acq_repeat = repeat + bpm.acq_repeat = rep bpm.acq_channel = acq_rate bpm.acq_trigger = trig bpm.acq_nrsamples_pre = nr_points_before bpm.acq_nrsamples_post = nr_points_after - return self.cmd_mturn_acq_start() + return self.cmd_start_mturn_acquisition() - def cmd_mturn_acq_abort(self, wait=True, timeout=10) -> int: + def cmd_abort_mturn_acquisition(self, wait=True, timeout=10) -> int: """Abort BPMs acquistion. Args: @@ -335,7 +328,7 @@ def wait_acquisition_finish(self, timeout=10) -> int: timeout -= _time.time() - t0_ return 0 - def cmd_mturn_acq_start(self, wait=True, timeout=10) -> int: + def cmd_start_mturn_acquisition(self, wait=True, timeout=10) -> int: """Start BPMs acquisition. Args: @@ -391,21 +384,21 @@ def set_switching_mode(self, mode='direct'): for bpm in self.bpms: bpm.switching_mode = mode - def mturn_update_initial_timestamps(self): + def update_mturn_initial_timestamps(self): """Call this method before acquisition to get orbit for comparison.""" self._initial_timestamps = self.get_mturn_timestamps() - def mturn_reset_flags(self): + def reset_mturn_flags(self): """Reset Multiturn flags to wait for a new orbit update.""" for flag in self._mturn_flags.values(): flag.clear() - def mturn_reset_flags_and_update_initial_timestamps(self): + def reset_mturn_initial_state(self): """Set initial state to wait for orbit acquisition to start.""" - self.mturn_reset_flags() - self.mturn_update_initial_timestamps() + self.reset_mturn_flags() + self.update_mturn_initial_timestamps() - def mturn_wait_update_flags(self, timeout=10): + def wait_update_mturn_flags(self, timeout=10): """Wait for all acquisition flags to be updated. Args: @@ -425,11 +418,11 @@ def mturn_wait_update_flags(self, timeout=10): timeout = max(timeout, 0) return 0 - def mturn_wait_update_timestamps(self, timeout=10) -> int: - """Call this method after acquisition to check if data was updated. + def wait_update_mturn_timestamps(self, timeout=10) -> int: + """Call this method after acquisition to check for timestamps update. For this method to work it is necessary to call - mturn_update_initial_timestamps + update_mturn_initial_timestamps before the acquisition starts, so that a reference for comparison is created. @@ -437,11 +430,13 @@ def mturn_wait_update_timestamps(self, timeout=10) -> int: timeout (int, optional): Waiting timeout. Defaults to 10. Returns: - int: code describing what happened: + float: code describing what happened: -2: size of timestamps changed in relation to initial timestamp -1: initial timestamps were not defined; =0: data updated. >0: index of the first BPM which did not update plus 1. + X.[1-N]: The fractional part indicates which signal, from 1 to + N, that didn't update. """ if self._initial_timestamps is None: @@ -451,7 +446,18 @@ def mturn_wait_update_timestamps(self, timeout=10) -> int: while timeout > 0: t00 = _time.time() tsmp = self.get_mturn_timestamps() - if tsmp.size != tsmp0.size: + if tsmp.shape != tsmp0.shape: + return -2 + errors = _np.equal(tsmp, tsmp0) + if not _np.any(errors): + return 0 + _time.sleep(0.1) + timeout -= _time.time() - t00 + + bpm_idx = int(_np.nonzero(_np.any(errors, axis=0))[0][0]) + code = bpm_idx + 1 + code += (int(_np.nonzero(errors[:, bpm_idx])[0][0]) + 1) / 10 + return code return -2 errors = _np.any(_np.equal(tsmp, tsmp0), axis=1) if not _np.any(errors): @@ -461,28 +467,40 @@ def mturn_wait_update_timestamps(self, timeout=10) -> int: return int(_np.nonzero(errors)[0][0])+1 - def mturn_wait_update(self, timeout=10) -> int: + def wait_update_mturn(self, timeout=10) -> int: """Combine all methods to wait update data. Args: timeout (int, optional): Waiting timeout. Defaults to 10. Returns: - int: code describing what happened: + int|float: code describing what happened: -2: size of timestamps changed in relation to initial timestamp -1: initial timestamps were not defined; =0: data updated. >0: index of the first BPM which did not update plus 1. + X.[1-N]: The fractional part indicates which signal, from 1 to + N, that didn't update. """ t00 = _time.time() - ret = self.mturn_wait_update_flags(timeout) + ret = self.wait_update_mturn_flags(timeout) if ret > 0: return ret - timeout -= _time.time() - t00 + t01 = _time.time() + dtime = t01 - t00 + timeout -= dtime + _log.debug("Flags updated (ETA: %.3fs).", dtime) - return self.mturn_wait_update_timestamps(timeout) + ret = self.wait_update_mturn_timestamps(timeout) + if ret != 0: + return ret + t02 = _time.time() + dtime = t02 - t01 + timeout -= dtime + _log.debug("Timestamps updated (ETA: %.3fs).", dtime) + return ret - def _mturn_set_flag(self, pvname, **kwargs): + def _set_mturn_flag(self, pvname, **kwargs): _ = kwargs self._mturn_flags[pvname].set() From 9abc4443f87e2cfc686111b05888d97e028463e8 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:06:21 -0300 Subject: [PATCH 250/309] DEV.FAMBPM.MNT: Propagate changes from last commit to other modules. --- siriuspy/siriuspy/devices/bpm_eq.py | 18 +++++++++--------- siriuspy/siriuspy/orbintlk/main.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index d72c02be6..f6857e195 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -252,15 +252,15 @@ def _do_acquire(self): # acquire antennas data in FOFB rate self._log('Preparing BPMs') - ret = self.cmd_mturn_acq_abort() + ret = self.cmd_abort_mturn_acquisition() if ret > 0: self._log( f'ERR: BPM {self.bpm_names[ret-1]} did not abort ' 'previous acquistion.') return - self.mturn_reset_flags_and_update_initial_timestamps() - ret = self.mturn_config_acquisition( + self.reset_mturn_initial_state() + ret = self.config_mturn_acquisition( nr_points_after=self._acq_nrpoints, nr_points_before=0, acq_rate='FOFB', repeat=False, external=True) if ret > 0: @@ -272,7 +272,7 @@ def _do_acquire(self): self.trigger.source = self.trigger.source_options.index('Clock3') self._log('Waiting BPMs to update') - ret = self.mturn_wait_update(timeout=self._acq_timeout) + ret = self.wait_update_mturn(timeout=self._acq_timeout) if ret > 0: self._log( f'ERR: BPM {self.bpm_names[ret-1]} did not update in time.') @@ -330,7 +330,7 @@ def acquire_data_for_checking(self): def _do_acquire_for_check(self): # acquire antennas data in FOFB rate self._log('Preparing BPMs') - ret = self.cmd_mturn_acq_abort() + ret = self.cmd_abort_mturn_acquisition() if ret > 0: self._log( f'ERR: BPM {self.bpm_names[ret-1]} did not abort ' @@ -341,8 +341,8 @@ def _do_acquire_for_check(self): fsamp = self.get_sampling_frequency(1) nrpts = int(fsamp / fswtc) - self.mturn_reset_flags_and_update_initial_timestamps() - ret = self.mturn_config_acquisition( + self.reset_mturn_initial_state() + ret = self.config_mturn_acquisition( nr_points_after=nrpts, nr_points_before=0, acq_rate='FOFB', repeat=False, external=True) if ret > 0: @@ -354,7 +354,7 @@ def _do_acquire_for_check(self): self.trigger.source = self.trigger.source_options.index('Clock3') self._log('Waiting BPMs to update') - ret = self.mturn_wait_update(timeout=self._acq_timeout) + ret = self.wait_update_mturn(timeout=self._acq_timeout) if ret > 0: self._log( f'ERR: BPM {self.bpm_names[ret-1]} did not update in time.') @@ -685,7 +685,7 @@ def _estimate_orbit(mean, gains, gainx, gainy, offx, offy): b_d = (b-d) / (b+d) # Get the positions: posx = (a_c - b_d) / 2 - posy = (a_c + b_d) / 2 + posy = (a_c + b_d) / 2 # Apply position gains: posx *= gainx[:, None] posy *= gainy[:, None] diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 61fc1d6fc..cce2cd5de 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -864,12 +864,12 @@ def cmd_acq_config(self, value=None): def _acq_config(self): self._update_log('Aborting BPM acquisition...') - ret = self._fambpm_dev.cmd_mturn_acq_abort() + ret = self._fambpm_dev.cmd_abort_mturn_acquisition() if ret > 0: self._update_log('ERR:Failed to abort BPM acquisition.') return self._update_log('...done. Configuring BPM acquisition...') - ret = self._fambpm_dev.mturn_config_acquisition( + ret = self._fambpm_dev.config_mturn_acquisition( nr_points_before=self._acq_spre, nr_points_after=self._acq_spost, acq_rate=self._acq_chan, From cebb4137bc2b556948d09837dfa68f15adf2ad91 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:06:44 -0300 Subject: [PATCH 251/309] DEV.FAMBPM.ENH: Add method to check for data update. --- siriuspy/siriuspy/devices/bpm_fam.py | 49 ++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 63f2202a3..febf67932 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -78,6 +78,7 @@ def __init__( self._bpm_names = bpm_names self._csbpm = self.bpms[0].csdata self._initial_timestamps = None + self._initial_signals = None self._mturn_flags = dict() # NOTE: ACQCount-Mon need to be fixed on BPM's IOC @@ -384,6 +385,10 @@ def set_switching_mode(self, mode='direct'): for bpm in self.bpms: bpm.switching_mode = mode + def update_mturn_initial_signals(self): + """Call this method before acquisition to get orbit for comparison.""" + self._initial_signals = _np.array(self.get_mturn_signals()) + def update_mturn_initial_timestamps(self): """Call this method before acquisition to get orbit for comparison.""" self._initial_timestamps = self.get_mturn_timestamps() @@ -397,6 +402,7 @@ def reset_mturn_initial_state(self): """Set initial state to wait for orbit acquisition to start.""" self.reset_mturn_flags() self.update_mturn_initial_timestamps() + self.update_mturn_initial_signals() def wait_update_mturn_flags(self, timeout=10): """Wait for all acquisition flags to be updated. @@ -458,14 +464,47 @@ def wait_update_mturn_timestamps(self, timeout=10) -> int: code = bpm_idx + 1 code += (int(_np.nonzero(errors[:, bpm_idx])[0][0]) + 1) / 10 return code + + def wait_update_mturn_signals(self, timeout=10) -> int: + """Call this method after acquisition to check for data update. + + For this method to work it is necessary to call + update_mturn_initial_signals + before the acquisition starts, so that a reference for comparison is + created. + + Args: + timeout (int, optional): Waiting timeout. Defaults to 10. + + Returns: + int: code describing what happened: + -2: size of signals changed in relation to initial signals + -1: initial signals were not defined; + =0: signals updated. + >0: index of the first BPM which did not update plus 1. + X.[1-N]: The fractional part indicates which signal, from 1 to + N, that didn't update. + + """ + if self._initial_signals is None: + return -1 + + sig0 = self._initial_signals + while timeout > 0: + t00 = _time.time() + sig = self.get_mturn_signals() + if sig.shape != sig0.shape: return -2 - errors = _np.any(_np.equal(tsmp, tsmp0), axis=1) + errors = _np.all(_np.equal(sig, sig0), axis=1) if not _np.any(errors): return 0 _time.sleep(0.1) timeout -= _time.time() - t00 - return int(_np.nonzero(errors)[0][0])+1 + bpm_idx = int(_np.nonzero(_np.any(errors, axis=0))[0][0]) + code = bpm_idx + 1 + code += (int(_np.nonzero(errors[:, bpm_idx])[0][0]) + 1) / 10 + return code def wait_update_mturn(self, timeout=10) -> int: """Combine all methods to wait update data. @@ -499,6 +538,12 @@ def wait_update_mturn(self, timeout=10) -> int: dtime = t02 - t01 timeout -= dtime _log.debug("Timestamps updated (ETA: %.3fs).", dtime) + + ret = self.wait_update_mturn_signals(timeout) + if ret != 0: + return ret + dtime = _time.time() - t02 + _log.debug("Data updated (ETA: %.3fs).", dtime) return ret def _set_mturn_flag(self, pvname, **kwargs): From e9207ea9f3c6039748695234a737e661d2d362ea Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 12:14:19 -0300 Subject: [PATCH 252/309] DEV.FAMBPM.BUG: Fix problem with wait_update_mturn_signals. --- siriuspy/siriuspy/devices/bpm_fam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index febf67932..97ff2578b 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -492,7 +492,7 @@ def wait_update_mturn_signals(self, timeout=10) -> int: sig0 = self._initial_signals while timeout > 0: t00 = _time.time() - sig = self.get_mturn_signals() + sig = _np.array(self.get_mturn_signals()) if sig.shape != sig0.shape: return -2 errors = _np.all(_np.equal(sig, sig0), axis=1) From ba28ba9c92207d17b0381cde99a645a215701766 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 18 Dec 2023 13:12:37 -0300 Subject: [PATCH 253/309] Fix IDFF.main --- siriuspy/siriuspy/idff/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/idff/main.py b/siriuspy/siriuspy/idff/main.py index d70267f8e..0ec299584 100644 --- a/siriuspy/siriuspy/idff/main.py +++ b/siriuspy/siriuspy/idff/main.py @@ -339,6 +339,8 @@ def _update_corr_status(self): def _update_corr_setpoints(self): """Update corrector setpoint PVs.""" + if self._corr_setpoints is None: + return setpoints, *_ = self._corr_setpoints idff = self._idff corrnames = idff.chnames + idff.cvnames + idff.qsnames From c819ef9785722c6f9f3ab20b9a3ac47989a63401 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 13:28:05 -0300 Subject: [PATCH 254/309] DEV.FAMBPM.MNT: Add logging message when wait_update_mturn_signals is not updated. --- siriuspy/siriuspy/devices/bpm_fam.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 97ff2578b..bf9af8a28 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -498,6 +498,7 @@ def wait_update_mturn_signals(self, timeout=10) -> int: errors = _np.all(_np.equal(sig, sig0), axis=1) if not _np.any(errors): return 0 + _log.debug('Signals did not update yet. Trying again.') _time.sleep(0.1) timeout -= _time.time() - t00 From c3b2e69e5ef4bb655a2c12a2f19db6c42f504fa1 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 18 Dec 2023 13:39:08 -0300 Subject: [PATCH 255/309] Fix IDFF --- siriuspy/siriuspy/idff/csdev.py | 13 +++++++------ siriuspy/siriuspy/idff/main.py | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/siriuspy/siriuspy/idff/csdev.py b/siriuspy/siriuspy/idff/csdev.py index a6600f8f9..e65de0f90 100644 --- a/siriuspy/siriuspy/idff/csdev.py +++ b/siriuspy/siriuspy/idff/csdev.py @@ -35,6 +35,7 @@ class IDFFConst(_csdev.Const): DEFAULT_LOOP_FREQ = 10 # [Hz] DEFAULT_LOOP_STATE = LoopState.Open DEFAULT_CONTROL_QS = _csdev.Const.DsblEnbl.Enbl + DEFAULT_CORR_PREC = 4 def __init__(self, idname): """Init.""" @@ -80,16 +81,16 @@ def get_propty_database(self): 'value': self.StsLblsCorr._fields}, 'CorrCH1Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, 'CorrCH2Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, 'CorrCV1Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, 'CorrCV2Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, } if self.has_qscorrs: dbase.update({ @@ -103,10 +104,10 @@ def get_propty_database(self): 'unit': 'If QS are included in loop'}, 'CorrQS1Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, 'CorrQS2Current-Mon': { 'type': 'float', 'value': 0, - 'unit': 'A', 'prec': 3}, + 'unit': 'A', 'prec': self.DEFAULT_CORR_PREC}, }) dbase = _csdev.add_pvslist_cte(dbase) return dbase diff --git a/siriuspy/siriuspy/idff/main.py b/siriuspy/siriuspy/idff/main.py index 0ec299584..85f8af76e 100644 --- a/siriuspy/siriuspy/idff/main.py +++ b/siriuspy/siriuspy/idff/main.py @@ -189,6 +189,7 @@ def quit(self, value): self._quit = value def main_idff_loop(self): + """Main IDFF loop.""" while not self._quit: # updating interval tplanned = 1.0/self._loop_freq @@ -204,14 +205,14 @@ def main_idff_loop(self): # update polarization state self._do_update_polarization() + # correctors value calculation + self._do_update_correctors() + # return if loop is not closed if not self._loop_state: self._do_sleep(_t0, tplanned) continue - # correctors value calculation - self._do_update_correctors() - # setpoints implementation if self._corr_setpoints: self._do_implement_correctors() @@ -313,7 +314,7 @@ def _do_implement_correctors(self): corrdevs = self._idff.chdevs + self._idff.cvdevs try: # use PS IOCs (IDFF) to implement setpoints - setpoints = self._corr_setpoints + setpoints, *_ = self._corr_setpoints self._idff.implement_setpoints( setpoints=setpoints, corrdevs=corrdevs) From 7cc5881424f2a24fc73503f5230a5224734402bf Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 13:39:32 -0300 Subject: [PATCH 256/309] DEV.BPM.STY: Fix imports order of module. --- siriuspy/siriuspy/devices/bpm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm.py b/siriuspy/siriuspy/devices/bpm.py index 7507107ec..e460f1a6d 100644 --- a/siriuspy/siriuspy/devices/bpm.py +++ b/siriuspy/siriuspy/devices/bpm.py @@ -1,13 +1,14 @@ """BPM devices.""" import time as _time -# from threading import Event as _Flag import numpy as _np -from .device import Device as _Device from ..diagbeam.bpm.csdev import Const as _csbpm from ..search import BPMSearch as _BPMSearch +from .device import Device as _Device + +# from threading import Event as _Flag class BPM(_Device): From 3547ce3080a945d48d8453e3afe411cf017929e0 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 13:40:04 -0300 Subject: [PATCH 257/309] DEV.FAMBPM.MNT: Turn on auto_monitor of acquisition signals in use. --- siriuspy/siriuspy/devices/bpm_fam.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index bf9af8a28..306b8681b 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -74,6 +74,12 @@ def __init__( dev, auto_monitor_mon=False, ispost_mortem=ispost_mortem, props2init=props2init) for dev in bpm_names] + for bpm in self.bpms: + for sig in self.mturn_signals2acq: + sig = 'SUM' if sig.upper() == 'S' else sig.upper() + pv = bpm.pv_object(f'GEN_{sig}ArrayData') + pv.auto_monitor = True + super().__init__(self.bpms[:], devname=devname) self._bpm_names = bpm_names self._csbpm = self.bpms[0].csdata From 36ae8477e26489a1b84bf0bd4c6b7d751a18cd48 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 13:56:05 -0300 Subject: [PATCH 258/309] DEV.FAMBPM.MNT: Turn on auto_monitor of acquisition signals in use. Move control to mturn_signals2acq setter method. --- siriuspy/siriuspy/devices/bpm_fam.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 306b8681b..e86b5e82c 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -69,16 +69,13 @@ def __init__( filters={'sec': devname.sec, 'dev': devname.dev}) self._ispost_mortem = ispost_mortem - self._mturn_signals2acq = list(mturn_signals2acq) + self._mturn_signals2acq = '' self.bpms = [BPM( dev, auto_monitor_mon=False, ispost_mortem=ispost_mortem, props2init=props2init) for dev in bpm_names] - for bpm in self.bpms: - for sig in self.mturn_signals2acq: - sig = 'SUM' if sig.upper() == 'S' else sig.upper() - pv = bpm.pv_object(f'GEN_{sig}ArrayData') - pv.auto_monitor = True + # use property here to ensure auto_monitor + self.mturn_signals2acq = list(mturn_signals2acq) super().__init__(self.bpms[:], devname=devname) self._bpm_names = bpm_names @@ -115,7 +112,9 @@ def mturn_signals2acq(self, sigs): diff = set(sigs) - set(self.ALL_MTURN_SIGNALS2ACQ) if diff: raise ValueError('The following signals do not exist: '+str(diff)) + self._configure_automonitor_acquisition_pvs(state=False) self._mturn_signals2acq = sigs + self._configure_automonitor_acquisition_pvs(state=True) def set_attenuation(self, value=RFFEATT_MAX, timeout=TIMEOUT): """.""" @@ -553,6 +552,13 @@ def wait_update_mturn(self, timeout=10) -> int: _log.debug("Data updated (ETA: %.3fs).", dtime) return ret + # ---------------------- Auxiliary methods ------------------------------ + def _configure_automonitor_acquisition_pvs(self, state): + for bpm in self.bpms: + for sig in self._mturn_signals2acq: + sig = 'SUM' if sig.upper() == 'S' else sig.upper() + bpm.pv_object(f'GEN_{sig}ArrayData').auto_monitor = state + def _set_mturn_flag(self, pvname, **kwargs): _ = kwargs self._mturn_flags[pvname].set() From 08dc6f761895fd06da22e31c52ac81c8f0e8cae6 Mon Sep 17 00:00:00 2001 From: Fernando Date: Mon, 18 Dec 2023 17:28:08 -0300 Subject: [PATCH 259/309] DEV.FAMBPM.DOC: Improve docstring of some methods. --- siriuspy/siriuspy/devices/bpm_fam.py | 31 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index e86b5e82c..89dc4c2e0 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -441,13 +441,16 @@ def wait_update_mturn_timestamps(self, timeout=10) -> int: timeout (int, optional): Waiting timeout. Defaults to 10. Returns: - float: code describing what happened: + int|float: code describing what happened: -2: size of timestamps changed in relation to initial timestamp -1: initial timestamps were not defined; =0: data updated. - >0: index of the first BPM which did not update plus 1. - X.[1-N]: The fractional part indicates which signal, from 1 to - N, that didn't update. + >0: timeout waiting BPMs. The returned value is a float of + form X.Y, where: + X: The integer part indicates the index of the first + BPM which did not update plus 1. + Y: The fractional part indicates which signal, from + 1 to N, that didn't update. """ if self._initial_timestamps is None: @@ -482,13 +485,16 @@ def wait_update_mturn_signals(self, timeout=10) -> int: timeout (int, optional): Waiting timeout. Defaults to 10. Returns: - int: code describing what happened: + int|float: code describing what happened: -2: size of signals changed in relation to initial signals -1: initial signals were not defined; =0: signals updated. - >0: index of the first BPM which did not update plus 1. - X.[1-N]: The fractional part indicates which signal, from 1 to - N, that didn't update. + >0: timeout waiting BPMs. The returned value is a float of + form X.Y, where: + X: The integer part indicates the index of the first + BPM which did not update plus 1. + Y: The fractional part indicates which signal, from + 1 to N, that didn't update. """ if self._initial_signals is None: @@ -523,9 +529,12 @@ def wait_update_mturn(self, timeout=10) -> int: -2: size of timestamps changed in relation to initial timestamp -1: initial timestamps were not defined; =0: data updated. - >0: index of the first BPM which did not update plus 1. - X.[1-N]: The fractional part indicates which signal, from 1 to - N, that didn't update. + >0: timeout waiting BPMs. The returned value is a float of + form X.Y, where: + X: The integer part indicates the index of the first + BPM which did not update plus 1. + Y: The fractional part indicates which signal, from + 1 to N, that didn't update. """ t00 = _time.time() From 5fafbcf25022817acb3332788ddc4aabc4596af2 Mon Sep 17 00:00:00 2001 From: Fernando Date: Tue, 19 Dec 2023 10:19:15 -0300 Subject: [PATCH 260/309] INJCTRL.STY: Adapt bias_feedback to ruff formatter style. --- siriuspy/siriuspy/injctrl/bias_feedback.py | 233 +++++++++++---------- 1 file changed, 121 insertions(+), 112 deletions(-) diff --git a/siriuspy/siriuspy/injctrl/bias_feedback.py b/siriuspy/siriuspy/injctrl/bias_feedback.py index 69f14b84e..598b6fb27 100644 --- a/siriuspy/siriuspy/injctrl/bias_feedback.py +++ b/siriuspy/siriuspy/injctrl/bias_feedback.py @@ -1,15 +1,15 @@ """.""" import logging as _log -from epics.ca import CAThread as _Thread +import GPy as gpy import numpy as _np +from epics.ca import CAThread as _Thread from numpy.polynomial import polynomial as _np_poly -import GPy as gpy from .csdev import Const as _Const, get_biasfb_database as _get_database -class BiasFeedback(): +class BiasFeedback: """.""" def __init__(self, injctrl): @@ -17,66 +17,68 @@ def __init__(self, injctrl): db_ = _get_database() self.database = db_ self._injctrl = injctrl - self.loop_state = db_['BiasFBLoopState-Sel']['value'] + self.loop_state = db_["BiasFBLoopState-Sel"]["value"] self.already_set = False - self.min_bias_voltage = db_['BiasFBMinVoltage-SP']['value'] # [V] - self.max_bias_voltage = db_['BiasFBMaxVoltage-SP']['value'] # [V] + self.min_bias_voltage = db_["BiasFBMinVoltage-SP"]["value"] # [V] + self.max_bias_voltage = db_["BiasFBMaxVoltage-SP"]["value"] # [V] - self.model_type = db_['BiasFBModelType-Sel']['value'] - self.model_max_num_points = db_['BiasFBModelMaxNrPts-SP']['value'] - self.model_auto_fit_rate = db_[ - 'BiasFBModelAutoFitEveryNrPts-SP']['value'] - self.model_auto_fit = db_['BiasFBModelAutoFitParams-Sel']['value'] - self.model_update_data = db_['BiasFBModelUpdateData-Sel']['value'] + self.model_type = db_["BiasFBModelType-Sel"]["value"] + self.model_max_num_points = db_["BiasFBModelMaxNrPts-SP"]["value"] + self.model_auto_fit_rate = db_["BiasFBModelAutoFitEveryNrPts-SP"][ + "value" + ] + self.model_auto_fit = db_["BiasFBModelAutoFitParams-Sel"]["value"] + self.model_update_data = db_["BiasFBModelUpdateData-Sel"]["value"] - self.linmodel_angcoeff = db_[ - 'BiasFBLinModAngCoeff-SP']['value'] # [V/mA] - self.linmodel_offcoeff = db_[ - 'BiasFBLinModOffCoeff-SP']['value'] # [V] + # [V/mA]: + self.linmodel_angcoeff = db_["BiasFBLinModAngCoeff-SP"]["value"] + self.linmodel_offcoeff = db_["BiasFBLinModOffCoeff-SP"]["value"] # [V] self._npts_after_fit = 0 self.bias_data = _np.array( - db_['BiasFBModelDataBias-Mon']['value'], dtype=float) + db_["BiasFBModelDataBias-Mon"]["value"], dtype=float + ) self.injc_data = _np.array( - db_['BiasFBModelDataInjCurr-Mon']['value'], dtype=float) + db_["BiasFBModelDataInjCurr-Mon"]["value"], dtype=float + ) self.gpmodel = None self._initialize_models() self.do_update_models = False - pv_ = self._injctrl.currinfo_dev.pv_object('InjCurr-Mon') + pv_ = self._injctrl.currinfo_dev.pv_object("InjCurr-Mon") pv_.auto_monitor = True pv_.add_callback(self._callback_to_thread) # pvname to write method map self.map_pv2write = { - 'LoopState-Sel': self.set_loop_state, - 'MinVoltage-SP': self.set_min_voltage, - 'MaxVoltage-SP': self.set_max_voltage, - 'ModelType-Sel': self.set_model_type, - 'ModelMaxNrPts-SP': self.set_max_num_pts, - 'ModelFitParamsNow-Cmd': self.cmd_fit_params, - 'ModelAutoFitParams-Sel': self.set_auto_fit, - 'ModelAutoFitEveryNrPts-SP': self.set_auto_fit_rate, - 'ModelUpdateData-Sel': self.set_update_data, - 'ModelDataBias-SP': self.set_data_bias, - 'ModelDataInjCurr-SP': self.set_data_injcurr, - 'LinModAngCoeff-SP': self.set_lin_ang_coeff, - 'LinModOffCoeff-SP': self.set_lin_off_coeff, - 'GPModNoiseStd-SP': self.set_gp_noise_std, - 'GPModKernStd-SP': self.set_gp_kern_std, - 'GPModKernLenScl-SP': self.set_gp_kern_leng, - 'GPModNoiseStdFit-Sel': self.set_gp_noise_std_fit, - 'GPModKernStdFit-Sel': self.set_gp_kern_std_fit, - 'GPModKernLenSclFit-Sel': self.set_gp_kern_leng_fit, - } + "LoopState-Sel": self.set_loop_state, + "MinVoltage-SP": self.set_min_voltage, + "MaxVoltage-SP": self.set_max_voltage, + "ModelType-Sel": self.set_model_type, + "ModelMaxNrPts-SP": self.set_max_num_pts, + "ModelFitParamsNow-Cmd": self.cmd_fit_params, + "ModelAutoFitParams-Sel": self.set_auto_fit, + "ModelAutoFitEveryNrPts-SP": self.set_auto_fit_rate, + "ModelUpdateData-Sel": self.set_update_data, + "ModelDataBias-SP": self.set_data_bias, + "ModelDataInjCurr-SP": self.set_data_injcurr, + "LinModAngCoeff-SP": self.set_lin_ang_coeff, + "LinModOffCoeff-SP": self.set_lin_off_coeff, + "GPModNoiseStd-SP": self.set_gp_noise_std, + "GPModKernStd-SP": self.set_gp_kern_std, + "GPModKernLenScl-SP": self.set_gp_kern_leng, + "GPModNoiseStdFit-Sel": self.set_gp_noise_std_fit, + "GPModKernStdFit-Sel": self.set_gp_kern_std_fit, + "GPModKernLenSclFit-Sel": self.set_gp_kern_leng_fit, + } def init_database(self): """Set initial PV values.""" for key, pvdbase in self.database.items(): pvname = key.split(_Const.BIASFB_PROPTY_PREFIX)[1] - self.run_callbacks(pvname, pvdbase['value']) + self.run_callbacks(pvname, pvdbase["value"]) @property def use_gpmodel(self): @@ -95,13 +97,14 @@ def linmodel_coeffs_inverse(self): """.""" ang = self.linmodel_angcoeff off = self.linmodel_offcoeff - return (-off/ang, 1/ang) + return (-off / ang, 1 / ang) def get_delta_current_per_pulse( - self, per=1, nrpul=1, curr_avg=100, curr_now=99.5, ltime=17*3600): + self, per=1, nrpul=1, curr_avg=100, curr_now=99.5, ltime=17 * 3600 + ): """.""" ltime = max(_Const.BIASFB_MINIMUM_LIFETIME, ltime) - curr_tar = curr_avg / (1 - per/2/ltime) + curr_tar = curr_avg / (1 - per / 2 / ltime) dcurr = (curr_tar - curr_now) / nrpul return dcurr @@ -118,67 +121,68 @@ def run_callbacks(self, name, *args, **kwd): if self._injctrl.has_callbacks: self._injctrl.run_callbacks(name, *args, **kwd) return - self.database[name]['value'] = args[0] + self.database[name]["value"] = args[0] def update_log(self, msg): """.""" - self._injctrl.run_callbacks('Log-Mon', msg) + self._injctrl.run_callbacks("Log-Mon", msg) # ###################### Setter methods for IOC ###################### def set_loop_state(self, value): """.""" self.loop_state = bool(value) - self.run_callbacks('LoopState-Sts', value) + self.run_callbacks("LoopState-Sts", value) return True def set_min_voltage(self, value): """.""" self.min_bias_voltage = value self._update_models() - self.run_callbacks('MinVoltage-RB', value) + self.run_callbacks("MinVoltage-RB", value) return True def set_max_voltage(self, value): """.""" self.max_bias_voltage = value self._update_models() - self.run_callbacks('MaxVoltage-RB', value) + self.run_callbacks("MaxVoltage-RB", value) return True def set_model_type(self, value): """.""" self.model_type = value - self.run_callbacks('ModelType-Sts', value) + self.run_callbacks("ModelType-Sts", value) return True def set_max_num_pts(self, value): """.""" self.model_max_num_points = int(value) self._update_models() - self.run_callbacks('ModelMaxNrPts-RB', value) + self.run_callbacks("ModelMaxNrPts-RB", value) return True def cmd_fit_params(self, value): """.""" + _ = value self._update_models(force_optimize=True) return True def set_auto_fit(self, value): """.""" self.model_auto_fit = bool(value) - self.run_callbacks('ModelAutoFitParams-Sts', value) + self.run_callbacks("ModelAutoFitParams-Sts", value) return True def set_auto_fit_rate(self, value): """.""" self.model_auto_fit_rate = int(value) - self.run_callbacks('ModelAutoFitEveryNrPts-RB', value) + self.run_callbacks("ModelAutoFitEveryNrPts-RB", value) return True def set_update_data(self, value): """.""" self.model_update_data = bool(value) - self.run_callbacks('ModelUpdateData-Sts', value) + self.run_callbacks("ModelUpdateData-Sts", value) return True def set_data_bias(self, value): @@ -186,13 +190,13 @@ def set_data_bias(self, value): self.bias_data = _np.array(value) max_ = _Const.BIASFB_MAX_DATA_SIZE if self.bias_data.size > max_: - msg = f'WARN: Bias data is too big (>{max_:d}). ' - msg += 'Trimming first points.' + msg = f"WARN: Bias data is too big (>{max_:d}). " + msg += "Trimming first points." _log.warning(msg) self.update_log(msg) self.bias_data = self.bias_data[-max_:] self._update_models() - self.run_callbacks('ModelDataBias-RB', value) + self.run_callbacks("ModelDataBias-RB", value) return True def set_data_injcurr(self, value): @@ -200,48 +204,48 @@ def set_data_injcurr(self, value): self.injc_data = _np.array(value) max_ = _Const.BIASFB_MAX_DATA_SIZE if self.injc_data.size > max_: - msg = f'WARN: InjCurr data is too big (>{max_:d}). ' - msg += 'Trimming first points.' + msg = f"WARN: InjCurr data is too big (>{max_:d}). " + msg += "Trimming first points." _log.warning(msg) self.update_log(msg) self.injc_data = self.injc_data[-max_:] self._update_models() - self.run_callbacks('ModelDataInjCurr-RB', value) + self.run_callbacks("ModelDataInjCurr-RB", value) return True def set_lin_ang_coeff(self, value): """.""" self.linmodel_angcoeff = value self._update_models() - self.run_callbacks('LinModAngCoeff-RB', value) + self.run_callbacks("LinModAngCoeff-RB", value) return True def set_lin_off_coeff(self, value): """.""" self.linmodel_offcoeff = value self._update_models() - self.run_callbacks('LinModOffCoeff-RB', value) + self.run_callbacks("LinModOffCoeff-RB", value) return True def set_gp_noise_std(self, value): """.""" self.gpmodel.likelihood.variance = value**2 self._update_models() - self.run_callbacks('GPModNoiseStd-RB', value) + self.run_callbacks("GPModNoiseStd-RB", value) return True def set_gp_kern_std(self, value): """.""" self.gpmodel.kern.variance = value**2 self._update_models() - self.run_callbacks('GPModKernStd-RB', value) + self.run_callbacks("GPModKernStd-RB", value) return True def set_gp_kern_leng(self, value): """.""" self.gpmodel.kern.lengthscale = value self._update_models() - self.run_callbacks('GPModKernLenScl-RB', value) + self.run_callbacks("GPModKernLenScl-RB", value) return True def set_gp_noise_std_fit(self, value): @@ -250,7 +254,7 @@ def set_gp_noise_std_fit(self, value): self.gpmodel.likelihood.variance.unfix() else: self.gpmodel.likelihood.variance.fix() - self.run_callbacks('GPModNoiseStdFit-Sts', value) + self.run_callbacks("GPModNoiseStdFit-Sts", value) return True def set_gp_kern_std_fit(self, value): @@ -259,7 +263,7 @@ def set_gp_kern_std_fit(self, value): self.gpmodel.kern.variance.unfix() else: self.gpmodel.kern.variance.fix() - self.run_callbacks('GPModKernStdFit-Sts', value) + self.run_callbacks("GPModKernStdFit-Sts", value) return True def set_gp_kern_leng_fit(self, value): @@ -268,7 +272,7 @@ def set_gp_kern_leng_fit(self, value): self.gpmodel.kern.lengthscale.unfix() else: self.gpmodel.kern.lengthscale.fix() - self.run_callbacks('GPModKernLenSclFit-Sts', value) + self.run_callbacks("GPModKernLenSclFit-Sts", value) return True # ############ Auxiliary Methods ############ @@ -282,37 +286,40 @@ def _initialize_models(self): self.bias_data = _np.linspace( self.min_bias_voltage, self.max_bias_voltage, - self.model_max_num_points) + self.model_max_num_points, + ) self.injc_data = _np_poly.polyval( - self.bias_data, self.linmodel_coeffs_inverse) + self.bias_data, self.linmodel_coeffs_inverse + ) x = self.bias_data[:, None].copy() y = self.injc_data[:, None].copy() kernel = gpy.kern.RBF(input_dim=1) - db_ = self.database['BiasFBGPModKernStd-RB'] - kernel.variance.constrain_bounded(db_['lolim']**2, db_['hilim']**2) - kernel.variance = db_['value']**2 - if bool(self.database['BiasFBGPModKernStdFit-Sts']['value']): + db_ = self.database["BiasFBGPModKernStd-RB"] + kernel.variance.constrain_bounded(db_["lolim"] ** 2, db_["hilim"] ** 2) + kernel.variance = db_["value"] ** 2 + if bool(self.database["BiasFBGPModKernStdFit-Sts"]["value"]): kernel.variance.unfix() else: kernel.variance.fix() - db_ = self.database['BiasFBGPModKernLenScl-RB'] - kernel.lengthscale.constrain_bounded(db_['lolim'], db_['hilim']) - kernel.lengthscale = db_['value'] - if bool(self.database['BiasFBGPModKernLenSclFit-Sts']['value']): + db_ = self.database["BiasFBGPModKernLenScl-RB"] + kernel.lengthscale.constrain_bounded(db_["lolim"], db_["hilim"]) + kernel.lengthscale = db_["value"] + if bool(self.database["BiasFBGPModKernLenSclFit-Sts"]["value"]): kernel.lengthscale.unfix() else: kernel.lengthscale.fix() gpmodel = gpy.models.GPRegression(x, y, kernel) - db_ = self.database['BiasFBGPModNoiseStd-RB'] + db_ = self.database["BiasFBGPModNoiseStd-RB"] gpmodel.likelihood.variance.constrain_bounded( - db_['lolim']**2, db_['hilim']**2) - gpmodel.likelihood.variance = db_['value']**2 - if bool(self.database['BiasFBGPModNoiseStdFit-Sts']['value']): + db_["lolim"] ** 2, db_["hilim"] ** 2 + ) + gpmodel.likelihood.variance = db_["value"] ** 2 + if bool(self.database["BiasFBGPModNoiseStdFit-Sts"]["value"]): gpmodel.likelihood.variance.unfix() else: gpmodel.likelihood.variance.fix() @@ -322,7 +329,7 @@ def _initialize_models(self): def _update_data(self, **kwgs): bias = self._injctrl.egun_dev.bias.voltage - dcurr = kwgs['value'] + dcurr = kwgs["value"] if None in {bias, dcurr}: return @@ -331,8 +338,8 @@ def _update_data(self, **kwgs): if bias in xun: idx = (xun == bias).nonzero()[0][0] if cnts[idx] >= max(2, self.bias_data.size // 5): - msg = 'WARN: Too many data with this abscissa. ' - msg += 'Discarding point.' + msg = "WARN: Too many data with this abscissa. " + msg += "Discarding point." _log.warning(msg) self.update_log(msg) return @@ -341,19 +348,19 @@ def _update_data(self, **kwgs): # Update models data self.bias_data = _np.r_[self.bias_data, bias] self.injc_data = _np.r_[self.injc_data, dcurr] - self.bias_data = self.bias_data[-_Const.BIASFB_MAX_DATA_SIZE:] - self.injc_data = self.injc_data[-_Const.BIASFB_MAX_DATA_SIZE:] + self.bias_data = self.bias_data[-_Const.BIASFB_MAX_DATA_SIZE :] + self.injc_data = self.injc_data[-_Const.BIASFB_MAX_DATA_SIZE :] self._update_models() def _update_models(self, force_optimize=False): x = _np.r_[self.bias_data, self.linmodel_offcoeff] y = _np.r_[self.injc_data, 0] - x = x[-self.model_max_num_points:] - y = y[-self.model_max_num_points:] + x = x[-self.model_max_num_points :] + y = y[-self.model_max_num_points :] if x.size != y.size: - msg = 'WARN: Arrays with incompatible sizes. ' - msg += 'Trimming first points of ' - msg += 'bias.' if x.size > y.size else 'injcurr.' + msg = "WARN: Arrays with incompatible sizes. " + msg += "Trimming first points of " + msg += "bias." if x.size > y.size else "injcurr." _log.warning(msg) self.update_log(msg) siz = min(x.size, y.size) @@ -361,8 +368,8 @@ def _update_models(self, force_optimize=False): y = y[-siz:] if x.size < 2: - msg = 'ERR: Too few data points. ' - msg += 'Skipping Model update.' + msg = "ERR: Too few data points. " + msg += "Skipping Model update." _log.error(msg) self.update_log(msg) return @@ -375,7 +382,8 @@ def _update_models(self, force_optimize=False): # Optimize Linear Model if do_opt and not self.use_gpmodel: self.linmodel_angcoeff = _np_poly.polyfit( - y, x - self.linmodel_offcoeff, deg=[1, ])[1] + y, x - self.linmodel_offcoeff, deg=[1] + )[1] self._npts_after_fit = 0 # update Gaussian Process Model data @@ -388,39 +396,40 @@ def _update_models(self, force_optimize=False): self.gpmodel.optimize_restarts(num_restarts=2, verbose=False) self._npts_after_fit = 0 - self.run_callbacks('ModelNrPtsAfterFit-Mon', self._npts_after_fit) + self.run_callbacks("ModelNrPtsAfterFit-Mon", self._npts_after_fit) self._update_predictions() def _update_predictions(self): gp_ = self.gpmodel self.run_callbacks( - 'GPModNoiseStd-Mon', float(gp_.likelihood.variance)**0.5) - self.run_callbacks('GPModKernStd-Mon', float(gp_.kern.variance)**0.5) - self.run_callbacks('GPModKernLenScl-Mon', float(gp_.kern.lengthscale)) - self.run_callbacks('LinModAngCoeff-Mon', self.linmodel_angcoeff) - self.run_callbacks('LinModOffCoeff-Mon', self.linmodel_offcoeff) + "GPModNoiseStd-Mon", float(gp_.likelihood.variance) ** 0.5 + ) + self.run_callbacks("GPModKernStd-Mon", float(gp_.kern.variance) ** 0.5) + self.run_callbacks("GPModKernLenScl-Mon", float(gp_.kern.lengthscale)) + self.run_callbacks("LinModAngCoeff-Mon", self.linmodel_angcoeff) + self.run_callbacks("LinModOffCoeff-Mon", self.linmodel_offcoeff) - self.run_callbacks('ModelDataBias-Mon', self.gpmodel.X.ravel()) - self.run_callbacks('ModelDataInjCurr-Mon', self.gpmodel.Y.ravel()) - self.run_callbacks('ModelNrPts-Mon', self.gpmodel.Y.size) + self.run_callbacks("ModelDataBias-Mon", self.gpmodel.X.ravel()) + self.run_callbacks("ModelDataInjCurr-Mon", self.gpmodel.Y.ravel()) + self.run_callbacks("ModelNrPts-Mon", self.gpmodel.Y.size) injcurr = _np.linspace(0, 1, 100) bias_lin = self._get_bias_voltage_linear_model(injcurr) bias_gp = self._get_bias_voltage_gpmodel(injcurr) - self.run_callbacks('LinModInferenceInjCurr-Mon', injcurr) - self.run_callbacks('LinModInferenceBias-Mon', bias_lin) - self.run_callbacks('GPModInferenceInjCurr-Mon', injcurr) - self.run_callbacks('GPModInferenceBias-Mon', bias_gp) + self.run_callbacks("LinModInferenceInjCurr-Mon", injcurr) + self.run_callbacks("LinModInferenceBias-Mon", bias_lin) + self.run_callbacks("GPModInferenceInjCurr-Mon", injcurr) + self.run_callbacks("GPModInferenceBias-Mon", bias_gp) bias = _np.linspace(self.min_bias_voltage, self.max_bias_voltage, 100) injc_lin = _np_poly.polyval(bias, self.linmodel_coeffs_inverse) injca_gp, injcs_gp = self._gpmodel_predict(bias) injcs_gp = _np.sqrt(injcs_gp) - self.run_callbacks('LinModPredBias-Mon', bias) - self.run_callbacks('LinModPredInjCurrAvg-Mon', injc_lin) - self.run_callbacks('GPModPredBias-Mon', bias) - self.run_callbacks('GPModPredInjCurrAvg-Mon', injca_gp.ravel()) - self.run_callbacks('GPModPredInjCurrStd-Mon', injcs_gp.ravel()) + self.run_callbacks("LinModPredBias-Mon", bias) + self.run_callbacks("LinModPredInjCurrAvg-Mon", injc_lin) + self.run_callbacks("GPModPredBias-Mon", bias) + self.run_callbacks("GPModPredInjCurrAvg-Mon", injca_gp.ravel()) + self.run_callbacks("GPModPredInjCurrStd-Mon", injcs_gp.ravel()) def _get_bias_voltage_gpmodel(self, dcurr): bias = self._gpmodel_infer_newx(_np.array(dcurr, ndmin=1)) From f785edee20a2f526f1c33423d9eb1b06834fb205 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 3 Jan 2024 09:32:12 -0300 Subject: [PATCH 261/309] MNT: change default value of env variables to use 10.0.38 subnet --- siriuspy/siriuspy/envars.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/envars.py b/siriuspy/siriuspy/envars.py index 914837f64..a899d69a2 100644 --- a/siriuspy/siriuspy/envars.py +++ b/siriuspy/siriuspy/envars.py @@ -43,19 +43,19 @@ 'SIRIUS_URL_CABLES', default='http://cables:8086') SRVURL_CSCONSTS = _os.environ.get( 'SIRIUS_URL_CONSTS', - default='http://10.128.255.4/control-system-constants') + default='http://10.0.38.59/control-system-constants') SRVURL_CSCONSTS_2 = _os.environ.get( 'SIRIUS_URL_CONSTS_2', - default='http://10.128.255.3/control-system-constants') + default='http://10.0.38.46/control-system-constants') SRVURL_LOGBOOK = _os.environ.get( 'SIRIUS_URL_LOGBOOK', default='http://10.0.38.42/Olog') SRVURL_CONFIGDB = _os.environ.get( 'SIRIUS_URL_CONFIGDB', - default='http://10.128.255.4/config-db') + default='http://10.0.38.59/config-db') SRVURL_CONFIGDB_2 = _os.environ.get( 'SIRIUS_URL_CONFIGDB_2', - default='http://10.128.255.3/config-db') + default='http://10.0.38.46/config-db') SRVURL_ARCHIVER = _os.environ.get( 'SIRIUS_URL_ARCHIVER', default='https://10.0.38.42') From 587999932eb1b780879243833c1e7e631a3f8f0e Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 3 Jan 2024 16:48:54 -0300 Subject: [PATCH 262/309] DEV.FAMBPM.BUG: Fix problem in checking signals for update. --- siriuspy/siriuspy/devices/bpm_fam.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 89dc4c2e0..8c9631da3 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -392,7 +392,9 @@ def set_switching_mode(self, mode='direct'): def update_mturn_initial_signals(self): """Call this method before acquisition to get orbit for comparison.""" - self._initial_signals = _np.array(self.get_mturn_signals()) + sig = _np.array(self.get_mturn_signals()) + sig = sig if sig.shape[1] != 0 else None + self._initial_signals = sig def update_mturn_initial_timestamps(self): """Call this method before acquisition to get orbit for comparison.""" @@ -486,7 +488,7 @@ def wait_update_mturn_signals(self, timeout=10) -> int: Returns: int|float: code describing what happened: - -2: size of signals changed in relation to initial signals + -2: size of signals is 0; -1: initial signals were not defined; =0: signals updated. >0: timeout waiting BPMs. The returned value is a float of @@ -504,9 +506,10 @@ def wait_update_mturn_signals(self, timeout=10) -> int: while timeout > 0: t00 = _time.time() sig = _np.array(self.get_mturn_signals()) - if sig.shape != sig0.shape: + siz = min(sig.shape[1], sig0.shape[1]) + if siz == 0: return -2 - errors = _np.all(_np.equal(sig, sig0), axis=1) + errors = _np.all(_np.equal(sig[:, :siz], sig0[:, :siz]), axis=1) if not _np.any(errors): return 0 _log.debug('Signals did not update yet. Trying again.') From 94acc1015ce2d7ce7ddd0f93af11a83d69099aa6 Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 3 Jan 2024 16:50:42 -0300 Subject: [PATCH 263/309] DEV.FAMBPM.MNT: Refactor code. --- siriuspy/siriuspy/devices/bpm_fam.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 8c9631da3..4f5494c60 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -393,8 +393,7 @@ def set_switching_mode(self, mode='direct'): def update_mturn_initial_signals(self): """Call this method before acquisition to get orbit for comparison.""" sig = _np.array(self.get_mturn_signals()) - sig = sig if sig.shape[1] != 0 else None - self._initial_signals = sig + self._initial_signals = sig if sig.shape[1] != 0 else None def update_mturn_initial_timestamps(self): """Call this method before acquisition to get orbit for comparison.""" From bcc5ca01ad1bd5ef718717fc4341eebeb1408f38 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 3 Jan 2024 17:27:18 -0300 Subject: [PATCH 264/309] Add image projection PVs to ImgProc --- siriuspy/siriuspy/dvfimgproc/csdev.py | 8 +++++++- siriuspy/siriuspy/dvfimgproc/main.py | 2 ++ siriuspy/siriuspy/dvfimgproc/meas.py | 7 ++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/dvfimgproc/csdev.py b/siriuspy/siriuspy/dvfimgproc/csdev.py index d38ac05a0..8bda01401 100644 --- a/siriuspy/siriuspy/dvfimgproc/csdev.py +++ b/siriuspy/siriuspy/dvfimgproc/csdev.py @@ -26,6 +26,8 @@ class Constants(_csdev.Const): NoYes = _get_namedtuple('NoYes', _et.NO_YES) StsLblsDVF = _get_namedtuple('StsLblsDVF', _et.STS_LBLS_DVF) + DEF_DVFSTATUS = 0b11111111 + def __init__(self, devname): """.""" self._devname = devname @@ -141,6 +143,10 @@ def _get_roi_db(self): 'ImgROI' + axis + 'FWHM' + mon_: { 'type': 'int', 'unit': 'px' }, + 'ImgROI' + axis + 'Proj' + mon_: { + 'type': 'float', 'count': 1, + 'unit': 'intensity', + }, 'ImgROI' + axis + 'UpdateWithFWHMFactor-SP': { 'type': 'float', 'value': 2.0, 'unit': 'fwhm_factor', 'prec': 3, 'lolim': 0, 'hilim': 2000, @@ -227,7 +233,7 @@ def _get_others_db(self): 'type': 'int', 'value': 0, }, 'ImgDVFStatus-Mon': { - 'type': 'int', 'value': 0b11111111, + 'type': 'int', 'value': self.DEF_DVFSTATUS, }, 'ImgDVFStatusLabels-Cte': { 'type': 'string', 'count': len(self.StsLblsDVF._fields), diff --git a/siriuspy/siriuspy/dvfimgproc/main.py b/siriuspy/siriuspy/dvfimgproc/main.py index 42f92700a..2a79d5e0f 100644 --- a/siriuspy/siriuspy/dvfimgproc/main.py +++ b/siriuspy/siriuspy/dvfimgproc/main.py @@ -34,6 +34,7 @@ class App: 'ImgROIX-RB': ('fitx', 'roi'), 'ImgROIXCenter-Mon': ('fitx', 'roi_center'), 'ImgROIXFWHM-Mon': ('fitx', 'roi_fwhm'), + 'ImgROIXProj-Mon': ('fitx', 'roi_proj'), # --- roix_fit --- 'ImgROIXFitAmplitude-Mon': ('fitx', 'roi_amplitude'), 'ImgROIXFitMean-Mon': ('fitx', 'roi_mean'), @@ -43,6 +44,7 @@ class App: 'ImgROIY-RB': ('fity', 'roi'), 'ImgROIYCenter-Mon': ('fity', 'roi_center'), 'ImgROIYFWHM-Mon': ('fity', 'roi_fwhm'), + 'ImgROIYProj-Mon': ('fity', 'roi_proj'), # --- roiy_fit --- 'ImgROIYFitAmplitude-Mon': ('fity', 'roi_amplitude'), 'ImgROIYFitMean-Mon': ('fity', 'roi_mean'), diff --git a/siriuspy/siriuspy/dvfimgproc/meas.py b/siriuspy/siriuspy/dvfimgproc/meas.py index e35f964d3..3023549a0 100644 --- a/siriuspy/siriuspy/dvfimgproc/meas.py +++ b/siriuspy/siriuspy/dvfimgproc/meas.py @@ -17,10 +17,11 @@ class MeasDVF(): MIN_ROI_SIZE = 5 # [pixels] def __init__( - self, devname, fwhmx_factor, fwhmy_factor, roi_with_fwhm, + self, const, fwhmx_factor, fwhmy_factor, roi_with_fwhm, intensity_threshold, use_svd4theta, callback=None): """.""" - self._devname = devname + self._const = const + self._devname = const.devname self._callback = callback self._status = MeasDVF.STATUS_SUCCESS self._dvf = None @@ -58,7 +59,7 @@ def dvf(self): @property def status_dvf(self): """.""" - status = 0b00000000 + status = 0 * self._const.DEF_DVFSTATUS status |= ((1 if not self.dvf.connected else 0) << 0) status |= ((1 if not self.dvf.acquisition_status else 0) << 1) return status From 64cb4115e3d5fb60550e554b6237603d1cae9e16 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 3 Jan 2024 17:37:28 -0300 Subject: [PATCH 265/309] Fix _create_meas in imgproc --- siriuspy/siriuspy/dvfimgproc/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/dvfimgproc/main.py b/siriuspy/siriuspy/dvfimgproc/main.py index 2a79d5e0f..3f8532635 100644 --- a/siriuspy/siriuspy/dvfimgproc/main.py +++ b/siriuspy/siriuspy/dvfimgproc/main.py @@ -289,7 +289,7 @@ def _create_meas(self): # create object meas = MeasDVF( - self.const.devname, + self.const, fwhmx_factor=fwhmx_factor, fwhmy_factor=fwhmy_factor, roi_with_fwhm=roi_with_fwhm, intensity_threshold=intensity_threshold, From 390164a5e45ac488219a32611c24bda5dc40cb97 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 4 Jan 2024 08:53:34 -0300 Subject: [PATCH 266/309] Update imgproc PV type --- siriuspy/siriuspy/dvfimgproc/csdev.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/dvfimgproc/csdev.py b/siriuspy/siriuspy/dvfimgproc/csdev.py index 8bda01401..98a1cda78 100644 --- a/siriuspy/siriuspy/dvfimgproc/csdev.py +++ b/siriuspy/siriuspy/dvfimgproc/csdev.py @@ -144,8 +144,7 @@ def _get_roi_db(self): 'type': 'int', 'unit': 'px' }, 'ImgROI' + axis + 'Proj' + mon_: { - 'type': 'float', 'count': 1, - 'unit': 'intensity', + 'type': 'int', 'count': 2, 'unit': 'intensity', }, 'ImgROI' + axis + 'UpdateWithFWHMFactor-SP': { 'type': 'float', 'value': 2.0, 'unit': 'fwhm_factor', From d134d4ba0e13e75833e6a02c567463b5b9a04093 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 4 Jan 2024 10:48:10 -0300 Subject: [PATCH 267/309] Change PV update in ImgProc when there is no beam --- siriuspy/siriuspy/dvfimgproc/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/dvfimgproc/main.py b/siriuspy/siriuspy/dvfimgproc/main.py index 3f8532635..3fc0aa16a 100644 --- a/siriuspy/siriuspy/dvfimgproc/main.py +++ b/siriuspy/siriuspy/dvfimgproc/main.py @@ -202,7 +202,6 @@ def update_driver(self): if not self.meas.image2dfit.is_with_image: self._write_pv('ImgIsWithBeam-Mon', 0) - return invalid_fitx, invalid_fity = [False]*2 for pvname, attr in App._MON_PVS_2_IMGFIT.items(): @@ -211,6 +210,9 @@ def update_driver(self): if not self.meas.update_roi_with_fwhm: continue + if 'Fit' in pvname: + return + # get image attribute value value = self._conv_imgattr2value(attr) if value is None: From bfb83e687e2dde359a0f01fb7ad42b4426b8d0d1 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 4 Jan 2024 10:52:29 -0300 Subject: [PATCH 268/309] Fix last commit --- siriuspy/siriuspy/dvfimgproc/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/dvfimgproc/main.py b/siriuspy/siriuspy/dvfimgproc/main.py index 3fc0aa16a..7f4a6e018 100644 --- a/siriuspy/siriuspy/dvfimgproc/main.py +++ b/siriuspy/siriuspy/dvfimgproc/main.py @@ -210,7 +210,7 @@ def update_driver(self): if not self.meas.update_roi_with_fwhm: continue - if 'Fit' in pvname: + if not self.meas.image2dfit.is_with_image and 'Fit' in pvname: return # get image attribute value From 2fffb7d491ff5fd58bd0925baeec8ca0cd063288 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 4 Jan 2024 12:54:36 -0300 Subject: [PATCH 269/309] Fix ImgProc PVs ImgROI*Proj-Mon --- siriuspy/siriuspy/dvfimgproc/csdev.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/dvfimgproc/csdev.py b/siriuspy/siriuspy/dvfimgproc/csdev.py index 98a1cda78..dd6a593a7 100644 --- a/siriuspy/siriuspy/dvfimgproc/csdev.py +++ b/siriuspy/siriuspy/dvfimgproc/csdev.py @@ -27,6 +27,7 @@ class Constants(_csdev.Const): StsLblsDVF = _get_namedtuple('StsLblsDVF', _et.STS_LBLS_DVF) DEF_DVFSTATUS = 0b11111111 + DEF_BEAM_THRESHOLD = 100 def __init__(self, devname): """.""" @@ -116,19 +117,23 @@ def _get_image_db(self): 'value': self.NoYes.No, }, 'ImgIsWithBeamThreshold-SP': { - 'type': 'int', 'unit': 'intensity', 'value': 10, + 'type': 'int', 'unit': 'intensity', + 'value': self.DEF_BEAM_THRESHOLD, }, 'ImgIsWithBeamThreshold-RB': { - 'type': 'int', 'unit': 'intensity', 'value': 10, + 'type': 'int', 'unit': 'intensity', + 'value': self.DEF_BEAM_THRESHOLD, }, } return dbase def _get_roi_db(self): + dvf_params = _DVF.conv_devname2parameters(self.devname) db = {} rb_ = '-RB' sp_ = '-SP' mon_ = '-Mon' + sizes = {'X': dvf_params.IMAGE_SIZE_X, 'Y': dvf_params.IMAGE_SIZE_Y} for axis in ['X', 'Y']: db.update({ 'ImgROI' + axis + sp_: { @@ -144,7 +149,7 @@ def _get_roi_db(self): 'type': 'int', 'unit': 'px' }, 'ImgROI' + axis + 'Proj' + mon_: { - 'type': 'int', 'count': 2, 'unit': 'intensity', + 'type': 'int', 'count': sizes[axis], 'unit': 'intensity', }, 'ImgROI' + axis + 'UpdateWithFWHMFactor-SP': { 'type': 'float', 'value': 2.0, 'unit': 'fwhm_factor', From 04d62282f3f9e053a862c74d0c511edcaa8d96ae Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 4 Jan 2024 13:34:48 -0300 Subject: [PATCH 270/309] Change ImgProc so that ProcTime PV is updated even wo beam --- siriuspy/siriuspy/dvfimgproc/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/dvfimgproc/main.py b/siriuspy/siriuspy/dvfimgproc/main.py index 7f4a6e018..fc29e7176 100644 --- a/siriuspy/siriuspy/dvfimgproc/main.py +++ b/siriuspy/siriuspy/dvfimgproc/main.py @@ -204,13 +204,16 @@ def update_driver(self): self._write_pv('ImgIsWithBeam-Mon', 0) invalid_fitx, invalid_fity = [False]*2 + with_beam = self.meas.image2dfit.is_with_image + for pvname, attr in App._MON_PVS_2_IMGFIT.items(): # check if is roi_rb and if it needs updating if pvname in ('ImgROIX-RB', 'ImgROIY-RB'): if not self.meas.update_roi_with_fwhm: continue - if not self.meas.image2dfit.is_with_image and 'Fit' in pvname: + # if no beam, return if PV is of fit type + if not with_beam and 'Fit' in pvname and 'ProcTime' not in pvname: return # get image attribute value From 124cc7178639cc45bc970264680a882d295cf10d Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 11 Jan 2024 08:20:36 -0300 Subject: [PATCH 271/309] DEV.FAMBPMS.ENH: Add static method to calculate positions from antennas amplitudes. --- siriuspy/siriuspy/devices/bpm_eq.py | 29 +++----------- siriuspy/siriuspy/devices/bpm_fam.py | 56 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index f6857e195..53151b879 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -506,10 +506,10 @@ def estimate_orbit_variation(self): if gains_new is None: self._log('ERR:Missing info. Acquire and process data first.') - orbx_init, orby_init = self._estimate_orbit( - mean, gains_init, gainx, gainy, offx, offy) - orbx_new, orby_new = self._estimate_orbit( - mean, gains_new, gainx, gainy, offx, offy) + orbx_init, orby_init = self.calc_positions_from_amplitudes( + mean * gains_init, gainx, gainy, offx, offy) + orbx_new, orby_new = self.calc_positions_from_amplitudes( + mean * gains_new, gainx, gainy, offx, offy) # Get the average over both semicycles self.data['orbx_init'] = orbx_init.mean(axis=-1) self.data['orby_init'] = orby_init.mean(axis=-1) @@ -628,8 +628,8 @@ def plot_antennas_mean(self): if not i and not j: ld.set_label('Direct') li.set_label('Inverse') - posx, posy = self._estimate_orbit( - antm, gain, gainx, gainy, offx, offy) + posx, posy = self.calc_positions_from_amplitudes( + antm * gain, gainx, gainy, offx, offy) sum_ = val.sum(axis=0) axs[4, j].plot(posx[:, 0], 'o-') axs[4, j].plot(posx[:, 1], 'o-') @@ -677,23 +677,6 @@ def plot_antennas_for_check(self): # ------- auxiliary methods ---------- - @staticmethod - def _estimate_orbit(mean, gains, gainx, gainy, offx, offy): - a, b, c, d = mean * gains - # Calculate difference over sum for each pair - a_c = (a-c) / (a+c) - b_d = (b-d) / (b+d) - # Get the positions: - posx = (a_c - b_d) / 2 - posy = (a_c + b_d) / 2 - # Apply position gains: - posx *= gainx[:, None] - posy *= gainy[:, None] - # Subtract offsets: - posx -= offx[:, None] - posy -= offy[:, None] - return posx, posy - def _log(self, message, *args, level='INFO', **kwrgs): if self._logger is None: print(message, *args, **kwrgs) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 4f5494c60..7114025cd 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -116,6 +116,62 @@ def mturn_signals2acq(self, sigs): self._mturn_signals2acq = sigs self._configure_automonitor_acquisition_pvs(state=True) + @staticmethod + def calc_positions_from_amplitudes( + amps, gainx=None, gainy=None, offx=0.0, offy=0.0 + ): + """Calculate transverse positions from antennas amplitudes. + + Args: + amps (list|numpy.ndarray, (4, ...)): A list or N-D array + containing the amplitudes of the four antennas in the order + A, B, C, D. If each antenna is a 2D array, the last index is + assumed to be related to BPMs. + gainx (float|numpy.ndarray, optional): Horizontal gain in [um]. If + None, then the nominal value of 12/sqrt(2) of the storage ring + will be used. Defaults to None. An array can be used to + specify different values for each BPM. + gainy (float|numpy.ndarray, optional): Vertical gain in [um]. If + None, then the nominal value of 12/sqrt(2) of the storage ring + will be used. Defaults to None. An array can be used to + specify different values for each BPM. + offx (float|numpy.ndarray, optional): Horizontal offset in [um]. + Defaults to 0.0. An array can be used to specify different + values for each BPM. + offy (float|numpy.ndarray, optional): Vertical offset in [um]. + Defaults to 0.0. An array can be used to specify different + values for each BPM. + + Returns: + posx (numpy.ndarray, (...)): Horizontal position in [um]. Same + shape of antennas array. + posy (numpy.ndarray, (...)): Vertical position in [um]. Same + shape of antennas array. + + """ + a, b, c, d = amps + + gainx = 12e3 / _np.sqrt(2) if gainx is None else gainx # [um] + gainy = 12e3 / _np.sqrt(2) if gainy is None else gainy # [um] + gainx = _np.atleast_1d(gainx) + gainy = _np.atleast_1d(gainy) + offx = _np.atleast_1d(offx) + offy = _np.atleast_1d(offy) + + # Calculate difference over sum for each pair + a_c = (a - c) / (a + c) + b_d = (b - d) / (b + d) + # Get the positions: + posx = (a_c - b_d) / 2 + posy = (a_c + b_d) / 2 + # Apply position gains: + posx *= gainx + posy *= gainy + # Subtract offsets: + posx -= offx + posy -= offy + return posx, posy + def set_attenuation(self, value=RFFEATT_MAX, timeout=TIMEOUT): """.""" for bpm in self: From 5310ce4c7d886b2c94425382aff052aa1ced03da Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 11 Jan 2024 08:39:49 -0300 Subject: [PATCH 272/309] DEV.BPMEQ.BUG: Adequate code to interface of `calc_positions_from_amplitudes`. --- siriuspy/siriuspy/devices/bpm_eq.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_eq.py b/siriuspy/siriuspy/devices/bpm_eq.py index 53151b879..f378a9ff0 100644 --- a/siriuspy/siriuspy/devices/bpm_eq.py +++ b/siriuspy/siriuspy/devices/bpm_eq.py @@ -499,17 +499,17 @@ def estimate_orbit_variation(self): mean = self.data.get('antennas_mean') gains_init = self.data.get('gains_init') gains_new = self.data.get('gains_new') - gainx = self.data.get('posx_gain') - gainy = self.data.get('posy_gain') - offx = self.data.get('posx_offset', _np.zeros(len(self.bpms))) - offy = self.data.get('posy_offset', _np.zeros(len(self.bpms))) + gnx = self.data.get('posx_gain')[:, None] + gny = self.data.get('posy_gain')[:, None] + ofx = self.data.get('posx_offset', _np.zeros(len(self.bpms)))[:, None] + ofy = self.data.get('posy_offset', _np.zeros(len(self.bpms)))[:, None] if gains_new is None: self._log('ERR:Missing info. Acquire and process data first.') orbx_init, orby_init = self.calc_positions_from_amplitudes( - mean * gains_init, gainx, gainy, offx, offy) + mean * gains_init, gnx, gny, ofx, ofy) orbx_new, orby_new = self.calc_positions_from_amplitudes( - mean * gains_new, gainx, gainy, offx, offy) + mean * gains_new, gnx, gny, ofx, ofy) # Get the average over both semicycles self.data['orbx_init'] = orbx_init.mean(axis=-1) self.data['orby_init'] = orby_init.mean(axis=-1) @@ -595,10 +595,10 @@ def plot_semicycle_indices(self): def plot_antennas_mean(self): """.""" - gainx = self.data.get('posx_gain') - gainy = self.data.get('posx_gain') - offx = self.data.get('posx_offset') - offy = self.data.get('posx_offset') + gnx = self.data.get('posx_gain')[:, None] + gny = self.data.get('posx_gain')[:, None] + ofx = self.data.get('posx_offset')[:, None] + ofy = self.data.get('posx_offset')[:, None] gacq = self.data.get('gains_acq') gini = self.data.get('gains_init') gnew = self.data.get('gains_new') @@ -629,7 +629,7 @@ def plot_antennas_mean(self): ld.set_label('Direct') li.set_label('Inverse') posx, posy = self.calc_positions_from_amplitudes( - antm * gain, gainx, gainy, offx, offy) + antm * gain, gnx, gny, ofx, ofy) sum_ = val.sum(axis=0) axs[4, j].plot(posx[:, 0], 'o-') axs[4, j].plot(posx[:, 1], 'o-') From d32e53ac1e90f11ad653d747c1ec17c1b59c7f43 Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 11 Jan 2024 08:49:06 -0300 Subject: [PATCH 273/309] DEV.FAMBPMS.DOC: Improve docstring of `calc_positions_from_amplitudes`. --- siriuspy/siriuspy/devices/bpm_fam.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 7114025cd..4c98ef8cc 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -130,17 +130,25 @@ def calc_positions_from_amplitudes( gainx (float|numpy.ndarray, optional): Horizontal gain in [um]. If None, then the nominal value of 12/sqrt(2) of the storage ring will be used. Defaults to None. An array can be used to - specify different values for each BPM. + specify different values for each BPM. In this case the gain + array must match the shape of the antennas arrays or satisfy + the broadcast rules in relation to them. gainy (float|numpy.ndarray, optional): Vertical gain in [um]. If None, then the nominal value of 12/sqrt(2) of the storage ring will be used. Defaults to None. An array can be used to - specify different values for each BPM. + specify different values for each BPM. In this case the gain + array must match the shape of the antennas arrays or satisfy + the broadcast rules in relation to them. offx (float|numpy.ndarray, optional): Horizontal offset in [um]. Defaults to 0.0. An array can be used to specify different - values for each BPM. + values for each BPM. In this case the gain array must match + the shape of the antennas arrays or satisfy the broadcast + rules in relation to them. offy (float|numpy.ndarray, optional): Vertical offset in [um]. Defaults to 0.0. An array can be used to specify different - values for each BPM. + values for each BPM. In this case the gain array must match + the shape of the antennas arrays or satisfy the broadcast + rules in relation to them. Returns: posx (numpy.ndarray, (...)): Horizontal position in [um]. Same @@ -151,8 +159,9 @@ def calc_positions_from_amplitudes( """ a, b, c, d = amps - gainx = 12e3 / _np.sqrt(2) if gainx is None else gainx # [um] - gainy = 12e3 / _np.sqrt(2) if gainy is None else gainy # [um] + radius = 12e3 # [um] + gainx = radius / _np.sqrt(2) if gainx is None else gainx + gainy = radius / _np.sqrt(2) if gainy is None else gainy gainx = _np.atleast_1d(gainx) gainy = _np.atleast_1d(gainy) offx = _np.atleast_1d(offx) From 62c1119fd15347f627b0dad1dae488492d21ff0a Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 11 Jan 2024 08:52:09 -0300 Subject: [PATCH 274/309] DEV.FAMBPMS.DOC: Fix docstring of `calc_positions_from_amplitudes`. --- siriuspy/siriuspy/devices/bpm_fam.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index 4c98ef8cc..c0ae3f93f 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -125,8 +125,7 @@ def calc_positions_from_amplitudes( Args: amps (list|numpy.ndarray, (4, ...)): A list or N-D array containing the amplitudes of the four antennas in the order - A, B, C, D. If each antenna is a 2D array, the last index is - assumed to be related to BPMs. + A, B, C, D. gainx (float|numpy.ndarray, optional): Horizontal gain in [um]. If None, then the nominal value of 12/sqrt(2) of the storage ring will be used. Defaults to None. An array can be used to From 12e54b91471037b6acd99815c89855233d1490c3 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 12 Jan 2024 19:20:19 -0300 Subject: [PATCH 275/309] macreport.MNT: update report scripts --- .../siriuspy/machshift/gensumm_macreport.py | 83 +++++-------------- .../siriuspy/machshift/savedata_macreport.py | 18 ++-- 2 files changed, 34 insertions(+), 67 deletions(-) diff --git a/siriuspy/siriuspy/machshift/gensumm_macreport.py b/siriuspy/siriuspy/machshift/gensumm_macreport.py index 6322c95b0..ca2db8c68 100644 --- a/siriuspy/siriuspy/machshift/gensumm_macreport.py +++ b/siriuspy/siriuspy/machshift/gensumm_macreport.py @@ -7,33 +7,18 @@ # failure statistics per month intervals = [ - [Time(2021, 1, 1, 0, 0), Time(2021, 1, 31, 23, 59, 59)], - [Time(2021, 2, 1, 0, 0), Time(2021, 2, 28, 23, 59, 59)], - [Time(2021, 3, 1, 0, 0), Time(2021, 3, 31, 23, 59, 59)], - [Time(2021, 4, 1, 0, 0), Time(2021, 4, 30, 23, 59, 59)], - [Time(2021, 5, 1, 0, 0), Time(2021, 5, 31, 23, 59, 59)], - [Time(2021, 6, 1, 0, 0), Time(2021, 6, 30, 23, 59, 59)], - [Time(2021, 7, 1, 0, 0), Time(2021, 7, 31, 23, 59, 59)], - [Time(2021, 8, 1, 0, 0), Time(2021, 8, 31, 23, 59, 59)], - [Time(2021, 9, 1, 0, 0), Time(2021, 9, 30, 23, 59, 59)], - [Time(2021, 10, 1, 0, 0), Time(2021, 10, 31, 23, 59, 59)], - [Time(2021, 11, 1, 0, 0), Time(2021, 11, 30, 23, 59, 59)], - [Time(2021, 12, 1, 0, 0), Time(2021, 12, 31, 23, 59, 59)], - [Time(2022, 1, 1, 0, 0), Time(2022, 1, 31, 23, 59, 59)], - [Time(2022, 2, 1, 0, 0), Time(2022, 2, 28, 23, 59, 59)], - [Time(2022, 3, 1, 0, 0), Time(2022, 3, 31, 23, 59, 59)], - [Time(2022, 4, 1, 0, 0), Time(2022, 4, 30, 23, 59, 59)], - [Time(2022, 5, 1, 0, 0), Time(2022, 5, 31, 23, 59, 59)], - [Time(2022, 6, 1, 0, 0), Time(2022, 6, 30, 23, 59, 59)], - [Time(2022, 7, 1, 0, 0), Time(2022, 7, 31, 23, 59, 59)], - [Time(2022, 8, 1, 0, 0), Time(2022, 8, 31, 23, 59, 59)], - [Time(2022, 9, 1, 0, 0), Time(2022, 9, 30, 23, 59, 59)], - [Time(2022, 10, 1, 0, 0), Time(2022, 10, 31, 23, 59, 59)], - [Time(2022, 11, 1, 0, 0), Time(2022, 11, 30, 23, 59, 59)], - [Time(2022, 12, 1, 0, 0), Time(2022, 12, 31, 23, 59, 59)], [Time(2023, 1, 1, 0, 0), Time(2023, 1, 31, 23, 59, 59)], [Time(2023, 2, 1, 0, 0), Time(2023, 2, 28, 23, 59, 59)], [Time(2023, 3, 1, 0, 0), Time(2023, 3, 31, 23, 59, 59)], + [Time(2023, 4, 1, 0, 0), Time(2023, 4, 30, 23, 59, 59)], + [Time(2023, 5, 1, 0, 0), Time(2023, 5, 31, 23, 59, 59)], + [Time(2023, 6, 1, 0, 0), Time(2023, 6, 30, 23, 59, 59)], + [Time(2023, 7, 1, 0, 0), Time(2023, 7, 31, 23, 59, 59)], + [Time(2023, 8, 1, 0, 0), Time(2023, 8, 31, 23, 59, 59)], + [Time(2023, 9, 1, 0, 0), Time(2023, 9, 30, 23, 59, 59)], + [Time(2023, 10, 1, 0, 0), Time(2023, 10, 31, 23, 59, 59)], + [Time(2023, 11, 1, 0, 0), Time(2023, 11, 30, 23, 59, 59)], + [Time(2023, 12, 1, 0, 0), Time(2023, 12, 31, 23, 59, 59)], ] macreports = dict() @@ -48,6 +33,7 @@ progrmd, delivd, usertot = dict(), dict(), dict() currmean, currstd = dict(), dict() stable, unstable, relstable = dict(), dict(), dict() +nrbeamdump = dict() for date, macr in macreports.items(): mtbfs[date] = macr.usershift_time_between_failures_average mttrs[date] = macr.usershift_time_to_recover_average @@ -60,13 +46,15 @@ stable[date] = macr.usershift_total_stable_beam_time unstable[date] = macr.usershift_total_unstable_beam_time relstable[date] = macr.usershift_relative_stable_beam_time + nrbeamdump[date] = macr.usershift_beam_dump_count -str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' +str_ = '{:<10s}' + '{:>16s}'*10 + '{:>20s}' print(str_.format( 'Y-M', 'MTBF', 'MTTR', 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', - '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) -str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' + '% stable hours', 'Stable hours', 'Unstable hours', '# Beam Dump', + 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*10 + ' {:4.3f} ± {:4.3f}' for date in macreports: print(str_.format( str(date.year)+'-'+str(date.month), @@ -79,6 +67,7 @@ relstable[date], stable[date], unstable[date], + nrbeamdump[date], currmean[date], currstd[date], )) @@ -105,16 +94,17 @@ # programmed vs. delivered hours macr = MacReport() macr.connector.timeout = 300 -macr.time_start = Time(2022, 4, 1, 0, 0) -macr.time_stop = Time(2023, 3, 31, 23, 59, 59) +macr.time_start = Time(2023, 1, 1, 0, 0) +macr.time_stop = Time(2023, 12, 31, 23, 59, 59) macr.update() -str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' +str_ = '{:<10s}' + '{:>16s}'*10 + '{:>20s}' print(str_.format( 'Y-M', 'MTBF', 'MTTR', 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', - '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) -str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' + '% stable hours', 'Stable hours', 'Unstable hours', '# Beam Dump', + 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*10 + ' {:4.3f} ± {:4.3f}' print( str_.format( str(macr.time_start.year)+'-'+str(macr.time_start.month) + ' a ' + @@ -128,6 +118,7 @@ macr.usershift_relative_stable_beam_time, macr.usershift_total_stable_beam_time, macr.usershift_total_unstable_beam_time, + macr.usershift_beam_dump_count, macr.usershift_current_average, macr.usershift_current_stddev, )) @@ -154,31 +145,3 @@ plt.legend(loc=4) plt.title('Integrated User Hours') fig.show() - -new_dates, new_dtimes_progmd, new_dtimes_deliv = [], [], [] -for i, d in enumerate(dates): - if not new_dates or d.date() != new_dates[-1].date(): - new_dates.append(d) - new_dtimes_progmd.append(dtimes_users_progmd[i]) - new_dtimes_deliv.append(dtimes_users_impltd[i]) - else: - new_dtimes_progmd[-1] += dtimes_users_progmd[i] - new_dtimes_deliv[-1] += dtimes_users_impltd[i] -new_cum_progmd = np.cumsum(new_dtimes_progmd) -new_cum_deliv = np.cumsum(new_dtimes_deliv) - -fig = plt.figure() -axs = plt.gca() -axs.xaxis.axis_date() -axs.plot(new_dates, new_cum_progmd, '-', label='Programmed') -axs.plot(new_dates, new_cum_deliv, '-', label='Delivered') -axs.grid() -axs.set_ylabel('Integrated Hours') -plt.legend(loc=4) -plt.title('Integrated User Hours') -fig.show() - -np.savetxt( - 'integrated_user_hours_2021.txt', - np.c_[[d.timestamp() for d in new_dates], - new_cum_progmd, new_cum_deliv]) diff --git a/siriuspy/siriuspy/machshift/savedata_macreport.py b/siriuspy/siriuspy/machshift/savedata_macreport.py index 9bfbaa907..2a8848e51 100644 --- a/siriuspy/siriuspy/machshift/savedata_macreport.py +++ b/siriuspy/siriuspy/machshift/savedata_macreport.py @@ -5,8 +5,8 @@ from siriuspy.machshift.macreport import MacReport # determine interval -time_start = Time(2022, 1, 1, 0, 0) -time_stop = Time(2022, 12, 31, 23, 59, 59) +time_start = Time(2023, 1, 1, 0, 0) +time_stop = Time(2023, 12, 31, 23, 59, 59) # get data from interval macr = MacReport() @@ -16,12 +16,13 @@ macr.update() # print small report -str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' +str_ = '{:<10s}' + '{:>16s}'*10 + '{:>20s}' print(str_.format( 'Y-M', 'MTBF', 'MTTR', 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', - '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) -str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' + '% stable hours', 'Stable hours', 'Unstable hours', '# Beam Dump', + 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*10 + ' {:4.3f} ± {:4.3f}' print( str_.format( str(macr.time_start.year)+'-'+str(macr.time_start.month) + ' a ' + @@ -35,6 +36,7 @@ macr.usershift_relative_stable_beam_time, macr.usershift_total_stable_beam_time, macr.usershift_total_unstable_beam_time, + macr.usershift_beam_dump_count, macr.usershift_current_average, macr.usershift_current_stddev, )) @@ -50,18 +52,20 @@ raw_data['Failures - SubsystemsNOk'] = np.asarray(failures['SubsystemsNOk'], dtype=int) raw_data['Failures - NoEBeam'] = np.asarray(failures['NoEBeam'], dtype=int) raw_data['Failures - WrongShift'] = np.asarray(failures['WrongShift'], dtype=int) +raw_data['Failures - ManualAnnotated'] = np.asarray(failures['ManualAnnotated'], dtype=int) raw_data['TimeDate'] = [Time(t).get_iso8601() for t in raw_data['Timestamp']] # stored data in specific order order = [ 'Timestamp', 'TimeDate', 'Current', - 'Failures - SubsystemsNOk', 'Failures - NoEBeam', 'Failures - WrongShift', + 'Failures - SubsystemsNOk', 'Failures - NoEBeam', + 'Failures - WrongShift', 'Failures - ManualAnnotated', 'UserShiftProgmd', 'UserShiftInitCurr', 'UserShiftDelivd'] data = {k: raw_data[k] for k in order} # save data to csv df = pd.DataFrame.from_dict(data) -df.to_csv('raw_data_machine_report_2022.csv', index=False, header=True) +df.to_csv('raw_data_machine_report_2023.csv', index=False, header=True) # check hour numbers: each point is equivalent to 5s, converting to hours programmed = sum(data['UserShiftProgmd'])*5/60/60 From 47cee036ebc5ae8397c88ffbb60b724c18208510 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 12 Jan 2024 19:20:41 -0300 Subject: [PATCH 276/309] macreport.FIX: fix bug in beam dump count calculation --- siriuspy/siriuspy/machshift/macreport.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/siriuspy/siriuspy/machshift/macreport.py b/siriuspy/siriuspy/machshift/macreport.py index 554df9515..52684044d 100644 --- a/siriuspy/siriuspy/machshift/macreport.py +++ b/siriuspy/siriuspy/machshift/macreport.py @@ -1607,10 +1607,13 @@ def _calc_beam_for_users_stats(self): self._usershift_current_end_stddev = 0 # # # ----- failures ----- - beam_dump_values = _np.logical_not( - self._raw_data['Failures']['WrongShift']) * \ - self._raw_data['Failures']['ManualAnnotated'] * \ - self._raw_data['Failures']['NoEBeam'] + beam_dump_values = 1 * _np.logical_and( + _np.logical_not( + self._raw_data['Failures']['WrongShift'] + ), _np.logical_or( + self._raw_data['Failures']['ManualAnnotated'], + self._raw_data['Failures']['NoEBeam'] + )) self._usershift_beam_dump_count = _np.sum( _np.diff(beam_dump_values) > 0) From 432fe258a515c8671187070233e36d7d4adbc5a6 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 12 Jan 2024 19:21:26 -0300 Subject: [PATCH 277/309] macreport.MNT: add manual annotated failure for March 03 (hydraulic failure, wrong machine shift for recovery) --- siriuspy/siriuspy/machshift/macreport.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/machshift/macreport.py b/siriuspy/siriuspy/machshift/macreport.py index 52684044d..67cf16bb9 100644 --- a/siriuspy/siriuspy/machshift/macreport.py +++ b/siriuspy/siriuspy/machshift/macreport.py @@ -254,6 +254,8 @@ class MacReport: ] FAILURES_MANUAL = [ + # hydraulic failure, wrong machine shift for recovery + [_Time(2023, 3, 3, 22, 56, 0, 0), _Time(2023, 3, 3, 23, 0, 0, 0)], # power grid failure, archiver was down [_Time(2023, 5, 18, 5, 55, 0, 0), _Time(2023, 5, 18, 9, 8, 0, 0)], ] From c112769037698c5053fa3bfa80323eafd9220056 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Fri, 12 Jan 2024 19:29:17 -0300 Subject: [PATCH 278/309] Update version to 2.86.0 --- siriuspy/siriuspy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/VERSION b/siriuspy/siriuspy/VERSION index af8717366..c99417194 100644 --- a/siriuspy/siriuspy/VERSION +++ b/siriuspy/siriuspy/VERSION @@ -1 +1 @@ -2.85.0 +2.86.0 From 6ed0559fcbf2fab62e2ad449a606cc7c79b0cd84 Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 23 Jan 2024 16:20:54 -0300 Subject: [PATCH 279/309] Fix IDFF init --- siriuspy/siriuspy/devices/idff.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 41730cbe8..212685921 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -155,6 +155,8 @@ def implement_setpoints( self.calculate_setpoints( pparameter_value=None, kparameter_value=None) + else: + polarization, pparameter_value, kparameter_value = [None, ] * 3 if corrdevs is None: corrdevs = self._devsch + self._devscv + self._devsqs for pvname, value in setpoints.items(): From da9b386f1289f242db1d96f37d84b4d86b520f83 Mon Sep 17 00:00:00 2001 From: ximenes Date: Wed, 24 Jan 2024 09:01:44 -0300 Subject: [PATCH 280/309] fix bug devices ids --- siriuspy/siriuspy/devices/ids.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 6ca60823d..f6ecac0c6 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -609,7 +609,7 @@ def cmd_move(self, pparam=None, kparam=None, timeout=None): timeout = max(timeout - (t1_ - t0_), 0) # calc timeout - timeout = self._calc_move_timeout(None, None, timeout) + timeout = self.calc_move_timeout(pparam, kparam, timeout) # wait for movement within timeout based on movement ETA return self.wait_move_config(pparam, kparam, timeout) @@ -649,7 +649,8 @@ def calc_move_eta(self, pparam_goal=None, kparam_goal=None): if None not in (param_goal, param_val): dparam = abs(param_goal - param_val) dparam = 0 if dparam < param_tol else dparam - pparam_eta = IDBase._calc_move_eta_model(dparam, param_vel, param_acc) + pparam_eta = IDBase._calc_move_eta_model( + dparam, param_vel, param_acc) else: pparam_eta = 0.0 @@ -660,19 +661,22 @@ def calc_move_eta(self, pparam_goal=None, kparam_goal=None): if None not in (param_goal, param_val): dparam = abs(abs(param_goal) - abs(param_val)) # abs for DELTA dparam = 0 if dparam < param_tol else dparam - kparam_eta = IDBase._calc_move_eta_model(dparam, param_vel, param_acc) + kparam_eta = IDBase._calc_move_eta_model( + dparam, param_vel, param_acc) else: kparam_eta = 0.0 return pparam_eta, kparam_eta def calc_move_eta_composed(self, pparam_eta, kparam_eta): + """.""" # model: here pparam and kparam as serial in time eta = pparam_eta + kparam_eta return eta def calc_move_timeout( self, pparam_goal=None, kparam_goal=None, timeout=None): + """.""" # calc timeout pparam_eta, kparam_eta = self.calc_move_eta(pparam_goal, kparam_goal) eta = self.calc_move_eta_composed(pparam_eta, kparam_eta) From 5b38514e771427c82088d050454cdfb4ae1a8f4d Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Wed, 24 Jan 2024 15:59:43 -0300 Subject: [PATCH 281/309] Adding BO Pwr sensor, SSA tower 3 and 4 alarm and offset config PVs --- .../siriuspy/clientconfigdb/types/as_rf.py | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index d509784e4..8b3d63948 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -352,6 +352,16 @@ def get_dict(): ] +_pvs_bo_pow_sensor = [ + #Keysight U2021xa Power Sensor config + ['RA-RF:PowerSensor1:GainOffsetStat-Sel', 0, 0.0], + ['RA-RF:PowerSensor1:GainOffset-SP', 0, 0.0], + ['RA-RF:PowerSensor1:Egu-SP', 0, 0.0], + ['RA-RF:PowerSensor1:TracTime-SP', 0, 0.0], + ['RA-RF:PowerSensor1:Freq-SP', 0, 0.0], + ] + + _pvs_si_llrf = [ # Interlock disable ['SR-RF-DLLRF-01:ILK:REVSSA1:S', 0, 0.0], @@ -510,15 +520,7 @@ def get_dict(): # ['RA-ToSIA01:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA01:OffsetConfig:LowerReflectedPower', 0, 0.0], - # ['RA-ToSIA01:OffsetConfig:InputIncidentPower', 0, 0.0], - # ['RA-ToSIA01:OffsetConfig:InputReflectedPower', 0, 0.0], - # ['RA-ToSIA01:OffsetConfig:OutputIncidentPower', 0, 0.0], - # ['RA-ToSIA01:OffsetConfig:OutputReflectedPower', 0, 0.0], # SSA tower 1 pwr alarm limits - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLow', 0, 0.0], - # ['RA-ToSIA01:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA01:AlarmConfig:InnerPowerLimLow', 0, 0.0], @@ -533,15 +535,7 @@ def get_dict(): # ['RA-ToSIA02:OffsetConfig:UpperReflectedPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerIncidentPower', 0, 0.0], # ['RA-ToSIA02:OffsetConfig:LowerReflectedPower', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:InputIncidentPower', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:InputReflectedPower', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:OutputIncidentPower', 0, 0.0], - # ['RA-ToSIA02:OffsetConfig:OutputReflectedPower', 0, 0.0], - # SSA tower 2 pwr alarm limits - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHiHi', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimHigh', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLow', 0, 0.0], - # ['RA-ToSIA02:AlarmConfig:GeneralPowerLimLoLo', 0, 0.0], + # SSA tower 2 pwr alarm limits # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:InnerPowerLimLow', 0, 0.0], @@ -551,6 +545,46 @@ def get_dict(): # ['RA-ToSIA02:AlarmConfig:CurrentLimHigh', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLow', 0, 0.0], # ['RA-ToSIA02:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # SSA tower 3 offsets + ['RA-ToSIA03:OffsetConfig:UpperIncidentPower', 0, 0.0], + ['RA-ToSIA03:OffsetConfig:UpperReflectedPower', 0, 0.0], + ['RA-ToSIA03:OffsetConfig:LowerIncidentPower', 0, 0.0], + ['RA-ToSIA03:OffsetConfig:LowerReflectedPower', 0, 0.0], + # SSA tower 3 pwr alarm limits + ['RA-ToSIA03:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:InnerPowerLimLow', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # SSA tower 3 current alarm limits + ['RA-ToSIA03:AlarmConfig:CurrentLimHiHi', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:CurrentLimHigh', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:CurrentLimLow', 0, 0.0], + ['RA-ToSIA03:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # SSA tower 4 offsets + ['RA-ToSIA04:OffsetConfig:UpperIncidentPower', 0, 0.0], + ['RA-ToSIA04:OffsetConfig:UpperReflectedPower', 0, 0.0], + ['RA-ToSIA04:OffsetConfig:LowerIncidentPower', 0, 0.0], + ['RA-ToSIA04:OffsetConfig:LowerReflectedPower', 0, 0.0], + # SSA tower 4 pwr alarm limits + ['RA-ToSIA04:AlarmConfig:InnerPowerLimHiHi', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:InnerPowerLimHigh', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:InnerPowerLimLow', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:InnerPowerLimLoLo', 0, 0.0], + # SSA tower 4 current alarm limits + ['RA-ToSIA04:AlarmConfig:CurrentLimHiHi', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:CurrentLimHigh', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:CurrentLimLow', 0, 0.0], + ['RA-ToSIA04:AlarmConfig:CurrentLimLoLo', 0, 0.0], + # SSA1 Pwr Cal Coeff + # ['RA-ToSIA01:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], + # ['RA-ToSIA01:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], + # ['RA-ToSIA01:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], + # ['RA-ToSIA01:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], + # SSA2 Pwr Cal Coeff + # ['RA-ToSIA02:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], + # ['RA-ToSIA02:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], + # ['RA-ToSIA02:RF-SSAmpTower:Hw2PwrFwdOutCoeff-Cte', az, 0.0], + # ['RA-ToSIA02:RF-SSAmpTower:Hw2PwrRevOutCoeff-Cte', az, 0.0], # SSA3 Pwr Cal Coeff ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrFwdInCoeff-Cte', az, 0.0], ['RA-ToSIA03:RF-SSAmpTower:Hw2PwrRevInCoeff-Cte', az, 0.0], @@ -719,7 +753,7 @@ def get_dict(): _template_dict = { 'pvs': - _pvs_as_rf + - _pvs_li_llrf + _pvs_bo_llrf + _pvs_bo_rfssa + _pvs_bo_rfcal + + _pvs_as_rf + _pvs_li_llrf + + _pvs_bo_pow_sensor + _pvs_bo_llrf + _pvs_bo_rfssa + _pvs_bo_rfcal + _pvs_si_llrf + _pvs_si_rfssa + _pvs_si_rfcav + _pvs_si_rfcal - } + } \ No newline at end of file From 6df80778efd4366d63d70e4f1758edf9f12ed985 Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Wed, 24 Jan 2024 16:31:44 -0300 Subject: [PATCH 282/309] New line at the end of the file added --- siriuspy/siriuspy/clientconfigdb/types/as_rf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index 8b3d63948..ca2e9af37 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -756,4 +756,5 @@ def get_dict(): _pvs_as_rf + _pvs_li_llrf + _pvs_bo_pow_sensor + _pvs_bo_llrf + _pvs_bo_rfssa + _pvs_bo_rfcal + _pvs_si_llrf + _pvs_si_rfssa + _pvs_si_rfcav + _pvs_si_rfcal - } \ No newline at end of file + } + \ No newline at end of file From f3f082b67c861068471ed655341118b593ed0b2c Mon Sep 17 00:00:00 2001 From: "felipe.hoshino" Date: Thu, 25 Jan 2024 11:24:05 -0300 Subject: [PATCH 283/309] Adding Calibration System Offsets --- .../siriuspy/clientconfigdb/types/as_rf.py | 64 ++++++++++++++----- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py index ca2e9af37..9cba69604 100644 --- a/siriuspy/siriuspy/clientconfigdb/types/as_rf.py +++ b/siriuspy/siriuspy/clientconfigdb/types/as_rf.py @@ -216,7 +216,7 @@ def get_dict(): _pvs_bo_rfcal = [ # Offsets and conv coeffs - ['BR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:CAV:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:Raw-U:C2:S', 0, 0.0], @@ -227,7 +227,7 @@ def get_dict(): ['BR-RF-DLLRF-01:CAV:Const:U-Raw:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:U-Raw:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:CAV:Const:U-Raw:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:FWDCAV:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:FWDCAV:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:FWDCAV:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCAV:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCAV:Const:Raw-U:C2:S', 0, 0.0], @@ -238,19 +238,19 @@ def get_dict(): ['BR-RF-DLLRF-01:FWDCAV:Const:U-Raw:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCAV:Const:U-Raw:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCAV:Const:U-Raw:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:REVCAV:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:REVCAV:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:REVCAV:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCAV:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCAV:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCAV:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCAV:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:MO:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:MO:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:MO:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:MO:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:MO:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:MO:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:MO:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:FWDSSA1:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:FWDSSA1:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:FWDSSA1:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDSSA1:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDSSA1:Const:Raw-U:C2:S', 0, 0.0], @@ -261,61 +261,61 @@ def get_dict(): ['BR-RF-DLLRF-01:FWDSSA1:Const:U-Raw:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDSSA1:Const:U-Raw:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDSSA1:Const:U-Raw:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:REVSSA1:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:REVSSA1:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:REVSSA1:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:REVSSA1:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:REVSSA1:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:REVSSA1:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:REVSSA1:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:CELL2:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:CELL2:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:CELL2:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL2:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL2:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL2:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL2:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:CELL4:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:CELL4:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:CELL4:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL4:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL4:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL4:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL4:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:CELL1:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:CELL1:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:CELL1:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL1:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL1:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL1:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL1:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:CELL5:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:CELL5:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:CELL5:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL5:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL5:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL5:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:CELL5:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:INPRE:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:INPRE:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:INPRE:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:INPRE:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:INPRE:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:INPRE:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:INPRE:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:FWDPRE:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:FWDPRE:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:FWDPRE:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDPRE:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDPRE:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDPRE:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDPRE:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:REVPRE:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:REVPRE:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:REVPRE:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:REVPRE:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:REVPRE:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:REVPRE:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:REVPRE:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:FWDCIRC:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:FWDCIRC:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:FWDCIRC:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCIRC:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCIRC:Const:Raw-U:C2:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCIRC:Const:Raw-U:C3:S', 0, 0.0], ['BR-RF-DLLRF-01:FWDCIRC:Const:Raw-U:C4:S', 0, 0.0], - ['BR-RF-DLLRF-01:REVCIRC:Const:OFS:S', 0, 0.0], + ['BR-RF-DLLRF-01:REVCIRC:Const:OFS:S', 0, 0.0], # [dB] ['BR-RF-DLLRF-01:REVCIRC:Const:Raw-U:C0:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCIRC:Const:Raw-U:C1:S', 0, 0.0], ['BR-RF-DLLRF-01:REVCIRC:Const:Raw-U:C2:S', 0, 0.0], @@ -349,6 +349,23 @@ def get_dict(): ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff2-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff3-SP', 0, 0.0], ['RA-RaBO01:RF-LLRF:Hw2AmpVCavCoeff4-SP', 0, 0.0], + # CalSys Offsets + ['RA-RaBO01:RF-RFCalSys:OFSdB1-Mon', 0, 0.0], # [dB] + ['RA-RaBO01:RF-RFCalSys:OFSdB2-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB3-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB4-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB5-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB6-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB7-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB8-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB9-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB10-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB11-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB12-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB13-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB14-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB15-Mon', 0, 0.0], + ['RA-RaBO01:RF-RFCalSys:OFSdB16-Mon', 0, 0.0], ] @@ -748,6 +765,23 @@ def get_dict(): ['RA-RaSIA01:RF-LLRF:AmpVCav2HwCoeff4-SP', 0, 0.0], # Cavity Shunt impedance ['SI-02SB:RF-P7Cav:Rsh-SP', 0, 0.0], # [Ohm] + # CalSys Offsets + ['RA-RaSIA01:RF-RFCalSys:OFSdB1-Mon', 0, 0.0], # [dB] + ['RA-RaSIA01:RF-RFCalSys:OFSdB2-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB3-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB4-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB5-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB6-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB7-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB8-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB9-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB10-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB11-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB12-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB13-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB14-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB15-Mon', 0, 0.0], + ['RA-RaSIA01:RF-RFCalSys:OFSdB16-Mon', 0, 0.0], ] From 745c6600dabfe64c52616b325af243becc316178 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 25 Jan 2024 14:31:30 -0300 Subject: [PATCH 284/309] Remove unnecessary empty line --- siriuspy/siriuspy/devices/ids.py | 1 - 1 file changed, 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index f6ecac0c6..18e6be8ce 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -748,7 +748,6 @@ def _calc_move_eta_model(dparam, param_vel, param_acc=None): return dtime_total - class APU(IDBase): """APU Insertion Device.""" From acc38e264deeeae69a1f448018a76db5728c3e1e Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 25 Jan 2024 14:33:21 -0300 Subject: [PATCH 285/309] Minor docstring changes --- siriuspy/siriuspy/devices/idff.py | 2 +- siriuspy/siriuspy/devices/ids.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/devices/idff.py b/siriuspy/siriuspy/devices/idff.py index 212685921..f18e2d3b4 100644 --- a/siriuspy/siriuspy/devices/idff.py +++ b/siriuspy/siriuspy/devices/idff.py @@ -1,4 +1,4 @@ -"""Insertion Devices Feedforward Devices.""" +"""Insertion Device Feedforward Devices.""" from ..namesys import SiriusPVName as _SiriusPVName from ..search import IDSearch as _IDSearch diff --git a/siriuspy/siriuspy/devices/ids.py b/siriuspy/siriuspy/devices/ids.py index 18e6be8ce..d3a70335c 100644 --- a/siriuspy/siriuspy/devices/ids.py +++ b/siriuspy/siriuspy/devices/ids.py @@ -1,4 +1,4 @@ -"""Define Insertion Devices.""" +"""Insertion Devices.""" import time as _time import inspect as _inspect From 496d2415668a2dca1b4a3880bcd56f6f8089a650 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 5 Feb 2024 16:09:07 -0300 Subject: [PATCH 286/309] envars.MNT: return LA IP once this one was removed from 10.0.38 subnet --- siriuspy/siriuspy/envars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/envars.py b/siriuspy/siriuspy/envars.py index a899d69a2..863622dd2 100644 --- a/siriuspy/siriuspy/envars.py +++ b/siriuspy/siriuspy/envars.py @@ -46,7 +46,7 @@ default='http://10.0.38.59/control-system-constants') SRVURL_CSCONSTS_2 = _os.environ.get( 'SIRIUS_URL_CONSTS_2', - default='http://10.0.38.46/control-system-constants') + default='http://10.128.255.3/control-system-constants') SRVURL_LOGBOOK = _os.environ.get( 'SIRIUS_URL_LOGBOOK', default='http://10.0.38.42/Olog') @@ -55,7 +55,7 @@ default='http://10.0.38.59/config-db') SRVURL_CONFIGDB_2 = _os.environ.get( 'SIRIUS_URL_CONFIGDB_2', - default='http://10.0.38.46/config-db') + default='http://10.128.255.3/config-db') SRVURL_ARCHIVER = _os.environ.get( 'SIRIUS_URL_ARCHIVER', default='https://10.0.38.42') From 7d1894655ce2250fdc167812ccd6466ed2afacde Mon Sep 17 00:00:00 2001 From: Fernando Date: Tue, 6 Feb 2024 12:55:05 -0300 Subject: [PATCH 287/309] DEV.FAMBPM.BUG: Fix config_mturn_acquisition. --- siriuspy/siriuspy/devices/bpm_fam.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/devices/bpm_fam.py b/siriuspy/siriuspy/devices/bpm_fam.py index c0ae3f93f..c0e475f9c 100644 --- a/siriuspy/siriuspy/devices/bpm_fam.py +++ b/siriuspy/siriuspy/devices/bpm_fam.py @@ -332,7 +332,8 @@ def config_mturn_acquisition( 'adcswp': self._csbpm.AcqChan.ADCSwp, 'adc': self._csbpm.AcqChan.ADC, } - acq_rate = dic.get(acq_rate.lower(), acq_rate) + if isinstance(acq_rate, str): + acq_rate = dic.get(acq_rate.lower()) if acq_rate not in self._csbpm.AcqChan: raise ValueError( str(acq_rate) + ' is not a valid acquisition rate.') From 6123ee2066c44c081909c3e0f634f2df4f2d17b4 Mon Sep 17 00:00:00 2001 From: Fernando Date: Tue, 6 Feb 2024 18:37:53 -0300 Subject: [PATCH 288/309] CONFDB.ENH: Add method to compare configs. --- .../clientconfigdb/configdb_client.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index 730199da0..e982659cf 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -3,6 +3,7 @@ import json as _json import datetime as _datetime +import re as _re from urllib import parse as _parse from urllib.request import Request as _Request, urlopen as _urlopen from urllib.error import URLError as _URLError @@ -170,6 +171,39 @@ def check_valid_value(self, value, config_type=None): config_type = self._process_config_type(config_type) return _templates.check_value(config_type, value) + @staticmethod + def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): + """Compare "pvs" attribute of configs 1 and 2. + + Print the differences. + + Args: + config1 (dict): Valid configuration with "pvs" attribute. + config2 (dict): Valid configuration with "pvs" attribute. + pos_pattern (str, optional): Only PVs with this pattern will be + checked. Defaults to None. None means all PVs will be compared. + neg_pattern (_type_, optional): PVs which match this pattern will + not be checked. Defaults to None. None means no PV will be + excluded from comparison. In case of conflict with + `pos_pattern`, it will take precedence. + """ + pos_re = _re.compile('' if pos_pattern is None else pos_pattern) + # In case of None in neg_pattern, create a regexp that never matches: + # https://stackoverflow.com/questions/1723182/a-regex-that-will-never-be-matched-by-anything + neg_re = _re.compile(r'(?!x)x' if neg_pattern is None else pos_pattern) + + cf1pvs = {n: v for n, v, t in config1['pvs']} + cf2pvs = {n: v for n, v, t in config2['pvs']} + + allpvs = set(cf1pvs.keys() | cf2pvs.keys()) + for pv in allpvs: + if pos_re.match(pv) and not neg_re.match(pv): + continue + val1 = str(cf1pvs.get(pv, 'Not present')) + val2 = str(cf2pvs.get(pv, 'Not present')) + if val1 != val2: + print(f'{pv:50s} {val1[:30]:30s} {val2[:30]:30s}') + @classmethod def check_valid_configname(cls, name): "Check if `name` is a valid name for configurations." From 4ed73d53a752f601571683af5494005eec64db1d Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Tue, 6 Feb 2024 18:44:19 -0300 Subject: [PATCH 289/309] Update test_configdb_client.py --- siriuspy/tests/clientconfigdb/test_configdb_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/siriuspy/tests/clientconfigdb/test_configdb_client.py b/siriuspy/tests/clientconfigdb/test_configdb_client.py index c63e9f0c1..efc003e65 100755 --- a/siriuspy/tests/clientconfigdb/test_configdb_client.py +++ b/siriuspy/tests/clientconfigdb/test_configdb_client.py @@ -31,6 +31,7 @@ class TestConfigDBClient(TestCase): 'check_valid_configname', "conv_timestamp_txt_2_flt", "conv_timestamp_flt_2_txt", + "compare_configs", } def test_api(self): From 57b9b70e3d06803510e5af24a5a5ebb1aa303c99 Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Tue, 6 Feb 2024 19:27:48 -0300 Subject: [PATCH 290/309] Atualizar o configdb_client.py --- siriuspy/siriuspy/clientconfigdb/configdb_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index e982659cf..cfe1df560 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -197,7 +197,7 @@ def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): allpvs = set(cf1pvs.keys() | cf2pvs.keys()) for pv in allpvs: - if pos_re.match(pv) and not neg_re.match(pv): + if not pos_re.match(pv) and neg_re.match(pv): continue val1 = str(cf1pvs.get(pv, 'Not present')) val2 = str(cf2pvs.get(pv, 'Not present')) From a33b3d7fefc785552ba6b82fd6ab4ca8e293591c Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 7 Feb 2024 09:12:22 -0300 Subject: [PATCH 291/309] CONFIGDB.BUG: Solve problem in regex testing on compare_configs method. --- siriuspy/siriuspy/clientconfigdb/configdb_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index cfe1df560..983cd1cf3 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -190,14 +190,14 @@ def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): pos_re = _re.compile('' if pos_pattern is None else pos_pattern) # In case of None in neg_pattern, create a regexp that never matches: # https://stackoverflow.com/questions/1723182/a-regex-that-will-never-be-matched-by-anything - neg_re = _re.compile(r'(?!x)x' if neg_pattern is None else pos_pattern) + neg_re = _re.compile(r'(?!x)x' if neg_pattern is None else neg_pattern) cf1pvs = {n: v for n, v, t in config1['pvs']} cf2pvs = {n: v for n, v, t in config2['pvs']} allpvs = set(cf1pvs.keys() | cf2pvs.keys()) for pv in allpvs: - if not pos_re.match(pv) and neg_re.match(pv): + if not pos_re.match(pv) or neg_re.match(pv): continue val1 = str(cf1pvs.get(pv, 'Not present')) val2 = str(cf2pvs.get(pv, 'Not present')) From 5e985471f7aa657235a512dbc99f5dacc6e4af81 Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Wed, 7 Feb 2024 11:02:29 -0300 Subject: [PATCH 292/309] CONFDB.MNT: Remove unnecessary conversion. --- siriuspy/siriuspy/clientconfigdb/configdb_client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index 983cd1cf3..ec7d31fda 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -195,8 +195,7 @@ def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): cf1pvs = {n: v for n, v, t in config1['pvs']} cf2pvs = {n: v for n, v, t in config2['pvs']} - allpvs = set(cf1pvs.keys() | cf2pvs.keys()) - for pv in allpvs: + for pv in cf1pvs.keys() | cf2pvs.keys(): if not pos_re.match(pv) or neg_re.match(pv): continue val1 = str(cf1pvs.get(pv, 'Not present')) From dec9df178540aee03422f4338873c8f605ba0972 Mon Sep 17 00:00:00 2001 From: fernandohds564 Date: Wed, 7 Feb 2024 11:03:30 -0300 Subject: [PATCH 293/309] CONFIGDB.MNT: remove unnecessary variable naming. --- siriuspy/siriuspy/clientconfigdb/configdb_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index ec7d31fda..3d281ebdd 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -192,8 +192,8 @@ def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): # https://stackoverflow.com/questions/1723182/a-regex-that-will-never-be-matched-by-anything neg_re = _re.compile(r'(?!x)x' if neg_pattern is None else neg_pattern) - cf1pvs = {n: v for n, v, t in config1['pvs']} - cf2pvs = {n: v for n, v, t in config2['pvs']} + cf1pvs = {n: v for n, v, _ in config1['pvs']} + cf2pvs = {n: v for n, v, _ in config2['pvs']} for pv in cf1pvs.keys() | cf2pvs.keys(): if not pos_re.match(pv) or neg_re.match(pv): From ba51d1b8852499581d286cc9fa31c682cd96ec6f Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 20 Feb 2024 17:05:58 -0300 Subject: [PATCH 294/309] injctrl.ENH: do not control TB Sept in PU standby mode --- siriuspy/siriuspy/injctrl/main.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index 38d1783a4..f5ac94ebd 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -192,10 +192,18 @@ def __init__(self): curr_pvo.add_callback(self._callback_autostop) curr_pvo.connection_callbacks.append(self._callback_conn_autostop) - self._pu_names = self._injsys_dev.handlers['as_pu'].punames - self._pu_devs = self._injsys_dev.handlers['as_pu'].pudevices + self._pu_names, self._pu_devs = list(), list() self._pu_refvolt = list() - for dev in self._pu_devs: + for idx, pun in enumerate(self._injsys_dev.handlers['as_pu'].punames): + # NOTE: The voltage of the TB pulsed magnets are used to define + # enable conditions of the egun trigger. To avoid changing the + # trigger enable status during top-up, we will not include these + # magnets in standby/warm up. + if pun.startswith('TB'): + continue + self._pu_names.append(pun) + dev = self._injsys_dev.handlers['as_pu'].pudevices[idx] + self._pu_devs.append(dev) pvo = dev.pv_object('Voltage-SP') self._pu_refvolt.append(pvo.value) pvo.add_callback(self._callback_update_pu_refvolt) From 39cbaa21fc1567215c026639e732d6627f8c8ef4 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 20 Feb 2024 18:09:34 -0300 Subject: [PATCH 295/309] injctrl.ENH: do not update PU reference if standby is enabled --- siriuspy/siriuspy/injctrl/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index f5ac94ebd..f91048119 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -1125,6 +1125,11 @@ def _callback_update_pumode(self, **kws): def _callback_update_pu_refvolt(self, pvname, value, **kws): if value is None: return + # do not update PU reference voltage if standby is enabled + if self._topup_pustandbyenbl == _Const.DsblEnbl.Enbl: + self._update_log(f'WARN:PU Standby is enabled, ignoring') + self._update_log(f'WARN:setpoint to {pvname}') + return if self._aspu_standby_state == _Const.StandbyInject.Standby: return devname = _PVName(pvname).device_name From 4077263d3d8b37572a6755642a9ff31441515f3c Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 20 Feb 2024 18:12:02 -0300 Subject: [PATCH 296/309] Update version to 2.87.0 --- siriuspy/siriuspy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/VERSION b/siriuspy/siriuspy/VERSION index c99417194..863f84e5c 100644 --- a/siriuspy/siriuspy/VERSION +++ b/siriuspy/siriuspy/VERSION @@ -1 +1 @@ -2.86.0 +2.87.0 From 0ce2ca55b767468ea5e4d542b605032776ffcbc7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 26 Feb 2024 19:13:52 -0300 Subject: [PATCH 297/309] injctrl.MNT: remove log messages to avoid several logs during top-up --- siriuspy/siriuspy/injctrl/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index f91048119..1be757097 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -1127,8 +1127,6 @@ def _callback_update_pu_refvolt(self, pvname, value, **kws): return # do not update PU reference voltage if standby is enabled if self._topup_pustandbyenbl == _Const.DsblEnbl.Enbl: - self._update_log(f'WARN:PU Standby is enabled, ignoring') - self._update_log(f'WARN:setpoint to {pvname}') return if self._aspu_standby_state == _Const.StandbyInject.Standby: return From ed06a0a1fa7153661e27459f1856ebea0f560034 Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 27 Feb 2024 15:30:42 -0300 Subject: [PATCH 298/309] Sort PVs comparison --- siriuspy/siriuspy/clientconfigdb/configdb_client.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/clientconfigdb/configdb_client.py b/siriuspy/siriuspy/clientconfigdb/configdb_client.py index 3d281ebdd..2cb93034c 100644 --- a/siriuspy/siriuspy/clientconfigdb/configdb_client.py +++ b/siriuspy/siriuspy/clientconfigdb/configdb_client.py @@ -195,13 +195,19 @@ def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None): cf1pvs = {n: v for n, v, _ in config1['pvs']} cf2pvs = {n: v for n, v, _ in config2['pvs']} + lines = [] for pv in cf1pvs.keys() | cf2pvs.keys(): if not pos_re.match(pv) or neg_re.match(pv): continue val1 = str(cf1pvs.get(pv, 'Not present')) val2 = str(cf2pvs.get(pv, 'Not present')) if val1 != val2: - print(f'{pv:50s} {val1[:30]:30s} {val2[:30]:30s}') + lines.append(f'{pv:50s} {val1[:30]:30s} {val2[:30]:30s}') + + # sort and print lines + lines = sorted(lines) + for line in lines: + print(line) @classmethod def check_valid_configname(cls, name): From 3e886efd43ee7dfaa7467b7d55ad4f8026fcafe3 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 7 Mar 2024 00:10:53 -0300 Subject: [PATCH 299/309] Add getRecentlyModifiedPVs method to ClientArchiver --- siriuspy/siriuspy/clientarch/client.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/clientarch/client.py b/siriuspy/siriuspy/clientarch/client.py index 189ccd61f..4d88441f3 100644 --- a/siriuspy/siriuspy/clientarch/client.py +++ b/siriuspy/siriuspy/clientarch/client.py @@ -1,7 +1,10 @@ #!/usr/bin/env python-sirius """Fetcher module. -See https://slacmshankar.github.io/epicsarchiver_docs/userguide.html +See + https://slacmshankar.github.io/epicsarchiver_docs/userguide.html + http://slacmshankar.github.io/epicsarchiver_docs/details.html + http://slacmshankar.github.io/epicsarchiver_docs/api/mgmt_scriptables.html """ from threading import Thread as _Thread @@ -134,6 +137,18 @@ def getPausedPVsReport(self): resp = self._make_request(url, return_json=True) return None if not resp else resp + def getRecentlyModifiedPVs(self, limit=None): + """Get recently modified PVs. + + Currently version of the epics archiver appliance returns pvname + list from oldest to newest modified timestamps.""" + method = 'getRecentlyModifiedPVs' + if limit is not None: + method += f'?limit={str(limit)}' + url = self._create_url(method=method) + resp = self._make_request(url, return_json=True) + return None if not resp else resp + def pausePVs(self, pvnames): """Pause PVs.""" if not isinstance(pvnames, (list, tuple)): From 7076c566dca5df1a6a83ea4058b9e548e37bbde0 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 7 Mar 2024 00:12:32 -0300 Subject: [PATCH 300/309] Remove inappropriate she-bang in clientarch --- siriuspy/siriuspy/clientarch/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/siriuspy/siriuspy/clientarch/client.py b/siriuspy/siriuspy/clientarch/client.py index 4d88441f3..65f9a7e30 100644 --- a/siriuspy/siriuspy/clientarch/client.py +++ b/siriuspy/siriuspy/clientarch/client.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python-sirius """Fetcher module. See From c2035defb6b61dd019d9ede8465896e65f55f120 Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 7 Mar 2024 13:59:50 -0300 Subject: [PATCH 301/309] Update clientarch Time and ClientArch --- siriuspy/siriuspy/clientarch/client.py | 16 ++++++++++++++-- siriuspy/siriuspy/clientarch/time.py | 8 ++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/clientarch/client.py b/siriuspy/siriuspy/clientarch/client.py index 65f9a7e30..67acaa8c0 100644 --- a/siriuspy/siriuspy/clientarch/client.py +++ b/siriuspy/siriuspy/clientarch/client.py @@ -13,11 +13,14 @@ import logging as _log import urllib3 as _urllib3 from aiohttp import ClientSession as _ClientSession +# from datetime import datetime as _datetime +# from calendar import timegm as _timegm import numpy as _np from .. import envars as _envars from . import exceptions as _exceptions +from .time import Time as _Time class ClientArchiver: @@ -136,16 +139,25 @@ def getPausedPVsReport(self): resp = self._make_request(url, return_json=True) return None if not resp else resp - def getRecentlyModifiedPVs(self, limit=None): - """Get recently modified PVs. + def getRecentlyModifiedPVs(self, limit=None, epoch_time=True): + """Get list of PVs with recently modified PVTypeInfo. Currently version of the epics archiver appliance returns pvname list from oldest to newest modified timestamps.""" method = 'getRecentlyModifiedPVs' + # get data if limit is not None: method += f'?limit={str(limit)}' url = self._create_url(method=method) resp = self._make_request(url, return_json=True) + + # convert to epoch, if the case + if resp and epoch_time: + for item in resp: + modtime = item['modificationTime'][:-7] # remove ISO8601 offset + epoch_time = _Time.conv_to_epoch(modtime, '%b/%d/%Y %H:%M:%S') + item['modificationTime'] = epoch_time + return None if not resp else resp def pausePVs(self, pvnames): diff --git a/siriuspy/siriuspy/clientarch/time.py b/siriuspy/siriuspy/clientarch/time.py index 899573812..9983cd1e5 100644 --- a/siriuspy/siriuspy/clientarch/time.py +++ b/siriuspy/siriuspy/clientarch/time.py @@ -2,6 +2,7 @@ from . import exceptions as _exceptions from datetime import datetime as _datetime, timedelta as _timedelta +from calendar import timegm as _timegm class Time(_datetime): @@ -94,6 +95,13 @@ def __sub__(self, other): sub = super().__sub__(other) return Time(timestamp=sub.timestamp()) + @staticmethod + def conv_to_epoch(time, datetime_format): + """get epoch from datetime.""" + utc_time = _datetime.strptime(time, datetime_format) + epoch_time = _timegm(utc_time.timetuple()) + return epoch_time + def get_time_intervals( time_start, time_stop, interval, return_isoformat=False): From 01a6405d251c042b5c3f3e1b426953e64081463a Mon Sep 17 00:00:00 2001 From: ximenes Date: Thu, 7 Mar 2024 14:08:32 -0300 Subject: [PATCH 302/309] Add timeout arg to update methods in pvarch classes --- siriuspy/siriuspy/clientarch/pvarch.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/siriuspy/siriuspy/clientarch/pvarch.py b/siriuspy/siriuspy/clientarch/pvarch.py index d481d552a..ab0dede75 100644 --- a/siriuspy/siriuspy/clientarch/pvarch.py +++ b/siriuspy/siriuspy/clientarch/pvarch.py @@ -112,9 +112,11 @@ def is_archived(self): return False return True - def update(self): + def update(self, timeout=None): """.""" self.connect() + if timeout is not None: + self.timeout = None data = self.connector.getPVDetails(self.pvname) if not data: return False @@ -280,9 +282,11 @@ def severity(self): """Severity data.""" return self._severity - def update(self, mean_sec=None, parallel=True): + def update(self, mean_sec=None, parallel=True, timeout=None): """Update.""" self.connect() + if timeout is not None: + self.timeout = None if None in (self.timestamp_start, self.timestamp_stop): print('Start and stop timestamps not defined! Aborting.') return @@ -493,9 +497,11 @@ def parallel_query_bin_interval(self, new_intvl): self._pvdata[pvname].parallel_query_bin_interval = \ self._parallel_query_bin_interval - def update(self, mean_sec=None, parallel=True): + def update(self, mean_sec=None, parallel=True, timeout=None): """Update.""" self.connect() + if timeout is not None: + self.timeout = None if None in (self.timestamp_start, self.timestamp_stop): print('Start and stop timestamps not defined! Aborting.') return From a5b9a76ace8cdf8183150fceceb93095124a588b Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 11 Mar 2024 10:35:59 -0300 Subject: [PATCH 303/309] Fix wrong timeout impl. in pvarch --- siriuspy/siriuspy/clientarch/pvarch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/clientarch/pvarch.py b/siriuspy/siriuspy/clientarch/pvarch.py index ab0dede75..ad0d81a22 100644 --- a/siriuspy/siriuspy/clientarch/pvarch.py +++ b/siriuspy/siriuspy/clientarch/pvarch.py @@ -116,7 +116,7 @@ def update(self, timeout=None): """.""" self.connect() if timeout is not None: - self.timeout = None + self.timeout = timeout data = self.connector.getPVDetails(self.pvname) if not data: return False @@ -286,7 +286,7 @@ def update(self, mean_sec=None, parallel=True, timeout=None): """Update.""" self.connect() if timeout is not None: - self.timeout = None + self.timeout = timeout if None in (self.timestamp_start, self.timestamp_stop): print('Start and stop timestamps not defined! Aborting.') return From 89d25945249c3f501c28c5c3b80b55e6a95d5f63 Mon Sep 17 00:00:00 2001 From: ximenes Date: Mon, 11 Mar 2024 14:44:09 -0300 Subject: [PATCH 304/309] Remove commented out lines --- siriuspy/siriuspy/clientarch/client.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/siriuspy/siriuspy/clientarch/client.py b/siriuspy/siriuspy/clientarch/client.py index 67acaa8c0..fa6c4f0d2 100644 --- a/siriuspy/siriuspy/clientarch/client.py +++ b/siriuspy/siriuspy/clientarch/client.py @@ -13,8 +13,6 @@ import logging as _log import urllib3 as _urllib3 from aiohttp import ClientSession as _ClientSession -# from datetime import datetime as _datetime -# from calendar import timegm as _timegm import numpy as _np From 8e31580a646394176bc3b0f06c702c2b0337b2ab Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 16 Apr 2024 11:54:39 -0300 Subject: [PATCH 305/309] orbintlk.FIX: handle BPM false positive problem --- siriuspy/siriuspy/orbintlk/csdev.py | 1 + siriuspy/siriuspy/orbintlk/main.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 3d9f303fe..441993a0e 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -213,6 +213,7 @@ def __init__(self): if NR_BPM != len(self.bpm_names): raise ValueError('Inconsistent NR_BPM parameter!') self.bpm_nicknames = _BPMSearch.get_nicknames(self.bpm_names) + self.bpm_idcs = {b: idx for idx, b in enumerate(self.bpm_names)} # bpm position along the ring self.bpm_pos = _BPMSearch.get_positions(self.bpm_names) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index cce2cd5de..7ca7dbd5e 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -1358,13 +1358,23 @@ def _callback_bpm_intlk(self, pvname, value, **kws): if not value: return # launch thread to log interlock details + bpmname = _PVName(pvname).device_name _CAThread( target=self._log_bpm_intlk, - args=(_PVName(pvname).device_name, ), + args=(bpmname, ), daemon=True).start() # launch thread to send interlock to RF as a backup if self._thread_cbbpm and self._thread_cbbpm.is_alive(): return + + # NOTE: the next lines help to avoid killing beam in case one BPM that + # is not enabled raises a false positive interlock signal. + idx = self._const.bpm_idcs[bpmname] + enbl = self._enable_lists['pos'][idx] or self._enable_lists['ang'][idx] + if not enbl: + self._update_log(f'WARN:{bpmname} false positive') + return + self._thread_cbbpm = _CAThread( target=self._do_callback_bpm_intlk, daemon=True) self._thread_cbbpm.start() From 1fb0bf5565884854c931bce8e80b6540ceb7b9f5 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Tue, 16 Apr 2024 11:56:09 -0300 Subject: [PATCH 306/309] Update version to 2.87.1 --- siriuspy/siriuspy/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/siriuspy/siriuspy/VERSION b/siriuspy/siriuspy/VERSION index 863f84e5c..ece2083a6 100644 --- a/siriuspy/siriuspy/VERSION +++ b/siriuspy/siriuspy/VERSION @@ -1 +1 @@ -2.87.0 +2.87.1 From 992b9fc99a050afc44d3f8a16e3feb708626b10c Mon Sep 17 00:00:00 2001 From: ximenes Date: Tue, 16 Apr 2024 16:43:58 -0300 Subject: [PATCH 307/309] fix manname bug --- siriuspy/siriuspy/devices/pwrsupply.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/siriuspy/siriuspy/devices/pwrsupply.py b/siriuspy/siriuspy/devices/pwrsupply.py index b1679e3f6..9fab6b677 100644 --- a/siriuspy/siriuspy/devices/pwrsupply.py +++ b/siriuspy/siriuspy/devices/pwrsupply.py @@ -111,6 +111,8 @@ def __init__(self, devname, auto_monitor_mon=False, props2init='all'): name = devname.substitute(dis='MA') if name.dev == 'B1B2' or (name.sec == 'BO' and name.dev == 'B'): maname = name.substitute(idx='') + else: + maname = name self._normalizer = _NormFactory.create(maname) except: self._normalizer = None From e7be656dd112d8a35341eb5886b4f9cd0a4315af Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 22 Apr 2024 16:57:17 -0300 Subject: [PATCH 308/309] orbintlk.ENH: enable DCCT PsMtm logs --- siriuspy/siriuspy/orbintlk/csdev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 441993a0e..29bf2a3f5 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -84,12 +84,12 @@ class Const(_csdev.Const): ('Src-Sel', 0), ('State-Sel', 1), ('Polarity-Sel', 0), - ('Log-Sel', 0))), + ('Log-Sel', 1))), ('SI-14C4:TI-DCCT-PsMtm', ( ('Src-Sel', 0), ('State-Sel', 1), ('Polarity-Sel', 0), - ('Log-Sel', 0))), + ('Log-Sel', 1))), ] FOUTSFIXED_RXENBL = { 'CA-RaTim:TI-Fout-2': 0b01000001, From ac35904099f9c1f637ade652a1587a43a50124e7 Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Mon, 22 Apr 2024 18:30:32 -0300 Subject: [PATCH 309/309] orbintlk.FIX: fix EVG RxEnbl value --- siriuspy/siriuspy/orbintlk/csdev.py | 26 ++++++++++++++------------ siriuspy/siriuspy/orbintlk/main.py | 6 ++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/siriuspy/siriuspy/orbintlk/csdev.py b/siriuspy/siriuspy/orbintlk/csdev.py index 29bf2a3f5..f5c998cf7 100644 --- a/siriuspy/siriuspy/orbintlk/csdev.py +++ b/siriuspy/siriuspy/orbintlk/csdev.py @@ -139,23 +139,25 @@ def EVG_CONFIGS(cls): if cls.__EVG_CONFIGS is not None: return cls.__EVG_CONFIGS + hltg_enbl = [ + 'SI-Fam:TI-BPM-OrbIntlk', + 'SI-Fam:TI-OrbIntlkRedundancy', + ] + lltg_enbl = [] + for hltg in hltg_enbl: + lltg_enbl.extend(_HLTimeSearch.get_ll_trigger_names(hltg)) + lltg_enbl = set(lltg_enbl) + fouts = set() evgchans = set() - evgrxenbl = list() - for ch in _LLTimeSearch.get_connections_twds_evg(): - if ch.dev != 'BPM': - continue - if ch.sec != 'SI': - continue - if ch.dev == 'BPM' and ch.sub.endswith(('SA', 'SB', 'SP')): - continue - fch = _LLTimeSearch.get_fout_channel(ch) + evgrxenbl = set() + for lltg in lltg_enbl: + fch = _LLTimeSearch.get_fout_channel(lltg) fouts.add(fch.device_name) evgch = _LLTimeSearch.get_evg_channel(fch) - if evgch in evgchans: - continue evgchans.add(evgch) - evgrxenbl.append(int(evgch.propty[3:])) + evgrxenbl.add(int(evgch.propty[3:])) + evgrxenbl = sorted(evgrxenbl) hlevts = _HLTimeSearch.get_hl_events() evtin0 = int(hlevts['Intlk'].strip('Evt')) diff --git a/siriuspy/siriuspy/orbintlk/main.py b/siriuspy/siriuspy/orbintlk/main.py index 7ca7dbd5e..60c7c0c2b 100644 --- a/siriuspy/siriuspy/orbintlk/main.py +++ b/siriuspy/siriuspy/orbintlk/main.py @@ -105,8 +105,10 @@ def __init__(self, tests=False): pvo.add_callback(self._callback_evg_rxlock) # # Fouts - foutnames = list(self._const.FOUTS_2_MON) + \ - list(self._const.FOUTSFIXED_RXENBL.keys()) + foutnames = list( + self._const.FOUTS_2_MON | + self._const.FOUTSFIXED_RXENBL.keys() + ) self._thread_cbfout = {fout: None for fout in foutnames} self._fout_devs = { devname: _Device(