Exemplo n.º 1
0
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
Exemplo n.º 2
0
 def create_attributes(self):
     for data in super(DetectorDriverPart, self).create_attributes():
         yield data
     meta = NumberMeta("float64", "Time taken to readout detector")
     self.readout_time = meta.make_attribute(self.params.readoutTime)
     yield "readoutTime", self.readout_time, self.readout_time.set_value
     meta = ChoiceMeta("Whether detector is software or hardware triggered",
                       ["Software", "Hardware"])
     self.trigger_mode = meta.make_attribute("Hardware")
     yield "triggerMode", self.trigger_mode, None
Exemplo n.º 3
0
 def create_attributes(self):
     for data in super(DetectorDriverPart, self).create_attributes():
         yield data
     meta = NumberMeta("float64", "Time taken to readout detector")
     self.readout_time = meta.make_attribute(self.params.readoutTime)
     yield "readoutTime", self.readout_time, self.readout_time.set_value
     meta = ChoiceMeta("Whether detector is software or hardware triggered",
                       ["Software", "Hardware"])
     self.trigger_mode = meta.make_attribute("Hardware")
     yield "triggerMode", self.trigger_mode, None
Exemplo n.º 4
0
 def _make_scale_offset(self, field_name):
     group_tag = self._make_group("outputs")
     meta = StringMeta("Units for position fields on this block",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".UNITS", meta, writeable=True)
     meta = NumberMeta("float64",
                       "Scale for block position fields",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".SCALE", meta, writeable=True)
     meta = NumberMeta("float64",
                       "Offset for block position fields",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".OFFSET", meta, writeable=True)
Exemplo n.º 5
0
class CounterPart(Part):
    # Attribute for the counter value
    counter = None

    def create_attributes(self):
        self.counter = NumberMeta("uint32", "A counter").make_attribute(0)
        yield "counter", self.counter, self.counter.set_value

    @method_takes()
    def zero(self):
        self.counter.set_value(0)

    @method_takes()
    def increment(self):
        self.counter.set_value(self.counter.value + 1)
Exemplo n.º 6
0
 def create_attributes(self):
     for data in super(PMACTrajectoryPart, self).create_attributes():
         yield data
     self.min_turnaround = NumberMeta(
         "float64", "Min time for any gaps between frames").make_attribute(
         self.params.minTurnaround)
     yield "minTurnaround", self.min_turnaround, \
           self.min_turnaround.set_value
 def test_from_dict(self):
     nm = NumberMeta.from_dict(self.serialized)
     self.assertEqual(type(nm), NumberMeta)
     self.assertEquals(nm.description, "desc")
     self.assertEquals(nm.dtype, "float64")
     self.assertEqual(nm.tags, [])
     self.assertFalse(nm.writeable)
     self.assertEqual(nm.label, "name")
Exemplo n.º 8
0
 def test_from_dict(self):
     nm = NumberMeta.from_dict(self.serialized)
     self.assertEqual(type(nm), NumberMeta)
     self.assertEquals(nm.description, "desc")
     self.assertEquals(nm.dtype, "float64")
     self.assertEqual(nm.tags, [])
     self.assertFalse(nm.writeable)
     self.assertEqual(nm.label, "name")
Exemplo n.º 9
0
class CounterPart(Part):
    # Attribute for the counter value
    counter = None

    def create_attributes(self):
        self.counter = NumberMeta("float64", "A counter").make_attribute()
        yield "counter", self.counter, self.counter.set_value

    @method_takes()
    def zero(self):
        """Zero the counter attribute"""
        self.counter.set_value(0)

    @method_takes()
    def increment(self):
        """Add one to the counter attribute"""
        self.counter.set_value(self.counter.value + 1)
Exemplo n.º 10
0
 def setUp(self):
     n = NumberMeta(description='a number')
     s = StringMeta(description="a string")
     self.meta = MapMeta()
     self.meta.set_elements(ElementMap({"a": s, "b": s}))
     self.meta.set_required(["a"])
     self.nmeta = MapMeta()
     self.nmeta.set_elements(ElementMap({"a": n, "b": n}))
     self.nmeta.set_required(["a"])
Exemplo n.º 11
0
 def create_attributes(self):
     for data in super(RunnableController, self).create_attributes():
         yield data
     self.completed_steps = NumberMeta(
         "int32", "Readback of number of scan steps").make_attribute(0)
     self.completed_steps.meta.set_writeable_in(sm.PAUSED, sm.READY)
     yield "completedSteps", self.completed_steps, self.set_completed_steps
     self.configured_steps = NumberMeta(
         "int32", "Number of steps currently configured").make_attribute(0)
     yield "configuredSteps", self.configured_steps, None
     self.total_steps = NumberMeta(
         "int32", "Readback of number of scan steps"
     ).make_attribute(0)
     yield "totalSteps", self.total_steps, None
     self.axes_to_move = StringArrayMeta(
         "Default axis names to scan for configure()"
     ).make_attribute(self.params.axesToMove)
     self.axes_to_move.meta.set_writeable_in(sm.EDITABLE)
     yield "axesToMove", self.axes_to_move, self.set_axes_to_move
