Example #1
0
class TestAttribute(unittest.TestCase):
    def setUp(self):
        self.data = StringMeta().create_attribute_model()
        self.data.set_notifier_path(Mock(), ["block", "attr"])
        self.controller = Mock()
        self.context = Mock()
        self.o = Attribute(self.controller, self.context, self.data)

    def test_init(self):
        self.assertIsInstance(self.o, Attribute)
        assert hasattr(self.o, "meta")
        assert hasattr(self.o, "value")
        assert hasattr(self.o, "subscribe_value")

    def test_put(self):
        self.o.put_value(32)
        self.context.put.assert_called_once_with(["block", "attr", "value"],
                                                 32,
                                                 timeout=None)

    def test_put_async(self):
        f = self.o.put_value_async(32)
        self.context.put_async.assert_called_once_with(
            ["block", "attr", "value"], 32)
        assert f == self.context.put_async.return_value

    def test_repr(self):
        self.context.make_view.return_value = "foo"
        assert repr(self.o) == "<Attribute value='foo'>"
        self.context.make_view.assert_called_once_with(self.controller,
                                                       self.data, "value")
 def check_set(self, attr, expected):
     self.assertEqual(self.s.attributes[attr].pv.caput.call_count, 1)
     call_args = self.s.attributes[attr].pv.caput.call_args
     val = call_args[0][0]
     self.assertEquals(
         val, expected, "{}: expected {} got {}".format(attr, expected, val))
     Attribute.update(self.s.attributes[attr], val)
     self.s.attributes[attr].pv.reset_mock()
 def set_configured(self):
     # Set all the pvs to the right value
     for attr in sorted(self.send_params):
         self.s.attributes[attr]._value = self.send_params[attr]
     self.s.configure(block=False, **self.in_params)
     Attribute.update(self.s.attributes["delete"], True)
     cothread.Yield()
     Attribute.update(self.s.attributes["xml"], self.s._sconfig.seq_items[1].seq_params["xml"])
     cothread.Yield()
     self.assertEqual(self.s.state, DState.Ready)
 def create_attributes(self):
     self.value = Attribute(NumberMeta(description="Value"))
     self.value.meta.set_dtype('float64')
     yield 'value', self.value
     self.generator = Attribute(
         PointGeneratorMeta(description="Scan Point Generator"))
     yield "generator", self.generator
     self.axis_name = Attribute(StringMeta(description="Name of the axis"))
     yield "axis_name", self.axis_name
     self.exposure = Attribute(NumberMeta(description="Exposure time"))
     self.value.meta.set_dtype('float64')
     yield "exposure", self.exposure
Example #5
0
 def set_configured(self):
     # Set all the pvs to the right value
     for attr in sorted(self.send_params):
         self.s.attributes[attr]._value = self.send_params[attr]
     self.s.configure(block=False, **self.in_params)
     cothread.Yield()
     self.check_set("positionMode", True)
     Attribute.update(
         self.s.attributes["xml"], self.s._sconfig.seq_items[1].seq_params["xml"])
     cothread.Yield()
     self.assertEqual(self.s.state, DState.Ready)
     self.s.attributes["writeStatus"]._value = "Ok"
Example #6
0
 def test_run(self):
     self.set_configured()
     # Do a run
     spawned = cothread.Spawn(self.s.run)
     cothread.Yield()
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Running)
     self.check_set("capture", 1)
     self.assertEqual(self.s.capture, 1)
     Attribute.update(self.s.attributes["capture"], False)
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Idle)
     spawned.Wait(1)
     self.assertEqual(self.s.stateMachine.state, DState.Idle)
 def test_create_children(self, attribute_mock, method_mock):
     # Load up items to create
     mi1, mi2 = MagicMock(), MagicMock()
     method_mock.side_effect = [mi1, mi2]
     ai1, ai2 = MagicMock(), MagicMock()
     attribute_mock.side_effect = [ai1, ai2]
     # Load up refs to get
     group_attr = Attribute()
     child_attr = self.make_grouped_attr()
     m1 = MethodMeta()
     m2 = MethodMeta()
     BlockItem.items[("endpoint", "foo")] = ai1
     self.item.ref = OrderedDict((
         ("foo", group_attr), ("c", child_attr), ("a", m1), ("b", m2)))
     self.item.create_children()
     # Check it made the right thing
     self.assertEqual(len(self.item.children), 3)
     attribute_mock.assert_any_call(("endpoint", "foo"), group_attr)
     self.assertEqual(self.item.children[0], ai1)
     attribute_mock.assert_any_call(("endpoint", "c"), child_attr)
     ai1.add_child.assert_called_once_with(ai2)
     method_mock.assert_any_call(("endpoint", "a"), m1)
     self.assertEqual(self.item.children[1], mi1)
     method_mock.assert_any_call(("endpoint", "b"), m2)
     self.assertEqual(self.item.children[2], mi2)
 def test_run(self):
     self.set_configured()
     spawned = cothread.Spawn(self.s.run)
     # Yield to let run run
     cothread.Yield()
     self.assertEqual(self.s.state, DState.Ready)
     # Yield to let do_run run
     cothread.Yield()
     self.assertEqual(self.s.state, DState.Running)
     self.check_set("acquire", 1)
     self.assertEqual(self.s.acquire, 1)
     Attribute.update(self.s.attributes["acquire"], False)
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Idle)
     spawned.Wait(1)
     self.assertEqual(self.s.stateMachine.state, DState.Idle)
