Esempio n. 1
0
def test_grouped_register_invalid_params(data_dir, group_reg):
    """Test of register grouping with invalid width"""
    regs = Registers(TEST_DEVICE_NAME)

    with pytest.raises(SPSDKRegsErrorRegisterGroupMishmash):
        regs.load_registers_from_xml(data_dir + "/grp_regs.xml",
                                     grouped_regs=group_reg)
Esempio n. 2
0
class ShadowRegsXlsToXml():
    "Class to convert XLSX to XML with shadow register description"
    def __init__(self, xls_file: str, xml_file: str = "", xls_type: int=1) -> None:
        self.registers = Registers("Unknown")
        self.xls_type = xls_type
        self.header_cells = {}
        self.xml_file_name = xml_file if xml_file != "" else xls_file.replace(".xlsx", ".xml")
        self.wb = None
        print(os.path.dirname(os.path.realpath(__file__)))
        self.wb = openpyxl.load_workbook(xls_file)
        print(f"Loaded XLSX file ({xls_file})")
        self.convert()
        self.registers.write_xml(self.xml_file_name)
        print(f"Written XML file ({self.xml_file_name})")
        print(str(self.registers))

    def convert(self) -> None:
        raise NotImplementedError

    def _get_worksheet(self) -> Any:
        """Find the valid worksheet with the fuse map."""
        raise NotImplementedError

    def _get_header(self) -> None:
        """Returns the dictionary with cells of header."""
        raise NotImplementedError

    def _get_registers(self) -> None:
        """Function finds all registers in XLS sheet and store them."""
        raise NotImplementedError

    def __del__(self) -> None:
        """Just close all open files."""
        if self.wb:
            self.wb.close()
Esempio n. 3
0
    def __init__(self, debug_probe: DebugProbe, config: RegConfig, device: str, revision: str = "latest") -> None:
        """Initialization of Shadow register class."""
        self._probe = debug_probe
        self.config = config
        self.device = device
        self.offset = int(self.config.get_address(self.device, remove_underscore=True), 16)

        self.regs = Registers(self.device)
        rev = revision if revision != "latest" else config.get_latest_revision(self.device)
        self.regs.load_registers_from_xml(config.get_data_file(self.device, rev))
Esempio n. 4
0
    def __init__(self,
                 device: str = None,
                 revision: str = None,
                 user_config: PfrConfiguration = None) -> None:
        """Initialize an instance.

        :param device: device to use, list of supported devices is available via 'devices' method
        :param revision: silicon revision, if not specified, the latest is being used
        :param user_config: PfrConfiguration with user configuration to use with initialization
        :raises SPSDKError: When no device is provided
        :raises SPSDKError: When no device is not supported
        :raises SPSDKError: When there is invalid revision
        """
        if not (device or user_config):
            raise SPSDKError("No device provided")
        self.config = self._load_config()
        # either 'device' or 'user_config' IS defined! Mypy doesn't understand the check above
        self.device = device or user_config.device  # type: ignore

        if self.device not in self.config.get_devices():
            raise SPSDKError(f"Device '{self.device}' is not supported")
        self.revision = revision or (user_config.revision
                                     if user_config else "latest")
        if not self.revision or self.revision == "latest":
            self.revision = self.config.get_latest_revision(self.device)
            logger.warning(
                f"The silicon revision is not specified, the latest: '{self.revision}' has been used."
            )

        if self.revision not in self.config.get_revisions(self.device):
            raise SPSDKError(
                f"Invalid revision '{self.revision}' for '{self.device}'")
        self.registers = Registers(self.device)
        self.registers.load_registers_from_xml(
            xml=self.config.get_data_file(self.device, self.revision),
            filter_reg=self.config.get_ignored_registers(self.device),
            grouped_regs=self.config.get_grouped_registers(self.device),
        )

        # Set the computed field handler
        for reg, fields in self.config.get_computed_fields(
                self.device).items():
            reg_obj = self.registers.find_reg(reg)
            reg_obj.add_setvalue_hook(self.reg_computed_fields_handler, fields)

        self.user_config = PfrConfiguration(
            config=user_config,
            device=self.device,
            revision=self.revision,
            cfg_type=self.__class__.__name__,
        )

        if self.user_config.settings:
            self.set_config(self.user_config, raw=False)
Esempio n. 5
0
 def __init__(self, xls_file: str, xml_file: str = "", xls_type: int=1) -> None:
     self.registers = Registers("Unknown")
     self.xls_type = xls_type
     self.header_cells = {}
     self.xml_file_name = xml_file if xml_file != "" else xls_file.replace(".xlsx", ".xml")
     self.wb = None
     print(os.path.dirname(os.path.realpath(__file__)))
     self.wb = openpyxl.load_workbook(xls_file)
     print(f"Loaded XLSX file ({xls_file})")
     self.convert()
     self.registers.write_xml(self.xml_file_name)
     print(f"Written XML file ({self.xml_file_name})")
     print(str(self.registers))
Esempio n. 6
0
def create_simple_regs():
    """Create siple reg structure with basic cases."""
    regs = Registers(TEST_DEVICE_NAME)

    reg1 = RegsRegister(
        TEST_REG_NAME,
        TEST_REG_OFFSET,
        TEST_REG_WIDTH,
        TEST_REG_DESCR,
        TEST_REG_REV,
        TEST_REG_ACCESS,
    )

    reg2 = RegsRegister(
        TEST_REG_NAME + "_2",
        TEST_REG_OFFSET + 4,
        TEST_REG_WIDTH,
        TEST_REG_DESCR + "_2",
        TEST_REG_REV,
        TEST_REG_ACCESS,
    )

    bitfield1 = RegsBitField(
        reg2,
        TEST_BITFIELD_NAME,
        TEST_BITFIELD_OFFSET,
        TEST_BITFIELD_WIDTH,
        TEST_BITFIELD_DESCR,
        TEST_BITFIELD_RESET_VAL,
        TEST_BITFIELD_ACCESS,
    )

    bitfield2 = RegsBitField(
        reg2,
        TEST_BITFIELD_NAME + "_2",
        TEST_BITFIELD_OFFSET + TEST_BITFIELD_WIDTH,
        1,
        ".",
        0,
        TEST_BITFIELD_ACCESS,
    )
    enum1 = RegsEnum(TEST_ENUM_NAME, 0, TEST_ENUM_DESCR, 1)
    enum2 = RegsEnum(TEST_ENUM_NAME + "_2", 0, TEST_ENUM_DESCR + "_2", 1)
    bitfield2.add_enum(enum1)
    bitfield2.add_enum(enum2)
    reg2.add_bitfield(bitfield1)
    reg2.add_bitfield(bitfield2)
    regs.add_register(reg1)
    regs.add_register(reg2)

    return regs
