Exemplo n.º 1
0
 def _int(min=None, max=None, **kwds):  # pylint: disable=redefined-builtin
     # be tolerant with missing min / max here
     if max is None:
         if min is None:
             return int
         return intrange(min, 1<<64)
     return intrange(-1<<64 if min is None else min, max)
Exemplo n.º 2
0
class DimetixLaser(CanDisable, HasOffset, Readable):

    attached_devices = {
        'signal': Attach('signal strength device', Readable),
        'value': Attach('value device', Readable),
    }

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

    parameters = {
        'signallimit':
        Param('minimal signal strength for valid reading',
              type=floatrange(0.),
              default=8000),
        'invalidvalue':
        Param('value to indicate invalid value',
              type=intrange(-2000, -2000),
              default=-2000),
    }

    def doRead(self, maxage=0):
        if self._attached_signal.read(maxage) < self.signallimit:
            return self.invalidvalue
        return self._attached_value.read(maxage)

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

    def doPoll(self, n, maxage):
        self._attached_signal.poll(n, maxage)
        self._attached_signal.poll(n, maxage)
Exemplo n.º 3
0
class ChopperDisc2(ChopperDisc2Base, ChopperDisc):
    """Chopper disc 2 device."""
    parameter_overrides = {
        'pos':
        Override(type=intrange(0, 5),
                 volatile=True,
                 settable=True,
                 fmtstr='%d',
                 unit=''),
    }
Exemplo n.º 4
0
class Sharpness(PostprocessPassiveChannel):

    parameters = {
        'thr3':
        Param('Threshold for 3x3 pixels',
              type=intrange(0, 1000),
              settable=True,
              userparam=True,
              default=25),
        'thr5':
        Param('Threshold for 5x5 pixels',
              type=intrange(0, 1000),
              settable=True,
              userparam=True,
              default=100),
        'thr7':
        Param('Threshold for 7x7 pixels',
              type=intrange(0, 1000),
              settable=True,
              userparam=True,
              default=400),
        'sig_log':
        Param('Sig log',
              type=floatrange(0, 1),
              settable=True,
              userparam=True,
              default=0.8),
    }

    def valueInfo(self):
        return Value(name=self.name, type='counter', fmtstr='%.3f'),

    def getReadResult(self, arrays, results, quality):
        arr = np.array(arrays[0], dtype=int)
        return [
            scharr_filter(
                gam_rem_adp_log(arr, self.thr3, self.thr5, self.thr7,
                                self.sig_log))
        ]
Exemplo n.º 5
0
class NOKMotorIPC(CanReference, IPCMotor):
    """Basically a IPCMotor with referencing."""

    parameters = {
        'refpos':
        Param('Reference position in phys. units',
              unit='main',
              type=none_or(float),
              mandatory=True),
    }

    parameter_overrides = {
        'zerosteps': Override(default=500000, mandatory=False),
        'unit': Override(default='mm', mandatory=False),
        'backlash': Override(type=floatrange(0.0, 0.0)),  # only 0 is allowed!
        'speed': Override(default=10),
        'accel': Override(default=10),
        'slope': Override(default=2000),
        'confbyte': Override(default=48),
        'divider': Override(type=intrange(-1, 7)),
    }

    def doInit(self, mode):
        if mode != SIMULATION:
            self._attached_bus.ping(self.addr)
            if self._hwtype == 'single':
                if self.confbyte != self.doReadConfbyte():
                    self.doWriteConfbyte(self.confbyte)
                    self.log.warning(
                        'Confbyte mismatch between setup and card'
                        ', overriding card value to 0x%02x', self.confbyte)
            # make sure that the card has the right "last steps"
            # This should not applied at REFSANS, since it disturbs the running
            # TACO server settings
            # if self.steps != self.doReadSteps():
            #     self.doWriteSteps(self.steps)
            #     self.log.warning('Resetting stepper position to last known '
            #                      'good value %d', self.steps)
            self._type = 'stepper motor, ' + self._hwtype
        else:
            self._type = 'simulated stepper'

    def doReference(self):
        bus = self._attached_bus
        bus.send(self.addr, 34)  # always go forward (positive)
        bus.send(self.addr, 47, self.speed, 3)  # reference with normal speed
        # may need to sleep a little here....
        session.delay(0.1)
        self.wait()
        self.doSetPosition(self.refpos)
