fixups
Change-Id: I72abe9b4c2deb08e58ce69786f853ccc4b385a5d
This commit is contained in:
parent
9a402857f3
commit
357056d478
@ -242,11 +242,11 @@ merge datatype and validator:
|
||||
-----------------------------
|
||||
* ["enum", {<number_value>:<json_string>}]
|
||||
* ["int"] or ["int", <lowest_allowed_value>, <highest_allowed_value>]
|
||||
* ["blob"] or ["blob", <minimum_size_in_bytes or 0>, <maximum_size_in_bytes>]
|
||||
* ["double"] or ["double", <lowest_allowed_value>, <highest_allowed_value>]
|
||||
* ["string"] or ["string", <maximum_allowed_length>] or ["string", <min_size>, <max_size>]
|
||||
* ["bool"]
|
||||
* ["array", <basic_data_type>] or ["array", <dtype>, <min_elements>, <max_elements>]
|
||||
* ["blob", <maximum_size_in_bytes>] or ["blob", <minimum_size_in_bytes>, <maximum_size_in_bytes>]
|
||||
* ["string", <maximum_allowed_length>] or ["string", <min_size>, <max_size>]
|
||||
* ["array", <basic_data_type>, <max_elements>] or ["array", <dtype>, <min_elements>, <max_elements>]
|
||||
* ["tuple", [ <list_of_dtypes ]]
|
||||
* ["struct", { <name_of_component_as_json_string>:<dtype>}]
|
||||
|
||||
@ -346,3 +346,17 @@ heartbeat
|
||||
* if the client receives no pong within 3s it may close the connection
|
||||
* later discussions showed, that the ping/pong should stay untouched and the keepalive time should be (de-)activated by a special message instead. Also the 'connection specific settings' from earlier drafts may be resurrected for this....
|
||||
|
||||
|
||||
11.9.2017
|
||||
=========
|
||||
|
||||
merge datatype and validator:
|
||||
-----------------------------
|
||||
* enum, int, double, bool, tuple, struct as before
|
||||
* ["blob", <maximum_size_in_bytes>] or ["blob", <maximum_size_in_bytes>, <minimum_size_in_bytes>]
|
||||
* ["string", <maximum_allowed_length>] or ["string", <max_size_in_bytes>, <minimum_size_in_bytes>]
|
||||
* ["array", <basic_data_type>, <max_elements>] or ["array", <dtype>, <max_elements>, <min_elements>]
|
||||
|
||||
interface_class
|
||||
---------------
|
||||
* Drivable, Writable, Readable, Module (first character uppercase, no middle 'e')
|
||||
|
@ -64,7 +64,7 @@ vorerst folgende Festlegung:
|
||||
],
|
||||
"group": "very important/stuff",
|
||||
"implementation": "secop.devices.cryo.Cryostat",
|
||||
"interfaces": ["Driveable", "Readable", "Device"],
|
||||
"interfaces": ["Drivable", "Readable", "Device"],
|
||||
"parameters": ["status", {"readonly": true,
|
||||
"datatype": ["tuple", ["enum", {"unknown":-1,"idle":100, "warn":200, "unstable":250, "busy":300,"error":400}], "string"],
|
||||
"description": "current status of the device"
|
||||
|
@ -38,7 +38,7 @@
|
||||
## Testsuite ##
|
||||
|
||||
* embedded tests inside the actual files grow difficult to maintain
|
||||
=> need a testsuite (nose+pylint?)
|
||||
=> need a testsuite (pytest)
|
||||
|
||||
|
||||
## docu ##
|
||||
@ -48,3 +48,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
## transfer of blobs via json ##
|
||||
|
||||
* use base64
|
||||
|
||||
|
@ -312,7 +312,10 @@ class Client(object):
|
||||
if modname in self._cache:
|
||||
if pname in self._cache:
|
||||
previous = self._cache[modname][pname]
|
||||
self._cache.setdefault(modname, {})[pname] = Value(*data)
|
||||
if data:
|
||||
self._cache.setdefault(modname, {})[pname] = Value(*data)
|
||||
else:
|
||||
self.log.warning('got malformed answer! (spec data)' % (spec, data))
|
||||
# self.log.info('cache: %s:%s=%r (was: %s)', modname, pname, data, previous)
|
||||
if spec in self.callbacks:
|
||||
for func in self.callbacks[spec]:
|
||||
@ -537,7 +540,7 @@ class Client(object):
|
||||
return self.describing_data['modules'][module]['properties']
|
||||
|
||||
def getModuleBaseClass(self, module):
|
||||
return self.getModuleProperties(module)['interface']
|
||||
return self.getModuleProperties(module)['interface_class']
|
||||
|
||||
def getCommands(self, module):
|
||||
return self.describing_data['modules'][module]['commands']
|
||||
|
@ -131,8 +131,8 @@ class NodeCtrl(QWidget):
|
||||
row = 0
|
||||
for modname in sorted(self._node.modules):
|
||||
modprops = self._node.getModuleProperties(modname)
|
||||
baseclass = modprops['interface']
|
||||
description = modprops['interface']
|
||||
interfaces = modprops['interface_class']
|
||||
description = modprops['description']
|
||||
unit = self._node.getProperties(modname, 'value').get('unit', '')
|
||||
|
||||
if unit:
|
||||
@ -142,12 +142,12 @@ class NodeCtrl(QWidget):
|
||||
label = QLabel(labelstr)
|
||||
label.setFont(labelfont)
|
||||
|
||||
if baseclass == 'Driveable':
|
||||
widget = DriveableWidget(self._node, modname, self)
|
||||
elif baseclass == 'Readable':
|
||||
if 'Drivable' in interfaces:
|
||||
widget = DrivableWidget(self._node, modname, self)
|
||||
elif 'Readable' in interfaces:
|
||||
widget = ReadableWidget(self._node, modname, self)
|
||||
else:
|
||||
widget = QLabel('Unsupported Interfaceclass %r' % baseclass)
|
||||
widget = QLabel('Unsupported Interfaceclasses %r' % interfaces)
|
||||
|
||||
if description:
|
||||
widget.setToolTip(description)
|
||||
@ -159,6 +159,7 @@ class NodeCtrl(QWidget):
|
||||
self._moduleWidgets.extend((label, widget))
|
||||
layout.setRowStretch(row, 1)
|
||||
|
||||
|
||||
class ReadableWidget(QWidget):
|
||||
|
||||
def __init__(self, node, module, parent=None):
|
||||
@ -166,6 +167,8 @@ class ReadableWidget(QWidget):
|
||||
self._node = node
|
||||
self._module = module
|
||||
|
||||
self._status_type = self._node.getProperties(self._module, 'status').get('datatype')
|
||||
|
||||
params = self._node.getProperties(self._module, 'value')
|
||||
datatype = params.get('datatype', StringType())
|
||||
self._is_enum = isinstance(datatype, EnumType)
|
||||
@ -206,7 +209,10 @@ class ReadableWidget(QWidget):
|
||||
# XXX: also connect update_status signal to LineEdit ??
|
||||
|
||||
def update_status(self, status, qualifiers={}):
|
||||
self.statusLineEdit.setText(str(status))
|
||||
display_string = self._status_type.subtypes[0].entries.get(status[0])
|
||||
if status[1]:
|
||||
display_string += ':' + status[1]
|
||||
self.statusLineEdit.setText(display_string)
|
||||
# may change meaning of cmdPushButton
|
||||
|
||||
def _init_current_widgets(self):
|
||||
@ -241,7 +247,7 @@ class ReadableWidget(QWidget):
|
||||
self.update_target(*value)
|
||||
|
||||
|
||||
class DriveableWidget(ReadableWidget):
|
||||
class DrivableWidget(ReadableWidget):
|
||||
|
||||
def _init_target_widgets(self):
|
||||
params = self._node.getProperties(self._module, 'target')
|
||||
|
@ -40,6 +40,9 @@
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: lightgrey;</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -67,6 +70,12 @@
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLineEdit" name="statusLineEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: lightgrey;</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -25,13 +25,13 @@ import time
|
||||
import random
|
||||
import threading
|
||||
|
||||
from secop.modules import Driveable, CMD, PARAM
|
||||
from secop.modules import Drivable, CMD, PARAM
|
||||
from secop.protocol import status
|
||||
from secop.datatypes import FloatRange, EnumType, TupleOf
|
||||
from secop.lib import clamp, mkthread
|
||||
|
||||
|
||||
class CryoBase(Driveable):
|
||||
class CryoBase(Drivable):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -24,12 +24,12 @@ import time
|
||||
import random
|
||||
import threading
|
||||
|
||||
from secop.modules import Readable, Driveable, PARAM
|
||||
from secop.modules import Readable, Drivable, PARAM
|
||||
from secop.datatypes import EnumType, FloatRange, IntRange, ArrayOf, StringType, TupleOf, StructOf, BoolType
|
||||
from secop.protocol import status
|
||||
|
||||
|
||||
class Switch(Driveable):
|
||||
class Switch(Drivable):
|
||||
"""switch it on or off....
|
||||
"""
|
||||
PARAMS = {
|
||||
@ -94,7 +94,7 @@ class Switch(Driveable):
|
||||
return info
|
||||
|
||||
|
||||
class MagneticField(Driveable):
|
||||
class MagneticField(Drivable):
|
||||
"""a liquid magnet
|
||||
"""
|
||||
PARAMS = {
|
||||
@ -194,7 +194,7 @@ class CoilTemp(Readable):
|
||||
return round(2.3 + random.random(), 3)
|
||||
|
||||
|
||||
class SampleTemp(Driveable):
|
||||
class SampleTemp(Drivable):
|
||||
"""a sample temperature
|
||||
"""
|
||||
PARAMS = {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
import random
|
||||
|
||||
from secop.modules import Readable, Driveable, PARAM
|
||||
from secop.modules import Readable, Drivable, PARAM
|
||||
from secop.datatypes import FloatRange, StringType
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ class LN2(Readable):
|
||||
return round(100 * random.random(), 1)
|
||||
|
||||
|
||||
class Heater(Driveable):
|
||||
class Heater(Drivable):
|
||||
"""Just a driveable.
|
||||
|
||||
class name indicates it to be some heating element,
|
||||
@ -56,7 +56,7 @@ class Heater(Driveable):
|
||||
pass
|
||||
|
||||
|
||||
class Temp(Driveable):
|
||||
class Temp(Drivable):
|
||||
"""Just a driveable.
|
||||
|
||||
class name indicates it to be some temperature controller,
|
||||
|
@ -23,7 +23,7 @@
|
||||
import random
|
||||
|
||||
from secop.datatypes import EnumType, TupleOf, FloatRange, get_datatype, StringType
|
||||
from secop.modules import Readable, Device, Driveable, PARAM
|
||||
from secop.modules import Readable, Device, Drivable, PARAM
|
||||
from secop.protocol import status
|
||||
|
||||
try:
|
||||
@ -58,7 +58,7 @@ except ImportError:
|
||||
|
||||
|
||||
class EpicsReadable(Readable):
|
||||
"""EpicsDriveable handles a Driveable interfacing to EPICS v4"""
|
||||
"""EpicsDrivable handles a Drivable interfacing to EPICS v4"""
|
||||
# Commmon PARAMS for all EPICS devices
|
||||
PARAMS = {
|
||||
'value': PARAM('EPICS generic value',
|
||||
@ -117,8 +117,8 @@ class EpicsReadable(Readable):
|
||||
return (status.OK, 'no pv set')
|
||||
|
||||
|
||||
class EpicsDriveable(Driveable):
|
||||
"""EpicsDriveable handles a Driveable interfacing to EPICS v4"""
|
||||
class EpicsDrivable(Drivable):
|
||||
"""EpicsDrivable handles a Drivable interfacing to EPICS v4"""
|
||||
# Commmon PARAMS for all EPICS devices
|
||||
PARAMS = {
|
||||
'target': PARAM('EPICS generic target', datatype=FloatRange(),
|
||||
@ -193,7 +193,7 @@ class EpicsDriveable(Driveable):
|
||||
# features are agreed upon
|
||||
|
||||
|
||||
class EpicsTempCtrl(EpicsDriveable):
|
||||
class EpicsTempCtrl(EpicsDrivable):
|
||||
|
||||
PARAMS = {
|
||||
# TODO: restrict possible values with oneof datatype
|
||||
|
@ -33,10 +33,10 @@ from secop.lib.sequence import SequencerMixin, Step
|
||||
from secop.protocol import status
|
||||
from secop.datatypes import *
|
||||
from secop.errors import SECoPServerError, ConfigError, ProgrammingError, CommunicationError, HardwareError, DisabledError
|
||||
from secop.modules import PARAM, CMD, OVERRIDE, Device, Readable, Driveable
|
||||
from secop.modules import PARAM, CMD, OVERRIDE, Device, Readable, Drivable
|
||||
|
||||
|
||||
class GarfieldMagnet(SequencerMixin, Driveable):
|
||||
class GarfieldMagnet(SequencerMixin, Drivable):
|
||||
"""Garfield Magnet
|
||||
|
||||
uses a polarity switch ('+' or '-') to flip polarity and an onoff switch
|
||||
|
@ -41,7 +41,7 @@ from secop.lib import lazy_property, mkthread
|
||||
from secop.protocol import status
|
||||
from secop.datatypes import *
|
||||
from secop.errors import SECoPServerError, ConfigError, ProgrammingError, CommunicationError, HardwareError
|
||||
from secop.modules import PARAM, CMD, OVERRIDE, Device, Readable, Driveable
|
||||
from secop.modules import PARAM, CMD, OVERRIDE, Device, Readable, Drivable
|
||||
|
||||
|
||||
# Only export these classes for 'from secop_mlz import *'
|
||||
@ -394,7 +394,7 @@ class Sensor(AnalogInput):
|
||||
self._dev.Adjust(value)
|
||||
|
||||
|
||||
class AnalogOutput(PyTangoDevice, Driveable):
|
||||
class AnalogOutput(PyTangoDevice, Drivable):
|
||||
"""
|
||||
The AnalogOutput handles all devices which set an analogue value.
|
||||
|
||||
@ -800,7 +800,7 @@ class PartialDigitalInput(NamedDigitalInput):
|
||||
return value # mapping is done by datatype upon export()
|
||||
|
||||
|
||||
class DigitalOutput(PyTangoDevice, Driveable):
|
||||
class DigitalOutput(PyTangoDevice, Drivable):
|
||||
"""
|
||||
A devices that can set and read a digital value corresponding to a
|
||||
bitfield.
|
||||
|
Loading…
x
Reference in New Issue
Block a user