Exemple #1
0
class RTE1104YScaleSetting(Moveable):

    parameters = {
        'channel':
        Param('Input channel', type=intrange(1, 4), settable=False, default=1),
    }

    attached_devices = {
        'io':
        Attach('Communication device', StringIO),
        'regulator':
        Attach('regulator for the amplitude', Moveable, optional=True),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, volatile=True),
    }

    valuetype = float

    def doReadUnit(self):
        if self._attached_regulator:
            return self._attached_regulator.unit
        return 'V'

    def doRead(self, maxage=0):
        # main value is target amplitude
        if self._attached_regulator:
            return self._attached_regulator.read(maxage)
        setting = float(
            self._attached_io.communicate('CHAN%d:SCAL?' % self.channel))
        return setting * 10. / (2.2 * math.sqrt(2))

    def doStart(self, value):
        setting = math.ceil(value * math.sqrt(2.) * 2.2) / 10.
        self._attached_io.writeLine('CHAN%d:SCAL %g' % (self.channel, setting))
        if self._attached_regulator:
            self._attached_regulator.start(value)

    def doStatus(self, maxage=0):
        if self._attached_regulator:
            return self._attached_regulator.status(maxage)
        return status.OK, ''

    def doStop(self):
        if self._attached_regulator:
            self._attached_regulator.stop()
Exemple #2
0
class ADKafkaImageDetector(KafkaSubscriber, ImageChannelMixin, PassiveChannel):
    """
    Class for reading images from the stream associated with the ADPluginKafka
    """
    attached_devices = {
        'kafka_plugin':
        Attach('NICOS device for the ADPluginKafka',
               ADKafkaPlugin,
               optional=False)
    }

    def doPreinit(self, mode):
        broker = getattr(self._attached_kafka_plugin, 'broker')
        if not broker:
            raise Exception('Can\'t find broker address in ADPluginKafka')
        self._consumer = kafka.KafkaConsumer(
            bootstrap_servers=[broker],
            auto_offset_reset='latest'  # start at latest offset
        )

        # Settings for thread to fetch new message
        self._stoprequest = True
        self._updater_thread = None
        self._lastmessage = None

    def doInit(self, mode):
        topic = getattr(self._attached_kafka_plugin, 'topic')
        if not topic:
            raise Exception('Can\'t find topic in ADPluginKafka')
        self._consumer.subscribe([topic])

    def doReadArray(self, quality=LIVE):
        deserializer = HistogramFlatbuffersDeserializer()
        try:
            data, _, _ = deserializer.decode(self._lastmessage[1])
        except Exception as e:
            self.log.error(e)
            return []
        self.readresult = []
        return data.tolist()

    def new_messages_callback(self, messages):
        if not messages:
            return
        lastkey = sorted(list(messages.keys()))[-1]
        self._lastmessage = (lastkey, messages[lastkey])

    def doStatus(self, maxage=0):
        st = self._attached_kafka_plugin.doStatus()
        if st[0] != status.OK:
            return st
        if not self._consumer:
            return status.ERROR, 'Broker failure'
        if not self._consumer.subscription():
            return status.WARN, 'No topic subscribed'
        return status.OK, ''

    def valueInfo(self):
        return ()
Exemple #3
0
class ShutterSink(DataSink):
    """
    This class abuses the DataSink interface to open and close the
    ICON experiment shutters when a scan begins or ends. This is conditional
    on a ManualMove which decides if automatic shutter management is enabled
    or not.
    """
    attached_devices = {
        'shutter1':
        Attach('First shutter to open', Moveable),
        'shutter2':
        Attach('Second shutter to open', Moveable),
        'auto':
        Attach('Devices which knows if we are in automatic '
               'or manual mode', Readable),
    }
    handlerclass = ShutterHandler
Exemple #4
0
class SelectorTilt(HasLimits, BaseSequencer):
    """Before the selector is allowed to tilt, the speed has to be reduced
    to a certain value.
    """

    attached_devices = {
        'selector': Attach('The selector speed', Moveable),
        'motor': Attach('The tilt motor', Moveable),
    }

    parameters = {
        'maxtiltspeed':
        Param('Maximum safe speed for tilting the selector',
              mandatory=True,
              type=int,
              unit='rpm'),
    }

    def _generateSequence(self, target):
        seq = []
        if self._attached_selector.read(0) > self.maxtiltspeed:
            seq.insert(
                0,
                SeqDev(self._attached_selector,
                       self.maxtiltspeed,
                       stoppable=True))
        seq.append(SeqMethod(self, '_check_speed'))
        seq.append(SeqMethod(self._attached_motor, 'release'))
        seq.append(SeqDev(self._attached_motor, target, stoppable=True))
        seq.append(
            SeqMethod(self._attached_motor, 'fix',
                      'only move this using %s' % self))
        return seq

    def _check_speed(self):
        if self._attached_selector.read(0) > self.maxtiltspeed + 50:
            raise MoveError(self, 'selector not in safe speed range')

    def doRead(self, maxage=0):
        return self._attached_motor.read(maxage)

    def doIsAllowed(self, target):
        return self._attached_motor.isAllowed(target)

    def _getWaiters(self):
        return [self._attached_motor]
