Change-Id: I4e40e0ef8e80999832846eac3a415fdd767c6d98
This commit is contained in:
Enrico Faulhaber 2017-05-24 17:13:06 +02:00
parent 241af728d6
commit 462b6a0a7e
25 changed files with 130 additions and 84 deletions

View File

@ -27,6 +27,7 @@ import code
class NameSpace(dict): class NameSpace(dict):
def __init__(self): def __init__(self):
dict.__init__(self) dict.__init__(self)
self.__const = set() self.__const = set()
@ -63,6 +64,7 @@ from os import path
class ClientConsole(object): class ClientConsole(object):
def __init__(self, cfgname, basepath): def __init__(self, cfgname, basepath):
self.namespace = NameSpace() self.namespace = NameSpace()
self.namespace.setconst('help', self.helpCmd) self.namespace.setconst('help', self.helpCmd)
@ -98,6 +100,7 @@ from secop.protocol.messages import *
class TCPConnection(object): class TCPConnection(object):
def __init__(self, connect, port, encoding, framing, **kwds): def __init__(self, connect, port, encoding, framing, **kwds):
self.log = mlzlog.log.getChild('connection', False) self.log = mlzlog.log.getChild('connection', False)
self.encoder = ENCODERS[encoding]() self.encoder = ENCODERS[encoding]()
@ -164,6 +167,7 @@ class TCPConnection(object):
class Client(object): class Client(object):
def __init__(self, opts): def __init__(self, opts):
self.log = mlzlog.log.getChild('client', True) self.log = mlzlog.log.getChild('client', True)
self._cache = dict() self._cache = dict()

View File

@ -481,9 +481,9 @@ class Client(object):
def syncCommunicate(self, *msg): def syncCommunicate(self, *msg):
res = self._communicate(*msg) res = self._communicate(*msg)
try: try:
res = self.encode_message(*res) res = self.encode_message(*res)
except Exception: except Exception:
res = str(res) res = str(res)
return res return res
def ping(self, pingctr=[0]): def ping(self, pingctr=[0]):

View File

