Add option for generating RTE dummy files

Change-Id: Ie90031808b8cf47f6542caa73014445c803a2f94
This commit is contained in:
Henrik Wahlqvist 2025-01-13 14:31:40 +01:00
parent ef521427c8
commit 0a8a2d69a6
4 changed files with 271 additions and 1 deletions
powertrain_build
tests/powertrain_build

@ -34,6 +34,7 @@ from powertrain_build.memory_section import MemorySection
from powertrain_build.nvm_def import NVMDef, ZCNVMDef
from powertrain_build.problem_logger import ProblemLogger
from powertrain_build.replace_compu_tab_ref import replace_tab_verb
from powertrain_build.rte_dummy import RteDummy
from powertrain_build.sched_funcs import SchedFuncs
from powertrain_build.signal_if_html_rep import SigIfHtmlReport
from powertrain_build.signal_incons_html_rep import SigConsHtmlReport
@ -669,6 +670,11 @@ def add_args(parser):
action="store_true",
help="Generate core dummy code to enable integration with old supplier code",
)
powertrain_build_parser.add_argument(
"--rte-dummy",
action="store_true",
help="Generate RTE dummy code to enable e.g. Silver testing",
)
powertrain_build_parser.add_argument(
"--debug", action="store_true", help="Activate the debug log"
)
@ -708,6 +714,7 @@ def build(
project_config,
interface=False,
core_dummy=False,
rte_dummy=False,
no_abort=False,
no_nvm_a2l=False,
debug=False,
@ -724,6 +731,7 @@ def build(
project_config (str): Project configuration file.
interface (bool): Generate interface report. Default=False.
core_dummy (bool): Generate core dummy code. Default=False.
rte_dummy (bool): Generate RTE dummy code. Default=False.
no_abort (bool): Do not abort due to errors. Default=False.
no_nvm_a2l (bool): Do not generate A2L for NVM structs. Default=False.
debug (bool): Activate the debug log. Default=False.
@ -921,9 +929,15 @@ def build(
LOG.info("Generating DID files")
zc_dids.generate_did_files()
LOG.info("******************************************************")
LOG.info("Start generating NVMDefinitions")
LOG.info("Generating NVM definitions")
zc_nvm.generate_nvm_rte_files()
if rte_dummy:
LOG.info("******************************************************")
LOG.info("Generating RTE dummy files")
zc_rte = RteDummy(build_cfg, zc_nvm)
zc_rte.generate_rte_dummy()
if code_generation_config["generateCalibrationInterfaceFiles"]:
LOG.info("******************************************************")
LOG.info("Generating calibration interface files")

@ -0,0 +1,132 @@
# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.
# -*- coding: utf-8 -*-
"""Module containing classes for generating RTE dummy code.
These files are needed for building test SW,
where the RTE is not available.
For example, when running Silver tests.
"""
from powertrain_build.problem_logger import ProblemLogger
from pathlib import Path
class RteDummy(ProblemLogger):
"""A class for RTE dummy file generation."""
def __init__(self, build_cfg, nvm_def):
"""Init.
Args:
build_cfg (BuildProjConfig): Object with build configuration settings.
nvm_def (ZCNVMDef): Object with NVM definition information.
"""
super().__init__()
self.build_cfg = build_cfg
self.nvm_def = nvm_def
self.header_file_name = "Rte_Type"
self.source_file_name = "Rte_Dummy"
nvm_port_pattern = self.build_cfg.get_composition_config("nvmPortPattern")
if nvm_port_pattern is None:
nvm_port_pattern = "{NvName}"
self.nvm_port_pattern = nvm_port_pattern
def _get_header_header(self):
"""Get header for the RTE dummy header."""
return (
"/*\n"
" * This file is generated by the Powertrain Build System.\n"
" * It defines RTE dummy types.\n"
" * Do not modify this file manually.\n"
" */\n"
f"#ifndef {self.header_file_name.upper()}_H\n"
f"#define {self.header_file_name.upper()}_H\n\n"
'#include "tl_basetypes.h"\n\n'
"#define FALSE 0U\n"
"#define TRUE 1U\n\n"
)
def _get_header_footer(self):
"""Get footer for the RTE dummy header."""
return f"\n#endif /* {self.header_file_name.upper()}_H */\n"
def _get_source_header(self):
"""Get header for the RTE dummy source."""
return (
"/*\n"
" * This file is generated by the Powertrain Build System.\n"
" * It defines RTE dummy functions.\n"
" * Do not modify this file manually.\n"
" */\n"
f'#include "{self.header_file_name}.h"\n\n'
)
def _get_nvm_header_dummy(self):
"""Get NVM dummy header code."""
struct_defines = []
function_declarations = []
prefix = self.build_cfg.get_scheduler_prefix()
for memory_area in self.nvm_def._nvm_memory_areas:
nvm_name = f"{prefix}{memory_area}"
function_prefix = f"Rte_Call_{self.nvm_port_pattern.format(NvName=nvm_name)}"
function_declarations.append(f"dt_{nvm_name} *Rte_Pim_{nvm_name}(void);")
function_declarations.append(f"void {function_prefix}_SetRamBlockStatus(UInt8 status);")
function_declarations.append(f"void {function_prefix}_GetErrorStatus(UInt8 *status);")
function_declarations.append(f"void {function_prefix}_WriteBlock(dt_{nvm_name} *block);")
if self.build_cfg.get_code_generation_config("useRteNvmStructs"):
struct_defines.append("typedef struct\n{")
memory_area_index = self.nvm_def._get_nvm_areas_index(memory_area)
nr_of_unused_signals = self.nvm_def.nvm_definitions[memory_area_index]["size"]
signals = self.nvm_def.nvm_definitions[memory_area_index]["signals"]
for signal in signals:
signal_string = ""
nr_of_unused_signals -= signal["x_size"] * signal["y_size"]
signal_string += f' {signal["type"]} {self.nvm_def.struct_member_prefix}{signal["name"]}'
size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
if size > 1:
if signal["x_size"] > 1:
signal_string += f'[{signal["x_size"]}]'
if signal["y_size"] > 1:
signal_string += f'[{signal["y_size"]}]'
signal_string += ";"
struct_defines.append(signal_string)
if nr_of_unused_signals > 0:
struct_defines.append(
f' {self.nvm_def.nvm_definitions[memory_area_index]["default_datatype"]} '
f'unused[{nr_of_unused_signals}];'
)
struct_defines.append(f"}} dt_{nvm_name};\n")
return "\n".join(struct_defines + function_declarations)
def _generate_nvm_source_dummy(self):
"""Generate NVM source dummy code."""
lines_to_write = []
prefix = self.build_cfg.get_scheduler_prefix()
for memory_area in self.nvm_def._nvm_memory_areas:
nvm_name = f"{prefix}{memory_area}"
function_prefix = f"Rte_Call_{self.nvm_port_pattern.format(NvName=nvm_name)}"
lines_to_write.append(f"dt_{nvm_name} *Rte_Pim_{nvm_name}(void) {{ return (dt_{nvm_name} *)0; }}")
lines_to_write.append(f"void {function_prefix}_SetRamBlockStatus(UInt8 status) {{}}")
lines_to_write.append(f"void {function_prefix}_GetErrorStatus(UInt8 *status) {{}}")
lines_to_write.append(f"void {function_prefix}_WriteBlock(dt_{nvm_name} *block) {{}}")
lines_to_write.append("")
return "\n".join(lines_to_write)
def generate_rte_dummy(self):
"""Generate RTE dummy files."""
src_code_dest_dir = self.build_cfg.get_src_code_dst_dir()
header_file = Path(src_code_dest_dir, self.header_file_name + ".h")
source_file = Path(src_code_dest_dir, self.source_file_name + ".c")
with header_file.open(mode="w", encoding="utf-8") as header_fh:
header_fh.write(self._get_header_header())
header_fh.write(self._get_nvm_header_dummy())
header_fh.write(self._get_header_footer())
with source_file.open(mode="w", encoding="utf-8") as source_fh:
source_fh.write(self._get_source_header())
source_fh.write(self._generate_nvm_source_dummy())

@ -56,6 +56,7 @@ class PyBuildWrapper(pt_matlab.Matlab):
self.project_config = self._set_project_configuration(args)
self.generate_system_info = getattr(args, "generate_system_info", False)
self.core_dummy = getattr(args, "core_dummy", True)
self.rte_dummy = getattr(args, "rte_dummy", False)
self.debug = getattr(args, "debug", True)
self.no_abort = getattr(args, "no_abort", True)
self.no_nvm_a2l = getattr(args, "no_nvm_a2l", False)
@ -374,6 +375,7 @@ class PyBuildWrapper(pt_matlab.Matlab):
self.project_config,
interface=self.interface,
core_dummy=self.core_dummy,
rte_dummy=self.rte_dummy,
no_abort=self.no_abort,
no_nvm_a2l=self.no_nvm_a2l,
debug=self.debug,

@ -0,0 +1,122 @@
# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.
"""Unit test script for powertrain_build.rte_dummy."""
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch, mock_open
from powertrain_build.rte_dummy import RteDummy
def mock_get_nvm_areas_index(memory_area):
"""Return the index of the given memory area."""
return {"NVM_LIST_8": 0, "NVM_LIST_16": 1}[memory_area]
class TestRteDummy(unittest.TestCase):
"""Class for testing powertrain_build.rte_dummy."""
def setUp(self):
"""Set-up mocks and common variables and data structures for all tests in the test case."""
self.build_cfg = MagicMock()
self.build_cfg.get_scheduler_prefix.return_value = "DUMMY_"
self.build_cfg.get_composition_config.return_value = "PS_DUMMY_SwcNv_{NvName}"
self.nvm_def = MagicMock()
self.nvm_def._get_nvm_areas_index.side_effect = mock_get_nvm_areas_index
self.nvm_def.struct_member_prefix = "e_"
self.nvm_def._nvm_memory_areas = ("NVM_LIST_8", "NVM_LIST_16")
self.nvm_def.nvm_definitions = [
{
"name": "NVM_LIST_8",
"allowed_datatypes": ["Bool", "UInt8", "Int8"],
"size": 2,
"instanceName": "nvm_list_8",
"default_datatype": "UInt8",
"includeStop": "",
"includeStart": "",
"persistent": False,
"signals": [
{"name": "dummy", "type": "UInt8", "x_size": 1, "y_size": 1}
]
},
{
"name": "NVM_LIST_16",
"allowed_datatypes": ["UInt16", "Int16"],
"size": 2,
"instanceName": "nvm_list_16",
"default_datatype": "UInt16",
"includeStop": "",
"includeStart": "",
"persistent": False,
"signals": [
{"name": "dummy2", "type": "UInt16", "x_size": 1, "y_size": 1}
]
}
]
self.rte_dummy = RteDummy(self.build_cfg, self.nvm_def)
def test_generate_rte_dummy(self):
"""Test RteDummy.generate_rte_dummy()."""
result = []
m_open = mock_open()
m_open.return_value.write = result.append
with patch.object(Path, "open", m_open, create=True):
self.rte_dummy.generate_rte_dummy()
expected = [
( # header header
"/*\n"
" * This file is generated by the Powertrain Build System.\n"
" * It defines RTE dummy types.\n"
" * Do not modify this file manually.\n"
" */\n"
"#ifndef RTE_TYPE_H\n"
"#define RTE_TYPE_H\n\n"
"#include \"tl_basetypes.h\"\n\n"
"#define FALSE 0U\n"
"#define TRUE 1U\n\n"
),
( # header content
"typedef struct\n"
"{\n"
" UInt8 e_dummy;\n"
" UInt8 unused[1];\n"
"} dt_DUMMY_NVM_LIST_8;\n\n"
"typedef struct\n"
"{\n"
" UInt16 e_dummy2;\n"
" UInt16 unused[1];\n"
"} dt_DUMMY_NVM_LIST_16;\n\n"
"dt_DUMMY_NVM_LIST_8 *Rte_Pim_DUMMY_NVM_LIST_8(void);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_SetRamBlockStatus(UInt8 status);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_GetErrorStatus(UInt8 *status);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_WriteBlock(dt_DUMMY_NVM_LIST_8 *block);\n"
"dt_DUMMY_NVM_LIST_16 *Rte_Pim_DUMMY_NVM_LIST_16(void);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_SetRamBlockStatus(UInt8 status);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_GetErrorStatus(UInt8 *status);\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_WriteBlock(dt_DUMMY_NVM_LIST_16 *block);"
),
( # header footer
"\n#endif /* RTE_TYPE_H */\n"
),
( # source header
"/*\n"
" * This file is generated by the Powertrain Build System.\n"
" * It defines RTE dummy functions.\n"
" * Do not modify this file manually.\n"
" */\n"
"#include \"Rte_Type.h\"\n\n"
),
( # source content
"dt_DUMMY_NVM_LIST_8 *Rte_Pim_DUMMY_NVM_LIST_8(void) { return (dt_DUMMY_NVM_LIST_8 *)0; }\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_SetRamBlockStatus(UInt8 status) {}\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_GetErrorStatus(UInt8 *status) {}\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_8_WriteBlock(dt_DUMMY_NVM_LIST_8 *block) {}\n"
"dt_DUMMY_NVM_LIST_16 *Rte_Pim_DUMMY_NVM_LIST_16(void) { return (dt_DUMMY_NVM_LIST_16 *)0; }\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_SetRamBlockStatus(UInt8 status) {}\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_GetErrorStatus(UInt8 *status) {}\n"
"void Rte_Call_PS_DUMMY_SwcNv_DUMMY_NVM_LIST_16_WriteBlock(dt_DUMMY_NVM_LIST_16 *block) {}\n"
)
]
self.assertListEqual(result, expected)