def make_meta(subtyp, description, tags, writeable=True, labels=None): if subtyp == "enum": if writeable: widget_type = "combo" else: widget_type = "textupdate" tags.append(widget(widget_type)) meta = ChoiceMeta(description, labels, tags) elif subtyp == "bit": if writeable: widget_type = "checkbox" else: widget_type = "led" tags.append(widget(widget_type)) meta = BooleanMeta(description, tags) else: if writeable: widget_type = "textinput" else: widget_type = "textupdate" tags.append(widget(widget_type)) if subtyp == "uint": meta = NumberMeta("uint32", description, tags) elif subtyp == "int": meta = NumberMeta("int32", description, tags) elif subtyp == "scalar": meta = NumberMeta("float64", description, tags) elif subtyp == "lut": meta = StringMeta(description, tags) elif subtyp in ("pos", "relative_pos"): meta = NumberMeta("float64", description, tags) else: raise ValueError("Unknown subtype %r" % subtyp) return meta
def create_attribute_models(self): for data in super(ManagerController, self).create_attribute_models(): yield data assert os.path.isdir(self.params.configDir), \ "%s is not a directory" % self.params.configDir if not os.path.isdir(os.path.join(self.params.configDir, ".git")): # Try and make it a git repo, don't care if it fails self._run_git_cmd("init") self._run_git_cmd("commit", "--allow-empty", "-m", "Created repo") # Create writeable attribute table for the layout info we need elements = OrderedDict() elements["name"] = StringArrayMeta("Name of layout part") elements["mri"] = StringArrayMeta("Malcolm full name of child block") elements["x"] = NumberArrayMeta( "float64", "X Coordinate of child block") elements["y"] = NumberArrayMeta( "float64", "Y Coordinate of child block") elements["visible"] = BooleanArrayMeta("Whether child block is visible") layout_table_meta = TableMeta( "Layout of child blocks", elements=elements, tags=[widget("flowgraph")]) layout_table_meta.set_writeable_in(ss.READY) self.layout = layout_table_meta.create_attribute_model() yield "layout", self.layout, self.set_layout # Create writeable attribute for loading an existing layout design_meta = ChoiceMeta( "Design name to load", tags=[config(), widget("combo")]) design_meta.set_writeable_in(ss.READY) self.design = design_meta.create_attribute_model() yield "design", self.design, self.set_design # Create writeable attribute table for the exported fields elements = OrderedDict() elements["name"] = ChoiceArrayMeta("Name of exported block.field") elements["exportName"] = StringArrayMeta( "Name of the field within current block") exports_table_meta = TableMeta( "Exported fields of child blocks", tags=[widget("table")], elements=elements) exports_table_meta.set_writeable_in(ss.READY) self.exports = exports_table_meta.create_attribute_model() yield "exports", self.exports, self.set_exports # Create read-only indicator for when things are modified modified_meta = BooleanMeta( "Whether the design is modified", tags=[widget("led")]) self.modified = modified_meta.create_attribute_model() yield "modified", self.modified, None
class TestValidate(unittest.TestCase): def setUp(self): self.boolean_meta = BooleanMeta("test description") def test_given_value_str_then_cast_and_return(self): response = self.boolean_meta.validate("TestValue") assert response response = self.boolean_meta.validate("") assert not response def test_given_value_int_then_cast_and_return(self): response = self.boolean_meta.validate(15) assert response response = self.boolean_meta.validate(0) assert not response def test_given_value_boolean_then_cast_and_return(self): response = self.boolean_meta.validate(True) assert response response = self.boolean_meta.validate(False) assert not response def test_given_value_None_then_return(self): response = self.boolean_meta.validate(None) assert False == response
def test_method_also_takes(self): @method_takes("hello", StringMeta(), REQUIRED, "hello2", BooleanMeta(), False) class Thing(object): def __init__(self): pass @method_also_takes("world", BooleanMeta(), REQUIRED, "hello2", BooleanMeta(), True, "default", StringMeta(), "nothing") class Thing2(Thing): pass # Check original hasn't been modified itakes = MapMeta() elements = OrderedDict() elements["hello"] = StringMeta() elements["hello2"] = BooleanMeta() itakes.set_elements(elements) itakes.set_required(["hello"]) defaults = OrderedDict() defaults["hello2"] = False assert Thing.MethodModel.takes.to_dict() == itakes.to_dict() assert Thing.MethodModel.returns.to_dict() == MapMeta().to_dict() assert Thing.MethodModel.defaults == defaults # Check new one overrides/improves on original itakes = MapMeta() elements = OrderedDict() elements["hello"] = StringMeta() elements["hello2"] = BooleanMeta() elements["world"] = BooleanMeta() elements["default"] = StringMeta() itakes.set_elements(elements) itakes.set_required(["hello", "world"]) defaults = OrderedDict() defaults["hello2"] = True defaults["default"] = "nothing" assert Thing2.MethodModel.takes.to_dict() == itakes.to_dict() assert Thing2.MethodModel.returns.to_dict() == MapMeta().to_dict() assert Thing2.MethodModel.defaults == defaults
"Specify that this class will take a parameter name"), REQUIRED, "description", StringMeta( "Description of this parameter"), REQUIRED, "default", NumberMeta("float64", default_desc), OPTIONAL) def float64(params): """Add a float64 parameter to be passed when instantiating this YAML file""" return args_for_takes(params, NumberMeta, "float64") @method_takes( "name", StringMeta( "Specify that this class will take a parameter name"), REQUIRED, "description", StringMeta( "Description of this parameter"), REQUIRED, "default", NumberMeta("int32", default_desc), OPTIONAL) def int32(params): """Add an int32 parameter to be passed when instantiating this YAML file""" return args_for_takes(params, NumberMeta, "int32") @method_takes( "name", StringMeta( "Specify that this class will take a parameter name"), REQUIRED, "description", StringMeta( "Description of this parameter"), REQUIRED, "default", BooleanMeta("bool", default_desc), OPTIONAL) def boolean(params): """Add a boolean parameter to be passed when instantiating this YAML file""" return args_for_takes(params, BooleanMeta)
def setUp(self): self.boolean_meta = BooleanMeta("test description")
from malcolm.core import Part, method_takes, REQUIRED from malcolm.tags import widget_types, widget, config, group from malcolm.modules.builtin.vmetas import StringMeta, BooleanMeta, ChoiceMeta @method_takes("name", StringMeta("Name of the created attribute"), REQUIRED, "description", StringMeta("Desc of created attribute"), REQUIRED, "widget", ChoiceMeta("Widget type", [""] + widget_types), "", "writeable", BooleanMeta("Is the attribute writeable?"), False, "group", StringMeta("If given, which GUI group should we attach to"), "", "config", BooleanMeta("If writeable, should this field be loaded/saved?"), True) class AttributePart(Part): def __init__(self, params): # The created attribute self.attr = None # Store params self.params = params super(AttributePart, self).__init__(params.name) def create_attribute_models(self): # Find the tags tags = self.create_tags() # Make a meta object for our attribute meta = self.create_meta(self.params.description, tags) # The attribute we will be publishing initial_value = self.get_initial_value() self.attr = meta.create_attribute_model(initial_value) if self.is_writeable():
from malcolm.modules.builtin.controllers import ProxyController from malcolm.core import method_takes, REQUIRED from malcolm.modules.builtin.vmetas import StringMeta, BooleanMeta # This is done in python rather than YAML so that we can choose whether or not # to publish this block via the process @method_takes("comms", StringMeta("MRI for the comms block"), REQUIRED, "mri", StringMeta("MRI for the client block"), REQUIRED, "publish", BooleanMeta("Whether to publish this block"), False) def proxy_block(process, params): controller = ProxyController(process, (), params) process.add_controller(params.mri, controller, params.publish) return controller
from malcolm.modules.builtin.controllers import StatefulController from malcolm.core import Part, method_takes, REQUIRED, MethodModel from malcolm.modules.builtin.vmetas import StringMeta, NumberMeta, BooleanMeta from .catoolshelper import CaToolsHelper @method_takes( "name", StringMeta("Name of the created method"), REQUIRED, "description", StringMeta("desc of created method"), REQUIRED, "pv", StringMeta("full pv to write to when method called"), REQUIRED, "statusPv", StringMeta("Status pv to see if successful"), "", "goodStatus", StringMeta("Good value for status pv"), "", "messagePv", StringMeta("PV containing error message if unsuccessful"), "", "value", NumberMeta("int32", "value to write to pv when method called"), 1, "wait", BooleanMeta("Wait for caput callback?"), True) class CAActionPart(Part): """Group a number of PVs together that represent a method like acquire()""" def __init__(self, params): """ Args: params (Map): The params to initialize with """ self.method = None self.params = params self.catools = CaToolsHelper.instance() super(CAActionPart, self).__init__(params.name) def create_method_models(self): # Method instance self.method = MethodModel(self.params.description) # TODO: set widget tag?
from paho.mqtt import client from malcolm.modules.builtin.controllers.servercomms import ServerComms from malcolm.core import Hook, method_also_takes, Process, Subscribe, Update, Put, Unsubscribe from malcolm.modules.builtin.vmetas import StringMeta, NumberMeta, BooleanMeta @method_also_takes( "host", StringMeta("Address of MQTT broker"), "localhost", "port", NumberMeta("int32", "Port number to connect to the broker on"), 1883, "keepalive", NumberMeta("int32", "Number of seconds between pings to broker if no traffic since"), 60, "block", StringMeta("Block name to monitor"), "", "attribute", StringMeta("Attribute of block to monitor"), "", "topic_prefix", StringMeta("Prefix to prepend to MQTT topic (no slash)"), "", "read_only", BooleanMeta("Should MQTT only read and not write?"), True) class MQTTServerComms(ServerComms): """A class for communication between Malcolm and an MQTT broker""" _server = None _spawned = None _blockname = None _attributename = None _topic = None _blocking = False use_cothread = False def do_init(self): self.log.warn(self.params.read_only) super(MQTTServerComms, self).do_init() self._blockname = self.params.block self._attributename = self.params.attribute self._topic = str.join("", [self.params.topic_prefix, "/", self.params.block,
from malcolm.modules.builtin.vmetas import StringMeta, ChoiceMeta, \ BooleanMeta, NumberMeta from .catoolshelper import CaToolsHelper @method_takes( "name", StringMeta("Name of the created attribute"), REQUIRED, "description", StringMeta("Description of created attribute"), REQUIRED, "pv", StringMeta("Full pv of demand and default for rbv"), "", "rbv", StringMeta("Override for rbv"), "", "rbvSuff", StringMeta("Set rbv to pv + rbv_suff"), "", "widget", ChoiceMeta("Widget type", [""] + widget_types), "", "inport", ChoiceMeta("Inport type", [""] + port_types), "", "group", StringMeta("If given, which GUI group should we attach to"), "", "config", BooleanMeta("Should this field be loaded/saved?"), True, "minDelta", NumberMeta("float64", "Minimum time between attribute updates in seconds"), 0.05, "timeout", NumberMeta("float64", "Max time to wait for puts to complete, <0 is forever"), 5.0) class CAPart(AttributePart): """Abstract class for exposing PVs as `Attribute` instances""" def __init__(self, params): if not params.rbv and not params.pv: raise ValueError('Must pass pv or rbv') if not params.rbv: if params.rbvSuff: params.rbv = params.pv + params.rbvSuff else: params.rbv = params.pv # Camonitor subscription
def create_meta(self, description, tags): return BooleanMeta(description=description, tags=tags)
"""Define a float64 parameter to be used within this YAML file""" return {params.name: params.value} @method_takes("name", StringMeta("The name of the defined parameter"), REQUIRED, "value", NumberMeta("int32", "The value of the defined parameter"), REQUIRED) def int32(params): """Define an int32 parameter to be used within this YAML file""" return {params.name: params.value} @method_takes("name", StringMeta("The name of the defined parameter"), REQUIRED, "value", BooleanMeta("bool", "The value of the defined parameter"), REQUIRED) def boolean(params): """Define a boolean parameter to be used within this YAML file""" return {params.name: params.value} @method_takes("value", StringMeta("The docstring value"), REQUIRED) def docstring(params): """Define the docstring for the YAML file""" return {"docstring": params.value} @method_takes( "name", StringMeta("The name of the defined parameter"), REQUIRED, "env", StringMeta("The environment variable name to get the value from"), REQUIRED)