Exemple #5
0
class QMesyDAQSink(FileSink):
    attached_devices = {
        'image': Attach('Device to set the file name', Device),
    }

    parameter_overrides = {
        'settypes': Override(default=[POINT])
    }
Exemple #6
0
class LVPower(Moveable):
    """Toni TOFTOF-type low-voltage power supplies."""

    attached_devices = {
        'bus': Attach('Toni communication bus', ToniBus),
    }

    parameters = {
        'addr':
        Param('Bus address of the supply controller',
              type=intrange(0xF0, 0xFF),
              mandatory=True),
        'temperature':
        Param('Temperature of the module',
              type=int,
              settable=False,
              volatile=True,
              unit='degC',
              fmtstr='%d'),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, default=''),
    }

    valuetype = oneofdict({1: 'on', 0: 'off'})

    def doRead(self, maxage=0):
        sval = self._attached_bus.communicate('S?', self.addr, expect_hex=2)
        return 'on' if sval >> 7 else 'off'

    def doReadTemperature(self):
        return self._attached_bus.communicate('T?', self.addr, expect_hex=2)

    def doStatus(self, maxage=0):
        sval = self._attached_bus.communicate('S?', self.addr, expect_hex=2)
        if sval in (0x0, 0x80):
            return status.OK, ''
        msg = []
        if sval & 0x1:
            msg.append('undervoltage +5V')
        if sval & 0x2:
            msg.append('overvoltage +5V')
        if sval & 0x4:
            msg.append('undervoltage -5V')
        if sval & 0x8:
            msg.append('overvoltage -5V')
        if sval & 0x10:
            msg.append('undervoltage +12V')
        if sval & 0x20:
            msg.append('overvoltage +12V')
        return status.ERROR, ', '.join(msg)

    @requires(level=ADMIN)
    def doStart(self, target):
        self._attached_bus.communicate('P%d' % (target == 'on'),
                                       self.addr,
                                       expect_ok=True)