Exemplo n.º 12
0
class ScanTickerPart(ChildPart):
    # Generator instance
    generator = None
    # Where to start
    completed_steps = None
    # How many steps to do
    steps_to_do = None
    # When to blow up
    exception_step = None

    @RunnableController.Configure
    @RunnableController.PostRunReady
    @RunnableController.Seek
    @method_takes(
        "generator", PointGeneratorMeta("Generator instance"), REQUIRED,
        "axesToMove",
        StringArrayMeta(
            "List of axes in inner dimension of generator that should be moved"
        ), REQUIRED, "exceptionStep",
        NumberMeta("int32",
                   "If >0, raise an exception at the end of this step"), 0)
    def configure(self, task, completed_steps, steps_to_do, part_info, params):
        # If we are being asked to move
        if self.name in params.axesToMove:
            # Just store the generator and place we need to start
            self.generator = params.generator
            self.completed_steps = completed_steps
            self.steps_to_do = steps_to_do
            self.exception_step = params.exceptionStep
        else:
            # Flag nothing to do
            self.generator = None

    @RunnableController.Run
    @RunnableController.Resume
    def run(self, task, update_completed_steps):
        # Start time so everything is relative
        point_time = time.time()
        if self.generator:
            for i in range(self.completed_steps,
                           self.completed_steps + self.steps_to_do):
                # Get the point we are meant to be scanning
                point = self.generator.get_point(i)
                # Update the child counter to be the demand position
                position = point.positions[self.name]
                task.put(self.child["counter"], position)
                # Wait until the next point is due
                point_time += point.duration
                wait_time = point_time - time.time()
                task.sleep(wait_time)
                # Update the point as being complete
                update_completed_steps(i + 1, self)
                # If this is the exception step then blow up
                assert i +1 != self.exception_step, \
                    "Raising exception at step %s" % self.exception_step
Exemplo n.º 13
0
    def test_getattr(self):
        b = Block()
        a = NumberMeta("int32").make_attribute()
        b.replace_endpoints(dict(a=a))

        def f(meta, value):
            a.set_value(value)

        b.set_writeable_functions(dict(a=f))
        b.a = 32
        self.assertEqual(b.a, 32)
Exemplo n.º 14
0
 def _make_time_parts(self, field_name, field_data, writeable):
     description = field_data.description
     if writeable:
         widget_tag = widget("textupdate")
         group_tag = self._make_group("parameters")
     else:
         widget_tag = widget("textinput")
         group_tag = self._make_group("readbacks")
     meta = NumberMeta("float64", description, [group_tag, widget_tag])
     self._make_field_part(field_name, meta, writeable)
     meta = ChoiceMeta(description + " time units", ["s", "ms", "us"],
                       tags=[group_tag, widget("combo")])
     self._make_field_part(field_name + ".UNITS", meta, writeable=True)
class RawMotorPart(LayoutPart):
    @ManagerController.Report
    @method_returns("cs_axis", StringMeta("CS axis (like A, B, I, 0)"),
                    REQUIRED, "cs_port", StringMeta("CS port name"), REQUIRED,
                    "acceleration_time",
                    NumberMeta("float64",
                               "Seconds to velocity"), REQUIRED, "resolution",
                    NumberMeta("float64",
                               "Motor resolution"), REQUIRED, "offset",
                    NumberMeta("float64",
                               "Motor user offset"), REQUIRED, "max_velocity",
                    NumberMeta("float64", "Maximum motor velocity"), REQUIRED,
                    "current_position",
                    NumberMeta("float64", "Current motor position"), REQUIRED)
    def report_cs_info(self, _, returns):
        returns.cs_axis = self.child.cs_axis
        returns.cs_port = self.child.cs_port
        returns.acceleration_time = self.child.acceleration_time
        returns.resolution = self.child.resolution
        returns.offset = self.child.offset
        returns.max_velocity = self.child.max_velocity
        returns.current_position = self.child.position
        return returns
Exemplo n.º 16
0
class HelloPart(Part):
    @method_takes(
        "name",
        StringMeta("a name"),
        REQUIRED,
        "sleep",
        NumberMeta("float64", "Time to wait before returning"),
        0,
    )
    @method_returns("greeting", StringMeta(description="a greeting"), REQUIRED)
    def greet(self, parameters, return_map):
        """Optionally sleep <sleep> seconds, then return a greeting to <name>"""
        print("Manufacturing greeting...")
        time.sleep(parameters.sleep)
        return_map.greeting = "Hello %s" % parameters.name
        return return_map
Exemplo n.º 17
0
    def test_to_dict(self):
        a_mock = MagicMock()
        s = StringMeta(description="a string")
        meta = Meta()
        meta.elements = OrderedDict()
        meta.elements["b"] = s
        meta.elements["c"] = s
        meta.elements["d"] = NumberMeta("int32")
        meta.elements["e"] = s
        m = Map(meta, {"b":"test", "d":123, "e":"e"})

        expected = OrderedDict()
        expected["typeid"] = "malcolm:core/Map:1.0"
        expected["b"] = "test"
        expected["d"] = 123
        expected["e"] = "e"
        self.assertEquals(expected, m.to_dict())
Exemplo n.º 18
0
 def create_attributes(self):
     for data in super(RunnableController, self).create_attributes():
         yield data
     self.completed_steps = NumberMeta(
         "int32", "Readback of number of scan steps").make_attribute(0)
     self.completed_steps.meta.set_writeable_in(sm.PAUSED, sm.READY)
     yield "completedSteps", self.completed_steps, self.set_completed_steps
     self.configured_steps = NumberMeta(
         "int32", "Number of steps currently configured").make_attribute(0)
     yield "configuredSteps", self.configured_steps, None
     self.total_steps = NumberMeta(
         "int32", "Readback of number of scan steps").make_attribute(0)
     yield "totalSteps", self.total_steps, None
     self.axes_to_move = StringArrayMeta(
         "Default axis names to scan for configure()").make_attribute(
             self.params.axesToMove)
     self.axes_to_move.meta.set_writeable_in(sm.EDITABLE)
     yield "axesToMove", self.axes_to_move, self.set_axes_to_move
Exemplo n.º 19
0
class HelloPart(Part):
    @method_takes(
        "name",
        StringMeta("a name"),
        REQUIRED,
        "sleep",
        NumberMeta("float64", "Time to wait before returning"),
        0,
    )
    @method_returns("greeting", StringMeta(description="a greeting"), REQUIRED)
    def say_hello(self, parameters, return_map):
        """Says Hello to name

        Args:
            parameters(Map): The name of the person to say hello to
            return_map(Map): Return structure to complete and return

        Returns:
            Map: The greeting
        """

        return_map.greeting = "Hello %s" % parameters.name
        time.sleep(parameters.sleep)
        return return_map
Exemplo n.º 20
0
 def create_meta(self, description, tags):
     return NumberMeta("float64", description=description, tags=tags)
