class DigitalValue(Readable): attached_devices = { 'iodev': Attach('IO Device', VSDIO), } parameters = { 'channel': Param('Channel for readout', type=oneof(*VSDIO._HW_DigitalChannels), settable=True, preinit=True), 'mapping': Param('Mapping of 0/1 to sensible strings', type=dictof(str, oneof(0, 1)), mandatory=True), } parameter_overrides = { 'unit': Override(mandatory=False, settable=False, default=''), } def doInit(self, mode): self._revmapping = {v: k for k, v in self.mapping.items()} def doRead(self, maxage=0): ofs, bit = self._attached_iodev._HW_DigitalChannels[self.channel] # ofs is in Bytes, we need it in words! => /2 if self._attached_iodev._readU16(ofs // 2) & (1 << bit): return self._revmapping[1] return self._revmapping[0] def doStatus(self, maxage=0): return status.OK, ''
class BeamStopAxis(Axis): """special Axis, which always has an offset of 0 """ parameter_overrides = { 'fixed': Override(type=oneof(''), default=''), 'offset': Override(type=oneof(0.0), default=0.0), 'lowlevel': Override(default=True), 'maxtries': Override(default=1000, settable=False), } def doInit(self, mode): Axis.doInit(self, mode) if self.maxtries < 1000: self._setROParam('maxtries', 1000) self._setROParam('userlimits', self.abslimits) if mode not in (SIMULATION, SLAVE ) and self._attached_motor.status()[0] != status.BUSY: self._attached_motor.doSetPosition(self._attached_coder.read()) self._attached_motor.userlimits = self._attached_motor.abslimits def doReadOffset(self): return 0. def doWriteOffset(self, value): return 0. def doReadUserlimits(self): return Axis.doReadAbslimits(self)
class ComtecCounter(CounterChannelMixin, TacoBaseChannel, PassiveChannel): taco_class = Counter parameter_overrides = { 'type': Override(type=oneof('counter'), mandatory=False, default='counter'), 'mode': Override(type=oneof('normal'), mandatory=False, default='normal'), 'fmtstr': Override(default='%d'), } def doReadMode(self): return 'normal' def doWriteMode(self, value): return 'normal' def doReadIsmaster(self): return False def doWriteIsmaster(self, value): return False def valueInfo(self): return Value(self.name, unit='cts', errors='sqrt', type='counter', fmtstr='%d'),
class VirtualCounter(VirtualChannel): """A virtual counter channel for use together with `nicos.devices.generic.detector.Detector`. """ parameters = { 'countrate': Param('The maximum countrate', type=float, default=1000., settable=False), 'gentype': Param('Type of generating function', type=oneof('const', 'gauss'), default='gauss', settable=False), 'type': Param('Type of channel: monitor or counter', type=oneof('monitor', 'counter'), mandatory=True), } parameter_overrides = { 'unit': Override(default='cts'), 'fmtstr': Override(default='%d'), } def doInit(self, mode): VirtualChannel.doInit(self, mode) self._fcurrent = 0. if self.gentype == 'const': self._generator = lambda x: self.countrate * x elif self.gentype == 'gauss': self._generator = lambda x: normal(loc=self.countrate, scale=self.countrate / 10.) * x def doStart(self): self._fcurrent = 0. VirtualChannel.doStart(self) def _counting(self): self.log.debug('counting to %d cts with %d cts/s', self.preselection, self.countrate) try: while not self._stopflag: if self.ismaster and self.curvalue >= self.preselection: self.curvalue = self.preselection break time.sleep(self._base_loop_delay) self._fcurrent += max(0, self._generator(self._base_loop_delay)) self.curvalue = int(self._fcurrent) finally: self.curstatus = (status.OK, 'idle') def doSimulate(self, preset): if self.ismaster: return [self.preselection] return [random.randint(0, self.countrate)] def valueInfo(self): return Value(self.name, unit='cts', errors='sqrt', type=self.type, fmtstr='%d'),
class CryopadPol(Moveable): """Controls the incoming or outgoing polarization direction.""" attached_devices = { 'cryopad': Attach('Underlying Cryopad device', BaseCryopad) } parameters = { 'side': Param('Which side of the instrument is this device?', type=oneof('in', 'out'), mandatory=True), } parameter_overrides = { 'unit': Override(mandatory=False, default=''), } valuetype = oneof('+x', '-x', '+y', '-y', '+z', '-z') def doRead(self, maxage=0): # NOTE: for now, we just return the latest target because it became # necessary to introduce corrections to nutator angles that cannot yet # be included reliably in the calculations, and would change the readout # here to "unknown". return self.target # cppos = self._attached_cryopad.read(maxage) # theta, chi = cppos[0:2] if self.side == 'in' else cppos[2:4] # for (pos, (goaltheta, goalchi)) in calc.DIRECTIONS.items(): # # fix chi = -179.5, goalchi = 180 situation # diffchi = abs(chi - goalchi) # chiok = diffchi < 0.5 or 359.5 < diffchi < 360.5 # # XXX: make precision configurable # if abs(theta - goaltheta) < 0.5 and chiok: # return pos # return 'unknown' def doStatus(self, maxage=0): st, text = multiStatus(self._adevs) if st == status.BUSY: return st, text if self.read(maxage) == 'unknown': return status.NOTREACHED, 'unknown polarization setting' return status.OK, 'idle' def doStart(self, pos): theta_chi = calc.DIRECTIONS[pos] cppos = self._attached_cryopad.target or (0, 0, 0, 0) if self.side == 'in': target = tuple(theta_chi) + cppos[2:4] else: target = cppos[0:2] + tuple(theta_chi) self._attached_cryopad.start(target)
class Andor3LimaCCD(GenericLimaCCD): """ This device class is an extension to the GenericLimaCCD that adds the hardware specific functionality for all Andor SDK3 based cameras. """ READOUTRATES = [280, 200, 100] # Values from sdk manual ELSHUTTERMODES = ['rolling', 'global'] # Values from sdk manual parameters = { 'readoutrate': Param('Rate of pixel readout from sensor', type=oneof(*READOUTRATES), unit='MHz', settable=True, volatile=True, category='general'), 'elshuttermode': Param('On-sensor electronic shuttering mode', type=oneof(*ELSHUTTERMODES), settable=True, volatile=True, category='general'), 'framerate': Param('Frame rate', type=float, unit='Hz', settable=False, volatile=True, category='general'), } def doInfo(self): for p in ('readoutrate', 'elshuttermode', 'framerate'): self._pollParam(p) return [] def doReadReadoutrate(self): return int(self._hwDev._dev.adc_rate[3:]) def doWriteReadoutrate(self, value): self._hwDev._dev.adc_rate = 'MHZ%i' % value def doReadElshuttermode(self): return self._hwDev._dev.electronic_shutter_mode.lower() def doWriteElshuttermode(self, value): self._hwDev._dev.electronic_shutter_mode = value.upper() def doReadFramerate(self): return self._hwDev._dev.frame_rate
def doInit(self, mode): MultiSwitcher.doInit(self, mode) if len(self._attached_moveables) != 5: raise ConfigurationError(self, 'must have exactly 5 moveables') self._mot_rot, self._mot_xv, self._mot_yv, self._mot_xh, \ self._mot_yh = self._attached_moveables self.valuetype = oneof(*sorted(self.mapping, key=num_sort))
class SdsRatemeter(JsonBase): """Read the count rates for the different input channels of the SDS.""" parameters = { 'channel': Param('Channel to be rated', type=oneof('a', 'x', 'y'), default='a', settable=False) } parameter_overrides = { 'fmtstr': Override(default='%d'), 'unit': Override(default='cps'), } def doStatus(self, maxage=0): try: res = self._read_controller([self.valuekey]) if int(res[self.valuekey]) == 0: return status.OK, '' else: return status.ERROR, 'System tripped! please clear' except CommunicationError: return status.WARN, 'Timeout during talk to the hardware.' except NicosError: return status.ERROR, 'Could not talk to hardware.' def doRead(self, maxage=0): res = self._read_controller(['mon_counts_cps_%s' % self.channel]) res = int(res.values()[0]) ret = int(res / 2.46) self.log.info('system %dfoo countrate %dcps', res, ret) return ret
def doInit(self, mode): self.valuetype = oneof(*sorted(self.mapping, key=num_sort)) if len(self._attached_slits) != len(self.slitpos): raise ConfigurationError( self, 'number of elements in slitpos ' 'parameter must match number of attached ' 'slit devices')
class AsymmetricMagnet(HasTimeout, CurrentSupply): """Class for the asymmetric ccmsans. Provides the ability to set the current field, and the asymmetry ratio. """ parameters = { 'asymmetry': Param('Asymmetry ratio', type=oneof(0.0, 0.11, 0.25, 0.39, 0.53, 0.70), settable=True, volatile=True), } parameter_overrides = { # default timeout: doTime() + 5 mins 'timeout': Override(mandatory=False, default=300), } parameter_overrides = { # max range * max ramp + 5' 'timeout': Override(mandatory=False, default=5400 + 300) } busystates = (status.BUSY, status.ERROR) valuetype = float def doReadAsymmetry(self): return float( self._taco_guard(self._dev.deviceQueryResource, 'asymmetry')) def doWriteAsymmetry(self, value): self._taco_update_resource('asymmetry', str(value))
class GeneratorDevice(AnalogOutput): """RF generator frequency and amplitude device.""" parameters = { 'shape': Param('Wave shape', type=oneof('sinusoid', 'square'), settable=True, category='general'), 'offset': Param('Offset of zero point', type=float, settable=True, category='offsets'), } def doReadShape(self): return self._taco_guard(self._dev.deviceQueryResource, 'shape') def doReadOffset(self): return float(self._taco_guard(self._dev.deviceQueryResource, 'offset')) def doWriteShape(self, val): self._taco_update_resource('shape', val) def doWriteOffset(self, val): self._taco_update_resource('offset', str(val))
class TriangleAngle(HasOffset, TriangleMaster): parameters = { 'index': Param('index of return', type=intrange(0, 1), settable=False, volatile=False, userparam=False), 'scale': Param('direction definition (-1, 1)', type=oneof(-1, 1), settable=False, mandatory=True), } parameter_overrides = { 'offset': Override(type=floatrange(-2, 2)), } def doRead(self, maxage=0): try: self.log.debug('index: %d' % self.index) res = self.offset + self.scale * self._read_controller(self.index) self.log.debug('pos: %f' % res) except IndexError: res = 0 return res
def doInit(self, mode): self.valuetype = oneof(*sorted(self.presets, key=num_sort)) self._waitdevs = [] self._aliases = {} self._devpos = {} for setting, values in self.presets.items(): values = dict(values) try: self._aliases[setting] = (values.pop('active_ap'), values.pop('active_x'), values.pop('active_y')) except KeyError: raise ConfigurationError( self, 'setting %r needs active_ap, active_x and active_y ' 'settings' % setting) from None try: for name in self._aliases[setting]: session.getDevice(name) except NicosError as exc: raise ConfigurationError( self, 'could not create/find alias targets for setting %r' % setting) from exc for key in values: if key not in self.alloweddevs: raise ConfigurationError( self, 'device %s is not allowed ' 'to be moved by sample_pos' % key) self._devpos[setting] = values
class DLSCard(BaseImageChannel): attached_devices = { 'wheels': Attach('The filter wheel positions', Readable, multiple=True, optional=True), } parameters = { 'angles': Param('Scattering angles of the detector', type=tupleof(float, float), mandatory=True, settable=True), 'mode': Param('Measure mode', type=oneof(*MODES), default='cross_cross', settable=True), } def _get_filters(self): return ' '.join('%d' % wh.read() for wh in self._attached_wheels) def setMode(self): self._dev.readoutMode = self.mode def readAbscissa(self): return self._dev.abscissa def readIntensity(self): data = self._dev.intensity return data.reshape((len(data) // 3, 3)) abscissa_arraydesc = ArrayDesc('data', shape=(264,), dtype='<f8') intensity_arraydesc = ArrayDesc('data', shape=(100, 3), dtype='<f8')
class Frequency(AnalogOutput): """Device for RF generator frequency and frequency modulation settings.""" parameters = { 'deviation': Param('FM signal deviation', type=float, settable=True), 'modulationsource': Param('Modulation source', type=oneof('internal_1', 'internal_2', 'external_1', 'noise'), settable=True), 'enablemodulation': Param('Enable frequency modulation', type=bool, settable=True), } def doReadDeviation(self): return self._dev.moddeviation def doWriteDeviation(self, value): self._dev.moddeviation = value def doReadModulationsource(self): return self._dev.modsource def doWriteModulationsource(self, value): self._dev.modsource = value def doReadEnablemodulation(self): return self._dev.modulation def doWriteEnablemodulation(self, value): self._dev.modulation = value
class Lenses(Moveable): """High-level lens control.""" valuetype = oneof(*LENS_CONFIGS) hardware_access = False attached_devices = { 'io': Attach('Lens I/O device', Moveable), } parameters = { 'values': Param('Possible values (for GUI)', internal=True, type=listof(str), default=LENS_CONFIGS), } parameter_overrides = { 'fmtstr': Override(default='%s'), 'unit': Override(mandatory=False, default=''), } def doRead(self, maxage=0): lens_read = int(self._attached_io.read(maxage)) configs = [('in' if lens_read & (1 << i) else 'out') for i in range(3)] return '-'.join(configs) def doStart(self, target): configs = [(v == 'in') for v in target.split('-')] bits = configs[0] + 2 * configs[1] + 4 * configs[2] self._attached_io.start(bits)
class BeamElement(HasTimeout, Moveable): """ Class for readout of the MIRA shutter via digital input card, and closing the shutter via digital output (tied into Pilz security system). """ valuetype = oneof('in', 'out') attached_devices = { 'valve': Attach('in/out pressure valve', Moveable), 'switch_in': Attach('limit switch for "in" position', Readable), 'switch_out': Attach('limit switch for "out" position', Readable), } parameter_overrides = { 'timeout': Override(default=10), 'unit': Override(mandatory=False, default=''), } def doStatus(self, maxage=0): is_in = self._attached_switch_in.read(maxage) is_out = self._attached_switch_out.read(maxage) valvepos = self._attached_valve.read(maxage) if (is_in and valvepos == 'in') or (is_out and valvepos == 'out'): return status.OK, 'idle' return status.BUSY, 'moving' def doRead(self, maxage=0): return self._attached_valve.read(maxage) def doStart(self, target): self._attached_valve.start(target) def doReset(self): multiReset(self._adevs)
class CounterChannelMixin(DeviceMixinBase): """Mixin for channels that return a single counts value.""" is_timer = False parameters = { 'type': Param('Type of channel: monitor or counter', type=oneof('monitor', 'counter', 'other'), mandatory=True), } parameter_overrides = { 'unit': Override(default='cts'), 'fmtstr': Override(default='%d'), 'preselection': Override(type=int), } def valueInfo(self): return Value(self.name, unit=self.unit, errors='sqrt', type=self.type, fmtstr=self.fmtstr), def doSimulate(self, preset): if self.ismaster: return [int(self.preselection)] return [0]
class Experiment(FRM2Experiment): """Special RESEDA experiment with measurement mode support.""" parameters = { 'measurementmode': Param('Measurement mode', type=oneof('nrse', 'mieze'), settable=True), }
class TASConstant(Moveable): """ Common class for TAS k, E and lambda pseudo-devices. """ parameters = { 'scanmode': Param('Scanmode to set', type=oneof(*SCANMODES), mandatory=True), } parameter_overrides = { 'unit': Override(volatile=True), } attached_devices = { 'base': Attach('Device to move (mono or ana)', Moveable), 'tas': Attach('The spectrometer for setting scanmode', TAS), } valuetype = float hardware_access = False def doStatus(self, maxage=0): return self._attached_base.status(maxage) def _getWaiters(self): return [self._attached_base] def _start(self, k): # first drive there, to determine if it is within limits tas = self._attached_tas base = self._attached_base pos = from_k(k, base.unit) base.start(pos) msg = False if tas.scanmode != self.scanmode: tas.scanmode = self.scanmode msg = True if tas.scanconstant != pos: tas.scanconstant = pos msg = True return msg def doReadUnit(self): # needed for "does volatile param have a doRead" checking raise NotImplementedError def doStop(self): self._attached_base.stop() def fix(self, reason=''): # fix the base as well, avoids surprises Moveable.fix(self, reason) return self._attached_base.fix(reason) def release(self): Moveable.release(self) return self._attached_base.release()
class AmorExperiment(SinqExperiment): """Additional experiment parameters for AMOR""" parameters = { 'mode': Param('Current mode of operation', type=oneof('horizontal', 'deflector'), settable=True, category='experiment'), }
def doIsAllowed(self, target): self.log.debug('doIsAllowed') if isinstance(target, string_types): try: oneof('horizontal', '12mrad_b3_12.000', '12mrad_b2_12.254_eng', '12mrad_b2_12.88_big', '12mrad_b3_13.268', '12mrad_b3_789', '48mrad')(target) return True, '' except ValueError as e: return False, str(e) elif isinstance(target, number_types): try: floatrange(0, 48)(target) return True, '' except ValueError as e: return False, str(e) return False, 'Wrong value type'
class FPLCTrigger(HasTimeout, Moveable): """Trigger the FPLC flow and then wait for the sample to be ready inside the cell. Used as a sample environment device in kwscount(). """ valuetype = oneof('triggered', 'waiting') hardware_access = True attached_devices = { 'output': Attach('start output to FPLC', Moveable), 'input': Attach('trigger input from FPLC', Readable), } parameters = { 'started': Param('Time when device was started', internal=True, settable=True), 'triggered': Param('Time when input was triggered after a start', internal=True, settable=True), } parameter_overrides = { 'fmtstr': Override(default='%s'), 'timeout': Override(default=120), 'unit': Override(mandatory=False, default=''), } def doInit(self, mode): if mode == MASTER: self.triggered = self.started = 0 def doStart(self, target): if target == 'triggered': self._attached_output.start(1) sleep(0.1) self._attached_output.start(0) self.started = currenttime() def doStatus(self, maxage=0): if self.started: if self.mode == MASTER and self._attached_input.read(maxage): self.started = 0 self.triggered = currenttime() return status.OK, 'triggered' else: return status.BUSY, 'waiting' elif self.triggered: if self.mode == MASTER and currenttime() > self.triggered + 5: self.triggered = 0 return status.OK, 'triggered' return status.OK, '' def doRead(self, maxage=0): if self.started: return 'waiting' return 'triggered'
class AnalogValue(Readable): attached_devices = { 'iodev': Attach('IO Device', VSDIO), } parameters = { 'channel': Param('Channel for readout', type=oneof(*VSDIO._HW_AnalogChannels), settable=True, preinit=True), } parameter_overrides = { 'unit': Override(mandatory=False, volatile=True, settable=False), } def doReadUnit(self): _ofs, _scale, unit = \ self._attached_iodev._HW_AnalogChannels[self.channel] if unit == 'mA-foo': unit = 'mA' elif unit == 'V-foo': unit = 'V' return unit def doRead(self, maxage=0): ofs, scale, _unit = \ self._attached_iodev._HW_AnalogChannels[self.channel] # ofs is in Bytes, we need it in words! => /2 if _unit == 'mA-foo': raw = scale * self._attached_iodev._readU16(ofs // 2) self.log.debug('mA-foo %.2f', raw) # Work around bug in firmware if raw > 20.0: raw -= 615.37 self.log.debug('mA-foo %.2f', raw) # Tested against Multimeter (2018-08-07) raw /= 2.0 self.log.debug('mA-foo %.2f', raw) elif _unit == 'V-foo': raw = self._attached_iodev._readU16(ofs // 2) self.log.debug('V-foo %d', raw) # Work around bug in firmware if raw > 0x8000: raw -= 63536 self.log.debug('V-foo %d sign1', raw) self.log.debug('V-foo %d sign', raw) # Tested against Multimeter (2018-08-07) raw /= 2.0 self.log.debug('v-foo %.2f /2.0', raw) raw *= scale self.log.debug('v-foo %.2f scale', raw) else: raw = scale * self._attached_iodev._readU16(ofs // 2) return raw def doStatus(self, maxage=0): return status.OK, ''
class ImagingExperiment(Experiment, BaseImagingExperiment): """FRM II specific imaging experiment which provides all imaging experiment functionalities plus all the FRM II specific features. """ parameters = { 'curimgtype': Param('Type of current/next image', type=oneof('dark', 'openbeam', 'standard'), mandatory=False, default='standard', settable=True), } parameter_overrides = { 'dataroot': Override(default='/data/FRM-II'), } @property def elogpath(self): """path to the eLogbook of the current experiment/sample""" return path.join(self.proposalpath, 'logbook') @property def extrapaths(self): paths = set(Experiment.extrapaths.fget(self)) paths.update(BaseImagingExperiment.extrapaths.fget(self)) if self.sampledir: paths.add(path.join(self.samplepath, 'eval', 'recon')) return tuple(paths) @property def customproposalsymlink(self): if self.proptype == 'service': return None # construct user name user = re.split('[,(<@]', self.users)[0].strip() user = user if user else 'Unknown User' date = time.strftime('%F').replace('-', '_') return path.join( self.proposalpath, '..', safeName('%s-%s-%s-%s' % (date, user, self.proposal, self.title))) def newSample(self, parameters): name = parameters['name'] self.sampledir = safeName(name) Experiment.newSample(self, parameters) self.log.debug('new sample path: %s', self.samplepath) self.log.debug('new data path: %s', self.datapath) self.log.debug('new dark image path: %s', self.darkimagedir) self.log.debug('new open beam image path: %s', self.openbeamdir) self.log.debug('new measurement image path: %s', self.photodir)
class Polarizer(HasTimeout, Moveable): """Controls both the position of the polarizer and the spin flipper. """ valuetype = oneof(*POL_SETTINGS) hardware_access = True attached_devices = { 'output': Attach('output setter', Moveable), 'input_in': Attach('input for limit switch "in" position', Readable), 'input_out': Attach('input for limit switch "out" position', Readable), 'flipper': Attach('3He flipper', Moveable), } parameter_overrides = { 'fmtstr': Override(default='%s'), 'timeout': Override(default=10), 'unit': Override(mandatory=False, default=''), } parameters = { 'values': Param('Possible values (for GUI)', internal=True, type=listof(str), default=POL_SETTINGS), } def doStatus(self, maxage=0): is_in = self._attached_input_in.read(maxage) is_out = self._attached_input_out.read(maxage) # check individual bits if is_in ^ is_out != 3: # inconsistent state, check switches if ((is_in & 2) and (is_out & 2)) or \ ((is_in & 1) and (is_out & 1)): # both switches on? return status.ERROR, 'both switches on for element(s)' return status.BUSY, 'elements moving' # HasTimeout will check for target reached return self._attached_flipper.status(maxage) def doRead(self, maxage=0): is_in = self._attached_input_in.read(maxage) if is_in == 3: return self._attached_flipper.read() elif is_in > 0: return 'inconsistent' return 'out' def doStart(self, target): if target == 'out': self._attached_output.start(0) else: self._attached_output.start(3) self._attached_flipper.start(target)
class Polarizer(Moveable): """Controls both the position of the polarizer and the spin flipper. """ valuetype = oneof(*POL_SETTINGS) hardware_access = False attached_devices = { 'switcher': Attach('polarizer in/out switch', Moveable), 'flipper': Attach('flipper', Moveable), } parameters = { 'values': Param('Possible values (for GUI)', internal=True, type=listof(str), default=POL_SETTINGS), 'switchervalues': Param('Possible values for the switcher (out, in)', type=tupleof(str, str), default=('ng', 'pol')), } parameter_overrides = { 'fmtstr': Override(default='%s'), 'unit': Override(mandatory=False, default=''), } def doRead(self, maxage=0): switcher_pos = self._attached_switcher.read(maxage) flipper_pos = self._attached_flipper.read(maxage) if switcher_pos == 'unknown' or flipper_pos == 'unknown': return 'unknown' if switcher_pos == self.switchervalues[0]: return 'out' # Polarizer is a transmission supermirror => without flipper we get # the "down" polarization. if flipper_pos == 'on': return 'up' return 'down' def doStart(self, target): switch_pos = self._attached_switcher.read(0) if target == 'out': if switch_pos != self.switchervalues[0]: self._attached_switcher.start(self.switchervalues[0]) self._attached_flipper.start('off') else: if switch_pos != self.switchervalues[1]: self._attached_switcher.start(self.switchervalues[1]) if target == 'up': self._attached_flipper.start('on') elif target == 'down': self._attached_flipper.start('off')
def doInit(self, mode): if not self._attached_moveable.isAllowed(self.onvalue)[0]: raise ConfigurationError( self, "'onvalue' is not allowed for the " "'%s' device" % self._attached_moveable) if not self._attached_moveable.isAllowed(self.offvalue)[0]: raise ConfigurationError( self, "'offvalue' is not allowed for the " "'%s' device" % self._attached_moveable) self.valuetype = oneof(self.offvalue, self.onvalue)
class CPTReadout(HasOffset, JsonBase): parameters = { 'phasesign': Param('Phase sign', type=oneof('unsigned', 'signed'), settable=False, default='unsigned'), 'channel': Param( 'Index of value', type=intrange(-1, 99), ), } def _read_ctrl(self, channel): data = self._read_controller([self.valuekey, 'start_act']) self.log.debug('res: %r', data) self.log.debug('channel %d', channel) if channel == 0: self.log.debug('calc speed') res = 3e9 / data['start_act'] # speed res -= self.offset # should be Zero elif channel == -1: self.log.debug('calc phase in respect to Disk 1 of Disc 1') self.log.debug('offset %.2f', self.offset) res = -360.0 * data[self.valuekey][0] / data['start_act'] res -= self.offset res = self._kreis(res) else: self.log.debug('calc phase in respect to Disk 1') self.log.debug('offset %.2f', self.offset) res = -360.0 * data[self.valuekey][channel] / data['start_act'] res -= self.offset res = self._kreis(res) return res def _kreis(self, phase, kreis=360.0): line = 'kreis phase %.2f' % phase if self.phasesign == 'signed': while phase > kreis / 2: phase -= kreis while phase < -kreis / 2: phase += kreis else: phase = -phase while phase > kreis: phase -= kreis while phase < 0: phase += kreis self.log.debug('%s %.2f', line, phase) return phase def doRead(self, maxage=0): return self._read_ctrl(self.channel)
class Shs(PyTangoDevice, Readable): """ Basic IO Device object for devices in refsans' contains common things for all devices. """ _buffer_old = None hardware_access = True parameters = { 'address': Param('Starting offset (words) of IO area', # type=intrange(0x3000, 0x47ff), type=oneof(1026), mandatory=False, settable=False, userparam=False, default=1026), 'banks': Param('Banks to be read', type=listof(intrange(0, 0xffff)), settable=False, userparam=False, default=[0x300, 0x400]) } def doInit(self, mode): # switch off watchdog, important before doing any write access # if mode != SIMULATION: # self._taco_guard(self._dev.writeSingleRegister, (0, 0x1120, 0)) pass def _readBuffer(self): buf = () for bank in self.banks: Notausgang = 1 while True: self.log.debug('bank: 0x%04X', bank) for _ in range(2): session.delay(0.1) self._dev.WriteOutputWords((self.address, bank)) bu = tuple(self._dev.ReadOutputWords((0, 10))) if bu[2] == bank: self.log.debug('Bank ok %d == %d', bu[2], bank) buf += bu break self.log.debug('Data from wrong bank %d != %d', bu[2], bank) Notausgang += 1 if Notausgang > 6: self.log.info('NOTAUSGANG<') # raise error ??? break session.delay(0.5 * Notausgang) self.log.debug('buffer: %s', buf) self._buffer_old = buf return buf def doRead(self, maxage=0): return self._readBuffer() def doStatus(self, maxage=0): return status.OK, 'DEBUG'