Exemple #7
0
class AnalogValue(Readable):
    attached_devices = {
        'iodev': Attach('IO Device', VSDIO),
    }
    parameters = {
        'channel':
        Param('Channel for readout',
              type=oneof(*VSDIO._HW_AnalogChannels),
              settable=True,
              preinit=True),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, volatile=True, settable=False),
    }

    def doReadUnit(self):
        _ofs, _scale, unit = \
            self._attached_iodev._HW_AnalogChannels[self.channel]
        if unit == 'mA-foo':
            unit = 'mA'
        elif unit == 'V-foo':
            unit = 'V'
        return unit

    def doRead(self, maxage=0):
        ofs, scale, _unit = \
            self._attached_iodev._HW_AnalogChannels[self.channel]
        # ofs is in Bytes, we need it in words! => /2
        if _unit == 'mA-foo':
            raw = scale * self._attached_iodev._readU16(ofs // 2)
            self.log.debug('mA-foo %.2f', raw)
            # Work around bug in firmware
            if raw > 20.0:
                raw -= 615.37
            self.log.debug('mA-foo %.2f', raw)
            # Tested against Multimeter (2018-08-07)
            raw /= 2.0
            self.log.debug('mA-foo %.2f', raw)
        elif _unit == 'V-foo':
            raw = self._attached_iodev._readU16(ofs // 2)
            self.log.debug('V-foo %d', raw)
            # Work around bug in firmware
            if raw > 0x8000:
                raw -= 63536
                self.log.debug('V-foo %d sign1', raw)
            self.log.debug('V-foo %d sign', raw)
            # Tested against Multimeter (2018-08-07)
            raw /= 2.0
            self.log.debug('v-foo %.2f /2.0', raw)
            raw *= scale
            self.log.debug('v-foo %.2f scale', raw)
        else:
            raw = scale * self._attached_iodev._readU16(ofs // 2)
        return raw

    def doStatus(self, maxage=0):
        return status.OK, ''
Exemple #8
0
class EulerSXTal(SXTalBase):

    attached_devices = {
        'ttheta': Attach('two-theta device', Moveable),
        'omega': Attach('omega device', Moveable),
        'chi': Attach('chi device', Moveable),
        'phi': Attach('phi device', Moveable),
    }

    def _extractPos(self, pos):
        return [
            ('ttheta', np.rad2deg(2 * pos.theta)),
            ('omega', np.rad2deg(pos.omega)),
            ('chi', np.rad2deg(pos.chi)),
            ('phi', np.rad2deg(pos.phi)),
        ]

    def _convertPos(self, pos, wavelength=None):
        return pos.asE(wavelength)

    def _readPos(self, maxage=0):
        return PositionFactory('e',
                               theta=self._attached_ttheta.read(maxage) / 2.,
                               omega=self._attached_omega.read(maxage),
                               chi=self._attached_chi.read(maxage),
                               phi=self._attached_phi.read(maxage))

    def _createPos(self, ttheta, omega, chi, phi):
        return PositionFactory('e',
                               theta=ttheta / 2.,
                               omega=omega,
                               chi=chi,
                               phi=phi)

    def getScanWidthFor(self, hkl):
        """Get scanwidth as ``sqrt(u + v *tan Theta + w * tan² Theta)``."""
        th = session.experiment.sample.cell.Theta(hkl, self.wavelength)
        tan_th = np.tan(th)
        w2 = self.scan_uvw[0] + \
            self.scan_uvw[1] * tan_th + \
            self.scan_uvw[2] * (tan_th ** 2)
        if w2 > 0:
            return np.sqrt(w2)
        else:
            return -np.sqrt(-w2)
Exemple #9
0
class HoveringAxis(SequencerMixin, Axis):
    """An axis that also controls air for airpads."""

    attached_devices = {
        'switch': Attach('The device used for switching air on and off',
                         Moveable),
    }

    parameters = {
        'startdelay':
        Param('Delay after switching on air',
              type=float,
              mandatory=True,
              unit='s'),
        'stopdelay':
        Param('Delay before switching off air',
              type=float,
              mandatory=True,
              unit='s'),
        'switchvalues':
        Param('(off, on) values to write to switch device',
              type=tupleof(anytype, anytype),
              default=(0, 1)),
    }

    hardware_access = True

    def _generateSequence(self, target):
        return [
            SeqDev(self._attached_switch, self.switchvalues[1]),
            SeqSleep(self.startdelay),
            SeqCall(Axis.doStart, self, target),
            SeqCall(self._hw_wait),
            SeqSleep(self.stopdelay),
            SeqDev(self._attached_switch, self.switchvalues[0]),
        ]

    def _hw_wait(self):
        # overridden: query Axis status, not HoveringAxis status
        while Axis.doStatus(self, 0)[0] == status.BUSY:
            session.delay(self._base_loop_delay)

    def doStart(self, target):
        if self._seq_is_running():
            self.stop()
            self.log.info('waiting for axis to stop...')
            self.wait()
        if abs(target - self.read()) < self.precision:
            return
        self._startSequence(self._generateSequence(target))

    def doStop(self):
        # stop only the axis, but the sequence has to run through
        Axis.doStop(self)

    def doTime(self, start, end):
        return Axis.doTime(self, start, end) + self.startdelay + self.stopdelay
Exemple #10
0
class BeamFocus(Moveable):

    attached_devices = {
        'ellipse': Attach('output signal for ellipse', Moveable),
        'collimator': Attach('output signal for collimator', Moveable),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, default=''),
        'fmtstr': Override(default='%s'),
    }

    valuetype = oneof('Ell', 'Col')

    hardware_access = False

    def doInit(self, mode):
        ell_state = self._attached_ellipse.read(0)
        col_state = self._attached_collimator.read(0)
        if [ell_state, col_state] == [1, 1]:
            self.reset()

    def doReset(self):
        self._attached_ellipse.move(0)
        self._attached_collimator.move(0)

    def doStart(self, pos):
        if pos != self.doRead(0):
            if pos == 'Ell':
                self._attached_collimator.move(0)
                self._attached_ellipse.move(1)
            elif pos == 'Col':
                self._attached_ellipse.move(0)
                self._attached_collimator.move(1)
            self._hw_wait()

    def doRead(self, maxage=0):
        ell = self._attached_ellipse.read(maxage)
        col = self._attached_collimator.read(maxage)
        if [ell, col] == [0, 1]:
            return 'Col'
        elif [ell, col] == [1, 0]:
            return 'Ell'
        return None
Exemple #11
0
class Attenuator(HasTimeout, Moveable):
    """Controlling the attenuator."""

    valuetype = oneof('out', 'in')

    attached_devices = {
        'output':    Attach('output bits', Moveable),
        'input':     Attach('input bits', Readable),
    }

    parameter_overrides = {
        'fmtstr':     Override(default='%s'),
        'timeout':    Override(default=10),
        'unit':       Override(mandatory=False, default=''),
    }

    def doStatus(self, maxage=0):
        inputstatus = self._attached_input.read(maxage)
        if inputstatus == OUT:
            if self.target == 'out':
                return status.OK, 'idle'
            else:
                return status.WARN, 'out, but target=in'
        elif inputstatus == IN:
            if self.target == 'in':
                return status.OK, 'idle'
            else:
                return status.WARN, 'in, but target=out'
        # HasTimeout will check for target reached
        return status.OK, 'idle'

    def doRead(self, maxage=0):
        inputstatus = self._attached_input.read(maxage)
        if inputstatus == OUT:
            return 'out'
        elif inputstatus == IN:
            return 'in'
        return 'unknown'

    def doStart(self, target):
        if target == 'out':
            self._attached_output.start(OUT)
        else:
            self._attached_output.start(IN)
class Attenuator(HasLimits, Moveable):
    """Attentuator with 3 elements having a transmission of 1/2, 1/4, and 1/16
    """

    attached_devices = {
        'blades': Attach('The blade devices', Moveable, multiple=3),
    }

    parameters = {
        'base':
        Param(
            'Attenuating base (transmission = 1 / base ** n)',
            default=2,
            userparam=False,
            settable=False,
        ),
    }

    parameter_overrides = {
        'unit': Override(
            default='%',
            mandatory=False,
        ),
        'abslimits': Override(mandatory=False,
                              default=(0, 100),
                              settable=False),
    }

    def _attenuation(self, exp):
        return 100. * (1.0 - 1.0 / self.base**exp)

    def doRead(self, maxage=0):
        exp = 0
        i = 1
        for blade in self._attached_blades:
            if blade.read(maxage) == 'in':
                exp += i
            i *= 2
        return self._attenuation(exp)

    def doStatus(self, maxage=0):
        return status.OK, ''

    def doStart(self, value):
        for pos in range(8):
            if value <= self._attenuation(pos) or pos == 7:
                # Move first in all needed blades into the beam to reduce the
                # activation and/or save the detector and then move out the not
                # needed ones
                for (idx, blade) in enumerate(self._attached_blades):
                    if pos & (1 << idx):
                        blade.maw('in')
                for (idx, blade) in enumerate(self._attached_blades):
                    if not (pos & (1 << idx)):
                        blade.maw('out')
                break
Exemple #13
0
class LogoFeedBack(DigitalInput):
    """Device to simulate the LOGO feed back."""

    attached_devices = {
        'input': Attach('Digital input device', DigitalInput),
    }

    def doRead(self, maxage=0):
        v = self._attached_input.read(maxage)
        return sum((0x2 | min(1, ((1 << i) & v))) << (2 * i) for i in range(8))
Exemple #14
0
class MuxMotor(Motor):
    """CARESS motor using the ST180 multiplexer."""

    attached_devices = {
        'mux':
        Attach('Multiplexer device to access the motor controller',
               MUX,
               optional=True,
               multiple=False),
    }
Exemple #15
0
class DetectorZAxis(HasLimits, BaseSequencer):
    """Special device for the detector Z axis.

    Switches HV off before moving.
    """

    hardware_access = False

    parameters = {
        'precision': Param('Precision', volatile=True),
    }

    attached_devices = {
        'motor': Attach('The raw motor', Moveable),
        'hv':    Attach('The HV switch', Moveable),
    }

    def doReadPrecision(self):
        return self._attached_motor.precision

    def doReadAbslimits(self):
        return self._attached_motor.abslimits

    def _generateSequence(self, target):
        seq = []
        if self._attached_hv.read(0) != 'off':
            seq.append(SeqDev(self._attached_hv, 'off'))
        seq.append(SeqDev(self._attached_motor, target, stoppable=True))
        return seq

    def doRead(self, maxage=None):
        return self._attached_motor.read(maxage)

    def doStatus(self, maxage=None):
        code, text = BaseSequencer.doStatus(self, maxage)
        if code == status.OK:
            text = self._attached_motor.status(maxage)[1]
        return code, text

    def doStart(self, target):
        if abs(self.read(0) - target) <= self.precision:
            return
        BaseSequencer.doStart(self, target)
Exemple #16
0
class DetSwitcher(Moveable):
    """Switches the channel alias device between HRD and VHRD."""

    attached_devices = {
        'alias': Attach('the alias to switch', DeviceAlias),
        'hrd': Attach('the HRD device', Measurable),
        'vhrd': Attach('the VHRD device', Measurable),
    }

    _values = ['HRD', 'VHRD']

    parameters = {
        'values':
        Param('Possible values',
              type=listof(str),
              default=_values,
              settable=False,
              internal=True),
    }

    parameter_overrides = {
        'unit': Override(default='', mandatory=False),
    }

    valuetype = oneof(*_values)

    def doRead(self, maxage=0):
        if self._attached_alias.alias == self._attached_hrd.name:
            return 'HRD'
        elif self._attached_alias.alias == self._attached_vhrd.name:
            return 'VHRD'
        return 'unknown'

    def doStatus(self, maxage=0):
        if self.doRead(maxage) == 'unknown':
            return status.WARN, ''
        return status.OK, ''

    def doStart(self, target):
        if target == 'HRD':
            self._attached_alias.alias = self._attached_hrd
        else:
            self._attached_alias.alias = self._attached_vhrd
Exemple #17
0
class LensControl(HasTimeout, Moveable):
    """Control the 3 lenses."""

    valuetype = intrange(0, 7)

    attached_devices = {
        'output': Attach('output setter', Moveable),
        'input_in': Attach('input for limit switch "in" position', Readable),
        'input_out': Attach('input for limit switch "out" position', Readable),
        'sync_bit': Attach('sync bit output', Moveable),
    }

    parameter_overrides = {
        'fmtstr': Override(default='%d'),
        'timeout': Override(default=10),
        'unit': Override(mandatory=False, default=''),
    }

    def doStatus(self, maxage=0):
        is_in = self._attached_input_in.read(maxage)
        is_out = self._attached_input_out.read(maxage)
        # check individual bits
        for i in range(3):
            mask = 1 << i
            if is_in & mask == is_out & mask:
                # inconsistent state, check switches
                if is_in & mask:
                    # both switches on?
                    return status.ERROR, 'both switches on for lens ' \
                        '%d' % (i + 1)
                return status.BUSY, 'lenses moving'
        # HasTimeout will check for target reached
        return status.OK, 'idle'

    def doRead(self, maxage=0):
        return self._attached_input_in.read(maxage)

    def doStart(self, target):
        self._attached_output.start(target)
        # without this bit, no outputs will be changed
        self._attached_sync_bit.start(1)
Exemple #18
0
class MiraXmlSink(ImageSink):

    handlerclass = MiraXmlHandler

    attached_devices = {
        'timer': Attach('Timer readout', ActiveChannel),
        'monitor': Attach('Monitor readout', ActiveChannel),
        'mono': Attach('Monochromator device to read out', Monochromator),
        'sampledet': Attach('Sample-detector distance readout', Readable),
    }

    parameter_overrides = {
        'filenametemplate':
        Override(default=['mira_cas_%(pointcounter)08d.xml'], settable=False),
    }

    _format = None

    def isActiveForArray(self, arraydesc):
        # only for 2-D data
        return len(arraydesc.shape) == 2
Exemple #19
0
class PumpstandPressure(Readable):
    attached_devices = {
        'iodev': Attach('IO Device', PumpstandIO),
    }
    parameters = {
        'chamber': Param('Chamber of pumpenstand',
                         type=oneof('SFK', 'CB', 'SR'),
                         mandatory=True, settable=False,
                         userparam=False, default='SR'),
        'limits': Param('Pump activation limits',
                        type=limits, settable=True, volatile=True,
                        chatty=True, unit='mbar'),
    }

    parameter_overrides = {
        'unit': Override(default='mbar', mandatory=False),
        'fmtstr': Override(default='%.1g'),
    }
    #
    # Nicos methods
    #

    def doReset(self):
        self._attached_iodev._HW_rawCommand('ackErr')

    def doRead(self, maxage=0):
        return getattr(self._attached_iodev,
                       '_HW_%s_current_pressure' % self.chamber)()

    def doReadLimits(self):
        return (getattr(self._attached_iodev,
                        '_HW_%s_turn_off_pressure' % self.chamber)(),
                getattr(self._attached_iodev,
                        '_HW_%s_turn_on_pressure' % self.chamber)())

    def doWriteLimits(self, limits):
        lower, upper = limits
        upper = clamp(upper, 1e-3, self.parallel_pumping)
        lower = clamp(lower, 1e-3, upper)
        self._attached_iodev._HW_rawCommand('set_%s_low' % self.chamber,
                                            int(lower * 1e6))
        self._attached_iodev._HW_rawCommand('set_%s_high' % self.chamber,
                                            int(upper * 1e6))
        return (lower, upper)

    _HW_Alarmbit = dict(CB=13, SR=14, SFK=15)

    def doStatus(self, maxage=0):
        alarms = self._attached_iodev._HW_readAlarms()
        alarmbit = self._HW_Alarmbit[self.chamber]
        if alarms & (1 << alarmbit):
            return status.ERROR, 'Sensor- oder Kabelfehler Messtube'
        return status.OK, ''
Exemple #20
0
class CryopadPol(Moveable):
    """Controls the incoming or outgoing polarization direction."""

    attached_devices = {
        'cryopad': Attach('Underlying Cryopad device', BaseCryopad)
    }

    parameters = {
        'side':
        Param('Which side of the instrument is this device?',
              type=oneof('in', 'out'),
              mandatory=True),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, default=''),
    }

    valuetype = oneof('+x', '-x', '+y', '-y', '+z', '-z')

    def doRead(self, maxage=0):
        # NOTE: for now, we just return the latest target because it became
        # necessary to introduce corrections to nutator angles that cannot yet
        # be included reliably in the calculations, and would change the readout
        # here to "unknown".
        return self.target
        # cppos = self._attached_cryopad.read(maxage)
        # theta, chi = cppos[0:2] if self.side == 'in' else cppos[2:4]
        # for (pos, (goaltheta, goalchi)) in calc.DIRECTIONS.items():
        #     # fix chi = -179.5, goalchi = 180 situation
        #     diffchi = abs(chi - goalchi)
        #     chiok = diffchi < 0.5 or 359.5 < diffchi < 360.5
        #     # XXX: make precision configurable
        #     if abs(theta - goaltheta) < 0.5 and chiok:
        #         return pos
        # return 'unknown'

    def doStatus(self, maxage=0):
        st, text = multiStatus(self._adevs)
        if st == status.BUSY:
            return st, text
        if self.read(maxage) == 'unknown':
            return status.NOTREACHED, 'unknown polarization setting'
        return status.OK, 'idle'

    def doStart(self, pos):
        theta_chi = calc.DIRECTIONS[pos]
        cppos = self._attached_cryopad.target or (0, 0, 0, 0)
        if self.side == 'in':
            target = tuple(theta_chi) + cppos[2:4]
        else:
            target = cppos[0:2] + tuple(theta_chi)
        self._attached_cryopad.start(target)
Exemple #21
0
class RTE1104TimescaleSetting(Moveable):

    attached_devices = {
        'io': Attach('Communication device', StringIO),
        'freqgen': Attach('frequency generator', Moveable, optional=True),
    }

    parameters = {
        'timescale':
        Param('Time scale setting',
              type=float,
              settable=False,
              userparam=False,
              default=10.,
              category='general'),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, default='Hz'),
    }

    valuetype = float

    def doRead(self, maxage=0):
        # main value is freq!
        if self._attached_freqgen:
            return self._attached_freqgen.read(maxage)
        return self.timescale / float(
            self._attached_io.communicate('TIM:SCAL?' % self.channel))

    def doStart(self, target):
        self._attached_io.writeLine('TIM:SCAL %g' %
                                    (self.timescale / float(target)))
        if self._attached_freqgen:
            self._attached_freqgen.start(target)

    def doStatus(self, maxage=0):
        if self._attached_freqgen:
            return self._attached_freqgen.status(maxage)
        return status.OK, ''
