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:
parent
e2cc9f74b5
commit
795759786f
@ -19,9 +19,19 @@
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
# allow to import the most important classes from 'secop'
|
||||
from secop.datatypes import *
|
||||
from secop.modules import Module, Readable, Writable, Drivable, Communicator, Attached
|
||||
from secop.params import Parameter, Command, Override
|
||||
from secop.metaclass import Done
|
||||
from secop.commandhandler import CmdHandler, CmdHandlerBase
|
||||
from secop.stringio import StringIO, HasIodev
|
||||
|
||||
|
||||
try:
|
||||
import sip
|
||||
sip.setapi('QString', 2)
|
||||
|
@ -58,7 +58,6 @@ from secop.metaclass import Done
|
||||
from secop.errors import ProgrammingError
|
||||
|
||||
|
||||
|
||||
class CmdParser:
|
||||
"""helper for parsing replies
|
||||
|
||||
@ -71,11 +70,10 @@ class CmdParser:
|
||||
for letters, cast in (
|
||||
('d', int),
|
||||
('s', str), # 'c' is treated separately
|
||||
('o', lambda x:int(x, 8)),
|
||||
('xX', lambda x:int(x, 16)),
|
||||
('o', lambda x: int(x, 8)),
|
||||
('xX', lambda x: int(x, 16)),
|
||||
('eEfFgG', float),
|
||||
) for letter in letters
|
||||
}
|
||||
) for letter in letters}
|
||||
# pattern for chacaters to be escaped
|
||||
ESC_PAT = re.compile('([\\%s])' % '\\'.join('|^$-.+*?()[]{}<>'))
|
||||
# format pattern
|
||||
@ -97,7 +95,7 @@ class CmdParser:
|
||||
todofmt = None # format set aside to be treated in next loop
|
||||
|
||||
# loop over found formats and separators
|
||||
for fmt, sep in zip(spl_iter,spl_iter):
|
||||
for fmt, sep in zip(spl_iter, spl_iter):
|
||||
if fmt == '%%':
|
||||
if todofmt is None:
|
||||
pat.append('%' + escaped(sep)) # plain text
|
||||
@ -154,7 +152,7 @@ class Change:
|
||||
self._module = module
|
||||
self._valuedict = valuedict
|
||||
self._to_be_changed = set(self._valuedict)
|
||||
self._do_read = True
|
||||
self._reply = None
|
||||
|
||||
def __getattr__(self, key):
|
||||
"""return attribute from module key is not in self._valuedict"""
|
||||
@ -171,8 +169,7 @@ class Change:
|
||||
|
||||
and update our parameter attributes accordingly (i.e. do not touch the new values)
|
||||
"""
|
||||
if self._do_read:
|
||||
self._do_read = False
|
||||
if self._reply is None:
|
||||
self._reply = self._handler.send_command(self._module)
|
||||
result = self._handler.analyze(self._module, *self._reply)
|
||||
result.update(self._valuedict)
|
||||
@ -314,11 +311,8 @@ class CmdHandler(CmdHandlerBase):
|
||||
|
||||
implementing classes have to define/override the following:
|
||||
"""
|
||||
CMDARGS = [] # list of properties or parameters to be used for building
|
||||
# some of the the query and change commands
|
||||
CMDSEPARATOR = ';' # if given, it is valid to join a command a a query with
|
||||
# the given separator
|
||||
|
||||
CMDARGS = [] # list of properties or parameters to be used for building some of the the query and change commands
|
||||
CMDSEPARATOR = ';' # if given, it is valid to join a command a a query with the given separator
|
||||
|
||||
def __init__(self, group, querycmd, replyfmt, changecmd=None):
|
||||
"""initialize the command handler
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define validated data types."""
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define Metaclass for Modules/Features"""
|
||||
@ -30,14 +31,15 @@ from secop.params import Command, Override, Parameter
|
||||
from secop.datatypes import EnumType
|
||||
from secop.properties import PropertyMeta
|
||||
|
||||
|
||||
EVENT_ONLY_ON_CHANGED_VALUES = False
|
||||
|
||||
|
||||
class Done:
|
||||
"""a special return value for a read/write function
|
||||
|
||||
indicating that the setter is triggered already"""
|
||||
|
||||
|
||||
# warning: MAGIC!
|
||||
|
||||
class ModuleMeta(PropertyMeta):
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define Baseclasses for real Modules implemented in the server"""
|
||||
@ -190,7 +191,7 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
||||
self.writeDict = {} # values of parameters to be written
|
||||
for pname, pobj in self.parameters.items():
|
||||
if pname in cfgdict:
|
||||
if not pobj.readonly and not pobj.initwrite is False:
|
||||
if not pobj.readonly and pobj.initwrite is not False:
|
||||
# parameters given in cfgdict have to call write_<pname>
|
||||
try:
|
||||
pobj.value = pobj.datatype(cfgdict[pname])
|
||||
@ -264,7 +265,7 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
||||
self.DISPATCHER.announce_update_error(self, pname, pobj, exception)
|
||||
|
||||
def isBusy(self, status=None):
|
||||
'''helper function for treating substates of BUSY correctly'''
|
||||
"""helper function for treating substates of BUSY correctly"""
|
||||
# defined even for non drivable (used for dynamic polling)
|
||||
return False
|
||||
|
||||
@ -276,25 +277,24 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
||||
self.log.debug('empty %s.initModule()' % self.__class__.__name__)
|
||||
|
||||
def startModule(self, started_callback):
|
||||
'''runs after init of all modules
|
||||
"""runs after init of all modules
|
||||
|
||||
started_callback to be called when thread spawned by late_init
|
||||
or, if not implemented, immediately
|
||||
might return a timeout value, if different from default
|
||||
'''
|
||||
|
||||
"""
|
||||
self.log.debug('empty %s.startModule()' % self.__class__.__name__)
|
||||
started_callback()
|
||||
|
||||
def pollOneParam(self, pname):
|
||||
"""poll parameter <pname> with proper error handling"""
|
||||
try:
|
||||
return getattr(self, 'read_'+ pname)()
|
||||
except SilentError as e:
|
||||
return getattr(self, 'read_' + pname)()
|
||||
except SilentError:
|
||||
pass
|
||||
except SECoPError as e:
|
||||
self.log.error(str(e))
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.log.error(formatException())
|
||||
|
||||
def writeOrPoll(self, pname):
|
||||
@ -305,14 +305,14 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
||||
try:
|
||||
if pname in self.writeDict:
|
||||
self.log.debug('write parameter %s', pname)
|
||||
getattr(self, 'write_'+ pname)(self.writeDict.pop(pname))
|
||||
getattr(self, 'write_' + pname)(self.writeDict.pop(pname))
|
||||
else:
|
||||
getattr(self, 'read_'+ pname)()
|
||||
except SilentError as e:
|
||||
getattr(self, 'read_' + pname)()
|
||||
except SilentError:
|
||||
pass
|
||||
except SECoPError as e:
|
||||
self.log.error(str(e))
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.log.error(formatException())
|
||||
|
||||
|
||||
@ -348,7 +348,7 @@ class Readable(Module):
|
||||
}
|
||||
|
||||
def startModule(self, started_callback):
|
||||
'''start basic polling thread'''
|
||||
"""start basic polling thread"""
|
||||
if issubclass(self.pollerClass, BasicPoller):
|
||||
# use basic poller for legacy code
|
||||
mkthread(self.__pollThread, started_callback)
|
||||
@ -423,15 +423,15 @@ class Drivable(Writable):
|
||||
}
|
||||
|
||||
overrides = {
|
||||
'status' : Override(datatype=TupleOf(EnumType(Status), StringType())),
|
||||
'status': Override(datatype=TupleOf(EnumType(Status), StringType())),
|
||||
}
|
||||
|
||||
def isBusy(self, status=None):
|
||||
'''helper function for treating substates of BUSY correctly'''
|
||||
"""helper function for treating substates of BUSY correctly"""
|
||||
return 300 <= (status or self.status)[0] < 400
|
||||
|
||||
def isDriving(self, status=None):
|
||||
'''helper function (finalize is busy, not driving)'''
|
||||
"""helper function (finalize is busy, not driving)"""
|
||||
return 300 <= (status or self.status)[0] < 390
|
||||
|
||||
# improved polling: may poll faster if module is BUSY
|
||||
@ -472,7 +472,6 @@ class Communicator(Module):
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Attached(Property):
|
||||
# we can not put this to properties.py, as it needs datatypes
|
||||
def __init__(self, attrname=None):
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define classes for Parameters/Commands and Overriding them"""
|
||||
|
@ -19,7 +19,7 @@
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
'''general, advanced frappy poller
|
||||
"""general, advanced frappy poller
|
||||
|
||||
Usage examples:
|
||||
any Module which want to be polled with a specific Poller must define
|
||||
@ -31,7 +31,7 @@ Usage examples:
|
||||
...
|
||||
|
||||
modules having a parameter 'iodev' with the same value will share the same poller
|
||||
'''
|
||||
"""
|
||||
|
||||
import time
|
||||
from threading import Event
|
||||
@ -45,6 +45,7 @@ SLOW = 2
|
||||
REGULAR = 3
|
||||
DYNAMIC = 4
|
||||
|
||||
|
||||
class PollerBase:
|
||||
|
||||
startup_timeout = 30 # default timeout for startup
|
||||
@ -52,12 +53,12 @@ class PollerBase:
|
||||
|
||||
@classmethod
|
||||
def add_to_table(cls, table, module):
|
||||
'''sort module into poller table
|
||||
"""sort module into poller table
|
||||
|
||||
table is a dict, with (<pollerClass>, <name>) as the key, and the
|
||||
poller as value.
|
||||
<name> is module.iodev or module.name, if iodev is not present
|
||||
'''
|
||||
"""
|
||||
# for modules with the same iodev, a common poller is used,
|
||||
# modules without iodev all get their own poller
|
||||
name = getattr(module, 'iodev', module.name)
|
||||
@ -68,26 +69,26 @@ class PollerBase:
|
||||
poller.add_to_poller(module)
|
||||
|
||||
def start(self, started_callback):
|
||||
'''start poller thread
|
||||
"""start poller thread
|
||||
|
||||
started_callback to be called after all poll items were read at least once
|
||||
'''
|
||||
"""
|
||||
mkthread(self.run, started_callback)
|
||||
return self.startup_timeout
|
||||
|
||||
def run(self, started_callback):
|
||||
'''poller thread function
|
||||
"""poller thread function
|
||||
|
||||
started_callback to be called after all poll items were read at least once
|
||||
'''
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def stop(self):
|
||||
'''stop polling'''
|
||||
"""stop polling"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __bool__(self):
|
||||
'''is there any poll item?'''
|
||||
"""is there any poll item?"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __repr__(self):
|
||||
@ -95,7 +96,7 @@ class PollerBase:
|
||||
|
||||
|
||||
class Poller(PollerBase):
|
||||
'''a standard poller
|
||||
"""a standard poller
|
||||
|
||||
parameters may have the following polltypes:
|
||||
|
||||
@ -106,12 +107,12 @@ class Poller(PollerBase):
|
||||
Scheduled to poll every slowfactor * module.pollinterval
|
||||
- DYNAMIC: by default used for 'value' and 'status'
|
||||
When busy, scheduled to poll every fastfactor * module.pollinterval
|
||||
'''
|
||||
"""
|
||||
|
||||
DEFAULT_FACTORS = {SLOW: 4, DYNAMIC: 0.25, REGULAR: 1}
|
||||
|
||||
def __init__(self, name):
|
||||
'''create a poller'''
|
||||
"""create a poller"""
|
||||
self.queues = {polltype: [] for polltype in self.DEFAULT_FACTORS}
|
||||
self._event = Event()
|
||||
self._stopped = False
|
||||
@ -155,7 +156,7 @@ class Poller(PollerBase):
|
||||
polltype = REGULAR
|
||||
else:
|
||||
polltype = SLOW
|
||||
if not polltype in factors:
|
||||
if polltype not in factors:
|
||||
raise ProgrammingError("unknown poll type %r for parameter '%s'"
|
||||
% (polltype, pname))
|
||||
if pobj.handler:
|
||||
@ -167,12 +168,12 @@ class Poller(PollerBase):
|
||||
(0, module, pobj, pname, factors[polltype])))
|
||||
|
||||
def poll_next(self, polltype):
|
||||
'''try to poll next item
|
||||
"""try to poll next item
|
||||
|
||||
advance in queue until
|
||||
- an item is found which is really due to poll. return 0 in this case
|
||||
- or until the next item is not yet due. return next due time in this case
|
||||
'''
|
||||
"""
|
||||
queue = self.queues[polltype]
|
||||
if not queue:
|
||||
return float('inf') # queue is empty
|
||||
@ -211,7 +212,7 @@ class Poller(PollerBase):
|
||||
return True
|
||||
|
||||
def run(self, started_callback):
|
||||
'''start poll loop
|
||||
"""start poll loop
|
||||
|
||||
To be called as a thread. After all parameters are polled once first,
|
||||
started_callback is called. To be called in Module.start_module.
|
||||
@ -221,7 +222,7 @@ class Poller(PollerBase):
|
||||
If more polls are scheduled than time permits, at least every second poll is a
|
||||
dynamic poll. After every n regular polls, one slow poll is done, if due
|
||||
(where n is the number of regular parameters).
|
||||
'''
|
||||
"""
|
||||
if not self:
|
||||
# nothing to do (else we might call time.sleep(float('inf')) below
|
||||
started_callback()
|
||||
@ -255,7 +256,7 @@ class Poller(PollerBase):
|
||||
self._stopped = True
|
||||
|
||||
def __bool__(self):
|
||||
'''is there any poll item?'''
|
||||
"""is there any poll item?"""
|
||||
return any(self.queues.values())
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define validated data types."""
|
||||
|
@ -17,6 +17,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Dispatcher for SECoP Messages
|
||||
@ -50,7 +51,6 @@ from secop.protocol.messages import COMMANDREPLY, DESCRIPTIONREPLY, \
|
||||
HEARTBEATREPLY, IDENTREPLY, IDENTREQUEST, READREPLY, WRITEREPLY
|
||||
|
||||
|
||||
|
||||
def make_update(modulename, pobj):
|
||||
if pobj.readerror:
|
||||
return (ERRORPREFIX + EVENTREPLY, '%s:%s' % (modulename, pobj.export),
|
||||
@ -272,7 +272,7 @@ class Dispatcher:
|
||||
pobj = moduleobj.parameters[pname]
|
||||
if pobj.constant is not None:
|
||||
# really needed? we could just construct a readreply instead....
|
||||
#raise ReadOnlyError('This parameter is constant and can not be accessed remotely.')
|
||||
# raise ReadOnlyError('This parameter is constant and can not be accessed remotely.')
|
||||
return pobj.datatype.export_value(pobj.constant)
|
||||
|
||||
readfunc = getattr(moduleobj, 'read_%s' % pname, None)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""provides tcp interface to the SECoP Server"""
|
||||
@ -45,6 +46,7 @@ SPACE = b' '
|
||||
class OutputBufferOverflow(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def setup(self):
|
||||
@ -80,9 +82,9 @@ class TCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
# send bytestring
|
||||
outmsg = self._queue.popleft()
|
||||
if not outmsg:
|
||||
outmsg = ('error','InternalError', ['<unknown origin>', 'trying to send none-data', {}])
|
||||
outmsg = ('error', 'InternalError', ['<unknown origin>', 'trying to send none-data', {}])
|
||||
if len(outmsg) > 3:
|
||||
outmsg = ('error', 'InternalError', ['<unknown origin>', 'bad message format', {'msg':outmsg}])
|
||||
outmsg = ('error', 'InternalError', ['<unknown origin>', 'bad message format', {'msg': outmsg}])
|
||||
outdata = encode_msg_frame(*outmsg)
|
||||
try:
|
||||
mysocket.sendall(outdata)
|
||||
@ -97,7 +99,7 @@ class TCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
# no timeout error, but no new data -> connection closed
|
||||
return
|
||||
data = data + newdata
|
||||
except socket.timeout as e:
|
||||
except socket.timeout:
|
||||
continue
|
||||
except socket.error as e:
|
||||
self.log.exception(e)
|
||||
@ -118,7 +120,6 @@ class TCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
for idx, line in enumerate(HelpMessage.splitlines()):
|
||||
self.queue_async_reply((HELPREPLY, '%d' % (idx+1), line))
|
||||
continue
|
||||
result = None
|
||||
try:
|
||||
msg = decode_msg(origin)
|
||||
except Exception as err:
|
||||
@ -191,9 +192,9 @@ class TCPServer(HasProperties, socketserver.ThreadingTCPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
properties = {
|
||||
'bindto' : Property('hostname or ip address for binding',StringType(),
|
||||
'bindto': Property('hostname or ip address for binding', StringType(),
|
||||
default='localhost:%d' % DEF_PORT, export=False),
|
||||
'bindport' : Property('port number to bind',IntRange(1,65535),
|
||||
'bindport': Property('port number to bind', IntRange(1, 65535),
|
||||
default=DEF_PORT, export=False),
|
||||
'detailed_errors': Property('Flag to enable detailed Errorreporting.', BoolType(),
|
||||
default=False, export=False),
|
||||
|
@ -18,6 +18,7 @@
|
||||
# Module authors:
|
||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""Define helpers"""
|
||||
@ -56,6 +57,7 @@ class Server:
|
||||
('module', None, None),
|
||||
('interface', "tcp", {"tcp": "protocol.interface.tcp.TCPServer"}),
|
||||
]
|
||||
|
||||
def __init__(self, name, parent_logger=None):
|
||||
cfg = getGeneralConfig()
|
||||
|
||||
@ -120,15 +122,13 @@ class Server:
|
||||
def _processCfg(self):
|
||||
self.log.debug('Parse config file %s ...' % self._cfgfile)
|
||||
|
||||
parser = configparser.SafeConfigParser()
|
||||
parser = configparser.ConfigParser()
|
||||
parser.optionxform = str
|
||||
|
||||
if not parser.read([self._cfgfile]):
|
||||
self.log.error('Couldn\'t read cfg file !')
|
||||
raise ConfigError('Couldn\'t read cfg file %r' % self._cfgfile)
|
||||
|
||||
|
||||
|
||||
for kind, devtype, classmapping in self.CFGSECTIONS:
|
||||
kinds = '%ss' % kind
|
||||
objs = OrderedDict()
|
||||
@ -180,12 +180,12 @@ class Server:
|
||||
raise ConfigError('cfgfile %r: needs exactly one node section!' % self._cfgfile)
|
||||
self.dispatcher, = tuple(self.nodes.values())
|
||||
|
||||
pollTable = dict()
|
||||
poll_table = dict()
|
||||
# all objs created, now start them up and interconnect
|
||||
for modname, modobj in self.modules.items():
|
||||
self.log.info('registering module %r' % modname)
|
||||
self.dispatcher.register_module(modobj, modname, modobj.properties['export'])
|
||||
modobj.pollerClass.add_to_table(pollTable, modobj)
|
||||
modobj.pollerClass.add_to_table(poll_table, modobj)
|
||||
# also call earlyInit on the modules
|
||||
modobj.earlyInit()
|
||||
|
||||
@ -205,7 +205,7 @@ class Server:
|
||||
# startModule must return either a timeout value or None (default 30 sec)
|
||||
timeout = modobj.startModule(started_callback=event.set) or 30
|
||||
start_events.append((time.time() + timeout, 'module %s' % modname, event))
|
||||
for poller in pollTable.values():
|
||||
for poller in poll_table.values():
|
||||
event = threading.Event()
|
||||
# poller.start must return either a timeout value or None (default 30 sec)
|
||||
timeout = poller.start(started_callback=event.set) or 30
|
||||
|
@ -216,12 +216,12 @@ class StringIO(Communicator):
|
||||
self._reconnectCallbacks.pop(key)
|
||||
|
||||
def do_communicate(self, command):
|
||||
'''send a command and receive a reply
|
||||
"""send a command and receive a reply
|
||||
|
||||
using end_of_line, encoding and self._lock
|
||||
for commands without reply, join it with a query command,
|
||||
wait_before is respected for end_of_lines within a command.
|
||||
'''
|
||||
"""
|
||||
if not self.is_connected:
|
||||
self.read_is_connected() # try to reconnect
|
||||
try:
|
||||
|
@ -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]}
|
||||
|
@ -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):
|
||||
@ -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"""
|
||||
|
@ -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()
|
||||
@ -51,12 +53,13 @@ class QDevice:
|
||||
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
|
||||
print(QDevice('QD.MULTIVU.PPMS.1').send('LEVEL?'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user