# -*- 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 # ***************************************************************************** """vector field""" from frappy.core import Drivable, Done, BUSY, IDLE, WARN, ERROR from frappy.errors import BadValueError from frappy_psi.vector import Vector DECREASE = 1 INCREASE = 2 class VectorField(Vector, Drivable): _state = None def doPoll(self): """periodically called method""" try: if self._starting: # first decrease components driving = False for target, component in zip(self.target, self.components): if target * component.value < 0: # change sign: drive to zero first target = 0 if abs(target) < abs(component.target): if target != component.target: component.write_target(target) if component.isDriving(): driving = True if driving: return # now we can go to the final targets for target, component in zip(self.target, self.components): component.write_target(target) self._starting = False else: for component in self.components: if component.isDriving(): return self.setFastPoll(False) finally: super().doPoll() def merge_status(self): names = [c.name for c in self.components if c.status[0] >= ERROR] if names: return ERROR, 'error in %s' % ', '.join(names) names = [c.name for c in self.components if c.isDriving()] if self._state: # self.log.info('merge %r', [c.status for c in self.components]) if names: direction = 'down ' if self._state == DECREASE else '' return BUSY, 'ramping %s%s' % (direction, ', '.join(names)) if self.status[0] == BUSY: return self.status return BUSY, 'driving' if names: return WARN, 'moving %s directly' % ', '.join(names) names = [c.name for c in self.components if c.status[0] >= WARN] if names: return WARN, 'warnings in %s' % ', '.join(names) return IDLE, '' def write_target(self, value): """initiate target change""" # first make sure target is valid for target, component in zip(self.target, self.components): # check against limits if individual components component.check_limits(target) if sum(v * v for v in value) > 1: raise BadValueError('norm of vector too high') self.log.info('decrease') self.setFastPoll(True) self.target = value self._state = DECREASE self.doPoll() self.log.info('done write_target %r', value) return Done