Exemple #22
0
class Shutter(Moveable):
    """TOFTOF Shutter Control."""

    attached_devices = {
        'open': Attach('Shutter open button device', DigitalOutput),
        'close': Attach('Shutter close button device', DigitalOutput),
        'status': Attach('Shutter status device', DigitalOutput),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False),
        'fmtstr': Override(default='%s'),
    }

    valuetype = oneofdict({0: 'closed', 1: 'open'})

    def doStart(self, target):
        if target == 'open':
            self._attached_open.start(1)
            session.delay(0.01)
            self._attached_open.start(0)
        else:
            self._attached_close.start(1)
            session.delay(0.01)
            self._attached_close.start(0)

    def doStop(self):
        self.log.info(
            'note: shutter collimator does not use stop() anymore, '
            'use move(%s, "closed")', self)

    def doRead(self, maxage=0):
        ret = self._attached_status.read(maxage)
        if ret == 1:
            return 'closed'
        else:
            return 'open'

    def doStatus(self, maxage=0):
        return status.OK, ''
Exemple #23
0
class SamplePusher(Moveable):
    """Move the sample up/down inside the sample changer device."""

    valuetype = oneof('down', 'up')

    attached_devices = {
        'actuator': Attach('Actuator to perform the switch', Moveable),
        'sensort': Attach('Sensor at top of the tube.', Readable),
        'sensorl': Attach('Sensor at down of the tube', Readable),
    }

    parameter_overrides = {
        'unit': Override(default=''),
        'fmtstr': Override(default='%s'),
    }

    def doInit(self, mode):
        self._target_sens = None

    def doStart(self, target):
        self._attached_actuator.move(target)
        if target == 'up':
            self._target_sens = self._attached_sensort
        elif target == 'down':
            self._target_sens = self._attached_sensorl

    def doStatus(self, maxage=0):
        # it is a local object so poller gives wrong state here but maw works
        if self._target_sens:
            if self._target_sens.read(maxage) == 0:
                return status.BUSY, 'moving'
            elif self._target_sens.read(maxage) == 1:
                self._target_sens = None
        return status.OK, 'idle'

    def doRead(self, maxage=0):
        if self._attached_sensort.read(maxage):
            return 'up'
        elif self._attached_sensorl.read(maxage):
            return 'down'