Example #9
0
 def test_abort(self):
     self.set_configured()
     spawned = cothread.Spawn(self.s.run)
     cothread.Yield()
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Running)
     self.check_set("scanStart", 1)
     self.assertEqual(self.s.scanStart, 1)
     Attribute.update(self.s.attributes["progState"], "Scanning")
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Running)
     aspawned = cothread.Spawn(self.s.abort)
     cothread.Yield()
     Attribute.update(self.s.attributes["progState"], "Idle")
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Aborted)
     spawned.Wait(1)
     aspawned.Wait(1)
 def test_abort(self):
     self.set_configured()
     spawned = cothread.Spawn(self.s.run)
     cothread.Yield()
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Running)
     self.check_set("acquire", 1)
     self.assertEqual(self.s.acquire, 1)
     aspawned = cothread.Spawn(self.s.abort)
     cothread.Yield()
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Aborting)
     self.check_set("acquire", 0)
     Attribute.update(self.s.attributes["acquire"], False)
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Aborted)
     spawned.Wait(1)
     aspawned.Wait(1)
Example #11
0
 def create_attributes(self):
     self.value = Attribute(NumberMeta(description="Value"))
     self.value.meta.set_dtype('float64')
     yield 'value', self.value
     self.generator = Attribute(
         PointGeneratorMeta(description="Scan Point Generator"))
     yield "generator", self.generator
     self.axis_name = Attribute(StringMeta(description="Name of the axis"))
     yield "axis_name", self.axis_name
     self.exposure = Attribute(NumberMeta(description="Exposure time"))
     self.value.meta.set_dtype('float64')
     yield "exposure", self.exposure
class ScanPointTickerController(Controller):

    def create_attributes(self):
        self.value = Attribute(NumberMeta(description="Value"))
        self.value.meta.set_dtype('float64')
        yield 'value', self.value
        self.generator = Attribute(
            PointGeneratorMeta(description="Scan Point Generator"))
        yield "generator", self.generator
        self.axis_name = Attribute(StringMeta(description="Name of the axis"))
        yield "axis_name", self.axis_name
        self.exposure = Attribute(NumberMeta(description="Exposure time"))
        self.value.meta.set_dtype('float64')
        yield "exposure", self.exposure

    @takes("generator", PointGeneratorMeta(
                        description="Generator instance"), REQUIRED,
           "axis_name", StringMeta( description="Specifier for axis"), REQUIRED,
           "exposure", NumberMeta(
                       description="Detector exposure time"), REQUIRED)
    def configure(self, params):
        """
        Configure the controller

        Args:
            generator(PointGenerator): Generator to create points
            axis_name(String): Specifier for axis
            exposure(Double): Exposure time for detector
        """

        self.generator.set_value(params.generator)
        self.axis_name.set_value(params.axis_name)
        self.exposure.set_value(params.exposure)
        self.exposure.meta.set_dtype('float64')
        self.block.notify_subscribers()

    @Method.wrap_method
    def run(self):
        """
        Start the ticker process

        Yields:
            Point: Scan points from PointGenerator
        """
        axis_name = self.axis_name.value
        for point in self.generator.value.iterator():
            self.value.set_value(point.positions[axis_name])
            self.block.notify_subscribers()
            time.sleep(self.exposure.value)