Esempio n. 7
0
def test_registers_xml(data_dir, tmpdir):
    regs = Registers(TEST_DEVICE_NAME)

    with use_working_directory(data_dir):
        regs.load_registers_from_xml("registers.xml")

    with use_working_directory(tmpdir):
        regs.write_xml("registers.xml")

    regs2 = Registers(TEST_DEVICE_NAME)

    with use_working_directory(tmpdir):
        regs2.load_registers_from_xml("registers.xml")

    assert str(regs) == str(regs2)
Esempio n. 8
0
def info(pass_obj: dict, output: str, open_result: bool) -> None:
    """The command generate HTML of Shadow registers."""
    config = RegConfig(pass_obj["config_file"])
    device = pass_obj["device"]
    revision = pass_obj["revision"]
    registers = Registers(device)
    rev = revision if revision != "latest" else config.get_latest_revision(
        device)
    registers.load_registers_from_xml(config.get_data_file(device, rev))
    html_output = registers.generate_html(
        f"{device} - Shadow Registers",
        f"The table with Shadow registers description for {device}",
    )
    with open(output, "w", encoding="utf-8") as f:
        f.write(html_output)

    if open_result:  # pragma: no cover # can't test opening the html document
        click.launch(f"{output}")
Esempio n. 9
0
def test_bitfield_enums():
    parent_reg = RegsRegister(TEST_REG_NAME, TEST_REG_OFFSET, TEST_REG_WIDTH,
                              TEST_REG_DESCR, TEST_REG_REV, TEST_REG_ACCESS)

    bitfield = RegsBitField(parent_reg, TEST_BITFIELD_NAME,
                            TEST_BITFILED_OFFSET, TEST_BITFILED_WIDTH,
                            TEST_BITFIELD_DESCR, TEST_BITFIELD_RESET_VAL,
                            TEST_BITFIELD_ACCESS)

    parent_reg.add_bitfield(bitfield)

    enums = []
    for n in range((1 << TEST_BITFILED_WIDTH) - 1):
        enum = RegsEnum(f"{TEST_ENUM_NAME}{n}", n, f"{TEST_ENUM_DESCR}{n}",
                        TEST_BITFILED_WIDTH)
        enums.append(enum)
        bitfield.add_enum(enum)

    enum_names = bitfield.get_enum_names()

    for n in range((1 << TEST_BITFILED_WIDTH) - 1):
        assert n == bitfield.get_enum_constant(f"{TEST_ENUM_NAME}{n}")
        assert enums[n].name in enum_names

    for n in range((1 << TEST_BITFILED_WIDTH)):
        bitfield.set_value(n)
        if n < (1 << TEST_BITFILED_WIDTH) - 1:
            assert f"{TEST_ENUM_NAME}{n}" == bitfield.get_enum_value()
        else:
            assert n == bitfield.get_enum_value()

    for n in range((1 << TEST_BITFILED_WIDTH) - 1):
        bitfield.set_enum_value(f"{TEST_ENUM_NAME}{n}")
        assert n == bitfield.get_value()

    with pytest.raises(EnumNotFound):
        bitfield.get_enum_constant("Invalid name")

    regs = Registers(TEST_DEVICE_NAME)

    regs.add_register(parent_reg)
Esempio n. 10
0
    def __init__(
        self,
        debug_probe: DebugProbe,
        config: RegConfig,
        device: str,
        revision: str = "latest",
    ) -> None:
        """Initialization of Shadow register class."""
        self.probe = debug_probe
        self.config = config
        self.device = device
        self.offset = int(
            self.config.get_address(self.device, remove_underscore=True), 16)

        self.regs = Registers(self.device)
        rev = revision or "latest"
        rev = rev if rev != "latest" else config.get_latest_revision(
            self.device)
        self.regs.load_registers_from_xml(
            config.get_data_file(self.device, rev),
            grouped_regs=config.get_grouped_registers(self.device),
        )

        # Set the computed field handler
        for reg, fields in self.config.get_computed_fields(
                self.device).items():
            reg_obj = self.regs.find_reg(reg)
            reg_obj.add_setvalue_hook(self.reg_computed_fields_handler, fields)

        # Set the antipolize handler
        for reg, antipole_reg in self.config.get_antipole_regs(
                self.device).items():
            src = self.regs.find_reg(reg)
            dst = self.regs.find_reg(antipole_reg)
            src.add_setvalue_hook(self.reg_antipolize_src_handler, dst)
            dst.add_setvalue_hook(self.reg_antipolize_dst_handler, src)
Esempio n. 11
0
 def __init__(self,
              xls_file: str,
              xml_file: str = "",
              xls_type: int = 1) -> None:
     self.registers = Registers("Unknown")
     self.xls_type = xls_type
     self.header_cells: Dict[str, str] = {}
     self.xml_file_name = xml_file if xml_file != "" else xls_file.replace(
         ".xlsx", ".xml")
     self.workbook = None
     self.worksheet = None
     self.merged_cells = None
     click.echo(os.path.dirname(os.path.realpath(__file__)))
     self.workbook = openpyxl.load_workbook(xls_file)
     click.echo(f"Loaded XLSX file ({xls_file})")
Esempio n. 12
0
def test_registers_corrupted_xml(data_dir):
    """Test registers XML support with invalid data."""
    regs = Registers(TEST_DEVICE_NAME)

    with pytest.raises(SPSDKError):
        with use_working_directory(data_dir):
            regs.load_registers_from_xml("registers_corr.xml")

    with pytest.raises(SPSDKError):
        with use_working_directory(data_dir):
            regs.load_registers_from_xml("registers_corr2.xml")
Esempio n. 13
0
def test_register_duplicate():
    """Test registers add duplicate."""
    reg = RegsRegister(
        TEST_REG_NAME,
        TEST_REG_OFFSET,
        TEST_REG_WIDTH,
        TEST_REG_DESCR,
        TEST_REG_REV,
        TEST_REG_ACCESS,
    )
    reg1 = RegsRegister(
        TEST_REG_NAME,
        TEST_REG_OFFSET,
        TEST_REG_WIDTH,
        TEST_REG_DESCR,
        TEST_REG_REV,
        TEST_REG_ACCESS,
    )
    regs = Registers(TEST_DEVICE_NAME)
    regs.add_register(reg)

    with pytest.raises(SPSDKRegsError):
        regs.add_register(reg1)