Exemplo n.º 6
0
class SampleChanger(IsController, BaseSequencer):
    """The PGAA sample changer device."""

    hardware_access = False

    valuetype = intrange(1, 16)

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

    parameters = {
        'delay':
        Param('Time to wait until the push device is finished',
              type=floatrange(0, 2),
              default=2,
              settable=False,
              unit='s'),
    }

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

    def isAdevTargetAllowed(self, dev, target):
        if dev == self._attached_motor:
            if self._attached_push._attached_sensort.read(0) in ['down', 0]:
                return False, '"push" is not in top position or moving'
        elif dev == self._attached_push:
            if self._attached_motor.status(0)[0] == status.BUSY:
                return False, 'motor moving'
            if self._attached_motor.read(0) not in list(range(1, 17)):
                return False, 'invalid motor position'
        return True, ''

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

    def doRead(self, maxage=0):
        return round(self._attached_motor.read(maxage))
Exemplo n.º 7
0
def test_intrange():
    assert intrange(0, 10)(10) == 10
    assert intrange(1, 3)() == 1
    assert raises(ValueError, intrange(0, 10), 15)
    assert raises(ValueError, intrange(0, 10), 'x')
    assert raises(ValueError, intrange, 2, 1)
    assert raises(ValueError, intrange, True, False)
    assert raises(ValueError, intrange(0, 1), True)
    assert raises(ValueError, intrange(0, 1), False)
Exemplo n.º 8
0
class FileSink(DataSink):
    """Base class for sinks that save data into files."""

    parameters = {
        'subdir':           Param('Filetype specific subdirectory name',
                                  type=subdir, mandatory=False, default=''),
        'filenametemplate': Param('List of templates for data file names '
                                  '(will be hardlinked), can contain '
                                  'subdirectories',
                                  ext_desc=TEMPLATE_DESC, type=listof(str),
                                  default=['%(pointcounter)08d.dat'],
                                  settable=False, prefercache=False),
        'filemode':         Param('File access rights after closing the file, '
                                  "if set to 'none' (default) the OS defaults "
                                  'will be used',
                                  type=none_or(intrange(0o000, 0o777),)),
    }
Exemplo n.º 9
0
class BasePos(Readable):

    valuetype = int

    attached_devices = {
        'comm': Attach('Communication device', StringIO),
    }

    parameters = {
        'index':
        Param('index to get one side',
              type=intrange(1, 2),
              settable=False,
              userparam=True),
    }

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

    def doRead(self, maxage=0):
        return int(
            self._attached_comm.communicate('$0%d?*\r\n' % self.index)[1:-1])
Exemplo n.º 10
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)
Exemplo n.º 11
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
Exemplo n.º 12
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
Exemplo n.º 13
0
class HasCommunication(DeviceMixinBase):
    """
    Mixin class for devices that communicate with external devices or
    device servers.

    Provides parameters to set communication tries and delays, and basic
    services to map external exceptions to NICOS exception classes.
    """

    parameters = {
        'comtries':
        Param('Maximum retries for communication',
              type=intrange(1, 100),
              default=3,
              settable=True),
        'comdelay':
        Param('Delay between retries',
              unit='s',
              default=0.1,
              fmtstr='%.1f',
              settable=True),
    }

    @lazy_property
    def _com_lock(self):
        return threading.Lock()

    def _com_retry(self, info, function, *args, **kwds):
        """Try communicating with the hardware/device.

        Parameter "info" is passed to _com_return and _com_raise methods that
        process the return value or exception raised after maximum tries.
        """
        tries = self.comtries
        with self._com_lock:
            while True:
                tries -= 1
                try:
                    result = function(*args, **kwds)
                    return self._com_return(result, info)
                except Exception as err:
                    if tries == 0:
                        self._com_raise(err, info)
                    else:
                        name = getattr(function, '__name__', 'communication')
                        self._com_warn(tries, name, err, info)
                    session.delay(self.comdelay)

    def _com_return(self, result, info):
        """Process *result*, the return value of communication.

        Can raise an exception to initiate a retry.  Default is to return
        result unchanged.
        """
        return result

    def _com_warn(self, retries, name, err, info):
        """Gives the opportunity to warn the user on failed tries.

        Can also call _com_raise to abort early.
        """
        if retries == self.comtries - 1:
            self.log.warning('%s failed, retrying up to %d times',
                             name,
                             retries,
                             exc=1)

    def _com_raise(self, err, info):
        """Process the exception raised either by communication or _com_return.

        Should raise a NICOS exception.  Default is to raise
        CommunicationError.
        """
        raise CommunicationError(self, str(err))