Exemple #24
0
class Valve(Moveable):
    """Control element for 8 valves."""

    attached_devices = {
        'bus': Attach('Toni communication bus', ModBus),
    }

    parameters = {
        'addr':
        Param('Bus address of the valve control', type=int, mandatory=True),
        'channel':
        Param('Channel of the valve', type=intrange(0, 7), mandatory=True),
        'states':
        Param('Names for the closed/open states',
              type=listof(str),
              default=['off', 'on']),
        'waittime':
        Param('Time to wait after switching', type=float, unit='s', default=4),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False),
    }

    _started = 0

    def doInit(self, mode):
        if len(self.states) != 2:
            raise ConfigurationError(
                self, 'Valve states must be a list of '
                'two strings for closed/open state')
        self.valuetype = oneof(*self.states)

    def doStart(self, value):
        value = self.states.index(value)
        self._hw_wait()
        msg = '%s=%02x' % (value and 'O' or 'C', 1 << self.channel)
        self._attached_bus.communicate(msg, self.addr, expect_ok=True)
        self._started = currenttime()

    def doRead(self, maxage=0):
        ret = self._attached_bus.communicate('R?', self.addr, expect_hex=2)
        return self.states[bool(ret & (1 << self.channel))]

    def doStatus(self, maxage=0):
        ret = self._attached_bus.communicate('I?', self.addr, expect_hex=2)
        if ret != 0:
            return status.BUSY, 'busy'
        if self._started and self._started + self.waittime < currenttime():
            return status.BUSY, 'waiting'
        else:
            return status.OK, 'idle'