Esempio n. 14
0
def test_load_grouped_register_value_compatibility(data_dir):
    """Simply test to handle load of individual registers into grouped from YML."""
    regs = Registers(TEST_DEVICE_NAME)

    group = [{"name": "TestRegA"}]
    regs.load_registers_from_xml(data_dir + "/grp_regs.xml",
                                 grouped_regs=group)
    yaml = YAML()
    with open(data_dir + "/group_none_reg.yml", "r") as yml_file:
        data = yaml.load(yml_file)
    regs.load_yml_config(data)
    reg = regs.find_reg("TestRegA")
    assert reg.get_hex_value() == "0x01020304111213142122232431323334"
    assert regs.find_reg(
        "TestRegA0", include_group_regs=True).get_hex_value() == "0x01020304"
    assert regs.find_reg(
        "TestRegA1", include_group_regs=True).get_hex_value() == "0x11121314"
    assert regs.find_reg(
        "TestRegA2", include_group_regs=True).get_hex_value() == "0x21222324"
    assert regs.find_reg(
        "TestRegA3", include_group_regs=True).get_hex_value() == "0x31323334"
Esempio n. 15
0
def test_basic_grouped_register_reversed_value(data_dir):
    """Test basic functionality of register grouping functionality with reversed value"""
    regs = Registers(TEST_DEVICE_NAME)

    group = [{"name": "TestRegA", "reverse": "True"}]

    regs.load_registers_from_xml(data_dir + "/grp_regs.xml",
                                 grouped_regs=group)

    reg = regs.find_reg("TestRegA")
    assert reg.offset == 0x400
    assert reg.width == 4 * 32

    reg.set_value("0x01020304_11121314_21222324_31323334")
    assert regs.find_reg(
        "TestRegA0", include_group_regs=True).get_hex_value() == "0x01020304"
    assert regs.find_reg(
        "TestRegA1", include_group_regs=True).get_hex_value() == "0x11121314"
    assert regs.find_reg(
        "TestRegA2", include_group_regs=True).get_hex_value() == "0x21222324"
    assert regs.find_reg(
        "TestRegA3", include_group_regs=True).get_hex_value() == "0x31323334"
    assert regs.find_reg("TestRegA0", include_group_regs=True).reverse == True
    assert regs.find_reg("TestRegA1", include_group_regs=True).reverse == True
    assert regs.find_reg("TestRegA2", include_group_regs=True).reverse == True
    assert regs.find_reg("TestRegA3", include_group_regs=True).reverse == True

    assert reg.get_hex_value() == "0x01020304111213142122232431323334"
Esempio n. 16
0
def test_registers_xml_bad_format(data_dir):
    """Test registers XML support - BAd XML format exception."""
    regs = Registers(TEST_DEVICE_NAME)

    with pytest.raises(SPSDKRegsError):
        regs.load_registers_from_xml(data_dir + "/bad_format.xml")
Esempio n. 17
0
def test_registers_xml_hidden(data_dir, tmpdir):
    """Test registers XML support."""
    regs = Registers(TEST_DEVICE_NAME)

    with use_working_directory(data_dir):
        regs.load_registers_from_xml("registers_reserved.xml")

    assert len(regs.get_registers()[0].get_bitfields()) == 1
    assert regs.get_registers()[0].get_bitfields()[0].get_value() == 0xA
    assert regs.get_registers()[0].get_value() == 0x550A00

    with use_working_directory(tmpdir):
        regs.write_xml("registers_reserved.xml")

    regs2 = Registers(TEST_DEVICE_NAME)

    with use_working_directory(tmpdir):
        regs2.load_registers_from_xml("registers_reserved.xml")

    assert str(regs) == str(regs2)
