Example #1
0
class WebhookForwarder(ForwarderBase, Device):
    """Forwards cache updates to a web service."""

    parameters = {
        'hook_url':      Param('Hook URL endpoint', type=str, mandatory=True),
        'prefix':        Param('Cache key prefix', type=str, mandatory=True),
        'http_mode':     Param('HTTP request mode', type=oneof('GET', 'POST'),
                               mandatory=True),
        'paramencoding': Param('Parameter encoding',
                               type=oneof('plain', 'json'), mandatory=True),
        'jsonname':      Param('JSON parameter name (used for GET requests)',
                               type=str, default='json'),
    }

    def doInit(self, mode):
        if requests is None:
            raise ConfigurationError(self, 'requests package is missing')
        self._prefix = self.prefix.strip('/')
        if self._prefix:
            self._prefix += '/'
        self._initFilters()
        self._queue = queue.Queue(1000)
        self._processor = createThread('webhookprocessor', self._processQueue)

    def _putChange(self, time, ttl, key, value):
        if not self._checkKey(key):
            return
        pdict = dict(time=time, ttl=ttl, key=self._prefix + key, value=value)
        retry = 2
        while retry:
            try:
                self._queue.put(pdict, False)
                break
            except queue.Full:
                self._queue.get()
                self._queue.task_done()
                retry -= 1

    def _webHookTask(self, pdict):
        try:
            if self.paramencoding == 'json':
                if self.http_mode == 'GET':
                    pdict = {self.jsonname: json.dumps(pdict)}
                    requests.get(self.hook_url, params=pdict, timeout=0.5)
                elif self.http_mode == 'POST':
                    requests.post(self.hook_url, json=pdict, timeout=0.5)
            else:
                if self.http_mode == 'GET':
                    requests.get(self.hook_url, params=pdict, timeout=0.5)
                elif self.http_mode == 'POST':
                    requests.post(self.hook_url, data=pdict, timeout=0.5)
        except Exception:
            self.log.warning('Execption during webhook call', exc=True)

    def _processQueue(self):
        while not self._stoprequest:
            item = self._queue.get()
            self._webHookTask(item)
            self._queue.task_done()
Example #2
0
def test_oneof():
    assert oneof(0, 1)(1) == 1
    assert oneof(2, 3)() == 2
    assert oneof(None)() is None
    assert oneof(None)(None) is None
    assert oneof()() is None
    assert oneof()(None) is None
    assert raises(ValueError, oneof(0, 1), '0')
    assert raises(ValueError, oneof(0, 1), 2)
    assert raises(ValueError, oneof(0, 1), 'x')
Example #3
0
class Polariser(Moveable):
    """
    The polariser is in when segment 1 is on zus, out else
    """

    attached_devices = {
        'cols1': Attach('Collimator segment 1', Moveable),
    }

    parameter_overrides = {
        'unit': Override(mandatory=False),
    }
    valuetype = oneof('in', 'out')

    def doRead(self, maxage=0):
        pos = self._attached_cols1.read(maxage)
        if pos == 'zus':
            return 'in'
        return 'out'

    def doStart(self, pos):
        if pos == 'in':
            self._attached_cols1.start('zus')
        else:
            self._attached_cols1.start('ble')

    def doStatus(self, maxage=0):
        return self._attached_cols1.status(maxage)
Example #4
0
class HAMEG8131(EpicsMoveable):
    """
    This class takes care of initialising the frequency generator,
    and switching it on or off
    """

    attached_devices = {
        'port': Attach('Port to talk directly to the device',
                       EpicsCommandReply),
        'freq': Attach('Flipper frequency',
                       EpicsMoveable),
        'amp': Attach('Flipper amplitude',
                      EpicsMoveable),
    }

    valuetype = oneof('on', 'off')

    def doInit(self, mode):
        if mode == SIMULATION:
            return
        inicommands = ['RM1', 'RFI', 'OT0', 'SW0', 'SK0',
                       'CTM', 'VPP', 'AM0', 'SIN', 'OFS:0E+0',
                       'FRQ:2.534E+5', 'AMP:2.6E+0']
        for com in inicommands:
            self._attached_port.execute(com)

    def doIsAllowed(self, target):
        if target == 'on':
            freq = self._attached_freq.read(0)
            amp = self._attached_amp.read(0)
            if freq < 1. or amp < .1:
                return False,  'Set frequency and amplitude first'
        return True, ''

    def doStart(self, pos):
        if pos == 'on':
            self._put_pv('writepv', 1)
        else:
            self._put_pv('writepv', 0)

    def doRead(self, maxage=0):
        val = self._get_pv('readpv')
        freq = self._attached_freq.read(maxage)
        amp = self._attached_amp.read(maxage)
        if val == 0 or freq < 1. or amp < .1:
            return 'off'
        return 'on'

    def doStatus(self, maxage=0):
        pos = self.doRead(maxage)
        if pos == self.target:
            return status.OK, 'Done'
        return status.BUSY, 'Moving'
Example #5
0
class Flipper(MezeiFlipper):
    """MezeiFlipper subclass that has values of up/down instead of on/off."""

    valuetype = oneof(UP, DOWN)

    def doRead(self, maxage=0):
        if (abs(self._attached_corr.read(maxage)) > 0.05 or
                    abs(self._attached_flip.read(maxage)) > 0.05):
            return DOWN
        return UP

    def doStart(self, value):
        if value == DOWN:
            self._attached_flip.start(self.currents[0])
            self._attached_corr.start(self.currents[1])
        else:
            self._attached_flip.start(0)
            self._attached_corr.start(0)
Example #6
0
class SingleSideRead(Readable):
    """We need read access to a single side of a nok without mode.
    Readable is enough!
    """
    attached_devices = {
        'device': Attach('access to device with several axis', Readable),
    }

    parameters = {
        'index':
        Param('side of nok', type=oneof(0, 1), settable=False, mandatory=True),
    }

    def doRead(self, maxage=0):
        self.log.debug('SingleSiedRead read')
        return self._attached_device.read(maxage)[self.index]

    def doStatus(self, maxage=0):
        self.log.debug('SingleSideRead status')
        return self._attached_device.status(maxage)
Example #7
0
class Beamstop(BeamstopSequencer):
    """
    This is a SANS special device for moving the beamstop in or out. This
    requires a sequence of operations. Order of driving is important.
    """
    _out_x = 28.
    _out_y = -543.
    valuetype = oneof('in', 'out')

    def doRead(self, maxage):
        x = self._attached_x.read(maxage)
        y = self._attached_y.read(maxage)
        summ = abs(x - self._out_x)
        summ += abs(y - self._out_y)
        if summ < 1:
            return 'out'
        return 'in'

    def _generateSequence(self, target):
        seq = []

        s = SeqMethod(self, '_release')
        seq.append(s)

        if target == 'out':
            seq.append(SeqMethod(self, '_save_pos'))

            seq.append(SeqDev(self._attached_x, self._out_x))

            seq.append(SeqLimDev(self._attached_y, self._out_y, self._out_y))

            seq.append(SeqMethod(self, '_fix'))
        else:
            seq.append(SeqMethod(self, '_release'))

            seq.append(SeqLimDev(self._attached_y, self._in_y, -450))

            seq.append(SeqDev(self._attached_x, self._in_x))

        return seq
Example #8
0
class NarzissSpin(BaseSequencer):

    attached_devices = {
        'pom': Attach('Polariser rotation', Moveable),
        'pmag': Attach('Polariser magnet', Moveable),
    }

    valuetype = oneof('+', '-', '0', 'undefined')

    def _generateSequence(self, target):
        seq = []

        if target == '+':
            seq.append((SeqDev(self._attached_pom,
                               0.8), SeqDev(self._attached_pmag, -2.5)))
            seq.append(SeqSleep(4.))
            seq.append(SeqDev(self._attached_pmag, .15))
        elif target == '-':
            seq.append((SeqDev(self._attached_pom,
                               0.8), SeqDev(self._attached_pmag, 2.5)))
            seq.append(SeqSleep(4.))
            seq.append(SeqDev(self._attached_pmag, 1.))
        elif target == '0':
            seq.append((SeqDev(self._attached_pom,
                               3), SeqDev(self._attached_pmag, 0)))
        else:
            raise ProgrammingError('Invalid value requested')

        return seq

    def doRead(self, maxage=0):
        val = self._attached_pmag.read(maxage)
        if abs(val - .15) < .02:
            return '+'
        if abs(val - 1.) < .05:
            return '-'
        if abs(val - 0) < .05:
            return '0'
        return 'undefined'
Example #9
0
class ImageChannel(QMesyDAQImage, BaseImageChannel):

    parameters = {
        'readout': Param('Readout mode of the Detector', settable=True,
                         type=oneof('raw', 'mapped', 'amplitude'),
                         default='mapped', mandatory=False, chatty=True),
    }

    def doWriteListmode(self, value):
        self._dev.SetProperties(['writelistmode', '%s' % value])
        return self._getProperty('writelistmode')

    def doWriteHistogram(self, value):
        self._dev.SetProperties('writehistogram', '%s' % value)
        return self._getProperty('writehistogram')

    def doWriteReadout(self, value):
        self._dev.SetProperties(['histogram', '%s' % value])
        return self._getProperty('histogram')

    def doWriteListmodefile(self, value):
        self._dev.SetProperties(['lastlistfile', '%s' % value])
        return self._getProperty('lastlistfile')

#   def doReadListmodefile(self):
#       return self._getProperty('lastlistfile')

    def doWriteHistogramfile(self, value):
        self._taco_update_resource('lasthistfile', '%s' % value)
        return self._getProperty('lasthistfile')

#   def doReadHistogramfile(self):
#       return self._getProperty('lasthistfile')

    def doReadConfigfile(self):
        return self._getProperty('configfile')

    def doReadCalibrationfile(self):
        return self._getProperty('calibrationfile')
Example #10
0
class ChopperDisc(HasLimits, HasPrecision, DeviceMixinBase):

    parameters = {
        'phase': Param('Phase of chopper disc',
                       type=floatrange(0, 360), settable=True, userparam=True,
                       fmtstr='%.2f', unit='deg', category='status'),
        'current': Param('motor current',
                         type=float, settable=False, volatile=True,
                         userparam=True, fmtstr='%.2f', unit='A'),
        'mode': Param('Internal mode',
                      type=int, settable=False, userparam=True),
        'chopper': Param('chopper number inside controller',
                         type=intrange(1, 6), settable=False, userparam=True),
        'reference': Param('reference to Disc one',
                           type=floatrange(-360, 360), settable=False,
                           userparam=True),
        'edge': Param('Chopper edge of neutron window',
                      type=oneof('open', 'close'), settable=False,
                      userparam=True),
        'gear': Param('Chopper ratio',
                      type=intrange(-6, 6), settable=False, userparam=True,
                      default=0),
        'pos': Param('Distance to the disc 1',
                     type=floatrange(0), settable=False, userparam=True,
                     default=0., fmtstr='%.2f', unit='m', category='status'),
    }

    parameter_overrides = {
        'unit': Override(default='rpm', mandatory=False,),
        'precision': Override(default=2),
        'abslimits': Override(default=(0, 6000), mandatory=False),
        'fmtstr': Override(default='%.f'),
    }

    def doPoll(self, n, maxage):
        self._pollParam('current')

    def _isStopped(self):
        return abs(self.read(0)) <= self.precision
