Don't generate VcDebug files if there are no variables

Change-Id: I57c0d04ecaa08164e4654409ed40cfd01b63faef
This commit is contained in:
Henrik Wahlqvist
2025-07-07 16:03:35 +02:00
parent 2043d25e66
commit 05cd4a2b81
16 changed files with 980 additions and 423 deletions

864
NOTICE

File diff suppressed because it is too large Load Diff

View File

@@ -283,7 +283,7 @@ def generate_core_dummy(build_cfg, core, unit_cfg):
LOG.info("Finished generating Core Dummy (in %4.2f s)", time.time() - start_time)
def generate_ext_var(build_cfg, unit_cfg, signal_if, udt, asil_level_db, asil_level_dep, debug_code=True):
def generate_external_var(build_cfg, unit_cfg, udt, asil_level_dep, nrm_dict, dep_dict, sec_dict):
"""Generate two c-files that define the signal interface to the supplier.
The VcExtVar function assigns all variables to the CVC_DISP memory area,
@@ -296,28 +296,13 @@ def generate_ext_var(build_cfg, unit_cfg, signal_if, udt, asil_level_db, asil_le
Args:
build_cfg (BuildProjConfig): Build project class holding where files should be stored.
signal_if (SignalInterfaces): class holding signal interface information.
unit_cfg (UnitConfigs) : Aggregated unit configs class.
udt (UserDefinedTypes): Class holding user defined data types.
asil_level_db (str): ASIL level for debug variables.
asil_level_dep (str): ASIL level for dependability variables.
debug_code (boolean): If true, generate debug code.
asil_level_dep (str): ASIL level for the dependability variables.
nrm_dict (dict): Dictionary with normal variables.
dep_dict (dict): Dictionary with dependability variables.
sec_dict (dict): Dictionary with secure variables.
"""
LOG.info("******************************************************")
LOG.info("Start generating VcExtVar and VcDebug")
start_time = time.time()
nrm_dict, dep_dict, sec_dict, dbg_dict = signal_if.get_external_io()
_extract_external_var(build_cfg, unit_cfg, udt, asil_level_dep, nrm_dict, dep_dict, sec_dict)
if debug_code:
_extract_debug(build_cfg, unit_cfg, asil_level_db, dep_dict, dbg_dict)
LOG.info(
"Finished generating VcExtVar and VcDebug (in %4.2f s)",
time.time() - start_time,
)
def _extract_external_var(
build_cfg, unit_cfg, udt, asil_level_dep, nrm_dict, dep_dict, sec_dict
):
if build_cfg.has_yaml_interface:
ext_var_nrm = ExtVarYaml(nrm_dict, build_cfg, unit_cfg, udt)
ext_var_dep = ExtVarYaml(dep_dict, build_cfg, unit_cfg, udt, asil_level_dep)
@@ -339,19 +324,6 @@ def _extract_external_var(
instance.generate_files(ext_var_path)
def _extract_debug(build_cfg, unit_cfg, asil_level_db, dep_dict, dbg_dict):
dbg_instances = {
ExtDbg(dbg_dict, build_cfg, unit_cfg): ("VcDebug", "VcDebugOutput"),
ExtDbg(dep_dict, build_cfg, unit_cfg, asil_level_db): ("VcDebugSafe", "VcDebugOutputSafe")
}
for instance, dir_names in dbg_instances.items():
instance.gen_dbg_files(
pjoin(build_cfg.get_src_code_dst_dir(), dir_names[0]),
pjoin(build_cfg.get_src_code_dst_dir(), dir_names[1]),
)
def generate_dummy_var(build_cfg, unit_cfg, signal_if, udt):
"""Generate c-file that define the missing signals.
@@ -806,14 +778,30 @@ def build(
if interface:
interface_report(build_cfg, unit_cfg, signal_if)
generate_ext_var(
build_cfg,
unit_cfg,
signal_if,
udt,
build_defs.CVC_ASIL_LEVEL_MAP[code_generation_config["generalAsilLevelDebug"]],
build_defs.ASIL_LEVEL_MAP[code_generation_config["generalAsilLevelDependability"]]
)
LOG.info("******************************************************")
LOG.info("Start generating VcExtVar and VcDebug")
start_time = time.time()
asil_level_db = build_defs.CVC_ASIL_LEVEL_MAP[code_generation_config["generalAsilLevelDebug"]]
asil_level_dep = build_defs.ASIL_LEVEL_MAP[code_generation_config["generalAsilLevelDependability"]]
nrm_dict, dep_dict, sec_dict, dbg_dict = signal_if.get_external_io()
generate_external_var(build_cfg, unit_cfg, udt, asil_level_dep, nrm_dict, dep_dict, sec_dict)
restructured_dbg_dict = {}
dbg_instances = {
ExtDbg(dbg_dict, build_cfg, unit_cfg): ("VcDebug", "VcDebugOutput"),
ExtDbg(dep_dict, build_cfg, unit_cfg, asil_level_db): ("VcDebugSafe", "VcDebugOutputSafe")
}
for instance, dir_names in dbg_instances.items():
restructured_dbg_dict.update({
dir_names[0]: instance.dbg_dict["inputs"],
dir_names[1]: instance.dbg_dict["outputs"]
})
instance.gen_dbg_files(
pjoin(build_cfg.get_src_code_dst_dir(), dir_names[0]),
pjoin(build_cfg.get_src_code_dst_dir(), dir_names[1])
)
LOG.info("Finished generating VcExtVar and VcDebug (in %4.2f s)", time.time() - start_time)
if not code_generation_config["generateDummyVar"]:
LOG.info("******************************************************")
@@ -848,19 +836,15 @@ def build(
LOG.info("******************************************************")
LOG.info("Start generating the scheduling functions")
start_time = time.time()
gen_schd = SchedFuncs(build_cfg, unit_cfg)
gen_schd = SchedFuncs(build_cfg, unit_cfg, restructured_dbg_dict)
gen_schd.generate_sched_c_fncs(generate_rte_checkpoint_calls)
LOG.info(
"Finished generating the scheduling functions (in %4.2f s)",
time.time() - start_time,
)
LOG.info("Finished generating the scheduling functions (in %4.2f s)", time.time() - start_time)
LOG.info("******************************************************")
LOG.info("Start generating the ts header file")
start_time = time.time()
gen_schd.generate_ts_defines(pjoin(src_dst_dir, build_cfg.get_ts_header_name()))
LOG.info(
"Finished generating ts header file (in %4.2f s)", time.time() - start_time
)
LOG.info("Finished generating ts header file (in %4.2f s)", time.time() - start_time)
# Generate AllSystemInfo.mat for DocGen compatibility
if generate_system_info:

View File

@@ -65,11 +65,27 @@ class ExtDbg(ProblemLogger):
"""
super().__init__()
self.set_integrity_level(integrity_level)
self._var_dict = variable_dict
self.__restructured_data = self._restruct_data()
self._prj_cfg = prj_cfg
self._unit_cfg = unit_cfg
self.use_volatile_globals = prj_cfg.get_use_volatile_globals()
self._use_volatile_globals = prj_cfg.get_use_volatile_globals()
self.dbg_dict = self._restruct_data(variable_dict)
@staticmethod
def _restruct_data(variable_dict):
"""Restructure input variables per data-type.
This will be used for declaring the variables and generating the A2L-file.
"""
data = {'outputs': {}, 'inputs': {}}
for inp in variable_dict.keys():
if re.match(r'.*Output$', inp) is not None:
iotype = 'outputs'
else:
iotype = 'inputs'
for var, var_data in variable_dict[inp].items():
data_type_size = byte_size_string(var_data['type'])
data[iotype].setdefault(data_type_size, {})[var] = var_data
return data
def set_integrity_level(self, integrity_level):
"""Set integrity level of code generation.
@@ -84,22 +100,6 @@ class ExtDbg(ProblemLogger):
self._code_start = integrity_level['CODE']['START']
self._code_end = integrity_level['CODE']['END']
def _restruct_data(self):
"""Restructure input variables per data-type.
This will be used for declaring the variables and generating the A2L-file.
"""
data = {'outputs': {}, 'inputs': {}}
for inp in self._var_dict.keys():
if re.match(r'.*Output$', inp) is not None:
iotype = 'outputs'
else:
iotype = 'inputs'
for var, var_data in self._var_dict[inp].items():
data_type_size = byte_size_string(var_data['type'])
data[iotype].setdefault(data_type_size, {})[var] = var_data
return data
def _a2l_dict(self, var_dict, function):
"""Generate dict defining parameters for a2l-generation."""
def _range(data):
@@ -197,7 +197,7 @@ class ExtDbg(ProblemLogger):
fh_c.write('\n/* Debug values */\n\n')
for var, var_data in self._type_order_iterator(data):
initial_value = var_data['min'] if var_data['min'] != "-" and float(var_data['min']) > 0 else "0"
if self.use_volatile_globals:
if self._use_volatile_globals:
fh_c.write(f"volatile {var_data['type']} c{var[1:]}_db = {initial_value};\n")
else:
fh_c.write(f"{var_data['type']} c{var[1:]}_db = {initial_value};\n")
@@ -205,7 +205,7 @@ class ExtDbg(ProblemLogger):
fh_c.write('\n/* Debug switches */\n\n')
for var, var_data in self._type_order_iterator(data):
sw_name = self._var_name_to_dbgsw_name(var)
if self.use_volatile_globals:
if self._use_volatile_globals:
fh_c.write(f"volatile Bool {sw_name} = 0;\n")
else:
fh_c.write(f"Bool {sw_name} = 0;\n")
@@ -226,24 +226,30 @@ class ExtDbg(ProblemLogger):
fh_c.write(f'}}\n#include "{self._code_end}"\n\n')
self.info('Generated %s', filename)
def gen_dbg_files(self, fname_in, fname_out):
def gen_dbg_files(self, file_path_inputs, file_path_outputs):
"""Generate the c-files and A2L-files.
These declares all the supplier interface debug parameters and functions.
Args:
file_path_inputs (str): path to the debug inputs c-file.
file_path_outputs (str): path to the debug outputs c-file.
"""
# c-files
self._gen_dbg_c_file(self.__restructured_data['inputs'],
fname_in + '.c')
self._gen_dbg_c_file(self.__restructured_data['outputs'],
fname_out + '.c')
# A2L-files
_, fname_tmp = os.path.split(fname_in)
a2l_dict_in = self._a2l_dict(self.__restructured_data['inputs'],
fname_tmp)
_, fname_tmp = os.path.split(fname_out)
a2l_dict_out = self._a2l_dict(self.__restructured_data['outputs'],
fname_tmp)
a2l = A2l(a2l_dict_in, self._prj_cfg)
a2l.gen_a2l(fname_in + '.a2l')
a2l = A2l(a2l_dict_out, self._prj_cfg)
a2l.gen_a2l(fname_out + '.a2l')
_, file_name_inputs = os.path.split(file_path_inputs)
_, file_name_outputs = os.path.split(file_path_outputs)
if not self.dbg_dict['inputs']:
self.info(f"Skipping {file_name_inputs} as there were no corresponding vars.")
else:
self._gen_dbg_c_file(self.dbg_dict['inputs'], file_path_inputs + '.c')
a2l_dict_in = self._a2l_dict(self.dbg_dict['inputs'], file_name_inputs)
a2l = A2l(a2l_dict_in, self._prj_cfg)
a2l.gen_a2l(file_path_inputs + '.a2l')
if not self.dbg_dict['outputs']:
self.info(f"Skipping {file_name_outputs} as there were no corresponding vars.")
else:
self._gen_dbg_c_file(self.dbg_dict['outputs'], file_path_outputs + '.c')
a2l_dict_out = self._a2l_dict(self.dbg_dict['outputs'], file_name_outputs)
a2l = A2l(a2l_dict_out, self._prj_cfg)
a2l.gen_a2l(file_path_outputs + '.a2l')

View File

@@ -26,18 +26,20 @@ class SchedFuncs(ProblemLogger):
# Not included in VcExtINI.c and VcUnitTsDefines.h.
RESTART_FNC_EXCLUDE = ('VcDebug', 'VcDebugOutput', 'VcDebugSafe', 'VcDebugOutputSafe')
def __init__(self, build_proj_cfg, unit_cfg):
def __init__(self, build_proj_cfg, unit_cfg, dbg_dict):
"""Constructor.
Args:
build_proj_cfg (BuildProjConfig): project configuration.
unit_cfg (UnitConfigs): Class holding all unit interfaces.
dbg_dict (dict): Dictionary containing debug information, keys in RESTART_FNC_EXCLUDE.
"""
super().__init__()
if isinstance(build_proj_cfg, BuildProjConfig) and isinstance(unit_cfg, UnitConfigs):
self._prj_cfg = build_proj_cfg
self._unit_cfg = unit_cfg
self._dbg_dict = dbg_dict
else:
err = (
'Input arguments should be an instance of:'
@@ -108,23 +110,29 @@ class SchedFuncs(ProblemLogger):
unit_name = unit.rsplit('__', 1)[0]
if code_generator == 'embedded_coder':
ext_def_str += f'extern void {unit_name}_step(void);\n'
call_str += f' {unit_name}_step();\n'
if unit_name not in SchedFuncs.RESTART_FNC_EXCLUDE:
init_ext_def_s += f'extern void {unit_name}_initialize(void);\n'
init_call_s += f' {unit_name}_initialize();\n'
ext_def_str += f'extern void {unit_name}_step(void);\n'
call_str += f' {unit_name}_step();\n'
elif self._dbg_dict[unit_name]:
ext_def_str += f'extern void {unit_name}_step(void);\n'
call_str += f' {unit_name}_step();\n'
else:
ext_def_str += f'extern void {unit_name}(void);\n'
if generate_rte_checkpoint_calls:
call_str += (
f' Rte_Call_{function_name}_'
f'{function_name}LogicalCheckpointReached_CddPFMC_ASILD_'
f'{function_name}_LogicalCheckpointReached(ID_{unit_name});\n'
)
call_str += f' {unit_name}();\n'
if unit_name not in SchedFuncs.RESTART_FNC_EXCLUDE:
init_ext_def_s += f'extern void RESTART_{unit_name}(void);\n'
init_call_s += f' RESTART_{unit_name}();\n'
ext_def_str += f'extern void {unit_name}(void);\n'
call_str += f' {unit_name}();\n'
elif self._dbg_dict[unit_name]:
ext_def_str += f'extern void {unit_name}(void);\n'
call_str += f' {unit_name}();\n'
ext_def_str += '\n'
call_str += '}\n'
call_str += f'#include "{build_defs.CVC_CODE_END}"\n\n'

View File

@@ -0,0 +1,47 @@
/begin CHARACTERISTIC
cVcAc_D_EngRunReqClim_db /* Name */
"Engine running request (inhibit stop) from climate" /* LongIdentifier */
VALUE /* Datatype */
0x00000000 /* address: cVcAc_D_EngRunReqClim_db */
UBYTE_COL_DIRECT /* Deposit */
0 /* MaxDiff */
VcDebug_1_0_0_ /* Conversion */
0 /* LowerLimit */
3 /* UpperLimit */
/end CHARACTERISTIC
/begin CHARACTERISTIC
cVcAc_D_EngRunReqClim_sw /* Name */
"debug switch for cVcAc_D_EngRunReqClim_db (1=bdsw act)" /* LongIdentifier */
VALUE /* Datatype */
0x00000000 /* address: cVcAc_D_EngRunReqClim_sw */
UBYTE_COL_DIRECT /* Deposit */
0 /* MaxDiff */
VcDebug_1_0_0_ /* Conversion */
0 /* LowerLimit */
1 /* UpperLimit */
/end CHARACTERISTIC
/begin COMPU_METHOD
VcDebug_1_0_0_ /* Name */
"" /* LongIdentifier */
RAT_FUNC /* ConversionType */
"%11.3" /* Format */
"" /* Unit */
COEFFS 0 1 0.0 0 0 1
/end COMPU_METHOD
/begin FUNCTION
VcDebug /* Name */
"" /* LongIdentifier */
/begin DEF_CHARACTERISTIC
cVcAc_D_EngRunReqClim_db /* Identifier */
cVcAc_D_EngRunReqClim_sw /* Identifier */
/end DEF_CHARACTERISTIC
/end FUNCTION
/begin RECORD_LAYOUT
UBYTE_COL_DIRECT /* Name */
FNC_VALUES 1 UBYTE COLUMN_DIR DIRECT
/end RECORD_LAYOUT

View File

@@ -0,0 +1,29 @@
#include "tl_base_types.h"
#define CVC_DISP
#include "CVC_DISP_START.h"
extern CVC_DISP UInt8 sVcAc_D_EngRunReqClim;
#include "CVC_DISP_END.h"
#include "CVC_CAL_START.h"
/* Debug values */
volatile UInt8 cVcAc_D_EngRunReqClim_db = 0;
/* Debug switches */
volatile Bool cVcAc_D_EngRunReqClim_sw = 0;
#include "CVC_CAL_END.h"
/***********************/
/* debug functionality */
/***********************/
#include "CVC_CODE_START.h"
void VcDebug(void) {
if (cVcAc_D_EngRunReqClim_sw) {
sVcAc_D_EngRunReqClim = cVcAc_D_EngRunReqClim_db;
}
}
#include "CVC_CODE_END.h"

View File

@@ -0,0 +1,47 @@
/begin CHARACTERISTIC
cVcAc_D_AirCondCmpsrStats_db /* Name */
"Aircond compressor status" /* LongIdentifier */
VALUE /* Datatype */
0x00000000 /* address: cVcAc_D_AirCondCmpsrStats_db */
UBYTE_COL_DIRECT /* Deposit */
0 /* MaxDiff */
VcDebugOutput_1_0_0_ /* Conversion */
0 /* LowerLimit */
7 /* UpperLimit */
/end CHARACTERISTIC
/begin CHARACTERISTIC
cVcAc_D_AirCondCmpsrStats_sw /* Name */
"debug switch for cVcAc_D_AirCondCmpsrStats_db (1=bdsw act)" /* LongIdentifier */
VALUE /* Datatype */
0x00000000 /* address: cVcAc_D_AirCondCmpsrStats_sw */
UBYTE_COL_DIRECT /* Deposit */
0 /* MaxDiff */
VcDebugOutput_1_0_0_ /* Conversion */
0 /* LowerLimit */
1 /* UpperLimit */
/end CHARACTERISTIC
/begin COMPU_METHOD
VcDebugOutput_1_0_0_ /* Name */
"" /* LongIdentifier */
RAT_FUNC /* ConversionType */
"%11.3" /* Format */
"" /* Unit */
COEFFS 0 1 0.0 0 0 1
/end COMPU_METHOD
/begin FUNCTION
VcDebugOutput /* Name */
"" /* LongIdentifier */
/begin DEF_CHARACTERISTIC
cVcAc_D_AirCondCmpsrStats_db /* Identifier */
cVcAc_D_AirCondCmpsrStats_sw /* Identifier */
/end DEF_CHARACTERISTIC
/end FUNCTION
/begin RECORD_LAYOUT
UBYTE_COL_DIRECT /* Name */
FNC_VALUES 1 UBYTE COLUMN_DIR DIRECT
/end RECORD_LAYOUT

View File

@@ -0,0 +1,29 @@
#include "tl_base_types.h"
#define CVC_DISP
#include "CVC_DISP_START.h"
extern CVC_DISP UInt8 sVcAc_D_AirCondCmpsrStats;
#include "CVC_DISP_END.h"
#include "CVC_CAL_START.h"
/* Debug values */
volatile UInt8 cVcAc_D_AirCondCmpsrStats_db = 0;
/* Debug switches */
volatile Bool cVcAc_D_AirCondCmpsrStats_sw = 0;
#include "CVC_CAL_END.h"
/***********************/
/* debug functionality */
/***********************/
#include "CVC_CODE_START.h"
void VcDebugOutput(void) {
if (cVcAc_D_AirCondCmpsrStats_sw) {
sVcAc_D_AirCondCmpsrStats = cVcAc_D_AirCondCmpsrStats_db;
}
}
#include "CVC_CODE_END.h"

View File

@@ -0,0 +1,11 @@
#include "Rte_Type.h"
extern void VcModelName(void);
#include "CVC_CODE_START.h"
void PROJ_VcDummyRaster(void)
{
VcModelName();
}
#include "CVC_CODE_END.h"

View File

@@ -0,0 +1,6 @@
#ifndef VCDUMMYRASTER_H
#define VCDUMMYRASTER_H
void PROJ_VcDummyRaster(void);
#endif //VCDUMMYRASTER_H

View File

@@ -1,8 +1,10 @@
extern void RESTART_VcModelName(void);
#include "CVC_CODE_START.h"
void PROJ_VcExtINI(void)
{
RESTART_VcModelName();
}
#include "CVC_CODE_END.h"

View File

@@ -0,0 +1,4 @@
#ifndef VCEXTINI_H
#define VCEXTINI_H
void PROJ_VcExtINI(void);
#endif

View File

@@ -1,4 +1,8 @@
/* Autogenerated by build system */
#ifndef TS_TEST_H
#define TS_TEST_H
/**** raster VcDummyRaster *****/
#define ts_VcModelName ((Float32) 0.01F)
#endif /* TS_TEST_H */

View File

@@ -154,14 +154,13 @@ class TestBuild(unittest.TestCase):
core.get_current_core_config = MagicMock()
self.assertRaises(ValueError, build.generate_core_dummy, self.build_cfg, core, self.unit_cfg)
def test_generate_ext_var(self):
def test_generate_external_var(self):
"""Check that ExtVar files are generated."""
self.build_cfg.has_yaml_interface = False
signal_if = MagicMock(spec_set=CsvSignalInterfaces)
signal_if.get_external_io = MagicMock(return_value=(
{
'EMS-Output': {},
'EMS-Input': {'DummyIn': {
nrm_dict = {
'EMS-Output': {},
'EMS-Input': {
'DummyIn': {
'type': 'Float32',
'min': 0,
'max': 100,
@@ -170,16 +169,19 @@ class TestBuild(unittest.TestCase):
'init': 0,
'element_index': 5,
'IOType': 'x'
}},
'LIN-Output': {},
'LIN-Input': {},
'CAN-Output': {},
'CAN-Input': {},
'Private CAN-Output': {},
'Private CAN-Input': {}
}, {
'EMS-Output': {},
'EMS-Input': {'DummyInSafe': {
}
},
'LIN-Output': {},
'LIN-Input': {},
'CAN-Output': {},
'CAN-Input': {},
'Private CAN-Output': {},
'Private CAN-Input': {}
}
dep_dict = {
'EMS-Output': {},
'EMS-Input': {
'DummyInSafe': {
'type': 'Float32',
'min': 0,
'max': 100,
@@ -188,32 +190,29 @@ class TestBuild(unittest.TestCase):
'init': 0,
'element_index': 5,
'IOType': 's'
}},
'LIN-Output': {},
'LIN-Input': {},
'CAN-Output': {},
'CAN-Input': {},
'Private CAN-Output': {},
'Private CAN-Input': {}
}, {}, {}
))
}
},
'LIN-Output': {},
'LIN-Input': {},
'CAN-Output': {},
'CAN-Input': {},
'Private CAN-Output': {},
'Private CAN-Input': {}
}
sec_dict = {}
filepath = str(Path(SRC_DIR, 'output'))
files = [
filepath + '/VcExtVar.c',
filepath + '/VcExtVar.a2l',
filepath + '/VcExtVarSafe.c',
filepath + '/VcExtVarSafe.a2l',
filepath + '/VcDebug.c',
filepath + '/VcDebug.a2l',
filepath + '/VcDebugOutput.c',
filepath + '/VcDebugOutput.a2l']
filepath + '/VcExtVarSafe.a2l'
]
remove(*files)
with patch('powertrain_build.user_defined_types.UserDefinedTypes') as udt_mock:
udt_mock.return_value.common_header_files = PropertyMock(return_value=[])
build.generate_ext_var(
self.build_cfg, self.unit_cfg, signal_if, udt_mock, build_defs.CVC_ASIL_B, build_defs.ASIL_B
build.generate_external_var(
self.build_cfg, self.unit_cfg, udt_mock, build_defs.ASIL_B, nrm_dict, dep_dict, sec_dict
)
signal_if.get_external_io.assert_called_once()
self.build_cfg.get_src_code_dst_dir.assert_called()
exists(*files)
self.assertFalse(os.path.isfile(f"{filepath}/VcExtVarSecure.c"))

View File

@@ -5,11 +5,13 @@
import unittest
from unittest.mock import MagicMock
from pathlib import Path
from powertrain_build.ext_dbg import ExtDbg
from powertrain_build.build_proj_config import BuildProjConfig
from powertrain_build.unit_configs import UnitConfigs
from .io_cnfg import DBG_CNFG_DICT
SRC_DIR = Path(__file__).parent
class TestExtDbg(unittest.TestCase):
"""Test case for testing the ExtDbg class."""
@@ -17,13 +19,27 @@ class TestExtDbg(unittest.TestCase):
def setUp(self):
"""Set-up common data structures for all tests in the test case."""
self.build_cfg = MagicMock(spec_set=BuildProjConfig)
self.unit_cfg = MagicMock(spec_set=UnitConfigs)
self.build_cfg.get_ecu_info = MagicMock(return_value=('Denso', 'G2'))
self.unit_cfg = MagicMock()
self.unit_cfg.base_types_headers = '#include "tl_base_types.h"\n'
self.ext_dbg = ExtDbg(DBG_CNFG_DICT['VED4_GENIII'], self.build_cfg, self.unit_cfg)
prj_out_dir = Path(SRC_DIR, 'output')
self.file_path_inputs = Path(prj_out_dir, 'VcDebug')
self.file_path_outputs = Path(prj_out_dir, 'VcDebugOutput')
self.generated_debug_files = [
self.file_path_inputs.with_suffix('.c'),
self.file_path_inputs.with_suffix('.a2l'),
self.file_path_outputs.with_suffix('.c'),
self.file_path_outputs.with_suffix('.a2l')
]
for file_path in self.generated_debug_files:
if file_path.exists():
file_path.unlink()
def test_restruct_data(self):
"""Check restructuring of variable dict."""
result = self.ext_dbg._restruct_data()
expected = {
'inputs': {
'1': {
@@ -54,4 +70,23 @@ class TestExtDbg(unittest.TestCase):
}
}
}
self.assertDictEqual(result, expected)
self.assertDictEqual(self.ext_dbg.dbg_dict, expected)
def test_gen_dbg_files(self):
"""Check generation of debug files."""
self.ext_dbg.gen_dbg_files(self.file_path_inputs.as_posix(), self.file_path_outputs.as_posix())
for file_path in self.generated_debug_files:
self.assertTrue(file_path.exists(), f'File {file_path} was not created.')
with file_path.open(mode='r', encoding='utf-8') as file_handle:
result = file_handle.read()
with Path(SRC_DIR, 'reference_files', file_path.name).open(mode='r', encoding='utf-8') as file_handle:
expected = file_handle.read()
self.assertEqual(result, expected, f'Content of {file_path} does not match expected content.')
def test_gen_dbg_files_no_debug_variables(self):
"""Check generation of debug files, without any debug variables."""
self.ext_dbg.dbg_dict = {'inputs': {}, 'outputs': {}}
self.ext_dbg.gen_dbg_files(self.file_path_inputs.as_posix(), self.file_path_outputs.as_posix())
for file_path in self.generated_debug_files:
self.assertFalse(file_path.exists(), f'File {file_path} was created.')

View File

@@ -5,8 +5,6 @@
import unittest
from unittest.mock import MagicMock
from os.path import exists
from os import remove
from pathlib import Path
from powertrain_build.build_proj_config import BuildProjConfig
from powertrain_build.sched_funcs import SchedFuncs
@@ -27,18 +25,34 @@ class TestSchedFuncs(unittest.TestCase):
self.build_cfg.get_src_code_dst_dir = MagicMock(return_value=str(prj_out_dir))
self.build_cfg.get_prj_config = MagicMock(return_value='CFG1')
self.build_cfg.get_scheduler_prefix = MagicMock(return_value='PROJ_')
self.build_cfg.get_units_raster_cfg = MagicMock(
return_value={
'SampleTimes': {
'VcDummyRaster': 0.01
},
'Rasters': {
'VcDummyRaster': ['VcDebug', 'VcModelName']
}
}
)
self.unit_cfg = MagicMock(spec_set=UnitConfigs)
self.init_file = str(Path(prj_out_dir, 'VcExtINI.c'))
if exists(self.init_file):
remove(self.init_file)
self.ts_file = Path(prj_out_dir, 'ts_test.h')
self.generated_sched_files = [
Path(prj_out_dir, 'VcExtINI.h'),
Path(prj_out_dir, 'VcExtINI.c'),
Path(prj_out_dir, 'VcDummyRaster.c'),
Path(prj_out_dir, 'VcDummyRaster.h')
]
self.ts_file = str(Path(prj_out_dir, 'ts_test.h'))
if exists(self.ts_file):
remove(self.ts_file)
for file_path in self.generated_sched_files + [self.ts_file]:
if file_path.exists():
file_path.unlink()
self.sched_funcs = SchedFuncs(self.build_cfg, self.unit_cfg)
self.dbg_dict = {d: {} for d in SchedFuncs.RESTART_FNC_EXCLUDE}
self.sched_funcs = SchedFuncs(self.build_cfg, self.unit_cfg, self.dbg_dict)
def test_init_failure(self):
"""Check class init."""
@@ -47,23 +61,39 @@ class TestSchedFuncs(unittest.TestCase):
'Input arguments should be an instance of:'
f'BuildProjConfig, not {type(None)}'
f'AND/OR UnitConfigs, not {type(None)}',
SchedFuncs, None, None
SchedFuncs, None, None, {}
)
def test_generate_sched_c_fncs(self):
"""Check generated scheduling raster functions."""
self.sched_funcs.generate_sched_c_fncs(False)
with open(self.init_file, encoding="utf-8") as fhandle:
result = fhandle.read()
with Path(SRC_DIR, 'reference_files', 'VcExtINI.c').open(encoding="utf-8") as fhandle:
expected = fhandle.read()
self.assertEqual(result, expected)
for file_path in self.generated_sched_files:
self.assertTrue(file_path.exists(), f'File {file_path} was not created.')
with file_path.open(mode='r', encoding='utf-8') as file_handle:
result = file_handle.read()
with Path(SRC_DIR, 'reference_files', file_path.name).open(mode='r', encoding='utf-8') as file_handle:
expected = file_handle.read()
self.assertEqual(result, expected, f'Content of {file_path} does not match expected content.')
def test_generate_sched_c_fncs_with_debug(self):
"""Check generated scheduling raster functions, including debug dict."""
self.dbg_dict['VcDebug'].update({'VcModelname': {'dummy_data': 'test'}})
self.sched_funcs = SchedFuncs(self.build_cfg, self.unit_cfg, self.dbg_dict)
self.sched_funcs.generate_sched_c_fncs(False)
for file_path in self.generated_sched_files:
self.assertTrue(file_path.exists(), f'File {file_path} was not created.')
with file_path.open(mode='r', encoding='utf-8') as file_handle:
result = file_handle.read()
if file_path.name == 'VcDummyRaster.c':
self.assertIn('VcDebug', result, f'VcDebug should be in {file_path}.')
else:
self.assertNotIn('VcDebug', result, f'VcDebug should not be in {file_path}.')
def test_generate_ts_defines(self):
"""Check the ts defines generated for all units."""
self.sched_funcs.generate_ts_defines(self.ts_file)
with open(self.ts_file, encoding="utf-8") as fhandle:
result = fhandle.read()
with Path(SRC_DIR, 'reference_files', 'ts_test.h').open(encoding="utf-8") as fhandle:
expected = fhandle.read()
with self.ts_file.open(mode='r', encoding='utf-8') as file_handle:
result = file_handle.read()
with Path(SRC_DIR, 'reference_files', 'ts_test.h').open(encoding='utf-8') as file_handle:
expected = file_handle.read()
self.assertEqual(result, expected)