Esempio n. 18
0
class ShadowRegisters:
    """SPSDK support to control the shadow registers."""
    def __init__(
        self,
        debug_probe: DebugProbe,
        config: RegConfig,
        device: str,
        revision: str = "latest",
    ) -> None:
        """Initialization of Shadow register class."""
        self.probe = debug_probe
        self.config = config
        self.device = device
        self.offset = int(
            self.config.get_address(self.device, remove_underscore=True), 16)

        self.regs = Registers(self.device)
        rev = revision or "latest"
        rev = rev if rev != "latest" else config.get_latest_revision(
            self.device)
        self.regs.load_registers_from_xml(
            config.get_data_file(self.device, rev),
            grouped_regs=config.get_grouped_registers(self.device),
        )

        # Set the computed field handler
        for reg, fields in self.config.get_computed_fields(
                self.device).items():
            reg_obj = self.regs.find_reg(reg)
            reg_obj.add_setvalue_hook(self.reg_computed_fields_handler, fields)

        # Set the antipolize handler
        for reg, antipole_reg in self.config.get_antipole_regs(
                self.device).items():
            src = self.regs.find_reg(reg)
            dst = self.regs.find_reg(antipole_reg)
            src.add_setvalue_hook(self.reg_antipolize_src_handler, dst)
            dst.add_setvalue_hook(self.reg_antipolize_dst_handler, src)

    def _write_shadow_reg(self,
                          addr: int,
                          data: int,
                          verify: int = True) -> None:
        """The function write a shadow register.

        The function writes shadow register in to MCU and verify the write if requested.

        param addr: Shadow register address.
        param data: Shadow register data to write.
        param verify: If True the write is read back and compare, otherwise no check is done
        raises IoVerificationError
        """
        self.probe.mem_reg_write(addr, data)

        if verify:
            readback = self.probe.mem_reg_read(addr)
            if readback != data:
                raise IoVerificationError(
                    f"The written data 0x{data:08X} to 0x{addr:08X} address are invalid."
                )

    def reload_registers(self) -> None:
        """Reload all the values in managed registers."""
        for reg in self.regs.get_registers():
            self.reload_register(reg)

    def sets_all_registers(self) -> None:
        """Update all shadow registers in target by local values."""
        for reg in self.regs.get_registers():
            self.set_register(reg.name, reg.get_value())

    def reload_register(self, reg: RegsRegister) -> None:
        """Reload the value in requested register.

        :param reg: The register to reload from the HW.
        """
        reg.set_value(self.get_register(reg.name))

    def set_register(self, reg_name: str, data: Any) -> None:
        """The function sets the value of the specified register.

        param reg: The register name.
        param data: The new data to be stored to shadow register.
        raises SPSDKDebugProbeError: The debug probe is not specified.
        """
        if self.probe is None:
            raise SPSDKDebugProbeError("There is no debug probe.")

        try:
            reg = self.regs.find_reg(reg_name)
            value = value_to_bytes(data)

            start_address = self.offset + reg.offset
            width = reg.width

            if width < len(value) * 8:
                raise SPSDKError(
                    "Invalid length of data for shadow register write.")

            width = max(width, 32)

            data_aligned = bytearray(math.ceil(width / 8))
            data_aligned[len(data_aligned) -
                         len(value):len(data_aligned)] = value

            end_address = start_address + math.ceil(width / 8)
            addresses = range(start_address, end_address, 4)

            for i, addr in enumerate(addresses):
                val = data_aligned[i * 4:i * 4 + 4]
                self._write_shadow_reg(
                    addr,
                    int.from_bytes(
                        change_endianism(val) if reg.reverse else val, "big"),
                )

            reg.set_value(value, raw=True)

        except SPSDKError as exc:
            raise SPSDKError(
                f"The get shadow register failed({str(exc)}).") from exc

    def get_register(self, reg_name: str) -> bytes:
        """The function returns value of the requested register.

        param reg: The register name.
        return: The value of requested register in bytes
        raises SPSDKDebugProbeError: The debug probe is not specified.
        """
        if self.probe is None:
            raise SPSDKDebugProbeError("There is no debug probe.")

        array = bytearray()
        try:
            reg = self.regs.find_reg(reg_name)

            start_address = self.offset + reg.offset
            width = max(reg.width, 32)

            if width == 32:
                array.extend(
                    self.probe.mem_reg_read(start_address).to_bytes(4, "big"))
            else:
                end_address = start_address + math.ceil(width / 8)
                addresses = range(start_address, end_address, 4)

                for addr in addresses:
                    array.extend(
                        self.probe.mem_reg_read(addr).to_bytes(4, "big"))

            result = reverse_bytes_in_longs(
                bytes(array)) if reg.reverse else bytes(array)

        except SPSDKError as exc:
            raise SPSDKError(
                f"The get shadow register failed({str(exc)}).") from exc

        return result

    def create_yml_config(self, file_name: str, raw: bool = False) -> None:
        """The function creates the configuration YML file.

        :param file_name: The file_name (without extension) of stored configuration.
        :param raw: Raw output of configuration (including computed fields and anti-pole registers)
        """
        antipole_regs = None if raw else list(
            self.config.get_antipole_regs(self.device).values())
        computed_fields = None if raw else self.config.get_computed_fields(
            self.device)

        yaml = YAML()
        yaml.indent(sequence=SPSDK_YML_INDENT * 2, offset=SPSDK_YML_INDENT)
        data = CM()

        description = CM()
        description.yaml_set_start_comment(
            f"NXP {self.device.upper()} Shadow registers configuration",
            indent=2)
        description.insert(1,
                           "device",
                           self.device,
                           comment="The NXP device name.")
        description.insert(2,
                           "version",
                           __version__,
                           comment="The SPSDK Shadow register tool version.")
        description.insert(3,
                           "author",
                           __author__,
                           comment="The author of the configuration.")
        description.insert(4,
                           "release",
                           __release__,
                           comment="The SPSDK release.")

        data["description"] = description
        data["registers"] = self.regs.create_yml_config(
            exclude_regs=antipole_regs,
            exclude_fields=computed_fields,
            indent=2)
        with open(file_name, "w", encoding="utf8") as out_file:
            yaml.dump(data, out_file)

    def load_yml_config(self, file_name: str, raw: bool = False) -> None:
        """The function loads the configuration from YML file.

        :param file_name: The file_name (without extension) of stored configuration.
        :param raw: Raw input of configuration (including computed fields and anti-pole registers)
        :raises SPSDKError: When the configuration file not found.
        """
        antipole_regs = None if raw else list(
            self.config.get_antipole_regs(self.device).values())
        computed_fields = None if raw else self.config.get_computed_fields(
            self.device)
        try:
            with open(file_name, "r", encoding="utf8") as yml_config_file:
                yaml = YAML()
                yaml.indent(sequence=4, offset=2)
                data = yaml.load(yml_config_file)
        except FileNotFoundError as exc:
            raise SPSDKError(
                "File with YML configuration doesn't exists.") from exc

        self.regs.load_yml_config(data["registers"], antipole_regs,
                                  computed_fields)
        if not raw:
            # Just update only configured registers
            exclude_hooks = list(
                set(self.regs.get_reg_names()) - set(data["registers"].keys()))
            self.regs.run_hooks(exclude_hooks)

        logger.debug(
            "The shadow registers has been loaded from configuration.")

    @staticmethod
    def reg_antipolize_src_handler(val: int, context: Any) -> int:
        """Antipolize given register value.

        :param val: Input register value.
        :param context: The method context.
        :return: Antipolized value.
        """
        dst_reg: RegsRegister = context
        dst_reg.set_value(val ^ 0xFFFFFFFF, raw=True)
        return val

    @staticmethod
    def reg_antipolize_dst_handler(val: int, context: Any) -> int:
        """Keep same antipolized register value in computed register.

        :param val: Input register value.
        :param context: The method context.
        :return: Antipolized value.
        """
        src_reg: RegsRegister = context
        val = src_reg.get_value()
        new_val = val ^ 0xFFFFFFFF
        return new_val

    def reg_computed_fields_handler(self, val: bytes, context: Any) -> bytes:
        """Recalculate all fields for given register value.

        :param val: Input register value.
        :param context: The method context (fields).
        :return: recomputed value.
        :raises SPSDKError: Raises when the computing routine is not found.
        """
        fields: dict = context
        for method in fields.values():
            if hasattr(self, method):
                method_ref = getattr(self, method, None)
                val = method_ref(val)
            else:
                raise SPSDKError(
                    f"The '{method}' compute function doesn't exists.")

        return val

    # CRC8 - ITU
    @staticmethod
    def crc_update(data: bytes, crc: int = 0, is_final: bool = True) -> int:
        """The function compute the CRC8 ITU method from given bytes.

        :param data: Input data to compute CRC.
        :param crc: The seed for CRC.
        :param is_final: The flag the the function should return final result.
        :return: The CRC result.
        """
        k = 0
        data_len = len(data)
        while data_len != 0:
            data_len -= 1
            carry = data[k]
            k += 1
            for i in range(8):
                bit = (crc & 0x80) != 0
                if (carry & (0x80 >> i)) != 0:
                    bit = not bit
                crc <<= 1
                if bit:
                    crc ^= 0x07
            crc &= 0xFF
        if is_final:
            return (crc & 0xFF) ^ 0x55
        return crc & 0xFF

    @staticmethod
    def comalg_dcfg_cc_socu_crc8(val: int) -> int:
        """Function that creates the crc for DCFG_CC_SOCU.

        :param val: Input DCFG_CC_SOCU Value.
        :return: Returns the value of DCFG_CC_SOCU with computed CRC8 field.
        """
        in_val = bytearray(3)
        for i in range(3):
            in_val[i] = (val >> (8 + i * 8)) & 0xFF
        val &= ~0xFF
        val |= ShadowRegisters.crc_update(in_val)
        return val

    @staticmethod
    def comalg_dcfg_cc_socu_rsvd(val: int) -> int:
        """Function fill up the DCFG_CC_SOCU RSVD filed by 0x80 to satisfy MCU needs.

        :param val: Input DCFG_CC_SOCU Value.
        :return: Returns the value of DCFG_CC_SOCU with computed CRC8 field.
        """
        new_val = val | 0x80000000
        return new_val

    @staticmethod
    def comalg_do_nothing(val: int) -> int:
        """Function that do nothing.

        :param val: Input Value.
        :return: Returns same value as it get.
        """
        return val
