make most important classes available from secop

+ consmetic changes to make PyCharm more happy
+ update authorship

Change-Id: I67cb61a04e502b207be74cea4ca07931c88fdafe
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/22070
Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
2019-12-20 14:31:50 +01:00
parent e2cc9f74b5
commit 795759786f
15 changed files with 161 additions and 148 deletions

View File

@ -84,12 +84,12 @@ class Main(HasIodev, Module):
class ResChannel(HasIodev, Readable):
'''temperature channel on Lakeshore 336'''
"""temperature channel on Lakeshore 336"""
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]}
RES_SCALE = [2 * 10 ** (0.5 * i) for i in range(-7,16)] # RES_SCALE[0] is not used
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]}
@ -162,7 +162,7 @@ class ResChannel(HasIodev, Readable):
lim = 0.2
while rng > self.minrange and abs(result) < lim * self.RES_SCALE[rng]:
rng -= 1
lim -= 0.05 # not more than 4 steps at once
lim -= 0.05 # not more than 4 steps at once
# effectively: <0.16 %: 4 steps, <1%: 3 steps, <5%: 2 steps, <20%: 1 step
if lim != 0.2:
self.log.info('chan %d: lowered range to %.3g' %
@ -182,7 +182,7 @@ class ResChannel(HasIodev, Readable):
if not self.enabled:
return [self.Status.DISABLED, 'disabled']
result = int(self.sendRecv('RDGST?%d' % self.channel))
result &= 0x37 # mask T_OVER and T_UNDER (change this when implementing temperatures instead of resistivities)
result &= 0x37 # mask T_OVER and T_UNDER (change this when implementing temperatures instead of resistivities)
statustext = STATUS_TEXT[result]
if statustext:
return [self.Status.ERROR, statustext]
@ -205,13 +205,13 @@ class ResChannel(HasIodev, Readable):
def change_rdgrng(self, change):
iscur, exc, rng, autorange, excoff = change.readValues()
if change.doesInclude('vexc'): # in case vext is changed, do not consider iexc
if change.doesInclude('vexc'): # in case vext is changed, do not consider iexc
change.iexc = 0
if change.iexc != 0: # we need '!= 0' here, as bool(enum) is always True!
if change.iexc != 0: # we need '!= 0' here, as bool(enum) is always True!
iscur = 1
exc = change.iexc
excoff = 0
elif change.vexc != 0: # we need '!= 0' here, as bool(enum) is always True!
elif change.vexc != 0: # we need '!= 0' here, as bool(enum) is always True!
iscur = 0
exc = change.vexc
excoff = 0
@ -240,5 +240,5 @@ class ResChannel(HasIodev, Readable):
def change_filter(self, change):
_, settle, window = change.readValues()
if change.filter:
return 1, change.filter, 80 # always use 80% filter
return 1, change.filter, 80 # always use 80% filter
return 0, settle, window

View File

@ -53,7 +53,7 @@ except ImportError:
class CmdHandler(secop.commandhandler.CmdHandler):
CMDARGS = ['no']
CMDSEPARATOR = None # no command chaining
CMDSEPARATOR = None # no command chaining
READ_BEFORE_WRITE = False
def __init__(self, name, querycmd, replyfmt):
@ -68,7 +68,7 @@ class Main(Communicator):
'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
'data': Parameter('internal', poll=True, export=True, # export for test only
default="", readonly=True, datatype=StringType()),
}
properties = {
@ -100,7 +100,7 @@ class Main(Communicator):
return reply
def read_data(self):
mask = 1 # always get packed_status
mask = 1 # always get packed_status
for channelname, channel in self.modules.items():
if channel.enabled:
mask |= 1 << self._channel_to_index.get(channelname, 0)
@ -108,7 +108,7 @@ class Main(Communicator):
data = self.do_communicate('GETDAT? %d' % mask)
reply = data.split(',')
mask = int(reply.pop(0))
reply.pop(0) # pop timestamp
reply.pop(0) # pop timestamp
result = {}
for bitpos, channelname in enumerate(self._channel_names):
if mask & (1 << bitpos):
@ -118,10 +118,10 @@ class Main(Communicator):
if 'ts' in result:
result['temp'] = result['ts']
packed_status = int(result['packed_status'])
result['chamber'] = None # 'chamber' must be in result for status, but value is ignored
result['chamber'] = None # 'chamber' must be in result for status, but value is ignored
for channelname, channel in self.modules.items():
channel.update_value_status(result.get(channelname, None), packed_status)
return data # return data as string
return data # return data as string
class PpmsMixin(HasIodev, Module):
@ -130,9 +130,9 @@ class PpmsMixin(HasIodev, Module):
}
pollerClass = Poller
enabled = True # default, if no parameter enable is defined
_last_target_change = 0 # used by several modules
_last_settings = None # used by several modules
enabled = True # default, if no parameter enable is defined
_last_target_change = 0 # used by several modules
_last_settings = None # used by several modules
slow_pollfactor = 1
def initModule(self):
@ -188,7 +188,7 @@ class Channel(PpmsMixin, Readable):
datatype=StringType(), export=False, default=''),
'no':
Property('channel number',
datatype=IntRange(1, 4), export=False),
datatype=IntRange(1, 4), export=False),
}
def earlyInit(self):
@ -208,7 +208,7 @@ class UserChannel(Channel):
properties = {
'no':
Property('channel number',
datatype=IntRange(0, 0), export=False, default=0),
datatype=IntRange(0, 0), export=False, default=0),
}
@ -307,7 +307,7 @@ class Level(PpmsMixin, Readable):
self.status = [self.Status.IDLE, '']
else:
self.status = [self.Status.ERROR, 'old reading']
return dict(value = level)
return dict(value=level)
class Chamber(PpmsMixin, Drivable):
@ -448,7 +448,7 @@ class Temp(PpmsMixin, Drivable):
channel = 'temp'
_stopped = False
_expected_target = 0
_last_change = 0 # 0 means no target change is pending
_last_change = 0 # 0 means no target change is pending
def earlyInit(self):
self.setProperty('general_stop', False)
@ -469,7 +469,7 @@ class Temp(PpmsMixin, Drivable):
else:
self.status = [self.Status.IDLE, 'stopped(%s)' % status[1]]
return
if self._last_change: # there was a change, which is not yet confirmed by hw
if self._last_change: # there was a change, which is not yet confirmed by hw
if now > self._last_change + 5:
self._last_change = 0 # give up waiting for busy
elif self.isDriving(status) and status != self._status_before_change:
@ -510,12 +510,12 @@ class Temp(PpmsMixin, Drivable):
def write_approachmode(self, value):
if self.isDriving():
return value
return None # change_temp will not be called, as this would trigger an unnecessary T change
return None # change_temp will not be called, as this would trigger an unnecessary T change
def write_ramp(self, value):
if self.isDriving():
return value
return None # change_temp will not be called, as this would trigger an unnecessary T change
return None # change_temp will not be called, as this would trigger an unnecessary T change
def calc_expected(self, target, ramp):
self._expected_target = time.time() + abs(target - self.value) * 60.0 / max(0.1, ramp)
@ -545,7 +545,7 @@ class Field(PpmsMixin, Drivable):
FINALIZING = 390,
)
# pylint: disable=invalid-name
PersistentMode = Enum('PersistentMode', persistent = 0, driven = 1)
PersistentMode = Enum('PersistentMode', persistent=0, driven=1)
ApproachMode = Enum('ApproachMode', linear=0, no_overshoot=1, oscillate=2)
parameters = {
@ -554,7 +554,7 @@ class Field(PpmsMixin, Drivable):
'status':
Override(datatype=StatusType(Status), poll=True),
'target':
Override(datatype=FloatRange(-15,15,unit='T'), handler=field),
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')),
@ -584,7 +584,7 @@ class Field(PpmsMixin, Drivable):
channel = 'field'
_stopped = False
_last_target = 0
_last_change= 0 # means no target change is pending
_last_change = 0 # means no target change is pending
def update_value_status(self, value, packed_status):
"""update value and status"""
@ -602,8 +602,8 @@ class Field(PpmsMixin, Drivable):
else:
self.status = [status[0], 'stopped (%s)' % status[1]]
return
elif self._last_change: # there was a change, which is not yet confirmed by hw
if status_code == 1: # persistent mode
elif self._last_change: # there was a change, which is not yet confirmed by hw
if status_code == 1: # persistent mode
# leads are ramping (ppms has no extra status code for this!)
if now < self._last_change + 30:
status = [self.Status.PREPARING, 'ramping leads']
@ -637,7 +637,7 @@ class Field(PpmsMixin, Drivable):
else:
# changed ramp or approachmode
if not self.isDriving():
return None # nothing to be written, as this would trigger a ramp up of leads current
return None # nothing to be written, as this would trigger a ramp up of leads current
return change.target * 1e+4, change.ramp / 6e-3, change.approachmode, change.persistentmode
def do_stop(self):
@ -685,7 +685,7 @@ class Position(PpmsMixin, Drivable):
channel = 'position'
_stopped = False
_last_target = 0
_last_change = 0 # means no target change is pending
_last_change = 0 # means no target change is pending
def update_value_status(self, value, packed_status):
"""update value and status"""
@ -703,10 +703,10 @@ class Position(PpmsMixin, Drivable):
self._stopped = False
else:
status = [self.Status.IDLE, 'stopped(%s)' % status[1]]
if self._last_change: # there was a change, which is not yet confirmed by hw
if self._last_change: # there was a change, which is not yet confirmed by hw
now = time.time()
if now > self._last_change + 5:
self._last_change = 0 # give up waiting for busy
self._last_change = 0 # give up waiting for busy
elif self.isDriving() and status != self._status_before_change:
self._last_change = 0
self.log.debug('time needed to change to busy: %.3g', now - self._last_change)
@ -727,7 +727,7 @@ class Position(PpmsMixin, Drivable):
return change.target, 0, speed
def write_target(self, target):
self._last_target = self.target # save for stop command
self._last_target = self.target # save for stop command
self._stopped = False
self._last_change = 0
self._status_before_change = self.status
@ -736,7 +736,7 @@ class Position(PpmsMixin, Drivable):
def write_speed(self, value):
if self.isDriving():
return value
return None # change_move not called: as this would trigger an unnecessary move
return None # change_move not called: as this would trigger an unnecessary move
def do_stop(self):
if not self.isDriving():

View File

@ -27,9 +27,11 @@ except ImportError:
print("This Module only works with a pythoncom module on a MS Windows OS")
raise
class Error(Exception):
pass
class QDevice:
def __init__(self, classid):
self.threadlocal = threading.local()
@ -44,19 +46,20 @@ class QDevice:
self.threadlocal.mvu = mvu
args = [
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, command),
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, ""), # reply
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, ""), # error
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0), # ?
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)] # ?
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, ""), # reply
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, ""), # error
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0), # ?
win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)] # ?
err = mvu.SendPpmsCommand(*args)
# win32com does invert the order of results!
if err == 0:
#print '<', args[3].value
# print '<', args[3].value
return args[3].value
if err == 1:
#print '<done'
# print '<done'
return "OK"
raise Error(args[2].value.replace('\n', ' '))
if __name__ == "__main__": # test only
if __name__ == "__main__": # test only
print(QDevice('QD.MULTIVU.PPMS.1').send('LEVEL?'))