@ -46,6 +46,7 @@ EVENT_ONLY_ON_CHANGED_VALUES = False
class PARAM(object): class PARAM(object):
def __init__(self, def __init__(self,
description, description,
validator=float, validator=float,
@ -76,10 +77,10 @@ class PARAM(object):
def as_dict(self, static_only=False): def as_dict(self, static_only=False):
# used for serialisation only # used for serialisation only
res = dict( res = dict(
description=self.description, description=self.description,
readonly=self.readonly, readonly=self.readonly,
validator=validator_to_str(self.validator), validator=validator_to_str(self.validator),
) )
if self.unit: if self.unit:
res['unit'] = self.unit res['unit'] = self.unit
if self.group: if self.group:
@ -93,6 +94,7 @@ class PARAM(object):
# storage for CMDs settings (description + call signature...) # storage for CMDs settings (description + call signature...)
class CMD(object): class CMD(object):
def __init__(self, description, arguments, result): def __init__(self, description, arguments, result):
# descriptive text for humans # descriptive text for humans
self.description = description self.description = description
@ -117,6 +119,7 @@ class CMD(object):
class DeviceMeta(type): class DeviceMeta(type):
def __new__(mcs, name, bases, attrs): def __new__(mcs, name, bases, attrs):
newtype = type.__new__(mcs, name, bases, attrs) newtype = type.__new__(mcs, name, bases, attrs)
if '__constructed__' in attrs: if '__constructed__' in attrs:
@ -221,10 +224,10 @@ class Device(object):
# static PROPERTIES, definitions in derived classes should overwrite earlier ones. # static PROPERTIES, definitions in derived classes should overwrite earlier ones.
# how to configure some stuff which makes sense to take from configfile??? # how to configure some stuff which makes sense to take from configfile???
PROPERTIES = { PROPERTIES = {
'group' : None, # some Modules may be grouped together 'group': None, # some Modules may be grouped together
'meaning' : None, # XXX: ??? 'meaning': None, # XXX: ???
'priority' : None, # XXX: ??? 'priority': None, # XXX: ???
'visibility' : None, # XXX: ???? 'visibility': None, # XXX: ????
# what else? # what else?
} }
# PARAMS and CMDS are auto-merged upon subclassing # PARAMS and CMDS are auto-merged upon subclassing
@ -251,7 +254,8 @@ class Device(object):
self.PARAMS = params self.PARAMS = params
# check and apply properties specified in cfgdict # check and apply properties specified in cfgdict
# moduleproperties are to be specified as '.<propertyname>=<propertyvalue>' # moduleproperties are to be specified as
# '.<propertyname>=<propertyvalue>'
for k, v in cfgdict.items(): for k, v in cfgdict.items():
if k[0] == '.': if k[0] == '.':
if k[1:] in self.PROPERTIES: if k[1:] in self.PROPERTIES:
@ -262,17 +266,17 @@ class Device(object):
myclassname = '%s.%s' % (mycls.__module__, mycls.__name__) myclassname = '%s.%s' % (mycls.__module__, mycls.__name__)
self.PROPERTIES['implementation'] = myclassname self.PROPERTIES['implementation'] = myclassname
self.PROPERTIES['interfaces'] = [b.__name__ for b in mycls.__mro__ self.PROPERTIES['interfaces'] = [b.__name__ for b in mycls.__mro__
if b.__module__.startswith('secop.devices.core')] if b.__module__.startswith('secop.devices.core')]
self.PROPERTIES['interface'] = self.PROPERTIES['interfaces'][0] self.PROPERTIES['interface'] = self.PROPERTIES['interfaces'][0]
# remove unset (default) module properties # remove unset (default) module properties
for k,v in self.PROPERTIES.items(): for k, v in self.PROPERTIES.items():
if v == None: if v == None:
del self.PROPERTIES[k] del self.PROPERTIES[k]
# check and apply parameter_properties # check and apply parameter_properties
# specified as '<paramname>.<propertyname> = <propertyvalue>' # specified as '<paramname>.<propertyname> = <propertyvalue>'
for k,v in cfgdict.items()[:]: for k, v in cfgdict.items()[:]:
if '.' in k[1:]: if '.' in k[1:]:
paramname, propname = k.split('.', 1) paramname, propname = k.split('.', 1)
if paramname in self.PARAMS: if paramname in self.PARAMS:
@ -338,15 +342,15 @@ class Readable(Device):
'pollinterval': PARAM('sleeptime between polls', default=5, 'pollinterval': PARAM('sleeptime between polls', default=5,
readonly=False, validator=floatrange(0.1, 120), ), readonly=False, validator=floatrange(0.1, 120), ),
'status': PARAM('current status of the device', default=(status.OK, ''), 'status': PARAM('current status of the device', default=(status.OK, ''),
validator=vector( validator=vector(
enum(**{ enum(**{
'IDLE': status.OK, 'IDLE': status.OK,
'BUSY': status.BUSY, 'BUSY': status.BUSY,
'WARN': status.WARN, 'WARN': status.WARN,
'UNSTABLE': status.UNSTABLE, 'UNSTABLE': status.UNSTABLE,
'ERROR': status.ERROR, 'ERROR': status.ERROR,
'UNKNOWN': status.UNKNOWN 'UNKNOWN': status.UNKNOWN
}), str), }), str),
readonly=True), readonly=True),
} }
@ -374,7 +378,7 @@ class Driveable(Readable):
""" """
PARAMS = { PARAMS = {
'target': PARAM('target value of the device', default=0., readonly=False, 'target': PARAM('target value of the device', default=0., readonly=False,
), ),
} }
# XXX: CMDS ???? auto deriving working well enough? # XXX: CMDS ???? auto deriving working well enough?

View File