Example #13
0
class CounterController(Controller):
    def create_attributes(self):
        self.counter = Attribute(NumberMeta(description="A counter"))
        self.counter.meta.set_dtype('uint32')
        self.counter.set_put_function(self.counter.set_value)
        self.counter.set_value(0)
        yield "counter", self.counter

    @Controller.Resetting
    def do_reset(self):
        self.counter.set_value(0, notify=False)
        # Transition will do the notify for us

    @takes()
    def increment(self):
        self.counter.set_value(self.counter.value + 1)
Example #14
0
class ScanPointTickerController(Controller):
    def create_attributes(self):
        self.value = Attribute(NumberMeta(description="Value"))
        self.value.meta.set_dtype('float64')
        yield 'value', self.value
        self.generator = Attribute(
            PointGeneratorMeta(description="Scan Point Generator"))
        yield "generator", self.generator
        self.axis_name = Attribute(StringMeta(description="Name of the axis"))
        yield "axis_name", self.axis_name
        self.exposure = Attribute(NumberMeta(description="Exposure time"))
        self.value.meta.set_dtype('float64')
        yield "exposure", self.exposure

    @takes("generator", PointGeneratorMeta(description="Generator instance"),
           REQUIRED, "axis_name", StringMeta(description="Specifier for axis"),
           REQUIRED, "exposure",
           NumberMeta(description="Detector exposure time"), REQUIRED)
    def configure(self, params):
        """
        Configure the controller

        Args:
            generator(PointGenerator): Generator to create points
            axis_name(String): Specifier for axis
            exposure(Double): Exposure time for detector
        """

        self.generator.set_value(params.generator)
        self.axis_name.set_value(params.axis_name)
        self.exposure.set_value(params.exposure)
        self.exposure.meta.set_dtype('float64')
        self.block.notify_subscribers()

    @Method.wrap_method
    def run(self):
        """
        Start the ticker process

        Yields:
            Point: Scan points from PointGenerator
        """
        axis_name = self.axis_name.value
        for point in self.generator.value.iterator():
            self.value.set_value(point.positions[axis_name])
            self.block.notify_subscribers()
            time.sleep(self.exposure.value)
Example #15
0
 def create_attributes(self):
     params = self.params
     if params.pv is None and params.rbv is None:
         raise ValueError('must pass pv rbv')
     if params.rbv is None:
         if params.rbv_suff is None:
             params.rbv = params.pv
         else:
             params.rbv = params.pv + params.rbv_suff
     # Meta instance
     self.name = params.name
     self.meta = self.create_meta(params.description)
     # Pv strings
     self.pv = params.pv
     self.rbv = params.rbv
     # camonitor subscription
     self.monitor = None
     self.ca_format = catools.FORMAT_CTRL
     # This will be our attr
     self.attr = None
     # The attribute we will be publishing
     self.attr = Attribute(self.meta)
     self.attr.set_put_function(self.caput)
     yield self.name, self.attr
Example #16
0
class CounterController(Controller):

    def create_attributes(self):
        self.counter = Attribute(NumberMeta(description="A counter"))
        self.counter.meta.set_dtype('uint32')
        self.counter.set_put_function(self.counter.set_value)
        self.counter.set_value(0)
        yield "counter", self.counter

    @Controller.Resetting
    def do_reset(self):
        self.counter.set_value(0, notify=False)
        # Transition will do the notify for us

    @takes()
    def increment(self):
        self.counter.set_value(self.counter.value + 1)