Exemplo n.º 14
0
class TofChannel(PyTangoDevice, ImageChannelMixin, PassiveChannel):
    """Basic Tango Device for TofDetector."""

    STRSHAPE = ['x', 'y', 'z', 't']

    parameters = {
        'detshape':     Param('Shape of tof detector', type=dictof(str, int)),
        'timechannels': Param('Number of time channels - if set to 1 TOF mode '
                              'is disabled', type=intrange(1, 1024),
                              settable=True),
        'divisor':      Param('Width of a time channel',
                              type=int, unit='0.1us', settable=True),
        'delay':        Param('Offset delay in measure begin', type=int,
                              unit='0.1us', settable=True),
        'readchannels': Param('Tuple of (start, end) channel numbers will be '
                              'returned by a read', type=tupleof(int, int),
                              default=(0, 0), settable=True, mandatory=True),
        'readtimechan': Param('Tuple of (start, end) integrated time channels '
                              'will be returned by a read',
                              type=tupleof(int, int),
                              default=(0, 0), settable=True, mandatory=True),
    }

    def doInit(self, mode):
        self.arraydesc = ArrayDesc('data',
                                   (self.detshape.get('x', 1),
                                    self.detshape.get('t', 1)),
                                   numpy.uint32)
        if mode != SIMULATION:
            self._dev.set_timeout_millis(10000)

    def doPrepare(self):
        self._dev.Clear()
        PyTangoDevice._hw_wait(self)
        self.log.debug("Detector cleared")
        self._dev.Prepare()

    def doStart(self):
        start, end = self.readchannels
        self.readresult = [0] * (end - start + 1)
        self._dev.Start()
        self.log.debug("Detector started")

    def doFinish(self):
        self._dev.Stop()
        session.delay(0.2)
        PyTangoDevice._hw_wait(self)

    def doStop(self):
        self._dev.Stop()

    def doPause(self):
        self.doFinish()
        return True

    def doResume(self):
        self.doStart()

    def doReadTimechannels(self):
        return self._dev.timeChannels

    def doWriteTimechannels(self, value):
        self._dev.timeChannels = value
        self._pollParam('detshape')

    def doReadDivisor(self):
        return self._dev.timeInterval

    def doWriteDivisor(self, value):
        self._dev.timeInterval = value

    def doReadDelay(self):
        return self._dev.delay

    def doWriteDelay(self, value):
        self._dev.delay = value

    def doReadDetshape(self):
        shvalue = self._dev.detectorSize
        return {'x': shvalue[0], 't': shvalue[3]}

    def valueInfo(self):
        start, end = self.readchannels
        return tuple(Value("chan-%d" % i, unit="cts", errors="sqrt",
                           type="counter", fmtstr="%d")
                     for i in range(start, end + 1))

    def doReadArray(self, quality):
        self.log.debug("Tof Detector read image")
        start, end = self.readchannels
        # get current data array from detector
        array = numpy.asarray(self._dev.value, numpy.uint32)
        array = array.reshape(self.detshape['t'], self.detshape['x'])
        if self.timechannels > 1:
            startT, endT = self.readtimechan
            res = array[startT:endT+1].sum(axis=0)[start:end+1]
        else:
            res = array[0, start:end+1]
        self.readresult = res.tolist()
        return array