diff --git a/cfg/dil5_cfg.py b/cfg/dil5_cfg.py index 1ab193dc..ca34d360 100644 --- a/cfg/dil5_cfg.py +++ b/cfg/dil5_cfg.py @@ -12,7 +12,7 @@ logo_ip = '192.168.0.3' Node('dil5.linse@psi.ch', 'dil5 on linse-dil5', interface='tcp://5000', - secondary = ['ws://8010'] + secondary = ['ws://8051'] ) Mod('logo', diff --git a/frappy_psi/dilution.py b/frappy_psi/dilution.py index 149c391e..a422d948 100644 --- a/frappy_psi/dilution.py +++ b/frappy_psi/dilution.py @@ -20,6 +20,7 @@ # # ***************************************************************************** +import time from frappy.core import Readable, Drivable, Parameter, Attached, FloatRange, \ Command, IDLE, BUSY, WARN, ERROR, Property from frappy.datatypes import EnumType, IntRange, BoolType, StructOf, StringType @@ -86,14 +87,14 @@ class Dilution(HasStates, Drivable): _start_time = 0 init = True - _warn_manual_work = None + _valve_warnings = None def write_target(self, target): self.log.info('start %s', target) if target == 'condense': - self.start_machine(self.start_condense) + self.condense() elif target == 'remove': - self.start_machine(self.start_remove) + self.remove() else: raise RangeError(r'invalid command {target!r}') self.log.info('started %s', target) @@ -102,11 +103,15 @@ class Dilution(HasStates, Drivable): @Command def condense(self): """condense mixture""" + self._valve_warnings = None + self.handle_valves(self.condense_valves) self.start_machine(self.start_condense) @Command def remove(self): """remove mixture""" + self._valve_warnings = None + self.handle_valves(self.remove_valves) self.start_machine(self.start_remove) @status_code(BUSY) @@ -116,14 +121,13 @@ class Dilution(HasStates, Drivable): pumpstate = self.forepump.read_value() if self.turbopump: self.turbopump.write_target(0) - self.handle_valves(**self.condense_valves) + self.handle_valves(self.condense_valves) self._start_time = state.now if not pumpstate: # wait longer for starting fore pump self._start_time += 10 return Retry if self.wait_valves(): return Retry - self.check_valve_result() return self.condensing @status_code(BUSY) @@ -174,10 +178,9 @@ class Dilution(HasStates, Drivable): def circulate(self, state): """Zirkuliert die Mischung.""" if state.init: - self.handle_valves(**self.condense_valves) + self.handle_valves(self.condense_valves) if self.wait_valves(): return Retry - self.check_valve_result() return Finish @status_code(BUSY, 'remove (wait for turbo shut down)') @@ -185,7 +188,7 @@ class Dilution(HasStates, Drivable): """Entfernt die Mischung.""" if state.init: - self.handle_valves(**self.remove_valves) + self.handle_valves(self.remove_valves) if self.turbopump is not None: self._start_time = state.now self.turbopump.write_target(0) @@ -226,39 +229,40 @@ class Dilution(HasStates, Drivable): @status_code(BUSY) def close_valves_after_remove(self, state): - self.log.warn('V %r %r %r', state.init, self._valves_failed, self.valves_after_remove) + self.log.warn('V %r %r', state.init, self.valves_after_remove) if state.init: - self.handle_valves(**self.valves_after_remove) + self.handle_valves(self.valves_after_remove) return Retry self.turbopump.write_target(0) if self.wait_valves(): return Retry - self.check_valve_result() - self._warn_manual_work = True + self._valve_warnings = self.check_after_remove return self.final_status(WARN, 'please check manual valves') def read_status(self): status = super().read_status() self.value = status[1] - if status[0] < ERROR and self._warn_manual_work: - try: - self.handle_valves(**self.check_after_remove) - self._warn_manual_work = False - except ImpossibleError: - return WARN, f'please close manual valves {",".join(self._valves_failed[False])}' + if status[0] < ERROR and self._valve_warnings: + valves_failed = self.inner_handle_valves(**self._valve_warnings) + if valves_failed[False]: + return WARN, f'please close manual valves {",".join(valves_failed[False])}' + self._valve_warnings = None return status - def handle_valves(self, check_closed=(), check_open=(), close=(), open=()): - """check ot set given valves + def inner_handle_valves(self, check_closed=(), check_open=(), close=(), open=()): + """check or set given valves - raises ImpossibleError, when checks fails + returns failed valves raises ImpossibleError, when checks fails """ self._valves_to_wait_for = {} - self._valves_failed = {True: [], False: []} + self._valve_change_time = time.monotonic() + valves_failed = {True: [], False: []} for flag, valves in enumerate([check_closed, check_open]): for vname in valves.split(): if self.secNode.modules[vname].read_value() != flag: - self._valves_failed[flag].append(vname) + valves_failed[flag].append(vname) + if valves_failed: + return valves_failed for flag, valves in enumerate([close, open]): for vname in valves.split(): valve = self.secNode.modules[vname] @@ -268,28 +272,45 @@ class Dilution(HasStates, Drivable): elif valve.read_value() != flag: self.log.warn('valve %s=%r did not go to %r', vname, self.secNode.modules[vname].read_value(), flag) # self._valves_failed[flag].append(vname) + return {} + + def handle_valves(self, valveset): + """check or set given valves + + raises ImpossibleError, when checks fails + busy valves are stored in self._valves_to_wait_for + and handled in :meth:wait_valves later + """ + valves_failed = self.inner_handle_valves(**valveset) + self.check_failed_valves(valves_failed) + + def check_failed_valves(self, valves_failed, addtext=''): + result = [] + for flag, valves in valves_failed.items(): + if valves: + result.append(f"{','.join(valves)} not {'open' if flag else 'closed'}") + if result: + raise ImpossibleError(f"failed: {', '.join(result)}{addtext}") def wait_valves(self): busy = False + valves_failed = {True: [], False: []} + timedout = time.monotonic() > self._valve_change_time + 10 for vname, (valve, flag) in dict(self._valves_to_wait_for.items()): statuscode = valve.read_status()[0] - if statuscode == BUSY: + if statuscode == BUSY and not timedout: busy = True continue if valve.read_value() == flag and statuscode == IDLE: self._valves_to_wait_for.pop(vname) else: - self._valves_failed[flag].append(vname) + valves_failed[flag].append(vname) + if not busy: + self.check_failed_valves(valves_failed) + elif timedout: + self.check_failed_valves(valves_failed, ' after 10 sec') return busy - def check_valve_result(self): - result = [] - for flag, valves in self._valves_failed.items(): - if valves: - result.append(f"{','.join(valves)} not {'open' if flag else 'closed'}") - if result: - raise ImpossibleError(f"failed: {', '.join(result)}") - class DIL5(Dilution): condense_valves = {