# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Module authors: # Markus Zolliker # # ***************************************************************************** from frappy.datatypes import BoolType, EnumType, Enum from frappy.core import Parameter, Writable, Attached class HasControlledBy(Writable): """mixin for modules with controlled_by in the :meth:`write_target` the hardware action to switch to own control should be done and in addition self.self_controlled() should be called """ controlled_by = Parameter('source of target value', EnumType(members={'self': 0}), default=0) inputCallbacks = () def register_input(self, name, control_off): """register input :param name: the name of the module (for controlled_by enum) :param control_off: a method on the input module to switch off control """ if not self.inputCallbacks: self.inputCallbacks = {} self.inputCallbacks[name] = control_off prev_enum = self.parameters['controlled_by'].datatype.export_datatype()['members'] # add enum member, using autoincrement feature of Enum self.parameters['controlled_by'].datatype = EnumType(Enum(prev_enum, **{name: None})) def self_controlled(self): """method to change controlled_by to self must be called from the write_target method """ if self.controlled_by: self.controlled_by = 0 for name, control_off in self.inputCallbacks.items(): control_off(self.name) class HasOutputModule(Writable): """mixin for modules having an output module in the :meth:`write_target` the hardware action to switch to own control should be done and in addition self.activate_output() should be called """ # allow unassigned output module, it should be possible to configure a # module with fixed control output_module = Attached(HasControlledBy, mandatory=False) control_active = Parameter('control mode', BoolType()) def initModule(self): super().initModule() if self.output_module: self.output_module.register_input(self.name, self.control_off) def activate_output(self): """method to switch control_active on self.activate_output() must be called from the write_target method """ out = self.output_module if out: for name, control_off in out.inputCallbacks.items(): if name != self.name: control_off(self.name) out.controlled_by = self.name self.control_active = True def control_off(self, switched_by): """control_off is called, when an other module takes over control if possible avoid hardware access in an overriding method in an overriding method as this might lead to a deadlock with the modules accessLock """ if self.control_active: self.control_active = False self.log.warning(f'switched to manual mode by {switched_by}')