diff --git a/frappy_psi/dilution.py b/frappy_psi/dilution.py index 11f78da..9dc06fe 100644 --- a/frappy_psi/dilution.py +++ b/frappy_psi/dilution.py @@ -55,38 +55,42 @@ class Dilution(HasStates, Drivable): condense_valve = Attached() dump_valve = Attached() - circulate_pump = Attached() + forepump = Attached() compressor = Attached(mandatory=False) turbopump = Attached(mandatory=False) condenseline_valve = Attached() circuitshort_valve = Attached() still_pressure = Attached() + still_pressure_turbo = Attached(mandatory=False) value = Parameter('current state', EnumType(T), default=0) target = Parameter('target state', EnumType(T), default=0) sorbpumped = Parameter('sorb pump done', BoolType(), default=False) + dump_pressure = Attached() #ls372 = Attached() - V5 = Attached() #Name noch ändern!!! - p1 = Attached() #Name noch ändern!!! - - condensing_p_low = Parameter('Lower limit for condenseline pressure', FloatRange(unit='mbar')) - condensing_p_high = Parameter('Higher limit for condenseline pressure', FloatRange(unit='mbar')) + + condensing_p_low = Parameter('Lower limit for condenseline pressure', + FloatRange(unit='mbar'), readonly=False, default=1200) + condensing_p_high = Parameter('Higher limit for condenseline pressure', + FloatRange(unit='mbar'), readonly=False, default=1500) dump_target = Parameter('low dump pressure limit indicating end of condensation phase', - FloatRange(unit='mbar'), default=20) + FloatRange(unit='mbar * min'), readonly=False, default=100) + pulse_factor = Parameter('factor for calculating V9 pulse length', + FloatRange(unit='mbar'), readonly=False, default=20) end_condense_pressure = Parameter('low condense pressure indicating end of condensation phase', - FloatRange(unit='mbar'), default=500) + FloatRange(unit='mbar'), readonly=False, default=500) turbo_condense_pressure = Parameter('low condense pressure before turbo start', - FloatRange(unit='mbar'), default=900) - turbo_still_pressure = Parameter('low still pressure before turbo start', - FloatRange(unit='mbar'), default=10) - turbo_off_delay = Parameter('wait time after switching turbo off', - FloatRange(unit='s'), default=300) + FloatRange(unit='mbar'), readonly=False, default=900) + safe_turbo_pressure = Parameter('low still pressure before turbo start', + FloatRange(unit='mbar'), readonly=False, default=10) turbo_off_speed = Parameter('speed to wait for after switching turbo off', - FloatRange(unit='s'), default=60) - end_remove_still_pressure = Parameter('pressure reached before end of remove', - FloatRange(unit='mbar'), default=1e-4) + FloatRange(unit='Hz'), readonly=False, default=200) + end_remove_turbo_pressure = Parameter('pressure reached before end of remove (before turbo)', + FloatRange(unit='mbar'), readonly=False, default=1e-4) + end_remove_pressure = Parameter('pressure reached before end of remove (before fore pump)', + FloatRange(unit='mbar'), readonly=False, default=0.02) st = StringType() valve_set = StructOf(close=st, open=st, check_open=st, check_closed=st) condense_valves = Parameter('valve to act when condensing', valve_set) @@ -105,10 +109,16 @@ class Dilution(HasStates, Drivable): self.value = Targetstates.SORBPUMP return self.value """ - if self.value == self.target: + self.log.info('start %s', target.name) + if self.value == target: return target # not sure if this is correct. may be a step wants to be repeated? - self.start_machine(getattr(self, target.name, None)) + try: + self.start_machine(getattr(self, target.name, None)) + except Exception as e: + self.log.exception('error') + self.log.info('started %s', target.name) + return target """ @@ -150,22 +160,40 @@ class Dilution(HasStates, Drivable): def condense(self, state): """Führt das Kondensationsverfahren durch.""" if state.init: - self.value = V.condensing + # self.value = V.condensing + pumpstate = self.forepump.read_value() + if self.turbopump: + self.turbopump.write_target(0) 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 Retry + return self.condensing @status_code(BUSY) def condensing(self, state): - if self.condenseline_pressure.read_value() < self.condensing_p_low: - self.condense_valve.write_target(1) - elif self.condenseline_pressure.read_value() > self.condensing_p_high: - self.condense_valve.write_target(0) - - if self.p1.read_value() > self.dump_target: + pdump = self.dump_pressure.value # or self.dump_pressure.read_value() ? + pcond = self.condenseline_pressure.read_value() + v9 = self.condense_valve.read_value() + if v9: + if pcond > self.condensing_p_high: + self.log.info('shut V9') + self.condense_valve.write_target(0) + elif pcond < self.condensing_p_low and state.now > self._start_time + 5: + pulse_time = 60 * self.pulse_factor / pdump + if pulse_time > 59: + self.log.info('open V9') + self.condense_value.write_target(1) + else: + self.log.info('V9 pulse %r', pulse_time) + self._start_time = state.now + self.condense_valve.pulse(pulse_time) + + if pdump > self.dump_target: return Retry self.condense_valve.write_target(1) @@ -175,6 +203,14 @@ class Dilution(HasStates, Drivable): return self.wait_for_condense_line_pressure + @status_code(BUSY, 'condense (wait before starting turbo)') + def condense_wait_before_turbo_start(self, state): + if (self.condenseline_pressure.read_value() > self.turbo_condense_pressure + and self.still_pressure.read_value() > self.safe_turbo_pressure): + return Retry + self.turbopump.write_target(1) + return self.wait_for_condense_line_pressure + @status_code(BUSY) def wait_for_condense_line_pressure(self, state): if self.condenseline_pressure.read_value() > self.end_condense_pressure: @@ -182,14 +218,6 @@ class Dilution(HasStates, Drivable): self.condense_valve.write_target(0) return self.circulate - @status_code(BUSY, 'condense (wait before starting turbo)') - def condense_wait_before_turbo_start(self, state): - if (self.condenseline_pressure.read_value() > self.turbo_condense_pressure - and self.still_pressure.read_value() > self.turbo_still_pressure): - return Retry - self.turbopump.write_target(1) - return self.wait_for_condense_line_pressure - @status_code(BUSY) def circulate(self, state): """Zirkuliert die Mischung.""" @@ -206,20 +234,17 @@ class Dilution(HasStates, Drivable): """Entfernt die Mischung.""" if state.init: - self.condenseline_valve.write_target(0) - self.dump_valve.write_target(1) + self.handle_valves(**self.remove_valves) if self.turbopump is not None: self._start_time = state.now self.turbopump.write_target(0) return Retry if self.turbopump is not None: - self.turbopump.write_target(0) - - if (state.now - self._start_time < self.turbo_off_delay - or self.turbopump.read_speed() > self.turbo_off_speed): + # if (state.now - self._start_time < self.turbo_off_delay or + if self.turbopump.read_speed() > self.turbo_off_speed: return Retry - + self.circuitshort_valve.write_target(1) if self.turbopump is not None: @@ -229,27 +254,30 @@ class Dilution(HasStates, Drivable): @status_code(BUSY, 'remove (wait for still pressure low)') def remove_wait_for_still_pressure(self, state): - if self.still_pressure.read_value() > self.turbo_still_pressure: + if self.still_pressure.read_value() > self.safe_turbo_pressure: return Retry self.turbopump.write_target(1) return self.remove_endsequence @status_code(BUSY) def remove_endsequence(self, state): - if self.still_pressure.read_value() > self.end_remove_still_pressure: + if (self.still_pressure_turbo and + self.still_pressure_turbo.read_value() > self.end_remove_turbo_pressure): + return Retry + if self.still_pressure.read_value() > self.end_remove_pressure: return Retry self.circuitshort_valve.write_target(0) self.dump_valve.write_target(0) if self.compressor is not None: self.compressor.write_target(0) - self.circulate_pump.write_target(0) return self.close_valves_after_remove @status_code(BUSY) def close_valves_after_remove(self, state): if state.init: self.handle_valves(**self.valves_after_remove) + self.turbopump.write_target(0) if self.wait_valves(): return Retry self.check_valve_result() @@ -313,7 +341,13 @@ class DIL5(Dilution): 'close': 'V2 V4 V9', 'check_closed': 'MV10 MV13 MV8 MVB MV2', 'check_open': 'MV1 MV3a MV3b GV1 MV9 MV11 MV12 MV14', - 'open': 'V1 V5 compressor pump', + 'open': 'V1 V5 compressor forepump', + } + remove_valves = { + 'close': 'V1 V2 V9', + 'check_closed': 'MV10 MV13 MV8 MVB MV2', + 'check_open': 'MV1 MV3a MV3b GV1 MV9 MV11 MV12 MV14', + 'open': 'V4 V5 compressor forepump', } valves_after_remove = { 'close': 'V1 V2 V4 V5 V9', @@ -330,6 +364,7 @@ class DIL5(Dilution): class Interlock(LogoMixin, AddrMixin, Readable): + dil = Attached() value = AddrParam('interlock state (bitmap)', IntRange(0, 31), addr='V414', readonly=False) p5lim = AddrParam('safety limit on p5 to protect forepump', @@ -349,6 +384,15 @@ class Interlock(LogoMixin, AddrMixin, Readable): reset_param = Property('addr for reset', StringType(), default='V418.1') _mismatch = None _prefix = '' + _actuators = None + + def initModule(self): + super().initModule() + self._actuators = {} + for actions in self.conditions.values(): + for modname in actions: + if modname not in self._actuators: + self._actuators[modname] = self.secNode.modules[modname] def doPoll(self): self.read_status() # this includes read_value @@ -362,9 +406,8 @@ class Interlock(LogoMixin, AddrMixin, Readable): """reset the interlock""" self._prefix = '' self.set_vm_value(self.reset_param, 1) - for actions in self.conditions.values(): - for mname in actions: - self.secNode.modules[mname].reset_fault() + for actuator in self._actuators.values(): + actuator.reset_fault() if self.read_value() != 0: raise HardwareError('can not clear status byte') self.set_vm_value(self.reset_param, 0) @@ -375,13 +418,14 @@ class Interlock(LogoMixin, AddrMixin, Readable): self._mismatch = set() bits = self.read_value() if bits: + self.dil.stop() keys = formatStatusBits(bits, self.conditions, 1) statustext = [] for key in keys: actions = self.conditions[key] statustext.append(f"{' and '.join(actions)} {key}") for module, value in actions.items(): - modobj = self.secNode.modules[module] + modobj = self._actuators[module] if modobj.target != value: self._prefix = 'switched ' modobj.set_fault(value, f'switched {key}') diff --git a/frappy_psi/logo.py b/frappy_psi/logo.py index 7e2726d..a57e3f3 100644 --- a/frappy_psi/logo.py +++ b/frappy_psi/logo.py @@ -118,7 +118,7 @@ class DigitalActuator(LogoMixin, Writable): def initialReads(self): super().initialReads() - self.target = self.value + self.target = self.read_value() def set_fault(self, value, statustext): """on a fault condition, set target to value @@ -229,6 +229,10 @@ class Value(LogoMixin, Readable): return IDLE, '' +class DigitalValue(Value): + value = Parameter('airpressure state', datatype=BoolType()) + + # TODO: the following classes are too specific, they have to be moved class Pressure(LogoMixin, Drivable): diff --git a/frappy_psi/pfeiffer_new.py b/frappy_psi/pfeiffer_new.py index b1e1785..e24b465 100644 --- a/frappy_psi/pfeiffer_new.py +++ b/frappy_psi/pfeiffer_new.py @@ -129,7 +129,7 @@ class PfeifferMixin(HasIO): class RPT200(PfeifferMixin, Readable): - value = Parameter('Pressure', FloatRange(unit='hPa')) + value = Parameter('Pressure', FloatRange(unit='mbar')) def read_value(self): return self.data_request_u_expo_new(740) @@ -143,11 +143,11 @@ class RPT200(PfeifferMixin, Readable): class TCP400(PfeifferMixin, Drivable, Readable): - speed= Parameter('Rotational speed', FloatRange(unit = 'Hz'), readonly = False) + speed= Parameter('Rotational speed', FloatRange(unit='Hz'), readonly = False) target= Parameter('Pumping station', BoolType()) - current= Parameter('Current consumption', FloatRange(unit = '%')) + current= Parameter('Current consumption', FloatRange(unit='%')) value = Parameter('Turbopump state', BoolType()) - temp = Parameter('temp', FloatRange(unit = 'C')) + temp = Parameter('temp', FloatRange(unit='C')) def read_temp (self): return self.data_request_u_int(326)