@ -30,9 +30,11 @@ from secop.protocol import status
from secop.validators import floatrange, positive, enum, nonnegative, vector from secop.validators import floatrange, positive, enum, nonnegative, vector
from secop.lib import clamp, mkthread from secop.lib import clamp, mkthread
class CryoBase(Driveable): class CryoBase(Driveable):
pass pass
class Cryostat(CryoBase): class Cryostat(CryoBase):
"""simulated cryostat with: """simulated cryostat with:
@ -44,22 +46,22 @@ class Cryostat(CryoBase):
jitter=PARAM("amount of random noise on readout values", jitter=PARAM("amount of random noise on readout values",
validator=floatrange(0, 1), unit="K", validator=floatrange(0, 1), unit="K",
default=0.1, readonly=False, export=False, default=0.1, readonly=False, export=False,
), ),
T_start=PARAM("starting temperature for simulation", T_start=PARAM("starting temperature for simulation",
validator=positive, default=10, validator=positive, default=10,
export=False, export=False,
), ),
looptime=PARAM("timestep for simulation", looptime=PARAM("timestep for simulation",
validator=floatrange(0.01, 10), unit="s", default=1, validator=floatrange(0.01, 10), unit="s", default=1,
readonly=False, export=False, readonly=False, export=False,
), ),
ramp=PARAM("ramping speed of the setpoint", ramp=PARAM("ramping speed of the setpoint",
validator=floatrange(0, 1e3), unit="K/min", default=1, validator=floatrange(0, 1e3), unit="K/min", default=1,
readonly=False, readonly=False,
), ),
setpoint=PARAM("current setpoint during ramping else target", setpoint=PARAM("current setpoint during ramping else target",
validator=float, default=1, unit='K', validator=float, default=1, unit='K',
), ),
maxpower=PARAM("Maximum heater power", maxpower=PARAM("Maximum heater power",
validator=nonnegative, default=1, unit="W", validator=nonnegative, default=1, unit="W",
readonly=False, readonly=False,
@ -76,34 +78,35 @@ class Cryostat(CryoBase):
target=PARAM("target temperature", target=PARAM("target temperature",
validator=nonnegative, default=0, unit="K", validator=nonnegative, default=0, unit="K",
readonly=False, readonly=False,
), ),
value=PARAM("regulation temperature", value=PARAM("regulation temperature",
validator=nonnegative, default=0, unit="K", validator=nonnegative, default=0, unit="K",
), ),
pid=PARAM("regulation coefficients", pid=PARAM("regulation coefficients",
validator=vector(nonnegative, floatrange(0, 100), floatrange(0, 100)), validator=vector(nonnegative, floatrange(
0, 100), floatrange(0, 100)),
default=(40, 10, 2), readonly=False, default=(40, 10, 2), readonly=False,
group='pid', group='pid',
), ),
p=PARAM("regulation coefficient 'p'", p=PARAM("regulation coefficient 'p'",
validator=nonnegative, default=40, unit="%/K", readonly=False, validator=nonnegative, default=40, unit="%/K", readonly=False,
group='pid', group='pid',
), ),
i=PARAM("regulation coefficient 'i'", i=PARAM("regulation coefficient 'i'",
validator=floatrange(0, 100), default=10, readonly=False, validator=floatrange(0, 100), default=10, readonly=False,
group='pid', group='pid',
), ),
d=PARAM("regulation coefficient 'd'", d=PARAM("regulation coefficient 'd'",
validator=floatrange(0, 100), default=2, readonly=False, validator=floatrange(0, 100), default=2, readonly=False,
group='pid', group='pid',
), ),
mode=PARAM("mode of regulation", mode=PARAM("mode of regulation",
validator=enum('ramp', 'pid', 'openloop'), default='ramp', validator=enum('ramp', 'pid', 'openloop'), default='ramp',
readonly=False, readonly=False,
), ),
pollinterval=PARAM("polling interval", pollinterval=PARAM("polling interval",
validator=positive, default=5, validator=positive, default=5,
), ),
tolerance=PARAM("temperature range for stability checking", tolerance=PARAM("temperature range for stability checking",
validator=floatrange(0, 100), default=0.1, unit='K', validator=floatrange(0, 100), default=0.1, unit='K',
readonly=False, readonly=False,

View File

@ -35,19 +35,19 @@ class Switch(Driveable):
PARAMS = { PARAMS = {
'value': PARAM('current state (on or off)', 'value': PARAM('current state (on or off)',
validator=enum(on=1, off=0), default=0, validator=enum(on=1, off=0), default=0,
), ),
'target': PARAM('wanted state (on or off)', 'target': PARAM('wanted state (on or off)',
validator=enum(on=1, off=0), default=0, validator=enum(on=1, off=0), default=0,
readonly=False, readonly=False,
), ),
'switch_on_time': PARAM('seconds to wait after activating the switch', 'switch_on_time': PARAM('seconds to wait after activating the switch',
validator=floatrange(0, 60), unit='s', validator=floatrange(0, 60), unit='s',
default=10, export=False, default=10, export=False,
), ),
'switch_off_time': PARAM('cool-down time in seconds', 'switch_off_time': PARAM('cool-down time in seconds',
validator=floatrange(0, 60), unit='s', validator=floatrange(0, 60), unit='s',
default=10, export=False, default=10, export=False,
), ),
} }
def init(self): def init(self):
@ -100,22 +100,22 @@ class MagneticField(Driveable):
PARAMS = { PARAMS = {
'value': PARAM('current field in T', 'value': PARAM('current field in T',
unit='T', validator=floatrange(-15, 15), default=0, unit='T', validator=floatrange(-15, 15), default=0,
), ),
'target': PARAM('target field in T', 'target': PARAM('target field in T',
unit='T', validator=floatrange(-15, 15), default=0, unit='T', validator=floatrange(-15, 15), default=0,
readonly=False, readonly=False,
), ),
'ramp': PARAM('ramping speed', 'ramp': PARAM('ramping speed',
unit='T/min', validator=floatrange(0, 1), default=0.1, unit='T/min', validator=floatrange(0, 1), default=0.1,
readonly=False, readonly=False,
), ),
'mode': PARAM('what to do after changing field', 'mode': PARAM('what to do after changing field',
default=1, validator=enum(persistent=1, hold=0), default=1, validator=enum(persistent=1, hold=0),
readonly=False, readonly=False,
), ),
'heatswitch': PARAM('name of heat switch device', 'heatswitch': PARAM('name of heat switch device',
validator=str, export=False, validator=str, export=False,
), ),
} }
def init(self): def init(self):
@ -184,10 +184,10 @@ class CoilTemp(Readable):
PARAMS = { PARAMS = {
'value': PARAM('Coil temperatur', 'value': PARAM('Coil temperatur',
unit='K', validator=float, default=0, unit='K', validator=float, default=0,
), ),
'sensor': PARAM("Sensor number or calibration id", 'sensor': PARAM("Sensor number or calibration id",
validator=str, readonly=True, validator=str, readonly=True,
), ),
} }
def read_value(self, maxage=0): def read_value(self, maxage=0):
@ -200,14 +200,14 @@ class SampleTemp(Driveable):
PARAMS = { PARAMS = {
'value': PARAM('Sample temperature', 'value': PARAM('Sample temperature',
unit='K', validator=float, default=10, unit='K', validator=float, default=10,
), ),
'sensor': PARAM("Sensor number or calibration id", 'sensor': PARAM("Sensor number or calibration id",
validator=str, readonly=True, validator=str, readonly=True,
), ),
'ramp': PARAM('moving speed in K/min', 'ramp': PARAM('moving speed in K/min',
validator=floatrange(0, 100), unit='K/min', default=0.1, validator=floatrange(0, 100), unit='K/min', default=0.1,
readonly=False, readonly=False,
), ),
} }
def init(self): def init(self):
@ -244,16 +244,16 @@ class Label(Readable):
PARAMS = { PARAMS = {
'system': PARAM("Name of the magnet system", 'system': PARAM("Name of the magnet system",
validator=str, export=False, validator=str, export=False,
), ),
'subdev_mf': PARAM("name of subdevice for magnet status", 'subdev_mf': PARAM("name of subdevice for magnet status",
validator=str, export=False, validator=str, export=False,
), ),
'subdev_ts': PARAM("name of subdevice for sample temp", 'subdev_ts': PARAM("name of subdevice for sample temp",
validator=str, export=False, validator=str, export=False,
), ),
'value': PARAM("final value of label string", 'value': PARAM("final value of label string",
validator=str, validator=str,
), ),
} }
def read_value(self, maxage=0): def read_value(self, maxage=0):
@ -303,5 +303,5 @@ class ValidatorTest(Readable):
validator=intrange(2, 9), readonly=False, default=4), validator=intrange(2, 9), readonly=False, default=4),
'floatrange': PARAM('floatrange', 'floatrange': PARAM('floatrange',
validator=floatrange(-1, 1), readonly=False, default=0, validator=floatrange(-1, 1), readonly=False, default=0,
), ),
} }