Example #17
0
    def _fill_sequencer(self, seq_table: Attribute) -> None:
        assert self.generator, "No generator"
        points = self.generator.get_points(self.loaded_up_to, self.scan_up_to)

        if points is None or len(points) == 0:
            table = SequencerTable.from_rows([])
            seq_table.put_value(table)
            return

        rows = []

        if not self.axis_mapping:
            # No position compare or row triggering required
            rows.extend(self._generate_immediate_rows(points.duration))

            # one last dead frame signal
            rows.append(seq_row(half_duration=LAST_PULSE, dead=1))

            if len(rows) > SEQ_TABLE_ROWS:
                raise Exception("Seq table: {} rows with {} maximum".format(
                    len(rows), SEQ_TABLE_ROWS))

            table = SequencerTable.from_rows(rows)
            seq_table.put_value(table)
            return

        start_indices, end_indices = self._get_row_indices(points)

        point = points[0]
        first_point_static = point.positions == point.lower == point.upper
        end = start_indices[0] if start_indices.size else len(points)
        if not first_point_static:
            # If the motors are moving during this point then
            # wait for triggers
            rows.extend(self._generate_triggered_rows(points, 0, end, False))
        else:
            # This first row should not wait, and will trigger immediately
            rows.extend(self._generate_immediate_rows(points.duration[0:end]))

        for start, end in zip(start_indices, end_indices):
            # First row handled outside of loop
            self.last_point = points[start - 1]

            rows.extend(self._generate_triggered_rows(points, start, end,
                                                      True))

        # one last dead frame signal
        rows.append(seq_row(half_duration=LAST_PULSE, dead=1))

        if len(rows) > SEQ_TABLE_ROWS:
            raise Exception("Seq table: {} rows with {} maximum".format(
                len(rows), SEQ_TABLE_ROWS))

        table = SequencerTable.from_rows(rows)
        seq_table.put_value(table)
    def add_all_attributes(self):
        super(SimDetector, self).add_all_attributes()
        # Configure
        self._thing = None
        self.exposure = Attribute(VDouble, "Exposure time for each frame")
        self.exposure = 1.2
        if self.exposure > 0:
            print "blah"

        self.exposure.update(1.2, alarm=Alarm.disconnected())
        if self.exposure._value > 0:
            print "blah"

        self.period = Attribute(VDouble, "Time between the start of each frame")
        self.positions = Attribute(
            VTable,
            "Position table, column headings are dimension names, "
            "slowest changing first")
        self.hdf5File = Attribute(VString, "HDF5 full file path to write")
        # Monitor
        self.dimensions = Attribute(
            VIntArray, "Detected dimensionality of positions")
 def test_grouped_children(self):
     attr = self.make_grouped_attr()
     self.item.ref = dict(c=attr, d=Attribute())
     self.assertEqual(self.item.ref_children(), 1)
 def test_mismatch(self):
     self.set_configured()
     Attribute.update(self.s.attributes["arrayCallbacks"], False)
     self.assertEqual(self.s.state, DState.Ready)
     cothread.Yield()
     self.assertEqual(self.s.state, DState.Idle)
Example #21
0
class CAPart(Part):

    def create_attributes(self):
        params = self.params
        if params.pv is None and params.rbv is None:
            raise ValueError('must pass pv rbv')
        if params.rbv is None:
            if params.rbv_suff is None:
                params.rbv = params.pv
            else:
                params.rbv = params.pv + params.rbv_suff
        # Meta instance
        self.name = params.name
        self.meta = self.create_meta(params.description)
        # Pv strings
        self.pv = params.pv
        self.rbv = params.rbv
        # camonitor subscription
        self.monitor = None
        self.ca_format = catools.FORMAT_CTRL
        # This will be our attr
        self.attr = None
        # The attribute we will be publishing
        self.attr = Attribute(self.meta)
        self.attr.set_put_function(self.caput)
        yield self.name, self.attr

    def create_meta(self, description):
        raise NotImplementedError

    def get_datatype(self):
        raise NotImplementedError

    @Controller.Resetting
    def connect_pvs(self):
        # release old monitor
        self.close_monitor()
        # make the connection in cothread's thread, use caget for initial value
        pvs = [self.rbv]
        if self.pv:
            pvs.append(self.pv)
        ca_values = cothread.CallbackResult(
            catools.caget, pvs,
            format=self.ca_format, datatype=self.get_datatype())
        # check connection is ok
        for i, v in enumerate(ca_values):
            assert v.ok, "CA connect failed with %s" % v.state_strings[v.state]
        self.update_value(ca_values[0])
        # now setup monitor on rbv
        self.monitor = catools.camonitor(
            self.rbv, self.on_update, notify_disconnect=True,
            format=self.ca_format, datatype=self.get_datatype())

    def close_monitor(self):
        if self.monitor is not None:
            cothread.CallbackResult(self.monitor.close)
            self.monitor = None

    def caput(self, value):
        cothread.CallbackResult(
            catools.caput, self.pv, value, wait=True, timeout=None,
            datatype=self.get_datatype())
        # now do a caget
        value = cothread.CallbackResult(
            catools.caget, self.rbv,
            format=self.ca_format, datatype=self.get_datatype())
        self.update_value(value)

    def on_update(self, value):
        # Called on cothread's queue, so don't block
        self.process.spawn(self.update_value, value)

    def update_value(self, value):
        self.log_debug("Camonitor update %r", value)
        # TODO: make Alarm from value.status and value.severity
        # TODO: make Timestamp from value.timestamp
        if not value.ok:
            # TODO: set disconnect
            self.attr.set_value(None)
        else:
            # update value
            self.attr.set_value(value)
