make secop.poller.Poller default
modules using the old poller (now called secop.poller.BasicPoller) need to explcitly declare it (pollerClass = BasicPoller) BasicPoller is still used in: secop_mlz/amagnet.py secop_mlz/entangle.py secop/simulation.py Remark: before removing BasicPoller we may need a replacement for Readable.pollParams Change-Id: If1ae8b68e02f13e601334656b818337c882e06cc Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/21910 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
ca8b07496f
commit
59fbd5cac0
@ -30,11 +30,12 @@ from secop.datatypes import EnumType, FloatRange, BoolType, IntRange, \
|
|||||||
StringType, TupleOf, get_datatype, ArrayOf, TextType
|
StringType, TupleOf, get_datatype, ArrayOf, TextType
|
||||||
from secop.errors import ConfigError, ProgrammingError
|
from secop.errors import ConfigError, ProgrammingError
|
||||||
from secop.lib import formatException, \
|
from secop.lib import formatException, \
|
||||||
formatExtendedStack, mkthread, unset_value
|
formatExtendedStack, mkthread
|
||||||
from secop.lib.enum import Enum
|
from secop.lib.enum import Enum
|
||||||
from secop.metaclass import ModuleMeta
|
from secop.metaclass import ModuleMeta
|
||||||
from secop.params import PREDEFINED_ACCESSIBLES, Command, Override, Parameter, Parameters, Commands
|
from secop.params import PREDEFINED_ACCESSIBLES, Command, Override, Parameter, Parameters, Commands
|
||||||
from secop.properties import HasProperties, Property
|
from secop.properties import HasProperties, Property
|
||||||
|
from secop.poller import Poller, BasicPoller
|
||||||
|
|
||||||
|
|
||||||
# XXX: connect with 'protocol'-Modules.
|
# XXX: connect with 'protocol'-Modules.
|
||||||
@ -86,6 +87,8 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
|||||||
# reference to the dispatcher (used for sending async updates)
|
# reference to the dispatcher (used for sending async updates)
|
||||||
DISPATCHER = None
|
DISPATCHER = None
|
||||||
|
|
||||||
|
pollerClass = Poller
|
||||||
|
|
||||||
def __init__(self, name, logger, cfgdict, srv):
|
def __init__(self, name, logger, cfgdict, srv):
|
||||||
# remember the dispatcher object (for the async callbacks)
|
# remember the dispatcher object (for the async callbacks)
|
||||||
self.DISPATCHER = srv.dispatcher
|
self.DISPATCHER = srv.dispatcher
|
||||||
@ -179,13 +182,14 @@ class Module(HasProperties, metaclass=ModuleMeta):
|
|||||||
# is not specified in cfgdict
|
# is not specified in cfgdict
|
||||||
for k, v in self.parameters.items():
|
for k, v in self.parameters.items():
|
||||||
if k not in cfgdict:
|
if k not in cfgdict:
|
||||||
if v.default is unset_value and k != 'value':
|
if v.default is None:
|
||||||
# unset_value is the one single value you can not specify....
|
if not v.poll:
|
||||||
raise ConfigError('Module %s: Parameter %r has no default '
|
raise ConfigError('Module %s: Parameter %r has no default '
|
||||||
'value and was not given in config!' %
|
'value and was not given in config!' %
|
||||||
(self.name, k))
|
(self.name, k))
|
||||||
# assume default value was given
|
cfgdict[k] = v.datatype.default
|
||||||
cfgdict[k] = v.default
|
else:
|
||||||
|
cfgdict[k] = v.default
|
||||||
|
|
||||||
# 5) 'apply' config:
|
# 5) 'apply' config:
|
||||||
# pass values through the datatypes and store as attributes
|
# pass values through the datatypes and store as attributes
|
||||||
@ -265,7 +269,7 @@ class Readable(Module):
|
|||||||
parameters = {
|
parameters = {
|
||||||
'value': Parameter('current value of the Module', readonly=True,
|
'value': Parameter('current value of the Module', readonly=True,
|
||||||
default=0., datatype=FloatRange(),
|
default=0., datatype=FloatRange(),
|
||||||
unit='', poll=True,
|
poll=True,
|
||||||
),
|
),
|
||||||
'pollinterval': Parameter('sleeptime between polls', default=5,
|
'pollinterval': Parameter('sleeptime between polls', default=5,
|
||||||
readonly=False,
|
readonly=False,
|
||||||
@ -279,12 +283,12 @@ class Readable(Module):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def startModule(self, started_callback):
|
def startModule(self, started_callback):
|
||||||
'''start polling thread'''
|
'''start basic polling thread'''
|
||||||
if hasattr(self, 'pollerClass'): # an other poller is used
|
if issubclass(self.pollerClass, BasicPoller):
|
||||||
started_callback()
|
# use basic poller for legacy code
|
||||||
else:
|
|
||||||
# basic poller kept for reference
|
|
||||||
mkthread(self.__pollThread, started_callback)
|
mkthread(self.__pollThread, started_callback)
|
||||||
|
else:
|
||||||
|
started_callback()
|
||||||
|
|
||||||
def __pollThread(self, started_callback):
|
def __pollThread(self, started_callback):
|
||||||
while True:
|
while True:
|
||||||
|
@ -58,17 +58,13 @@ class PollerBase:
|
|||||||
poller as value.
|
poller as value.
|
||||||
<name> is module.iodev or module.name, if iodev is not present
|
<name> is module.iodev or module.name, if iodev is not present
|
||||||
'''
|
'''
|
||||||
try:
|
|
||||||
pollerClass = module.pollerClass
|
|
||||||
except AttributeError:
|
|
||||||
return # no pollerClass -> fall back to simple poller
|
|
||||||
# for modules with the same iodev, a common poller is used,
|
# for modules with the same iodev, a common poller is used,
|
||||||
# modules without iodev all get their own poller
|
# modules without iodev all get their own poller
|
||||||
name = getattr(module, 'iodev', module.name)
|
name = getattr(module, 'iodev', module.name)
|
||||||
poller = table.get((pollerClass, name), None)
|
poller = table.get((cls, name), None)
|
||||||
if poller is None:
|
if poller is None:
|
||||||
poller = pollerClass(name)
|
poller = cls(name)
|
||||||
table[(pollerClass, name)] = poller
|
table[(cls, name)] = poller
|
||||||
poller.add_to_poller(module)
|
poller.add_to_poller(module)
|
||||||
|
|
||||||
def start(self, started_callback):
|
def start(self, started_callback):
|
||||||
@ -97,8 +93,6 @@ class PollerBase:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%r)' % (self.__class__.__name__, self.name)
|
return '%s(%r)' % (self.__class__.__name__, self.name)
|
||||||
|
|
||||||
__nonzero__ = __bool__ # Py2/3 compat
|
|
||||||
|
|
||||||
|
|
||||||
class Poller(PollerBase):
|
class Poller(PollerBase):
|
||||||
'''a standard poller
|
'''a standard poller
|
||||||
@ -246,4 +240,14 @@ class Poller(PollerBase):
|
|||||||
'''is there any poll item?'''
|
'''is there any poll item?'''
|
||||||
return any(self.queues.values())
|
return any(self.queues.values())
|
||||||
|
|
||||||
__nonzero__ = __bool__ # Py2/3 compat
|
|
||||||
|
class BasicPoller(PollerBase):
|
||||||
|
"""basic poller
|
||||||
|
|
||||||
|
this is just a dummy, the poller thread is started in Readable.startModule
|
||||||
|
"""
|
||||||
|
# pylint: disable=abstract-method
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_to_table(cls, table, module):
|
||||||
|
pass
|
||||||
|
@ -122,8 +122,9 @@ class TCPRequestHandler(socketserver.BaseRequestHandler):
|
|||||||
try:
|
try:
|
||||||
msg = decode_msg(origin)
|
msg = decode_msg(origin)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
# we have to decode 'origin' here. utf-8 and ascii may lead to encoding errors
|
# we have to decode 'origin' here
|
||||||
msg = origin.decode('latin-1').split(' ', 3)
|
# use latin-1, as utf-8 or ascii may lead to encoding errors
|
||||||
|
msg = origin.decode('latin-1').split(' ', 3) + (None,) # make sure len(msg) > 1
|
||||||
result = (ERRORPREFIX + msg[0], msg[1], ['InternalError', str(err),
|
result = (ERRORPREFIX + msg[0], msg[1], ['InternalError', str(err),
|
||||||
{'exception': formatException(),
|
{'exception': formatException(),
|
||||||
'traceback': formatExtendedStack()}])
|
'traceback': formatExtendedStack()}])
|
||||||
|
@ -185,10 +185,7 @@ class Server:
|
|||||||
for modname, modobj in self.modules.items():
|
for modname, modobj in self.modules.items():
|
||||||
self.log.info('registering module %r' % modname)
|
self.log.info('registering module %r' % modname)
|
||||||
self.dispatcher.register_module(modobj, modname, modobj.properties['export'])
|
self.dispatcher.register_module(modobj, modname, modobj.properties['export'])
|
||||||
try:
|
modobj.pollerClass.add_to_table(pollTable, modobj)
|
||||||
modobj.pollerClass.add_to_table(pollTable, modobj)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
# also call earlyInit on the modules
|
# also call earlyInit on the modules
|
||||||
modobj.earlyInit()
|
modobj.earlyInit()
|
||||||
|
|
||||||
|
@ -27,10 +27,12 @@ from time import sleep
|
|||||||
|
|
||||||
from secop.datatypes import FloatRange
|
from secop.datatypes import FloatRange
|
||||||
from secop.lib import mkthread
|
from secop.lib import mkthread
|
||||||
from secop.modules import Drivable, Module, Parameter, Readable, Writable
|
from secop.modules import Drivable, Module, Parameter, Readable, Writable, BasicPoller
|
||||||
|
|
||||||
|
|
||||||
class SimBase:
|
class SimBase:
|
||||||
|
pollerClass = BasicPoller
|
||||||
|
|
||||||
def __init__(self, cfgdict):
|
def __init__(self, cfgdict):
|
||||||
# spice up parameters if requested by extra property
|
# spice up parameters if requested by extra property
|
||||||
# hint: us a comma-separated list if mor than one extra_param
|
# hint: us a comma-separated list if mor than one extra_param
|
||||||
@ -68,7 +70,7 @@ class SimBase:
|
|||||||
self.log.info('sim thread ended')
|
self.log.info('sim thread ended')
|
||||||
|
|
||||||
def sim(self):
|
def sim(self):
|
||||||
return True
|
return True # nothing to do, stop thread
|
||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
if 'jitter' in self.accessibles:
|
if 'jitter' in self.accessibles:
|
||||||
@ -138,6 +140,7 @@ class SimDrivable(SimBase, Drivable):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.status = self.Status.IDLE, ''
|
self.status = self.Status.IDLE, ''
|
||||||
|
return False # keep thread running
|
||||||
|
|
||||||
def _hw_wait(self):
|
def _hw_wait(self):
|
||||||
while self.status[0] == self.Status.BUSY:
|
while self.status[0] == self.Status.BUSY:
|
||||||
|
@ -31,7 +31,7 @@ import math
|
|||||||
from secop.datatypes import ArrayOf, FloatRange, StringType, StructOf, TupleOf
|
from secop.datatypes import ArrayOf, FloatRange, StringType, StructOf, TupleOf
|
||||||
from secop.errors import ConfigError, DisabledError
|
from secop.errors import ConfigError, DisabledError
|
||||||
from secop.lib.sequence import SequencerMixin, Step
|
from secop.lib.sequence import SequencerMixin, Step
|
||||||
from secop.modules import Drivable, Parameter
|
from secop.modules import Drivable, Parameter, BasicPoller
|
||||||
|
|
||||||
|
|
||||||
class GarfieldMagnet(SequencerMixin, Drivable):
|
class GarfieldMagnet(SequencerMixin, Drivable):
|
||||||
@ -47,6 +47,8 @@ class GarfieldMagnet(SequencerMixin, Drivable):
|
|||||||
the symmetry setting selects which.
|
the symmetry setting selects which.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pollerClass = BasicPoller
|
||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'subdev_currentsource': Parameter('(bipolar) Powersupply', datatype=StringType(), readonly=True, export=False),
|
'subdev_currentsource': Parameter('(bipolar) Powersupply', datatype=StringType(), readonly=True, export=False),
|
||||||
'subdev_enable': Parameter('Switch to set for on/off', datatype=StringType(), readonly=True, export=False),
|
'subdev_enable': Parameter('Switch to set for on/off', datatype=StringType(), readonly=True, export=False),
|
||||||
|
@ -41,7 +41,7 @@ from secop.errors import CommunicationFailedError, \
|
|||||||
ConfigError, HardwareError, ProgrammingError
|
ConfigError, HardwareError, ProgrammingError
|
||||||
from secop.lib import lazy_property
|
from secop.lib import lazy_property
|
||||||
from secop.modules import Command, Drivable, \
|
from secop.modules import Command, Drivable, \
|
||||||
Module, Override, Parameter, Readable
|
Module, Override, Parameter, Readable, BasicPoller
|
||||||
|
|
||||||
#####
|
#####
|
||||||
|
|
||||||
@ -158,6 +158,8 @@ class PyTangoDevice(Module):
|
|||||||
execution and attribute operations with logging and exception mapping.
|
execution and attribute operations with logging and exception mapping.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pollerClass = BasicPoller
|
||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'comtries': Parameter('Maximum retries for communication',
|
'comtries': Parameter('Maximum retries for communication',
|
||||||
datatype=IntRange(1, 100), default=3, readonly=False,
|
datatype=IntRange(1, 100), default=3, readonly=False,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user