Example #11
0
class Network(Readable):

    parameters = {
        'interval':
        Param(
            'Interval for load detection',
            type=floatrange(0.1, 60),
            default=0.1,
            settable=True,
        ),
        'interface':
        Param(
            'Network interface device (None=all)',
            type=oneof(None,
                       *net_io_counters(True).keys()),
            default=None,
            settable=True,
        ),
        'direction':
        Param(
            'Transport direction',
            type=oneof('tx', 'rx'),
            default='tx',
            settable=True,
        ),
        'lastvalue':
        Param('Last obtained value',
              type=float,
              internal=True,
              mandatory=False,
              default=0.0),
    }

    def doInit(self, mode):
        if mode == SIMULATION:
            return
        # create only run ONE thread: in the poller
        # it may look stupid, as the poller already has a thread polling read()
        # now imagine several such devices in a setup.... not so stupid anymore
        if session.sessiontype == POLLER:
            self._thread = createThread('measure networkload', self._run)

    def doWriteInterval(self, value):
        self.pollinterval = max(1, 2 * value)
        self.maxage = max(3, 5 * value)

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

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

    def _getData(self):
        if not self.interface:
            data = net_io_counters()
        else:
            data = net_io_counters(True)[self.interface]
        return data.bytes_sent if self.direction == 'tx' else data.bytes_recv

    def _run(self):
        old = self._getData()
        while True:
            timeslept = 0
            while timeslept < self.interval:
                # interval may be changed while we sleep!
                sleeptime = max(0.1, self.interval / 10)
                time.sleep(sleeptime)
                timeslept += sleeptime
            new = self._getData()
            self._setROParam('lastvalue', (new - old) / timeslept)
            old = new
Example #12
0
class Segment(Moveable):
    """
    This class controls a SANS collimator segment through a
    host of attached slave devices
    """

    attached_devices = {
        'hand': Attach('Switch into remote mode', Moveable),
        'ble': Attach('Switch to BLE position', Moveable),
        'nl': Attach('Switch to NL position', Moveable),
        'zus': Attach('Switch to ZUS position', Moveable),
        'mot_error': Attach('Test motor errror', Readable),
        'seq_error': Attach('Test sequence error', Readable),
        'bolt_error': Attach('Test bolt error', Readable),
        'mot_fast': Attach('Motor fast', Readable),
        'mot_slow': Attach('Motor slow', Readable)
    }
    valuetype = oneof('ble', 'nl', 'zus')

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

    _target = None
    _start_time = None

    def doInit(self, mode):
        self._target = self.read(0)
        self._attached_hand.start(1)

    def doRead(self, maxage=0):
        if self._attached_ble.read(maxage) == 1:
            return 'ble'
        if self._attached_nl.read(maxage) == 1:
            return 'nl'
        if self._attached_zus.read(maxage) == 1:
            return 'zus'
        return 'transit'

    def _test_error(self):
        if self._attached_mot_error.read() == 1:
            return True, 'motor error'
        if self._attached_seq_error.read() == 1:
            return True, 'sequence error'
        if self._attached_bolt_error.read() == 1:
            return True, 'bolt error'
        return False, ''

    def doIsAllowed(self, pos):
        test, reason = self._test_error()
        if test:
            return False, reason
        return True, ''

    def doStart(self, pos):
        # Will only need to be done once (or someone messes with the rack)
        if self._attached_hand.read(0) == 0:
            self._attached_hand.start(1)
        self._target = pos
        self._start_time = time.time()
        if pos == 'ble':
            self._attached_ble.start(1)
        elif pos == 'nl':
            self._attached_nl.start(1)
        elif pos == 'zus':
            self._attached_zus.start(1)

    def doStatus(self, maxage=0):
        test, reason = self._test_error()
        if test:
            return status.ERROR, \
                   'Collimator SPS broken with %s, reset manually' % reason
        pos = self.doRead(maxage)
        if pos == self._target:
            return status.OK, ' '
        else:
            if time.time() > self._start_time + 360:
                return status.ERROR, 'Timeout moving segment'
            if self._attached_mot_fast.read(maxage) == 1:
                return status.BUSY, 'Moving fast'
            if self._attached_mot_slow.read(maxage) == 1:
                return status.BUSY, 'Moving slow'
            return status.BUSY, 'Locking/Unlocking'
