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.
Files changed (132) hide show
  1. powertrain_build/__init__.py +40 -40
  2. powertrain_build/__main__.py +6 -6
  3. powertrain_build/a2l.py +582 -582
  4. powertrain_build/a2l_merge.py +650 -650
  5. powertrain_build/a2l_templates.py +717 -717
  6. powertrain_build/build.py +985 -985
  7. powertrain_build/build_defs.py +309 -309
  8. powertrain_build/build_proj_config.py +690 -690
  9. powertrain_build/check_interface.py +575 -575
  10. powertrain_build/cli.py +141 -141
  11. powertrain_build/config.py +542 -542
  12. powertrain_build/core.py +395 -395
  13. powertrain_build/core_dummy.py +343 -343
  14. powertrain_build/create_conversion_table.py +73 -73
  15. powertrain_build/dids.py +916 -916
  16. powertrain_build/dummy.py +157 -157
  17. powertrain_build/dummy_spm.py +252 -252
  18. powertrain_build/environmentcheck.py +52 -52
  19. powertrain_build/ext_dbg.py +255 -255
  20. powertrain_build/ext_var.py +327 -327
  21. powertrain_build/feature_configs.py +301 -301
  22. powertrain_build/gen_allsysteminfo.py +227 -227
  23. powertrain_build/gen_label_split.py +449 -449
  24. powertrain_build/handcode_replacer.py +124 -124
  25. powertrain_build/html_report.py +133 -133
  26. powertrain_build/interface/__init__.py +4 -4
  27. powertrain_build/interface/application.py +511 -511
  28. powertrain_build/interface/base.py +500 -500
  29. powertrain_build/interface/csp_api.py +490 -490
  30. powertrain_build/interface/device_proxy.py +677 -677
  31. powertrain_build/interface/ems.py +67 -67
  32. powertrain_build/interface/export_global_vars.py +121 -121
  33. powertrain_build/interface/generate_adapters.py +132 -132
  34. powertrain_build/interface/generate_hi_interface.py +87 -87
  35. powertrain_build/interface/generate_service.py +69 -69
  36. powertrain_build/interface/generate_wrappers.py +147 -147
  37. powertrain_build/interface/generation_utils.py +142 -142
  38. powertrain_build/interface/hal.py +194 -194
  39. powertrain_build/interface/model_yaml_verification.py +348 -348
  40. powertrain_build/interface/service.py +296 -296
  41. powertrain_build/interface/simulink.py +249 -249
  42. powertrain_build/interface/update_call_sources.py +180 -180
  43. powertrain_build/interface/update_model_yaml.py +186 -186
  44. powertrain_build/interface/zone_controller.py +362 -362
  45. powertrain_build/lib/__init__.py +4 -4
  46. powertrain_build/lib/helper_functions.py +127 -127
  47. powertrain_build/lib/logger.py +55 -55
  48. powertrain_build/matlab_scripts/CodeGen/BuildAutomationPyBuild.m +78 -78
  49. powertrain_build/matlab_scripts/CodeGen/Generate_A2L.m +154 -154
  50. powertrain_build/matlab_scripts/CodeGen/generateTLUnit.m +239 -239
  51. powertrain_build/matlab_scripts/CodeGen/getAsilClassification.m +28 -28
  52. powertrain_build/matlab_scripts/CodeGen/modelConfiguredForTL.m +28 -28
  53. powertrain_build/matlab_scripts/CodeGen/moveDefOutports.m +88 -88
  54. powertrain_build/matlab_scripts/CodeGen/parseCalMeasData.m +410 -410
  55. powertrain_build/matlab_scripts/CodeGen/parseCoreIdentifiers.m +139 -139
  56. powertrain_build/matlab_scripts/CodeGen/parseDIDs.m +141 -141
  57. powertrain_build/matlab_scripts/CodeGen/parseInPorts.m +106 -106
  58. powertrain_build/matlab_scripts/CodeGen/parseIncludeConfigs.m +25 -25
  59. powertrain_build/matlab_scripts/CodeGen/parseModelInfo.m +38 -38
  60. powertrain_build/matlab_scripts/CodeGen/parseNVM.m +81 -81
  61. powertrain_build/matlab_scripts/CodeGen/parseOutPorts.m +120 -120
  62. powertrain_build/matlab_scripts/CodeGen/parsePreProcBlks.m +23 -23
  63. powertrain_build/matlab_scripts/CodeGen/struct2JSON.m +128 -128
  64. powertrain_build/matlab_scripts/CodeGen/updateCodeSwConfig.m +31 -31
  65. powertrain_build/matlab_scripts/Init_PyBuild.m +91 -91
  66. powertrain_build/matlab_scripts/__init__.py +2 -2
  67. powertrain_build/matlab_scripts/helperFunctions/Get_Full_Name.m +46 -46
  68. powertrain_build/matlab_scripts/helperFunctions/Get_SrcLines.m +12 -12
  69. powertrain_build/matlab_scripts/helperFunctions/Init_Models.m +78 -78
  70. powertrain_build/matlab_scripts/helperFunctions/Init_Projects.m +67 -67
  71. powertrain_build/matlab_scripts/helperFunctions/Read_Units.m +34 -34
  72. powertrain_build/matlab_scripts/helperFunctions/SetProjectTimeSamples.m +26 -26
  73. powertrain_build/matlab_scripts/helperFunctions/Strip_Suffix.m +16 -16
  74. powertrain_build/matlab_scripts/helperFunctions/followLink.m +118 -118
  75. powertrain_build/matlab_scripts/helperFunctions/getCodeSwitches.m +50 -50
  76. powertrain_build/matlab_scripts/helperFunctions/getConsumerBlocks.m +30 -30
  77. powertrain_build/matlab_scripts/helperFunctions/getDefBlock.m +39 -39
  78. powertrain_build/matlab_scripts/helperFunctions/getDefOutport.m +58 -58
  79. powertrain_build/matlab_scripts/helperFunctions/getDstBlocks.m +19 -19
  80. powertrain_build/matlab_scripts/helperFunctions/getDstLines.m +13 -13
  81. powertrain_build/matlab_scripts/helperFunctions/getInterfaceSignals.m +37 -37
  82. powertrain_build/matlab_scripts/helperFunctions/getName.m +37 -37
  83. powertrain_build/matlab_scripts/helperFunctions/getPath.m +6 -6
  84. powertrain_build/matlab_scripts/helperFunctions/getProperValue.m +21 -21
  85. powertrain_build/matlab_scripts/helperFunctions/getSrcBlocks.m +19 -19
  86. powertrain_build/matlab_scripts/helperFunctions/getSrcLines.m +13 -13
  87. powertrain_build/matlab_scripts/helperFunctions/loadLibraries.m +10 -10
  88. powertrain_build/matlab_scripts/helperFunctions/loadjson.m +6 -6
  89. powertrain_build/matlab_scripts/helperFunctions/modifyEnumStructField.m +21 -21
  90. powertrain_build/matlab_scripts/helperFunctions/removeConfigDuplicates.m +31 -31
  91. powertrain_build/matlab_scripts/helperFunctions/sortSystemByClass.m +26 -26
  92. powertrain_build/matlab_scripts/helperFunctions/tl_getfast.m +89 -89
  93. powertrain_build/matlab_scripts/helperFunctions/topLevelSystem.m +20 -20
  94. powertrain_build/matlab_scripts/helperFunctions/updateModels.m +131 -131
  95. powertrain_build/memory_section.py +224 -224
  96. powertrain_build/nvm_def.py +729 -729
  97. powertrain_build/problem_logger.py +86 -86
  98. powertrain_build/pt_matlab.py +430 -430
  99. powertrain_build/pt_win32.py +144 -144
  100. powertrain_build/replace_compu_tab_ref.py +105 -105
  101. powertrain_build/rte_dummy.py +254 -254
  102. powertrain_build/sched_funcs.py +209 -207
  103. powertrain_build/signal.py +7 -7
  104. powertrain_build/signal_if_html_rep.py +221 -221
  105. powertrain_build/signal_if_html_rep_all.py +302 -302
  106. powertrain_build/signal_incons_html_rep.py +180 -180
  107. powertrain_build/signal_incons_html_rep_all.py +366 -366
  108. powertrain_build/signal_incons_html_rep_base.py +168 -168
  109. powertrain_build/signal_inconsistency_check.py +641 -641
  110. powertrain_build/signal_interfaces.py +864 -864
  111. powertrain_build/templates/Index_SigCheck_All.html +22 -22
  112. powertrain_build/templates/Index_SigIf_All.html +19 -19
  113. powertrain_build/types.py +218 -218
  114. powertrain_build/unit_configs.py +419 -419
  115. powertrain_build/user_defined_types.py +660 -660
  116. powertrain_build/versioncheck.py +66 -66
  117. powertrain_build/wrapper.py +512 -512
  118. powertrain_build/xlrd_csv.py +87 -87
  119. powertrain_build/zone_controller/__init__.py +4 -4
  120. powertrain_build/zone_controller/calibration.py +176 -176
  121. powertrain_build/zone_controller/composition_yaml.py +880 -878
  122. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/METADATA +100 -100
  123. powertrain_build-1.13.3.dev3.dist-info/RECORD +130 -0
  124. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/WHEEL +1 -1
  125. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/LICENSE +202 -202
  126. powertrain_build-1.13.3.dev3.dist-info/pbr.json +1 -0
  127. powertrain_build-1.13.1.dist-info/RECORD +0 -130
  128. powertrain_build-1.13.1.dist-info/pbr.json +0 -1
  129. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/entry_points.txt +0 -0
  130. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/AUTHORS +0 -0
  131. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/NOTICE +0 -0
  132. {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/top_level.txt +0 -0
@@ -1,419 +1,419 @@
1
- # Copyright 2024 Volvo Car Corporation
2
- # Licensed under Apache 2.0.
3
-
4
- # -*- coding: utf-8 -*-
5
- """Module for reading unit configuration files."""
6
- import json
7
- import os
8
- import time
9
- from pprint import pformat
10
-
11
- from powertrain_build.build_proj_config import BuildProjConfig
12
- from powertrain_build.problem_logger import ProblemLogger
13
- from powertrain_build.versioncheck import Version
14
-
15
-
16
- class CodeGenerators:
17
- """Enum for code generators."""
18
- target_link = 'target_link'
19
- embedded_coder = 'embedded_coder'
20
-
21
-
22
- class UnitConfigs(ProblemLogger):
23
- """A class for accessing the project’s unit definitions (see :doc:`unit_config`).
24
-
25
- Provides methods for retrieving the all definitions of a unit and all existing units.
26
- """
27
-
28
- CONFIG_SKIP_LIST = ['VcDebugSafe', 'VcDebug', 'VcDebugOutputSafe', 'VcDebugOutput']
29
-
30
- def __init__(self, build_prj_config, feature_config):
31
- """Class Initialization.
32
-
33
- Args:
34
- build_prj_config (BuildProjConfig): A class instance which holds
35
- the information of where to find units configs to parse
36
- feature_config (FeatureConfigs): Class instance project feature definitions
37
-
38
- """
39
- super().__init__()
40
- if not isinstance(build_prj_config, BuildProjConfig):
41
- raise TypeError('build_prj_config argument is not an'
42
- ' instance of BuildProjConfig')
43
- self._build_prj_config = build_prj_config
44
- self._feature_cfg = feature_config
45
- self._raw_per_unit_configs = {}
46
- self._per_unit_configs = {}
47
- self._per_type_unit_configs = {}
48
- self._if_define_dict = {}
49
- self._missing_configs = set()
50
- self._empty_config_def = set()
51
- self._parse_all_unit_configs()
52
- self._per_type_unit_signals()
53
- self.code_generators = self._get_code_generators()
54
- self.base_types_headers = self._get_base_types_headers()
55
-
56
- # write the summary of error (to avoid repeating error messages)
57
- for unit in self._missing_configs:
58
- self.critical('%s is missing config files', unit)
59
- for var, unit in self._empty_config_def:
60
- self.warning('%s in unit %s, has empty config_def!'
61
- 'probably goto-block, missing a corresponing from-block.',
62
- var, unit)
63
-
64
- def __repr__(self):
65
- """Get string representation of object."""
66
- return pformat(self._per_type_unit_configs)
67
-
68
- def _parse_all_unit_configs(self):
69
- """Parse all unit config files."""
70
- start_time = time.time()
71
- self.info(' Start loading unit_cfg json files')
72
- cfg_dirs = self._build_prj_config.get_unit_cfg_dirs()
73
- for unit, cfg_dir in cfg_dirs.items():
74
- self._parse_unit_config(unit, cfg_dir)
75
- self.info(' Finished loading unit_cfg json files (in %4.2f s)', time.time() - start_time)
76
-
77
- def _parse_unit_config(self, unit, cfg_dir):
78
- """Parse one unit config file."""
79
- file_ = os.path.join(cfg_dir, f'config_{unit}.json')
80
- with open(file_, 'r', encoding="utf-8") as fhndl:
81
- self.debug('Loading json file %s', unit)
82
- try:
83
- tmp_ucfg = json.load(fhndl)
84
- if not Version.is_compatible(tmp_ucfg.get('version', '0.0.0')):
85
- raise ValueError(f'Incompatible config file version for unit {unit}.')
86
- if unit in self._raw_per_unit_configs:
87
- self.critical("Conflicting Unit name %s: Units need to have unique names", unit)
88
- self._raw_per_unit_configs[unit] = tmp_ucfg
89
- except json.JSONDecodeError as ex:
90
- self.critical('Error reading config file %s: %s', file_, ex)
91
- return
92
- for include_unit in tmp_ucfg.get('includes', []):
93
- self.debug('%s includes %s in %s', unit, include_unit, cfg_dir)
94
- self._parse_unit_config(include_unit, cfg_dir)
95
-
96
- def _filter_io_nvm_feat(self):
97
- """Remove all parameters not defined in the prj_config.
98
-
99
- Parameters can be removed via not active feature in the unit, or
100
- the entire unit is not included in the project.
101
-
102
- Args:
103
- config (str): the name of the configuration
104
-
105
- the format of the data-dict::
106
-
107
- {'UnitName': {'class': 'CVC_EXT',
108
- 'configs': [['Vc_D_CodegenHev '
109
- '== 2',
110
- 'Vc_D_CodegenHev '
111
- '> 0']],
112
- 'description': 'HV battery cooling request',
113
- 'handle': 'VcPpmPsm/VcPpmPsm/Subsystem/'
114
- 'VcPpmPsm/yVcBec_B_ChillerCoolReq',
115
- 'lsb': 1,
116
- 'max': 3,
117
- 'min': 0,
118
- 'name': 'sVcBec_D_HvBattCoolgReq',
119
- 'offset': 0,
120
- 'type': 'UInt8',
121
- 'unit': '-'}
122
- }
123
-
124
- """
125
- res = {}
126
- self.debug('_filter_io_nvm_feat: Feature Cfg')
127
- for unit in self._build_prj_config.get_included_units():
128
- self._filter_io_nvm_feat_unit(unit, res)
129
- if not res:
130
- self.warning('No units configured for project')
131
- return res
132
-
133
- def _filter_core_config(self, u_def_data):
134
- """Handle core configs."""
135
- f_core = {}
136
- for core_type, core_data in u_def_data.items():
137
- f_core[core_type] = {}
138
- for key, value in core_data.items():
139
- if key != 'IllegalBlk':
140
- # Matlab sets core:{type:{name:{API_blk:[{path, config}]}}}
141
- # config.py - core:{type:{name:{configs}}}
142
- configs = value.get('configs', [cfg for blk in value['API_blk'] for cfg in blk['config']])
143
- if self._feature_cfg.check_if_active_in_config(configs):
144
- f_core[core_type][key] = value
145
- return f_core
146
-
147
- def _filter_io_nvm_feat_unit(self, unit, res):
148
- """Handle one unit config with respect to the filtering in :_filter_io_nvm_feat:."""
149
- try:
150
- u_data = self._raw_per_unit_configs[unit]
151
- except KeyError:
152
- # Some units in the raster should not have config files
153
- if unit not in self.CONFIG_SKIP_LIST:
154
- self.debug('_filter_io_nvm_feat_unit: cfg missing: %s', unit)
155
- self._missing_configs.add(unit)
156
- return
157
- for u_def_type, u_def_data in u_data.items():
158
- res.setdefault(unit, {}).setdefault(u_def_type, {})
159
- if u_def_type == 'dids':
160
- f_dids = {k: v for k, v in u_def_data.items()
161
- if self._feature_cfg.check_if_active_in_config(v['configs'])}
162
- res[unit][u_def_type] = f_dids
163
- elif u_def_type == 'core':
164
- res[unit][u_def_type] = self._filter_core_config(u_def_data)
165
- elif u_def_type == 'pre_procs':
166
- # the pre_proc key does not have configuration attributes
167
- res[unit]['pre_procs'] = u_def_data
168
- elif u_def_type == 'integrity_level':
169
- res[unit]['integrity_level'] = u_def_data
170
- elif u_def_type == 'code_generator':
171
- res[unit]['code_generator'] = u_def_data
172
- elif u_def_type == 'version':
173
- res[unit]['version'] = u_def_data
174
- elif u_def_type == 'csp':
175
- csp_data = {}
176
- if 'methods' in u_def_data:
177
- csp_data = {'methods': {}}
178
- for method_name, method_data in u_def_data['methods'].items():
179
- if self._feature_cfg.check_if_active_in_config(method_data['configs']):
180
- csp_data['methods'][method_name] = method_data
181
- res[unit][u_def_type] = csp_data
182
- elif u_def_type == 'includes':
183
- # List of configs for handwritten code
184
- for included_unit in u_def_data:
185
- self.debug('%s includes %s', unit, included_unit)
186
- self._filter_io_nvm_feat_unit(included_unit, res)
187
- else:
188
- for var, var_pars in u_def_data.items():
189
- # TODO: remove this code when the bug in the matlab code is removed.
190
- if var_pars['configs'] == []:
191
- self.debug('Adding %s', unit)
192
- self._empty_config_def.add((var, unit))
193
- if self._feature_cfg.check_if_active_in_config(var_pars['configs']):
194
- res[unit][u_def_type].setdefault(var, {}).update(var_pars)
195
-
196
- @staticmethod
197
- def _update_io_nvm(dict_, unit, data_type, variables):
198
- """Change the struct for in out and nvm variables.
199
-
200
- The resulting new struct is stored in the dict dict_
201
- """
202
- for var, var_pars in variables.items():
203
- dict_.setdefault(data_type, {}).setdefault(var, {}).setdefault(unit, var_pars)
204
-
205
- def _update_dids(self, unit, key, data, feat_cfg=None):
206
- """Change the struct for in out and nvm variables."""
207
- # TODO: Add functionality
208
-
209
- @staticmethod
210
- def _update_core(dict_, unit, data_type, core_ids):
211
- """Change the struct for in core parameters."""
212
- for _, core_data in core_ids.items():
213
- for var, var_pars in core_data.items():
214
- dict_.setdefault(data_type, {}).setdefault(var, {}).setdefault(unit, var_pars)
215
-
216
- def _update_pre_procs(self, unit, key, data, feat_cfg=None):
217
- """Change the struct for in pre_processor parameters."""
218
- # TODO: Add functionality
219
-
220
- def _per_type_unit_signals(self):
221
- """Change the structure of the data to aggregate all unit configs.
222
-
223
- Returns:
224
- dict: a structure per config type instead of per unit
225
-
226
- """
227
- # loop over all projects and store the active items in each configuration
228
- self._per_unit_configs = self._filter_io_nvm_feat()
229
- dict_ = self._per_type_unit_configs = {}
230
- for unit, udata in self._per_unit_configs.items():
231
- for data_type, variables in udata.items():
232
- if data_type in ['core']:
233
- self._update_core(dict_, unit, data_type, variables)
234
- elif data_type in ['dids']:
235
- self._update_dids(dict_, unit, data_type, variables)
236
- elif data_type in ['pre_procs']:
237
- self._update_pre_procs(dict_, unit, data_type, variables)
238
- elif data_type in ['outports', 'inports', 'dids', 'nvm', 'local_vars', 'calib_consts', 'csp']:
239
- self._update_io_nvm(dict_, unit, data_type, variables)
240
- else:
241
- dict_.setdefault(data_type, {}).setdefault(unit, udata)
242
-
243
- def check_if_in_unit_cfg(self, unit, symbol):
244
- """Check if the symbol is defined in the unit config file."""
245
- for data in self._raw_per_unit_configs[unit].values():
246
- if isinstance(data, dict):
247
- if symbol in data:
248
- return True
249
- return False
250
-
251
- def get_per_cfg_unit_cfg(self):
252
- """Get all io-signals and core-ids for all units.
253
-
254
- Get all io-signals and core-ids for all units, where all inports, outport, etc,
255
- are aggregated from all unit definition files.
256
-
257
- Returns:
258
- dict: a dict with the below format::
259
-
260
- {
261
- 'inports/outports/nvm/core': {
262
- 'VARIABLE_NAME': {
263
- 'UNIT_NAME': {
264
- 'class': 'CVC_EXT',
265
- 'configs': [['all']],
266
- 'description': 'Power Pulse ',
267
- 'handle': 'VcPemAlc/VcPemAlc/Subsystem/VcPemAlc/yVcVmcPmm_B_SsActive9',
268
- 'lsb': 1,
269
- 'max': 800,
270
- 'min': 0,
271
- 'name': 'sVcAesPp_Pw_PwrPls',
272
- 'offset': 0,
273
- 'type': 'UInt16',
274
- 'unit': 'W'
275
- }
276
- }
277
- }
278
- }
279
- }
280
-
281
- The top level keys are 'inports', 'outports', 'nvm' and 'core'
282
-
283
- """
284
- return self._per_type_unit_configs
285
-
286
- def check_if_in_per_cfg_unit_cfg(self, cfg, symbol):
287
- """Check if the symbol is defined in the aggregated unit config files."""
288
- return (
289
- cfg in self._per_type_unit_configs and
290
- symbol in self._per_type_unit_configs[cfg])
291
-
292
- def get_per_unit_cfg(self):
293
- """Get io-signals for all units, per unit, for a given project.
294
-
295
- If 'all' is given as a project, all signals, regardless of configuration,
296
- is returned.
297
-
298
- Returns:
299
- dict: a dict with the below format::
300
-
301
- {'NAME_OF_UNIT': {
302
- 'core': {'Events': {},
303
- 'FIDs': {},
304
- 'IUMPR': {},
305
- 'Ranking': {},
306
- 'TstId': {}},
307
- 'dids': {},
308
- 'inports': {'VARIABLE_NAME': {'class': 'CVC_DISP',
309
- 'configs': [['all']],
310
- 'description': 'Torque '
311
- 'arbitraion '
312
- 'state',
313
- 'handle': 'VcPemAlc/VcPemAlc/...',
314
- 'lsb': 1,
315
- 'max': 9,
316
- 'min': 0,
317
- 'name': 'rVcPemAlc_D_AuxLoadEvent',
318
- 'offset': 0,
319
- 'type': 'UInt8',
320
- 'unit': '-'}
321
- },
322
- 'outports' : {},
323
- 'nvm' : {}
324
- }
325
- }
326
-
327
- """
328
- return self._per_unit_configs
329
-
330
- def get_per_unit_cfg_total(self):
331
- """Get total io-signals configuration for all units, per unit, for a given project.
332
-
333
- Does not remove signals disabled by code switches.
334
-
335
- Returns:
336
- dict: a dict with the below format::
337
-
338
- {'NAME_OF_UNIT': {
339
- 'core': {'Events': {},
340
- 'FIDs': {},
341
- 'IUMPR': {},
342
- 'Ranking': {},
343
- 'TstId': {}},
344
- 'dids': {},
345
- 'inports': {'VARIABLE_NAME': {'class': 'CVC_DISP',
346
- 'configs': [['all']],
347
- 'description': 'Torque '
348
- 'arbitraion '
349
- 'state',
350
- 'handle': 'VcPemAlc/VcPemAlc/...',
351
- 'lsb': 1,
352
- 'max': 9,
353
- 'min': 0,
354
- 'name': 'rVcPemAlc_D_AuxLoadEvent',
355
- 'offset': 0,
356
- 'type': 'UInt8',
357
- 'unit': '-'}
358
- },
359
- 'outports' : {},
360
- 'nvm' : {}
361
- }
362
- }
363
-
364
- """
365
- res = {}
366
- for unit in self._build_prj_config.get_included_units():
367
- try:
368
- res[unit] = self._raw_per_unit_configs[unit]
369
- except KeyError:
370
- continue
371
- return res
372
-
373
- def get_unit_config(self, unit):
374
- """Get config for a unit.
375
-
376
- Arguments:
377
- unit (str): Unit to get config for
378
- """
379
- return self._raw_per_unit_configs[unit]
380
-
381
- @staticmethod
382
- def get_base_name(unit):
383
- """Get base name of unit."""
384
- return unit.partition('__')[0]
385
-
386
- def get_unit_code_generator(self, unit):
387
- """Get code generator for a given a unit (model).
388
-
389
- Args:
390
- unit (str): Current unit/model name.
391
- Returns:
392
- code_generator (str): Code generator used for given model.
393
- """
394
- per_unit_cfg = self.get_per_unit_cfg()
395
- if unit in per_unit_cfg and 'code_generator' in per_unit_cfg[unit]:
396
- code_generator = per_unit_cfg[unit]['code_generator']
397
- else:
398
- # Default to target_link
399
- code_generator = CodeGenerators.target_link
400
- return code_generator
401
-
402
- def _get_code_generators(self):
403
- per_unit_cfg = self.get_per_unit_cfg()
404
- code_generators = set()
405
- for _, config in per_unit_cfg.items():
406
- if 'code_generator' in config:
407
- code_generators.add(config['code_generator'])
408
- else:
409
- # Default to target_link
410
- code_generators.add(CodeGenerators.target_link)
411
- return code_generators
412
-
413
- def _get_base_types_headers(self):
414
- general_includes = ''
415
- if CodeGenerators.embedded_coder in self.code_generators:
416
- general_includes += '#include "rtwtypes.h"\n'
417
- if CodeGenerators.target_link in self.code_generators:
418
- general_includes += '#include "tl_basetypes.h"\n'
419
- return general_includes
1
+ # Copyright 2024 Volvo Car Corporation
2
+ # Licensed under Apache 2.0.
3
+
4
+ # -*- coding: utf-8 -*-
5
+ """Module for reading unit configuration files."""
6
+ import json
7
+ import os
8
+ import time
9
+ from pprint import pformat
10
+
11
+ from powertrain_build.build_proj_config import BuildProjConfig
12
+ from powertrain_build.problem_logger import ProblemLogger
13
+ from powertrain_build.versioncheck import Version
14
+
15
+
16
+ class CodeGenerators:
17
+ """Enum for code generators."""
18
+ target_link = 'target_link'
19
+ embedded_coder = 'embedded_coder'
20
+
21
+
22
+ class UnitConfigs(ProblemLogger):
23
+ """A class for accessing the project’s unit definitions (see :doc:`unit_config`).
24
+
25
+ Provides methods for retrieving the all definitions of a unit and all existing units.
26
+ """
27
+
28
+ CONFIG_SKIP_LIST = ['VcDebugSafe', 'VcDebug', 'VcDebugOutputSafe', 'VcDebugOutput']
29
+
30
+ def __init__(self, build_prj_config, feature_config):
31
+ """Class Initialization.
32
+
33
+ Args:
34
+ build_prj_config (BuildProjConfig): A class instance which holds
35
+ the information of where to find units configs to parse
36
+ feature_config (FeatureConfigs): Class instance project feature definitions
37
+
38
+ """
39
+ super().__init__()
40
+ if not isinstance(build_prj_config, BuildProjConfig):
41
+ raise TypeError('build_prj_config argument is not an'
42
+ ' instance of BuildProjConfig')
43
+ self._build_prj_config = build_prj_config
44
+ self._feature_cfg = feature_config
45
+ self._raw_per_unit_configs = {}
46
+ self._per_unit_configs = {}
47
+ self._per_type_unit_configs = {}
48
+ self._if_define_dict = {}
49
+ self._missing_configs = set()
50
+ self._empty_config_def = set()
51
+ self._parse_all_unit_configs()
52
+ self._per_type_unit_signals()
53
+ self.code_generators = self._get_code_generators()
54
+ self.base_types_headers = self._get_base_types_headers()
55
+
56
+ # write the summary of error (to avoid repeating error messages)
57
+ for unit in self._missing_configs:
58
+ self.critical('%s is missing config files', unit)
59
+ for var, unit in self._empty_config_def:
60
+ self.warning('%s in unit %s, has empty config_def!'
61
+ 'probably goto-block, missing a corresponing from-block.',
62
+ var, unit)
63
+
64
+ def __repr__(self):
65
+ """Get string representation of object."""
66
+ return pformat(self._per_type_unit_configs)
67
+
68
+ def _parse_all_unit_configs(self):
69
+ """Parse all unit config files."""
70
+ start_time = time.time()
71
+ self.info(' Start loading unit_cfg json files')
72
+ cfg_dirs = self._build_prj_config.get_unit_cfg_dirs()
73
+ for unit, cfg_dir in cfg_dirs.items():
74
+ self._parse_unit_config(unit, cfg_dir)
75
+ self.info(' Finished loading unit_cfg json files (in %4.2f s)', time.time() - start_time)
76
+
77
+ def _parse_unit_config(self, unit, cfg_dir):
78
+ """Parse one unit config file."""
79
+ file_ = os.path.join(cfg_dir, f'config_{unit}.json')
80
+ with open(file_, 'r', encoding="utf-8") as fhndl:
81
+ self.debug('Loading json file %s', unit)
82
+ try:
83
+ tmp_ucfg = json.load(fhndl)
84
+ if not Version.is_compatible(tmp_ucfg.get('version', '0.0.0')):
85
+ raise ValueError(f'Incompatible config file version for unit {unit}.')
86
+ if unit in self._raw_per_unit_configs:
87
+ self.critical("Conflicting Unit name %s: Units need to have unique names", unit)
88
+ self._raw_per_unit_configs[unit] = tmp_ucfg
89
+ except json.JSONDecodeError as ex:
90
+ self.critical('Error reading config file %s: %s', file_, ex)
91
+ return
92
+ for include_unit in tmp_ucfg.get('includes', []):
93
+ self.debug('%s includes %s in %s', unit, include_unit, cfg_dir)
94
+ self._parse_unit_config(include_unit, cfg_dir)
95
+
96
+ def _filter_io_nvm_feat(self):
97
+ """Remove all parameters not defined in the prj_config.
98
+
99
+ Parameters can be removed via not active feature in the unit, or
100
+ the entire unit is not included in the project.
101
+
102
+ Args:
103
+ config (str): the name of the configuration
104
+
105
+ the format of the data-dict::
106
+
107
+ {'UnitName': {'class': 'CVC_EXT',
108
+ 'configs': [['Vc_D_CodegenHev '
109
+ '== 2',
110
+ 'Vc_D_CodegenHev '
111
+ '> 0']],
112
+ 'description': 'HV battery cooling request',
113
+ 'handle': 'VcPpmPsm/VcPpmPsm/Subsystem/'
114
+ 'VcPpmPsm/yVcBec_B_ChillerCoolReq',
115
+ 'lsb': 1,
116
+ 'max': 3,
117
+ 'min': 0,
118
+ 'name': 'sVcBec_D_HvBattCoolgReq',
119
+ 'offset': 0,
120
+ 'type': 'UInt8',
121
+ 'unit': '-'}
122
+ }
123
+
124
+ """
125
+ res = {}
126
+ self.debug('_filter_io_nvm_feat: Feature Cfg')
127
+ for unit in self._build_prj_config.get_included_units():
128
+ self._filter_io_nvm_feat_unit(unit, res)
129
+ if not res:
130
+ self.warning('No units configured for project')
131
+ return res
132
+
133
+ def _filter_core_config(self, u_def_data):
134
+ """Handle core configs."""
135
+ f_core = {}
136
+ for core_type, core_data in u_def_data.items():
137
+ f_core[core_type] = {}
138
+ for key, value in core_data.items():
139
+ if key != 'IllegalBlk':
140
+ # Matlab sets core:{type:{name:{API_blk:[{path, config}]}}}
141
+ # config.py - core:{type:{name:{configs}}}
142
+ configs = value.get('configs', [cfg for blk in value['API_blk'] for cfg in blk['config']])
143
+ if self._feature_cfg.check_if_active_in_config(configs):
144
+ f_core[core_type][key] = value
145
+ return f_core
146
+
147
+ def _filter_io_nvm_feat_unit(self, unit, res):
148
+ """Handle one unit config with respect to the filtering in :_filter_io_nvm_feat:."""
149
+ try:
150
+ u_data = self._raw_per_unit_configs[unit]
151
+ except KeyError:
152
+ # Some units in the raster should not have config files
153
+ if unit not in self.CONFIG_SKIP_LIST:
154
+ self.debug('_filter_io_nvm_feat_unit: cfg missing: %s', unit)
155
+ self._missing_configs.add(unit)
156
+ return
157
+ for u_def_type, u_def_data in u_data.items():
158
+ res.setdefault(unit, {}).setdefault(u_def_type, {})
159
+ if u_def_type == 'dids':
160
+ f_dids = {k: v for k, v in u_def_data.items()
161
+ if self._feature_cfg.check_if_active_in_config(v['configs'])}
162
+ res[unit][u_def_type] = f_dids
163
+ elif u_def_type == 'core':
164
+ res[unit][u_def_type] = self._filter_core_config(u_def_data)
165
+ elif u_def_type == 'pre_procs':
166
+ # the pre_proc key does not have configuration attributes
167
+ res[unit]['pre_procs'] = u_def_data
168
+ elif u_def_type == 'integrity_level':
169
+ res[unit]['integrity_level'] = u_def_data
170
+ elif u_def_type == 'code_generator':
171
+ res[unit]['code_generator'] = u_def_data
172
+ elif u_def_type == 'version':
173
+ res[unit]['version'] = u_def_data
174
+ elif u_def_type == 'csp':
175
+ csp_data = {}
176
+ if 'methods' in u_def_data:
177
+ csp_data = {'methods': {}}
178
+ for method_name, method_data in u_def_data['methods'].items():
179
+ if self._feature_cfg.check_if_active_in_config(method_data['configs']):
180
+ csp_data['methods'][method_name] = method_data
181
+ res[unit][u_def_type] = csp_data
182
+ elif u_def_type == 'includes':
183
+ # List of configs for handwritten code
184
+ for included_unit in u_def_data:
185
+ self.debug('%s includes %s', unit, included_unit)
186
+ self._filter_io_nvm_feat_unit(included_unit, res)
187
+ else:
188
+ for var, var_pars in u_def_data.items():
189
+ # TODO: remove this code when the bug in the matlab code is removed.
190
+ if var_pars['configs'] == []:
191
+ self.debug('Adding %s', unit)
192
+ self._empty_config_def.add((var, unit))
193
+ if self._feature_cfg.check_if_active_in_config(var_pars['configs']):
194
+ res[unit][u_def_type].setdefault(var, {}).update(var_pars)
195
+
196
+ @staticmethod
197
+ def _update_io_nvm(dict_, unit, data_type, variables):
198
+ """Change the struct for in out and nvm variables.
199
+
200
+ The resulting new struct is stored in the dict dict_
201
+ """
202
+ for var, var_pars in variables.items():
203
+ dict_.setdefault(data_type, {}).setdefault(var, {}).setdefault(unit, var_pars)
204
+
205
+ def _update_dids(self, unit, key, data, feat_cfg=None):
206
+ """Change the struct for in out and nvm variables."""
207
+ # TODO: Add functionality
208
+
209
+ @staticmethod
210
+ def _update_core(dict_, unit, data_type, core_ids):
211
+ """Change the struct for in core parameters."""
212
+ for _, core_data in core_ids.items():
213
+ for var, var_pars in core_data.items():
214
+ dict_.setdefault(data_type, {}).setdefault(var, {}).setdefault(unit, var_pars)
215
+
216
+ def _update_pre_procs(self, unit, key, data, feat_cfg=None):
217
+ """Change the struct for in pre_processor parameters."""
218
+ # TODO: Add functionality
219
+
220
+ def _per_type_unit_signals(self):
221
+ """Change the structure of the data to aggregate all unit configs.
222
+
223
+ Returns:
224
+ dict: a structure per config type instead of per unit
225
+
226
+ """
227
+ # loop over all projects and store the active items in each configuration
228
+ self._per_unit_configs = self._filter_io_nvm_feat()
229
+ dict_ = self._per_type_unit_configs = {}
230
+ for unit, udata in self._per_unit_configs.items():
231
+ for data_type, variables in udata.items():
232
+ if data_type in ['core']:
233
+ self._update_core(dict_, unit, data_type, variables)
234
+ elif data_type in ['dids']:
235
+ self._update_dids(dict_, unit, data_type, variables)
236
+ elif data_type in ['pre_procs']:
237
+ self._update_pre_procs(dict_, unit, data_type, variables)
238
+ elif data_type in ['outports', 'inports', 'dids', 'nvm', 'local_vars', 'calib_consts', 'csp']:
239
+ self._update_io_nvm(dict_, unit, data_type, variables)
240
+ else:
241
+ dict_.setdefault(data_type, {}).setdefault(unit, udata)
242
+
243
+ def check_if_in_unit_cfg(self, unit, symbol):
244
+ """Check if the symbol is defined in the unit config file."""
245
+ for data in self._raw_per_unit_configs[unit].values():
246
+ if isinstance(data, dict):
247
+ if symbol in data:
248
+ return True
249
+ return False
250
+
251
+ def get_per_cfg_unit_cfg(self):
252
+ """Get all io-signals and core-ids for all units.
253
+
254
+ Get all io-signals and core-ids for all units, where all inports, outport, etc,
255
+ are aggregated from all unit definition files.
256
+
257
+ Returns:
258
+ dict: a dict with the below format::
259
+
260
+ {
261
+ 'inports/outports/nvm/core': {
262
+ 'VARIABLE_NAME': {
263
+ 'UNIT_NAME': {
264
+ 'class': 'CVC_EXT',
265
+ 'configs': [['all']],
266
+ 'description': 'Power Pulse ',
267
+ 'handle': 'VcPemAlc/VcPemAlc/Subsystem/VcPemAlc/yVcVmcPmm_B_SsActive9',
268
+ 'lsb': 1,
269
+ 'max': 800,
270
+ 'min': 0,
271
+ 'name': 'sVcAesPp_Pw_PwrPls',
272
+ 'offset': 0,
273
+ 'type': 'UInt16',
274
+ 'unit': 'W'
275
+ }
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ The top level keys are 'inports', 'outports', 'nvm' and 'core'
282
+
283
+ """
284
+ return self._per_type_unit_configs
285
+
286
+ def check_if_in_per_cfg_unit_cfg(self, cfg, symbol):
287
+ """Check if the symbol is defined in the aggregated unit config files."""
288
+ return (
289
+ cfg in self._per_type_unit_configs and
290
+ symbol in self._per_type_unit_configs[cfg])
291
+
292
+ def get_per_unit_cfg(self):
293
+ """Get io-signals for all units, per unit, for a given project.
294
+
295
+ If 'all' is given as a project, all signals, regardless of configuration,
296
+ is returned.
297
+
298
+ Returns:
299
+ dict: a dict with the below format::
300
+
301
+ {'NAME_OF_UNIT': {
302
+ 'core': {'Events': {},
303
+ 'FIDs': {},
304
+ 'IUMPR': {},
305
+ 'Ranking': {},
306
+ 'TstId': {}},
307
+ 'dids': {},
308
+ 'inports': {'VARIABLE_NAME': {'class': 'CVC_DISP',
309
+ 'configs': [['all']],
310
+ 'description': 'Torque '
311
+ 'arbitraion '
312
+ 'state',
313
+ 'handle': 'VcPemAlc/VcPemAlc/...',
314
+ 'lsb': 1,
315
+ 'max': 9,
316
+ 'min': 0,
317
+ 'name': 'rVcPemAlc_D_AuxLoadEvent',
318
+ 'offset': 0,
319
+ 'type': 'UInt8',
320
+ 'unit': '-'}
321
+ },
322
+ 'outports' : {},
323
+ 'nvm' : {}
324
+ }
325
+ }
326
+
327
+ """
328
+ return self._per_unit_configs
329
+
330
+ def get_per_unit_cfg_total(self):
331
+ """Get total io-signals configuration for all units, per unit, for a given project.
332
+
333
+ Does not remove signals disabled by code switches.
334
+
335
+ Returns:
336
+ dict: a dict with the below format::
337
+
338
+ {'NAME_OF_UNIT': {
339
+ 'core': {'Events': {},
340
+ 'FIDs': {},
341
+ 'IUMPR': {},
342
+ 'Ranking': {},
343
+ 'TstId': {}},
344
+ 'dids': {},
345
+ 'inports': {'VARIABLE_NAME': {'class': 'CVC_DISP',
346
+ 'configs': [['all']],
347
+ 'description': 'Torque '
348
+ 'arbitraion '
349
+ 'state',
350
+ 'handle': 'VcPemAlc/VcPemAlc/...',
351
+ 'lsb': 1,
352
+ 'max': 9,
353
+ 'min': 0,
354
+ 'name': 'rVcPemAlc_D_AuxLoadEvent',
355
+ 'offset': 0,
356
+ 'type': 'UInt8',
357
+ 'unit': '-'}
358
+ },
359
+ 'outports' : {},
360
+ 'nvm' : {}
361
+ }
362
+ }
363
+
364
+ """
365
+ res = {}
366
+ for unit in self._build_prj_config.get_included_units():
367
+ try:
368
+ res[unit] = self._raw_per_unit_configs[unit]
369
+ except KeyError:
370
+ continue
371
+ return res
372
+
373
+ def get_unit_config(self, unit):
374
+ """Get config for a unit.
375
+
376
+ Arguments:
377
+ unit (str): Unit to get config for
378
+ """
379
+ return self._raw_per_unit_configs[unit]
380
+
381
+ @staticmethod
382
+ def get_base_name(unit):
383
+ """Get base name of unit."""
384
+ return unit.partition('__')[0]
385
+
386
+ def get_unit_code_generator(self, unit):
387
+ """Get code generator for a given a unit (model).
388
+
389
+ Args:
390
+ unit (str): Current unit/model name.
391
+ Returns:
392
+ code_generator (str): Code generator used for given model.
393
+ """
394
+ per_unit_cfg = self.get_per_unit_cfg()
395
+ if unit in per_unit_cfg and 'code_generator' in per_unit_cfg[unit]:
396
+ code_generator = per_unit_cfg[unit]['code_generator']
397
+ else:
398
+ # Default to target_link
399
+ code_generator = CodeGenerators.target_link
400
+ return code_generator
401
+
402
+ def _get_code_generators(self):
403
+ per_unit_cfg = self.get_per_unit_cfg()
404
+ code_generators = set()
405
+ for _, config in per_unit_cfg.items():
406
+ if 'code_generator' in config:
407
+ code_generators.add(config['code_generator'])
408
+ else:
409
+ # Default to target_link
410
+ code_generators.add(CodeGenerators.target_link)
411
+ return code_generators
412
+
413
+ def _get_base_types_headers(self):
414
+ general_includes = ''
415
+ if CodeGenerators.embedded_coder in self.code_generators:
416
+ general_includes += '#include "rtwtypes.h"\n'
417
+ if CodeGenerators.target_link in self.code_generators:
418
+ general_includes += '#include "tl_basetypes.h"\n'
419
+ return general_includes