Exemplo n.º 21
0
 def test_to_dict(self):
     nm = NumberMeta("float64", "desc", label="name")
     self.assertEqual(nm.to_dict(), self.serialized)
Exemplo n.º 22
0
 def test_unsigned_validates(self):
     nm = NumberMeta("uint32")
     self.assertEqual(nm.validate("22"), 22)
     self.assertEqual(nm.validate(-22), 2**32-22)
Exemplo n.º 23
0
 def test_none_validates(self):
     nm = NumberMeta("int32")
     self.assertEquals(0, nm.validate(None))
Exemplo n.º 24
0
from malcolm.parts.builtin.attributepart import AttributePart
from malcolm.core import method_also_takes
from malcolm.core.vmetas import NumberMeta


@method_also_takes(
    "initialValue",
    NumberMeta("float64", "Initial value of attribute"),
    0.0,
)
class Float64Part(AttributePart):
    def get_initial_value(self):
        return self.params.initialValue

    def create_meta(self, description, tags):
        return NumberMeta("float64", description=description, tags=tags)
Exemplo n.º 25
0
from malcolm.core import method_takes, REQUIRED
from malcolm.core.vmetas import StringMeta, NumberMeta

from malcolm.parts.pandabox.pandaboxcontrol import PandABoxControl
from malcolm.parts.pandabox.pandaboxpoller import PandABoxPoller


@method_takes("mriPrefix", StringMeta("Malcolm resource id prefix for blocks"),
              REQUIRED, "hostname", StringMeta("Hostname of the box"),
              "localhost", "port",
              NumberMeta("uint32", "Port number of the server control"), 8888,
              "areaDetectorPrefix",
              StringMeta("Prefix for areaDetector records, if using EPICS"),
              "")
def hardware_collection(process, params):

    # Connect to the Control port
    control = PandABoxControl(process, params.hostname, params.port)
    control.start()

    # Create a block updater
    poller = PandABoxPoller(process, control)

    # Get some information about what is available in this PandABox
    blocks_data = control.get_blocks_data()
    blocks = []
    parts = []

    for block_name, block_data in blocks_data.items():
        block_names = []
        if block_data.number == 1:
Exemplo n.º 26
0
class RunnableController(ManagerController):
    """RunnableDevice implementer that also exposes GUI for child parts"""
    # The stateMachine that this controller implements
    stateMachine = sm()

    Validate = Hook()
    """Called at validate() to check parameters are valid

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part validate()
            method_takes() decorator

    Returns:
        [`ParameterTweakInfo`] - any parameters tweaks that have occurred
            to make them compatible with this part. If any are returned,
            Validate will be re-run with the modified parameters.
    """

    ReportStatus = Hook()
    """Called before Validate, Configure, PostRunReady and Seek hooks to report
    the current configuration of all parts

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        [`Info`] - any configuration Info objects relevant to other parts
    """

    Configure = Hook()
    """Called at configure() to configure child block for a run

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator

    Returns:
        [`Info`] - any Info objects that need to be passed to other parts for
            storing in attributes
    """

    PostConfigure = Hook()
    """Called at the end of configure() to store configuration info calculated
     in the Configure hook

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from Configure hook
    """

    Run = Hook()
    """Called at run() to start the configured steps running

    Args:
        task (Task): The task used to perform operations on child blocks
        update_completed_steps (callable): If part can report progress, this
            part should call update_completed_steps(completed_steps, self) with
            the integer step value each time progress is updated
    """

    PostRunReady = Hook()
    """Called at the end of run() when there are more steps to be run

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator
    """

    PostRunIdle = Hook()
    """Called at the end of run() when there are no more steps to be run

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    Pause = Hook()
    """Called at pause() to pause the current scan before Seek is called

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    Seek = Hook()
    """Called at seek() or at the end of pause() to reconfigure for a different
    number of completed_steps

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator
    """

    Resume = Hook()
    """Called at resume() to continue a paused scan

    Args:
        task (Task): The task used to perform operations on child blocks
        update_completed_steps (callable): If part can report progress, this
            part should call update_completed_steps(completed_steps, self) with
            the integer step value each time progress is updated
    """

    Abort = Hook()
    """Called at abort() to stop the current scan

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    # Attributes
    completed_steps = None
    configured_steps = None
    total_steps = None
    axes_to_move = None

    # Params passed to configure()
    configure_params = None

    # Stored for pause
    steps_per_run = 0

    # Progress reporting dict
    # {part: completed_steps for that part}
    progress_reporting = None

    @method_writeable_in(sm.IDLE)
    def edit(self):
        # Override edit to only work from Idle
        super(RunnableController, self).edit()

    @method_writeable_in(sm.FAULT, sm.DISABLED, sm.ABORTED, sm.READY)
    def reset(self):
        # Override reset to work from aborted and ready too
        super(RunnableController, self).reset()

    def create_attributes(self):
        for data in super(RunnableController, self).create_attributes():
            yield data
        self.completed_steps = NumberMeta(
            "int32", "Readback of number of scan steps").make_attribute(0)
        self.completed_steps.meta.set_writeable_in(sm.PAUSED, sm.READY)
        yield "completedSteps", self.completed_steps, self.set_completed_steps
        self.configured_steps = NumberMeta(
            "int32", "Number of steps currently configured").make_attribute(0)
        yield "configuredSteps", self.configured_steps, None
        self.total_steps = NumberMeta(
            "int32", "Readback of number of scan steps"
        ).make_attribute(0)
        yield "totalSteps", self.total_steps, None
        self.axes_to_move = StringArrayMeta(
            "Default axis names to scan for configure()"
        ).make_attribute(self.params.axesToMove)
        self.axes_to_move.meta.set_writeable_in(sm.EDITABLE)
        yield "axesToMove", self.axes_to_move, self.set_axes_to_move

    def do_reset(self):
        super(RunnableController, self).do_reset()
        self._update_configure_args()
        self.configured_steps.set_value(0)
        self.completed_steps.set_value(0)
        self.total_steps.set_value(0)

    def go_to_error_state(self, exception):
        if isinstance(exception, AbortedError):
            self.log_info("Got AbortedError in %s" % self.state.value)
        else:
            super(RunnableController, self).go_to_error_state(exception)

    def _update_configure_args(self):
        # Look for all parts that hook into Configure
        configure_funcs = self.Configure.find_hooked_functions(self.parts)
        method_metas = []
        for part, func_name in configure_funcs.items():
            method_metas.append(part.method_metas[func_name])

        # Update takes with the things we need
        default_configure = MethodMeta.from_dict(
            RunnableController.configure.MethodMeta.to_dict())
        default_configure.defaults["axesToMove"] = self.axes_to_move.value
        method_metas.append(default_configure)

        # Decorate validate and configure with the sum of its parts
        self.block["validate"].recreate_from_others(method_metas)
        self.block["validate"].set_returns(self.block["validate"].takes)
        self.block["configure"].recreate_from_others(method_metas)

    def set_axes_to_move(self, value):
        self.axes_to_move.set_value(value)
        self._update_configure_args()

    @method_takes(*configure_args)
    def validate(self, params, returns):
        iterations = 10
        # Make some tasks just for validate
        part_tasks = self.create_part_tasks()
        # Get any status from all parts
        status_part_info = self.run_hook(self.ReportStatus, part_tasks)
        while iterations > 0:
            # Try up to 10 times to get a valid set of parameters
            iterations -= 1
            # Validate the params with all the parts
            validate_part_info = self.run_hook(
                self.Validate, part_tasks, status_part_info, **params)
            tweaks = ParameterTweakInfo.filter_values(validate_part_info)
            if tweaks:
                for tweak in tweaks:
                    params[tweak.parameter] = tweak.value
                    self.log_debug(
                        "Tweaking %s to %s", tweak.parameter, tweak.value)
            else:
                # Consistent set, just return the params
                return params
        raise ValueError("Could not get a consistent set of parameters")

    @method_takes(*configure_args)
    @method_writeable_in(sm.IDLE)
    def configure(self, params):
        """Configure for a scan"""
        self.validate(params, params)
        self.try_stateful_function(
            sm.CONFIGURING, sm.READY, self.do_configure, params)

    def do_configure(self, params):
        # These are the part tasks that abort() and pause() will operate on
        self.part_tasks = self.create_part_tasks()
        # Store the params for use in seek()
        self.configure_params = params
        # Set the steps attributes that we will do across many run() calls
        self.total_steps.set_value(params.generator.num)
        self.completed_steps.set_value(0)
        self.configured_steps.set_value(0)
        # TODO: this should come from tne generator
        self.steps_per_run = self._get_steps_per_run(
            params.generator, params.axesToMove)
        # Get any status from all parts
        part_info = self.run_hook(self.ReportStatus, self.part_tasks)
        # Use the ProgressReporting classes for ourselves
        self.progress_reporting = {}
        # Run the configure command on all parts, passing them info from
        # ReportStatus. Parts should return any reporting info for PostConfigure
        completed_steps = 0
        steps_to_do = self.steps_per_run
        part_info = self.run_hook(
            self.Configure, self.part_tasks, completed_steps, steps_to_do,
            part_info, **self.configure_params)
        # Take configuration info and reflect it as attribute updates
        self.run_hook(self.PostConfigure, self.part_tasks, part_info)
        # Update the completed and configured steps
        self.configured_steps.set_value(steps_to_do)

    def _get_steps_per_run(self, generator, axes_to_move):
        steps = 1
        axes_set = set(axes_to_move)
        for g in reversed(generator.generators):
            # If the axes_set is empty then we are done
            if not axes_set:
                break
            # Consume the axes that this generator scans
            for axis in g.position_units:
                assert axis in axes_set, \
                    "Axis %s is not in %s" % (axis, axes_to_move)
                axes_set.remove(axis)
            # Now multiply by the dimensions to get the number of steps
            for dim in g.index_dims:
                steps *= dim
        return steps

    @method_writeable_in(sm.READY)
    def run(self):
        """Run an already configured scan"""
        if self.configured_steps.value < self.total_steps.value:
            next_state = sm.READY
        else:
            next_state = sm.IDLE
        self.try_stateful_function(sm.RUNNING, next_state, self._call_do_run)

    def _call_do_run(self):
        hook = self.Run
        while True:
            try:
                self.do_run(hook)
            except AbortedError:
                # Work out if it was an abort or pause
                state = self.state.value
                self.log_debug("Do run got AbortedError from %s", state)
                if state in (sm.SEEKING, sm.PAUSED):
                    # Wait to be restarted
                    task = Task("StateWaiter", self.process)
                    bad_states = [sm.DISABLING, sm.ABORTING, sm.FAULT]
                    try:
                        task.when_matches(self.state, sm.RUNNING, bad_states)
                    except BadValueError:
                        # raise AbortedError so we don't try to transition
                        raise AbortedError()
                    # Restart it
                    hook = self.Resume
                    self.status.set_value("Run resumed")
                else:
                    # just drop out
                    raise
            else:
                return

    def do_run(self, hook):
        self.run_hook(hook, self.part_tasks, self.update_completed_steps)
        self.transition(sm.POSTRUN, "Finishing run")
        completed_steps = self.configured_steps.value
        if completed_steps < self.total_steps.value:
            steps_to_do = self.steps_per_run
            part_info = self.run_hook(self.ReportStatus, self.part_tasks)
            self.completed_steps.set_value(completed_steps)
            self.run_hook(
                self.PostRunReady, self.part_tasks, completed_steps,
                steps_to_do, part_info, **self.configure_params)
            self.configured_steps.set_value(completed_steps + steps_to_do)
        else:
            self.run_hook(self.PostRunIdle, self.part_tasks)

    def update_completed_steps(self, completed_steps, part):
        # This is run in the child thread, so make sure it is thread safe
        self.progress_reporting[part] = completed_steps
        min_completed_steps = min(self.progress_reporting.values())
        if min_completed_steps > self.completed_steps.value:
            self.completed_steps.set_value(min_completed_steps)

    @method_writeable_in(
        sm.IDLE, sm.CONFIGURING, sm.READY, sm.RUNNING, sm.POSTRUN, sm.PAUSED,
        sm.SEEKING)
    def abort(self):
        self.try_stateful_function(
            sm.ABORTING, sm.ABORTED, self.do_abort, self.Abort)

    def do_abort(self, hook):
        for task in self.part_tasks.values():
            task.stop()
        self.run_hook(hook, self.create_part_tasks())
        for task in self.part_tasks.values():
            task.wait()

    def set_completed_steps(self, completed_steps):
        params = self.pause.MethodMeta.prepare_input_map(
            completedSteps=completed_steps)
        self.pause(params)

    @method_writeable_in(sm.READY, sm.PAUSED, sm.RUNNING)
    @method_takes("completedSteps", NumberMeta(
        "int32", "Step to mark as the last completed step, -1 for current"), -1)
    def pause(self, params):
        current_state = self.state.value
        if params.completedSteps < 0:
            completed_steps = self.completed_steps.value
        else:
            completed_steps = params.completedSteps
        if current_state == sm.RUNNING:
            next_state = sm.PAUSED
        else:
            next_state = current_state
        assert completed_steps < self.total_steps.value, \
            "Cannot seek to after the end of the scan"
        self.try_stateful_function(
            sm.SEEKING, next_state, self.do_pause, completed_steps)

    def do_pause(self, completed_steps):
        self.do_abort(self.Pause)
        in_run_steps = completed_steps % self.steps_per_run
        steps_to_do = self.steps_per_run - in_run_steps
        part_info = self.run_hook(self.ReportStatus, self.part_tasks)
        self.completed_steps.set_value(completed_steps)
        self.run_hook(
            self.Seek, self.part_tasks, completed_steps,
            steps_to_do, part_info, **self.configure_params)
        self.configured_steps.set_value(completed_steps + steps_to_do)

    @method_writeable_in(sm.PAUSED)
    def resume(self):
        self.transition(sm.RUNNING, "Resuming run")
Exemplo n.º 27
0
 def create_meta(self, description):
     return NumberMeta("int32", description)
Exemplo n.º 28
0
                # Crossed zero, put in an explicit zero velocity
                fraction = velocity_array[-1] / (velocity_array[-1] - v)
                time_array.append(time_array[-1] + fraction * t)
                velocity_array.append(0)
                t -= fraction * t
            time_array.append(time_array[-1] + t)
            velocity_array.append(v)
        # Add on the settle time
        if self.velocity_settle > 0:
            time_array.append(time_array[-1] + self.velocity_settle)
            velocity_array.append(v2)
        return time_array, velocity_array


@method_also_takes(
    "minTurnaround", NumberMeta(
        "float64", "Min time for any gaps between frames"), 0.0)
class PMACTrajectoryPart(ChildPart):
    # Axis information stored from validate
    # {scannable_name: MotorInfo}
    axis_mapping = None
    # Lookup of the completed_step value for each point
    completed_steps_lookup = []
    # If we are currently loading then block loading more points
    loading = False
    # The last index we have loaded
    end_index = 0
    # Where we should stop loading points
    steps_up_to = 0
    # Stored generator for positions
    generator = None
    # Min turnaround time
    @asynchronous
    def get(self, endpoint_str):
        endpoint = endpoint_str.split("/")
        request = Get(self, None, endpoint)
        self.servercomms.on_request(request)

    # curl --data 'parameters={"name": "me"}' http://localhost:8888/blocks/hello/say_hello
    @asynchronous
    def post(self, endpoint_str):
        endpoint = endpoint_str.split("/")
        parameters = json.loads(self.get_body_argument("parameters"))
        request = Post(self, None, endpoint, parameters)
        self.servercomms.on_request(request)


@method_takes("port", NumberMeta("int32", "Port number to run up under"), 8080)
class WebsocketServerComms(ServerComms):
    """A class for communication between browser and server"""
    def __init__(self, process, params):
        super(WebsocketServerComms, self).__init__(process)
        self.set_logger_name("WebsocketServerComms(%(port)d)" % params)
        MalcWebSocketHandler.servercomms = self
        MalcBlockHandler.servercomms = self

        application = Application([(r"/blocks/(.*)", MalcBlockHandler),
                                   (r"/ws", MalcWebSocketHandler)])
        self.server = HTTPServer(application)
        self.server.listen(int(params["port"]))
        self.loop = IOLoop.current()
        self.add_spawn_function(self.loop.start, self.stop_recv_loop)
Exemplo n.º 30
0
 class MyCAPart(CAPart):
     create_meta = MagicMock(return_value=NumberMeta("int32"))
     get_datatype = MagicMock()
 def create_meta(self, description):
     return NumberMeta("float64", description)
Exemplo n.º 32
0
 def create_attributes(self):
     self.counter = NumberMeta("uint32", "A counter").make_attribute(0)
     yield "counter", self.counter, self.counter.set_value
Exemplo n.º 33
0
 def create_attributes(self):
     self.counter = NumberMeta("float64", "A counter").make_attribute()
     yield "counter", self.counter, self.counter.set_value
Exemplo n.º 34
0
 def test_int_against_float(self):
     nm = NumberMeta("float64")
     self.assertEqual(123, nm.validate(123))
Exemplo n.º 35
0
class LayoutPart(Part):
    # Child block object
    child = None

    # {part_name: visible} saying whether part_name is visible
    part_visible = None

    # Layout options
    x = 0
    y = 0
    visible = False
    mri = None
    name = None

    def store_params(self, params):
        self.name = params.name
        self.child = self.process.get_block(params.child)
        self.mri = params.child
        self.part_visible = {}

    @ManagerController.UpdateLayout
    @method_takes("layout_table", layout_table_meta, REQUIRED, "outport_table",
                  outport_table_meta, REQUIRED)
    @method_returns("mri", StringMeta("Malcolm full name of child block"),
                    REQUIRED, "x",
                    NumberMeta("float64",
                               "X Co-ordinate of child block"), REQUIRED, "y",
                    NumberMeta("float64", "X Co-ordinate of child block"),
                    REQUIRED, "visible",
                    BooleanMeta("Whether child block is visible"), REQUIRED)
    def update_layout_table(self, task, params, returns):
        for i, name in enumerate(params.layout_table.name):
            _, _, x, y, visible = params.layout_table[i]
            if name == self.name:
                if self.visible and not visible:
                    self.sever_inports(task)
                self.x = x
                self.y = y
                self.visible = visible
            else:
                was_visible = self.part_visible.get(name, True)
                if was_visible and not visible:
                    self.sever_outports(task, name, params.outport_table)
                self.part_visible[name] = visible
        returns.mri = self.mri
        returns.x = self.x
        returns.y = self.y
        returns.visible = self.visible
        return returns

    def _get_flowgraph_ports(self, direction="out"):
        # {attr_name: port_tag}
        ports = OrderedDict()
        for attr_name in self.child.endpoints:
            attr = self.child[attr_name]
            if isinstance(attr, Attribute):
                for tag in attr.meta.tags:
                    if tag.startswith("flowgraph:%sport" % direction):
                        ports[attr] = tag
        return ports

    def sever_inports(self, task):
        inports = self._get_flowgraph_ports("in")
        futures = []
        for attr in inports:
            futures += task.put_async(attr, attr.meta.choices[0])
        task.wait_all(futures)

    def sever_outports(self, task, name, outport_table):
        # Find the outports of this part
        # {outport_value: typ} e.g. "PCOMP.OUT" -> "bit"
        outports = {}
        for i, n in enumerate(outport_table.name):
            if n == name:
                outports[outport_table.value[i]] = outport_table.type[i]
        inports = self._get_flowgraph_ports("in")
        futures = []
        for attr, port_tag in inports.items():
            typ = port_tag.split(":")[2]
            if outports.get(attr.value, None) == typ:
                futures += task.put_async(attr, attr.meta.choices[0])
        task.wait_all(futures)

    @ManagerController.ListOutports
    @method_returns("type",
                    StringArrayMeta("Type of outport (e.g. bit or pos)"),
                    REQUIRED, "value",
                    StringArrayMeta("Value of outport (e.g. PULSE1.OUT)"),
                    REQUIRED)
    def list_outports(self, _, returns):
        outports = self._get_flowgraph_ports("out")
        types = []
        values = []
        for port_tag in outports.values():
            _, _, typ, name = port_tag.split(":", 4)
            types.append(typ)
            values.append(name)
        returns.type = types
        returns.value = values
        return returns
Exemplo n.º 36
0
 def test_int_against_int(self):
     nm = NumberMeta("int32")
     self.assertEqual(123, nm.validate(123))
Exemplo n.º 37
0
class RunnableController(ManagerController):
    """RunnableDevice implementer that also exposes GUI for child parts"""
    # The stateMachine that this controller implements
    stateMachine = sm()

    Validate = Hook()
    """Called at validate() to check parameters are valid

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part validate()
            method_takes() decorator

    Returns:
        [`ParameterTweakInfo`] - any parameters tweaks that have occurred
            to make them compatible with this part. If any are returned,
            Validate will be re-run with the modified parameters.
    """

    ReportStatus = Hook()
    """Called before Validate, Configure, PostRunReady and Seek hooks to report
    the current configuration of all parts

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        [`Info`] - any configuration Info objects relevant to other parts
    """

    Configure = Hook()
    """Called at configure() to configure child block for a run

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator

    Returns:
        [`Info`] - any Info objects that need to be passed to other parts for
            storing in attributes
    """

    PostConfigure = Hook()
    """Called at the end of configure() to store configuration info calculated
     in the Configure hook

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from Configure hook
    """

    Run = Hook()
    """Called at run() to start the configured steps running

    Args:
        task (Task): The task used to perform operations on child blocks
        update_completed_steps (callable): If part can report progress, this
            part should call update_completed_steps(completed_steps, self) with
            the integer step value each time progress is updated
    """

    PostRunReady = Hook()
    """Called at the end of run() when there are more steps to be run

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator
    """

    PostRunIdle = Hook()
    """Called at the end of run() when there are no more steps to be run

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    Pause = Hook()
    """Called at pause() to pause the current scan before Seek is called

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    Seek = Hook()
    """Called at seek() or at the end of pause() to reconfigure for a different
    number of completed_steps

    Args:
        task (Task): The task used to perform operations on child blocks
        completed_steps (int): Number of steps already completed
        steps_to_do (int): Number of steps we should configure for
        part_info (dict): {part_name: [Info]} returned from ReportStatus
        params (Map): Any configuration parameters asked for by part configure()
            method_takes() decorator
    """

    Resume = Hook()
    """Called at resume() to continue a paused scan

    Args:
        task (Task): The task used to perform operations on child blocks
        update_completed_steps (callable): If part can report progress, this
            part should call update_completed_steps(completed_steps, self) with
            the integer step value each time progress is updated
    """

    Abort = Hook()
    """Called at abort() to stop the current scan

    Args:
        task (Task): The task used to perform operations on child blocks
    """

    # Attributes
    completed_steps = None
    configured_steps = None
    total_steps = None
    axes_to_move = None

    # Params passed to configure()
    configure_params = None

    # Stored for pause
    steps_per_run = 0

    # Progress reporting dict
    # {part: completed_steps for that part}
    progress_reporting = None

    @method_writeable_in(sm.IDLE)
    def edit(self):
        # Override edit to only work from Idle
        super(RunnableController, self).edit()

    @method_writeable_in(sm.FAULT, sm.DISABLED, sm.ABORTED, sm.READY)
    def reset(self):
        # Override reset to work from aborted and ready too
        super(RunnableController, self).reset()

    def create_attributes(self):
        for data in super(RunnableController, self).create_attributes():
            yield data
        self.completed_steps = NumberMeta(
            "int32", "Readback of number of scan steps").make_attribute(0)
        self.completed_steps.meta.set_writeable_in(sm.PAUSED, sm.READY)
        yield "completedSteps", self.completed_steps, self.set_completed_steps
        self.configured_steps = NumberMeta(
            "int32", "Number of steps currently configured").make_attribute(0)
        yield "configuredSteps", self.configured_steps, None
        self.total_steps = NumberMeta(
            "int32", "Readback of number of scan steps").make_attribute(0)
        yield "totalSteps", self.total_steps, None
        self.axes_to_move = StringArrayMeta(
            "Default axis names to scan for configure()").make_attribute(
                self.params.axesToMove)
        self.axes_to_move.meta.set_writeable_in(sm.EDITABLE)
        yield "axesToMove", self.axes_to_move, self.set_axes_to_move

    def do_reset(self):
        super(RunnableController, self).do_reset()
        self._update_configure_args()
        self.configured_steps.set_value(0)
        self.completed_steps.set_value(0)
        self.total_steps.set_value(0)

    def go_to_error_state(self, exception):
        if isinstance(exception, AbortedError):
            self.log_info("Got AbortedError in %s" % self.state.value)
        else:
            super(RunnableController, self).go_to_error_state(exception)

    def _update_configure_args(self):
        # Look for all parts that hook into Configure
        configure_funcs = self.Configure.find_hooked_functions(self.parts)
        method_metas = []
        for part, func_name in configure_funcs.items():
            method_metas.append(part.method_metas[func_name])

        # Update takes with the things we need
        default_configure = MethodMeta.from_dict(
            RunnableController.configure.MethodMeta.to_dict())
        default_configure.defaults["axesToMove"] = self.axes_to_move.value
        method_metas.append(default_configure)

        # Decorate validate and configure with the sum of its parts
        self.block["validate"].recreate_from_others(method_metas)
        self.block["validate"].set_returns(self.block["validate"].takes)
        self.block["configure"].recreate_from_others(method_metas)

    def set_axes_to_move(self, value):
        self.axes_to_move.set_value(value)
        self._update_configure_args()

    @method_takes(*configure_args)
    def validate(self, params, returns):
        iterations = 10
        # Make some tasks just for validate
        part_tasks = self.create_part_tasks()
        # Get any status from all parts
        status_part_info = self.run_hook(self.ReportStatus, part_tasks)
        while iterations > 0:
            # Try up to 10 times to get a valid set of parameters
            iterations -= 1
            # Validate the params with all the parts
            validate_part_info = self.run_hook(self.Validate, part_tasks,
                                               status_part_info, **params)
            tweaks = ParameterTweakInfo.filter_values(validate_part_info)
            if tweaks:
                for tweak in tweaks:
                    params[tweak.parameter] = tweak.value
                    self.log_debug("Tweaking %s to %s", tweak.parameter,
                                   tweak.value)
            else:
                # Consistent set, just return the params
                return params
        raise ValueError("Could not get a consistent set of parameters")

    @method_takes(*configure_args)
    @method_writeable_in(sm.IDLE)
    def configure(self, params):
        """Configure for a scan"""
        self.validate(params, params)
        self.try_stateful_function(sm.CONFIGURING, sm.READY, self.do_configure,
                                   params)

    def do_configure(self, params):
        # These are the part tasks that abort() and pause() will operate on
        self.part_tasks = self.create_part_tasks()
        # Load the saved settings first
        self.run_hook(self.Load, self.part_tasks, self.load_structure)
        # Store the params for use in seek()
        self.configure_params = params
        # This will calculate what we need from the generator, possibly a long
        # call
        params.generator.prepare()
        # Set the steps attributes that we will do across many run() calls
        self.total_steps.set_value(params.generator.size)
        self.completed_steps.set_value(0)
        self.configured_steps.set_value(0)
        # TODO: We can be cleverer about this and support a different number
        # of steps per run for each run by examining the generator structure
        self.steps_per_run = self._get_steps_per_run(params.generator,
                                                     params.axesToMove)
        # Get any status from all parts
        part_info = self.run_hook(self.ReportStatus, self.part_tasks)
        # Use the ProgressReporting classes for ourselves
        self.progress_reporting = {}
        # Run the configure command on all parts, passing them info from
        # ReportStatus. Parts should return any reporting info for PostConfigure
        completed_steps = 0
        steps_to_do = self.steps_per_run
        part_info = self.run_hook(self.Configure, self.part_tasks,
                                  completed_steps, steps_to_do, part_info,
                                  **self.configure_params)
        # Take configuration info and reflect it as attribute updates
        self.run_hook(self.PostConfigure, self.part_tasks, part_info)
        # Update the completed and configured steps
        self.configured_steps.set_value(steps_to_do)

    def _get_steps_per_run(self, generator, axes_to_move):
        steps = 1
        axes_set = set(axes_to_move)
        for dim in reversed(generator.dimensions):
            # If the axes_set is empty then we are done
            if not axes_set:
                break
            # Consume the axes that this generator scans
            for axis in dim.axes:
                assert axis in axes_set, \
                    "Axis %s is not in %s" % (axis, axes_to_move)
                axes_set.remove(axis)
            # Now multiply by the dimensions to get the number of steps
            steps *= dim.size
        return steps

    @method_writeable_in(sm.READY)
    def run(self):
        """Run an already configured scan"""
        if self.configured_steps.value < self.total_steps.value:
            next_state = sm.READY
        else:
            next_state = sm.IDLE
        self.try_stateful_function(sm.RUNNING, next_state, self._call_do_run)

    def _call_do_run(self):
        hook = self.Run
        while True:
            try:
                self.do_run(hook)
            except AbortedError:
                # Work out if it was an abort or pause
                state = self.state.value
                self.log_debug("Do run got AbortedError from %s", state)
                if state in (sm.SEEKING, sm.PAUSED):
                    # Wait to be restarted
                    task = Task("StateWaiter", self.process)
                    bad_states = [sm.DISABLING, sm.ABORTING, sm.FAULT]
                    try:
                        task.when_matches(self.state, sm.RUNNING, bad_states)
                    except BadValueError:
                        # raise AbortedError so we don't try to transition
                        raise AbortedError()
                    # Restart it
                    hook = self.Resume
                    self.status.set_value("Run resumed")
                else:
                    # just drop out
                    raise
            else:
                return

    def do_run(self, hook):
        self.run_hook(hook, self.part_tasks, self.update_completed_steps)
        self.transition(sm.POSTRUN, "Finishing run")
        completed_steps = self.configured_steps.value
        if completed_steps < self.total_steps.value:
            steps_to_do = self.steps_per_run
            part_info = self.run_hook(self.ReportStatus, self.part_tasks)
            self.completed_steps.set_value(completed_steps)
            self.run_hook(self.PostRunReady, self.part_tasks, completed_steps,
                          steps_to_do, part_info, **self.configure_params)
            self.configured_steps.set_value(completed_steps + steps_to_do)
        else:
            self.run_hook(self.PostRunIdle, self.part_tasks)

    def update_completed_steps(self, completed_steps, part):
        # This is run in the child thread, so make sure it is thread safe
        self.progress_reporting[part] = completed_steps
        min_completed_steps = min(self.progress_reporting.values())
        if min_completed_steps > self.completed_steps.value:
            self.completed_steps.set_value(min_completed_steps)

    @method_writeable_in(sm.IDLE, sm.CONFIGURING, sm.READY, sm.RUNNING,
                         sm.POSTRUN, sm.PAUSED, sm.SEEKING)
    def abort(self):
        self.try_stateful_function(sm.ABORTING, sm.ABORTED, self.do_abort,
                                   self.Abort)

    def do_abort(self, hook):
        for task in self.part_tasks.values():
            task.stop()
        self.run_hook(hook, self.create_part_tasks())
        for task in self.part_tasks.values():
            task.wait()

    def set_completed_steps(self, completed_steps):
        params = self.pause.MethodMeta.prepare_input_map(
            completedSteps=completed_steps)
        self.pause(params)

    @method_writeable_in(sm.READY, sm.PAUSED, sm.RUNNING)
    @method_takes(
        "completedSteps",
        NumberMeta("int32",
                   "Step to mark as the last completed step, -1 for current"),
        -1)
    def pause(self, params):
        current_state = self.state.value
        if params.completedSteps < 0:
            completed_steps = self.completed_steps.value
        else:
            completed_steps = params.completedSteps
        if current_state == sm.RUNNING:
            next_state = sm.PAUSED
        else:
            next_state = current_state
        assert completed_steps < self.total_steps.value, \
            "Cannot seek to after the end of the scan"
        self.try_stateful_function(sm.SEEKING, next_state, self.do_pause,
                                   completed_steps)

    def do_pause(self, completed_steps):
        self.do_abort(self.Pause)
        in_run_steps = completed_steps % self.steps_per_run
        steps_to_do = self.steps_per_run - in_run_steps
        part_info = self.run_hook(self.ReportStatus, self.part_tasks)
        self.completed_steps.set_value(completed_steps)
        self.run_hook(self.Seek, self.part_tasks, completed_steps, steps_to_do,
                      part_info, **self.configure_params)
        self.configured_steps.set_value(completed_steps + steps_to_do)

    @method_writeable_in(sm.PAUSED)
    def resume(self):
        self.transition(sm.RUNNING, "Resuming run")
Exemplo n.º 38
0
 def test_float_to_int_truncates(self):
     nm = NumberMeta("int32")
     self.assertEquals(nm.validate(123.6), 123)
Exemplo n.º 39
0
from malcolm.core import Part, method_takes, REQUIRED, MethodMeta
from malcolm.core.vmetas import StringMeta, NumberMeta, BooleanMeta
from malcolm.controllers.defaultcontroller import DefaultController
from malcolm.parts.ca.cothreadimporter import CothreadImporter


@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"), None, "goodStatus",
    StringMeta("Good value for status pv"), "", "value",
    NumberMeta("int32", "value to write to pv when method called"), 1, "wait",
    BooleanMeta("Wait for caput callback?"), True)
class CAActionPart(Part):
    method = None

    def __init__(self, process, params):
        self.cothread, self.catools = CothreadImporter.get_cothread(process)
        super(CAActionPart, self).__init__(process, params)

    def create_methods(self):
        # MethodMeta instance
        self.method = MethodMeta(self.params.description)
        # TODO: set widget tag?
        yield self.params.name, self.method, self.caput

    @DefaultController.Reset
    def connect_pvs(self, _):
        # make the connection in cothread's thread
        pvs = [self.params.pv]
Exemplo n.º 40
0
 def test_float_against_float32(self):
     nm = NumberMeta("float32")
     self.assertAlmostEqual(123.456, nm.validate(123.456), places=5)
Exemplo n.º 41
0
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.websocket import websocket_connect

from malcolm.core import ClientComms, Request, Subscribe, Response, \
    deserialize_object, method_takes
from malcolm.core.jsonutils import json_decode, json_encode
from malcolm.core.vmetas import StringMeta, NumberMeta


@method_takes("hostname", StringMeta("Hostname of malcolm websocket server"),
              "localhost", "port",
              NumberMeta("int32", "Port number to run up under"), 8080)
class WebsocketClientComms(ClientComms):
    """A class for a client to communicate with the server"""
    def __init__(self, process, params):
        """
        Args:
            process (Process): Process for primitive creation
            params (Map): Parameters map
        """
        super(WebsocketClientComms, self).__init__(process)
        self.url = "ws://%(hostname)s:%(port)d/ws" % params
        self.set_logger_name(self.url)
        # TODO: Are we starting one or more IOLoops here?
        self.conn = None
        self.loop = IOLoop.current()
        self.loop.add_callback(self.recv_loop)
        self.add_spawn_function(self.loop.start, self.stop_recv_loop)

    @gen.coroutine
Exemplo n.º 42
0
 def test_float_against_float64(self):
     nm = NumberMeta("float64")
     self.assertEqual(123.456, nm.validate(123.456))