Example #13
0
class Changer(BaseSequencer):
    attached_devices = {
        'lift':
        Attach('Lift moving a mono up or down between 4 '
               'positions', Moveable),
        'magazine':
        Attach('Magazine holding the monos and having 4 '
               'positions', Moveable),
        'liftclamp':
        Attach('Clamp holding the mono in the lift', Moveable),
        'magazineclamp':
        Attach('Clamp holding the mono in the magazine', Moveable),
        'tableclamp':
        Attach('Clamp holding the mono on the table', Moveable),
        'inhibitrelay':
        Attach('Inhibit to the remaining motor controllers', Moveable),
        'enable':
        Attach('To enable operation of the changer', Moveable),
        'magazineocc':
        Attach('Readout for occupancy of the magazine', Readable),
        'magazinestatus':
        Attach('Readout for status of magazine load position', Readable),
    }

    parameters = {
        'mono_on_table':
        Param('Name of Mono on the Monotable',
              type=oneof('PG', 'Si', 'Cu', 'Heusler', 'None', 'empty frame'),
              default='None',
              settable=True,
              internal=True),
        'mono_in_lift':
        Param('Which mono is in the lift',
              type=oneof('PG', 'Si', 'Cu', 'Heusler', 'None', 'empty frame'),
              default='None',
              settable=True,
              internal=True),
        'exchangepos':
        Param(
            'dict of device names to positional values '
            'for changing monos',
            type=dict,
            settable=False,
            userparam=False),
        'precisionchange':
        Param(
            'dict of device names and pairs of (normal '
            'value, change value) of the precision',
            type=dict,
            settable=False,
            userparam=False),
    }

    parameter_overrides = {
        'requires': Override(default={'level': 'admin'}),
    }

    positions = ['101', '110', '011', '111']  # CounterClockwise
    monos = ['Heusler', 'PG', 'Si', 'empty frame']  # assigned monos
    shields = ['110', '110', '110', '110']  # which magzinslot after changing
    #    (e.g. Put a PE dummy to 101 and set this to ('101,'*4).split(',')
    valuetype = oneof(*(monos + ['None']))

    def PrepareChange(self):
        '''is checking whether all the conditions for a change of mono are met'''

        # if not(self.SecShutter_is_closed()):
        #     raise UsageError(self, 'Secondary Shutter needs to be closed, '
        #                      'please close by hand and retry!')
        # if self.NotAus():
        #     raise UsageError(self, 'NotAus (Emergency stop) activated, '
        #                      'please check and retry!')
        # read all inputs and check for problems
        if not (self._attached_magazine.read() in self.positions):
            raise HWError(self, 'Unknown Magazine-Position !')
        if self._attached_lift.read() != '2':
            raise HWError(self, 'Lift not at parking position!')
        if self._attached_liftclamp.read() != 'close':
            raise HWError(self, 'liftclamp should be closed!')
        if self._attached_tableclamp.read() != 'close':
            raise HWError(self, 'tableclamp should be closed!')
        if self._attached_magazineclamp.read() != 'close':
            raise HWError(self, 'magazineclamp should be closed!')
        if self.mono_in_lift != 'None':
            raise HWError(
                self, 'There is mono %s in the lift, please change '
                'manually!' % self.mono_in_lift)

        # XXX TODO: store old values of positions and offsets someplace to
        # recover after changing back
        self.log.info('will change position of several devices to the '
                      'changing position, moving back is not yet implemented')

        # enhance precision of the devices
        for devname, prec in self.precisionchange.items():
            dev = session.getDevice(devname)
            dev.precision = prec[1]
            self.log.debug('changing precision of the %s device to the %f',
                           devname, prec[1])

        # go to the place where a change is possible
        devs = []
        for devname, pos in self.exchangepos.items():
            dev = session.getDevice(devname)
            # remove after implementation of moving back
            self.log.info('position of the %s device was %f', devname, dev())
            if isinstance(dev, HasOffset):
                dev.start(pos - dev.offset)
                self.log.debug(
                    'move and wait %s to the position %f - offset of %f',
                    devname, pos, dev.offset)
                dev.wait()
            else:
                dev.start(pos)
                self.log.debug('move and wait %s to the position %f', devname,
                               pos)
                dev.wait()
            devs.append(dev)
        multiWait(devs)

        # put precision back to normal
        for devname, prec in self.precisionchange.items():
            dev = session.getDevice(devname)
            dev.precision = prec[0]
            self.log.debug(
                'changing precision of the %s device back to '
                'the %f', devname, prec[0])

        try:
            dev = session.getDevice('focibox')
            self.mono_on_table = dev.read(0)
            dev.comm('XMA', forcechannel=False)
            dev.comm('YMA', forcechannel=False)
            dev.driverenable = False
            self.log.info('focus motors disabled')
        except NicosError as err:
            self.log.error('Problem disabling foci: %s', err)

        # switch on inhibit and enable
        self._attached_enable.maw(0xef16)
        self._attached_inhibitrelay.maw('on')
        self.log.info('changer enabled and inhibit active')

    def FinishChange(self):
        self._attached_inhibitrelay.maw('off')
        self._attached_enable.maw(0)
        self.log.warning('Please restart the daemon or reload the setups to '
                         'init the new Mono:')
        self.log.warning('  > NewSetup()')
        self.log.info('  > NewSetup()')

    def CheckMagazinSlotEmpty(self, slot):
        # checks if the given slot in the magazin is empty
        self.log.info('checking of there IS NOT mono in magazine slot %r' %
                      slot)
        if self._attached_magazineocc.status(0)[0] != status.OK:
            raise UsageError(
                self, 'Magazine occupancy switches are in warning state!')
        index = self.positions.index(slot)
        if not ((self._attached_magazineocc.read() >> index * 2) & 1):
            raise UsageError(self, 'Position %r is already occupied!' % slot)

    def CheckMagazinSlotUsed(self, slot):
        # checks if the given slot in the magazin is used (contains a monoframe)
        self.log.info('checking of there IS mono in magazine slot %r' % slot)
        if self._attached_magazineocc.status(0)[0] != status.OK:
            raise UsageError(
                self, 'Magazine occupancy switches are in warning state!')
        index = self.positions.index(slot)
        if (self._attached_magazineocc.read() >> index * 2) & 1:
            raise UsageError(self, 'Position %r is empty!' % slot)

    def _start(self, seq):
        if self._seq_is_running():
            raise MoveError(self, 'Can not start sequence, device is still '
                            'busy')
        self._startSequence(seq)

    # here is the party going on!
    def Transfer_Mono_Magazin2Lift(self):
        self._start(self._gen_mag2lift())
        self.wait()

    def _gen_mag2lift(self, magpos=None):
        seq = []
        if magpos is None:
            magpos = self._attached_magazine.read(0)
        else:
            seq.append(SeqDev(self._attached_magazine, magpos))
        # check preconditions
        seq.append(
            SeqCall(self.log.info, 'checking preconditions for Magazin2Lift'))
        seq.append(SeqCheckStatus(self._attached_magazine, status.OK))
        seq.append(SeqCheckStatus(self._attached_lift, status.OK))
        seq.append(SeqCheckPosition(self._attached_lift, '2'))
        seq.append(SeqCheckPosition(self._attached_liftclamp, 'close'))
        seq.append(SeqCheckPosition(self._attached_magazine, magpos))
        seq.append(SeqCheckPosition(self._attached_magazineclamp, 'close'))
        seq.append(SeqMethod(self, 'CheckMagazinSlotUsed', magpos))
        seq.append(SeqCheckAttr(self, 'mono_in_lift', 'None'))
        # transfer mono to lift
        seq.append(
            SeqCall(self.log.info, 'transferring mono from magazine to lift'))
        seq.append(SeqDev(self._attached_liftclamp, 'open'))
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqMethod(self._attached_liftclamp, 'start', 'close'))
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_liftclamp, 'close'))
        seq.append(SeqMethod(self._attached_magazineclamp, 'start', 'open'))
        # rattle a little
        seq.append(SeqCall(self.log.info, 'rattle to release magazine grab'))
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_magazineclamp, 'open'))
        seq.append(SeqMethod(self, 'CheckMagazinSlotEmpty', magpos))
        # move (with mono) to parking position
        seq.append(
            SeqCall(self.log.info, 'moving with mono to parking position'))
        seq.append(
            SeqSetAttr(self, 'mono_in_lift',
                       self.monos[self.positions.index(magpos)]))
        seq.append(SeqDev(self._attached_lift, '2'))  # park position
        seq.append(SeqDev(self._attached_magazineclamp, 'close'))
        # Magazin should not contain a mono now
        seq.append(SeqMethod(self, 'CheckMagazinSlotEmpty', magpos))
        return seq

    def Transfer_Mono_Lift2Magazin(self):
        self._start(self._gen_lift2mag())
        self.wait()

    def _gen_lift2mag(self, magpos=None):
        seq = []
        if magpos is None:
            magpos = self._attached_magazine.read(0)
        else:
            seq.append(SeqDev(self._attached_magazine, magpos))
        # check preconditions
        seq.append(
            SeqCall(self.log.info, 'checking preconditions for Lift2Magazin'))
        seq.append(SeqCheckStatus(self._attached_magazine, status.OK))
        seq.append(SeqCheckStatus(self._attached_lift, status.OK))
        seq.append(SeqCheckPosition(self._attached_lift, '2'))
        seq.append(SeqCheckPosition(self._attached_liftclamp, 'close'))
        seq.append(SeqCheckPosition(self._attached_magazine, magpos))
        seq.append(SeqCheckPosition(self._attached_magazineclamp, 'close'))
        seq.append(SeqMethod(self, 'CheckMagazinSlotEmpty', magpos))
        # there needs to be a mono in the lift
        seq.append(
            SeqCall(self.log.info, 'checking if there is a mono in lift'))
        seq.append(
            SeqCheckAttr(self,
                         'mono_in_lift',
                         values=[m for m in self.monos if m != 'None']))
        # prepare magazin
        seq.append(SeqCall(self.log.info, 'testing magazin grab'))
        seq.append(SeqDev(self._attached_magazineclamp, 'open'))
        seq.append(SeqDev(self._attached_magazineclamp, 'close'))
        seq.append(SeqDev(self._attached_magazineclamp, 'open'))
        seq.append(SeqDev(self._attached_magazineclamp, 'close'))
        seq.append(SeqDev(self._attached_magazineclamp, 'open'))
        # transfer mono to lift
        seq.append(SeqCall(self.log.info, 'moving lift to top position'))
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(
            SeqCall(self.log.info,
                    'closing the magazin grab and rattling lift'))
        seq.append(SeqMethod(self._attached_magazineclamp, 'start', 'close'))
        # rattle a little
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_lift, '3'))  # almost top position
        seq.append(SeqDev(self._attached_magazineclamp, 'close'))
        seq.append(SeqMethod(self, 'CheckMagazinSlotUsed', magpos))
        seq.append(SeqCall(self.log.info, 'opening lift clamp'))
        seq.append(SeqMethod(self._attached_liftclamp, 'start', 'open'))
        seq.append(SeqDev(self._attached_lift, '4'))  # top position
        seq.append(SeqDev(self._attached_lift, '3'))  # top position
        seq.append(SeqDev(self._attached_liftclamp, 'open'))
        seq.append(SeqCall(self.log.info, 'moving lift to park position'))
        seq.append(SeqDev(self._attached_lift, '2'))  # park position
        seq.append(SeqCall(self.log.info, 'closing lift clamp'))
        seq.append(SeqDev(self._attached_liftclamp, 'close'))
        # move (without mono) to parking position
        seq.append(SeqSetAttr(self, 'mono_in_lift', 'None'))
        # Magazin should not contain a mono now
        seq.append(SeqMethod(self, 'CheckMagazinSlotUsed', magpos))
        return seq

    def Transfer_Mono_Lift2Table(self):
        self._start(self._gen_lift2table())
        self.wait()

    def _gen_lift2table(self):
        seq = []
        # check preconditions
        seq.append(
            SeqCall(self.log.info, 'checking preconditions for Lift2Table'))
        seq.append(SeqCheckStatus(self._attached_tableclamp, status.OK))
        seq.append(SeqCheckStatus(self._attached_liftclamp, status.OK))
        seq.append(SeqCheckStatus(self._attached_lift, status.OK))
        seq.append(SeqCheckPosition(self._attached_lift, '2'))
        seq.append(SeqCheckPosition(self._attached_liftclamp, 'close'))
        seq.append(SeqCheckPosition(self._attached_tableclamp, 'close'))
        # there shall be a mono in the lift!
        seq.append(SeqCall(self.log.info, 'check if there is a mono in Lift'))
        seq.append(
            SeqCheckAttr(self,
                         'mono_in_lift',
                         values=[m for m in self.monos if m != 'None']))
        seq.append(SeqCheckAttr(self, 'mono_on_table', 'None'))
        seq.append(SeqCall(self.log.info, 'moving down the lift'))
        # transfer mono to table
        seq.append(SeqDev(self._attached_tableclamp, 'open'))
        seq.append(SeqDev(self._attached_lift, '1'))  # bottom position
        seq.append(
            SeqCall(self.log.info,
                    'closing table grab and releasing lift clamp'))
        seq.append(SeqDev(self._attached_tableclamp, 'close'))
        # move (without mono) to parking position
        seq.append(SeqDev(self._attached_liftclamp, 'open'))

        def func(self):
            self.mono_on_table, self.mono_in_lift = self.mono_in_lift, 'None'

        seq.append(SeqCall(func, self))
        # seq.append(SeqSetAttr(self, 'mono_on_table', self.mono_in_lift))
        # seq.append(SeqSetAttr(self, 'mono_in_lift', 'None'))
        seq.append(SeqCall(self.log.info, 'moving lift to park position'))
        seq.append(SeqDev(self._attached_lift, '2'))  # park position
        seq.append(SeqDev(self._attached_liftclamp, 'close'))
        # TODO: change foci alias and reactivate foci
        return seq

    def Transfer_Mono_Table2Lift(self):
        self._start(self._gen_table2lift())
        self.wait()

    def _gen_table2lift(self):
        # XXX TODO drive all foci to 0 and switch of motors....
        # XXX TODO move mty/mtx to monospecific abholposition
        # hier nur das reine abholen vom Monotisch
        seq = []
        # check preconditions
        seq.append(
            SeqCall(self.log.info, 'checking preconditions for Table2Lift'))
        seq.append(SeqCheckStatus(self._attached_tableclamp, status.OK))
        seq.append(SeqCheckStatus(self._attached_liftclamp, status.OK))
        seq.append(SeqCheckStatus(self._attached_lift, status.OK))
        seq.append(SeqCheckPosition(self._attached_lift, '2'))
        seq.append(SeqCheckPosition(self._attached_liftclamp, 'close'))
        seq.append(SeqCheckPosition(self._attached_tableclamp, 'close'))
        # there shall be no mono in the lift, but one on the table
        seq.append(
            SeqCall(self.log.info, 'checking if there IS NOT a mono in Lift'))
        seq.append(SeqCheckAttr(self, 'mono_in_lift', 'None'))
        seq.append(
            SeqCheckAttr(self,
                         'mono_on_table',
                         values=[m for m in self.monos if m != 'None']))
        # transfer mono to lift
        seq.append(SeqCall(self.log.info, 'moving down the lift'))
        seq.append(SeqDev(self._attached_liftclamp, 'open'))
        seq.append(SeqDev(self._attached_lift, '1'))  # bottom position
        seq.append(SeqCall(self.log.info, 'grabbing the monochromator'))
        seq.append(SeqDev(self._attached_liftclamp, 'close'))
        seq.append(SeqDev(self._attached_tableclamp, 'open'))

        # move (with mono) to parking position
        def func(self):
            self.mono_on_table, self.mono_in_lift = 'None', self.mono_on_table

        seq.append(SeqCall(func, self))
        # seq.append(SeqSetAttr(self, 'mono_on_table', 'None'))
        # seq.append(SeqSetAttr(self, 'mono_in_lift', self.mono_on_table))
        seq.append(
            SeqCall(self.log.info,
                    'moving the lift with mono to parking position'))
        seq.append(SeqDev(self._attached_lift, '2'))  # park position
        seq.append(SeqDev(self._attached_tableclamp, 'close'))
        return seq

    def doStart(self, target):
        self.change(self.mono_on_table, target)

    def change(self, old, whereto):
        ''' cool kurze Wechselroutine
        Der Knackpunkt ist in den Hilfsroutinen!'''
        if not (old in self.monos + ['None']):
            raise UsageError(
                self, '\'%s\' is illegal value for Mono, use one '
                'of ' % old + ', '.join(self.monos + ['None']))
        if not (whereto in self.monos + ['None']):
            raise UsageError(
                self, '\'%s\' is illegal value for Mono, use one '
                'of ' % whereto + ', '.join(self.monos + ['None']))
        self.PrepareChange()
        if self.monos.index(whereto) == self.monos.index(old):
            # Nothing to do, requested Mono is supposed to be on the table
            return
        # Ok, we have a good state, the only thing we do not know is which mono
        # is on the table......
        # for this we use the (cached) parameter mono_on_table

        if self.mono_on_table != old:
            raise UsageError(
                self, 'Mono %s is not supposed to be on the '
                'table, %s is!' % (old, self.mono_on_table))

        seq = []
        # 0) move magazine to mono position
        magpos_to_put = self.positions[self.monos.index(old)]
        seq.append(SeqMethod(self, 'CheckMagazinSlotEmpty', magpos_to_put))
        seq.append(SeqDev(self._attached_magazine, magpos_to_put))
        # 1) move away the old mono, if any
        if old != 'None':
            seq.extend(self._gen_table2lift())
            seq.extend(
                self._gen_lift2mag(self.positions[self.monos.index(old)]))
        # 2) fetch the new mono (if any) from the magazin
        if whereto != 'None':
            seq.extend(
                self._gen_mag2lift(self.positions[self.monos.index(whereto)]))
            seq.extend(self._gen_lift2table())
            seq.append(
                SeqDev(self._attached_magazine,
                       self.shields[self.monos.index(whereto)]))

        # seq.append(SeqDev(self._attached_enable, 0)) - will be done in FinishChange
        seq.append(SeqMethod(self, 'FinishChange'))
        self._start(seq)
        self.wait()

    @usermethod
    def printstatusinfo(self):
        self.log.info(
            'PLC is %s', 'enabled' if self._attached_enable.read() == 0xef16
            else 'disabled, you need to set enable_word to the '
            'correct value')
        self.log.info('Inhibit_relay is %s',
                      self._attached_inhibitrelay.read())
        liftposnames = {
            '0': 'unknown, error in switches',
            '1': 'Monotable loading',
            '2': 'Park position',
            '3': 'Bottom storage',
            '4': 'Upper storage'
        }
        self.log.info('lift is at %s',
                      liftposnames[self._attached_lift.read()])
        try:
            magpos = self._attached_magazine.read()
            self.log.info('magazine is at %r which is assigned to %s', magpos,
                          self.monos[self.positions.index(magpos)])
        except Exception:
            self.log.error('magazine is at an unknown position !!!')
        for n in 'liftclamp magazineclamp tableclamp'.split():
            self.log.info('%s is %s', n, self._adevs[n].read())
        occ = self._attached_magazineocc.read(0)
        for i in range(4):
            self.log.info(
                'magazine slot %r is %sempty and its readouts are %sbroken',
                self.positions[i], '' if (occ >> (i * 2)) & 1 else 'not ',
                '' if (occ >> (i * 2 + 1)) & 1 else 'not ')
        if self._attached_magazinestatus.read() == 'free':
            self.log.info('magazine is currently free to load monochromator')
        else:
            self.log.info('magazine is currently occupied with monochromator '
                          'and cannot load another')

    def doRead(self, maxage=0):
        return ''
