migrated secop_psi drivers to new syntax
- includes all changes up to 'fix inheritance order' from git_mlz
6a32ecf342
Change-Id: Ie3ceee3dbd0a9284b47b1d5b5dbe262eebe8f283
This commit is contained in:
@ -20,65 +20,53 @@
|
||||
# *****************************************************************************
|
||||
"""WAVE FUNCTION LECROY XX: SIGNAL GENERATOR"""
|
||||
|
||||
from secop.core import Readable, Parameter, Override, Command, FloatRange, TupleOf, \
|
||||
HasIodev, StringIO, Done, Attached, IntRange, BoolType, EnumType, StringType, Module, \
|
||||
Property
|
||||
from secop.core import Readable, Parameter, FloatRange, \
|
||||
HasIodev, IntRange, BoolType, EnumType, Module, Property
|
||||
|
||||
|
||||
class Channel(Module):
|
||||
properties = {
|
||||
'channel':Property('choose channel to manipulate',IntRange(1,2)),
|
||||
}
|
||||
parameters = {
|
||||
'freq':
|
||||
Parameter('frequency', FloatRange(1e-6,20e6,unit='Hz'),
|
||||
poll=True, initwrite=True, default=1000),
|
||||
'amp':
|
||||
Parameter('exc_volt_int', FloatRange(0.00,5,unit='Vrms'),
|
||||
poll=True, readonly=False, initwrite=True, default=0.1),
|
||||
'offset':
|
||||
Parameter('offset_volt_int', FloatRange(0.00,10,unit='V'),
|
||||
poll = True, readonly = False, initwrite = True, default = 0.0),
|
||||
'wave':
|
||||
Parameter ('type of wavefunction',
|
||||
EnumType('WaveFunction', SINE=1, SQUARE=2, RAMP=3, PULSE=4, NOISE=5, ARB=6, DC=7),
|
||||
poll=True, readonly=False, default='SINE'),
|
||||
'phase':
|
||||
Parameter('signal phase', FloatRange(0,360,unit='deg'),
|
||||
poll=True, readonly=False, initwrite=True, default=0),
|
||||
'enabled':
|
||||
Parameter('enable output channel', datatype=EnumType('OnOff', OFF=0, ON=1),
|
||||
readonly=False, default='OFF'),
|
||||
'symm':
|
||||
Parameter('wavefunction symmetry', FloatRange(0,100, unit=''),
|
||||
poll=True, readonly =False, default=0),
|
||||
}
|
||||
class Channel(HasIodev, Module):
|
||||
channel = Property('choose channel to manipulate', IntRange(1, 2))
|
||||
|
||||
freq = Parameter('frequency', FloatRange(1e-6, 20e6, unit='Hz'),
|
||||
poll=True, initwrite=True, default=1000)
|
||||
amp = Parameter('exc_volt_int', FloatRange(0.00, 5, unit='Vrms'),
|
||||
poll=True, readonly=False, initwrite=True, default=0.1)
|
||||
offset = Parameter('offset_volt_int', FloatRange(0.00, 10, unit='V'),
|
||||
poll=True, readonly=False, initwrite=True, default=0.0)
|
||||
wave = Parameter('type of wavefunction',
|
||||
EnumType('WaveFunction', SINE=1, SQUARE=2, RAMP=3, PULSE=4, NOISE=5, ARB=6, DC=7),
|
||||
poll=True, readonly=False, default='SINE'),
|
||||
phase = Parameter('signal phase', FloatRange(0, 360, unit='deg'),
|
||||
poll=True, readonly=False, initwrite=True, default=0)
|
||||
enabled = Parameter('enable output channel', datatype=EnumType('OnOff', OFF=0, ON=1),
|
||||
readonly=False, default='OFF')
|
||||
symm = Parameter('wavefunction symmetry', FloatRange(0, 100, unit=''),
|
||||
poll=True, readonly=False, default=0)
|
||||
|
||||
def read_value(self):
|
||||
return self.sendRecv('C%d:BSWV FRQ?' % self.channel)
|
||||
|
||||
|
||||
def write_target(self,value):
|
||||
def write_target(self, value):
|
||||
self.sendRecv('C%d:BSWV FRQ, %g' % (self.channel, str(value)+'Hz'))
|
||||
return value
|
||||
|
||||
#signal wavefunction parameter
|
||||
|
||||
# signal wavefunction parameter
|
||||
def read_wave(self):
|
||||
return self.sendRecv('C%d:BSWV WVTP?' % self.channel)
|
||||
|
||||
def write_wave(self,value): #string value
|
||||
def write_wave(self, value): # string value
|
||||
self.sendRecv('C%d:BSWV WVTP, %s' % (self.channel, value.name))
|
||||
return value
|
||||
|
||||
#signal amplitude parameter
|
||||
|
||||
# signal amplitude parameter
|
||||
def read_amp(self):
|
||||
return self.sendRecv('C%d:BSWV AMP?' % self.channel)
|
||||
|
||||
def write_amp(self,value):
|
||||
def write_amp(self, value):
|
||||
self.sendRecv('C%d:BSWV AMP, %g' % (self.channel, value))
|
||||
return value
|
||||
|
||||
#offset value parameter
|
||||
# offset value parameter
|
||||
def read_offset(self):
|
||||
return self.sendRecv('C%d:BSWV OFST?' % self.channel)
|
||||
|
||||
@ -86,44 +74,41 @@ class Channel(Module):
|
||||
self.sendRecv('C%d:BSWV OFST %g' % (self.channel, value))
|
||||
return value
|
||||
|
||||
|
||||
# channel symmetry
|
||||
# channel symmetry
|
||||
def read_symm(self):
|
||||
return self.sendRecv('C%d:BSWV SYM?' % self.channel)
|
||||
|
||||
def write_symm(self, value):
|
||||
self.comm('C%d:BSWV SYM %g' % (self.channel, value))
|
||||
self.sendRecv('C%d:BSWV SYM %g' % (self.channel, value))
|
||||
return value
|
||||
|
||||
# wave phase parameter
|
||||
# wave phase parameter
|
||||
def read_phase(self):
|
||||
return self.sendRecv('C%d:BSWV PHSE?' % self.channel)
|
||||
|
||||
def write_phase(self, value):
|
||||
self.sendRecv('C%d:BSWV PHSE %g' % (self.channel, str(value)))
|
||||
|
||||
|
||||
return value
|
||||
|
||||
|
||||
# dis/enable output channel
|
||||
|
||||
# dis/enable output channel
|
||||
def read_enabled(self):
|
||||
return self.sendRecv('C%d: OUTP?' % self.channel)
|
||||
|
||||
|
||||
def write_enabled(self, value):
|
||||
self.sendRecv('C%d: OUTP %s' % (self.channel, value.name))
|
||||
return value
|
||||
|
||||
|
||||
# devices are defined as arg less output enable what is defined as arg2
|
||||
|
||||
# devices are defined as arg less output enable what is defined as arg2
|
||||
|
||||
class arg(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='')),
|
||||
}
|
||||
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit=''))
|
||||
|
||||
|
||||
class arg2(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=BoolType(unit='')),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=BoolType())
|
||||
|
@ -20,262 +20,29 @@
|
||||
# *****************************************************************************
|
||||
"""SIGNAL RECOVERY SR7270: lOCKIN AMPLIFIER FOR AC SUSCEPTIBILITY"""
|
||||
|
||||
from secop.core import Readable, Parameter, Override, Command, FloatRange, TupleOf, \
|
||||
HasIodev, StringIO, Done, Attached, IntRange, BoolType, EnumType
|
||||
from secop.core import FloatRange, HasIodev, \
|
||||
Parameter, Readable, StringIO, TupleOf
|
||||
|
||||
|
||||
class SR7270(StringIO):
|
||||
end_of_line = b'\x00'
|
||||
|
||||
def do_communicate(self, command): #remove dash from terminator
|
||||
reply = StringIO.do_communicate(self, command)
|
||||
status = self._conn.readbytes(2, 0.1) # get the 2 status bytes
|
||||
# print('comm=',command,'reply=',reply,'status=',status)
|
||||
return reply + ';%d;%d' % tuple(status)
|
||||
|
||||
# end_of_line = '\x00' #termination line from maanual page 6.8
|
||||
end_of_line = '\n'
|
||||
|
||||
|
||||
class XY(HasIodev, Readable):
|
||||
value = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V')))
|
||||
freq = Parameter('exc_freq_int', FloatRange(0.001,250e3,unit='Hz'), readonly=False, default=100)
|
||||
|
||||
|
||||
class XY(HasIodev, Readable):
|
||||
properties = {
|
||||
'x': Attached(),
|
||||
'y': Attached(),
|
||||
'freq_arg': Attached(),
|
||||
'amp_arg': Attached(),
|
||||
'tc_arg': Attached(),
|
||||
'phase_arg': Attached(),
|
||||
'dac_arg': Attached(),
|
||||
}#parameters required an initial value but initwrite write the default value for polled parameters
|
||||
parameters = {
|
||||
'value': Override('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V'))),
|
||||
'freq': Parameter('exc_freq_int',
|
||||
FloatRange(0.001,250e3,unit='Hz'),
|
||||
poll=True, readonly=False, initwrite=True, default=1000),
|
||||
'amp': Parameter('exc_volt_int',
|
||||
FloatRange(0.00,5,unit='Vrms'),
|
||||
poll=True, readonly=False, initwrite=True, default=0.1),
|
||||
'range': Parameter('sensitivity value', FloatRange(0.00,1,unit='V'), poll=True, default=1),
|
||||
'irange': Parameter('sensitivity index', IntRange(0,27), poll=True, readonly=False, default=25),
|
||||
'autorange': Parameter('autorange_on', EnumType('autorange', off=0, soft=1, hard=2), readonly=False, default=0, initwrite=True),
|
||||
'tc': Parameter('time constant value', FloatRange(10e-6,100,unit='s'), poll=True, default=0.1),
|
||||
'itc': Parameter('time constant index', IntRange(0,30), poll=True, readonly=False, initwrite=True, default=14),
|
||||
'nm': Parameter ('noise mode',BoolType(), readonly=False, default=0),
|
||||
'phase': Parameter('Reference phase control', FloatRange(-360,360,unit='deg'), poll=True, readonly=False, initwrite=True, default=0),
|
||||
'vmode' : Parameter('Voltage input configuration', IntRange(0,3), readonly=False, default=3),
|
||||
# 'dac': Parameter ('output DAC channel value', datatype=TupleOf(IntRange(1,4), FloatRange(0.00,5000,unit='mV')), poll=True, readonly=False, initwrite=True, default=(3,0)),
|
||||
'dac': Parameter ('output DAC channel value', FloatRange(-10000,10000,unit='mV'), poll=True, readonly=False, initwrite=True, default=0),
|
||||
}
|
||||
commands = {
|
||||
'aphase': Command('auto phase'),
|
||||
}
|
||||
iodevClass = SR7270
|
||||
|
||||
|
||||
def comm(self, command):
|
||||
reply, status, overload = self.sendRecv(command).split(';')
|
||||
if overload != '0':
|
||||
self.status = self.Status.WARN, 'overload %s' % overload
|
||||
else:
|
||||
self.status = self.Status.IDLE, ''
|
||||
return reply
|
||||
|
||||
def read_value(self):
|
||||
reply = self.comm('XY.').split(',')
|
||||
x = float(reply[0])
|
||||
y = float(reply[1])
|
||||
if self.autorange == 1: # soft
|
||||
if max(abs(x), abs(y)) >= 0.9*self.range and self.irange < 27:
|
||||
self.write_irange(self.irange+1)
|
||||
elif max(abs(x), abs(y)) <= 0.3*self.range and self.irange > 1:
|
||||
self.write_irange(self.irange-1)
|
||||
self._x.value = x # to update X,Y classes which will be the collected data.
|
||||
self._y.value = y
|
||||
# print(x,y)
|
||||
self._freq_arg.value = self.freq
|
||||
self._amp_arg.value = self.amp
|
||||
self._tc_arg.value = self.tc
|
||||
self._phase_arg.value = self.phase
|
||||
self._dac_arg.value = self.dac
|
||||
return x,y
|
||||
reply = self.sendRecv('XY.').split('\x00')[-1]
|
||||
return reply.split(',')
|
||||
|
||||
def read_freq(self):
|
||||
reply = self.comm('OF.')
|
||||
reply = self.sendRecv('OF.').split('\x00')[-1]
|
||||
return reply
|
||||
|
||||
def write_freq(self,value):
|
||||
self.comm('OF. %g' % value)
|
||||
|
||||
self.sendRecv('OF. %g' % value)
|
||||
return value
|
||||
|
||||
def write_autorange(self, value):
|
||||
if value == 2: # hard
|
||||
self.comm('AS') # put hardware autorange on
|
||||
self.comm('AUTOMATIC. 1')
|
||||
else:
|
||||
self.comm('AUTOMATIC. 0')
|
||||
return value
|
||||
|
||||
def read_autorange(self):
|
||||
reply=self.comm('AUTOMATIC')
|
||||
# determine hardware autorange
|
||||
if reply == 1: #"hardware auto range is on":
|
||||
return 2 # hard
|
||||
if self.autorange == 0: # soft
|
||||
return self.autorange() #read autorange
|
||||
return reply # off
|
||||
|
||||
#oscillator amplitude module
|
||||
def read_amp(self):
|
||||
reply = self.comm('OA.')
|
||||
return reply
|
||||
|
||||
def write_amp(self,value):
|
||||
self.comm('OA. %g' % value)
|
||||
|
||||
return value
|
||||
|
||||
#external output DAC
|
||||
def read_dac(self):
|
||||
# reply = self.comm('DAC %g' % channel) # failed to add the DAC channel you want to control
|
||||
reply = self.comm('DAC 3') #stack to channel 3
|
||||
return reply
|
||||
|
||||
def write_dac(self,value):
|
||||
#self.comm('DAC %g %g' % channel % value)
|
||||
self.comm('DAC 3 %g' % value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
#sensitivity module
|
||||
def read_range(self):
|
||||
reply = self.comm('SEN.')
|
||||
|
||||
return reply
|
||||
|
||||
|
||||
def write_irange(self,value):
|
||||
self.comm('SEN %g' % value)
|
||||
self.read_range()
|
||||
return value
|
||||
|
||||
def read_irange(self):
|
||||
reply = self.comm('SEN')
|
||||
|
||||
return reply
|
||||
|
||||
#time constant module/ noisemode off or 0 allows to use all the time constant range
|
||||
def read_nm(self):
|
||||
reply = self.comm('NOISEMODE')
|
||||
return reply
|
||||
|
||||
def write_nm(self,value):
|
||||
self.comm('NOISEMODE %d' % int(value))
|
||||
self.read_nm()
|
||||
return value
|
||||
|
||||
|
||||
def read_tc(self):
|
||||
reply = self.comm('TC.')
|
||||
|
||||
return reply
|
||||
|
||||
|
||||
def write_itc(self,value):
|
||||
self.comm('TC %g' % value)
|
||||
self.read_tc()
|
||||
return value
|
||||
|
||||
def read_itc(self):
|
||||
reply = self.comm('TC')
|
||||
|
||||
return reply
|
||||
|
||||
#phase and autophase
|
||||
|
||||
|
||||
def read_phase(self):
|
||||
reply = self.comm('REFP.')
|
||||
|
||||
return reply
|
||||
|
||||
def write_phase(self,value):
|
||||
self.comm('REFP %d' % round(1000*value,0))
|
||||
self.read_phase()
|
||||
return value
|
||||
|
||||
|
||||
def do_aphase(self):
|
||||
self.read_phase()
|
||||
reply = self.comm('AQN')
|
||||
self.read_phase()
|
||||
|
||||
#voltage input configuration 0:grounded,1=A,2=B,3=A-B
|
||||
# def read_vmode(self):
|
||||
# reply = self.comm('VMODE')
|
||||
# return reply
|
||||
|
||||
def write_vmode(self,value):
|
||||
self.comm('VMODE %d' % value)
|
||||
# self.read_vmode()
|
||||
return value
|
||||
|
||||
|
||||
class Comp(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='V')),
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class arg(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='')),
|
||||
}
|
||||
|
||||
# parameters = {
|
||||
# 'valueX': Override('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V'))),
|
||||
#}
|
||||
#iodevClass = SR7270
|
||||
# def read_valueX(self):
|
||||
# reply = self.sendRecv('XY.')
|
||||
# return reply.split(',')[0]
|
||||
# def read_valueY(self):
|
||||
# reply = self.sendRecv('XY.')
|
||||
# return reply.split(',')[1]
|
||||
|
||||
|
||||
#class aphase(self):
|
||||
# reply = self.sendRecv('ASM')
|
||||
# return reply
|
||||
|
||||
# def asens(self):
|
||||
# reply = self.sendRecv('AS')
|
||||
# return reply
|
||||
|
||||
# def write_Fstart(self,value):
|
||||
# self.sendRecv('FSTART. %g' % value)
|
||||
# return value
|
||||
|
||||
# def write_Fstop(self,value):
|
||||
# self.sendRecv('FSTOP. %g' % value)
|
||||
# return value
|
||||
|
||||
# def write_Fstep(self,value):
|
||||
# self.sendRecv('FSTEP. %g' % value)
|
||||
# return value
|
||||
|
||||
# def write_Astart(self,value):
|
||||
# self.sendRecv('ASTART. %g' % value')
|
||||
# return value
|
||||
|
||||
# def write_Astop(self,value):
|
||||
# self.sendRecv('ASTOP. %g' % value)
|
||||
# return value
|
||||
|
||||
# def write_Astep(self,value):
|
||||
# self.sendRecv('ASTEP. %g' % value)
|
||||
# return value
|
||||
|
@ -20,7 +20,7 @@
|
||||
# *****************************************************************************
|
||||
"""Andeen Hagerling capacitance bridge"""
|
||||
|
||||
from secop.core import Readable, Parameter, Override, FloatRange, HasIodev, StringIO, Done
|
||||
from secop.core import Done, FloatRange, HasIodev, Parameter, Readable, StringIO
|
||||
|
||||
|
||||
class Ah2700IO(StringIO):
|
||||
@ -29,12 +29,12 @@ class Ah2700IO(StringIO):
|
||||
|
||||
|
||||
class Capacitance(HasIodev, Readable):
|
||||
parameters = {
|
||||
'value': Override('capacitance', FloatRange(unit='pF'), poll=True),
|
||||
'freq': Parameter('frequency', FloatRange(unit='Hz'), readonly=False, default=0),
|
||||
'voltage': Parameter('voltage', FloatRange(unit='V'), readonly=False, default=0),
|
||||
'loss': Parameter('loss', FloatRange(unit='deg'), default=0),
|
||||
}
|
||||
|
||||
value = Parameter('capacitance', FloatRange(unit='pF'), poll=True)
|
||||
freq = Parameter('frequency', FloatRange(unit='Hz'), readonly=False, default=0)
|
||||
voltage = Parameter('voltage', FloatRange(unit='V'), readonly=False, default=0)
|
||||
loss = Parameter('loss', FloatRange(unit='deg'), default=0)
|
||||
|
||||
iodevClass = Ah2700IO
|
||||
|
||||
def parse_reply(self, reply):
|
||||
|
@ -20,7 +20,7 @@
|
||||
# *****************************************************************************
|
||||
"""Delay generator stanford 645"""
|
||||
|
||||
from secop.core import Module, Parameter, Override, FloatRange, HasIodev, StringIO, Done
|
||||
from secop.core import FloatRange, HasIodev, Module, Parameter, StringIO
|
||||
|
||||
|
||||
class DG645(StringIO):
|
||||
@ -28,12 +28,12 @@ class DG645(StringIO):
|
||||
|
||||
|
||||
class Delay(HasIodev, Module):
|
||||
parameters = {
|
||||
'on1': Parameter('on delay 1', FloatRange(unit='sec'), readonly=False, default=0),
|
||||
'off1': Parameter('off delay 1', FloatRange(unit='sec'), readonly=False, default=60e-9),
|
||||
'on2': Parameter('on delay 2', FloatRange(unit='sec'), readonly=False, default=0),
|
||||
'off2': Parameter('off delay 2', FloatRange(unit='sec'), readonly=False, default=150e-9),
|
||||
}
|
||||
|
||||
on1 = Parameter('on delay 1', FloatRange(unit='sec'), readonly=False, default=0)
|
||||
off1 = Parameter('off delay 1', FloatRange(unit='sec'), readonly=False, default=60e-9)
|
||||
on2 = Parameter('on delay 2', FloatRange(unit='sec'), readonly=False, default=0)
|
||||
off2 = Parameter('off delay 2', FloatRange(unit='sec'), readonly=False, default=150e-9)
|
||||
|
||||
iodevClass = DG645
|
||||
|
||||
def read_on1(self):
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
not tested yet"""
|
||||
|
||||
from secop.core import Writable, Module, Parameter, Override, Attached,\
|
||||
BoolType, FloatRange, EnumType, HasIodev, StringIO
|
||||
from secop.core import Attached, BoolType, EnumType, FloatRange, \
|
||||
HasIodev, Module, Parameter, StringIO, Writable
|
||||
|
||||
|
||||
class K2601bIO(StringIO):
|
||||
@ -42,13 +42,13 @@ SOURCECMDS = {
|
||||
|
||||
|
||||
class SourceMeter(HasIodev, Module):
|
||||
parameters = {
|
||||
'resistivity': Parameter('readback resistivity', FloatRange(unit='Ohm'), poll=True),
|
||||
'power': Parameter('readback power', FloatRange(unit='W'), poll=True),
|
||||
'mode': Parameter('measurement mode', EnumType(off=0, current=1, voltage=2),
|
||||
readonly=False, default=0),
|
||||
'active': Parameter('output enable', BoolType(), readonly=False, poll=True),
|
||||
}
|
||||
|
||||
resistivity = Parameter('readback resistivity', FloatRange(unit='Ohm'), poll=True)
|
||||
power = Parameter('readback power', FloatRange(unit='W'), poll=True)
|
||||
mode = Parameter('measurement mode', EnumType(off=0, current=1, voltage=2),
|
||||
readonly=False, default=0)
|
||||
active = Parameter('output enable', BoolType(), readonly=False, poll=True)
|
||||
|
||||
iodevClass = K2601bIO
|
||||
|
||||
def read_resistivity(self):
|
||||
@ -74,15 +74,12 @@ class SourceMeter(HasIodev, Module):
|
||||
|
||||
|
||||
class Current(HasIodev, Writable):
|
||||
properties = {
|
||||
'sourcemeter': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'value': Override('measured current', FloatRange(unit='A'), poll=True),
|
||||
'target': Override('set current', FloatRange(unit='A'), poll=True),
|
||||
'active': Parameter('current is controlled', BoolType(), default=False), # polled from Current/Voltage
|
||||
'limit': Parameter('current limit', FloatRange(0, 2.0, unit='A'), default=2, poll=True),
|
||||
}
|
||||
sourcemeter = Attached()
|
||||
|
||||
value = Parameter('measured current', FloatRange(unit='A'), poll=True)
|
||||
target = Parameter('set current', FloatRange(unit='A'), poll=True)
|
||||
active = Parameter('current is controlled', BoolType(), default=False) # polled from Current/Voltage
|
||||
limit = Parameter('current limit', FloatRange(0, 2.0, unit='A'), default=2, poll=True)
|
||||
|
||||
def read_value(self):
|
||||
return self.sendRecv('print(smua.measure.i())')
|
||||
@ -120,15 +117,12 @@ class Current(HasIodev, Writable):
|
||||
|
||||
|
||||
class Voltage(HasIodev, Writable):
|
||||
properties = {
|
||||
'sourcemeter': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'value': Override('measured voltage', FloatRange(unit='V'), poll=True),
|
||||
'target': Override('set voltage', FloatRange(unit='V'), poll=True),
|
||||
'active': Parameter('voltage is controlled', BoolType(), poll=True),
|
||||
'limit': Parameter('current limit', FloatRange(0, 2.0, unit='V'), default=2, poll=True),
|
||||
}
|
||||
sourcemeter = Attached()
|
||||
|
||||
value = Parameter('measured voltage', FloatRange(unit='V'), poll=True)
|
||||
target = Parameter('set voltage', FloatRange(unit='V'), poll=True)
|
||||
active = Parameter('voltage is controlled', BoolType(), poll=True)
|
||||
limit = Parameter('current limit', FloatRange(0, 2.0, unit='V'), default=2, poll=True)
|
||||
|
||||
def read_value(self):
|
||||
return self.sendRecv('print(smua.measure.v())')
|
||||
@ -159,7 +153,7 @@ class Voltage(HasIodev, Writable):
|
||||
def write_active(self, value):
|
||||
if self._sourcemeter.mode != 2:
|
||||
if value:
|
||||
self._sourcemeter.write_mode(2) # switch to voltage
|
||||
self._sourcemeter.write_mode(2) # switch to voltage
|
||||
else:
|
||||
return 0
|
||||
return self._sourcemeter.write_active(value)
|
||||
|
@ -22,13 +22,13 @@
|
||||
|
||||
import time
|
||||
|
||||
from secop.modules import Readable, Drivable, Parameter, Override, Property, Attached
|
||||
from secop.metaclass import Done
|
||||
from secop.datatypes import FloatRange, IntRange, EnumType, BoolType
|
||||
from secop.stringio import HasIodev
|
||||
from secop.poller import Poller, REGULAR
|
||||
from secop.lib import formatStatusBits
|
||||
import secop.iohandler
|
||||
from secop.datatypes import BoolType, EnumType, FloatRange, IntRange
|
||||
from secop.lib import formatStatusBits
|
||||
from secop.modules import Attached, Done, \
|
||||
Drivable, Parameter, Property, Readable
|
||||
from secop.poller import REGULAR, Poller
|
||||
from secop.stringio import HasIodev
|
||||
|
||||
Status = Drivable.Status
|
||||
|
||||
@ -59,19 +59,18 @@ class StringIO(secop.stringio.StringIO):
|
||||
|
||||
|
||||
class Main(HasIodev, Drivable):
|
||||
parameters = {
|
||||
'value': Override('the current channel', poll=REGULAR, datatype=IntRange(0, 17)),
|
||||
'target': Override('channel to select', datatype=IntRange(0, 17)),
|
||||
'autoscan':
|
||||
Parameter('whether to scan automatically', datatype=BoolType(), readonly=False, default=False),
|
||||
'pollinterval': Override('sleeptime between polls', default=1),
|
||||
}
|
||||
|
||||
value = Parameter('the current channel', poll=REGULAR, datatype=IntRange(0, 17))
|
||||
target = Parameter('channel to select', datatype=IntRange(0, 17))
|
||||
autoscan = Parameter('whether to scan automatically', datatype=BoolType(), readonly=False, default=False)
|
||||
pollinterval = Parameter('sleeptime between polls', default=1)
|
||||
|
||||
pollerClass = Poller
|
||||
iodevClass = StringIO
|
||||
_channel_changed = 0 # time of last channel change
|
||||
_channels = None # dict <channel no> of <module object>
|
||||
|
||||
def earlyInit(self):
|
||||
self._channel_changed = 0
|
||||
self._channels = {}
|
||||
|
||||
def register_channel(self, modobj):
|
||||
@ -85,10 +84,8 @@ class Main(HasIodev, Drivable):
|
||||
|
||||
def read_value(self):
|
||||
channel, auto = scan.send_command(self)
|
||||
# response = self.sendRecv('SCAN?').strip().split(',')
|
||||
# channel, auto = (int(s) for s in response)
|
||||
if channel not in self._channels:
|
||||
return channel
|
||||
return channel
|
||||
if not self._channels[channel].enabled:
|
||||
# channel was disabled recently, but still selected
|
||||
nextchannel = 0
|
||||
@ -129,61 +126,42 @@ class ResChannel(HasIodev, Readable):
|
||||
|
||||
RES_RANGE = {key: i+1 for i, key in list(
|
||||
enumerate(mag % val for mag in ['%gmOhm', '%gOhm', '%gkOhm', '%gMOhm']
|
||||
for val in [2, 6.32, 20, 63.2, 200, 632]))[:-2]}
|
||||
for val in [2, 6.32, 20, 63.2, 200, 632]))[:-2]}
|
||||
RES_SCALE = [2 * 10 ** (0.5 * i) for i in range(-7, 16)] # RES_SCALE[0] is not used
|
||||
CUR_RANGE = {key: i + 1 for i, key in list(
|
||||
enumerate(mag % val for mag in ['%gpA', '%gnA', '%guA', '%gmA']
|
||||
for val in [1, 3.16, 10, 31.6, 100, 316]))[:-2]}
|
||||
for val in [1, 3.16, 10, 31.6, 100, 316]))[:-2]}
|
||||
VOLT_RANGE = {key: i + 1 for i, key in list(
|
||||
enumerate(mag % val for mag in ['%guV', '%gmV']
|
||||
for val in [2, 6.32, 20, 63.2, 200, 632]))}
|
||||
for val in [2, 6.32, 20, 63.2, 200, 632]))}
|
||||
|
||||
pollerClass = Poller
|
||||
iodevClass = StringIO
|
||||
_main = None # main module
|
||||
_last_range_change = 0 # time of last range change
|
||||
|
||||
properties = {
|
||||
'channel':
|
||||
Property('the Lakeshore channel', datatype=IntRange(1, 16), export=False),
|
||||
'main':
|
||||
Attached()
|
||||
}
|
||||
channel = Property('the Lakeshore channel', datatype=IntRange(1, 16), export=False)
|
||||
main = Attached()
|
||||
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='Ohm')),
|
||||
'pollinterval':
|
||||
Override(visibility=3),
|
||||
'range':
|
||||
Parameter('reading range', readonly=False,
|
||||
datatype=EnumType(**RES_RANGE), handler=rdgrng),
|
||||
'minrange':
|
||||
Parameter('minimum range for software autorange', readonly=False, default=1,
|
||||
datatype=EnumType(**RES_RANGE)),
|
||||
'autorange':
|
||||
Parameter('autorange', datatype=EnumType(off=0, hard=1, soft=2),
|
||||
readonly=False, handler=rdgrng, default=2),
|
||||
'iexc':
|
||||
Parameter('current excitation', datatype=EnumType(off=0, **CUR_RANGE), readonly=False, handler=rdgrng),
|
||||
'vexc':
|
||||
Parameter('voltage excitation', datatype=EnumType(off=0, **VOLT_RANGE), readonly=False, handler=rdgrng),
|
||||
'enabled':
|
||||
Parameter('is this channel enabled?', datatype=BoolType(), readonly=False, handler=inset),
|
||||
'pause':
|
||||
Parameter('pause after channel change', datatype=FloatRange(3, 60), readonly=False, handler=inset),
|
||||
'dwell':
|
||||
Parameter('dwell time with autoscan', datatype=FloatRange(1, 200), readonly=False, handler=inset),
|
||||
'filter':
|
||||
Parameter('filter time', datatype=FloatRange(1, 200), readonly=False, handler=filterhdl),
|
||||
}
|
||||
value = Parameter(datatype=FloatRange(unit='Ohm'))
|
||||
pollinterval = Parameter(visibility=3)
|
||||
range = Parameter('reading range', readonly=False,
|
||||
datatype=EnumType(**RES_RANGE), handler=rdgrng)
|
||||
minrange = Parameter('minimum range for software autorange', readonly=False, default=1,
|
||||
datatype=EnumType(**RES_RANGE))
|
||||
autorange = Parameter('autorange', datatype=EnumType(off=0, hard=1, soft=2),
|
||||
readonly=False, handler=rdgrng, default=2)
|
||||
iexc = Parameter('current excitation', datatype=EnumType(off=0, **CUR_RANGE), readonly=False, handler=rdgrng)
|
||||
vexc = Parameter('voltage excitation', datatype=EnumType(off=0, **VOLT_RANGE), readonly=False, handler=rdgrng)
|
||||
enabled = Parameter('is this channel enabled?', datatype=BoolType(), readonly=False, handler=inset)
|
||||
pause = Parameter('pause after channel change', datatype=FloatRange(3, 60), readonly=False, handler=inset)
|
||||
dwell = Parameter('dwell time with autoscan', datatype=FloatRange(1, 200), readonly=False, handler=inset)
|
||||
filter = Parameter('filter time', datatype=FloatRange(1, 200), readonly=False, handler=filterhdl)
|
||||
|
||||
def initModule(self):
|
||||
self._main = self.DISPATCHER.get_module(self.main)
|
||||
self._main.register_channel(self)
|
||||
|
||||
def startModule(self, started_callback):
|
||||
self._last_range_change = 0
|
||||
super().startModule(started_callback)
|
||||
|
||||
def read_value(self):
|
||||
if self.channel != self._main.value:
|
||||
return Done
|
||||
@ -195,7 +173,7 @@ class ResChannel(HasIodev, Readable):
|
||||
if self.autorange == 'soft':
|
||||
now = time.time()
|
||||
if now > self._last_range_change + self.pause:
|
||||
rng = int(max(self.minrange, self.range)) # convert from enum to int
|
||||
rng = int(max(self.minrange, self.range)) # convert from enum to int
|
||||
if self.status[1] == '':
|
||||
if abs(result) > self.RES_SCALE[rng]:
|
||||
if rng < 22:
|
||||
@ -236,8 +214,6 @@ class ResChannel(HasIodev, Readable):
|
||||
result = dict(range=rng)
|
||||
if autorange:
|
||||
result['autorange'] = 'hard'
|
||||
#elif self.autorange == 'hard':
|
||||
# result['autorange'] = 'soft'
|
||||
# else: do not change autorange
|
||||
self.log.info('%s range %r %r %r' % (self.name, rng, autorange, self.autorange))
|
||||
if excoff:
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
from secop.modules import Communicator
|
||||
|
||||
|
||||
class Ls370Sim(Communicator):
|
||||
CHANNEL_COMMANDS = [
|
||||
('RDGR?%d', '1.0'),
|
||||
@ -32,9 +33,8 @@ class Ls370Sim(Communicator):
|
||||
]
|
||||
OTHER_COMMANDS = [
|
||||
('*IDN?', 'LSCI,MODEL370,370184,05302003'),
|
||||
('SCAN?', '1,1'),
|
||||
('SCAN?', '3,1'),
|
||||
]
|
||||
channel = [None]
|
||||
|
||||
def earlyInit(self):
|
||||
self._data = dict(self.OTHER_COMMANDS)
|
||||
@ -43,7 +43,7 @@ class Ls370Sim(Communicator):
|
||||
self._data[fmt % chan] = v
|
||||
# mkthread(self.run)
|
||||
|
||||
def do_communicate(self, command):
|
||||
def communicate(self, command):
|
||||
# simulation part, time independent
|
||||
for channel in range(1,17):
|
||||
_, _, _, _, excoff = self._data['RDGRNG?%d' % channel].split(',')
|
||||
|
@ -31,20 +31,19 @@ Polling of value and status is done commonly for all modules. For each registere
|
||||
<module>.update_value_status() is called in order to update their value and status.
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import time
|
||||
|
||||
from secop.modules import Module, Readable, Drivable, Parameter, Override,\
|
||||
Communicator, Property, Attached
|
||||
from secop.datatypes import EnumType, FloatRange, IntRange, StringType,\
|
||||
BoolType, StatusType
|
||||
from secop.lib.enum import Enum
|
||||
from secop.lib import clamp
|
||||
from secop.errors import HardwareError
|
||||
from secop.poller import Poller
|
||||
import secop.iohandler
|
||||
from secop.datatypes import BoolType, EnumType, \
|
||||
FloatRange, IntRange, StatusType, StringType
|
||||
from secop.errors import HardwareError
|
||||
from secop.lib import clamp
|
||||
from secop.lib.enum import Enum
|
||||
from secop.modules import Attached, Communicator, Done, \
|
||||
Drivable, Parameter, Property, Readable
|
||||
from secop.poller import Poller
|
||||
from secop.stringio import HasIodev
|
||||
from secop.metaclass import Done
|
||||
|
||||
try:
|
||||
import secop_psi.ppmswindows as ppmshw
|
||||
@ -73,19 +72,14 @@ class IOHandler(secop.iohandler.IOHandler):
|
||||
class Main(Communicator):
|
||||
"""ppms communicator module"""
|
||||
|
||||
parameters = {
|
||||
'pollinterval': Parameter('poll interval', readonly=False,
|
||||
datatype=FloatRange(), default=2),
|
||||
'communicate': Override('GBIP command'),
|
||||
'data': Parameter('internal', poll=True, export=True, # export for test only
|
||||
default="", readonly=True, datatype=StringType()),
|
||||
}
|
||||
properties = {
|
||||
'class_id': Property('Quantum Design class id', export=False,
|
||||
datatype=StringType()),
|
||||
}
|
||||
pollinterval = Parameter('poll interval', FloatRange(), readonly=False, default=2)
|
||||
data = Parameter('internal', StringType(), poll=True, export=True, # export for test only
|
||||
default="", readonly=True)
|
||||
|
||||
_channel_names = ['packed_status', 'temp', 'field', 'position', 'r1', 'i1', 'r2', 'i2',
|
||||
class_id = Property('Quantum Design class id', StringType(), export=False)
|
||||
|
||||
_channel_names = [
|
||||
'packed_status', 'temp', 'field', 'position', 'r1', 'i1', 'r2', 'i2',
|
||||
'r3', 'i3', 'r4', 'i4', 'v1', 'v2', 'digital', 'cur1', 'pow1', 'cur2', 'pow2',
|
||||
'p', 'u20', 'u21', 'u22', 'ts', 'u24', 'u25', 'u26', 'u27', 'u28', 'u29']
|
||||
assert len(_channel_names) == 30
|
||||
@ -102,7 +96,8 @@ class Main(Communicator):
|
||||
def register(self, other):
|
||||
self.modules[other.channel] = other
|
||||
|
||||
def do_communicate(self, command):
|
||||
def communicate(self, command):
|
||||
"""GPIB command"""
|
||||
with self.lock:
|
||||
reply = self._ppms_device.send(command)
|
||||
self.log.debug("%s|%s", command, reply)
|
||||
@ -114,7 +109,7 @@ class Main(Communicator):
|
||||
if channel.enabled:
|
||||
mask |= 1 << self._channel_to_index.get(channelname, 0)
|
||||
# send, read and convert to floats and ints
|
||||
data = self.do_communicate('GETDAT? %d' % mask)
|
||||
data = self.communicate('GETDAT? %d' % mask)
|
||||
reply = data.split(',')
|
||||
mask = int(reply.pop(0))
|
||||
reply.pop(0) # pop timestamp
|
||||
@ -133,23 +128,23 @@ class Main(Communicator):
|
||||
return data # return data as string
|
||||
|
||||
|
||||
class PpmsMixin(HasIodev, Module):
|
||||
"""common methods for ppms modules"""
|
||||
|
||||
parameters = {
|
||||
'pollinterval': None,
|
||||
}
|
||||
class PpmsBase(HasIodev, Readable):
|
||||
"""common base for all ppms modules"""
|
||||
iodev = Attached()
|
||||
|
||||
pollerClass = Poller
|
||||
enabled = True # default, if no parameter enable is defined
|
||||
_last_settings = None # used by several modules
|
||||
slow_pollfactor = 1
|
||||
|
||||
# as this pollinterval affects only the polling of settings
|
||||
# it would be confusing to export it.
|
||||
pollinterval = Parameter(export=False)
|
||||
|
||||
def initModule(self):
|
||||
self._iodev.register(self)
|
||||
|
||||
def startModule(self, started_callback):
|
||||
""""""
|
||||
# no polls except on main module
|
||||
started_callback()
|
||||
|
||||
@ -160,8 +155,8 @@ class PpmsMixin(HasIodev, Module):
|
||||
|
||||
def read_status(self):
|
||||
# polling is done by the main module
|
||||
# and PPMS does not deliver really fresh status values anyway:
|
||||
# e.g. the status is not changed immediately after a target change!
|
||||
# and PPMS does not deliver really fresh status values anyway: the status is not
|
||||
# changed immediately after a target change!
|
||||
return Done
|
||||
|
||||
def update_value_status(self, value, packed_status):
|
||||
@ -177,29 +172,22 @@ class PpmsMixin(HasIodev, Module):
|
||||
self.status = (self.Status.IDLE, '')
|
||||
|
||||
|
||||
class Channel(PpmsMixin, Readable):
|
||||
class Channel(PpmsBase):
|
||||
"""channel base class"""
|
||||
|
||||
parameters = {
|
||||
'value':
|
||||
Override('main value of channels', poll=True),
|
||||
'enabled':
|
||||
Parameter('is this channel used?', readonly=False, poll=False,
|
||||
datatype=BoolType(), default=False),
|
||||
}
|
||||
properties = {
|
||||
'channel':
|
||||
Property('channel name',
|
||||
datatype=StringType(), export=False, default=''),
|
||||
'no':
|
||||
Property('channel number',
|
||||
datatype=IntRange(1, 4), export=False),
|
||||
}
|
||||
value = Parameter('main value of channels', poll=True)
|
||||
enabled = Parameter('is this channel used?', readonly=False, poll=False,
|
||||
datatype=BoolType(), default=False)
|
||||
|
||||
channel = Property('channel name',
|
||||
datatype=StringType(), export=False, default='')
|
||||
no = Property('channel number',
|
||||
datatype=IntRange(1, 4), export=False)
|
||||
|
||||
def earlyInit(self):
|
||||
Readable.earlyInit(self)
|
||||
if not self.channel:
|
||||
self.properties['channel'] = self.name
|
||||
self.channel = self.name
|
||||
|
||||
def get_settings(self, pname):
|
||||
return ''
|
||||
@ -208,15 +196,12 @@ class Channel(PpmsMixin, Readable):
|
||||
class UserChannel(Channel):
|
||||
"""user channel"""
|
||||
|
||||
properties = {
|
||||
'no':
|
||||
Property('*(unused)*',
|
||||
datatype=IntRange(0, 0), export=False, default=0),
|
||||
'linkenable':
|
||||
Property('name of linked channel for enabling',
|
||||
datatype=StringType(), export=False, default=''),
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
}
|
||||
no = Property('channel number',
|
||||
datatype=IntRange(0, 0), export=False, default=0)
|
||||
linkenable = Property('name of linked channel for enabling',
|
||||
datatype=StringType(), export=False, default='')
|
||||
|
||||
def write_enabled(self, enabled):
|
||||
other = self._iodev.modules.get(self.linkenable, None)
|
||||
@ -230,14 +215,11 @@ class DriverChannel(Channel):
|
||||
|
||||
drvout = IOHandler('drvout', 'DRVOUT? %(no)d', '%d,%g,%g')
|
||||
|
||||
parameters = {
|
||||
'current':
|
||||
Parameter('driver current', readonly=False, handler=drvout,
|
||||
datatype=FloatRange(0., 5000., unit='uA')),
|
||||
'powerlimit':
|
||||
Parameter('power limit', readonly=False, handler=drvout,
|
||||
datatype=FloatRange(0., 1000., unit='uW')),
|
||||
}
|
||||
current = Parameter('driver current', readonly=False, handler=drvout,
|
||||
datatype=FloatRange(0., 5000., unit='uA'))
|
||||
powerlimit = Parameter('power limit', readonly=False, handler=drvout,
|
||||
datatype=FloatRange(0., 1000., unit='uW'))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
def analyze_drvout(self, no, current, powerlimit):
|
||||
if self.no != no:
|
||||
@ -255,25 +237,19 @@ class BridgeChannel(Channel):
|
||||
bridge = IOHandler('bridge', 'BRIDGE? %(no)d', '%d,%g,%g,%d,%d,%g')
|
||||
# pylint: disable=invalid-name
|
||||
ReadingMode = Enum('ReadingMode', standard=0, fast=1, highres=2)
|
||||
parameters = {
|
||||
'enabled':
|
||||
Override(handler=bridge),
|
||||
'excitation':
|
||||
Parameter('excitation current', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.01, 5000., unit='uA')),
|
||||
'powerlimit':
|
||||
Parameter('power limit', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.001, 1000., unit='uW')),
|
||||
'dcflag':
|
||||
Parameter('True when excitation is DC (else AC)', readonly=False, handler=bridge,
|
||||
datatype=BoolType()),
|
||||
'readingmode':
|
||||
Parameter('reading mode', readonly=False, handler=bridge,
|
||||
datatype=EnumType(ReadingMode)),
|
||||
'voltagelimit':
|
||||
Parameter('voltage limit', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.0001, 100., unit='mV')),
|
||||
}
|
||||
|
||||
enabled = Parameter(handler=bridge)
|
||||
excitation = Parameter('excitation current', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.01, 5000., unit='uA'))
|
||||
powerlimit = Parameter('power limit', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.001, 1000., unit='uW'))
|
||||
dcflag = Parameter('True when excitation is DC (else AC)', readonly=False, handler=bridge,
|
||||
datatype=BoolType())
|
||||
readingmode = Parameter('reading mode', readonly=False, handler=bridge,
|
||||
datatype=EnumType(ReadingMode))
|
||||
voltagelimit = Parameter('voltage limit', readonly=False, handler=bridge,
|
||||
datatype=FloatRange(0.0001, 100., unit='mV'))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
def analyze_bridge(self, no, excitation, powerlimit, dcflag, readingmode, voltagelimit):
|
||||
if self.no != no:
|
||||
@ -294,23 +270,22 @@ class BridgeChannel(Channel):
|
||||
return self.no, 0, 0, change.dcflag, change.readingmode, 0
|
||||
|
||||
|
||||
class Level(PpmsMixin, Readable):
|
||||
class Level(PpmsBase):
|
||||
"""helium level"""
|
||||
|
||||
level = IOHandler('level', 'LEVEL?', '%g,%d')
|
||||
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='%'), handler=level),
|
||||
'status': Override(handler=level),
|
||||
}
|
||||
value = Parameter(datatype=FloatRange(unit='%'), handler=level)
|
||||
status = Parameter(handler=level)
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
channel = 'level'
|
||||
|
||||
def update_value_status(self, value, packed_status):
|
||||
pass
|
||||
# must be a no-op
|
||||
# when called from Main.read_data, value is always None
|
||||
# value and status is polled via settings
|
||||
pass
|
||||
|
||||
def analyze_level(self, level, status):
|
||||
# ignore 'old reading' state of the flag, as this happens only for a short time
|
||||
@ -318,7 +293,7 @@ class Level(PpmsMixin, Readable):
|
||||
return dict(value=level, status=(self.Status.IDLE, ''))
|
||||
|
||||
|
||||
class Chamber(PpmsMixin, Drivable):
|
||||
class Chamber(PpmsBase, Drivable):
|
||||
"""sample chamber handling
|
||||
|
||||
value is an Enum, which is redundant with the status text
|
||||
@ -351,14 +326,13 @@ class Chamber(PpmsMixin, Drivable):
|
||||
venting_continuously=9,
|
||||
general_failure=15,
|
||||
)
|
||||
parameters = {
|
||||
'value':
|
||||
Override(description='chamber state', handler=chamber,
|
||||
datatype=EnumType(StatusCode)),
|
||||
'target':
|
||||
Override(description='chamber command', handler=chamber,
|
||||
datatype=EnumType(Operation)),
|
||||
}
|
||||
|
||||
value = Parameter(description='chamber state', handler=chamber,
|
||||
datatype=EnumType(StatusCode))
|
||||
target = Parameter(description='chamber command', handler=chamber,
|
||||
datatype=EnumType(Operation))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
STATUS_MAP = {
|
||||
StatusCode.purged_and_sealed: (Status.IDLE, 'purged and sealed'),
|
||||
StatusCode.vented_and_sealed: (Status.IDLE, 'vented and sealed'),
|
||||
@ -387,44 +361,40 @@ class Chamber(PpmsMixin, Drivable):
|
||||
return dict(target=target)
|
||||
|
||||
def change_chamber(self, change):
|
||||
# write settings, combining <pname>=<value> and current attributes
|
||||
# and request updated settings
|
||||
if change.target == self.Operation.noop:
|
||||
return None
|
||||
return (change.target,)
|
||||
|
||||
|
||||
class Temp(PpmsMixin, Drivable):
|
||||
class Temp(PpmsBase, Drivable):
|
||||
"""temperature"""
|
||||
|
||||
temp = IOHandler('temp', 'TEMP?', '%g,%g,%d')
|
||||
Status = Enum(Drivable.Status,
|
||||
RAMPING = 370,
|
||||
STABILIZING = 380,
|
||||
Status = Enum(
|
||||
Drivable.Status,
|
||||
RAMPING=370,
|
||||
STABILIZING=380,
|
||||
)
|
||||
# pylint: disable=invalid-name
|
||||
ApproachMode = Enum('ApproachMode', fast_settle=0, no_overshoot=1)
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='K'), poll=True),
|
||||
'status':
|
||||
Override(datatype=StatusType(Status), poll=True),
|
||||
'target':
|
||||
Override(datatype=FloatRange(1.7, 402.0, unit='K'), poll=False, needscfg=False),
|
||||
'setpoint':
|
||||
Parameter('intermediate set point',
|
||||
datatype=FloatRange(1.7, 402.0, unit='K'), handler=temp),
|
||||
'ramp':
|
||||
Parameter('ramping speed', readonly=False, default=0,
|
||||
datatype=FloatRange(0, 20, unit='K/min')),
|
||||
'workingramp':
|
||||
Parameter('intermediate ramp value',
|
||||
datatype=FloatRange(0, 20, unit='K/min'), handler=temp),
|
||||
'approachmode':
|
||||
Parameter('how to approach target!', readonly=False, handler=temp,
|
||||
datatype=EnumType(ApproachMode)),
|
||||
'timeout':
|
||||
Parameter('drive timeout, in addition to ramp time', readonly=False,
|
||||
datatype=FloatRange(0, unit='sec'), default=3600),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit='K'), poll=True)
|
||||
status = Parameter(datatype=StatusType(Status), poll=True)
|
||||
target = Parameter(datatype=FloatRange(1.7, 402.0, unit='K'), poll=False, needscfg=False)
|
||||
setpoint = Parameter('intermediate set point',
|
||||
datatype=FloatRange(1.7, 402.0, unit='K'), handler=temp)
|
||||
ramp = Parameter('ramping speed', readonly=False, default=0,
|
||||
datatype=FloatRange(0, 20, unit='K/min'))
|
||||
workingramp = Parameter('intermediate ramp value',
|
||||
datatype=FloatRange(0, 20, unit='K/min'), handler=temp)
|
||||
approachmode = Parameter('how to approach target!', readonly=False, handler=temp,
|
||||
datatype=EnumType(ApproachMode))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
timeout = Parameter('drive timeout, in addition to ramp time', readonly=False,
|
||||
datatype=FloatRange(0, unit='sec'), default=3600)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
TempStatus = Enum(
|
||||
'TempStatus',
|
||||
@ -449,17 +419,14 @@ class Temp(PpmsMixin, Drivable):
|
||||
14: (Status.ERROR, 'can not complete'),
|
||||
15: (Status.ERROR, 'general failure'),
|
||||
}
|
||||
properties = {
|
||||
'general_stop': Property('respect general stop', datatype=BoolType(),
|
||||
export=True, default=True)
|
||||
}
|
||||
general_stop = Property('respect general stop', datatype=BoolType(),
|
||||
default=True, value=False)
|
||||
|
||||
channel = 'temp'
|
||||
_stopped = False
|
||||
_expected_target_time = 0
|
||||
_last_change = 0 # 0 means no target change is pending
|
||||
_last_target = None # last reached target
|
||||
general_stop = False
|
||||
_cool_deadline = 0
|
||||
_wait_at10 = False
|
||||
_ramp_at_limit = False
|
||||
@ -573,7 +540,7 @@ class Temp(PpmsMixin, Drivable):
|
||||
def calc_expected(self, target, ramp):
|
||||
self._expected_target_time = time.time() + abs(target - self.value) * 60.0 / max(0.1, ramp)
|
||||
|
||||
def do_stop(self):
|
||||
def stop(self):
|
||||
if not self.isDriving():
|
||||
return
|
||||
if self.status[0] != self.Status.STABILIZING:
|
||||
@ -586,37 +553,31 @@ class Temp(PpmsMixin, Drivable):
|
||||
self._stopped = True
|
||||
|
||||
|
||||
class Field(PpmsMixin, Drivable):
|
||||
class Field(PpmsBase, Drivable):
|
||||
"""magnetic field"""
|
||||
|
||||
field = IOHandler('field', 'FIELD?', '%g,%g,%d,%d')
|
||||
Status = Enum(Drivable.Status,
|
||||
PREPARED = 150,
|
||||
PREPARING = 340,
|
||||
RAMPING = 370,
|
||||
FINALIZING = 390,
|
||||
Status = Enum(
|
||||
Drivable.Status,
|
||||
PREPARED=150,
|
||||
PREPARING=340,
|
||||
RAMPING=370,
|
||||
FINALIZING=390,
|
||||
)
|
||||
# pylint: disable=invalid-name
|
||||
PersistentMode = Enum('PersistentMode', persistent=0, driven=1)
|
||||
ApproachMode = Enum('ApproachMode', linear=0, no_overshoot=1, oscillate=2)
|
||||
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='T'), poll=True),
|
||||
'status':
|
||||
Override(datatype=StatusType(Status), poll=True),
|
||||
'target':
|
||||
Override(datatype=FloatRange(-15, 15, unit='T'), handler=field),
|
||||
'ramp':
|
||||
Parameter('ramping speed', readonly=False, handler=field,
|
||||
datatype=FloatRange(0.064, 1.19, unit='T/min')),
|
||||
'approachmode':
|
||||
Parameter('how to approach target', readonly=False, handler=field,
|
||||
datatype=EnumType(ApproachMode)),
|
||||
'persistentmode':
|
||||
Parameter('what to do after changing field', readonly=False, handler=field,
|
||||
datatype=EnumType(PersistentMode)),
|
||||
}
|
||||
value = Parameter(datatype=FloatRange(unit='T'), poll=True)
|
||||
status = Parameter(datatype=StatusType(Status), poll=True)
|
||||
target = Parameter(datatype=FloatRange(-15, 15, unit='T'), handler=field)
|
||||
ramp = Parameter('ramping speed', readonly=False, handler=field,
|
||||
datatype=FloatRange(0.064, 1.19, unit='T/min'))
|
||||
approachmode = Parameter('how to approach target', readonly=False, handler=field,
|
||||
datatype=EnumType(ApproachMode))
|
||||
persistentmode = Parameter('what to do after changing field', readonly=False, handler=field,
|
||||
datatype=EnumType(PersistentMode))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
STATUS_MAP = {
|
||||
1: (Status.IDLE, 'persistent mode'),
|
||||
@ -652,7 +613,7 @@ class Field(PpmsMixin, Drivable):
|
||||
else:
|
||||
status = (self.Status.WARN, 'timeout when ramping leads')
|
||||
elif now > self._last_change + 5:
|
||||
self._last_change = 0 # give up waiting for driving
|
||||
self._last_change = 0 # give up waiting for driving
|
||||
elif self.isDriving(status) and status != self._status_before_change:
|
||||
self._last_change = 0
|
||||
self.log.debug('time needed to change to busy: %.3g', now - self._last_change)
|
||||
@ -718,7 +679,7 @@ class Field(PpmsMixin, Drivable):
|
||||
return Done
|
||||
return None # do not execute FIELD command, as this would trigger a ramp up of leads current
|
||||
|
||||
def do_stop(self):
|
||||
def stop(self):
|
||||
if not self.isDriving():
|
||||
return
|
||||
newtarget = clamp(self._last_target, self.value, self.target)
|
||||
@ -729,23 +690,20 @@ class Field(PpmsMixin, Drivable):
|
||||
self._stopped = True
|
||||
|
||||
|
||||
class Position(PpmsMixin, Drivable):
|
||||
class Position(PpmsBase, Drivable):
|
||||
"""rotator position"""
|
||||
|
||||
move = IOHandler('move', 'MOVE?', '%g,%g,%g')
|
||||
Status = Drivable.Status
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='deg'), poll=True),
|
||||
'target':
|
||||
Override(datatype=FloatRange(-720., 720., unit='deg'), handler=move),
|
||||
'enabled':
|
||||
Parameter('is this channel used?', readonly=False, poll=False,
|
||||
datatype=BoolType(), default=True),
|
||||
'speed':
|
||||
Parameter('motor speed', readonly=False, handler=move,
|
||||
datatype=FloatRange(0.8, 12, unit='deg/sec')),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit='deg'), poll=True)
|
||||
target = Parameter(datatype=FloatRange(-720., 720., unit='deg'), handler=move)
|
||||
enabled = Parameter('is this channel used?', readonly=False, poll=False,
|
||||
datatype=BoolType(), default=True)
|
||||
speed = Parameter('motor speed', readonly=False, handler=move,
|
||||
datatype=FloatRange(0.8, 12, unit='deg/sec'))
|
||||
# pollinterval = Parameter(visibility=3)
|
||||
|
||||
STATUS_MAP = {
|
||||
1: (Status.IDLE, 'at target'),
|
||||
5: (Status.BUSY, 'moving'),
|
||||
@ -824,7 +782,7 @@ class Position(PpmsMixin, Drivable):
|
||||
self.speed = value
|
||||
return None # do not execute MOVE command, as this would trigger an unnecessary move
|
||||
|
||||
def do_stop(self):
|
||||
def stop(self):
|
||||
if not self.isDriving():
|
||||
return
|
||||
newtarget = clamp(self._last_target, self.value, self.target)
|
||||
|
@ -20,9 +20,9 @@
|
||||
# *****************************************************************************
|
||||
"""PPMS mf proxy"""
|
||||
|
||||
from secop.core import Enum, FloatRange, EnumType, Override, Parameter, Drivable
|
||||
from secop.datatypes import StatusType
|
||||
import secop_psi.ppms
|
||||
from secop.core import Drivable, Enum, EnumType, FloatRange, Override, Parameter
|
||||
from secop.datatypes import StatusType
|
||||
from secop.proxy import proxy_class
|
||||
|
||||
|
||||
|
@ -18,9 +18,10 @@
|
||||
# Module authors:
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
# *****************************************************************************
|
||||
import time
|
||||
import json
|
||||
import math
|
||||
import time
|
||||
|
||||
|
||||
def num(string):
|
||||
return json.loads(string)
|
||||
|
@ -32,21 +32,21 @@ t1:raw tt t1/raw /tt/t1/raw tt t1 raw /tt/t1
|
||||
rx:bla rx bla /some/rx_a/bla rx bla /some/rx_a
|
||||
"""
|
||||
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
import json
|
||||
from os.path import join, expanduser
|
||||
from os.path import expanduser, join
|
||||
|
||||
from secop.modules import Module, Parameter, Command, Override, Drivable, Readable, Writable, Property, Attached
|
||||
from secop.datatypes import StringType, FloatRange, ArrayOf, BoolType, IntRange, EnumType
|
||||
from secop.lib import mkthread, getGeneralConfig
|
||||
from secop.lib.asynconn import AsynConn, ConnectionClosed
|
||||
from secop.metaclass import ModuleMeta, Done
|
||||
from secop.errors import HardwareError, secop_error, ConfigError
|
||||
from secop.client import ProxyClient
|
||||
from secop.datatypes import ArrayOf, BoolType, \
|
||||
EnumType, FloatRange, IntRange, StringType
|
||||
from secop.errors import ConfigError, HardwareError, secop_error
|
||||
from secop.lib import getGeneralConfig, mkthread
|
||||
from secop.lib.asynconn import AsynConn, ConnectionClosed
|
||||
from secop.modules import Attached, Command, Done, Drivable, \
|
||||
Module, Parameter, Property, Readable, Writable
|
||||
from secop.protocol.dispatcher import make_update
|
||||
|
||||
|
||||
CFG_HEADER = """[NODE]
|
||||
id = %(samenv)s.psi.ch
|
||||
description = %(samenv)s over SEA
|
||||
@ -76,7 +76,7 @@ def get_sea_port(instance):
|
||||
for line in f:
|
||||
linesplit = line.split()
|
||||
if len(linesplit) == 3:
|
||||
cmd, var, value = line.split()
|
||||
_, var, value = line.split()
|
||||
if var == 'serverport':
|
||||
return value
|
||||
except FileNotFoundError:
|
||||
@ -87,23 +87,10 @@ def get_sea_port(instance):
|
||||
class SeaClient(ProxyClient, Module):
|
||||
"""connection to SEA"""
|
||||
|
||||
properties = {
|
||||
'json_path': Property('path to SEA json descriptors',
|
||||
datatype=StringType(),
|
||||
default=join(expanduser('~'), 'sea/tcl/json'))
|
||||
}
|
||||
parameters = {
|
||||
'uri':
|
||||
Parameter('hostname:portnumber', datatype=StringType(), default='localhost:5000'),
|
||||
'timeout':
|
||||
Parameter('timeout', datatype=FloatRange(0), default=10),
|
||||
}
|
||||
commands = {
|
||||
'communicate':
|
||||
Command('send a command to SEA', argument=StringType(), result=StringType()),
|
||||
'describe':
|
||||
Command('save objects (and sub-objects) description', result=StringType()),
|
||||
}
|
||||
json_path = Property('path to SEA json descriptors', StringType())
|
||||
|
||||
uri = Parameter('hostname:portnumber', datatype=StringType(), default='localhost:5000')
|
||||
timeout = Parameter('timeout', datatype=FloatRange(0), default=10)
|
||||
|
||||
def __init__(self, name, log, opts, srv):
|
||||
instance = srv.node_cfg['name'].rsplit('_', 1)[0]
|
||||
@ -198,7 +185,7 @@ class SeaClient(ProxyClient, Module):
|
||||
if msg.startswith('_E '):
|
||||
try:
|
||||
_, path, readerror = msg.split(None, 2)
|
||||
except Exception as e:
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
@ -241,11 +228,15 @@ class SeaClient(ProxyClient, Module):
|
||||
# do not update unchanged values within 0.1 sec
|
||||
self.updateValue(module, param, value, now, readerror)
|
||||
|
||||
def do_communicate(self, command):
|
||||
@Command
|
||||
def communicate(self, command):
|
||||
"""send a command to SEA"""
|
||||
reply = self.request(command)
|
||||
return reply
|
||||
|
||||
def do_describe(self):
|
||||
@Command(result=StringType())
|
||||
def describe(self):
|
||||
"""save objects (and sub-objects) description"""
|
||||
reply = self.request('describe_all')
|
||||
reply = ''.join('' if line.startswith('WARNING') else line for line in reply.split('\n'))
|
||||
samenv, reply = json.loads(reply)
|
||||
@ -288,9 +279,7 @@ def get_datatype(paramdesc):
|
||||
|
||||
|
||||
class SeaModule(Module):
|
||||
properties = {
|
||||
'iodev': Attached(),
|
||||
}
|
||||
iodev = Attached()
|
||||
|
||||
# pollerClass=None
|
||||
path2param = None
|
||||
@ -329,8 +318,7 @@ class SeaModule(Module):
|
||||
else: # take all
|
||||
main = ''
|
||||
path2param = {}
|
||||
parameters = {}
|
||||
attributes = dict(sea_object=sea_object, path2param=path2param, parameters=parameters)
|
||||
attributes = dict(sea_object=sea_object, path2param=path2param)
|
||||
for paramdesc in descr:
|
||||
path = paramdesc['path']
|
||||
readonly = paramdesc.get('readonly', True)
|
||||
@ -351,6 +339,7 @@ class SeaModule(Module):
|
||||
else:
|
||||
kwds['group'] = pathlist[-2]
|
||||
# flatten path to parameter name
|
||||
key = None
|
||||
for i in reversed(range(len(pathlist))):
|
||||
key = '_'.join(pathlist[i:])
|
||||
if not key in cls.accessibles:
|
||||
@ -361,12 +350,12 @@ class SeaModule(Module):
|
||||
if key in cls.accessibles:
|
||||
if key == 'target':
|
||||
kwds['readonly'] = False
|
||||
pobj = Override(**kwds)
|
||||
pobj = cls.accessibles[key].override(**kwds)
|
||||
datatype = kwds.get('datatype', cls.accessibles[key].datatype)
|
||||
else:
|
||||
pobj = Parameter(**kwds)
|
||||
datatype = pobj.datatype
|
||||
parameters[key] = pobj
|
||||
attributes[key] = pobj
|
||||
if not hasattr(cls, 'read_' + key):
|
||||
def rfunc(self, cmd='hval /sics/%s/%s' % (sea_object, path)):
|
||||
print('READ', cmd)
|
||||
@ -395,19 +384,20 @@ class SeaModule(Module):
|
||||
return Done
|
||||
|
||||
attributes['write_' + key] = wfunc
|
||||
|
||||
# create standard parameters like value and status, if not yet there
|
||||
for pname, pobj in cls.accessibles.items():
|
||||
if pname == 'pollinterval':
|
||||
parameters[pname] = Override(export=False)
|
||||
elif pname not in parameters and isinstance(pobj, Parameter):
|
||||
parameters[pname] = Override(poll=False, needscfg=False)
|
||||
attributes[pname] = pobj.override(export=False)
|
||||
elif pname not in attributes and isinstance(pobj, Parameter):
|
||||
attributes[pname] = pobj.override(poll=False, needscfg=False)
|
||||
|
||||
classname = '%s_%s' % (cls.__name__, sea_object)
|
||||
newcls = ModuleMeta.__new__(ModuleMeta, classname, (cls,), attributes)
|
||||
newcls = type(classname, (cls,), attributes)
|
||||
return Module.__new__(newcls)
|
||||
|
||||
def __init__(self, name, logger, cfgdict, dispatcher):
|
||||
Module.__init__(self, name, logger, cfgdict, dispatcher)
|
||||
# def __init__(self, name, logger, cfgdict, dispatcher):
|
||||
# Module.__init__(self, name, logger, cfgdict, dispatcher)
|
||||
|
||||
def updateEvent(self, module, parameter, value, timestamp, readerror):
|
||||
upd = getattr(self, 'update_' + parameter, None)
|
||||
@ -442,9 +432,9 @@ class SeaReadable(SeaModule, Readable):
|
||||
if readerror:
|
||||
value = repr(readerror)
|
||||
if value == '':
|
||||
self.status = [self.Status.IDLE, '']
|
||||
self.status = (self.Status.IDLE, '')
|
||||
else:
|
||||
self.status = [self.Status.ERROR, value]
|
||||
self.status = (self.Status.ERROR, value)
|
||||
|
||||
def read_status(self):
|
||||
return self.status
|
||||
@ -485,11 +475,11 @@ class SeaDrivable(SeaModule, Drivable):
|
||||
|
||||
def updateStatus(self):
|
||||
if self._sea_status:
|
||||
self.status = [self.Status.ERROR, self._sea_status]
|
||||
self.status = (self.Status.ERROR, self._sea_status)
|
||||
elif self._is_running:
|
||||
self.status = [self.Status.BUSY, 'driving']
|
||||
self.status = (self.Status.BUSY, 'driving')
|
||||
else:
|
||||
self.status = [self.Status.IDLE, '']
|
||||
self.status = (self.Status.IDLE, '')
|
||||
|
||||
def updateTarget(self, module, parameter, value, timestamp, readerror):
|
||||
if value is not None:
|
||||
|
@ -21,33 +21,33 @@
|
||||
"""senis hall sensor"""
|
||||
|
||||
|
||||
import time
|
||||
import threading
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from serial import Serial
|
||||
from secop.core import Property, Parameter, Override, Readable, BoolType, \
|
||||
FloatRange, TupleOf, StringType, IntRange, Attached
|
||||
|
||||
from secop.core import Attached, BoolType, FloatRange, IntRange, \
|
||||
Parameter, Property, Readable, StringType, TupleOf
|
||||
|
||||
|
||||
class Temperature(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='degC')),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit='degC'))
|
||||
|
||||
|
||||
class Bcomp(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange(unit='T')),
|
||||
'range': Parameter('working range', FloatRange(unit='T'), default=0),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit='T'))
|
||||
range = Parameter('working range', FloatRange(unit='T'), default=0)
|
||||
|
||||
|
||||
class Raw(Readable):
|
||||
pollerClass = None
|
||||
parameters = {
|
||||
'value': Override(datatype=FloatRange()),
|
||||
}
|
||||
|
||||
value = Parameter(datatype=FloatRange())
|
||||
|
||||
|
||||
class TeslameterBase(Readable):
|
||||
@ -58,18 +58,15 @@ class TeslameterBase(Readable):
|
||||
|
||||
the B components (and temperatures for 3MH6) are implemented as separate modules
|
||||
"""
|
||||
properties = {
|
||||
'x': Attached(),
|
||||
'y': Attached(),
|
||||
'z': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'value': Override('B vector', poll=True,
|
||||
datatype=TupleOf(FloatRange(unit='T'), FloatRange(unit='T'), FloatRange(unit='T'))),
|
||||
'usb': Parameter('usb device', StringType(), readonly=False),
|
||||
'enabled': Parameter('enable data acq', datatype=BoolType(), readonly=False, default=True),
|
||||
'nsample': Parameter('number of samples for average', datatype=IntRange(1, 1000), readonly=False, default=1),
|
||||
}
|
||||
x = Attached()
|
||||
y = Attached()
|
||||
z = Attached()
|
||||
|
||||
value = Parameter('B vector', poll=True,
|
||||
datatype=TupleOf(FloatRange(unit='T'), FloatRange(unit='T'), FloatRange(unit='T')))
|
||||
usb = Parameter('usb device', StringType(), readonly=False)
|
||||
enabled = Parameter('enable data acq', datatype=BoolType(), readonly=False, default=True)
|
||||
nsample = Parameter('number of samples for average', datatype=IntRange(1, 1000), readonly=False, default=1)
|
||||
|
||||
def init_serial(self, baud):
|
||||
self._conn = Serial(self.usb, baud, timeout=0.1)
|
||||
@ -103,9 +100,7 @@ class Teslameter3MH3(TeslameterBase):
|
||||
remark: no query for the sample rate is possible, therefore set always to
|
||||
a default rate (therefore initwrite=True on the rate parameter)
|
||||
"""
|
||||
properties = {
|
||||
'range': Property('full scale', datatype=FloatRange(), default=2),
|
||||
}
|
||||
range = Property('full scale', datatype=FloatRange(), default=2)
|
||||
|
||||
def earlyInit(self):
|
||||
self.init_serial(115200)
|
||||
@ -122,7 +117,7 @@ class Teslameter3MH3(TeslameterBase):
|
||||
s.timeout = 0.1 + 0.02 * self.nsample
|
||||
for _ in range(2):
|
||||
self.write_bytes(b'B')
|
||||
t = time.time()
|
||||
# t = time.time()
|
||||
reply = self.read_bytes(8 * self.nsample)
|
||||
s.timeout = 0.1
|
||||
self.stop_reading()
|
||||
@ -147,21 +142,19 @@ class Teslameter3MH3(TeslameterBase):
|
||||
|
||||
class Teslameter3MH6(TeslameterBase):
|
||||
"""luxury model with probe and box temperature and autorange"""
|
||||
properties = {
|
||||
'x_direct': Attached(),
|
||||
'y_direct': Attached(),
|
||||
'z_direct': Attached(),
|
||||
'probe_temp': Attached(),
|
||||
'box_temp': Attached(),
|
||||
'probe_temp_direct': Attached(),
|
||||
'box_temp_direct': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'range': Parameter('range or 0 for autorange', FloatRange(0, 20, unit='T'), readonly=False, default=0),
|
||||
'rate': Parameter('sampling rate', datatype=FloatRange(10, 15000, unit='Hz'),
|
||||
readonly=False, poll=True),
|
||||
'avtime': Parameter('data acquisition time', FloatRange(), default=0),
|
||||
}
|
||||
x_direct = Attached()
|
||||
y_direct = Attached()
|
||||
z_direct = Attached()
|
||||
probe_temp = Attached()
|
||||
box_temp = Attached()
|
||||
probe_temp_direct = Attached()
|
||||
box_temp_direct = Attached()
|
||||
|
||||
range = Parameter('range or 0 for autorange', FloatRange(0, 20, unit='T'), readonly=False, default=0)
|
||||
rate = Parameter('sampling rate', datatype=FloatRange(10, 15000, unit='Hz'),
|
||||
readonly=False, poll=True)
|
||||
avtime = Parameter('data acquisition time', FloatRange(), default=0)
|
||||
|
||||
SAMPLING_RATES = {0xe0: 15000, 0xd0: 7500, 0xc0: 3750, 0xb0: 2000, 0xa1: 1000,
|
||||
0x92: 500, 0x82: 100, 0x72: 60, 0x63: 50, 0x53: 30, 0x23: 10}
|
||||
RANGES = dict(zip(b'1234', [0.1, 0.5, 2, 20]))
|
||||
@ -183,7 +176,7 @@ class Teslameter3MH6(TeslameterBase):
|
||||
chk = np.frombuffer(reply, dtype='i1,23i1,i1')
|
||||
if not np.all(np.sum(chk['f1'], axis=1) % 256 == 0):
|
||||
status = 'checksum error'
|
||||
continue
|
||||
continue
|
||||
# first byte must be 'B' and last byte must be CR
|
||||
if np.all(chk['f0'] == ord(b'B')) and np.all(chk['f2'] == 13):
|
||||
break
|
||||
@ -219,7 +212,7 @@ class Teslameter3MH6(TeslameterBase):
|
||||
self._z.value = mean['z'] * 0.001
|
||||
self._probe_temp.value = mean['thc']
|
||||
self._box_temp.value = mean['tec']
|
||||
|
||||
|
||||
self.write_bytes(b'D') # put into NONcalibrated mode
|
||||
if self.read_bytes(1) != b'd':
|
||||
self.log.error('missing response to D command')
|
||||
|
@ -20,13 +20,14 @@
|
||||
# *****************************************************************************
|
||||
"""Software calibration"""
|
||||
|
||||
import os
|
||||
from os.path import join, exists, basename
|
||||
import math
|
||||
import numpy as np
|
||||
from scipy.interpolate import splrep, splev # pylint: disable=import-error
|
||||
import os
|
||||
from os.path import basename, exists, join
|
||||
|
||||
from secop.core import Readable, Parameter, Override, Attached, StringType, BoolType
|
||||
import numpy as np
|
||||
from scipy.interpolate import splev, splrep # pylint: disable=import-error
|
||||
|
||||
from secop.core import Attached, BoolType, Parameter, Readable, StringType
|
||||
|
||||
|
||||
def linear(x):
|
||||
@ -102,6 +103,7 @@ class CalCurve:
|
||||
sensopt = calibspec.split(',')
|
||||
calibname = sensopt.pop(0)
|
||||
_, dot, ext = basename(calibname).rpartition('.')
|
||||
kind = None
|
||||
for path in os.environ.get('FRAPPY_CALIB_PATH', '').split(','):
|
||||
# first try without adding kind
|
||||
filename = join(path.strip(), calibname)
|
||||
@ -109,8 +111,8 @@ class CalCurve:
|
||||
kind = ext if dot else None
|
||||
break
|
||||
# then try adding all kinds as extension
|
||||
for kind in KINDS:
|
||||
for nam in {calibname, calibname.upper(), calibname.lower()}:
|
||||
for nam in calibname, calibname.upper(), calibname.lower():
|
||||
for kind in KINDS:
|
||||
filename = join(path.strip(), '%s.%s' % (nam, kind))
|
||||
if exists(filename):
|
||||
break
|
||||
@ -150,16 +152,14 @@ class CalCurve:
|
||||
|
||||
|
||||
class Sensor(Readable):
|
||||
properties = {
|
||||
'rawsensor': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'calib': Parameter('calibration name', datatype=StringType(), readonly=False),
|
||||
'abs': Parameter('True: take abs(raw) before calib', datatype=BoolType(), readonly=False, default=True),
|
||||
'value': Override(unit='K'),
|
||||
'pollinterval': Override(export=False),
|
||||
'status': Override(default=(Readable.Status.ERROR, 'unintialized'))
|
||||
}
|
||||
rawsensor = Attached()
|
||||
|
||||
calib = Parameter('calibration name', datatype=StringType(), readonly=False)
|
||||
abs = Parameter('True: take abs(raw) before calib', datatype=BoolType(), readonly=False, default=True)
|
||||
value = Parameter(unit='K')
|
||||
pollinterval = Parameter(export=False)
|
||||
status = Parameter(default=(Readable.Status.ERROR, 'unintialized'))
|
||||
|
||||
pollerClass = None
|
||||
description = 'a calibrated sensor value'
|
||||
_value_error = None
|
||||
@ -179,7 +179,7 @@ class Sensor(Readable):
|
||||
self._value_error = None
|
||||
|
||||
def error_update_value(self, err):
|
||||
if self.abs and str(err) == 'R_UNDER':
|
||||
if self.abs and str(err) == 'R_UNDER': # hack: ignore R_UNDER from ls370
|
||||
self._value_error = None
|
||||
return None
|
||||
self._value_error = repr(err)
|
||||
|
@ -20,40 +20,38 @@
|
||||
# *****************************************************************************
|
||||
"""Test command arguments"""
|
||||
|
||||
from secop.core import Module, Parameter, Command, FloatRange, StringType, BoolType, TupleOf, StructOf, ArrayOf
|
||||
from secop.core import ArrayOf, BoolType, Command, FloatRange, \
|
||||
Module, Parameter, StringType, StructOf, TupleOf
|
||||
|
||||
|
||||
class TestCmd(Module):
|
||||
|
||||
commands = {
|
||||
'arg':
|
||||
Command('5 args',
|
||||
argument=TupleOf(StringType(), FloatRange(), BoolType(), TupleOf(BoolType()), StructOf(a=StringType())),
|
||||
result=StringType()),
|
||||
'keyed':
|
||||
Command('keyworded arg', argument=StructOf(a=StringType(), b=FloatRange(), c=BoolType(), optional=['b']), result=StringType()),
|
||||
'one':
|
||||
Command('1 arg', argument=FloatRange(), result=StringType()),
|
||||
'none':
|
||||
Command('no arg', result=StringType()),
|
||||
}
|
||||
parameters = {
|
||||
'struct': Parameter('struct', StructOf(a=StringType(), b=FloatRange(), c=BoolType(), optional=['b']),
|
||||
readonly=False, default=dict(a='',c=True)),
|
||||
'array': Parameter('array', ArrayOf(BoolType()),
|
||||
readonly=False, default=[]),
|
||||
'tuple': Parameter('tuple', TupleOf(StringType(), FloatRange(), BoolType(), TupleOf(BoolType()), StructOf(a=StringType())),
|
||||
readonly=False, default=('',0,False,(False,),dict(a=''))),
|
||||
}
|
||||
struct = Parameter('struct', StructOf(a=StringType(), b=FloatRange(), c=BoolType(), optional=['b']),
|
||||
readonly=False, default=dict(a='', c=True))
|
||||
array = Parameter('array', ArrayOf(BoolType()),
|
||||
readonly=False, default=[])
|
||||
tuple = Parameter('tuple', TupleOf(StringType(), FloatRange(), BoolType(),
|
||||
TupleOf(BoolType()), StructOf(a=StringType())),
|
||||
readonly=False, default=('', 0, False, (False,), dict(a='')))
|
||||
|
||||
def do_arg(self, arg):
|
||||
@Command(argument=TupleOf(StringType(), FloatRange(), BoolType(), TupleOf(BoolType()), StructOf(a=StringType())),
|
||||
result=StringType())
|
||||
def arg(self, *arg):
|
||||
"""5 args"""
|
||||
return repr(arg)
|
||||
|
||||
def do_keyed(self, arg):
|
||||
@Command(argument=StructOf(a=StringType(), b=FloatRange(), c=BoolType(), optional=['b']),
|
||||
result=StringType())
|
||||
def keyed(self, **arg):
|
||||
"""keyworded arg"""
|
||||
return repr(arg)
|
||||
|
||||
def do_one(self, arg):
|
||||
@Command(argument=FloatRange(), result=StringType())
|
||||
def one(self, arg):
|
||||
"""1 arg"""
|
||||
return repr(arg)
|
||||
|
||||
def do_none(self):
|
||||
@Command(result=StringType())
|
||||
def none(self):
|
||||
"""no arg"""
|
||||
return repr(None)
|
||||
|
@ -20,31 +20,23 @@
|
||||
# *****************************************************************************
|
||||
"""Temp"""
|
||||
|
||||
from secop.modules import Readable, Drivable, Parameter, Override
|
||||
from secop.datatypes import FloatRange, IntRange, StringType
|
||||
from secop.modules import Drivable, Parameter, Readable
|
||||
from secop.stringio import HasIodev
|
||||
|
||||
Status = Drivable.Status
|
||||
|
||||
class TempLoop(HasIodev, Drivable):
|
||||
'''temperature channel on Lakeshore 336'''
|
||||
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='K'), default=0, poll=True),
|
||||
'status':
|
||||
Override(poll=False),
|
||||
'target':
|
||||
Override(datatype=FloatRange(1.0, 402.0, unit='K'), default=1.3, poll=True),
|
||||
'tolerance':
|
||||
Parameter('the tolerance', FloatRange(-400,400), default=1, readonly=False),
|
||||
'pollinterval':
|
||||
Override(visibility=3),
|
||||
'channel':
|
||||
Parameter('the Lakeshore channel', datatype=StringType(), export=False),
|
||||
'loop':
|
||||
Parameter('the Lakeshore loop number', datatype=IntRange(1,3), export=False),
|
||||
}
|
||||
class TempLoop(HasIodev, Drivable):
|
||||
"""temperature channel on Lakeshore 336"""
|
||||
|
||||
value = Parameter(datatype=FloatRange(unit='K'), default=0, poll=True)
|
||||
status = Parameter(poll=False)
|
||||
target = Parameter(datatype=FloatRange(1.0, 402.0, unit='K'), default=1.3, poll=True)
|
||||
tolerance = Parameter('the tolerance', FloatRange(-400, 400), default=1, readonly=False)
|
||||
pollinterval = Parameter(visibility=3)
|
||||
channel = Parameter('the Lakeshore channel', datatype=StringType(), export=False)
|
||||
loop = Parameter('the Lakeshore loop number', datatype=IntRange(1, 3), export=False)
|
||||
|
||||
def earlyInit(self):
|
||||
super(TempLoop, self).earlyInit()
|
||||
@ -67,24 +59,18 @@ class TempLoop(HasIodev, Drivable):
|
||||
float('x')
|
||||
return result
|
||||
|
||||
def do_stop(self):
|
||||
def stop(self):
|
||||
self.target = self.value
|
||||
self.status = [Status.IDLE, 'stopped']
|
||||
|
||||
|
||||
class TempChannel(HasIodev, Readable):
|
||||
'''temperature channel on Lakeshore 336'''
|
||||
"""temperature channel on Lakeshore 336"""
|
||||
|
||||
parameters = {
|
||||
'value':
|
||||
Override(datatype=FloatRange(unit='K'), default=0, poll=True),
|
||||
'status':
|
||||
Override(poll=False, constant=[Status.IDLE, 'idle']),
|
||||
'pollinterval':
|
||||
Override(visibility=3),
|
||||
'channel':
|
||||
Parameter('the Lakeshore channel', datatype=StringType(), export=False),
|
||||
}
|
||||
value = Parameter(datatype=FloatRange(unit='K'), default=0, poll=True)
|
||||
status = Parameter(poll=False, constant=[Status.IDLE, 'idle'])
|
||||
pollinterval = Parameter(visibility=3)
|
||||
channel = Parameter('the Lakeshore channel', datatype=StringType(), export=False)
|
||||
|
||||
def read_value(self):
|
||||
result = self.sendRecv('KRDG?%s' % self.channel)
|
||||
|
@ -20,17 +20,19 @@
|
||||
# *****************************************************************************
|
||||
"""frappy support for ultrasound"""
|
||||
|
||||
import math
|
||||
#import serial
|
||||
import os
|
||||
import math
|
||||
import time
|
||||
from secop.core import Readable, Parameter, Override, FloatRange, BoolType, StringIO, \
|
||||
Done, Attached, TupleOf, StringType, IntRange, EnumType, HasIodev, Module
|
||||
from secop.properties import Property
|
||||
from adq_mr import Adq
|
||||
import iqplot
|
||||
|
||||
import numpy as np
|
||||
|
||||
import iqplot
|
||||
from adq_mr import Adq
|
||||
from secop.core import Attached, BoolType, Done, FloatRange, HasIodev, \
|
||||
IntRange, Module, Parameter, Readable, StringIO, StringType
|
||||
from secop.properties import Property
|
||||
|
||||
|
||||
def fname_from_time(t, extension):
|
||||
tm = time.localtime(t)
|
||||
@ -43,32 +45,27 @@ def fname_from_time(t, extension):
|
||||
|
||||
|
||||
class Roi(Readable):
|
||||
properties = {
|
||||
'main': Attached(),
|
||||
}
|
||||
parameters = {
|
||||
'value': Override('amplitude', FloatRange(), default=0),
|
||||
'phase': Parameter('phase', FloatRange(unit='deg'), default=0),
|
||||
'i': Parameter('in phase', FloatRange(), default=0),
|
||||
'q': Parameter('out of phase', FloatRange(), default=0),
|
||||
'time': Parameter('start time', FloatRange(unit='nsec'),
|
||||
readonly=False),
|
||||
'size': Parameter('interval (symmetric around time)', FloatRange(unit='nsec'),
|
||||
readonly=False),
|
||||
'enable': Parameter('calculate this roi', BoolType(), readonly=False, default=True),
|
||||
#'status': Override(export=False),
|
||||
'pollinterval': Override(export=False),
|
||||
}
|
||||
|
||||
main = Attached()
|
||||
|
||||
value = Parameter('amplitude', FloatRange(), default=0)
|
||||
phase = Parameter('phase', FloatRange(unit='deg'), default=0)
|
||||
i = Parameter('in phase', FloatRange(), default=0)
|
||||
q = Parameter('out of phase', FloatRange(), default=0)
|
||||
time = Parameter('start time', FloatRange(unit='nsec'), readonly=False)
|
||||
size = Parameter('interval (symmetric around time)', FloatRange(unit='nsec'), readonly=False)
|
||||
enable = Parameter('calculate this roi', BoolType(), readonly=False, default=True)
|
||||
#status = Parameter(export=False)
|
||||
pollinterval = Parameter(export=False)
|
||||
|
||||
interval = (0,0)
|
||||
|
||||
|
||||
def initModule(self):
|
||||
self._main.register_roi(self)
|
||||
self.calc_interval()
|
||||
|
||||
def calc_interval(self):
|
||||
self.interval = (self.time - 0.5 * self.size, self.time + 0.5 * self.size)
|
||||
|
||||
|
||||
def write_time(self, value):
|
||||
self.time = value
|
||||
self.calc_interval()
|
||||
@ -83,53 +80,49 @@ class Roi(Readable):
|
||||
class Pars(Module):
|
||||
description = 'relevant parameters from SEA'
|
||||
|
||||
parameters = {
|
||||
'timestamp': Parameter('unix timestamp', StringType(), default='0', readonly=False),
|
||||
'temperature': Parameter('T', FloatRange(unit='K'), default=0, readonly=False),
|
||||
'mf': Parameter('field', FloatRange(unit='T'), default=0, readonly=False),
|
||||
'sr': Parameter('rotaion angle', FloatRange(unit='deg'), default=0, readonly=False),
|
||||
}
|
||||
timestamp = Parameter('unix timestamp', StringType(), default='0', readonly=False)
|
||||
temperature = Parameter('T', FloatRange(unit='K'), default=0, readonly=False)
|
||||
mf = Parameter('field', FloatRange(unit='T'), default=0, readonly=False)
|
||||
sr = Parameter('rotaion angle', FloatRange(unit='deg'), default=0, readonly=False)
|
||||
|
||||
|
||||
class FreqStringIO(StringIO):
|
||||
end_of_line = '\r'
|
||||
|
||||
|
||||
|
||||
|
||||
class Frequency(HasIodev, Readable):
|
||||
properties = {
|
||||
'pars': Attached(),
|
||||
'sr': Property('samples per record', datatype=IntRange(), default=16384),
|
||||
'maxy': Property('plot y scale', datatype=FloatRange(), default=0.5),
|
||||
}
|
||||
parameters = {
|
||||
'value': Override('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0),
|
||||
'basefreq': Parameter('base frequency', FloatRange(unit='Hz'), readonly=False),
|
||||
'nr': Parameter('number of records', datatype=IntRange(1,10000), default=500),
|
||||
'freq': Parameter('target frequency', FloatRange(unit='Hz'), readonly=False, poll=True),
|
||||
'amp': Parameter('amplitude', FloatRange(unit='dBm'), readonly=False, poll=True),
|
||||
'control': Parameter('control loop on?', BoolType(), readonly=False, default=True),
|
||||
'time': Parameter('pulse start time', FloatRange(unit='nsec'),
|
||||
readonly=False),
|
||||
'size': Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
|
||||
readonly=False),
|
||||
'pulselen': Parameter('adjusted pulse length (integer number of periods)', FloatRange(unit='nsec'), default=1),
|
||||
'maxstep': Parameter('max frequency step', FloatRange(unit='Hz'), readonly=False,
|
||||
default=10000),
|
||||
'minstep': Parameter('min frequency step for slope calculation', FloatRange(unit='Hz'),
|
||||
readonly=False, default=4000),
|
||||
'slope': Parameter('inphase/frequency slope', FloatRange(), readonly=False,
|
||||
default=1e6),
|
||||
'plot': Parameter('create plot images', BoolType(), readonly=False, default=True),
|
||||
'save': Parameter('save data', BoolType(), readonly=False, default=True),
|
||||
'pollinterval': Override(datatype=FloatRange(0,120)),
|
||||
}
|
||||
pars = Attached()
|
||||
sr = Property('samples per record', datatype=IntRange(), default=16384)
|
||||
maxy = Property('plot y scale', datatype=FloatRange(), default=0.5)
|
||||
|
||||
value = Parameter('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0)
|
||||
basefreq = Parameter('base frequency', FloatRange(unit='Hz'), readonly=False)
|
||||
nr = Parameter('number of records', datatype=IntRange(1,10000), default=500)
|
||||
freq = Parameter('target frequency', FloatRange(unit='Hz'), readonly=False, poll=True)
|
||||
amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False, poll=True)
|
||||
control = Parameter('control loop on?', BoolType(), readonly=False, default=True)
|
||||
time = Parameter('pulse start time', FloatRange(unit='nsec'),
|
||||
readonly=False)
|
||||
size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
|
||||
readonly=False)
|
||||
pulselen = Parameter('adjusted pulse length (integer number of periods)', FloatRange(unit='nsec'), default=1)
|
||||
maxstep = Parameter('max frequency step', FloatRange(unit='Hz'), readonly=False,
|
||||
default=10000)
|
||||
minstep = Parameter('min frequency step for slope calculation', FloatRange(unit='Hz'),
|
||||
readonly=False, default=4000)
|
||||
slope = Parameter('inphase/frequency slope', FloatRange(), readonly=False,
|
||||
default=1e6)
|
||||
plot = Parameter('create plot images', BoolType(), readonly=False, default=True)
|
||||
save = Parameter('save data', BoolType(), readonly=False, default=True)
|
||||
pollinterval = Parameter(datatype=FloatRange(0,120))
|
||||
|
||||
iodevClass = FreqStringIO
|
||||
|
||||
lastfreq = None
|
||||
old = None
|
||||
starttime = None
|
||||
interval = (0,0)
|
||||
|
||||
|
||||
def earlyInit(self):
|
||||
#assert self.iodev.startswith('serial:')
|
||||
#self._iodev = serial.Serial(self.iodev[7:])
|
||||
@ -142,30 +135,30 @@ class Frequency(HasIodev, Readable):
|
||||
|
||||
def calc_interval(self):
|
||||
self.interval = (self.time, self.time + self.size)
|
||||
|
||||
|
||||
def write_time(self, value):
|
||||
self.time = value
|
||||
self.calc_interval()
|
||||
return Done
|
||||
|
||||
|
||||
def write_size(self, value):
|
||||
self.size = value
|
||||
self.calc_interval()
|
||||
return Done
|
||||
|
||||
|
||||
def write_nr(self, value):
|
||||
# self.pollinterval = value * 0.0001
|
||||
return value
|
||||
|
||||
|
||||
def register_roi(self, roi):
|
||||
self.roilist.append(roi)
|
||||
|
||||
|
||||
def set_freq(self):
|
||||
freq = self.freq + self.basefreq
|
||||
reply = self.sendRecv('FREQ %.15g;FREQ?' % freq)
|
||||
self.sendRecv('FREQ %.15g;FREQ?' % freq)
|
||||
#self._iodev.readline().decode('ascii')
|
||||
return freq
|
||||
|
||||
|
||||
def write_amp(self, amp):
|
||||
reply = self.sendRecv('AMPR %g;AMPR?' % amp)
|
||||
return float(reply)
|
||||
@ -173,11 +166,11 @@ class Frequency(HasIodev, Readable):
|
||||
def read_amp(self):
|
||||
reply = self.sendRecv('AMPR?')
|
||||
return float(reply)
|
||||
|
||||
|
||||
def write_freq(self, value):
|
||||
self.skipctrl = 2 # suppress control for the 2 next steps
|
||||
return value
|
||||
|
||||
|
||||
def read_freq(self):
|
||||
"""used as main polling loop body"""
|
||||
if self.lastfreq is None:
|
||||
@ -197,7 +190,7 @@ class Frequency(HasIodev, Readable):
|
||||
self.adq.start() # start next acq
|
||||
times.append(('start',time.time()))
|
||||
roilist = [r for r in self.roilist if r.enable]
|
||||
|
||||
|
||||
gates = self.adq.gates_and_curves(data, freq, self.interval,
|
||||
[r.interval for r in roilist])
|
||||
if self.save:
|
||||
|
Reference in New Issue
Block a user