Exemple #25
0
class WutDiff(Readable):

    attached_devices = {
        'dev1': Attach('1st Device', Readable),
        'dev2': Attach('2nd Device', Readable),
    }

    parameter_overrides = {
        'unit':         Override(mandatory=False),
        'pollinterval': Override(default=60),
        'maxage':       Override(default=125),
    }

    def doReadUnit(self):
        return self._attached_dev1.unit

    def doRead(self, maxage=0):
        return self._attached_dev1.doRead(maxage) - \
            self._attached_dev2.doRead(maxage)

    def doStatus(self, maxage=0):
        return status.OK, ''
Exemple #26
0
class Leckmon(Readable):
    """Water supply leak monitor."""

    attached_devices = {
        'bus': Attach('Toni communication bus', ModBus),
    }

    parameters = {
        'addr': Param('Bus address of monitor', type=int, mandatory=True),
    }

    def doRead(self, maxage=0):
        return self._attached_bus.communicate('S?', self.addr)
Exemple #27
0
class SampleChanger(IsController, BaseSequencer):
    """The PGAA sample changer device."""

    attached_devices = {
        'motor': Attach('Stage rotation', Moveable),
        'push': Attach('Moving sample to rotation stage', Moveable),
    }

    parameter_overrides = {
        'unit': Override(default=''),
        'fmtstr': Override(default='%.f'),
    }

    def isAdevTargetAllowed(self, dev, target):
        if dev == self._attached_motor:
            if not self._attached_push._attached_sensort.read(0):
                return False, '"push" is not in top position or moving'
        elif dev == self._attached_push:
            if self._attached_motor.status(0)[0] == status.BUSY:
                return False, 'motor moving'
            if self._attached_motor.read(0) not in (1., 2., 3., 4., 5., 6., 7.,
                                                    8., 9., 10., 11., 12., 13.,
                                                    14., 15., 16.):
                return False, 'invalid motor position'
        return True, ''

    def _generateSequence(self, target):
        seq = []
        if target != self.doRead(0):
            seq.append(SeqDev(self._attached_push, 'up', stoppable=False))
            seq.append(SeqSleep(2))
            seq.append(SeqSampleMotor(self._attached_motor, target,
                                      stoppable=False))
            seq.append(SeqSleep(2))
            seq.append(SeqDev(self._attached_push, 'down', stoppable=False))
        return seq

    def doRead(self, maxage=0):
        return self._attached_motor.read(maxage)
