powertrain-build 1.13.1__py3-none-any.whl → 1.13.3.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- powertrain_build/__init__.py +40 -40
- powertrain_build/__main__.py +6 -6
- powertrain_build/a2l.py +582 -582
- powertrain_build/a2l_merge.py +650 -650
- powertrain_build/a2l_templates.py +717 -717
- powertrain_build/build.py +985 -985
- powertrain_build/build_defs.py +309 -309
- powertrain_build/build_proj_config.py +690 -690
- powertrain_build/check_interface.py +575 -575
- powertrain_build/cli.py +141 -141
- powertrain_build/config.py +542 -542
- powertrain_build/core.py +395 -395
- powertrain_build/core_dummy.py +343 -343
- powertrain_build/create_conversion_table.py +73 -73
- powertrain_build/dids.py +916 -916
- powertrain_build/dummy.py +157 -157
- powertrain_build/dummy_spm.py +252 -252
- powertrain_build/environmentcheck.py +52 -52
- powertrain_build/ext_dbg.py +255 -255
- powertrain_build/ext_var.py +327 -327
- powertrain_build/feature_configs.py +301 -301
- powertrain_build/gen_allsysteminfo.py +227 -227
- powertrain_build/gen_label_split.py +449 -449
- powertrain_build/handcode_replacer.py +124 -124
- powertrain_build/html_report.py +133 -133
- powertrain_build/interface/__init__.py +4 -4
- powertrain_build/interface/application.py +511 -511
- powertrain_build/interface/base.py +500 -500
- powertrain_build/interface/csp_api.py +490 -490
- powertrain_build/interface/device_proxy.py +677 -677
- powertrain_build/interface/ems.py +67 -67
- powertrain_build/interface/export_global_vars.py +121 -121
- powertrain_build/interface/generate_adapters.py +132 -132
- powertrain_build/interface/generate_hi_interface.py +87 -87
- powertrain_build/interface/generate_service.py +69 -69
- powertrain_build/interface/generate_wrappers.py +147 -147
- powertrain_build/interface/generation_utils.py +142 -142
- powertrain_build/interface/hal.py +194 -194
- powertrain_build/interface/model_yaml_verification.py +348 -348
- powertrain_build/interface/service.py +296 -296
- powertrain_build/interface/simulink.py +249 -249
- powertrain_build/interface/update_call_sources.py +180 -180
- powertrain_build/interface/update_model_yaml.py +186 -186
- powertrain_build/interface/zone_controller.py +362 -362
- powertrain_build/lib/__init__.py +4 -4
- powertrain_build/lib/helper_functions.py +127 -127
- powertrain_build/lib/logger.py +55 -55
- powertrain_build/matlab_scripts/CodeGen/BuildAutomationPyBuild.m +78 -78
- powertrain_build/matlab_scripts/CodeGen/Generate_A2L.m +154 -154
- powertrain_build/matlab_scripts/CodeGen/generateTLUnit.m +239 -239
- powertrain_build/matlab_scripts/CodeGen/getAsilClassification.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/modelConfiguredForTL.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/moveDefOutports.m +88 -88
- powertrain_build/matlab_scripts/CodeGen/parseCalMeasData.m +410 -410
- powertrain_build/matlab_scripts/CodeGen/parseCoreIdentifiers.m +139 -139
- powertrain_build/matlab_scripts/CodeGen/parseDIDs.m +141 -141
- powertrain_build/matlab_scripts/CodeGen/parseInPorts.m +106 -106
- powertrain_build/matlab_scripts/CodeGen/parseIncludeConfigs.m +25 -25
- powertrain_build/matlab_scripts/CodeGen/parseModelInfo.m +38 -38
- powertrain_build/matlab_scripts/CodeGen/parseNVM.m +81 -81
- powertrain_build/matlab_scripts/CodeGen/parseOutPorts.m +120 -120
- powertrain_build/matlab_scripts/CodeGen/parsePreProcBlks.m +23 -23
- powertrain_build/matlab_scripts/CodeGen/struct2JSON.m +128 -128
- powertrain_build/matlab_scripts/CodeGen/updateCodeSwConfig.m +31 -31
- powertrain_build/matlab_scripts/Init_PyBuild.m +91 -91
- powertrain_build/matlab_scripts/__init__.py +2 -2
- powertrain_build/matlab_scripts/helperFunctions/Get_Full_Name.m +46 -46
- powertrain_build/matlab_scripts/helperFunctions/Get_SrcLines.m +12 -12
- powertrain_build/matlab_scripts/helperFunctions/Init_Models.m +78 -78
- powertrain_build/matlab_scripts/helperFunctions/Init_Projects.m +67 -67
- powertrain_build/matlab_scripts/helperFunctions/Read_Units.m +34 -34
- powertrain_build/matlab_scripts/helperFunctions/SetProjectTimeSamples.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/Strip_Suffix.m +16 -16
- powertrain_build/matlab_scripts/helperFunctions/followLink.m +118 -118
- powertrain_build/matlab_scripts/helperFunctions/getCodeSwitches.m +50 -50
- powertrain_build/matlab_scripts/helperFunctions/getConsumerBlocks.m +30 -30
- powertrain_build/matlab_scripts/helperFunctions/getDefBlock.m +39 -39
- powertrain_build/matlab_scripts/helperFunctions/getDefOutport.m +58 -58
- powertrain_build/matlab_scripts/helperFunctions/getDstBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getDstLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/getInterfaceSignals.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getName.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getPath.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/getProperValue.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/getSrcBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getSrcLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/loadLibraries.m +10 -10
- powertrain_build/matlab_scripts/helperFunctions/loadjson.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/modifyEnumStructField.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/removeConfigDuplicates.m +31 -31
- powertrain_build/matlab_scripts/helperFunctions/sortSystemByClass.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/tl_getfast.m +89 -89
- powertrain_build/matlab_scripts/helperFunctions/topLevelSystem.m +20 -20
- powertrain_build/matlab_scripts/helperFunctions/updateModels.m +131 -131
- powertrain_build/memory_section.py +224 -224
- powertrain_build/nvm_def.py +729 -729
- powertrain_build/problem_logger.py +86 -86
- powertrain_build/pt_matlab.py +430 -430
- powertrain_build/pt_win32.py +144 -144
- powertrain_build/replace_compu_tab_ref.py +105 -105
- powertrain_build/rte_dummy.py +254 -254
- powertrain_build/sched_funcs.py +209 -207
- powertrain_build/signal.py +7 -7
- powertrain_build/signal_if_html_rep.py +221 -221
- powertrain_build/signal_if_html_rep_all.py +302 -302
- powertrain_build/signal_incons_html_rep.py +180 -180
- powertrain_build/signal_incons_html_rep_all.py +366 -366
- powertrain_build/signal_incons_html_rep_base.py +168 -168
- powertrain_build/signal_inconsistency_check.py +641 -641
- powertrain_build/signal_interfaces.py +864 -864
- powertrain_build/templates/Index_SigCheck_All.html +22 -22
- powertrain_build/templates/Index_SigIf_All.html +19 -19
- powertrain_build/types.py +218 -218
- powertrain_build/unit_configs.py +419 -419
- powertrain_build/user_defined_types.py +660 -660
- powertrain_build/versioncheck.py +66 -66
- powertrain_build/wrapper.py +512 -512
- powertrain_build/xlrd_csv.py +87 -87
- powertrain_build/zone_controller/__init__.py +4 -4
- powertrain_build/zone_controller/calibration.py +176 -176
- powertrain_build/zone_controller/composition_yaml.py +880 -878
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/METADATA +100 -100
- powertrain_build-1.13.3.dev3.dist-info/RECORD +130 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/WHEEL +1 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/LICENSE +202 -202
- powertrain_build-1.13.3.dev3.dist-info/pbr.json +1 -0
- powertrain_build-1.13.1.dist-info/RECORD +0 -130
- powertrain_build-1.13.1.dist-info/pbr.json +0 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/entry_points.txt +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/AUTHORS +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/NOTICE +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/top_level.txt +0 -0
powertrain_build/dummy_spm.py
CHANGED
|
@@ -1,252 +1,252 @@
|
|
|
1
|
-
# Copyright 2024 Volvo Car Corporation
|
|
2
|
-
# Licensed under Apache 2.0.
|
|
3
|
-
|
|
4
|
-
# -*- coding: utf-8 -*-
|
|
5
|
-
"""Module containing classes for model out-port interfaces."""
|
|
6
|
-
import os
|
|
7
|
-
from operator import itemgetter
|
|
8
|
-
import math
|
|
9
|
-
|
|
10
|
-
import powertrain_build.build_defs as bd
|
|
11
|
-
from powertrain_build import signal
|
|
12
|
-
from powertrain_build.a2l import A2l
|
|
13
|
-
from powertrain_build.problem_logger import ProblemLogger
|
|
14
|
-
from powertrain_build.types import byte_size, get_bitmask
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class DummySpm(ProblemLogger):
|
|
18
|
-
"""Generate c-files which defines missing outport variables in the model out-port interface.
|
|
19
|
-
|
|
20
|
-
The models declare all in-ports as 'external' and powertrain-build will then
|
|
21
|
-
generate any missing outports in the correct #if/#endif guards here.
|
|
22
|
-
One c-file per outport origin model should be generated.
|
|
23
|
-
|
|
24
|
-
* Generate c-code from matlab/TL script with #if/#endif guards.
|
|
25
|
-
- Pro: Is generated at the same time as other code and placed in model src folder.
|
|
26
|
-
- Pro: Generic code. Will be cached together with TL-generated code.
|
|
27
|
-
- Con: m-script
|
|
28
|
-
* Generate c-code from python with only needed variables. No preprocessor directives.
|
|
29
|
-
- Pro: Python
|
|
30
|
-
- Pro: Simpler c-file with only used variables.
|
|
31
|
-
- Con: Not generic! Not cached?
|
|
32
|
-
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
__asil_level_map = {
|
|
36
|
-
'A': (bd.CVC_DISP_ASIL_A_START, bd.CVC_DISP_ASIL_A_END),
|
|
37
|
-
'B': (bd.CVC_DISP_ASIL_B_START, bd.CVC_DISP_ASIL_B_END),
|
|
38
|
-
'C': (bd.CVC_DISP_ASIL_C_START, bd.CVC_DISP_ASIL_C_END),
|
|
39
|
-
'D': (bd.CVC_DISP_ASIL_D_START, bd.CVC_DISP_ASIL_D_END),
|
|
40
|
-
'QM': (bd.CVC_DISP_START, bd.CVC_DISP_END)}
|
|
41
|
-
|
|
42
|
-
def __init__(self, missing_outports, prj_cfg, feature_cfg, unit_cfg, user_defined_types, basename):
|
|
43
|
-
"""Constructor.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
missing_outports (list): undefined outports based on unit config variables.
|
|
47
|
-
prj_cfg (BuildProjConfig): Build project class holding where files should be stored.
|
|
48
|
-
feature_cfg (FeatureConfig): Feature configs from SPM_Codeswitch_Setup.
|
|
49
|
-
unit_cfg (UnitConfigs): Class holding all unit interfaces.
|
|
50
|
-
user_defined_types (UserDefinedTypes): Class holding user defined data types.
|
|
51
|
-
basename (str): the basename of the outvar, used for .c and .a2l creation.
|
|
52
|
-
|
|
53
|
-
See :doc:`Unit config <unit_config>` for information on the 'outport' dict.
|
|
54
|
-
"""
|
|
55
|
-
super().__init__()
|
|
56
|
-
self._prj_cfg = prj_cfg
|
|
57
|
-
self._feature_cfg = feature_cfg
|
|
58
|
-
self._unit_cfg = unit_cfg
|
|
59
|
-
self._enumerations = user_defined_types.get_enumerations()
|
|
60
|
-
self._common_header_files = user_defined_types.common_header_files
|
|
61
|
-
self._name = basename
|
|
62
|
-
self.use_volatile_globals = prj_cfg.get_use_volatile_globals()
|
|
63
|
-
self._missing_outports = self._restruct_input_data(missing_outports)
|
|
64
|
-
|
|
65
|
-
def _get_byte_size(self, data_type):
|
|
66
|
-
"""Get byte size of a data type.
|
|
67
|
-
Enumeration byte sizes are derived from the underlying data type.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
data_type (str): Data type.
|
|
71
|
-
Returns:
|
|
72
|
-
byte_size(powertrain_build.types.byte_size): Return result of powertrain_build.types.byte_size.
|
|
73
|
-
"""
|
|
74
|
-
if data_type in self._enumerations:
|
|
75
|
-
return byte_size(self._enumerations[data_type]['underlying_data_type'])
|
|
76
|
-
return byte_size(data_type)
|
|
77
|
-
|
|
78
|
-
def _restruct_input_data(self, outports):
|
|
79
|
-
"""Restructure all the input variables per data-type."""
|
|
80
|
-
outports.sort(key=itemgetter('name'))
|
|
81
|
-
outports.sort(key=lambda var: self._get_byte_size(var['type']), reverse=True)
|
|
82
|
-
new_outports = {}
|
|
83
|
-
for outport in outports:
|
|
84
|
-
integrity_level = outport.get('integrity_level', 'QM')
|
|
85
|
-
if integrity_level == 'QM':
|
|
86
|
-
outport['cvc_type'] = 'CVC_DISP'
|
|
87
|
-
else:
|
|
88
|
-
outport['cvc_type'] = f'ASIL_{integrity_level}/CVC_DISP_ASIL_{integrity_level}'
|
|
89
|
-
if integrity_level in new_outports:
|
|
90
|
-
new_outports[integrity_level].append(outport)
|
|
91
|
-
else:
|
|
92
|
-
new_outports.update({integrity_level: [outport]})
|
|
93
|
-
return new_outports
|
|
94
|
-
|
|
95
|
-
def _a2l_dict(self, outports):
|
|
96
|
-
"""Return a dict defining all parameters for a2l-generation."""
|
|
97
|
-
res = {
|
|
98
|
-
'vars': {},
|
|
99
|
-
'function': 'VcDummy_spm'
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for outport in [port for sublist in outports.values() for port in sublist]:
|
|
103
|
-
var = outport['name']
|
|
104
|
-
|
|
105
|
-
if outport['type'] in self._enumerations:
|
|
106
|
-
data_type = self._enumerations[outport['type']]['underlying_data_type']
|
|
107
|
-
else:
|
|
108
|
-
data_type = outport['type']
|
|
109
|
-
|
|
110
|
-
resv = res['vars']
|
|
111
|
-
resv.setdefault(var, {})['a2l_data'] = {
|
|
112
|
-
'bitmask': get_bitmask(data_type),
|
|
113
|
-
'description': outport.get('description', ''),
|
|
114
|
-
'lsb': '2^{}'.format(int(math.log2(outport.get('lsb', 1)))
|
|
115
|
-
if outport.get('lsb') not in ['-', '']
|
|
116
|
-
else 0),
|
|
117
|
-
'max': outport.get('max'),
|
|
118
|
-
'min': outport.get('min'),
|
|
119
|
-
'offset': -(outport.get('offset', 0) if outport.get('offset') not in ['-', ''] else 0),
|
|
120
|
-
'unit': outport['unit'],
|
|
121
|
-
'x_axis': None,
|
|
122
|
-
'y_axis': None}
|
|
123
|
-
resv[var]['function'] = ['VcEc']
|
|
124
|
-
resv[var]['var'] = {'cvc_type': outport['cvc_type'],
|
|
125
|
-
'type': data_type,
|
|
126
|
-
'var': var}
|
|
127
|
-
resv[var]['array'] = outport.get('width', 1)
|
|
128
|
-
res.update({'vars': resv})
|
|
129
|
-
return res
|
|
130
|
-
|
|
131
|
-
def generate_code_files(self, dst_dir):
|
|
132
|
-
"""Generate code and header files.
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
dst_dir (str): Path to destination directory.
|
|
136
|
-
|
|
137
|
-
"""
|
|
138
|
-
h_file_path = os.path.join(dst_dir, f'{self._name}.h')
|
|
139
|
-
self._generate_h_file(h_file_path, self._missing_outports)
|
|
140
|
-
c_file_path = os.path.join(dst_dir, f'{self._name}.c')
|
|
141
|
-
self._generate_c_file(c_file_path, self._missing_outports)
|
|
142
|
-
|
|
143
|
-
def generate_a2l_files(self, dst_dir):
|
|
144
|
-
"""Generate A2L files.
|
|
145
|
-
|
|
146
|
-
Args:
|
|
147
|
-
dst_dir (str): Path to destination directory.
|
|
148
|
-
|
|
149
|
-
"""
|
|
150
|
-
filename = f"{os.path.join(dst_dir, self._name)}.a2l"
|
|
151
|
-
a2l_dict = self._a2l_dict(self._missing_outports)
|
|
152
|
-
a2l = A2l(a2l_dict, self._prj_cfg)
|
|
153
|
-
a2l.gen_a2l(filename)
|
|
154
|
-
|
|
155
|
-
def _generate_h_file(self, file_path, outports):
|
|
156
|
-
"""Generate header file.
|
|
157
|
-
|
|
158
|
-
Args:
|
|
159
|
-
file_path (str): File path to generate.
|
|
160
|
-
"""
|
|
161
|
-
file_name = os.path.basename(file_path).split('.')[0]
|
|
162
|
-
with open(file_path, 'w', encoding="utf-8") as fh:
|
|
163
|
-
fh.write(f'#ifndef {file_name.upper()}_H\n')
|
|
164
|
-
fh.write(f'#define {file_name.upper()}_H\n')
|
|
165
|
-
|
|
166
|
-
fh.write(self._unit_cfg.base_types_headers)
|
|
167
|
-
fh.write('#include "VcCodeSwDefines.h"\n')
|
|
168
|
-
for common_header_file in self._common_header_files:
|
|
169
|
-
fh.write(f'#include "{common_header_file}"\n')
|
|
170
|
-
|
|
171
|
-
for integrity_level in outports.keys():
|
|
172
|
-
disp_start = bd.PREDECL_ASIL_LEVEL_MAP[integrity_level]['DISP']['START']
|
|
173
|
-
disp_end = bd.PREDECL_ASIL_LEVEL_MAP[integrity_level]['DISP']['END']
|
|
174
|
-
fh.write('\n')
|
|
175
|
-
fh.write(f'#include "{disp_start}"\n')
|
|
176
|
-
for outport in outports[integrity_level]:
|
|
177
|
-
if outport['class'] not in signal.INPORT_CLASSES:
|
|
178
|
-
self.warning(f'inport {outport["name"]} class {outport["class"]} is not an inport class')
|
|
179
|
-
|
|
180
|
-
array = ''
|
|
181
|
-
width = outport['width']
|
|
182
|
-
if not isinstance(width, list):
|
|
183
|
-
width = [width]
|
|
184
|
-
if len(width) != 1 or width[0] != 1:
|
|
185
|
-
for w in width:
|
|
186
|
-
if w > 1:
|
|
187
|
-
if not isinstance(w, int):
|
|
188
|
-
self.critical(f'{outport["name"]} widths must be integers. Got "{type(w)}"')
|
|
189
|
-
array += f'[{w}]'
|
|
190
|
-
elif w < 0:
|
|
191
|
-
self.critical(f'{outport["name"]} widths can not be negative. Got "{w}"')
|
|
192
|
-
if self.use_volatile_globals:
|
|
193
|
-
fh.write(f"extern volatile {outport['type']} {outport['name']}{array};\n")
|
|
194
|
-
else:
|
|
195
|
-
fh.write(f"extern {outport['type']} {outport['name']}{array};\n")
|
|
196
|
-
fh.write(f'#include "{disp_end}"\n')
|
|
197
|
-
|
|
198
|
-
fh.write(f'#endif /* {file_name.upper()}_H */\n')
|
|
199
|
-
|
|
200
|
-
def _generate_c_file(self, file_path, outports):
|
|
201
|
-
"""Generate C-file for inports that are missing outports except for supplier ports."""
|
|
202
|
-
file_name = os.path.basename(file_path).split('.')[0]
|
|
203
|
-
base_header = f'#include "{file_name}.h"\n'
|
|
204
|
-
|
|
205
|
-
with open(file_path, 'w', encoding="utf-8") as fh_c:
|
|
206
|
-
fh_c.write(base_header)
|
|
207
|
-
for integrity_level in outports.keys():
|
|
208
|
-
disp_start = bd.CVC_ASIL_LEVEL_MAP[integrity_level]['DISP']['START']
|
|
209
|
-
disp_end = bd.CVC_ASIL_LEVEL_MAP[integrity_level]['DISP']['END']
|
|
210
|
-
fh_c.write('\n')
|
|
211
|
-
fh_c.write(f'#include "{disp_start}"\n')
|
|
212
|
-
for outport in outports[integrity_level]:
|
|
213
|
-
if outport['class'] not in signal.INPORT_CLASSES:
|
|
214
|
-
self.warning(f'inport {outport["name"]} class {outport["class"]} is not an inport class')
|
|
215
|
-
|
|
216
|
-
width = outport['width']
|
|
217
|
-
if outport['type'] in self._enumerations:
|
|
218
|
-
if self._enumerations[outport['type']]['default_value'] is not None:
|
|
219
|
-
init_value = self._enumerations[outport['type']]['default_value']
|
|
220
|
-
else:
|
|
221
|
-
self.warning('Initializing enumeration %s to "zero".', outport['type'])
|
|
222
|
-
init_value = [
|
|
223
|
-
k for k, v in self._enumerations[outport['type']]['members'].items() if v == 0
|
|
224
|
-
][0]
|
|
225
|
-
if width != 1:
|
|
226
|
-
self.critical(f'{outport["name"]} enumeration width must be 1. Got "{width}"')
|
|
227
|
-
fh_c.write(f"{outport['type']} {outport['name']} = {init_value};\n")
|
|
228
|
-
else:
|
|
229
|
-
if not isinstance(width, list):
|
|
230
|
-
width = [width]
|
|
231
|
-
if len(width) == 1 and width[0] == 1:
|
|
232
|
-
array = ' = 0'
|
|
233
|
-
else:
|
|
234
|
-
array = ''
|
|
235
|
-
for w in width:
|
|
236
|
-
if w > 1:
|
|
237
|
-
if not isinstance(w, int):
|
|
238
|
-
msg = f'{outport["name"]} widths must be integers. Got "{type(w)}"'
|
|
239
|
-
self.critical(msg)
|
|
240
|
-
array += f'[{w}]'
|
|
241
|
-
elif w < 0:
|
|
242
|
-
self.critical(f'{outport["name"]} widths can not be negative. Got "{w}"')
|
|
243
|
-
if self.use_volatile_globals:
|
|
244
|
-
fh_c.write(f'volatile {outport["type"]} {outport["name"]}{array};\n')
|
|
245
|
-
else:
|
|
246
|
-
fh_c.write(f'{outport["type"]} {outport["name"]}{array};\n')
|
|
247
|
-
fh_c.write(f'#include "{disp_end}"\n')
|
|
248
|
-
|
|
249
|
-
def generate_files(self, dst_dir):
|
|
250
|
-
"""Generate the files for defining all missing input variables."""
|
|
251
|
-
self.generate_code_files(dst_dir)
|
|
252
|
-
self.generate_a2l_files(dst_dir)
|
|
1
|
+
# Copyright 2024 Volvo Car Corporation
|
|
2
|
+
# Licensed under Apache 2.0.
|
|
3
|
+
|
|
4
|
+
# -*- coding: utf-8 -*-
|
|
5
|
+
"""Module containing classes for model out-port interfaces."""
|
|
6
|
+
import os
|
|
7
|
+
from operator import itemgetter
|
|
8
|
+
import math
|
|
9
|
+
|
|
10
|
+
import powertrain_build.build_defs as bd
|
|
11
|
+
from powertrain_build import signal
|
|
12
|
+
from powertrain_build.a2l import A2l
|
|
13
|
+
from powertrain_build.problem_logger import ProblemLogger
|
|
14
|
+
from powertrain_build.types import byte_size, get_bitmask
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DummySpm(ProblemLogger):
|
|
18
|
+
"""Generate c-files which defines missing outport variables in the model out-port interface.
|
|
19
|
+
|
|
20
|
+
The models declare all in-ports as 'external' and powertrain-build will then
|
|
21
|
+
generate any missing outports in the correct #if/#endif guards here.
|
|
22
|
+
One c-file per outport origin model should be generated.
|
|
23
|
+
|
|
24
|
+
* Generate c-code from matlab/TL script with #if/#endif guards.
|
|
25
|
+
- Pro: Is generated at the same time as other code and placed in model src folder.
|
|
26
|
+
- Pro: Generic code. Will be cached together with TL-generated code.
|
|
27
|
+
- Con: m-script
|
|
28
|
+
* Generate c-code from python with only needed variables. No preprocessor directives.
|
|
29
|
+
- Pro: Python
|
|
30
|
+
- Pro: Simpler c-file with only used variables.
|
|
31
|
+
- Con: Not generic! Not cached?
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
__asil_level_map = {
|
|
36
|
+
'A': (bd.CVC_DISP_ASIL_A_START, bd.CVC_DISP_ASIL_A_END),
|
|
37
|
+
'B': (bd.CVC_DISP_ASIL_B_START, bd.CVC_DISP_ASIL_B_END),
|
|
38
|
+
'C': (bd.CVC_DISP_ASIL_C_START, bd.CVC_DISP_ASIL_C_END),
|
|
39
|
+
'D': (bd.CVC_DISP_ASIL_D_START, bd.CVC_DISP_ASIL_D_END),
|
|
40
|
+
'QM': (bd.CVC_DISP_START, bd.CVC_DISP_END)}
|
|
41
|
+
|
|
42
|
+
def __init__(self, missing_outports, prj_cfg, feature_cfg, unit_cfg, user_defined_types, basename):
|
|
43
|
+
"""Constructor.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
missing_outports (list): undefined outports based on unit config variables.
|
|
47
|
+
prj_cfg (BuildProjConfig): Build project class holding where files should be stored.
|
|
48
|
+
feature_cfg (FeatureConfig): Feature configs from SPM_Codeswitch_Setup.
|
|
49
|
+
unit_cfg (UnitConfigs): Class holding all unit interfaces.
|
|
50
|
+
user_defined_types (UserDefinedTypes): Class holding user defined data types.
|
|
51
|
+
basename (str): the basename of the outvar, used for .c and .a2l creation.
|
|
52
|
+
|
|
53
|
+
See :doc:`Unit config <unit_config>` for information on the 'outport' dict.
|
|
54
|
+
"""
|
|
55
|
+
super().__init__()
|
|
56
|
+
self._prj_cfg = prj_cfg
|
|
57
|
+
self._feature_cfg = feature_cfg
|
|
58
|
+
self._unit_cfg = unit_cfg
|
|
59
|
+
self._enumerations = user_defined_types.get_enumerations()
|
|
60
|
+
self._common_header_files = user_defined_types.common_header_files
|
|
61
|
+
self._name = basename
|
|
62
|
+
self.use_volatile_globals = prj_cfg.get_use_volatile_globals()
|
|
63
|
+
self._missing_outports = self._restruct_input_data(missing_outports)
|
|
64
|
+
|
|
65
|
+
def _get_byte_size(self, data_type):
|
|
66
|
+
"""Get byte size of a data type.
|
|
67
|
+
Enumeration byte sizes are derived from the underlying data type.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
data_type (str): Data type.
|
|
71
|
+
Returns:
|
|
72
|
+
byte_size(powertrain_build.types.byte_size): Return result of powertrain_build.types.byte_size.
|
|
73
|
+
"""
|
|
74
|
+
if data_type in self._enumerations:
|
|
75
|
+
return byte_size(self._enumerations[data_type]['underlying_data_type'])
|
|
76
|
+
return byte_size(data_type)
|
|
77
|
+
|
|
78
|
+
def _restruct_input_data(self, outports):
|
|
79
|
+
"""Restructure all the input variables per data-type."""
|
|
80
|
+
outports.sort(key=itemgetter('name'))
|
|
81
|
+
outports.sort(key=lambda var: self._get_byte_size(var['type']), reverse=True)
|
|
82
|
+
new_outports = {}
|
|
83
|
+
for outport in outports:
|
|
84
|
+
integrity_level = outport.get('integrity_level', 'QM')
|
|
85
|
+
if integrity_level == 'QM':
|
|
86
|
+
outport['cvc_type'] = 'CVC_DISP'
|
|
87
|
+
else:
|
|
88
|
+
outport['cvc_type'] = f'ASIL_{integrity_level}/CVC_DISP_ASIL_{integrity_level}'
|
|
89
|
+
if integrity_level in new_outports:
|
|
90
|
+
new_outports[integrity_level].append(outport)
|
|
91
|
+
else:
|
|
92
|
+
new_outports.update({integrity_level: [outport]})
|
|
93
|
+
return new_outports
|
|
94
|
+
|
|
95
|
+
def _a2l_dict(self, outports):
|
|
96
|
+
"""Return a dict defining all parameters for a2l-generation."""
|
|
97
|
+
res = {
|
|
98
|
+
'vars': {},
|
|
99
|
+
'function': 'VcDummy_spm'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for outport in [port for sublist in outports.values() for port in sublist]:
|
|
103
|
+
var = outport['name']
|
|
104
|
+
|
|
105
|
+
if outport['type'] in self._enumerations:
|
|
106
|
+
data_type = self._enumerations[outport['type']]['underlying_data_type']
|
|
107
|
+
else:
|
|
108
|
+
data_type = outport['type']
|
|
109
|
+
|
|
110
|
+
resv = res['vars']
|
|
111
|
+
resv.setdefault(var, {})['a2l_data'] = {
|
|
112
|
+
'bitmask': get_bitmask(data_type),
|
|
113
|
+
'description': outport.get('description', ''),
|
|
114
|
+
'lsb': '2^{}'.format(int(math.log2(outport.get('lsb', 1)))
|
|
115
|
+
if outport.get('lsb') not in ['-', '']
|
|
116
|
+
else 0),
|
|
117
|
+
'max': outport.get('max'),
|
|
118
|
+
'min': outport.get('min'),
|
|
119
|
+
'offset': -(outport.get('offset', 0) if outport.get('offset') not in ['-', ''] else 0),
|
|
120
|
+
'unit': outport['unit'],
|
|
121
|
+
'x_axis': None,
|
|
122
|
+
'y_axis': None}
|
|
123
|
+
resv[var]['function'] = ['VcEc']
|
|
124
|
+
resv[var]['var'] = {'cvc_type': outport['cvc_type'],
|
|
125
|
+
'type': data_type,
|
|
126
|
+
'var': var}
|
|
127
|
+
resv[var]['array'] = outport.get('width', 1)
|
|
128
|
+
res.update({'vars': resv})
|
|
129
|
+
return res
|
|
130
|
+
|
|
131
|
+
def generate_code_files(self, dst_dir):
|
|
132
|
+
"""Generate code and header files.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
dst_dir (str): Path to destination directory.
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
h_file_path = os.path.join(dst_dir, f'{self._name}.h')
|
|
139
|
+
self._generate_h_file(h_file_path, self._missing_outports)
|
|
140
|
+
c_file_path = os.path.join(dst_dir, f'{self._name}.c')
|
|
141
|
+
self._generate_c_file(c_file_path, self._missing_outports)
|
|
142
|
+
|
|
143
|
+
def generate_a2l_files(self, dst_dir):
|
|
144
|
+
"""Generate A2L files.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
dst_dir (str): Path to destination directory.
|
|
148
|
+
|
|
149
|
+
"""
|
|
150
|
+
filename = f"{os.path.join(dst_dir, self._name)}.a2l"
|
|
151
|
+
a2l_dict = self._a2l_dict(self._missing_outports)
|
|
152
|
+
a2l = A2l(a2l_dict, self._prj_cfg)
|
|
153
|
+
a2l.gen_a2l(filename)
|
|
154
|
+
|
|
155
|
+
def _generate_h_file(self, file_path, outports):
|
|
156
|
+
"""Generate header file.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
file_path (str): File path to generate.
|
|
160
|
+
"""
|
|
161
|
+
file_name = os.path.basename(file_path).split('.')[0]
|
|
162
|
+
with open(file_path, 'w', encoding="utf-8") as fh:
|
|
163
|
+
fh.write(f'#ifndef {file_name.upper()}_H\n')
|
|
164
|
+
fh.write(f'#define {file_name.upper()}_H\n')
|
|
165
|
+
|
|
166
|
+
fh.write(self._unit_cfg.base_types_headers)
|
|
167
|
+
fh.write('#include "VcCodeSwDefines.h"\n')
|
|
168
|
+
for common_header_file in self._common_header_files:
|
|
169
|
+
fh.write(f'#include "{common_header_file}"\n')
|
|
170
|
+
|
|
171
|
+
for integrity_level in outports.keys():
|
|
172
|
+
disp_start = bd.PREDECL_ASIL_LEVEL_MAP[integrity_level]['DISP']['START']
|
|
173
|
+
disp_end = bd.PREDECL_ASIL_LEVEL_MAP[integrity_level]['DISP']['END']
|
|
174
|
+
fh.write('\n')
|
|
175
|
+
fh.write(f'#include "{disp_start}"\n')
|
|
176
|
+
for outport in outports[integrity_level]:
|
|
177
|
+
if outport['class'] not in signal.INPORT_CLASSES:
|
|
178
|
+
self.warning(f'inport {outport["name"]} class {outport["class"]} is not an inport class')
|
|
179
|
+
|
|
180
|
+
array = ''
|
|
181
|
+
width = outport['width']
|
|
182
|
+
if not isinstance(width, list):
|
|
183
|
+
width = [width]
|
|
184
|
+
if len(width) != 1 or width[0] != 1:
|
|
185
|
+
for w in width:
|
|
186
|
+
if w > 1:
|
|
187
|
+
if not isinstance(w, int):
|
|
188
|
+
self.critical(f'{outport["name"]} widths must be integers. Got "{type(w)}"')
|
|
189
|
+
array += f'[{w}]'
|
|
190
|
+
elif w < 0:
|
|
191
|
+
self.critical(f'{outport["name"]} widths can not be negative. Got "{w}"')
|
|
192
|
+
if self.use_volatile_globals:
|
|
193
|
+
fh.write(f"extern volatile {outport['type']} {outport['name']}{array};\n")
|
|
194
|
+
else:
|
|
195
|
+
fh.write(f"extern {outport['type']} {outport['name']}{array};\n")
|
|
196
|
+
fh.write(f'#include "{disp_end}"\n')
|
|
197
|
+
|
|
198
|
+
fh.write(f'#endif /* {file_name.upper()}_H */\n')
|
|
199
|
+
|
|
200
|
+
def _generate_c_file(self, file_path, outports):
|
|
201
|
+
"""Generate C-file for inports that are missing outports except for supplier ports."""
|
|
202
|
+
file_name = os.path.basename(file_path).split('.')[0]
|
|
203
|
+
base_header = f'#include "{file_name}.h"\n'
|
|
204
|
+
|
|
205
|
+
with open(file_path, 'w', encoding="utf-8") as fh_c:
|
|
206
|
+
fh_c.write(base_header)
|
|
207
|
+
for integrity_level in outports.keys():
|
|
208
|
+
disp_start = bd.CVC_ASIL_LEVEL_MAP[integrity_level]['DISP']['START']
|
|
209
|
+
disp_end = bd.CVC_ASIL_LEVEL_MAP[integrity_level]['DISP']['END']
|
|
210
|
+
fh_c.write('\n')
|
|
211
|
+
fh_c.write(f'#include "{disp_start}"\n')
|
|
212
|
+
for outport in outports[integrity_level]:
|
|
213
|
+
if outport['class'] not in signal.INPORT_CLASSES:
|
|
214
|
+
self.warning(f'inport {outport["name"]} class {outport["class"]} is not an inport class')
|
|
215
|
+
|
|
216
|
+
width = outport['width']
|
|
217
|
+
if outport['type'] in self._enumerations:
|
|
218
|
+
if self._enumerations[outport['type']]['default_value'] is not None:
|
|
219
|
+
init_value = self._enumerations[outport['type']]['default_value']
|
|
220
|
+
else:
|
|
221
|
+
self.warning('Initializing enumeration %s to "zero".', outport['type'])
|
|
222
|
+
init_value = [
|
|
223
|
+
k for k, v in self._enumerations[outport['type']]['members'].items() if v == 0
|
|
224
|
+
][0]
|
|
225
|
+
if width != 1:
|
|
226
|
+
self.critical(f'{outport["name"]} enumeration width must be 1. Got "{width}"')
|
|
227
|
+
fh_c.write(f"{outport['type']} {outport['name']} = {init_value};\n")
|
|
228
|
+
else:
|
|
229
|
+
if not isinstance(width, list):
|
|
230
|
+
width = [width]
|
|
231
|
+
if len(width) == 1 and width[0] == 1:
|
|
232
|
+
array = ' = 0'
|
|
233
|
+
else:
|
|
234
|
+
array = ''
|
|
235
|
+
for w in width:
|
|
236
|
+
if w > 1:
|
|
237
|
+
if not isinstance(w, int):
|
|
238
|
+
msg = f'{outport["name"]} widths must be integers. Got "{type(w)}"'
|
|
239
|
+
self.critical(msg)
|
|
240
|
+
array += f'[{w}]'
|
|
241
|
+
elif w < 0:
|
|
242
|
+
self.critical(f'{outport["name"]} widths can not be negative. Got "{w}"')
|
|
243
|
+
if self.use_volatile_globals:
|
|
244
|
+
fh_c.write(f'volatile {outport["type"]} {outport["name"]}{array};\n')
|
|
245
|
+
else:
|
|
246
|
+
fh_c.write(f'{outport["type"]} {outport["name"]}{array};\n')
|
|
247
|
+
fh_c.write(f'#include "{disp_end}"\n')
|
|
248
|
+
|
|
249
|
+
def generate_files(self, dst_dir):
|
|
250
|
+
"""Generate the files for defining all missing input variables."""
|
|
251
|
+
self.generate_code_files(dst_dir)
|
|
252
|
+
self.generate_a2l_files(dst_dir)
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
# Copyright 2024 Volvo Car Corporation
|
|
2
|
-
# Licensed under Apache 2.0.
|
|
3
|
-
|
|
4
|
-
"""Environment compatibility check."""
|
|
5
|
-
|
|
6
|
-
import sys
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def check_python_string(python_lower, python_upper=None):
|
|
10
|
-
"""Ensure current Python interpreter is a version between lower and upper.
|
|
11
|
-
|
|
12
|
-
Arguments:
|
|
13
|
-
python_lower (str): Required lower bound for Python version.
|
|
14
|
-
python_upper (str): Optional upper bound for Python version.
|
|
15
|
-
Raises:
|
|
16
|
-
RuntimeError: If current Python executable is not compatible with powertrain_build.
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
versions = [_split_version(python_lower)]
|
|
20
|
-
if python_upper:
|
|
21
|
-
versions.append(_split_version(python_upper))
|
|
22
|
-
check_python_tuple(*versions)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def check_python_tuple(python_lower, python_upper=None):
|
|
26
|
-
"""Ensure current Python interpreter is a version between lower and upper.
|
|
27
|
-
|
|
28
|
-
Arguments:
|
|
29
|
-
python_lower (2-tuple): Required lower bound for Python version.
|
|
30
|
-
python_upper (2-tuple): Optional upper bound for Python version.
|
|
31
|
-
Raises:
|
|
32
|
-
RuntimeError: If current Python executable is not compatible with powertrain_build.
|
|
33
|
-
|
|
34
|
-
"""
|
|
35
|
-
cur_version = sys.version_info[:2]
|
|
36
|
-
|
|
37
|
-
if cur_version[0] < python_lower[0] or cur_version[1] < python_lower[1]:
|
|
38
|
-
raise RuntimeError(_format_error(f'must be higher than {python_lower}'))
|
|
39
|
-
|
|
40
|
-
if python_upper and (cur_version[0] > python_upper[0] or cur_version[1] > python_upper[1]):
|
|
41
|
-
raise RuntimeError(_format_error(f'must be lower than {python_upper}'))
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _split_version(version_string):
|
|
45
|
-
"""Split a major.minor style string and returns a 2-tuple of integers."""
|
|
46
|
-
parts = version_string.split('.')
|
|
47
|
-
return (int(parts[0]), int(parts[1]))
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _format_error(message):
|
|
51
|
-
"""Return a version error string including current interpreter, version and a custom message."""
|
|
52
|
-
return f'Unsupported Python version ({sys.version_info}), {message}. Path: {sys.executable}'
|
|
1
|
+
# Copyright 2024 Volvo Car Corporation
|
|
2
|
+
# Licensed under Apache 2.0.
|
|
3
|
+
|
|
4
|
+
"""Environment compatibility check."""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_python_string(python_lower, python_upper=None):
|
|
10
|
+
"""Ensure current Python interpreter is a version between lower and upper.
|
|
11
|
+
|
|
12
|
+
Arguments:
|
|
13
|
+
python_lower (str): Required lower bound for Python version.
|
|
14
|
+
python_upper (str): Optional upper bound for Python version.
|
|
15
|
+
Raises:
|
|
16
|
+
RuntimeError: If current Python executable is not compatible with powertrain_build.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
versions = [_split_version(python_lower)]
|
|
20
|
+
if python_upper:
|
|
21
|
+
versions.append(_split_version(python_upper))
|
|
22
|
+
check_python_tuple(*versions)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def check_python_tuple(python_lower, python_upper=None):
|
|
26
|
+
"""Ensure current Python interpreter is a version between lower and upper.
|
|
27
|
+
|
|
28
|
+
Arguments:
|
|
29
|
+
python_lower (2-tuple): Required lower bound for Python version.
|
|
30
|
+
python_upper (2-tuple): Optional upper bound for Python version.
|
|
31
|
+
Raises:
|
|
32
|
+
RuntimeError: If current Python executable is not compatible with powertrain_build.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
cur_version = sys.version_info[:2]
|
|
36
|
+
|
|
37
|
+
if cur_version[0] < python_lower[0] or cur_version[1] < python_lower[1]:
|
|
38
|
+
raise RuntimeError(_format_error(f'must be higher than {python_lower}'))
|
|
39
|
+
|
|
40
|
+
if python_upper and (cur_version[0] > python_upper[0] or cur_version[1] > python_upper[1]):
|
|
41
|
+
raise RuntimeError(_format_error(f'must be lower than {python_upper}'))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _split_version(version_string):
|
|
45
|
+
"""Split a major.minor style string and returns a 2-tuple of integers."""
|
|
46
|
+
parts = version_string.split('.')
|
|
47
|
+
return (int(parts[0]), int(parts[1]))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _format_error(message):
|
|
51
|
+
"""Return a version error string including current interpreter, version and a custom message."""
|
|
52
|
+
return f'Unsupported Python version ({sys.version_info}), {message}. Path: {sys.executable}'
|