View File

@ -28,16 +28,20 @@ from secop.devices.core import Readable, Device, Driveable, PARAM
from secop.protocol import status from secop.protocol import status
try: try:
from pvaccess import Channel #import EPIVSv4 functionallity, PV access from pvaccess import Channel # import EPIVSv4 functionallity, PV access
except ImportError: except ImportError:
class Channel(object): class Channel(object):
def __init__(self, pv_name): def __init__(self, pv_name):
self.pv_name = pv_name self.pv_name = pv_name
self.value = 0.0 self.value = 0.0
def get(self): def get(self):
return self return self
def getDouble(self): def getDouble(self):
return self.value return self.value
def put(self, value): def put(self, value):
try: try:
self.value = value self.value = value
@ -48,10 +52,12 @@ try:
from epics import PV from epics import PV
except ImportError: except ImportError:
class PV(object): class PV(object):
def __init__(self, pv_name): def __init__(self, pv_name):
self.pv_name = pv_name self.pv_name = pv_name
self.value = 0.0 self.value = 0.0
class EpicsReadable(Readable): class EpicsReadable(Readable):
"""EpicsDriveable handles a Driveable interfacing to EPICS v4""" """EpicsDriveable handles a Driveable interfacing to EPICS v4"""
# Commmon PARAMS for all EPICS devices # Commmon PARAMS for all EPICS devices
@ -64,16 +70,17 @@ class EpicsReadable(Readable):
'value_pv': PARAM('EPICS pv_name of value', validator=str, 'value_pv': PARAM('EPICS pv_name of value', validator=str,
default="unset", export=False), default="unset", export=False),
'status_pv': PARAM('EPICS pv_name of status', validator=str, 'status_pv': PARAM('EPICS pv_name of status', validator=str,
default="unset", export=False), default="unset", export=False),
} }
# Generic read and write functions # Generic read and write functions
def _read_pv(self, pv_name): def _read_pv(self, pv_name):
if self.epics_version == 'v4': if self.epics_version == 'v4':
pv_channel = Channel(pv_name) pv_channel = Channel(pv_name)
# TODO: cannot handle read of string (is there a .getText() or .getString() ?) # TODO: cannot handle read of string (is there a .getText() or
# .getString() ?)
return_value = pv_channel.get().getDouble() return_value = pv_channel.get().getDouble()
else: # Not EPICS v4 else: # Not EPICS v4
# TODO: fix this, it does not work # TODO: fix this, it does not work
pv = PV(pv_name + ".VAL") pv = PV(pv_name + ".VAL")
return_value = pv.value return_value = pv.value
@ -91,11 +98,10 @@ class EpicsReadable(Readable):
if self.epics_version == 'v4': if self.epics_version == 'v4':
pv_channel = Channel(pv_name) pv_channel = Channel(pv_name)
pv_channel.put(write_value) pv_channel.put(write_value)
else: # Not EPICS v4 else: # Not EPICS v4
pv = PV(pv_name + ".VAL") pv = PV(pv_name + ".VAL")
pv.value = write_value pv.value = write_value
def read_value(self, maxage=0): def read_value(self, maxage=0):
return self._read_pv(self.value_pv) return self._read_pv(self.value_pv)
@ -109,7 +115,6 @@ class EpicsReadable(Readable):
return (status.OK, 'no pv set') return (status.OK, 'no pv set')
class EpicsDriveable(Driveable): class EpicsDriveable(Driveable):
"""EpicsDriveable handles a Driveable interfacing to EPICS v4""" """EpicsDriveable handles a Driveable interfacing to EPICS v4"""
# Commmon PARAMS for all EPICS devices # Commmon PARAMS for all EPICS devices
@ -126,16 +131,17 @@ class EpicsDriveable(Driveable):
'value_pv': PARAM('EPICS pv_name of value', validator=str, 'value_pv': PARAM('EPICS pv_name of value', validator=str,
default="unset", export=False), default="unset", export=False),
'status_pv': PARAM('EPICS pv_name of status', validator=str, 'status_pv': PARAM('EPICS pv_name of status', validator=str,
default="unset", export=False), default="unset", export=False),
} }
# Generic read and write functions # Generic read and write functions
def _read_pv(self, pv_name): def _read_pv(self, pv_name):
if self.epics_version == 'v4': if self.epics_version == 'v4':
pv_channel = Channel(pv_name) pv_channel = Channel(pv_name)
# TODO: cannot handle read of string (is there a .getText() or .getString() ?) # TODO: cannot handle read of string (is there a .getText() or
# .getString() ?)
return_value = pv_channel.get().getDouble() return_value = pv_channel.get().getDouble()
else: # Not EPICS v4 else: # Not EPICS v4
# TODO: fix this, it does not work # TODO: fix this, it does not work
pv = PV(pv_name + ".VAL") pv = PV(pv_name + ".VAL")
return_value = pv.value return_value = pv.value
@ -153,7 +159,7 @@ class EpicsDriveable(Driveable):
if self.epics_version == 'v4': if self.epics_version == 'v4':
pv_channel = Channel(pv_name) pv_channel = Channel(pv_name)
pv_channel.put(write_value) pv_channel.put(write_value)
else: # Not EPICS v4 else: # Not EPICS v4
pv = PV(pv_name + ".VAL") pv = PV(pv_name + ".VAL")
pv.value = write_value pv.value = write_value
@ -177,9 +183,11 @@ class EpicsDriveable(Driveable):
(status.BUSY, 'Moving') (status.BUSY, 'Moving')
"""Temperature control loop""" """Temperature control loop"""
# should also derive from secop.core.temperaturecontroller, once its features are agreed upon # should also derive from secop.core.temperaturecontroller, once its
# features are agreed upon
class EpicsTempCtrl(EpicsDriveable): class EpicsTempCtrl(EpicsDriveable):
PARAMS = { PARAMS = {
@ -187,7 +195,7 @@ class EpicsTempCtrl(EpicsDriveable):
'heaterrange': PARAM('Heater range', validator=str, 'heaterrange': PARAM('Heater range', validator=str,
default='Off', readonly=False,), default='Off', readonly=False,),
'tolerance': PARAM('allowed deviation between value and target', 'tolerance': PARAM('allowed deviation between value and target',
validator=floatrange(1e-6,1e6), default=0.1, validator=floatrange(1e-6, 1e6), default=0.1,
readonly=False,), readonly=False,),
# 'private' parameters: not remotely accessible # 'private' parameters: not remotely accessible
'heaterrange_pv': PARAM('EPICS pv_name of heater range', 'heaterrange_pv': PARAM('EPICS pv_name of heater range',
@ -209,14 +217,13 @@ class EpicsTempCtrl(EpicsDriveable):
def read_status(self, maxage=0): def read_status(self, maxage=0):
# XXX: comparison may need to collect a history to detect oscillations # XXX: comparison may need to collect a history to detect oscillations
at_target = abs(self.read_value(maxage) - self.read_target(maxage)) \ at_target = abs(self.read_value(maxage) - self.read_target(maxage)) \
<= self.tolerance <= self.tolerance
return (status.OK, 'at Target') if at_target else (status.BUSY, 'Moving') return (status.OK, 'at Target') if at_target else (status.BUSY, 'Moving')
# TODO: add support for strings over epics pv # TODO: add support for strings over epics pv
#def read_heaterrange(self, maxage=0): # def read_heaterrange(self, maxage=0):
# return self._read_pv(self.heaterrange_pv) # return self._read_pv(self.heaterrange_pv)
# TODO: add support for strings over epics pv # TODO: add support for strings over epics pv
#def write_heaterrange(self, range_value): # def write_heaterrange(self, range_value):
# self._write_pv(self.heaterrange_pv, range_value) # self._write_pv(self.heaterrange_pv, range_value)

View File

@ -46,7 +46,7 @@ class Heater(Driveable):
PARAMS = { PARAMS = {
'maxheaterpower': PARAM('maximum allowed heater power', 'maxheaterpower': PARAM('maximum allowed heater power',
validator=floatrange(0, 100), unit='W', validator=floatrange(0, 100), unit='W',
), ),
} }
def read_value(self, maxage=0): def read_value(self, maxage=0):
@ -65,10 +65,10 @@ class Temp(Driveable):
PARAMS = { PARAMS = {
'sensor': PARAM("Sensor number or calibration id", 'sensor': PARAM("Sensor number or calibration id",
validator=str, readonly=True, validator=str, readonly=True,
), ),
'target': PARAM("Target temperature", 'target': PARAM("Target temperature",
default=300.0, validator=positive, readonly=False, unit='K', default=300.0, validator=positive, readonly=False, unit='K',
), ),
} }
def read_value(self, maxage=0): def read_value(self, maxage=0):

View File

@ -37,6 +37,7 @@ ITEM_TYPE_MODULE = QTreeWidgetItem.UserType + 2
ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 3 ITEM_TYPE_PARAMETER = QTreeWidgetItem.UserType + 3
class QSECNode(SECNode, QObject): class QSECNode(SECNode, QObject):
newData = pyqtSignal(str, str, object) # module, parameter, data newData = pyqtSignal(str, str, object) # module, parameter, data
@ -63,6 +64,7 @@ class QSECNode(SECNode, QObject):
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super(MainWindow, self).__init__(parent) super(MainWindow, self).__init__(parent)

View File

@ -56,6 +56,7 @@ class ParameterButtons(QWidget):
class ModuleCtrl(QWidget): class ModuleCtrl(QWidget):
def __init__(self, node, module, parent=None): def __init__(self, node, module, parent=None):
super(ModuleCtrl, self).__init__(parent) super(ModuleCtrl, self).__init__(parent)
loadUi(self, 'modulectrl.ui') loadUi(self, 'modulectrl.ui')

View File

@ -32,6 +32,7 @@ from secop.protocol.errors import SECOPError
class NodeCtrl(QWidget): class NodeCtrl(QWidget):
def __init__(self, node, parent=None): def __init__(self, node, parent=None):
super(NodeCtrl, self).__init__(parent) super(NodeCtrl, self).__init__(parent)
loadUi(self, 'nodectrl.ui') loadUi(self, 'nodectrl.ui')

View File

@ -29,6 +29,7 @@ from secop.validators import validator_to_str
class ParameterView(QWidget): class ParameterView(QWidget):
def __init__(self, node, module, parameter, parent=None): def __init__(self, node, module, parameter, parent=None):
super(ParameterView, self).__init__(parent) super(ParameterView, self).__init__(parent)
loadUi(self, 'paramview.ui') loadUi(self, 'paramview.ui')

View File

@ -80,6 +80,7 @@ def format_time(timestamp=None):
class Timezone(tzinfo): class Timezone(tzinfo):
def __init__(self, offset, name='unknown timezone'): def __init__(self, offset, name='unknown timezone'):
self.offset = offset self.offset = offset
self.name = name self.name = name

View File

@ -46,6 +46,7 @@ from secop.lib.parsing import format_time
class Dispatcher(object): class Dispatcher(object):
def __init__(self, logger, options): def __init__(self, logger, options):
self.equipment_id = options.pop('equipment_id') self.equipment_id = options.pop('equipment_id')
self.log = logger self.log = logger
@ -213,7 +214,7 @@ class Dispatcher(object):
dd = { dd = {
'parameters': self.list_module_params(modulename, only_static=True), 'parameters': self.list_module_params(modulename, only_static=True),
'commands': self.list_module_cmds(modulename), 'commands': self.list_module_cmds(modulename),
'properties' : module.PROPERTIES, 'properties': module.PROPERTIES,
} }
result['modules'][modulename] = dd result['modules'][modulename] = dd
result['equipment_id'] = self.equipment_id result['equipment_id'] = self.equipment_id

View File

@ -36,6 +36,7 @@ DEMO_RE = re.compile(
class DemoEncoder(MessageEncoder): class DemoEncoder(MessageEncoder):
def decode(sef, encoded): def decode(sef, encoded):
# match [!][*|devicename][: *|paramname [: *|propname]] [=value] # match [!][*|devicename][: *|paramname [: *|propname]] [=value]
match = DEMO_RE.match(encoded) match = DEMO_RE.match(encoded)

View File

@ -92,6 +92,7 @@ DEMO_RE_OTHER = re.compile(
class DemoEncoder(MessageEncoder): class DemoEncoder(MessageEncoder):
def __init__(self, *args, **kwds): def __init__(self, *args, **kwds):
MessageEncoder.__init__(self, *args, **kwds) MessageEncoder.__init__(self, *args, **kwds)
self.result = [] # for decoding self.result = [] # for decoding
@ -321,6 +322,7 @@ DEMO_RE_MZ = re.compile(
class DemoEncoder_MZ(MessageEncoder): class DemoEncoder_MZ(MessageEncoder):
def decode(sef, encoded): def decode(sef, encoded):
m = DEMO_RE_MZ.match(encoded) m = DEMO_RE_MZ.match(encoded)
if m: if m:

View File

@ -135,15 +135,18 @@ class DemoEncoder(MessageEncoder):
encode_cmd_result, ), encode_cmd_result, ),
WriteRequest: ( WriteRequest: (
WRITEREQUEST, WRITEREQUEST,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, lambda msg: "%s:%s" % (
msg.module, msg.parameter) if msg.parameter else msg.module,
'value', ), 'value', ),
WriteReply: ( WriteReply: (
WRITEREPLY, WRITEREPLY,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, lambda msg: "%s:%s" % (
msg.module, msg.parameter) if msg.parameter else msg.module,
'value', ), 'value', ),
PollRequest: ( PollRequest: (
TRIGGERREQUEST, TRIGGERREQUEST,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, lambda msg: "%s:%s" % (
msg.module, msg.parameter) if msg.parameter else msg.module,
), ),
HeartbeatRequest: ( HeartbeatRequest: (
HEARTBEATREQUEST, HEARTBEATREQUEST,
@ -158,7 +161,8 @@ class DemoEncoder(MessageEncoder):
encode_error_msg, ), encode_error_msg, ),
Value: ( Value: (
EVENT, EVENT,
lambda msg: "%s:%s" % (msg.module, msg.parameter or (msg.command + '()')) if msg.parameter or msg.command else msg.module, lambda msg: "%s:%s" % (msg.module, msg.parameter or (
msg.command + '()')) if msg.parameter or msg.command else msg.module,
encode_value_data, ), encode_value_data, ),
} }
DECODEMAP = { DECODEMAP = {

View File

@ -35,6 +35,7 @@ except ImportError:
class PickleEncoder(MessageEncoder): class PickleEncoder(MessageEncoder):
def encode(self, messageobj): def encode(self, messageobj):
"""msg object -> transport layer message""" """msg object -> transport layer message"""
return pickle.dumps(messageobj) return pickle.dumps(messageobj)

View File

@ -37,6 +37,7 @@ SCPMESSAGE = re.compile(
class SCPEncoder(MessageEncoder): class SCPEncoder(MessageEncoder):
def encode(self, msg): def encode(self, msg):
"""msg object -> transport layer message""" """msg object -> transport layer message"""
# fun for Humans # fun for Humans

View File

@ -30,6 +30,7 @@ from secop.lib.parsing import *
class TextEncoder(MessageEncoder): class TextEncoder(MessageEncoder):
def __init__(self): def __init__(self):
# build safe namespace # build safe namespace
ns = dict() ns = dict()

View File

@ -23,6 +23,7 @@
class SECOPError(RuntimeError): class SECOPError(RuntimeError):
def __init__(self, *args, **kwds): def __init__(self, *args, **kwds):
self.args = args self.args = args
for k, v in kwds.items(): for k, v in kwds.items():

View File

@ -35,6 +35,7 @@ from secop.protocol.messages import HelpMessage
class TCPRequestHandler(SocketServer.BaseRequestHandler): class TCPRequestHandler(SocketServer.BaseRequestHandler):
def setup(self): def setup(self):
self.log = self.server.log self.log = self.server.log
self._queue = collections.deque(maxlen=100) self._queue = collections.deque(maxlen=100)

View File

@ -50,6 +50,7 @@ class Message(object):
class Value(object): class Value(object):
def __init__(self, def __init__(self,
module, module,
parameter=None, parameter=None,

View File

@ -95,6 +95,7 @@ class Message(object):
class Value(object): class Value(object):
def __init__(self, value=Ellipsis, qualifiers=None, **kwds): def __init__(self, value=Ellipsis, qualifiers=None, **kwds):
self.dev = '' self.dev = ''
self.param = '' self.param = ''
@ -166,6 +167,7 @@ class HelpMessage(Message):
class NoSuchDeviceError(ErrorMessage): class NoSuchDeviceError(ErrorMessage):
def __init__(self, *devs): def __init__(self, *devs):
ErrorMessage.__init__( ErrorMessage.__init__(
self, self,
@ -175,6 +177,7 @@ class NoSuchDeviceError(ErrorMessage):
class NoSuchParamError(ErrorMessage): class NoSuchParamError(ErrorMessage):
def __init__(self, dev, *params): def __init__(self, dev, *params):
ErrorMessage.__init__( ErrorMessage.__init__(
self, self,
@ -185,6 +188,7 @@ class NoSuchParamError(ErrorMessage):
class ParamReadonlyError(ErrorMessage): class ParamReadonlyError(ErrorMessage):
def __init__(self, dev, *params): def __init__(self, dev, *params):
ErrorMessage.__init__( ErrorMessage.__init__(
self, self,
@ -196,6 +200,7 @@ class ParamReadonlyError(ErrorMessage):
class InvalidParamValueError(ErrorMessage): class InvalidParamValueError(ErrorMessage):
def __init__(self, dev, param, value, e): def __init__(self, dev, param, value, e):
ErrorMessage.__init__( ErrorMessage.__init__(
self, self,
@ -207,6 +212,7 @@ class InvalidParamValueError(ErrorMessage):
class InternalError(ErrorMessage): class InternalError(ErrorMessage):
def __init__(self, err, **kwds): def __init__(self, err, **kwds):
ErrorMessage.__init__( ErrorMessage.__init__(
self, errorstring=str(err), errortype='InternalError', **kwds) self, errorstring=str(err), errortype='InternalError', **kwds)
@ -217,7 +223,7 @@ MESSAGE = dict((cls.MSGTYPE, cls)
HelpMessage, ErrorMessage, EventMessage, TriggerMessage, HelpMessage, ErrorMessage, EventMessage, TriggerMessage,
UnsubscribeMessage, SubscribeMessage, PollMessage, UnsubscribeMessage, SubscribeMessage, PollMessage,
CommandMessage, WriteMessage, ReadMessage, ListMessage CommandMessage, WriteMessage, ReadMessage, ListMessage
]) ])
if __name__ == '__main__': if __name__ == '__main__':
print("Minimal testing of messages....") print("Minimal testing of messages....")

View File

@ -39,6 +39,7 @@ from secop.errors import ConfigError
class Server(object): class Server(object):
def __init__(self, name, workdir, parentLogger=None): def __init__(self, name, workdir, parentLogger=None):
self._name = name self._name = name
self._workdir = workdir self._workdir = workdir

View File

@ -200,6 +200,7 @@ class oneof(Validator):
class enum(Validator): class enum(Validator):
def __init__(self, *args, **kwds): def __init__(self, *args, **kwds):
self.mapping = {} self.mapping = {}
# use given kwds directly # use given kwds directly