Exemple #28
0
class SelectorSpeed(HasLimits, HasPrecision, Moveable):
    """Control selector speed via PLC I/O devices."""

    attached_devices = {
        'valid':  Attach('Output for the "valid" bit', Moveable),
        'speed':  Attach('I/O for current speed and its setpoint', Moveable),
        'status': Attach('Input for reading the status', Readable),
    }

    def _getWaiters(self):
        return [self._attached_speed]

    def doRead(self, maxage=0):
        return self._attached_speed.read(maxage)

    def doStatus(self, maxage=0):
        stbits = self._attached_status.read(maxage)
        if not stbits & 1:
            return status.WARN, 'local mode'
        if not stbits & 2:
            if self._attached_speed.read(maxage) < 0.1:
                return status.WARN, 'off'
            return status.BUSY, 'moving'
        return status.OK, ''

    def doStart(self, pos):
        # do not start moving if already there, since the stability check in
        # the SPS always waits
        if pos == self.target and abs(self.read(0) - pos) < self.precision:
            return
        stbits = self._attached_status.read(0)
        if not stbits & 1:
            raise MoveError(self, 'selector is in local mode')
        # valid bit needs a rising edge
        self._attached_valid.move(0)
        self._attached_speed.maw(pos)
        time.sleep(0.2)
        self._attached_valid.move(1)
        time.sleep(0.2)