Example #14
0
class AndorHFRCamera(PyTangoDevice, UsesFastshutter, ImageChannelMixin,
                     ActiveChannel):
    """Camera communicating with Andor Basic script."""

    TRIGGER_MODES = {
        'internal': 0,
        'external': 1,
        'external start': 6,
        'external exposure': 7,
        'external exposure FVB': 9,
    }

    SHUTTER_MODES = {
        'rolling': 0,
        'global': 1,
    }

    parameters = {
        'bin':
        Param('Binning (x,y)',
              type=tupleof(intrange(1, 64), intrange(1, 64)),
              settable=True,
              default=(1, 1),
              category='general'),
        'triggermode':
        Param('Triggering signal definition',
              type=oneof(*TRIGGER_MODES),
              settable=True,
              default='internal',
              category='general'),
        'shuttermode':
        Param('Shutter mode setting',
              type=oneof(*SHUTTER_MODES),
              settable=True,
              default='rolling',
              category='general'),
        'spooldirectory':
        Param('Path to spool the images on the remote '
              'machine',
              type=absolute_win_path,
              category='general'),
        'extratime':
        Param('Extra sleeping time to sync with Andors Basic',
              type=floatrange(0),
              default=3,
              settable=True),
        '_started':
        Param('Cached counting start flag',
              type=none_or(float),
              default=None,
              settable=True,
              internal=True),
    }

    def doPreinit(self, mode):
        PyTangoDevice.doPreinit(self, mode)
        self.log.info('Checking if camera script is ready!')
        try:
            msg = self._dev.communicate('ready?')
            if msg.strip() != 'ready!':
                raise CommunicationError(
                    self, 'Camera script gave wrong '
                    'answer - please check!')
        except NicosError:
            self.log.warning('Camera is not responding - please start '
                             'tomography script on camera first!')
            raise

    def doReset(self):
        self.log.info('Checking if camera script is ready!')
        try:
            msg = self._dev.communicate('ready?')
            if msg.strip() != 'ready!':
                raise CommunicationError(
                    self, 'Camera script gave wrong '
                    'answer - please check!')
        except NicosError:
            self.log.warning('Camera is not responding - please start '
                             'tomography script on camera first!')
            raise

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

    def valueInfo(self):
        # no readresult by default
        return ()

    def doStart(self):
        self.bin = self.bin
        self.shuttermode = self.shuttermode
        self.triggermode = self.triggermode
        self.doWriteSpooldirectory(self.spooldirectory)
        kct = float(self._query_value('GetKineticCycleTime'))
        self.log.info('kct: %s', kct)
        self._counttime = self._knumber * kct + 3
        self.log.info('measure time = %s s', self._counttime)
        self.openFastshutter()
        self._write_command('count')
        self._started = currenttime()
        self.log.debug('started: %s', self._started)

    def doSetPreset(self, **presets):
        for preset, val in presets.items():
            self._write_presets(preset, val)
        self._write_presets(
            'spoolfile',
            presets.get('spoolfile', session.experiment.sample.samplename))

    def presetInfo(self):
        return ['exptime', 'number', 'cycletime', 'spoolfile']

    def doStatus(self, maxage=0):
        if self._started:
            if (self._started + self._counttime) > currenttime():
                return status.BUSY, 'counting'
        return status.OK, 'idle'

    def doStop(self):
        self._started = None
        self.status(0)
        self._attached_fastshutter.maw('closed')

    def doFinish(self):
        self._started = None
        # self._attached_fastshutter.maw('closed')

    def doWriteTriggermode(self, value):
        self._write_command('SetTriggerMode %d' % self.TRIGGER_MODES[value])

    def doWriteShuttermode(self, value):
        self._write_command('SetShutterMode %d' % self.SHUTTER_MODES[value])

    def doWriteSpooldirectory(self, value):
        self._write_command('SetSpoolDirectory %s' % value)

    def doWriteBin(self, value):
        self._write_command('SetHBin %d' % value[0])
        self._write_command('SetVBin %d' % value[1])

    def _write_command(self, command):
        ret = self._dev.communicate(command)
        if not ret.startswith('ACK'):
            if ret.startswith('ERR'):
                raise InvalidValueError(self,
                                        'Command: %s is invalid ' % command)
            raise InvalidValueError(
                self, 'Command: %s has invalid '
                'parameters' % command)

    def _query_value(self, request):
        return self._dev.communicate(request)

    def _write_presets(self, preset, value):
        if preset == 'exptime':
            self._write_command('SetExposureTime %f' % value)
        elif preset == 'number':
            self._write_command('SetKineticNumber %d' % value)
            self._knumber = int(value)
        elif preset == 'cycletime':
            self._write_command('SetKineticCycleTime %f' % value)
        elif preset == 'spoolfile':
            self._write_command('SetSpoolFileName %s' % value)
Example #15
0
class IDS3010Control(Moveable):
    """Control interferometer measurement and alignment options.
    """

    _modes = {
        "system idle": status.OK,
        "measurement starting": status.BUSY,
        "measurement running": status.OK,
        "optics alignment starting": status.BUSY,
        "optics alignment running": status.OK,
        "pilot laser enabled": status.OK,
    }

    parameters = {
        'pilot': Param('Pilot laser for alignment', type=oneof('on', 'off'),
                       settable=True, category='general', chatty=True, ),
        'align': Param('Measure in alignment mode', type=oneof('on', 'off'),
                       settable=True, category='general', chatty=True, ),
        'contrast1': Param('Measure in alignment mode', type=float,
                           settable=False, category='general', chatty=True,
                           unit='%'),
        'contrast2': Param('Measure in alignment mode', type=float,
                           settable=False, category='general', chatty=True,
                           unit='%'),
        'contrast3': Param('Measure in alignment mode', type=float,
                           settable=False, category='general', chatty=True,
                           unit='%'),
    }

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

    attached_devices = {
        'server': Attach('Server for communication', IDS3010Server)
    }

    valuetype = oneof('on', 'off')

    def doStatus(self, maxage=0):
        mode = self._attached_server.communicate('system.getCurrentMode')[0]
        return self._modes[mode], mode

    def doRead(self, maxage=0):
        return 'on' if self.status()[1] == "measurement running" else 'off'

    def doStart(self, value):
        self._attached_server.communicate('system.startMeasurement'
                                          if value == 'on' else
                                          'system.stopMeasurement')

    def doReadPilot(self):
        enabled = self._attached_server.communicate('pilotlaser.isEnabled')[0]
        return 'on' if enabled else 'off'

    def doWritePilot(self, value):
        self._attached_server.communicate('pilotlaser.enable' if value == 'on'
                                          else 'pilotlaser.disable')

    def doReadAlign(self):
        enabled = self._attached_server.communicate(
            'system.getCurrentMode')[0].startswith('optics alignment')
        return 'on' if enabled else 'off'

    def doWriteAlign(self, value):
        if (value == 'on' and
                self._attached_server.communicate(
                    'system.getCurrentMode')[0] == "system idle"):
            self._attached_server.communicate('system.startOpticsAlignment')
        else:
            self._attached_server.communicate('system.stopOpticsAlignment')

    def doReadContrast1(self):
        return self._attached_server.communicate(
            'adjustment.getContrastInPermille', 0)[1] * 0.1

    def doReadContrast2(self):
        return self._attached_server.communicate(
            'adjustment.getContrastInPermille', 1)[1] * 0.1

    def doReadContrast3(self):
        return self._attached_server.communicate(
            'adjustment.getContrastInPermille', 2)[1] * 0.1

    def doReset(self):
        self._attached_server.com.attocube.system.rebootSystem()

    def doPoll(self, n, maxage=0):
        # poll contrast values when in alignment mode
        if self.align=='on':
            self._pollParam('contrast1')
            self._pollParam('contrast2')
            self._pollParam('contrast3')
