예제 #1
0
class StatefulStates(object):
    """The most basic Malcolm state machine"""

    RESETTING = "Resetting"
    DISABLED = "Disabled"
    DISABLING = "Disabling"
    FAULT = "Fault"
    READY = "Ready"

    def __init__(self):
        self._allowed = OrderedDict()
        # These are all the states we can possibly be in
        self.possible_states = []
        self.create_block_transitions()
        self.create_error_disable_transitions()

    def create_block_transitions(self):
        self.set_allowed(self.RESETTING, self.READY)

    def create_error_disable_transitions(self):
        block_states = self.possible_states[:]

        # Set transitions for standard states
        for state in block_states:
            self.set_allowed(state, self.FAULT)
            self.set_allowed(state, self.DISABLING)
        self.set_allowed(self.FAULT, [self.RESETTING, self.DISABLING])
        self.set_allowed(self.DISABLING, [self.FAULT, self.DISABLED])
        self.set_allowed(self.DISABLED, self.RESETTING)

    def transition_allowed(self, initial_state, target_state):
        """
        Check if a transition between two states is allowed

        Args:
            initial_state(str): Initial state
            target_state(str): Target state

        Returns:
            bool: True if allowed, False if not
        """
        assert initial_state in self._allowed, \
            "%s is not in %s" % (initial_state, list(self._allowed))
        return target_state in self._allowed[initial_state]

    def set_allowed(self, initial_state, allowed_states):
        """Add an allowed transition state

        Args:
            initial_state (str): Initial state
            allowed_states (str or list): state or list of states that
                initial_state can transition to
        """
        if not isinstance(allowed_states, list):
            allowed_states = [allowed_states]

        self._allowed.setdefault(initial_state, set()).update(allowed_states)
        for state in allowed_states + [initial_state]:
            if state not in self.possible_states:
                self.possible_states.append(state)
 def handle_changes(self, changes):
     for k, v in changes:
         self.changes[k] = v
     block_changes = OrderedDict()
     for full_field, val in list(self.changes.items()):
         block_name, field_name = full_field.split(".", 1)
         block_changes.setdefault(block_name, []).append((
             field_name, full_field, val))
     for block_name, field_changes in block_changes.items():
         # Squash changes
         block_mri = "%s:%s" % (self.mri, block_name)
         try:
             block_controller = self.process.get_controller(block_mri)
         except ValueError:
             self.log.debug("Block %s not known", block_name)
             for _, full_field, _ in field_changes:
                 self.changes.pop(full_field)
         else:
             with block_controller.changes_squashed:
                 self.do_field_changes(block_name, field_changes)
예제 #3
0
class StateSet:
    def __init__(self) -> None:
        self._allowed = OrderedDict()
        # These are all the states we can possibly be in
        self.possible_states: List[str] = []

    def transition_allowed(self, initial_state: str,
                           target_state: str) -> bool:
        """Check if a transition between two states is allowed"""
        assert (initial_state in self._allowed
                ), f"{initial_state} is not in {list(self._allowed)}"
        return target_state in self._allowed[initial_state]

    def set_allowed(self, initial_state: str, *allowed_states: str) -> None:
        """Add an allowed transition from initial_state to allowed_states"""
        allowed_states_list = list(allowed_states)
        self._allowed.setdefault(initial_state,
                                 set()).update(allowed_states_list)
        for state in allowed_states_list + [initial_state]:
            if state not in self.possible_states:
                self.possible_states.append(state)
예제 #4
0
class StateSet(object):
    def __init__(self):
        # type: () -> None
        self._allowed = OrderedDict()
        # These are all the states we can possibly be in
        self.possible_states = []

    def transition_allowed(self, initial_state, target_state):
        # type: (str, str) -> bool
        """Check if a transition between two states is allowed"""
        assert initial_state in self._allowed, \
            "%s is not in %s" % (initial_state, list(self._allowed))
        return target_state in self._allowed[initial_state]

    def set_allowed(self, initial_state, *allowed_states):
        # type: (str, *str) -> None
        """Add an allowed transition from initial_state to allowed_states"""
        allowed_states = list(allowed_states)
        self._allowed.setdefault(initial_state, set()).update(allowed_states)
        for state in allowed_states + [initial_state]:
            if state not in self.possible_states:
                self.possible_states.append(state)