Exemple #29
0
class AmorLogicalMotor(Motor):
    """ Class to represent the logical motor in AMOR. This motor has a
    type which can be one of the ath(analyzer theta), m2t(monochormator
    two theta) or s2t(sample two theta).
    """
    parameters = {
        'motortype':
        Param('Type of motor ath/m2t/s2t',
              type=oneof(*motortypes),
              mandatory=True),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False, default='degree'),
        'target': Override(volatile=True),
        'abslimits': Override(mandatory=False, default=(-3.0, 3.0)),
        'userlimits': Override(mandatory=False, default=(-3.0, 3.0))
    }

    attached_devices = {
        'controller':
        Attach('Controller for the logical motors', AmorLogicalMotorHandler)
    }

    def doInit(self, mode):
        self._attached_controller.register(self.motortype, self)

    def doRead(self, maxage=0):
        return self._attached_controller.doRead(maxage)[self.motortype]

    def doReadTarget(self):
        return self._getFromCache('target', self.doRead)

    def doStatus(self, maxage=0):
        # Check for error and warning in the dependent devices
        return self._attached_controller.doStatus(maxage)

    def doIsAllowed(self, pos):
        return self._attached_controller.doIsAllowed({self.motortype: pos})

    def doIsCompleted(self):
        return self._attached_controller.doIsCompleted()

    def doStart(self, pos):
        self._attached_controller.doStart({self.motortype: pos})

    def doStop(self):
        if self.status(0)[0] == status.BUSY:
            self._attached_controller.stop()
            # Reset the target for this motor
            self._setROParam('target', self.doRead(0))
Exemple #30
0
class FPLCRate(AnalogInput):
    """Forward the current detector countrate to the FPLC."""

    attached_devices = {
        'rate':   Attach('device to read countrate', Readable),
    }

    def doStatus(self, maxage=0):
        return status.OK, ''

    def doRead(self, maxage=0):
        rate = self._attached_rate.read(maxage)[1]
        self._dev.value = rate
        return rate