Esempio n. 19
0
def test_registers_corrupted_xml(data_dir, tmpdir):
    regs = Registers(TEST_DEVICE_NAME)

    with use_working_directory(data_dir):
        regs.load_registers_from_xml("registers_corr.xml")

    with use_working_directory(tmpdir):
        regs.write_xml("registers_corr.xml")

    assert not filecmp.cmp(os.path.join(data_dir, "registers_corr.xml"),
                           os.path.join(tmpdir, "registers_corr.xml"))

    regs.clear()

    with use_working_directory(tmpdir):
        regs.load_registers_from_xml("registers_corr.xml")
        regs.write_xml("registers_corr1.xml")

    assert filecmp.cmp(os.path.join(tmpdir, "registers_corr.xml"),
                       os.path.join(tmpdir, "registers_corr1.xml"))

    # Without clear - Cannot add register with same name as is already added
    with use_working_directory(tmpdir):
        regs.load_registers_from_xml("registers_corr.xml")
        regs.write_xml("registers_corr1.xml")

    assert filecmp.cmp(os.path.join(tmpdir, "registers_corr.xml"),
                       os.path.join(tmpdir, "registers_corr1.xml"))
Esempio n. 20
0
class BaseConfigArea:
    """Base for CMPA and CFPA classes."""

    CONFIG_DIR = PFR_DATA_FOLDER
    CONFIG_FILE = "database.json"
    BINARY_SIZE = 512
    ROTKH_SIZE = 32
    ROTKH_REGISTER = "ROTKH"
    MARK = b"SEAL"
    DESCRIPTION = "Base Config Area"
    IMAGE_PREFILL_PATTERN = 0

    def __init__(self,
                 device: str = None,
                 revision: str = None,
                 user_config: PfrConfiguration = None) -> None:
        """Initialize an instance.

        :param device: device to use, list of supported devices is available via 'devices' method
        :param revision: silicon revision, if not specified, the latest is being used
        :param user_config: PfrConfiguration with user configuration to use with initialization
        :raises SPSDKError: When no device is provided
        :raises SPSDKError: When no device is not supported
        :raises SPSDKError: When there is invalid revision
        """
        if not (device or user_config):
            raise SPSDKError("No device provided")
        self.config = self._load_config()
        # either 'device' or 'user_config' IS defined! Mypy doesn't understand the check above
        self.device = device or user_config.device  # type: ignore

        if self.device not in self.config.get_devices():
            raise SPSDKError(f"Device '{self.device}' is not supported")
        self.revision = revision or (user_config.revision
                                     if user_config else "latest")
        if not self.revision or self.revision == "latest":
            self.revision = self.config.get_latest_revision(self.device)
            logger.warning(
                f"The silicon revision is not specified, the latest: '{self.revision}' has been used."
            )

        if self.revision not in self.config.get_revisions(self.device):
            raise SPSDKError(
                f"Invalid revision '{self.revision}' for '{self.device}'")
        self.registers = Registers(self.device)
        self.registers.load_registers_from_xml(
            xml=self.config.get_data_file(self.device, self.revision),
            filter_reg=self.config.get_ignored_registers(self.device),
            grouped_regs=self.config.get_grouped_registers(self.device),
        )

        # Set the computed field handler
        for reg, fields in self.config.get_computed_fields(
                self.device).items():
            reg_obj = self.registers.find_reg(reg)
            reg_obj.add_setvalue_hook(self.reg_computed_fields_handler, fields)

        self.user_config = PfrConfiguration(
            config=user_config,
            device=self.device,
            revision=self.revision,
            cfg_type=self.__class__.__name__,
        )

        if self.user_config.settings:
            self.set_config(self.user_config, raw=False)

    def reg_computed_fields_handler(self, val: bytes, context: Any) -> bytes:
        """Recalculate all fields for given register value.

        :param val: Input register value.
        :param context: The method context (fields).
        :return: recomputed value.
        :raises SPSDKPfrError: Raises when the computing routine is not found.
        """
        fields: dict = context
        for method in fields.values():
            if hasattr(self, method):
                method_ref = getattr(self, method, None)
                val = method_ref(val)
            else:
                raise SPSDKPfrError(
                    f"The '{method}' compute function doesn't exists.")

        return val

    @staticmethod
    def pfr_reg_inverse_high_half(val: int) -> int:
        """Function that inverse low 16-bits of register value to high 16 bits.

        :param val: Input current reg value.
        :return: Returns the complete register value with updated higher half field.
        """
        ret = val & 0xFFFF
        ret |= (ret ^ 0xFFFF) << 16
        return ret

    @classmethod
    def _load_config(cls) -> RegConfig:
        """Loads the PFR block configuration file.

        :return: PFR block configuration database.
        """
        return RegConfig(os.path.join(cls.CONFIG_DIR, cls.CONFIG_FILE))

    @classmethod
    def devices(cls) -> List[str]:
        """Classmethod to get list of supported devices.

        :return: List of supported devices.
        """
        config = cls._load_config()
        return config.get_devices()

    def _get_registers(self) -> List[RegsRegister]:
        """Get a list of all registers.

        :return: List of PFR configuration registers.
        """
        exclude = self.config.get_ignored_registers(self.device)
        return self.registers.get_registers(exclude)

    def set_config(self, config: PfrConfiguration, raw: bool = False) -> None:
        """Apply configuration from file.

        :param config: PFR configuration.
        :param raw: When set all (included computed fields) configuration will be applied.
        :raises SPSDKError: When device is not provided.
        :raises SPSDKError: When revision is not provided.
        :raises SPSDKPfrConfigError: Invalid config file.
        """
        if not self.device:
            raise SPSDKError("No device provided")
        if not self.revision:
            raise SPSDKError("No revision provided")

        if config.device != self.device:
            raise SPSDKPfrConfigError(
                f"Invalid device in configuration. {self.device} != {config.device}"
            )
        if not config.revision or config.revision in ("latest", ""):
            config.revision = self.config.get_latest_revision(self.device)
            logger.warning(
                f"The configuration file doesn't contains silicon revision, \
the latest: '{config.revision}' has been used.")
        if config.revision != self.revision:
            raise SPSDKPfrConfigError(
                f"Invalid revision in configuration. {self.revision} != {config.revision}"
            )
        if config.type and config.type.upper() != self.__class__.__name__:
            raise SPSDKPfrConfigError(
                f"Invalid configuration type. {self.__class__.__name__} != {config.type}"
            )

        if not config.settings:
            raise SPSDKPfrConfigError("Missing configuration of PFR fields!")

        computed_regs = []
        computed_regs.extend(self.config.get_ignored_registers(self.device))
        if not raw:
            computed_regs.extend(
                self.config.get_computed_registers(self.device))
        computed_fields = None if raw else self.config.get_computed_fields(
            self.device)

        self.registers.load_yml_config(config.settings, computed_regs,
                                       computed_fields)
        if not raw:
            # # Just update only configured registers
            exclude_hooks = []
            if not self.config.get_value("mandatory_computed_regs",
                                         self.device):
                exclude_hooks.extend(
                    list(
                        set(self.registers.get_reg_names()) -
                        set(config.settings.keys())))
            self.registers.run_hooks(exclude_hooks)

    def get_yaml_config(self,
                        exclude_computed: bool = True,
                        diff: bool = False,
                        indent: int = 0) -> CM:
        """Return YAML configuration from loaded registers.

        :param exclude_computed: Omit computed registers and fields.
        :param diff: Get only configuration with difference value to reset state.
        :param indent: YAML start indent.
        :return: YAML PFR configuration in commented map(ordered dict).
        """
        computed_regs = (None if not exclude_computed else
                         self.config.get_computed_registers(self.device))
        computed_fields = (None if not exclude_computed else
                           self.config.get_computed_fields(self.device))
        ignored_fields = self.config.get_ignored_fields(self.device)

        data = self.registers.create_yml_config(computed_regs, computed_fields,
                                                ignored_fields, diff,
                                                indent + 2)
        return self.user_config.get_yaml_config(data, indent)

    def generate_config(self, exclude_computed: bool = True) -> CM:
        """Generate configuration structure for user configuration.

        :param exclude_computed: Exclude computed fields, defaults to True.
        :return: YAML commented map with PFR configuration  in reset state.
        """
        # Create own copy to keep self as is and get reset values by standard YML output
        copy_of_self = copy.deepcopy(self)
        copy_of_self.registers.reset_values()

        return copy_of_self.get_yaml_config(exclude_computed)

    def _calc_rotkh(self, keys: List[PublicKey]) -> bytes:
        """Calculate ROTKH (Root Of Trust Key Hash).

        :param keys: List of Keys to compute ROTKH.
        :return: Value of ROTKH with right width.
        :raises SPSDKPfrError: Algorithm width doesn't fit into ROTKH field.
        """
        # the data structure use for computing final ROTKH is 4*32B long
        # 32B is a hash of individual keys
        # 4 is the max number of keys, if a key is not provided the slot is filled with '\x00'
        # The LPC55S3x has two options to compute ROTKH, so it's needed to be
        # detected the right algorithm and mandatory warn user about this selection because
        # it's MUST correspond to settings in eFuses!
        reg_rotkh = self.registers.find_reg("ROTKH")
        width = reg_rotkh.width
        if isinstance(keys[0], rsa.RSAPublicKey):
            algorithm_width = 256
        else:
            algorithm_width = keys[0].key_size

        if algorithm_width > width:
            raise SPSDKPfrError(
                "The ROTKH field is smaller than used algorithm width.")

        key_hashes = [
            calc_pub_key_hash(key, openssl_backend, algorithm_width)
            for key in keys
        ]
        data = [
            key_hashes[i] if i < len(key_hashes) else bytes(algorithm_width //
                                                            8)
            for i in range(4)
        ]
        return openssl_backend.hash(bytearray().join(data),
                                    f"sha{algorithm_width}").ljust(
                                        width // 8, b"\x00")

    def _get_seal_start_address(self) -> int:
        """Function returns start of seal fields for the device.

        :return: Start of seals fields.
        :raises SPSDKError: When 'seal_start_address' in database.json can not be found
        """
        start = self.config.get_seal_start_address(self.device)
        if not start:
            raise SPSDKError(
                "Can't find 'seal_start_address' in database.json")
        return self.registers.find_reg(start).offset

    def _get_seal_count(self) -> int:
        """Function returns seal count for the device.

        :return: Count of seals fields.
        :raises SPSDKError: When 'seal_count' in database.json can not be found
        """
        count = self.config.get_seal_count(self.device)
        if not count:
            raise SPSDKError("Can't find 'seal_count' in database.json")
        return value_to_int(count)

    def export(self,
               add_seal: bool = False,
               keys: List[PublicKey] = None) -> bytes:
        """Generate binary output.

        :param add_seal: The export is finished in the PFR record by seal.
        :param keys: List of Keys to compute ROTKH field.
        :return: Binary block with PFR configuration(CMPA or CFPA).
        :raises SPSDKPfrRotkhIsNotPresent: This PFR block doesn't contains ROTKH field.
        :raises SPSDKError: The size of data is {len(data)}, is not equal to {self.BINARY_SIZE}.
        """
        if keys:
            try:
                # ROTKH may or may not be present, derived class defines its presense
                rotkh_reg = self.registers.find_reg(self.ROTKH_REGISTER)
                rotkh_data = self._calc_rotkh(keys)
                rotkh_reg.set_value(rotkh_data, True)
            except SPSDKRegsErrorRegisterNotFound as exc:
                raise SPSDKPfrRotkhIsNotPresent(
                    "This device doesn't contain ROTKH register!") from exc

        data = bytearray([self.IMAGE_PREFILL_PATTERN] * self.BINARY_SIZE)
        for reg in self._get_registers():
            data[reg.offset:reg.offset +
                 reg.width // 8] = reg.get_bytes_value()

        if add_seal:
            seal_start = self._get_seal_start_address()
            seal_count = self._get_seal_count()
            data[seal_start:seal_start +
                 seal_count * 4] = self.MARK * seal_count

        if len(data) != self.BINARY_SIZE:
            raise SPSDKError(
                f"The size of data is {len(data)}, is not equal to {self.BINARY_SIZE}"
            )
        return bytes(data)

    def parse(self, data: bytes) -> None:
        """Parse input binary data to registers.

        :param data: Input binary data of PFR block.
        """
        for reg in self._get_registers():
            value = bytearray(data[reg.offset:reg.offset + reg.width // 8])
            # don't change endian if register is meant to be used in 'reverse' (array of bytes)
            reg.set_value(value if reg.reverse else change_endianism(value),
                          raw=True)
Esempio n. 21
0
def test_basic_regs(tmpdir):
    """Basic test of registers class."""
    regs = Registers(TEST_DEVICE_NAME)

    assert regs.dev_name == TEST_DEVICE_NAME

    reg1 = RegsRegister(TEST_REG_NAME, TEST_REG_OFFSET, TEST_REG_WIDTH,
                        TEST_REG_DESCR, TEST_REG_REV, TEST_REG_ACCESS)

    with pytest.raises(RegisterNotFound):
        regs.find_reg("NonExisting")

    # Ther Registers MUST return empty erray
    assert regs.get_reg_names() == []

    with pytest.raises(TypeError):
        regs.remove_register("String")

    with pytest.raises(ValueError):
        regs.remove_register(reg1)

    # Now we could do tests with a register added to list
    regs.add_register(reg1)

    regs.remove_register_by_name(["String"])

    assert TEST_REG_NAME in regs.get_reg_names()

    regt = regs.find_reg(TEST_REG_NAME)

    assert regt == reg1

    with pytest.raises(TypeError):
        regs.add_register("Invalid Parameter")

    regt.set_value(TEST_REG_VALUE)
    assert reg1.get_value() == TEST_REG_VALUE.to_bytes(4, "big")

    filename = os.path.join(tmpdir, TEST_XML_FILE)
    regs.write_xml(filename)
    assert os.path.isfile(filename)

    printed_str = str(regs)

    assert TEST_DEVICE_NAME in printed_str
    assert TEST_REG_NAME in printed_str

    regs.remove_register_by_name([TEST_REG_NAME])

    with pytest.raises(RegisterNotFound):
        regs.find_reg(TEST_REG_NAME)
        assert False
Esempio n. 22
0
class ShadowRegisters():
    """SPSDK support to control the shadow registers."""

    def __init__(self, debug_probe: DebugProbe, config: RegConfig, device: str, revision: str = "latest") -> None:
        """Initialization of Shadow register class."""
        self._probe = debug_probe
        self.config = config
        self.device = device
        self.offset = int(self.config.get_address(self.device, remove_underscore=True), 16)

        self.regs = Registers(self.device)
        rev = revision if revision != "latest" else config.get_latest_revision(self.device)
        self.regs.load_registers_from_xml(config.get_data_file(self.device, rev))

    def _write_shadow_reg(self, addr: int, data: int, verify: int = True) -> None:
        """The function write a shadow register.

        The funstion writes shadow register in to MCU and verify the write if requested.

        param addr: Shadow register address.
        param data: Shadow register data to write.
        param verify: If True the write is read back and compare, otherwise no check is done
        raises IoVerificationError
        """
        self._probe.mem_reg_write(addr, data)

        if verify:
            readback = self._probe.mem_reg_read(addr)
            if readback != data:
                raise IoVerificationError(f"The written data 0x{data:08X} to 0x{addr:08X} address are invalid.")

    def reload_registers(self) -> None:
        """Reload all the values in managed registers."""
        for reg in self.regs.registers:
            self.reload_register(reg)

    def sets_all_registers(self) -> None:
        """Update all shadow registers in target by local values."""
        for reg in self.regs.registers:
            self.set_register(reg.name, reg.get_value())

    def reload_register(self, reg: RegsRegister) -> None:
        """Reload the value in requested register.

        :param reg: The register to reload from the HW.
        """
        reg.set_value(self.get_register(reg.name))

    @staticmethod
    def _reverse_bytes_in_longs(arr: bytearray) -> bytearray:
        """The function reverse byte order in longs from input bytes.

        param arr: Input array.
        :return: New array with reversed bytes.
        :raises ValueError: Raises when invalid value is in input.
        """
        arr_len = len(arr)
        if arr_len % 4 != 0:
            raise ValueError("The input array is not in modulo 4!")

        result = bytearray()

        for x in range(arr_len):
            word = bytearray(arr[x*4:x*4+4])
            word.reverse()
            result.extend(word)
        return result

    def set_register(self, reg_name: str, data: Any) -> None:
        """The function sets the value of the specified register.

        param reg: The register name.
        param data: The new data to be stored to shadow register.
        raises DebugProbeError: The debug probe is not specified.
        """
        if self._probe is None:
            raise DebugProbeError("There is no debug probe.")

        try:
            reg = self.regs.find_reg(reg_name)
            value = value_to_bytes(data)

            start_address = self.offset + reg.offset
            width = reg.width

            if width < len(value) * 8:
                raise SPSDKError(f"Invalid length of data for shadow register write.")

            if width < 32:
                width = 32

            data_alligned = bytearray(math.ceil(width / 8))
            data_alligned[len(data_alligned) - len(value) : len(data_alligned)] = value

            if reg.reverse:
                data_alligned = self._reverse_bytes_in_longs(data_alligned)

            if width == 32:
                self._write_shadow_reg(start_address, int.from_bytes(data_alligned[:4], "big"))
            else:
                end_address = start_address + math.ceil(width / 8)
                addresses = range(start_address, end_address, 4)

                i = 0
                for addr in addresses:
                    self._write_shadow_reg(addr, int.from_bytes(data_alligned[i:i+4], "big"))
                    i += 4

            reg.set_value(value)

        except SPSDKError as exc:
            raise SPSDKError(f"The get shadow register failed({str(exc)}).")

    def get_register(self, reg_name: str) -> bytes:
        """The function returns value of the requested register.

        param reg: The register name.
        return: The value of requested register in bytes
        raises DebugProbeError: The debug probe is not specified.
        """
        if self._probe is None:
            raise DebugProbeError("There is no debug probe.")

        result = bytearray()
        try:
            reg = self.regs.find_reg(reg_name)

            start_address = self.offset + reg.offset
            width = reg.width

            if width < 32:
                width = 32

            if width == 32:
                result.extend(self._probe.mem_reg_read(start_address).to_bytes(4, "big"))
            else:
                end_address = start_address + math.ceil(width / 8)
                addresses = range(start_address, end_address, 4)

                for addr in addresses:
                    result.extend(self._probe.mem_reg_read(addr).to_bytes(4, "big"))

            if reg.reverse:
                result = self._reverse_bytes_in_longs(result)

        except SPSDKError as exc:
            raise SPSDKError(f"The get shadow register failed({str(exc)}).")

        return result

    def create_yml_config(self, file_name: str, raw: bool = False) -> None:
        """The function creates the configuration YML file.

        :param file_name: The file_name (without extension) of stored configuration.
        :param raw: Raw output of configuration (including computed fields and anti-pole registers)
        """
        CM = ruamel.yaml.comments.CommentedMap  # defaults to block style

        antipole_regs = self.config.get_antipole_regs(self.device)
        computed_fields = self.config.get_computed_fields(self.device)

        yaml = YAML()
        yaml.indent(sequence=4, offset=2)
        data = CM()
        data["registers"] = CM()

        for reg in self.regs.registers:
            if not raw and reg.name in antipole_regs.values():
                continue
            reg_yml = CM()
            reg_yml.yaml_set_start_comment("Reg Description:" + reg.description)
            reg_yml.insert(1, "name", reg.name, comment="The name of the register")
            data["registers"][reg.name] = reg_yml
            if len(reg.get_bitfields()) > 0:
                btf_yml = CM()
                reg_yml["bitfields"] = btf_yml
                for i, bitf in enumerate(reg.get_bitfields()):
                    if not raw and reg.name in computed_fields.keys() and bitf.name in computed_fields[reg.name].keys():
                        continue
                    possible_values = ""
                    if bitf.has_enums():
                        # print the comments as a hint of possible values
                        possible_values = f", (Possible values: {', '.join(bitf.get_enum_names())})"
                    btf_yml.insert(i,
                                   bitf.name,
                                   bitf.get_enum_value(),
                                   comment=f"The width: {bitf.width} bits{possible_values}")
            else:
                reg_yml.insert(2, "value", reg.get_hex_value(), comment="The value of the register")

        with open(file_name, "w") as out_file:
            yaml.dump(data, out_file)

    def load_yml_config(self, file_name: str, raw: bool = False) -> None:
        """The function loads the configuration from YML file.

        :param file_name: The file_name (without extension) of stored configuration.
        :param raw: Raw input of configuration (including computed fields and anti-pole registers)
        :raise SPSDKError: When the configuration file not found.
        """
        antipole_regs = self.config.get_antipole_regs(self.device)
        computed_fields = self.config.get_computed_fields(self.device)
        try:
            with open(file_name, "r") as yml_config_file:
                yaml = YAML()
                yaml.indent(sequence=4, offset=2)
                data = yaml.load(yml_config_file)
        except FileNotFoundError:
            raise SPSDKError("File with YML configuration doesn't exists.")

        for reg in data["registers"].keys():
            if not raw and reg in antipole_regs.values():
                continue
            if reg not in self.regs.get_reg_names():
                continue
            #The loaded register is our
            if "value" in data["registers"][reg].keys():
                val = data['registers'][reg]['value']
                val = val.replace("0x", "")
                self.regs.find_reg(reg).set_value(bytes.fromhex(val))
            elif "bitfields" in data["registers"][reg].keys():
                for bitf_name in data["registers"][reg]["bitfields"]:
                    try:
                        self.regs.find_reg(reg).find_bitfield(bitf_name)
                    except BitfieldNotFound:
                        continue
                    if not raw and reg in computed_fields.keys() and bitf_name in computed_fields[reg].keys():
                        continue
                    bitf = self.regs.find_reg(reg).find_bitfield(bitf_name)
                    if bitf.has_enums():
                        #solve the bitfields store in enums string
                        bitf.set_enum_value(data["registers"][reg]["bitfields"][bitf_name])
                    else:
                        #load bitfield data
                        bitf.set_value(int(data["registers"][reg]["bitfields"][bitf_name]))
            else:
                logger.error(f"There are no data for {reg} register.")

            if not raw and reg in computed_fields.keys():
                # Check the computed fields
                for field in computed_fields[reg].keys():
                    val = self.regs.find_reg(reg).get_value()
                    if hasattr(self, computed_fields[reg][field]):
                        method = getattr(self, computed_fields[reg][field], None)
                        computed_val = method(val)
                        self.regs.find_reg(reg).set_value(computed_val)
                    else:
                        raise SPSDKError(f"The '{computed_fields[reg][field]}' compute function doesn't exists.")

            if not raw and reg in antipole_regs.keys():
                #Write also anti-pole value
                val = self.regs.find_reg(reg).get_value()
                self.regs.find_reg(antipole_regs[reg]).set_value(self.antipolize_reg(val))

            logger.debug(f"The register {reg} has been loaded from configuration.")

    @staticmethod
    def antipolize_reg(val: bytes) -> bytes:
        """Antipolize given register value.

        :param val: Input register value.
        :return: Antipolized value.
        """
        newval = [0]*len(val)
        for i, val_byte in enumerate(val):
            newval[i] = val_byte ^ 0xFF
        return bytes(newval)

    # CRC8 - ITU
    @staticmethod
    def crc_update(data: bytes, crc: int = 0, is_final: bool = True) -> int:
        """The function compute the CRC8 ITU method from given bytes.

        :param data: Input data to compute CRC.
        :param crc: The seed for CRC.
        :param is_final: The flag the the function should retrn final result.
        :return: The CRC result.
        """
        k = 0
        data_len = len(data)
        while data_len != 0:
            data_len -= 1
            c = data[k]
            k += 1
            for i in range(8):
                bit = (crc & 0x80) != 0
                if (c & (0x80>>i)) != 0:
                    bit = not bit
                crc <<= 1
                if bit:
                    crc ^= 0x07
            crc &= 0xff
        if is_final:
            return (crc & 0xff) ^ 0x55
        else:
            return crc & 0xff


    def comalg_dcfg_cc_socu_crc8(self, val: bytes) -> bytes:
        """Function that creates the crc for DCFG_CC_SOCU.

        :param val: Input DCFG_CC_SOCU Value.
        :return: Returns the value of DCFG_CC_SOCU with computed CRC8 field.
        """
        ret = [0]*4
        ret[0:3] = val[0:3]
        input = bytearray(val[0:3])
        input.reverse()
        ret[3] = self.crc_update(input)
        return bytes(ret)

    def comalg_dcfg_cc_socu_rsvd(self, val: bytes) -> bytes:
        """Function fill up the DCFG_CC_SOCU RSVD filed by 0x40 to satisfy MCU needs.

        :param val: Input DCFG_CC_SOCU Value.
        :return: Returns the value of DCFG_CC_SOCU with computed CRC8 field.
        """
        new_val = bytearray(val)
        new_val[0] &= ~0xFE
        new_val[0] |= 0x40
        return new_val

    def comalg_do_nothig(self, val: bytes) -> bytes:
        """Function that do nothing.

        :param val: Input Value.
        :return: Returns same value as it get.
        """
        return val