예제 #5
0
class FieldRegistry(object):
    def __init__(self):
        # type: () -> None
        self.fields = OrderedDict()  # type: FieldDict

    def get_field(self, name):
        # type: (str) -> Field
        for fields in self.fields.values():
            for (n, field, _) in fields:
                if n == name:
                    return field
        raise ValueError("No field named %s found" % (name,))

    def add_method_model(self,
                         func,  # type: Callable
                         name=None,  # type: Optional[str]
                         description=None,  # type: Optional[str]
                         owner=None,  # type: object
                         ):
        # type: (...) -> MethodModel
        """Register a function to be added to the block"""
        if name is None:
            name = func.__name__
        method = MethodModel.from_callable(func, description)
        self._add_field(owner, name, method, func)
        return method

    def add_attribute_model(self,
                            name,  # type: str
                            attr,  # type: AttributeModel
                            writeable_func=None,  # type: Optional[Callable]
                            owner=None,  # type: object
                            ):
        # type: (...) -> AttributeModel
        self._add_field(owner, name, attr, writeable_func)
        return attr

    def _add_field(self, owner, name, model, writeable_func):
        # type: (object, str, Field, Callable) -> None
        assert CAMEL_RE.match(name), \
            "Field %r published by %s is not camelCase" % (name, owner)
        part_fields = self.fields.setdefault(owner, [])
        part_fields.append((name, model, writeable_func))
예제 #6
0
 def do_save(self, design=""):
     if not design:
         design = self.design.value
     assert design, "Please specify save design name when saving from new"
     assert not design.startswith(
         "template_"), "Cannot save over a template"
     structure = OrderedDict()
     attributes = structure.setdefault("attributes", OrderedDict())
     # Add the layout table
     layout = attributes.setdefault("layout", OrderedDict())
     for name, mri, x, y, visible in self.layout.value.rows():
         layout_structure = OrderedDict()
         layout_structure["x"] = x
         layout_structure["y"] = y
         layout_structure["visible"] = visible
         layout[name] = layout_structure
     # Add the exports table
     exports = attributes.setdefault("exports", OrderedDict())
     for source, export in self.exports.value.rows():
         exports[source] = export
     # Add other attributes
     for name, attribute in self.our_config_attributes.items():
         attributes[name] = attribute.value
     # Add any structure that a child part wants to save
     structure["children"] = self.run_hooks(
         SaveHook(p, c)
         for p, c in self.create_part_contexts(only_visible=False).items())
     text = json_encode(structure, indent=2)
     filename = self._validated_config_filename(design)
     if filename.startswith("/tmp"):
         self.log.warning("Saving to tmp directory %s" % filename)
     with open(filename, "w") as f:
         f.write(text)
     # Run a sync command to make sure we flush this file to disk
     subprocess.call("sync")
     # Try and commit the file to git, don't care if it fails
     self._run_git_cmd("add", filename)
     msg = "Saved %s %s" % (self.mri, design)
     self._run_git_cmd("commit", "--allow-empty", "-m", msg, filename)
     self._mark_clean(design)