Example #16
0
class Configuration(PyTangoDevice, PassiveChannel):
    """Channel that allows to configure various parameters of the DECTRIS
    Pilatus detector.

    Without this channel you cannot access any parameter of the Pilatus
    detector except for the exposure time (TimerChannel) out of NICOS.

    You can attach devices to this channel in order to read out their values
    and store them in the Pilatus image header via the ``mxsettings``
    parameter.
    """

    # TODO: add proper descriptions
    attached_devices = {
        'detector_distance': Attach(
            'Current detector distance to sample.',
            Readable, optional=True,
        ),
        'detector_voffset': Attach(
            'Current vertical detector translation.',
            Readable,  optional=True,
        ),
        'flux': Attach(
            'Current photon flux in cps.',
            Readable, optional=True,
        ),
        'filter_transmission': Attach(
            'Current transmission filter factor.',
            Readable, optional=True,
        ),
        'start_angle': Attach(
            '',
            Readable, optional=True,
        ),
        'detector_2theta': Attach(
            'Current two-theta position.',
            Readable, optional=True,
        ),
        'polarization': Attach(
            '',
            Readable, optional=True,
        ),
        'alpha': Attach(
            'Current alpha position.',
            Readable, optional=True,
        ),
        'kappa': Attach(
            'Current kappa position.',
            Readable, optional=True,
        ),
        'phi': Attach(
            'Current phi position.',
            Readable, optional=True,
        ),
        'chi': Attach(
            'Current chi position.',
            Readable, optional=True,
        ),
        'omega': Attach(
            'Current omega position.',
            Readable, optional=True,
        ),
        'start_position': Attach(
            '',
            Readable, optional=True,
        ),
        'shutter_time': Attach(
            '',
            Readable, optional=True,
        ),
    }

    parameters = {
        'energy': Param(
            'X-ray and threshold energy in kilo electron volt. Set to "None" '
            'if the energy is either not set yet not configurable for this '
            'detector.',
            type=none_or(
                dictwith(**dict((p, float) for p in ENERGY_PARAMETERS))),
            settable=True,
            volatile=True,
            unit='keV',
            prefercache=False,
            chatty=True,
        ),
        'exposures': Param(
            'Number of exposures to accumulate per frame/readout.',
            type=intrange(1, 2**32 - 1),
            settable=True,
            volatile=True,
            userparam=False,
            unit='',
        ),
        'imageheader': Param(
            'String to be included in the image header.',
            type=str,
            settable=True,
            volatile=True,
            unit='',
            chatty=True,
        ),
        'images': Param(
            'Number of images for an automatic sequence.',
            type=intrange(1, 2**16 - 1),
            settable=True,
            volatile=True,
            userparam=False,
            unit='',
        ),
        'mxsettings': Param(
            'Crystallographic parameters reported in the image header.',
            type=dictof(oneof(*MX_PARAMETERS), anytype),
            settable=True,
            volatile=True,
            unit='',
            prefercache=False,
        ),
        'period': Param(
            'Exposure period in seconds (must be longer than exposure time + '
            '2.28 ms readout time).',
            type=floatrange(1.0015, 60 * 24 * 60 * 60),  # maximum: 60 days
            settable=True,
            volatile=True,
            userparam=False,
            unit='s',
        ),
        'sensorvalues': Param(
            'Relative humidity and temperature sensor values on all channels.',
            type=dictof(str, str),
            unit='',
            volatile=True,
        ),
    }

    parameter_overrides = {
        'lowlevel': Override(default=True),
    }

    def _poll_all_channels(self):
        # update the status of all pilatus detector channels
        for detector in session.experiment.detectors:
            if isinstance(detector, Detector):
                detector.poll()

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

    def valueInfo(self):
        return ()

    def doStatus(self, maxage=0):
        return PyTangoDevice.doStatus(self, maxage)[0], ''

    def doPrepare(self):
        self.doUpdateMxsettings({})

    def doReadEnergy(self):
        values = self._dev.energy
        return dict(zip(ENERGY_PARAMETERS, values)) if all(values) else None

    def _write_energy(self, value):
        # only send the energy parameters to the hardware if they have changed
        if self.energy:
            for param in ENERGY_PARAMETERS:
                if abs(value[param] - self.energy[param]) > 0.001:
                    self._dev.energy = [value['xray'], value['threshold']]
                    return

    def doWriteEnergy(self, value):
        self._write_energy(value)
        self._poll_all_channels()

    def doUpdateEnergy(self, value):
        # only necessary for transmitting setup values to the hardware
        if self.doStatus()[0] == status.OK:
            self._write_energy(value)

    def doReadExposures(self):
        return self._dev.exposures

    def doReadImages(self):
        return self._dev.images

    def doWriteImages(self, value):
        self._dev.images = value

    def doReadImageheader(self):
        return self._dev.imageHeader

    def doWriteImageHeader(self, value):
        self._dev.imageHeader = value

    def doReadMxsettings(self):
        mx_settings = self._dev.mxSettings
        if not mx_settings:
            return {}
        # create dict {k1: v1, k2: v2, ...} from list [k1, v1, k2, v2, ...]
        mx_settings = {mx_settings[2 * i]: mx_settings[2 * i + 1]
                       for i in range(len(mx_settings) // 2)}
        # convert values to tuple, float or int
        return {k: MX_PARAMETERS[k](v) for k, v in mx_settings.items()}

    def doWriteMxsettings(self, value):
        start_time = time()
        # energy update must be completed after maximum 15 seconds
        while time() < start_time + 15:
            if self.doStatus()[0] == status.OK:
                break
            self.log.info('waiting until the detector is ready')
            session.delay(1.5)
        else:
            self.log.error('mxsettings update could not be performed: '
                           'pilatus detector is still busy')
            return
        # flatten dict {k1: v1, k2: v2, ...} to [k1, v1, k2, v2, ...]
        self._dev.mxSettings = [str(v) for v in list(sum(value.items(), ()))]

    def doUpdateMxsettings(self, value):
        value = dict(value)  # convert to writable dict
        for name, adev in ((k, v) for k, v in self._adevs.items() if v):
            adev_value = adev.read()
            if name == 'filter_transmission':
                adev_value = 1 / adev_value
            value[name] = str(adev_value)
        if value:
            self.doWriteMxsettings(value)

    def doReadPeriod(self):
        return self._dev.period

    def doWritePeriod(self, value):
        self._dev.period = value

    def doReadSensorvalues(self):
        sensor_values = self._dev.sensorValues
        # create dict {k1: v1, k2: v2, ...} from list [k1, v1, k2, v2, ...]
        return {sensor_values[2 * i]: sensor_values[2 * i + 1]
                for i in range(len(sensor_values) // 2)}

    @usermethod
    @requires(level=USER)
    def setEnergy(self, radiation=None, **value):
        """Either load the predefined settings that are suitable for usage with
        silver, chromium, copper, iron oder molybdenum radiation or set
        the x-ray and threshold energy to any other appropriate values.

        :param str radiation: 'Ag', 'Cr', 'Cu', 'Fe' or 'Mo' (case insensitive)
        :param dict[str, float] value: {'xray': x, 'threshold': y}
        """
        if not (radiation or value) or radiation and value:
            raise InvalidValueError('call either dev.SetEnergy("<radiation>") '
                                    'or dev.SetEnergy(xray=x, threshold=y)')
        if radiation:
            self._dev.LoadEnergySettings(radiation)
            self._poll_all_channels()
        else:
            self.energy = value
Example #17
0
class DoubleMotorBeckhoff(PseudoNOK, BeckhoffMotorBase):
    """a double motor Beckhoff knows both axis at once!
    It comunicats direktly by modbuss
    """

    hardware_access = True

    parameters = {
        'addresses':
        Param('addresses of each motor',
              type=tupleof(motoraddress, motoraddress),
              mandatory=True,
              settable=False,
              userparam=False),
        'mode':
        Param('Beam mode',
              type=oneof(*MODES),
              settable=True,
              userparam=True,
              default='ng',
              category='experiment'),
        'motortemp':
        Param('Motor temperature',
              type=tupleof(float, float),
              settable=False,
              userparam=True,
              volatile=True,
              unit='degC',
              fmtstr='%.1f, %.1f'),
        '_rawvalues':
        Param('Raw positions',
              type=tupleof(float, float),
              internal=True,
              category='experiment'),
    }

    parameter_overrides = {
        'ruler':
        Override(type=tupleof(float, float),
                 mandatory=True,
                 settable=False,
                 userparam=False),
    }

    valuetype = tupleof(float, float)

    def doReference(self):
        """Reference the NOK.

        Just set the do_reference bit and check for completion
        """
        self.log.error('nope')

    def doReadMaxvalue(self):
        return 1111

    def doReadMinvalue(self):
        return -1111

    def doReadMotortemp(self):
        # in degC
        self.log.debug('DoubleMotorBeckhoff doReadMotortemp')
        return self._HW_readParameter('motorTemp')

    def doReadFirmware(self):
        # TODO self._HW_readParameter('firmwareVersion'))
        return 'V%.1f' % (0.1 * 0)

    def doReadVmax(self):
        # TODO self._speed2phys(self._HW_readParameter('vMax'))
        return 0

    def doReadRefpos(self):
        # TODO self._steps2phys(self._HW_readParameter('refPos'))
        return 0

    def doReadPotentiometer(self):
        return [self._fit(a)
                for a in self._HW_readParameter('potentiometer')][0]

    def _writeUpperControlWord(self, value):
        self.log.debug('_writeUpperControlWord 0x%04x', value)
        value = int(value) & 0xffff
        self._dev.WriteOutputWord((self.addresses[0] + 1, value))
        self._dev.WriteOutputWord((self.addresses[1] + 1, value))

    def _readReturn(self):
        value = []
        for i in range(2):
            valuel = self._dev.ReadOutputWords((self.addresses[i] + 8, 2))
            self.log.debug('_readReturn %d: -> %d (0x%08x)', i, valuel, valuel)
            value.append(struct.unpack('=i', struct.pack('<2H', *valuel))[0])
        return value

    def _HW_readParameter(self, index):
        if index not in self.HW_readable_Params:
            raise UsageError('Reading not possible for parameter index %s' %
                             index)

        index = self.HW_readable_Params.get(index, index)
        self.log.debug('readParameter %d', index)

        for i in range(10):
            self._writeUpperControlWord((index << 8) | 4)
            session.delay(0.15)
            stat = self._areadStatusWord(self.addresses[0])
            self.log.debug('readStatusWord 0 %d', stat)
            stat = self._areadStatusWord(self.addresses[0])
            self.log.debug('readStatusWord 1 %d', stat)
            if (stat & 0x8000) != 0:
                if i > 0:
                    self.log.debug('readParameter %d', i + 1)
                return self._readReturn()
            if (stat & 0x4000) != 0:
                raise UsageError(
                    self, 'NACK ReadPar command not recognized '
                    'by HW, please retry later...')
        raise UsageError(
            self, 'ReadPar command not recognized by HW, please '
            'retry later ...')

    def _areadPosition(self, address):
        value = self._dev.ReadOutputWords((address + 6, 2))
        value = struct.unpack('=i', struct.pack('<2H', *value))[0]
        self.log.debug('_readPosition: -> %d steps', value)
        return value

    def _awriteDestination(self, value, address):
        self.log.debug('_writeDestination %r', value)
        value = struct.unpack('<2H', struct.pack('=i', value))
        self._dev.WriteOutputWords(tuple([address + 2]) + value)

    def _awriteControlBit(self, bit, value, numbits, address):
        self.log.debug('_writeControlBit %r, %r', bit, value)
        self._dev.WriteOutputWord(
            (address, (value & ((1 << int(numbits)) - 1)) << int(bit)))
        session.delay(0.1)  # work around race conditions....

    def _asteps2phys(self, steps, ruler):
        value = steps / float(self.slope) - ruler
        self.log.debug('_steps2phys ruler: %r steps -> %s', steps,
                       self.format(value, unit=True))
        return value

    def _aphys2steps(self, value, ruler):
        steps = int((value + ruler) * float(self.slope))
        self.log.debug('_phys2steps ruler: %s -> %r steps',
                       self.format(value, unit=True), steps)
        return steps

    def _indexReadPosition(self, i):
        return self._asteps2phys(self._areadPosition(self.addresses[i]),
                                 self.ruler[i])

    def _areadStatusWord(self, address):
        value = self._dev.ReadOutputWords((address + 4, 1))[0]
        self.log.debug('_areadStatusWord 0x%04x', value)
        return value

    def _areadErrorWord(self, address):
        value = self._dev.ReadOutputWords((address + 5, 1))[0]
        self.log.debug('_readErrorWord 0x%04x', value)
        return value

    def _indexHW_status(self, i):
        """Used status bits."""
        # read HW values
        errval = self._areadErrorWord(self.addresses[i])
        statval = (self._areadStatusWord(self.addresses[i])
                   ^ self.HW_Status_Inv) & ~self.HW_Status_Ign

        msg = bitDescription(statval, *self.HW_Statusbits)
        self.log.debug('HW_status: (%x) %s', statval, msg)
        if errval:
            errnum = errval
            return status.ERROR, 'ERROR %d: %s, %s' % (
                errnum,
                self.HW_Errors.get(errnum,
                                   'Unknown Error {0:d}'.format(errnum)), msg)

        for mask, stat in self.HW_Status_map:
            if statval & mask:
                return stat, msg

        return status.OK, msg if msg else 'Ready'

    def _HW_wait_while_HOT(self):
        sd = 6.5
        anz = int(round(self.waittime * 60 / sd))
        # Pech bei 2.session
        for a in range(anz):
            temp = max(self.motortemp)
            if temp < self.maxtemp:  # wait if temp>33 until temp<26
                if a:
                    self.log.info('%d Celsius continue', temp)
                else:
                    self.log.debug('%d Celsius continue', temp)
                return True
            self.log.info('%d Celsius Timeout in: %.1f min', temp,
                          (anz - a) * sd / 60)
            session.delay(sd)
        raise NicosTimeoutError('HW still HOT after {0:d} min'.format(
            self.waittime))

    def doRead(self, maxage=0):
        self.log.debug('DoubleMotorBeckhoff read')
        res = [self._indexReadPosition(0), self._indexReadPosition(1)]
        self.log.debug('%s', res)
        self._setROParam('_rawvalues', res)
        return res

    def doStatus(self, maxage=0):
        self.log.debug('DoubleMotorBeckhoff status')
        lowlevel = BaseSequencer.doStatus(self, maxage)
        if lowlevel[0] == status.BUSY:
            return lowlevel
        akt = [self._indexHW_status(0), self._indexHW_status(1)]
        self.log.debug('Status: %s', akt)
        msg = [st[1] for st in akt]
        self.log.debug('Status: %s', msg)
        return (max([st[0] for st in akt]),
                ', '.join(msg) if msg.count(msg[0]) == 1 else msg[0])

    def _generateSequence(self, target, indexes, code):
        self.log.debug('DoubleMotorBeckhoff Seq generated %s %s 0x%X', target,
                       indexes, code)
        seq = [SeqMethod(self, '_HW_wait_while_HOT')]
        for i in indexes:
            seq.append(
                SeqMethod(self, '_awriteDestination',
                          self._aphys2steps(target[i], self.ruler[i]),
                          self.addresses[i]))
            seq.append(
                SeqMethod(self, '_awriteControlBit', 0, code, 10,
                          self.addresses[i]))
        return seq

    def doStart(self, target):
        self.log.debug('DoubleMotorBeckhoff move to %s', target)
        if self._seq_is_running():
            raise MoveError(self, 'Cannot start device, it is still moving!')
        self._startSequence(self._generateSequence(target, [0, 1], 0x304))
Example #18
0
class BeamstopChanger(BeamstopSequencer):
    """
    A class for changing the beamstop. At SANS this is realised through
    a sequence of motor movements.
    """
    attached_devices = {
        'io': Attach('SPS I/O for reading slot', Readable),
    }

    valuetype = oneof(1, 2, 3, 4)

    _beamstop_pos = {
        1: 28.0,
        2: -100.5,
        3: -220.5,
        4: -340.5,
    }

    def doInit(self, mode):
        # Stopping this procedure can mess up things badly
        self._honor_stop = False

    def _emergencyFix(self, reason):
        session.log.error('%s, Fixing motors, Get a manager to fix this',
                          reason)
        self._fix()

    def doRead(self, maxage):
        dio = self._attached_io.read(maxage)
        test = dio[1]
        val = 1
        count = 0
        for i in range(0, 3):
            if test & 1 << i:
                val = i + 2
                count += 1
        if count > 1:
            self._emergencyFix('Beamstop lost!!!')
        return val

    def doIsAllowed(self, pos):
        if self._attached_y.isAtTarget(-543):
            return False, 'Cannot change beamstop in OUT position'
        return True, ''

    def _testArrival(self, xpos, ypos):
        if not (self._attached_x.isAtTarget(xpos) and
                self._attached_y.isAtTarget(ypos)):
            self._emergencyFix('Beamstop driving failed!!!')

    def _generateSequence(self, target):
        seq = []

        pos = self.read(0)
        self._save_pos()

        xpos = self._beamstop_pos[pos]
        seq.append((SeqDev(self._attached_y, -450),
                    SeqDev(self._attached_x, xpos)))
        seq.append(SeqMethod(self, '_testArrival', xpos, -450.))

        seq.append(SeqLimDev(self._attached_y, -549, -549))
        seq.append(SeqMethod(self, '_testArrival', xpos, -549.))

        xpos = self._beamstop_pos[int(target)]
        seq.append(SeqDev(self._attached_x, xpos))
        seq.append(SeqMethod(self, '_testArrival', xpos,
                             -549.))

        seq.append(SeqLimDev(self._attached_y, -450, -450))
        seq.append(SeqMethod(self, '_testArrival', xpos, -450))

        seq.append((SeqDev(self._attached_y, self._in_y),
                    SeqDev(self._attached_x, self._in_x)))

        return seq

    def _runFailed(self, step, action, exc_info):
        self._emergencyFix('Beamstop motor failed to run!!!')
        BeamstopSequencer._runFailed(self, step, action, exc_info)

    def doStatus(self, maxage=0):
        stat = BaseSequencer.doStatus(self, maxage)
        if stat[0] != status.BUSY and self._seq_is_running():
            return status.BUSY, stat[1]
        return stat
Example #19
0
class ImageChannel(QMesyDAQImage, BaseImageChannel):

    parameters = {
        'readout':
        Param('Readout mode of the Detector',
              settable=True,
              type=oneof('raw', 'mapped', 'amplitude'),
              default='mapped',
              mandatory=False,
              chatty=True),
        'flipaxes':
        Param('Flip data along these axes after reading from det',
              type=listof(int),
              default=[],
              unit=''),
        'transpose':
        Param('Whether to transpose the image', type=bool, default=False),
    }

    # Use the configuration from QMesyDAQ
    parameter_overrides = {
        'listmode': Override(volatile=True),
        'histogram': Override(volatile=True),
    }

    def doWriteListmode(self, value):
        self._dev.SetProperties(['writelistmode', ('%s' % value).lower()])
        return self.doReadListmode()

    def doReadListmode(self):
        return {
            'false': False,
            'true': True
        }[self._getProperty('writelistmode')]

    def doWriteHistogram(self, value):
        self._dev.SetProperties(['writehistogram', ('%s' % value).lower()])
        return self.doReadHistogram()

    def doReadHistogram(self):
        return {
            'false': False,
            'true': True
        }[self._getProperty('writehistogram')]

    def doWriteReadout(self, value):
        self._dev.SetProperties(['histogram', value])
        return self._getProperty('histogram')

    def doWriteListmodefile(self, value):
        self._dev.SetProperties(['lastlistfile', value])
        return self._getProperty('lastlistfile')

#   def doReadListmodefile(self):
#       return self._getProperty('lastlistfile')

    def doWriteHistogramfile(self, value):
        self._dev.SetProperties(['lasthistfile', value])
        return self._getProperty('lasthistfile')


#   def doReadHistogramfile(self):
#       return self._getProperty('lasthistfile')

    def doReadConfigfile(self):
        return self._getProperty('configfile')

    def doReadCalibrationfile(self):
        return self._getProperty('calibrationfile')

    def doReadArray(self, quality):
        narray = BaseImageChannel.doReadArray(self, quality)
        if self.transpose:
            narray = np.transpose(narray)
        for axis in self.flipaxes:
            narray = np.flip(narray, axis)
        return narray

    def doFinish(self):
        self.doStatus(0)
        return BaseImageChannel.doFinish(self)

    def doStop(self):
        self.doStatus(0)
        return BaseImageChannel.doStop(self)
Example #20
0
class ChopperMaster(CanReference, BaseSequencer):

    valuetype = dictwith(
        wlmin=float,
        wlmax=float,
        gap=float,
        chopper2_pos=intrange(1, 6),
        D=float,
    )

    parameters = {
        'mode':
        Param('Chopper operation mode (normal, virtual6)',
              type=oneof('normal_mode', 'virtual_disc2_pos_6'),
              settable=False,
              category='status'),
        'delay':
        Param('delay for Startsignal in Degree',
              type=floatrange(-360, 360),
              settable=True,
              userparam=True),
        'wlmin':
        Param('Wavelength min',
              type=floatrange(0, 30),
              settable=True,
              userparam=True,
              unit='AA',
              category='status'),
        'wlmax':
        Param('Wavelength max',
              type=floatrange(0, 30),
              settable=True,
              userparam=True,
              unit='AA',
              category='status'),
        'dist':
        Param('flight path (distance chopper disc 1 to detector)',
              type=floatrange(0),
              settable=True,
              userparam=True,
              unit='m',
              category='status'),
        'gap':
        Param('Gap ... ',
              type=floatrange(0, 100),
              settable=True,
              userparam=True,
              unit='%',
              category='status'),
        'resolution':
        Param('Resolution ...',
              type=intrange(1, 6),
              settable=False,
              userparam=True,
              mandatory=False,
              volatile=True,
              category='status'),
        'speed':
        Param('Chopper1 speed ... ',
              type=float,
              settable=False,
              userparam=True,
              mandatory=False,
              volatile=True,
              category='status'),
    }

    _max_disks = 6

    attached_devices = {
        'chopper1': Attach('chopper1 defining speed', Moveable),
        'chopper2': Attach('chopper2 phase', Moveable),
        'chopper3': Attach('chopper3 phase also height', Moveable),
        'chopper4': Attach('chopper4 phase also height', Moveable),
        'chopper5': Attach('chopper5 phase half speed', Moveable),
        'chopper6': Attach('chopper6 phase half speed', Moveable),
        'shutter': Attach('Shutter device', Moveable),
    }

    def doInit(self, mode):
        self._choppers = (self._attached_chopper1, self._attached_chopper2,
                          self._attached_chopper3, self._attached_chopper4,
                          self._attached_chopper5, self._attached_chopper6)

    def _generateSequence(self, target):
        self.wlmin, self.wlmax = limits(
            (target.get('wlmin', self.wlmin), target.get('wlmax', self.wlmax)))
        self.dist = target.get('D', self.dist)
        self.gap = target.get('gap', self.gap)
        chopper2_pos = target.get('chopper2_pos')

        speed, angles = chopper_config(self.wlmin,
                                       self.wlmax,
                                       self.dist,
                                       chopper2_pos,
                                       gap=self.gap)

        self.log.debug('speed: %d, angles = %s', speed, angles)

        seq = []
        shutter_pos = self._attached_shutter.read(0)
        shutter_ok = self._attached_shutter.status(0)[0] == status.OK
        if chopper2_pos == 6:
            self._setROParam('mode', 'virtual_disc2_pos_6')
        else:
            self._setROParam('mode', 'normal_mode')
            chopper2_pos_akt = self._attached_chopper2.pos
            if chopper2_pos_akt != chopper2_pos:
                if shutter_ok:
                    seq.append(
                        SeqDev(self._attached_shutter,
                               'closed',
                               stoppable=True))
                seq.append(SeqDev(self._attached_chopper1, 0, stoppable=True))
                seq.append(
                    SeqSlowParam(self._attached_chopper2, 'pos', chopper2_pos))

        for dev, t in zip(self._choppers[1:], angles[1:]):
            # The Chopper measures the phase in the opposite direction
            # as we do this was catered for here, we have moved the
            # sign conversion to the doWritePhase function
            # dev.phase = -t  # sign by history
            seq.append(SeqFuzzyParam(dev, 'phase', t, 0.5))
        seq.append(SeqDev(self._attached_chopper1, speed, stoppable=True))
        if shutter_ok:
            seq.append(
                SeqDev(self._attached_shutter, shutter_pos, stoppable=True))
        return seq

    def doRead(self, maxage=0):
        # TODO: for cfg
        value = {
            'D':
            self.dist,
            'wlmin':
            self.wlmin,
            'wlmax':
            self.wlmax,
            'gap':
            self.gap,
            'chopper2_pos':
            self._attached_chopper2.pos if self.mode == 'normal_mode' else 6,
        }
        return value

    def _getWaiters(self):
        return self._choppers

    def doReadResolution(self):
        if self.mode == 'normal_mode':
            return self._attached_chopper2.pos
        else:
            return 6

    def doReadSpeed(self):
        return self._attached_chopper1.read(0)
Example #21
0
class HVSwitch(SequencerMixin, MappedMoveable):
    """High voltage convenience switching device for the CHARM detector."""

    valuetype = oneof('on', 'off', 'safe')

    attached_devices = {
        'anodes':
        Attach('HV channels for the anodes', Moveable, multiple=[2, 9]),
        'banodes':
        Attach('HV channels for the boundary anodes',
               Moveable,
               multiple=[1, 8]),
        'cathodes':
        Attach('HV channels for the boundary cathodes', Moveable, multiple=2),
        'window':
        Attach('HV channel for the window', Moveable, multiple=1),
        'trip':
        Attach('Devices signaling a trip on the hardware', Readable),
    }

    parameters = {
        '_tripped':
        Param('Indicator for hardware trip',
              type=bool,
              internal=True,
              default=False),
    }

    parameter_overrides = {
        'unit': Override(default='', mandatory=False),
        'fallback': Override(default='unknown'),
        'mapping': Override(type=dictof(str, dictof(str, float))),
    }

    def doInit(self, mode):
        if self.fallback in self.mapping:
            raise ConfigurationError(
                self, 'Value of fallback parameter is '
                'not allowed to be in the mapping!')
        self._devices = {
            dev.name: dev
            for dev in (self._attached_anodes + self._attached_banodes +
                        self._attached_cathodes + self._attached_window)
        }

        if len(self._attached_anodes) != len(self._attached_banodes) + 1:
            raise ConfigurationError(
                self, 'Number of anode devices must be '
                'the number of boundary anodes + 1: %d, '
                '%d' % (len(self.anodes), len(self.banodes)))
        # if not self.relax_mapping:
        #     self.valuetype = oneof(*sorted(self.mapping, key=num_sort))

        for value in sorted(self.mapping, key=num_sort):
            try:
                self.valuetype(value)
            except ValueError as err:
                raise ConfigurationError(
                    self, '%r not allowed as key in mapping. %s' %
                    (value, err)) from err

    def doIsAllowed(self, target):
        if target == 'off':
            ok = True
        else:
            ok = not self._tripped and not self._attached_trip.read(0)
        return ok, '' if ok else 'hardware is tripped'

    def doStop(self):
        if not self._tripped:
            SequencerMixin.doStop(self)
        else:
            raise ModeError(self, "can't be stopped, device is tripped.")

    def doReset(self):
        if self._tripped:
            if self.doStatus(0)[0] == status.BUSY or self._hardware_tripped():
                raise ModeError(self,
                                "can't reset device. Hardware is tripped")
        SequencerMixin.doReset(self)
        self._setROParam('_tripped', False)

    def doPoll(self, n, maxage):
        if not self._tripped and session.sessiontype == POLLER and \
           self._hardware_tripped():
            self._setROParam('_tripped', True)

    def _hardware_tripped(self):
        return self._attached_trip.read(0) == 'Trip'

    def _generateSequence(self, target):
        anodes = self._attached_anodes + self._attached_banodes
        seq = [
            [
                SeqDev(dev, self.mapping[target][dev.name])
                for dev in self._attached_window
            ],
            [SeqDev(dev, self.mapping[target][dev.name]) for dev in anodes],
            [
                SeqDev(dev, self.mapping[target][dev.name])
                for dev in self._attached_cathodes
            ],
        ]
        return seq

    def _is_at_target(self, pos, target):
        # if values are exact the same
        if pos == target:
            return True
        for dev in pos:
            if not self._devices[dev].isAtTarget(pos[dev], target[dev]):
                return False
        return True

    def _mapReadValue(self, value):
        for val in self.mapping:
            if self._is_at_target(value, self.mapping[val]):
                return val
        if self.fallback is not None:
            return self.fallback
        else:
            raise PositionError(self, 'unknown unmapped position %r' % value)

    def _readRaw(self, maxage=0):
        return {dev.name: dev.read(maxage) for dev in self._devices.values()}

    def _startRaw(self, target):
        ramp = 60 * self.mapping[self.target]['ramp']
        seq = self._generateSequence(self.target)
        if self.target in ['off', 'safe']:
            seq.reverse()
        self._startSequence([
            SeqParam(dev, 'ramp', ramp)
            for dev in self._attached_anodes + self._attached_banodes +
            self._attached_cathodes + self._attached_window
        ] + seq)
Example #22
0
class DoubleMotorBeckhoffNOK(DoubleMotorBeckhoff):
    """NOK using two axes.
    """

    parameters = {
        'mode':
        Param('Beam mode',
              type=oneof(*MODES),
              settable=True,
              userparam=True,
              default='ng',
              category='experiment'),
        'nok_motor':
        Param('Position of the motor for this NOK',
              type=tupleof(float, float),
              settable=False,
              unit='mm',
              category='general'),
        'inclinationlimits':
        Param('Allowed range for the positional '
              'difference',
              type=limits,
              mandatory=True),
        'backlash':
        Param('Backlash correction in phys. units',
              type=float,
              default=0.,
              unit='main'),
        'offsets':
        Param('Offsets of NOK-Motors (reactor side, sample side)',
              type=tupleof(float, float),
              default=(0., 0.),
              settable=False,
              unit='main',
              category='offsets'),
    }

    parameter_overrides = {
        'precision':
        Override(type=floatrange(0, 100)),
        'masks':
        Override(type=dictwith(**{name: float
                                  for name in MODES}),
                 unit='',
                 mandatory=True),
        'address':
        Override(mandatory=False),
    }

    valuetype = tupleof(float, float)
    _honor_stop = True

    def doInit(self, mode):
        for name, idx in [('reactor', 0), ('sample', 1)]:
            self.__dict__[name] = SingleMotorOfADoubleMotorNOK(
                '%s.%s' % (self.name, name),
                unit=self.unit,
                both=self,
                lowlevel=True,
                index=idx)

    def doWriteMode(self, mode):
        self.log.debug('DoubleMotorBeckhoffNOK arg:%s  self:%s', mode,
                       self.mode)
        target = self.doRead(0)
        self.log.debug('DoubleMotorBeckhoffNOK target %s', target)
        target = [pos + self.masks[mode] for pos in target]
        self.log.debug('DoubleMotorBeckhoffNOK target %s', target)
        DoubleMotorBeckhoff.doStart(self, target)

    def doRead(self, maxage=0):
        self.log.debug('DoubleMotorBeckhoffNOK read')
        return [
            pos - self.masks[self.mode]
            for pos in DoubleMotorBeckhoff.doRead(self, maxage)
        ]

    def doIsAllowed(self, target):
        self.log.debug('DoubleMotorBeckhoffNOK doIsAllowed')
        target_r, target_s = (target[0] + self.offsets[0],
                              target[1] + self.offsets[1])

        incmin, incmax = self.inclinationlimits

        inclination = target_s - target_r
        if not incmin < inclination < incmax:
            return False, 'Inclination %.2f out of limit (%.2f, %.2f)!' % (
                inclination, incmin, incmax)

        # no problems detected, so it should be safe to go there....
        return True, ''

    def doIsAtTarget(self, pos, target):
        self.log.debug('DoubleMotorBeckhoffNOK doIsAtTarget')
        stat = self.status(0)
        if stat[0] == status.BUSY:
            return False
        return True

    def doStart(self, target):
        self.log.debug('DoubleMotorBeckhoffNOK doStart')
        self.log.debug('target %s %s', target, type(target))
        target = [pos + self.masks[self.mode] for pos in target]
        self.log.debug('target %s %s', target, type(target))
        DoubleMotorBeckhoff.doStart(self, target)
Example #23
0
class DoubleMotorNOK(SequencerMixin, CanReference, PseudoNOK, HasPrecision,
                     Moveable):
    """NOK using two axes.

    If backlash is negative, approach form the negative side (default),
    else approach from the positive side.
    If backlash is zero, don't mind and just go to the target.
    """

    attached_devices = {
        'motor_r': Attach('NOK moving motor, reactor side', Moveable),
        'motor_s': Attach('NOK moving motor, sample side', Moveable),
    }

    parameters = {
        'mode':
        Param('Beam mode',
              type=oneof(*MODES),
              settable=True,
              userparam=True,
              default='ng',
              category='experiment'),
        'nok_motor':
        Param('Position of the motor for this NOK',
              type=tupleof(float, float),
              settable=False,
              unit='mm',
              category='general'),
        'inclinationlimits':
        Param('Allowed range for the positional '
              'difference',
              type=limits,
              mandatory=True),
        'backlash':
        Param('Backlash correction in phys. units',
              type=float,
              default=0.,
              unit='main'),
        'offsets':
        Param('Offsets of NOK-Motors (reactor side, sample side)',
              type=tupleof(float, float),
              default=(0., 0.),
              settable=False,
              unit='main',
              category='offsets'),
    }

    parameter_overrides = {
        'precision':
        Override(type=floatrange(0, 100)),
        'masks':
        Override(type=dictwith(**{name: float
                                  for name in MODES}),
                 unit='',
                 mandatory=True),
    }

    valuetype = tupleof(float, float)
    _honor_stop = True

    @lazy_property
    def _devices(self):
        return self._attached_motor_r, self._attached_motor_s

    def doInit(self, mode):
        for dev in self._devices:
            if hasattr(dev, 'backlash') and dev.backlash != 0:
                self.log.warning(
                    'Attached Device %s should not have a '
                    'non-zero backlash!', dev)

    def doRead(self, maxage=0):
        return [
            dev.read(maxage) - ofs - self.masks[self.mode]
            for dev, ofs in zip(self._devices, self.offsets)
        ]

    def doIsAllowed(self, targets):
        target_r, target_s = targets
        target_r += self.offsets[0]
        target_s += self.offsets[1]

        incmin, incmax = self.inclinationlimits

        inclination = target_s - target_r
        if not incmin <= inclination <= incmax:
            return False, 'Inclination %.2f out of limit (%.2f, %.2f)!' % (
                inclination, incmin, incmax)

        for dev in self._devices:
            res = dev.isAllowed(target_r)
            if not res[0]:
                return res

        # no problems detected, so it should be safe to go there....
        return True, ''

    def doIsAtTarget(self, targets):
        traveldists = [
            target - (akt + ofs)
            for target, akt, ofs in zip(targets, self.read(0), self.offsets)
        ]
        self.log.debug('doIsAtTarget', targets, 'traveldists', traveldists)
        return max(abs(v) for v in traveldists) <= self.precision

    def doStop(self):
        SequencerMixin.doStop(self)
        for dev in self._devices:
            dev.stop()
        try:
            self.wait()
        finally:
            self.reset()

    def doStart(self, targets):
        """Generate and start a sequence if none is running.

        The sequence is optimised for negative backlash.
        It will first move both motors to the lowest value of
        (target + backlash, current_position) and then
        to the final target.
        So, inbetween, the NOK should be parallel to the beam.
        """
        if self._seq_is_running():
            raise MoveError(self, 'Cannot start device, it is still moving!')

        # check precision, only move if needed!
        if self.isAtTarget(targets):
            return

        devices = self._devices

        # XXX: backlash correction and repositioning later

        # build a moving sequence
        sequence = []

        # now go to target
        sequence.append([
            SeqDev(d, t + ofs + self.masks[self.mode], stoppable=True)
            for d, t, ofs in zip(devices, targets, self.offsets)
        ])

        # now go to target again
        sequence.append([
            SeqDev(d, t + ofs + self.masks[self.mode], stoppable=True)
            for d, t, ofs in zip(devices, targets, self.offsets)
        ])

        self.log.debug('Seq: %r', sequence)
        self._startSequence(sequence)

    def doReset(self):
        multiReset(self._motors)
Example #24
0
class ImagePlateImage(ImageChannelMixin, PassiveChannel):
    """Represents the client to a MAATEL Image Plate Detector."""

    MAP_SHAPE = {
        125: (900, 10000),
        250: (900, 5000),
        500: (900, 2500),
    }

    attached_devices = {
        "imgdrum":      Attach("Image Plate Detector Drum "
                               "control device.", ImagePlateDrum),
    }

    parameters = {
        "erase": Param("Erase image plate on next start?", type=bool,
                       settable=True, mandatory=False, default=True),
        "roi": Param("Region of interest",
                     type=tupleof(int, int, int, int),
                     default=(0, 0, 0, 0),
                     settable=True, volatile=True,
                     category="general"),
        "pixelsize": Param("Pixel size in microns",
                           type=oneof(125, 250, 500), default=500,
                           settable=True, volatile=True, category="general"),
        "file": Param("Image file location on maatel computer",
                      type=str, settable=True, volatile=True,
                      category="general"),
        "readout_millis": Param("Timeout in ms for the readout",
                                type=int, settable=True, default=60000),
    }

    def doInit(self, mode):
        self.arraydesc = ArrayDesc('data',
                                   self.MAP_SHAPE[self.pixelsize],
                                   numpy.uint16)

    def doPrepare(self):
        # erase and expo position
        if self.erase:
            self._attached_imgdrum.maw(ImagePlateDrum.POS_ERASE)
        self._attached_imgdrum.maw(ImagePlateDrum.POS_EXPO)

    def valueInfo(self):
        # no readresult -> no values
        return ()

    def doReadArray(self, quality):
        if quality == FINAL:
            # start readout
            self._attached_imgdrum.maw(ImagePlateDrum.POS_READ)
            narray = None
            timeout = self._attached_imgdrum._dev.get_timeout_millis()
            self._attached_imgdrum._dev.set_timeout_millis(self.readout_millis)
            try:
                narray = self._attached_imgdrum._dev.Bitmap16Bit
            finally:
                self._attached_imgdrum._dev.set_timeout_millis(timeout)
            return narray
        return None

    def doReadRoi(self):
        return (0, self._attached_imgdrum._dev.InterestZoneY, 1250,
                self._attached_imgdrum._dev.InterestZoneH)

    def doReadPixelsize(self):
        return self._attached_imgdrum._dev.PixelSize

    def doReadFile(self):
        return self._attached_imgdrum._dev.ImageFile

    def doWriteRoi(self, value):
        self.log.warning("setting x offset and width are not supported "
                         "- ignored.")
        self._attached_imgdrum._dev.InterestZoneY = value[1]
        self._attached_imgdrum._dev.InterestZoneH = value[3]

    def doWritePixelsize(self, value):
        self._attached_imgdrum._dev.PixelSize = value
        self.arraydesc = ArrayDesc('data', self.MAP_SHAPE[value], numpy.uint16)

    def doWriteFile(self, value):
        self._attached_imgdrum._dev.ImageFile = value
Example #25
0
class CascadeDetector(VirtualImage):

    _perfoil = 16

    parameters = {
        'mode':
        Param('Data acquisition mode (tof or image)',
              type=oneof('tof', 'image'),
              settable=True,
              default='image',
              category='presets'),
        'roi':
        Param('Region of interest, given as (x1, y1, x2, y2)',
              type=tupleof(int, int, int, int),
              default=(-1, -1, -1, -1),
              settable=True),
        'tofchannels':
        Param('Total number of TOF channels to use',
              type=intrange(1, 1024),
              default=128,
              settable=True,
              category='presets'),
        'foilsorder':
        Param('Usable foils, ordered by number.',
              type=listof(intrange(0, 31)),
              settable=False,
              default=[0, 1, 2, 3, 4, 5, 6, 7],
              category='instrument'),
        'fitfoil':
        Param('Foil for contrast fitting (number BEFORE '
              'resorting)',
              type=int,
              default=0,
              settable=True),
    }

    def doInit(self, mode):
        self._buf = self._generate(0).astype('<u4')

    def doUpdateMode(self, value):
        self._dataprefix = (value == 'image') and 'IMAG' or 'DATA'
        self._datashape = (value == 'image') and self.sizes or \
            (self._perfoil * len(self.foilsorder), ) + self.sizes
        # (self.tofchannels,)
        self._tres = (value == 'image') and 1 or self.tofchannels

    def doStart(self):
        self.readresult = [0, 0]
        VirtualImage.doStart(self)

    def valueInfo(self):
        if self.mode == 'tof':
            return (Value(self.name + '.roi',
                          unit='cts',
                          type='counter',
                          errors='sqrt',
                          fmtstr='%d'),
                    Value(self.name + '.total',
                          unit='cts',
                          type='counter',
                          errors='sqrt',
                          fmtstr='%d'),
                    Value('fit.contrast',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.3f'),
                    Value('fit.contrastErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.3f'),
                    Value('fit.avg',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.1f'),
                    Value('fit.avgErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.1f'),
                    Value('roi.contrast',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.3f'),
                    Value('roi.contrastErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.3f'),
                    Value('roi.avg',
                          unit='',
                          type='other',
                          errors='next',
                          fmtstr='%.1f'),
                    Value('roi.avgErr',
                          unit='',
                          type='error',
                          errors='none',
                          fmtstr='%.1f'))
        return (Value(self.name + '.roi',
                      unit='cts',
                      type='counter',
                      errors='sqrt',
                      fmtstr='%d'),
                Value(self.name + '.total',
                      unit='cts',
                      type='counter',
                      errors='sqrt',
                      fmtstr='%d'))

    @property
    def arraydesc(self):
        if self.mode == 'image':
            return ArrayDesc('data', self._datashape, '<u4', ['X', 'Y'])
        return ArrayDesc('data', self._datashape, '<u4', ['T', 'X', 'Y'])

    def doReadArray(self, quality):
        # get current data array from detector, reshape properly
        data = VirtualImage.doReadArray(self, quality)
        # determine total and roi counts
        total = data.sum()
        if self.roi != (-1, -1, -1, -1):
            x1, y1, x2, y2 = self.roi
            roi = data[..., y1:y2, x1:x2].sum()
        else:
            x1, y1, x2, y2 = 0, 0, data.shape[-1], data.shape[-2]
            roi = total

        if self.mode == 'image':
            self.readresult = [roi, total]
            return data

        data = np.array([data] * self._datashape[0])

        # demux timing into foil + timing
        nperfoil = self._datashape[0] // len(self.foilsorder)
        shaped = data.reshape((len(self.foilsorder), nperfoil) +
                              self._datashape[1:])
        # nperfoil = self.tofchannels // self.foils
        # shaped = data.reshape((self.foils, nperfoil) + self._datashape[1:])

        x = np.arange(nperfoil)

        ty = shaped[self.fitfoil].sum((1, 2))
        ry = shaped[self.fitfoil, :, y1:y2, x1:x2].sum((1, 2))

        self.log.debug('fitting %r and %r' % (ty, ry))

        self.readresult = [
            roi,
            total,
        ]

        # also fit per foil data and pack everything together to be send
        # via cache for display
        payload = []
        for foil in self.foilsorder:
            foil_tot = shaped[foil].sum((1, 2))
            foil_roi = shaped[foil, :, y1:y2, x1:x2].sum((1, 2))
            tpopt, tperr, _ = fit_a_sin_fixed_freq(x, foil_tot)
            rpopt, rperr, _ = fit_a_sin_fixed_freq(x, foil_roi)
            payload.append([
                tpopt, tperr,
                foil_tot.tolist(), rpopt, rperr,
                foil_roi.tolist()
            ])

        self._cache.put(self.name, '_foildata', payload, flag=FLAG_NO_STORE)
        return data
Example #26
0
class ImagePlateDrum(PyTangoDevice, Moveable):
    """ImagePlateDrum implements erasing, moving to expo position and readout
    for MAATEL Image Plate Detectors.
    """

    DEFAULT_URL_FMT = "tango://%s/EMBL/Microdiff/General#dbase=no"

    tango_status_mapping = dict(PyTangoDevice.tango_status_mapping)
    tango_status_mapping[DevState.STANDBY] = status.OK
    tango_status_mapping[DevState.ALARM] = status.ERROR

    POS_ERASE = "erase"
    POS_EXPO = "expo"
    POS_READ = "read"

    valuetype = oneof(POS_ERASE, POS_EXPO, POS_READ)

    parameters = {
        "drumpos": Param("Drum position in degree", type=float,
                         settable=True, volatile=True, category="general"),
        "readheadpos": Param("Read head motor position in mm",
                             type=float, settable=True, volatile=True,
                             category="general"),
        "drumexpo": Param("Drum expo position in degree",
                          type=float, settable=True, volatile=True,
                          category="general"),
        "readspeed": Param("Readout velocity for the detector drum "
                           "in rpm", type=float, settable=True,
                           volatile=True, category="general"),
        "erasespeed": Param("Erase velocity for the detector drum "
                            "in rpm", type=float, settable=True,
                            volatile=True, category="general"),
        "freqlaser": Param("Frequency for the laser diode in Hz",
                           type=float, settable=True, volatile=True,
                           category="general"),
        "timeerase": Param("Erasure time in seconds", type=float,
                           settable=True, volatile=True, category="general"),
    }

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

    def doInit(self, mode):
        self._lastStatus = None
        self._moveTo = None
        if mode == SIMULATION:
            self._mapStart = {}
            self._mapStop = {}
            return
        self._mapStart = {
            ImagePlateDrum.POS_ERASE: self._dev.StartErasureProcess,
            ImagePlateDrum.POS_EXPO: self._dev.MoveExpoPosition,
            ImagePlateDrum.POS_READ: self._dev.StartReadProcess,
        }
        self._mapStop = {
            ImagePlateDrum.POS_ERASE: self._dev.AbortErasureProcess,
            ImagePlateDrum.POS_EXPO: self._dev.AbortExposureProcess,
            ImagePlateDrum.POS_READ: self._dev.AbortReadProcess,
        }

    def doStart(self, pos):
        self.log.debug("doStart: pos: %s", pos)
        myStatus = self.status(0)
        if myStatus[0] == status.OK:
            self._moveTo = pos
            self._mapStart[pos]()
        else:
            raise MoveError(self, "Movement not allowed during device status "
                            "'%s'" % (status.statuses[myStatus[0]]))

    def doStop(self):
        self.log.debug("doStop")
        if self._moveTo in self._mapStop:
            self._mapStop[self._moveTo]()
        else:
            myStatus = self.status(0)
            if myStatus[0] == status.OK:
                self.log.warning("Device already stopped.")
            else:
                raise NicosError(self, "Internal moveTo state unknown. "
                                       "Check device status.")

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

    def doStatus(self, maxage=0):
        # Workaround for status changes from busy to another state although the
        # operation has _not_ been completed.
        st, msg = PyTangoDevice.doStatus(self, maxage)
        if self._lastStatus == status.BUSY and st != status.BUSY:
            self.log.debug("doStatus: leaving busy state (%d)? %d. "
                           "Check again after a short delay.", status.BUSY, st)
            session.delay(5)
            st, msg = PyTangoDevice.doStatus(self, 0)
            self.log.debug("doStatus: recheck result: %d", st)
        self._lastStatus = st
        return st, msg

    def doFinish(self):
        self._moveTo = None

    def doReadDrumpos(self):
        return self._dev.DrumPosition

    def doReadReadheadpos(self):
        return self._dev.ReadHeadPosition

    def doReadDrumexpo(self):
        return self._dev.DrumExpoPosition

    def doReadReadspeed(self):
        return self._dev.ReadingDrumJogSpeed

    def doReadErasespeed(self):
        return self._dev.ErasureDrumJogSpeed

    def doReadFreqlaser(self):
        return self._dev.LaserDiodeLevel

    def doReadTimeerase(self):
        return self._dev.ErasureDuration

    def doWriteDrumpos(self, value):
        self._dev.DrumPosition = value

    def doWriteReadheadpos(self, value):
        self._dev.ReadHeadPosition = value

    def doWriteDrumexpo(self, value):
        self._dev.DrumExpoPosition = value

    def doWriteReadspeed(self, value):
        self._dev.ReadingDrumJogSpeed = value

    def doWriteErasespeed(self, value):
        self._dev.ErasureDrumJogSpeed = value

    def doWriteFreqlaser(self, value):
        self._dev.LaserDiodeLevel = value

    def doWriteTimeerase(self, value):
        self._dev.ErasureDuration = value
Example #27
0
class SingleMotorOfADoubleMotorNOK(AutoDevice, Moveable):
    """
    empty class marking a Motor as beeing useable by a (DoubleMotorNok)
    """

    hardware_access = True

    attached_devices = {
        'both': Attach('access to both of them via mode', Moveable),
    }

    parameters = {
        'index':
        Param('right side of nok',
              type=oneof(0, 1),
              settable=False,
              mandatory=True),
    }

    def doRead(self, maxage=0):
        self.log.debug('SingleMotorOfADoubleMotorNOK %d', self.index)
        quick = self._attached_both
        return quick.read(maxage)[self.index]

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

    def doStart(self, target):
        self.log.debug('SingleMotorOfADoubleMotorNOK for %s to %s', self.name,
                       target)
        if self._seq_is_running():
            raise MoveError(self, 'Cannot start device, it is still moving!')
        incmin, incmax = self._attached_both.inclinationlimits
        both = self._attached_both
        port = self._attached_both._attached_device

        if self.index == 1:
            code = 0x204
            inclination = both.read(0)[0]
        else:
            code = 0x104
            inclination = both.read(0)[1]
        self.log.debug('code 0x%03X d%d', code, code)

        inclination = target - inclination
        if incmin > inclination:
            brother = target - incmin / 2
        elif incmax < inclination:
            brother = target - incmax / 2
        else:
            self.log.debug('legal driving range')
            port._startSequence(
                port._generateSequence([target + both.masks[both.mode]],
                                       [self.index], code))
            return

        self.log.debug('brother move %.2f', brother)
        if self.index == 1:
            both.move([brother, target])
        else:
            both.move([target, brother])