Example #22
0
 def test_mismatch(self):
     self.set_configured()
     Attribute.update(self.s.attributes["extraDimSizeN"], 2)
     self.assertEqual(self.s.stateMachine.state, DState.Ready)
     cothread.Yield()
     self.assertEqual(self.s.stateMachine.state, DState.Idle)
class SimDetector(PausableDevice):

    @wrap_method(
        simDetector=InstanceAttribute(SimDetectorDriver, "SimDetectorDriver Device"),
        hdf5Writer=InstanceAttribute(Hdf5Writer, "Hdf5Writer Device"),
        positionPlugin=InstanceAttribute(
            PositionPlugin, "PositionPlugin Device"),
    )
    def __init__(self, name, simDetector, positionPlugin, hdf5Writer):
        super(SimDetector, self).__init__(name)
        self.simDetectorDriver = simDetector
        self.positionPlugin = positionPlugin
        self.hdf5Writer = hdf5Writer
        self.children = [simDetector, positionPlugin, hdf5Writer]
        # Child state machine listeners
        for c in self.children:
            c.add_listener(self.post_changes, "stateMachine")
        self.child_statemachines = [c.stateMachine for c in self.children]
        # Run monitors
        hdf5Writer.add_listener(
            self.post_changes, "attributes.uniqueId")
        hdf5Writer.add_listener(
            self.post_changes, "attributes.capture")
        positionPlugin.add_listener(
            self.post_changes, "attributes.running")

    def add_all_attributes(self):
        super(SimDetector, self).add_all_attributes()
        # Configure
        self._thing = None
        self.exposure = Attribute(VDouble, "Exposure time for each frame")
        self.exposure = 1.2
        if self.exposure > 0:
            print "blah"

        self.exposure.update(1.2, alarm=Alarm.disconnected())
        if self.exposure._value > 0:
            print "blah"

        self.period = Attribute(VDouble, "Time between the start of each frame")
        self.positions = Attribute(
            VTable,
            "Position table, column headings are dimension names, "
            "slowest changing first")
        self.hdf5File = Attribute(VString, "HDF5 full file path to write")
        # Monitor
        self.dimensions = Attribute(
            VIntArray, "Detected dimensionality of positions")

    def _validate_hdf5Writer(self, hdf5File, positions, dimensions,
                             totalSteps):
        filePath, fileName = os.path.split(hdf5File)
        dimNames = []
        dimUnits = []
        names = [c[0] for c in positions]
        indexNames = [n for n in names if n.endswith("_index")]
        for name, _, _, unit in positions:
            if not name.endswith("_index"):
                dimNames.append(name)
                if unit:
                    dimUnits.append(unit)
                else:
                    dimUnits.append("mm")
        assert len(dimNames) == len(dimensions), \
            "Can't unify position number of index columns {} with " \
            "dimensions {}".format(len(dimNames), dimensions)
        return self.hdf5Writer.validate(
            filePath, fileName, dimNames, dimUnits, indexNames, dimensions)

    @wrap_method()
    def validate(self, hdf5File, exposure, positions=def_positions,
                 period=None):
        # Validate self
        dimensions, positions = self._add_position_indexes(positions)
        # Validate simDetectorDriver
        totalSteps = len(positions[0][2])
        sim_params = self.simDetectorDriver.validate(exposure, totalSteps, period)
        runTime = sim_params["runTime"]
        runTimeout = sim_params["runTimeout"]
        period = sim_params["period"]
        # Validate position plugin
        self.positionPlugin.validate(positions)
        # Validate hdf writer
        self._validate_hdf5Writer(hdf5File, positions, dimensions, totalSteps)
        return super(SimDetector, self).validate(locals())

    def _add_position_indexes(self, positions):
        # which columns are index columns?
        names = [column[0] for column in positions]
        indexes = [n[:-len("_index")] for n in names if n.endswith("_index")]
        non_indexes = [n for n in names if not n.endswith("_index")]
        expected_indexes = ["{}_index".format(n) for n in non_indexes]
        # check if indexes are supplied
        if indexes == expected_indexes or indexes == ["n_index"]:
            # just get dimensionality from these indexes
            dims = [max(d) + 1 for n, _, d, _ in positions if n in indexes]
            index_columns = [c for c in positions if n in indexes]
        else:
            # detect dimensionality of non_index columns
            uniq = [sorted(set(d))
                    for n, _, d, _ in positions if n in non_indexes]
            dims = [len(pts) for pts in uniq]
            npts = len(positions[0][2])
            if numpy.prod(dims) != npts:
                # This is a sparse scan, should be written as long list
                dims = [npts]
                index_columns = [
                    ("n_index", VInt, numpy.arange(npts, dtype=numpy.int32), '')]
            else:
                # Create position table
                index_columns = []
                for name, sort in zip(non_indexes, uniq):
                    index = "{}_index".format(name)
                    # select the correct named column
                    data = [d for n, _, d, _ in positions if n == name][0]
                    # work out their index in the unique sorted list
                    data = numpy.array([sort.index(x)
                                        for x in data], dtype=numpy.int32)
                    index_columns.append((index, VInt, data, ''))
        positions = [c for c in positions if n in non_indexes] + index_columns
        return dims, positions

    def _configure_simDetectorDriver(self):
        self.simDetectorDriver.configure(
            self.exposure, self.totalSteps - self.currentStep, self.period,
            self.currentStep, block=False)

    def _configure_positionPlugin(self):
        if self.currentStep > 0:
            positions = []
            for n, t, d, u in self.positions:
                positions.append([n, t, d[self.currentStep:], u])
        else:
            positions = self.positions
        assert self.simDetectorDriver.portName is not None, \
            "Expected simDetectorDriver.portName != None"
        self.positionPlugin.configure(
            positions, self.currentStep + 1, self.simDetectorDriver.portName,
            block=False)

    def _configure_hdf5Writer(self):
        params = self._validate_hdf5Writer(self.hdf5File, self.positions,
                                           self.dimensions, self.totalSteps)
        params = {k: v for k, v in params.items()
                  if k in self.hdf5Writer.configure.arguments}
        assert self.positionPlugin.portName is not None, \
            "Expected positionPlugin.portName != None"
        params.update(arrayPort=self.positionPlugin.portName, block=False)
        self.hdf5Writer.configure(**params)

    def do_configure(self, config_params, task):
        """Start doing a configuration using config_params.
        Return DState.Configuring, message when started
        """
        for d in self.children:
            assert d.state in DState.canConfig(), \
                "Child device {} in state {} is not configurable"\
                .format(d, d.state)
        # Setup self
        for name, value in config_params.items():
            setattr(self, name, value)
        self.stepsPerRun = 1
        self.currentStep = 0
        task.report("Configuring simDetectorDriver")
        self._configure_simDetectorDriver()
        task.report("Configuring positionPlugin")
        self._configure_positionPlugin()
        # Setup config matcher
        self._sconfig = ConfigMatcher(
            SeqTransitionItem(
                self.child_statemachines,
                DState.Ready, DState.rest()))
        name, changes = task.report_wait("Wait for plugins to configure")
        while not self._sconfig.check_done(name, changes):
            name, changes = task.report_wait()
        task.report("Configuring hdf5Writer")
        self._configure_hdf5Writer(self.positionPlugin.dimensions)
        # Finished
        task.report("Configuring done", DState.Ready)

    def do_ready(self, value, changes):
        """Work out if the changes mean we are still ready for run.
        Return None, message if it is still ready.
        Return DState.Idle, message if it isn't still ready.
        """
        mismatches = self._sconfig.mismatches()
        if mismatches:
            yield "Unconfigured: {}".format(mismatches), DState.Idle

    def do_run(self):
        """Start doing a run.
        Return DState.Running, message when started
        """
        plugins = [self.simDetectorDriver.stateMachine,
                   self.positionPlugin.stateMachine]
        for d in plugins:
            assert d.state == DState.Ready, \
                "Child device {} in state {} is not runnable"\
                .format(d.name, d.state)
        self.report("Running positionPlugin")
        self.positionPlugin.run(block=False)
        # If hdf writer is not already running then run it
        if self.hdf5Writer.state != DState.Running:
            self.hdf5Writer.run(block=False)
            t = SeqTransitionItem(self.hdf5Writer.attributes["capture"], True)
            name, changes = yield "Wait for hdf5Writer to run"
            while not t.check_done(name, changes):
                name, changes = yield "Wait for hdf5Writer to run"
        # Now start the other plugins
        t = SeqTransitionItem(self.positionPlugin.attributes["running"], True)
        name, changes = yield "Wait for hdf5Writer to run"
        while not t.check_done(name, changes):
            name, changes = yield "Wait for hdf5Writer to run"
        

        seq_items += [
            SeqTransitionItem(
                "Wait for positionPlugin to run",
                self.positionPlugin.attributes["running"], True),
            SeqFunctionItem(
                "Running simDetectorDriver", self.simDetectorDriver.run,
                block=False),
            SeqTransitionItem(
                "Wait for run to finish", self.child_statemachines,
                DState.Idle, DState.rest()),
        ]
        # Add a configuring object
        self._srun = Sequence(self.name + ".SRun", *seq_items)
        # Start the sequence
        item_done, msg = self._srun.start()
        if item_done:
            # Arrange for a callback to process the next item
            self.post_changes(None, None)
        return DState.Running, msg

    def do_running(self, value, changes):
        """Work out if the changes mean running is complete.
        Return None, message if it isn't.
        Return DState.Idle, message if it is and we are all done
        Return DState.Ready, message if it is and we are partially done
        """
        # Update progress
        if value == self.hdf5Writer.attributes["uniqueId"]:
            self.currentStep = value.value
        running, item_done, msg = self._srun.process(value, changes)
        if running is False:
            # Finished
            return DState.Idle, "Running done"
        elif item_done:
            # Arrange for a callback to process the next item
            self.post_changes(None, None)
        # Still going
        return DState.Running, msg

    def do_abort(self):
        """Stop acquisition
        """
        if self.state == DState.Configuring:
            self._sconfig.abort()
        elif self.state == DState.Running:
            self._srun.abort()
        elif self.state == DState.Rewinding:
            self._spause.abort()
        for d in self.children:
            if d.state in DState.canAbort():
                d.abort(block=False)
        self.post_changes(None, None)
        return DState.Aborting, "Aborting started"

    def do_aborting(self, value, changes):
        """Work out if the changes mean aborting is complete.
        Return None, message if it isn't.
        Return DState.Aborted, message if it is.
        """
        child_states = [c.state for c in self.children]
        rest = [s in DState.rest() for s in child_states]
        if all(rest):
            # All are in rest states
            no_fault = [s != DState.Fault for s in child_states]
            assert all(no_fault), \
                "Expected no fault, got {}".format(child_states)
            return DState.Aborted, "Aborting finished"
        else:
            # No change
            return None, None

    def do_reset(self):
        """Start doing a reset from aborted or fault state.
        Return DState.Resetting, message when started
        """
        seq_items = []
        # Abort any items that need to be aborted
        need_wait = []
        need_reset = []
        for d in self.children:
            if d.state not in DState.rest():
                d.abort(block=False)
                need_wait.append(d.stateMachine)
                need_reset.append(d)
            elif d.state in DState.canReset():
                need_reset.append(d)
        if need_wait:
            seq_items.append(SeqTransitionItem(
                "Wait for plugins to stop aborting",
                need_wait, DState.rest()))
        if need_reset:
            for d in need_reset:
                seq_items.append(SeqFunctionItem(
                    "Reset {}".format(d.name), d.reset,
                    block=False))
            seq_items.append(SeqTransitionItem(
                "Wait for plugins to stop resetting",
                [d.stateMachine for d in need_reset], DState.rest()))
        # Add a resetting object
        if seq_items:
            self._sreset = Sequence(self.name + ".SReset", *seq_items)
            # Start the sequence
            item_done, msg = self._sreset.start()
            if item_done:
                # Arrange for a callback to process the next item
                self.post_changes(None, None)
        else:
            self._sreset = None
            msg = "Started resetting"
            self.post_changes(None, None)
        return DState.Resetting, msg

    def do_resetting(self, value, changes):
        """Work out if the changes mean resetting is complete.
        Return None, message if it isn't.
        Return DState.Idle, message if it is.
        """
        if self._sreset is None:
            return DState.Idle, "Resetting done"
        running, item_done, msg = self._sreset.process(value, changes)
        if running is False:
            # Finished
            child_states = [d.state for d in self.children]
            nofault = [s != DState.Fault for s in child_states]
            assert all(nofault), \
                "Expected all not in fault, got {}".format(child_states)
            return DState.Idle, "Resetting done"
        elif item_done:
            # Arrange for a callback to process the next item
            self.post_changes(None, None)
        # Still going
        return DState.Resetting, msg

    def do_rewind(self, steps=None):
        """Start a pause"""
        # make some sequences for config
        plugins = [self.simDetectorDriver.stateMachine,
                   self.positionPlugin.stateMachine]
        for d in plugins:
            assert d.state in DState.canAbort(), \
                "Child device {} in state {} is not abortable"\
                .format(d, d.state)
        seq_items = []
        # if we need to abort
        if self.simDetectorDriver.state not in DState.canConfig() or \
                self.positionPlugin.state not in DState.canConfig():
            seq_items += [
                SeqFunctionItem(
                    "Stopping simDetectorDriver", self.simDetectorDriver.abort,
                    block=False),
                SeqFunctionItem(
                    "Stopping positionPlugin", self.positionPlugin.abort,
                    block=False),
                SeqTransitionItem(
                    "Wait for plugins to stop", plugins,
                    DState.Aborted, DState.rest()),
                SeqFunctionItem(
                    "Reset simDetectorDriver", self.simDetectorDriver.reset,
                    block=False),
                SeqFunctionItem(
                    "Reset positionPlugin", self.positionPlugin.reset,
                    block=False),
                SeqTransitionItem(
                    "Wait for plugins to reset", plugins,
                    DState.Idle, DState.rest())
            ]
        # Add the config stages
        seq_items += [
            SeqFunctionItem(
                "Configuring positionPlugin", self._configure_positionPlugin),
            SeqFunctionItem(
                "Configuring simDetectorDriver", self._configure_simDetectorDriver),
            SeqTransitionItem(
                "Wait for plugins to configure", plugins,
                DState.Ready, DState.rest()),
        ]
        # Add a configuring object
        self._spause = Sequence(self.name + ".SPause", *seq_items)
        if self.state == DState.Ready:
            self._post_rewind_state = DState.Ready
        else:
            self._post_rewind_state = DState.Paused
        if steps is not None:
            self.currentStep -= steps
        # Start the sequence
        item_done, msg = self._spause.start()
        if item_done:
            # Arrange for a callback to process the next item
            self.post_changes(None, None)
        return DState.Rewinding, msg

    def do_rewinding(self, value, changes):
        """Receive run status events and move to next state when finished"""
        running, item_done, msg = self._spause.process(value, changes)
        if running is False:
            # Finished
            return self._post_rewind_state, "Rewinding done"
        elif item_done:
            # Arrange for a callback to process the next item
            self.post_changes(None, None)
        # Still going
        return None, msg
Example #24
0
 def create_attributes(self):
     self.counter = Attribute(NumberMeta(description="A counter"))
     self.counter.meta.set_dtype('uint32')
     self.counter.set_put_function(self.counter.set_value)
     self.counter.set_value(0)
     yield "counter", self.counter
Example #25
0
 def create_attributes(self):
     self.counter = Attribute(NumberMeta(description="A counter"))
     self.counter.meta.set_dtype('uint32')
     self.counter.set_put_function(self.counter.set_value)
     self.counter.set_value(0)
     yield "counter", self.counter
 def make_grouped_attr(self):
     attr = Attribute()
     attr.set_endpoint_data("meta", MagicMock())
     attr.meta.tags = ["group:foo"]
     return attr
Example #27
0
 def setUp(self):
     self.data = StringMeta().create_attribute_model()
     self.data.set_notifier_path(Mock(), ["block", "attr"])
     self.controller = Mock()
     self.context = Mock()
     self.o = Attribute(self.controller, self.context, self.data)
 def test_ref_children(self):
     self.item.ref = dict(
         a=MethodMeta(), b=MethodMeta(), c=Attribute())
     self.assertEqual(self.item.ref_children(), 3)