Source code for ekfsm.core.components

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from anytree import LevelGroupOrderIter, NodeMixin, RenderTree, findall
from munch import Munch

if TYPE_CHECKING:
    from ekfsm.devices.generic import Device

    from .slots import Slot


[docs] class SysTree(NodeMixin): """ Base class for all system components including Hardware Modules and Devices. """ def __init__(self, name: str, abort: bool = False) -> None: from ekfsm.log import ekfsm_logger self.logger = ekfsm_logger(name) self.name = name self.abort = abort def _render_tree(self) -> str: output = "" for pre, _, node in RenderTree(self): output += f"{pre}{repr(node)}" + "\n" return output def __str__(self): return self._render_tree()
[docs] def print(self) -> None: print(self)
[docs] class HwModule(SysTree): """ A HwModule represents an instantiation of a specifc hw board type, for example an instance of an EKF SC9 board. """ def __init__( self, instance_name: str, config: dict, slot: Slot, abort: bool = False, *args, **kwargs, ) -> None: from ekfsm.core.utils import deserialize_hardware_tree from .slots import SlotType super().__init__(instance_name, abort=abort) self._slot: Slot = slot self.config = config self.id, self.board_type, slot_type, self.children = deserialize_hardware_tree( self.logger, self.config, parent=self ) self.slot_type = SlotType.from_string(slot_type) for children in LevelGroupOrderIter(self): for child in children: for sub_child in child.children: setattr(child, sub_child.name.lower(), sub_child) # If the device provides functions, add function and corresponding attributes to this hw module self._create_functions_from_node_providers(sub_child) @property def is_master(self) -> bool: slot_attributes = self.slot.attributes if slot_attributes is not None and hasattr(slot_attributes, "is_master"): return slot_attributes.is_master return False def _create_functions_from_node_providers(self, device: Device) -> None: providers: Munch | None = getattr(device, "provides", None) if providers is not None: for key, value in providers.items(): if key not in self.__dict__: provider = Munch() else: provider = getattr(self, key) provider.update(value) setattr(self, key, provider)
[docs] def probe(self, *args, **kwargs) -> bool: from ekfsm.core.probe import ProbeableDevice nodes = findall(self, lambda node: isinstance(node, ProbeableDevice)) for node in nodes: try: if node.probe(*args, **kwargs): return True except Exception as e: self.logger.error(f"Error probing {node}: {e}") return False
[docs] def info(self) -> dict[str, Any]: """ Returns a dictionary with information about the hardware module. """ return { "name": self.instance_name, "slot": self.slot, }
@property def instance_name(self) -> str: if self.name is None: raise RuntimeError("instance name not set") return self.name @property def slot(self) -> Slot: if self._slot is None: raise RuntimeError("slot not set") return self._slot def __repr__(self) -> str: return f"{self.__class__.__name__}(name={self.name}, type={self.board_type})"