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)
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)
class ChopperDisc2(ChopperDisc2Base, ChopperDisc): """Chopper disc 2 device.""" parameter_overrides = { 'pos': Override(type=intrange(0, 5), volatile=True, settable=True, fmtstr='%d', unit=''), }
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)) ]
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)
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))
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)
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),)), }
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])
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)
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
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
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))
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