예제 #7
0
class StateMachine(Loggable):

    RESETTING = "Resetting"
    DISABLED = "Disabled"
    DISABLING = "Disabling"
    FAULT = "Fault"

    # Subclasses must override this
    AFTER_RESETTING = None

    def __init__(self):
        self.set_logger_name(type(self).__name__)
        self.allowed_transitions = OrderedDict()
        self.busy_states = []
        assert self.AFTER_RESETTING is not None, \
            "No AFTER_RESETTING state given"
        self.set_allowed(self.RESETTING, self.AFTER_RESETTING)
        self.set_busy(self.RESETTING)
        self.create_states()
        custom_states = list(self.allowed_transitions) + [self.AFTER_RESETTING]

        # Set transitions for standard states
        for state in custom_states:
            self.set_allowed(state, self.FAULT)
            self.set_allowed(state, self.DISABLING)
        self.set_allowed(self.FAULT, [self.RESETTING, self.DISABLING])
        self.set_allowed(self.DISABLING, [self.FAULT, self.DISABLED])
        self.set_allowed(self.DISABLED, self.RESETTING)

        # These are all the states we can possibly be in
        self.possible_states = list(self.allowed_transitions)

    def create_states(self):
        raise NotImplementedError()

    def is_allowed(self, initial_state, target_state):
        """
        Check if a transition between two states is allowed

        Args:
            initial_state(str): Initial state
            target_state(str): Target state

        Returns:
            bool: True if allowed, False if not
        """
        assert initial_state in self.allowed_transitions, \
            "%s is not in %s" % (initial_state, list(self.allowed_transitions))
        return target_state in self.allowed_transitions[initial_state]

    def set_allowed(self, initial_state, allowed_states):
        """
        Add an allowed transition state

        Args:
            initial_state(str): Initial state
            allowed_states(list(str) / str): States that initial_state can
            transition to
        """

        if not isinstance(allowed_states, list):
            allowed_states = [allowed_states]

        self.allowed_transitions.setdefault(initial_state, set()).update(
            allowed_states)

    def set_busy(self, state, busy=True):
        """
        Set the busy-ness of a state; i.e. whether the block is considered
        to be busy in a certain state

        Args:
            state(str): State to update
            busy(bool): True or False for whether state is a busy state
        """

        if not busy and state in self.busy_states:
            self.busy_states.remove(state)

        elif busy and state not in self.busy_states:
            self.busy_states.append(state)

    def is_busy(self, state):
        """
        Check if a state is a busy state

        Args:
            state(str): State to check busy-ness for

        Returns:
            bool: True if state is a busy state, False if not
        """
        return state in self.busy_states
예제 #8
0
class StateMachine(Loggable):

    RESETTING = "Resetting"
    DISABLED = "Disabled"
    DISABLING = "Disabling"
    FAULT = "Fault"

    # Subclasses must override this
    AFTER_RESETTING = None

    def __init__(self):
        self.set_logger_name(type(self).__name__)
        self.allowed_transitions = OrderedDict()
        self.busy_states = []
        assert self.AFTER_RESETTING is not None, \
            "No AFTER_RESETTING state given"
        self.set_allowed(self.RESETTING, self.AFTER_RESETTING)
        self.set_busy(self.RESETTING)
        self.create_states()
        custom_states = list(self.allowed_transitions) + [self.AFTER_RESETTING]

        # Set transitions for standard states
        for state in custom_states:
            self.set_allowed(state, self.FAULT)
            self.set_allowed(state, self.DISABLING)
        self.set_allowed(self.FAULT, [self.RESETTING, self.DISABLING])
        self.set_allowed(self.DISABLING, [self.FAULT, self.DISABLED])
        self.set_allowed(self.DISABLED, self.RESETTING)

        # These are all the states we can possibly be in
        self.possible_states = list(self.allowed_transitions)

    def create_states(self):
        raise NotImplementedError()

    def is_allowed(self, initial_state, target_state):
        """
        Check if a transition between two states is allowed

        Args:
            initial_state(str): Initial state
            target_state(str): Target state

        Returns:
            bool: True if allowed, False if not
        """
        assert initial_state in self.allowed_transitions, \
            "%s is not in %s" % (initial_state, list(self.allowed_transitions))
        return target_state in self.allowed_transitions[initial_state]

    def set_allowed(self, initial_state, allowed_states):
        """
        Add an allowed transition state

        Args:
            initial_state(str): Initial state
            allowed_states(list(str) / str): States that initial_state can
            transition to
        """

        if not isinstance(allowed_states, list):
            allowed_states = [allowed_states]

        self.allowed_transitions.setdefault(initial_state,
                                            set()).update(allowed_states)

    def set_busy(self, state, busy=True):
        """
        Set the busy-ness of a state; i.e. whether the block is considered
        to be busy in a certain state

        Args:
            state(str): State to update
            busy(bool): True or False for whether state is a busy state
        """

        if not busy and state in self.busy_states:
            self.busy_states.remove(state)

        elif busy and state not in self.busy_states:
            self.busy_states.append(state)

    def is_busy(self, state):
        """
        Check if a state is a busy state

        Args:
            state(str): State to check busy-ness for

        Returns:
            bool: True if state is a busy state, False if not
        """
        return state in self.busy_states