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,690 +1,690 @@
1
- # Copyright 2024 Volvo Car Corporation
2
- # Licensed under Apache 2.0.
3
-
4
- # -*- coding: utf-8 -*-
5
- """Module used to read project and base configuration files and provides methods for abstraction."""
6
-
7
- import glob
8
- import json
9
- import os
10
- import shutil
11
- import pathlib
12
- from pprint import pformat
13
-
14
- from powertrain_build.lib.helper_functions import deep_dict_update
15
- from powertrain_build.versioncheck import Version
16
-
17
-
18
- class BuildProjConfig:
19
- """A class holding build project configurations."""
20
-
21
- def __init__(self, prj_config_file):
22
- """Read project configuration file to internal an representation.
23
-
24
- Args:
25
- prj_config_file (str): Project config filename
26
- """
27
- super().__init__()
28
- self._prj_cfg_file = prj_config_file
29
- prj_root_dir, _ = os.path.split(prj_config_file)
30
- self._prj_root_dir = os.path.abspath(prj_root_dir)
31
-
32
- with open(prj_config_file, 'r', encoding="utf-8") as pcfg:
33
- self._prj_cfg = json.load(pcfg)
34
- if not Version.is_compatible(self._prj_cfg.get('ConfigFileVersion')):
35
- raise ValueError('Incompatible project config file version.')
36
- # Load a basic config that can be common for several projects
37
- # the local config overrides the base config
38
- if 'BaseConfig' in self._prj_cfg:
39
- fil_tmp = os.path.join(prj_root_dir, self._prj_cfg['BaseConfig'])
40
- fil_ = os.path.abspath(fil_tmp)
41
- with open(fil_, 'r', encoding="utf-8") as bcfg:
42
- base_cnfg = json.load(bcfg)
43
- deep_dict_update(self._prj_cfg, base_cnfg)
44
- if not Version.is_compatible(self._prj_cfg.get('BaseConfigFileVersion')):
45
- raise ValueError('Incompatible base config file version.')
46
- deep_dict_update(self._prj_cfg, self._get_code_generation_config())
47
- self._composition_config = self._parse_composition_config(self._prj_cfg.get('CompositionConfig', {}))
48
- self.has_yaml_interface = self._prj_cfg['ProjectInfo'].get('yamlInterface', False)
49
- self.device_domains = self._get_device_domains()
50
- self.services_file = self._get_services_file()
51
- self._load_unit_configs()
52
- self._add_global_const_file()
53
- self._all_units = []
54
- self._calc_all_units()
55
- self.name = self._prj_cfg['ProjectInfo']['projConfig']
56
- self.allow_undefined_unused = self._prj_cfg['ProjectInfo'].get('allowUndefinedUnused', True)
57
- self._scheduler_prefix = self._prj_cfg['ProjectInfo'].get('schedulerPrefix', '')
58
- if self._scheduler_prefix:
59
- self._scheduler_prefix = self._scheduler_prefix + '_'
60
-
61
- def __repr__(self):
62
- """Get string representation of object."""
63
- return pformat(self._prj_cfg['ProjectInfo'])
64
-
65
- def _get_default_code_generation_config(self):
66
- return {
67
- 'generalAsilLevelDebug': 'B',
68
- 'generalAsilLevelDependability': 'B',
69
- 'generateCalibrationInterfaceFiles': False,
70
- 'useCalibrationRteMacroExpansion': False,
71
- 'generateCoreDummy': False,
72
- 'generateDummyVar': False,
73
- 'generateInterfaceHeaders': False,
74
- 'rteCheckpointIdSize': None,
75
- 'customRteCheckpointEntityName': 'AR_{raster}_CheckpointReached',
76
- 'generateYamlInterfaceFile': False,
77
- 'includeAllEnums': False,
78
- 'mapToRteEnums': False,
79
- 'propagateTagName': False,
80
- 'useA2lSymbolLinks': False,
81
- 'useRteNvmStructs': False,
82
- 'useCamelCaseForNvmVariables': False
83
- }
84
-
85
- def _get_code_generation_config(self):
86
- """ Get code generation configuration.
87
-
88
- Anything already set in CodeGenerationConfig in ProjectCfg.json takes priority.
89
- If there is a project template for the ECU supplier, those values are used,
90
- unless already set in ProjectCfg.json.
91
- Finally, default values are inserted for missing keys.
92
-
93
- Args:
94
- item (str): Item to get from the configuration. If None, the whole configuration is returned.
95
- Returns:
96
- (dict): Code generation configuration.
97
- """
98
- code_generation_configuration = {}
99
- ecu_supplier = self.get_ecu_info()[0]
100
- deep_dict_update(code_generation_configuration, self._prj_cfg.get('ProjectTemplates', {}).get(ecu_supplier, {}))
101
- deep_dict_update(code_generation_configuration, self._get_default_code_generation_config())
102
- return {'CodeGenerationConfig': code_generation_configuration}
103
-
104
- def _get_device_domains(self):
105
- file_name = self._prj_cfg['ProjectInfo'].get('deviceDomains')
106
- full_path = pathlib.Path(self._prj_root_dir, file_name)
107
- if full_path.is_file():
108
- with open(full_path, 'r', encoding="utf-8") as device_domains:
109
- return json.loads(device_domains.read())
110
- return {}
111
-
112
- def _get_services_file(self):
113
- file_name = self._prj_cfg['ProjectInfo'].get('serviceInterfaces', '')
114
- full_path = pathlib.Path(self._prj_root_dir, file_name)
115
- return full_path
116
-
117
- @staticmethod
118
- def get_services(services_file):
119
- """Get the services from the services file.
120
-
121
- Args:
122
- services_file (pathlib.Path): The services file.
123
-
124
- Returns:
125
- (dict): The services.
126
- """
127
- if services_file.is_file():
128
- with services_file.open() as services:
129
- return json.loads(services.read())
130
- return {}
131
-
132
- def _load_unit_configs(self):
133
- """Load Unit config json file.
134
-
135
- This file contains which units are included in which projects.
136
- """
137
- if 'UnitCfgs' in self._prj_cfg:
138
- fil_tmp = os.path.join(self._prj_root_dir, self._prj_cfg['UnitCfgs'])
139
- with open(fil_tmp, 'r', encoding="utf-8") as fpr:
140
- tmp_unit_cfg = json.load(fpr)
141
- sample_times = tmp_unit_cfg.pop('SampleTimes')
142
- self._unit_cfg = {
143
- 'Rasters': tmp_unit_cfg,
144
- 'SampleTimes': sample_times
145
- }
146
- else:
147
- raise ValueError('UnitCfgs is not specified in project config')
148
-
149
- def _add_global_const_file(self):
150
- """Add the global constants definition to the 'not_scheduled' time raster."""
151
- ugc = self.get_use_global_const()
152
- if ugc:
153
- self._unit_cfg['Rasters'].setdefault('NoSched', []).append(ugc)
154
-
155
- def create_build_dirs(self):
156
- """Create the necessary output build dirs if they are missing.
157
-
158
- Clear the output build dirs if they exist.
159
- """
160
- src_outp = self.get_src_code_dst_dir()
161
- if os.path.exists(src_outp):
162
- shutil.rmtree(src_outp)
163
- os.makedirs(src_outp)
164
-
165
- log_outp = self.get_log_dst_dir()
166
- if os.path.exists(log_outp):
167
- shutil.rmtree(log_outp)
168
- os.makedirs(log_outp)
169
-
170
- rep_outp = self.get_reports_dst_dir()
171
- if os.path.exists(rep_outp):
172
- shutil.rmtree(rep_outp)
173
- os.makedirs(rep_outp)
174
-
175
- unit_cfg_outp = self.get_unit_cfg_deliv_dir()
176
- if os.path.exists(unit_cfg_outp):
177
- shutil.rmtree(unit_cfg_outp)
178
- if unit_cfg_outp is not None:
179
- os.makedirs(unit_cfg_outp)
180
-
181
- def get_code_generation_config(self, item=None):
182
- """ Get code generation configuration.
183
-
184
- Args:
185
- item (str): Item to get from the configuration. If None, the whole configuration is returned.
186
- Returns:
187
- (dict): Code generation configuration.
188
- """
189
- if item is not None:
190
- return self._prj_cfg['CodeGenerationConfig'].get(item, {})
191
- return self._prj_cfg['CodeGenerationConfig']
192
-
193
- def get_memory_map_config(self):
194
- """ Get memory map configuration.
195
-
196
- Returns:
197
- (dict): Memory map configuration.
198
- """
199
- return self._prj_cfg.get('MemoryMapConfig', {})
200
-
201
- def get_a2l_cfg(self):
202
- """ Get A2L configuration from A2lConfig.
203
-
204
- Returns:
205
- config (dict): A2L configuration
206
- """
207
- a2l_config = self._prj_cfg.get('A2lConfig', {})
208
- return {
209
- 'name': a2l_config.get('name', self._prj_cfg["ProjectInfo"]["projConfig"]),
210
- 'allow_kp_blob': a2l_config.get('allowKpBlob', True),
211
- 'ip_address': a2l_config.get('ipAddress', "169.254.4.10"),
212
- 'ip_port': '0x%X' % a2l_config.get('ipPort', 30000),
213
- 'asap2_version': a2l_config.get('asap2Version', "1 51")
214
- }
215
-
216
- def get_enable_end_to_end_status_signals(self):
217
- """Get the enable end-to-end status signals configuration.
218
-
219
- NOTE: Only appicable for device proxy type signal interfaces.
220
-
221
- Returns:
222
- (bool): True if end-to-end status signals are enabled, False otherwise.
223
- """
224
- return self._prj_cfg['ProjectInfo'].get('enableEndToEndStatusSignals', False)
225
-
226
- def get_unit_cfg_deliv_dir(self):
227
- """Get the directory where to put the unit configuration files.
228
-
229
- If this key is undefined, or set to None, the unit-configs will
230
- not be copied to the output folder.
231
-
232
- Returns:
233
- A path to the unit deliver dir, or None
234
-
235
- """
236
- if 'unitCfgDeliveryDir' in self._prj_cfg['ProjectInfo']:
237
- return os.path.join(self.get_root_dir(),
238
- os.path.normpath(self._prj_cfg['ProjectInfo']
239
- ['unitCfgDeliveryDir']))
240
- return None
241
-
242
- def get_root_dir(self):
243
- """Get the root directory of the project.
244
-
245
- Returns:
246
- A path to the project root (with wildcards)
247
-
248
- """
249
- return self._prj_root_dir
250
-
251
- def get_src_code_dst_dir(self):
252
- """Return the absolute path to the source output folder."""
253
- return os.path.join(self.get_root_dir(),
254
- os.path.normpath(self._prj_cfg['ProjectInfo']
255
- ['srcCodeDstDir']))
256
-
257
- def _parse_composition_config(self, file_config):
258
- """Parse the composition configuration from project config."""
259
- composition_config = {
260
- 'compositionName': None,
261
- 'compositionEnding': 'yml',
262
- 'compositionArxml': file_config.get("compositionArxml", None),
263
- 'customYamlInitFunctionName': file_config.get("customYamlInitFunctionName", None),
264
- 'customYamlStepFunctionName': file_config.get("customYamlStepFunctionName", None),
265
- 'generateExternalImplementationType': file_config.get("generateExternalImplementationType", True),
266
- 'softwareComponentName': file_config.get("softwareComponentName", self.get_a2l_cfg()['name']),
267
- 'asil': file_config.get('asil', 'QM'),
268
- 'secure': file_config.get('secure', False),
269
- 'includeStatic': file_config.get('includeStatic', True),
270
- 'includeShared': file_config.get('includeShared', True),
271
- 'includeSharedSwAddrMethod': file_config.get('includeSharedSwAddrMethod', None),
272
- 'includeDiagnostics': file_config.get('includeDiagnostics', True),
273
- 'includeNvm': file_config.get('includeNvm', True),
274
- 'scaleMapsAndCurves': file_config.get('scaleMapsAndCurves', True),
275
- }
276
- composition_name = file_config.get("compositionName", None)
277
- if composition_name is not None:
278
- composition_config["compositionName"] = composition_name.split(".")[0]
279
- if "." in composition_name:
280
- composition_config["compositionEnding"] = composition_name.split(".")[1]
281
- return composition_config
282
-
283
- def get_composition_config(self, key=None):
284
- """Get the composition configuration from project config."""
285
- if key is None:
286
- return self._composition_config
287
- return self._composition_config[key]
288
-
289
- def get_car_com_dst(self):
290
- """Return the absolute path to the source output folder."""
291
- return os.path.join(self.get_root_dir(),
292
- os.path.normpath(self._prj_cfg['ProjectInfo']
293
- ['didCarCom']))
294
-
295
- def get_reports_dst_dir(self):
296
- """Get the destination dir for build reports.
297
-
298
- Returns:
299
- A path to the report files destination directory (with wildcards)
300
-
301
- """
302
- return os.path.join(self.get_root_dir(),
303
- os.path.normpath(self._prj_cfg['ProjectInfo']
304
- ['reportDstDir']))
305
-
306
- def get_all_reports_dst_dir(self):
307
- """Get the destination dir for build reports.
308
-
309
- Returns:
310
- A path to the report files destination directory (for all projects)
311
-
312
- """
313
- return os.path.join(self.get_root_dir(), "..", "..", "Reports")
314
-
315
- def get_log_dst_dir(self):
316
- """Return the absolute path to the log output folder.
317
-
318
- Returns:
319
- A path to the log files destination directory (with wildcards)
320
-
321
- """
322
- return os.path.join(self.get_root_dir(),
323
- os.path.normpath(self._prj_cfg['ProjectInfo']
324
- ['logDstDir']))
325
-
326
- def get_core_dummy_name(self):
327
- """Return the file name of the core dummy file from the config file.
328
-
329
- Returns:
330
- A file name for the core dummy files
331
-
332
- """
333
- path = os.path.join(self.get_src_code_dst_dir(),
334
- os.path.normpath(self._prj_cfg['ProjectInfo']
335
- ['coreDummyFileName']))
336
- return path
337
-
338
- def get_feature_conf_header_name(self):
339
- """Return the feature configuration header file name.
340
-
341
- Returns:
342
- A file name for the feature config header file
343
-
344
- """
345
- return self._prj_cfg['ProjectInfo']['featureHeaderName']
346
-
347
- def get_ts_header_name(self):
348
- """Return the name of the ts header file, defined in the config file.
349
-
350
- Returns:
351
- The file name of the file defining all unit raster times
352
-
353
- """
354
- return self._prj_cfg['ProjectInfo']['tsHeaderName']
355
-
356
- def get_included_units(self):
357
- """Return a list of all the included units in the project.
358
-
359
- TODO:Consider moving this to the Feature Configs class if we start
360
- using our configuration tool for model inclusion and scheduling
361
- TODO:Consider calculate this on init and storing the result in the
362
- class. this method would the just return the stored list.
363
- """
364
- units_dict = self._unit_cfg['Rasters']
365
- units = []
366
- for unit in units_dict.values():
367
- units.extend(unit)
368
- return units
369
-
370
- def get_included_common_files(self):
371
- """Return a list of all the included common files in the project.
372
-
373
- Returns:
374
- included_common_files ([str]): The names of the common files which are included in the project.
375
-
376
- """
377
- return self._prj_cfg.get('includedCommonFiles', [])
378
-
379
- def _calc_all_units(self):
380
- """Return a list of all the units."""
381
- units = set()
382
- for runits in self._unit_cfg['Rasters'].values():
383
- units = units.union(set(runits))
384
- self._all_units = list(units)
385
-
386
- def get_includes_paths_flat(self):
387
- """Return list of paths to files to be included flat in source directory."""
388
- includes_paths = self._prj_cfg.get('includesPaths', [])
389
- return [os.path.join(self.get_root_dir(), os.path.normpath(path)) for path in includes_paths]
390
-
391
- def get_includes_paths_tree(self):
392
- """Return list of paths to files to included with directories in source directory."""
393
- includes_paths_tree = self._prj_cfg.get('includesPathsTree', [])
394
- return [os.path.join(self.get_root_dir(), os.path.normpath(path)) for path in includes_paths_tree]
395
-
396
- def get_all_units(self):
397
- """Return a list of all the units."""
398
- return self._all_units
399
-
400
- def get_prj_cfg_dir(self):
401
- """Return the directory containing the project configuration files.
402
-
403
- Returns:
404
- An absolute path to the project configuration files
405
-
406
- """
407
- return os.path.join(self._prj_root_dir,
408
- self._prj_cfg['ProjectInfo']['configDir'])
409
-
410
- def get_scheduler_prefix(self):
411
- """Returns a prefix used to distinguish function calls in one project from
412
- similarly named functions in other projects, when linked/compiled together
413
-
414
- Returns:
415
- scheduler_prefix (string): prefix for scheduler functions.
416
- """
417
- return self._scheduler_prefix
418
-
419
- def get_local_defs_name(self):
420
- """Return a string which defines the file name of local defines.
421
-
422
- Returns:
423
- A string containing the wildcard file name local defines
424
-
425
- """
426
- return self._prj_cfg['ProjectInfo']['prjLocalDefs']
427
-
428
- def get_codeswitches_name(self):
429
- """Return a string which defines the file name of code switches.
430
-
431
- Returns:
432
- A string containing the wildcard file name code switches
433
-
434
- """
435
- return self._prj_cfg['ProjectInfo']['prjCodeswitches']
436
-
437
- def get_did_cfg_file_name(self):
438
- """Return the did definition file name.
439
-
440
- Returns:
441
- DID definition file name
442
-
443
- """
444
- return self._prj_cfg['ProjectInfo']['didDefFile']
445
-
446
- def get_prj_config(self):
447
- """Get the project configuration name from the config file.
448
-
449
- Returns:
450
- Project config name
451
-
452
- """
453
- return self._prj_cfg['ProjectInfo']["projConfig"]
454
-
455
- def get_a2l_name(self):
456
- """Get the name of the a2l-file, which the build system shall generate."""
457
- return self._prj_cfg['ProjectInfo']['a2LFileName']
458
-
459
- def get_ecu_info(self):
460
- """Return ecuSupplier and ecuType.
461
-
462
- Returns:
463
- (ecuSupplier, ecuType)
464
- """
465
- return (
466
- self._prj_cfg['ProjectInfo'].get('ecuSupplier', None),
467
- self._prj_cfg['ProjectInfo'].get('ecuType', '')
468
- )
469
-
470
- def get_xcp_enabled(self):
471
- """Return True/False whether XCP is enabled in the project or not.
472
-
473
- Returns:
474
- (bool): True/False whether XCP is enabled in the project or not
475
-
476
- """
477
- return self._prj_cfg['ProjectInfo'].get('enableXcp', True)
478
-
479
- def get_nvm_defs(self):
480
- """Return NVM-ram block definitions.
481
-
482
- The definitions contains the sizes of the six NVM areas
483
- which are defined in the build-system.
484
-
485
- Returns:
486
- NvmConfig dict from config file.
487
-
488
- """
489
- return self._prj_cfg['NvmConfig']
490
-
491
- def _get_inc_dirs(self, path):
492
- """Get the dirs with the models defined in the units config file.
493
-
494
- Model name somewhere in the path.
495
- """
496
- all_dirs = glob.glob(path)
497
- inc_units = self.get_included_units()
498
- psep = os.path.sep
499
- out = {}
500
- for dir_ in all_dirs:
501
- folders = dir_.split(psep)
502
- for inc_unit in inc_units:
503
- if inc_unit in folders:
504
- out.update({inc_unit: dir_})
505
- break
506
- return out
507
-
508
- def get_units_raster_cfg(self):
509
- """Get the units' scheduling raster config.
510
-
511
- I.e. which units are included, and in which
512
- rasters they are scheduled, and in which order.
513
-
514
- Returns:
515
- A dict in the following format.
516
-
517
- ::
518
-
519
- {
520
- "SampleTimes": {
521
- "NameOfRaster": scheduling time},
522
- "Rasters": {
523
- "NameOfRaster": [
524
- "NameOfFunction",
525
- ...],
526
- ...}
527
- }
528
-
529
- Example::
530
-
531
- {
532
- "SampleTimes": {
533
- "Vc10ms": 0.01,
534
- "Vc40ms": 0.04},
535
- "Rasters": {
536
- "Vc10ms": [
537
- "VcPpmImob",
538
- "VcPpmPsm",
539
- "VcPpmRc",
540
- "VcPpmSt",
541
- "VcPemAlc"],
542
- "Vc40ms": [
543
- "VcRegCh"]
544
- }
545
-
546
- """
547
- return self._unit_cfg
548
-
549
- def get_unit_cfg_dirs(self):
550
- """Get config dirs which matches the project config parameter prjUnitCfgDir.
551
-
552
- Furthermore, they should be included in the unit definition for this project
553
-
554
- Returns:
555
- A list with absolute paths to all unit config dirs
556
- included in the project
557
-
558
- """
559
- path = os.path.join(self.get_root_dir(),
560
- os.path.normpath(self._prj_cfg['ProjectInfo']
561
- ['prjUnitCfgDir']))
562
- return self._get_inc_dirs(path)
563
-
564
- def get_translation_files_dirs(self):
565
- """Get translation files directories, specified as a path regex in project
566
- config by key prjTranslationDir. If key is not present, will fall back to
567
- prjUnitCfgDir.
568
-
569
- Returns:
570
- A dictionary with absolute paths to all translation file dirs included
571
- in the project
572
- """
573
-
574
- if "prjTranslationDir" not in self._prj_cfg['ProjectInfo']:
575
- return self.get_unit_cfg_dirs()
576
-
577
- normpath_dir = os.path.normpath(self._prj_cfg['ProjectInfo']['prjTranslationDir'])
578
- path = os.path.join(self.get_root_dir(), normpath_dir)
579
-
580
- all_dirs = glob.glob(path)
581
- translation_dirs = {}
582
- for directory in all_dirs:
583
- file = pathlib.Path(directory).stem
584
- translation_dirs[file] = directory
585
- return translation_dirs
586
-
587
- def get_common_src_dir(self):
588
- """Get source dir which matches the project config parameter commonSrcDir.
589
-
590
- Returns:
591
- Absolute path to common source dir
592
-
593
- """
594
- return os.path.join(self.get_root_dir(),
595
- os.path.normpath(self._prj_cfg['ProjectInfo']['commonSrcDir']))
596
-
597
- def get_unit_src_dirs(self):
598
- """Get source dirs which matches the project config parameter prjUnitCfgDir.
599
-
600
- Furthermore, they should be included in the unit definition for this project
601
-
602
- Returns:
603
- A list with absolute paths to all source dirs included in the
604
- project
605
-
606
- """
607
- path = os.path.join(self.get_root_dir(),
608
- os.path.normpath(self._prj_cfg['ProjectInfo']
609
- ['prjUnitSrcDir']))
610
- return self._get_inc_dirs(path)
611
-
612
- def get_unit_mdl_dirs(self):
613
- """Get source dirs which matches the project config parameter prjUnitCfgDir.
614
-
615
- Furthermore, they should be included in the unit definition for this project
616
-
617
- Returns:
618
- A list with absolute paths to all model dirs included in the
619
- project
620
-
621
- """
622
- path = os.path.join(self.get_root_dir(),
623
- os.path.normpath(self._prj_cfg['ProjectInfo']
624
- ['prjUnitMdlDir']))
625
- return self._get_inc_dirs(path)
626
-
627
- def get_use_global_const(self):
628
- """Get the name of the global constant module."""
629
- return self._prj_cfg['ProjectInfo']['useGlobalConst']
630
-
631
- def get_use_volatile_globals(self):
632
- """Get if global variables should be defined as volatile or not."""
633
- if 'useVolatileGlobals' in self._prj_cfg['ProjectInfo']:
634
- return self._prj_cfg['ProjectInfo']['useVolatileGlobals']
635
- return False
636
-
637
- def get_use_custom_dummy_spm(self):
638
- """Get path to file defining missing internal variables, if any.
639
-
640
- This file will be used instead of generating VcDummy_spm.c,
641
- to make it easier to maintain missing internal signals.
642
-
643
- Returns:
644
- customDummySpm (os.path): An absolute path to the custom dummy spm file, if existent.
645
- """
646
- if 'customDummySpm' in self._prj_cfg['ProjectInfo']:
647
- return os.path.join(
648
- self.get_root_dir(),
649
- os.path.normpath(self._prj_cfg['ProjectInfo']['customDummySpm'])
650
- )
651
- return None
652
-
653
- def get_use_custom_sources(self):
654
- """Get path to files with custom handwritten sourcecode, if any.
655
-
656
- Returns:
657
- customSources (os.path): A list of absolute paths to custom sources, if existent.
658
- """
659
- if 'customSources' in self._prj_cfg['ProjectInfo']:
660
- normalized_paths = (os.path.normpath(p) for p in self._prj_cfg['ProjectInfo']['customSources'])
661
- return [os.path.join(self.get_root_dir(), p) for p in normalized_paths]
662
- return None
663
-
664
- def get_if_cfg_dir(self):
665
- """Return the directory containing the interface configuration files.
666
-
667
- Returns:
668
- An absolute path to the interface configuration files
669
-
670
- """
671
- return os.path.join(self._prj_root_dir,
672
- self._prj_cfg['ProjectInfo']['interfaceCfgDir'])
673
-
674
- def get_enum_def_dir(self):
675
- """Get path to dir containing simulink enumeration definitions, if any.
676
-
677
- Returns:
678
- enumDefDir (os.path): An absolute path to the simulink enumerations, if existent.
679
- """
680
- if 'enumDefDir' in self._prj_cfg['ProjectInfo']:
681
- return os.path.join(
682
- self.get_root_dir(),
683
- os.path.normpath(self._prj_cfg['ProjectInfo']['enumDefDir'])
684
- )
685
- return None
686
-
687
-
688
- if __name__ == '__main__':
689
- # Function for testing the module
690
- BPC = BuildProjConfig('../../ProjectCfg.json')
1
+ # Copyright 2024 Volvo Car Corporation
2
+ # Licensed under Apache 2.0.
3
+
4
+ # -*- coding: utf-8 -*-
5
+ """Module used to read project and base configuration files and provides methods for abstraction."""
6
+
7
+ import glob
8
+ import json
9
+ import os
10
+ import shutil
11
+ import pathlib
12
+ from pprint import pformat
13
+
14
+ from powertrain_build.lib.helper_functions import deep_dict_update
15
+ from powertrain_build.versioncheck import Version
16
+
17
+
18
+ class BuildProjConfig:
19
+ """A class holding build project configurations."""
20
+
21
+ def __init__(self, prj_config_file):
22
+ """Read project configuration file to internal an representation.
23
+
24
+ Args:
25
+ prj_config_file (str): Project config filename
26
+ """
27
+ super().__init__()
28
+ self._prj_cfg_file = prj_config_file
29
+ prj_root_dir, _ = os.path.split(prj_config_file)
30
+ self._prj_root_dir = os.path.abspath(prj_root_dir)
31
+
32
+ with open(prj_config_file, 'r', encoding="utf-8") as pcfg:
33
+ self._prj_cfg = json.load(pcfg)
34
+ if not Version.is_compatible(self._prj_cfg.get('ConfigFileVersion')):
35
+ raise ValueError('Incompatible project config file version.')
36
+ # Load a basic config that can be common for several projects
37
+ # the local config overrides the base config
38
+ if 'BaseConfig' in self._prj_cfg:
39
+ fil_tmp = os.path.join(prj_root_dir, self._prj_cfg['BaseConfig'])
40
+ fil_ = os.path.abspath(fil_tmp)
41
+ with open(fil_, 'r', encoding="utf-8") as bcfg:
42
+ base_cnfg = json.load(bcfg)
43
+ deep_dict_update(self._prj_cfg, base_cnfg)
44
+ if not Version.is_compatible(self._prj_cfg.get('BaseConfigFileVersion')):
45
+ raise ValueError('Incompatible base config file version.')
46
+ deep_dict_update(self._prj_cfg, self._get_code_generation_config())
47
+ self._composition_config = self._parse_composition_config(self._prj_cfg.get('CompositionConfig', {}))
48
+ self.has_yaml_interface = self._prj_cfg['ProjectInfo'].get('yamlInterface', False)
49
+ self.device_domains = self._get_device_domains()
50
+ self.services_file = self._get_services_file()
51
+ self._load_unit_configs()
52
+ self._add_global_const_file()
53
+ self._all_units = []
54
+ self._calc_all_units()
55
+ self.name = self._prj_cfg['ProjectInfo']['projConfig']
56
+ self.allow_undefined_unused = self._prj_cfg['ProjectInfo'].get('allowUndefinedUnused', True)
57
+ self._scheduler_prefix = self._prj_cfg['ProjectInfo'].get('schedulerPrefix', '')
58
+ if self._scheduler_prefix:
59
+ self._scheduler_prefix = self._scheduler_prefix + '_'
60
+
61
+ def __repr__(self):
62
+ """Get string representation of object."""
63
+ return pformat(self._prj_cfg['ProjectInfo'])
64
+
65
+ def _get_default_code_generation_config(self):
66
+ return {
67
+ 'generalAsilLevelDebug': 'B',
68
+ 'generalAsilLevelDependability': 'B',
69
+ 'generateCalibrationInterfaceFiles': False,
70
+ 'useCalibrationRteMacroExpansion': False,
71
+ 'generateCoreDummy': False,
72
+ 'generateDummyVar': False,
73
+ 'generateInterfaceHeaders': False,
74
+ 'rteCheckpointIdSize': None,
75
+ 'customRteCheckpointEntityName': 'AR_{raster}_CheckpointReached',
76
+ 'generateYamlInterfaceFile': False,
77
+ 'includeAllEnums': False,
78
+ 'mapToRteEnums': False,
79
+ 'propagateTagName': False,
80
+ 'useA2lSymbolLinks': False,
81
+ 'useRteNvmStructs': False,
82
+ 'useCamelCaseForNvmVariables': False
83
+ }
84
+
85
+ def _get_code_generation_config(self):
86
+ """ Get code generation configuration.
87
+
88
+ Anything already set in CodeGenerationConfig in ProjectCfg.json takes priority.
89
+ If there is a project template for the ECU supplier, those values are used,
90
+ unless already set in ProjectCfg.json.
91
+ Finally, default values are inserted for missing keys.
92
+
93
+ Args:
94
+ item (str): Item to get from the configuration. If None, the whole configuration is returned.
95
+ Returns:
96
+ (dict): Code generation configuration.
97
+ """
98
+ code_generation_configuration = {}
99
+ ecu_supplier = self.get_ecu_info()[0]
100
+ deep_dict_update(code_generation_configuration, self._prj_cfg.get('ProjectTemplates', {}).get(ecu_supplier, {}))
101
+ deep_dict_update(code_generation_configuration, self._get_default_code_generation_config())
102
+ return {'CodeGenerationConfig': code_generation_configuration}
103
+
104
+ def _get_device_domains(self):
105
+ file_name = self._prj_cfg['ProjectInfo'].get('deviceDomains')
106
+ full_path = pathlib.Path(self._prj_root_dir, file_name)
107
+ if full_path.is_file():
108
+ with open(full_path, 'r', encoding="utf-8") as device_domains:
109
+ return json.loads(device_domains.read())
110
+ return {}
111
+
112
+ def _get_services_file(self):
113
+ file_name = self._prj_cfg['ProjectInfo'].get('serviceInterfaces', '')
114
+ full_path = pathlib.Path(self._prj_root_dir, file_name)
115
+ return full_path
116
+
117
+ @staticmethod
118
+ def get_services(services_file):
119
+ """Get the services from the services file.
120
+
121
+ Args:
122
+ services_file (pathlib.Path): The services file.
123
+
124
+ Returns:
125
+ (dict): The services.
126
+ """
127
+ if services_file.is_file():
128
+ with services_file.open() as services:
129
+ return json.loads(services.read())
130
+ return {}
131
+
132
+ def _load_unit_configs(self):
133
+ """Load Unit config json file.
134
+
135
+ This file contains which units are included in which projects.
136
+ """
137
+ if 'UnitCfgs' in self._prj_cfg:
138
+ fil_tmp = os.path.join(self._prj_root_dir, self._prj_cfg['UnitCfgs'])
139
+ with open(fil_tmp, 'r', encoding="utf-8") as fpr:
140
+ tmp_unit_cfg = json.load(fpr)
141
+ sample_times = tmp_unit_cfg.pop('SampleTimes')
142
+ self._unit_cfg = {
143
+ 'Rasters': tmp_unit_cfg,
144
+ 'SampleTimes': sample_times
145
+ }
146
+ else:
147
+ raise ValueError('UnitCfgs is not specified in project config')
148
+
149
+ def _add_global_const_file(self):
150
+ """Add the global constants definition to the 'not_scheduled' time raster."""
151
+ ugc = self.get_use_global_const()
152
+ if ugc:
153
+ self._unit_cfg['Rasters'].setdefault('NoSched', []).append(ugc)
154
+
155
+ def create_build_dirs(self):
156
+ """Create the necessary output build dirs if they are missing.
157
+
158
+ Clear the output build dirs if they exist.
159
+ """
160
+ src_outp = self.get_src_code_dst_dir()
161
+ if os.path.exists(src_outp):
162
+ shutil.rmtree(src_outp)
163
+ os.makedirs(src_outp)
164
+
165
+ log_outp = self.get_log_dst_dir()
166
+ if os.path.exists(log_outp):
167
+ shutil.rmtree(log_outp)
168
+ os.makedirs(log_outp)
169
+
170
+ rep_outp = self.get_reports_dst_dir()
171
+ if os.path.exists(rep_outp):
172
+ shutil.rmtree(rep_outp)
173
+ os.makedirs(rep_outp)
174
+
175
+ unit_cfg_outp = self.get_unit_cfg_deliv_dir()
176
+ if os.path.exists(unit_cfg_outp):
177
+ shutil.rmtree(unit_cfg_outp)
178
+ if unit_cfg_outp is not None:
179
+ os.makedirs(unit_cfg_outp)
180
+
181
+ def get_code_generation_config(self, item=None):
182
+ """ Get code generation configuration.
183
+
184
+ Args:
185
+ item (str): Item to get from the configuration. If None, the whole configuration is returned.
186
+ Returns:
187
+ (dict): Code generation configuration.
188
+ """
189
+ if item is not None:
190
+ return self._prj_cfg['CodeGenerationConfig'].get(item, {})
191
+ return self._prj_cfg['CodeGenerationConfig']
192
+
193
+ def get_memory_map_config(self):
194
+ """ Get memory map configuration.
195
+
196
+ Returns:
197
+ (dict): Memory map configuration.
198
+ """
199
+ return self._prj_cfg.get('MemoryMapConfig', {})
200
+
201
+ def get_a2l_cfg(self):
202
+ """ Get A2L configuration from A2lConfig.
203
+
204
+ Returns:
205
+ config (dict): A2L configuration
206
+ """
207
+ a2l_config = self._prj_cfg.get('A2lConfig', {})
208
+ return {
209
+ 'name': a2l_config.get('name', self._prj_cfg["ProjectInfo"]["projConfig"]),
210
+ 'allow_kp_blob': a2l_config.get('allowKpBlob', True),
211
+ 'ip_address': a2l_config.get('ipAddress', "169.254.4.10"),
212
+ 'ip_port': '0x%X' % a2l_config.get('ipPort', 30000),
213
+ 'asap2_version': a2l_config.get('asap2Version', "1 51")
214
+ }
215
+
216
+ def get_enable_end_to_end_status_signals(self):
217
+ """Get the enable end-to-end status signals configuration.
218
+
219
+ NOTE: Only appicable for device proxy type signal interfaces.
220
+
221
+ Returns:
222
+ (bool): True if end-to-end status signals are enabled, False otherwise.
223
+ """
224
+ return self._prj_cfg['ProjectInfo'].get('enableEndToEndStatusSignals', False)
225
+
226
+ def get_unit_cfg_deliv_dir(self):
227
+ """Get the directory where to put the unit configuration files.
228
+
229
+ If this key is undefined, or set to None, the unit-configs will
230
+ not be copied to the output folder.
231
+
232
+ Returns:
233
+ A path to the unit deliver dir, or None
234
+
235
+ """
236
+ if 'unitCfgDeliveryDir' in self._prj_cfg['ProjectInfo']:
237
+ return os.path.join(self.get_root_dir(),
238
+ os.path.normpath(self._prj_cfg['ProjectInfo']
239
+ ['unitCfgDeliveryDir']))
240
+ return None
241
+
242
+ def get_root_dir(self):
243
+ """Get the root directory of the project.
244
+
245
+ Returns:
246
+ A path to the project root (with wildcards)
247
+
248
+ """
249
+ return self._prj_root_dir
250
+
251
+ def get_src_code_dst_dir(self):
252
+ """Return the absolute path to the source output folder."""
253
+ return os.path.join(self.get_root_dir(),
254
+ os.path.normpath(self._prj_cfg['ProjectInfo']
255
+ ['srcCodeDstDir']))
256
+
257
+ def _parse_composition_config(self, file_config):
258
+ """Parse the composition configuration from project config."""
259
+ composition_config = {
260
+ 'compositionName': None,
261
+ 'compositionEnding': 'yml',
262
+ 'compositionArxml': file_config.get("compositionArxml", None),
263
+ 'customYamlInitFunctionName': file_config.get("customYamlInitFunctionName", None),
264
+ 'customYamlStepFunctionName': file_config.get("customYamlStepFunctionName", None),
265
+ 'generateExternalImplementationType': file_config.get("generateExternalImplementationType", True),
266
+ 'softwareComponentName': file_config.get("softwareComponentName", self.get_a2l_cfg()['name']),
267
+ 'asil': file_config.get('asil', 'QM'),
268
+ 'secure': file_config.get('secure', False),
269
+ 'includeStatic': file_config.get('includeStatic', True),
270
+ 'includeShared': file_config.get('includeShared', True),
271
+ 'includeSharedSwAddrMethod': file_config.get('includeSharedSwAddrMethod', None),
272
+ 'includeDiagnostics': file_config.get('includeDiagnostics', True),
273
+ 'includeNvm': file_config.get('includeNvm', True),
274
+ 'scaleMapsAndCurves': file_config.get('scaleMapsAndCurves', True),
275
+ }
276
+ composition_name = file_config.get("compositionName", None)
277
+ if composition_name is not None:
278
+ composition_config["compositionName"] = composition_name.split(".")[0]
279
+ if "." in composition_name:
280
+ composition_config["compositionEnding"] = composition_name.split(".")[1]
281
+ return composition_config
282
+
283
+ def get_composition_config(self, key=None):
284
+ """Get the composition configuration from project config."""
285
+ if key is None:
286
+ return self._composition_config
287
+ return self._composition_config[key]
288
+
289
+ def get_car_com_dst(self):
290
+ """Return the absolute path to the source output folder."""
291
+ return os.path.join(self.get_root_dir(),
292
+ os.path.normpath(self._prj_cfg['ProjectInfo']
293
+ ['didCarCom']))
294
+
295
+ def get_reports_dst_dir(self):
296
+ """Get the destination dir for build reports.
297
+
298
+ Returns:
299
+ A path to the report files destination directory (with wildcards)
300
+
301
+ """
302
+ return os.path.join(self.get_root_dir(),
303
+ os.path.normpath(self._prj_cfg['ProjectInfo']
304
+ ['reportDstDir']))
305
+
306
+ def get_all_reports_dst_dir(self):
307
+ """Get the destination dir for build reports.
308
+
309
+ Returns:
310
+ A path to the report files destination directory (for all projects)
311
+
312
+ """
313
+ return os.path.join(self.get_root_dir(), "..", "..", "Reports")
314
+
315
+ def get_log_dst_dir(self):
316
+ """Return the absolute path to the log output folder.
317
+
318
+ Returns:
319
+ A path to the log files destination directory (with wildcards)
320
+
321
+ """
322
+ return os.path.join(self.get_root_dir(),
323
+ os.path.normpath(self._prj_cfg['ProjectInfo']
324
+ ['logDstDir']))
325
+
326
+ def get_core_dummy_name(self):
327
+ """Return the file name of the core dummy file from the config file.
328
+
329
+ Returns:
330
+ A file name for the core dummy files
331
+
332
+ """
333
+ path = os.path.join(self.get_src_code_dst_dir(),
334
+ os.path.normpath(self._prj_cfg['ProjectInfo']
335
+ ['coreDummyFileName']))
336
+ return path
337
+
338
+ def get_feature_conf_header_name(self):
339
+ """Return the feature configuration header file name.
340
+
341
+ Returns:
342
+ A file name for the feature config header file
343
+
344
+ """
345
+ return self._prj_cfg['ProjectInfo']['featureHeaderName']
346
+
347
+ def get_ts_header_name(self):
348
+ """Return the name of the ts header file, defined in the config file.
349
+
350
+ Returns:
351
+ The file name of the file defining all unit raster times
352
+
353
+ """
354
+ return self._prj_cfg['ProjectInfo']['tsHeaderName']
355
+
356
+ def get_included_units(self):
357
+ """Return a list of all the included units in the project.
358
+
359
+ TODO:Consider moving this to the Feature Configs class if we start
360
+ using our configuration tool for model inclusion and scheduling
361
+ TODO:Consider calculate this on init and storing the result in the
362
+ class. this method would the just return the stored list.
363
+ """
364
+ units_dict = self._unit_cfg['Rasters']
365
+ units = []
366
+ for unit in units_dict.values():
367
+ units.extend(unit)
368
+ return units
369
+
370
+ def get_included_common_files(self):
371
+ """Return a list of all the included common files in the project.
372
+
373
+ Returns:
374
+ included_common_files ([str]): The names of the common files which are included in the project.
375
+
376
+ """
377
+ return self._prj_cfg.get('includedCommonFiles', [])
378
+
379
+ def _calc_all_units(self):
380
+ """Return a list of all the units."""
381
+ units = set()
382
+ for runits in self._unit_cfg['Rasters'].values():
383
+ units = units.union(set(runits))
384
+ self._all_units = list(units)
385
+
386
+ def get_includes_paths_flat(self):
387
+ """Return list of paths to files to be included flat in source directory."""
388
+ includes_paths = self._prj_cfg.get('includesPaths', [])
389
+ return [os.path.join(self.get_root_dir(), os.path.normpath(path)) for path in includes_paths]
390
+
391
+ def get_includes_paths_tree(self):
392
+ """Return list of paths to files to included with directories in source directory."""
393
+ includes_paths_tree = self._prj_cfg.get('includesPathsTree', [])
394
+ return [os.path.join(self.get_root_dir(), os.path.normpath(path)) for path in includes_paths_tree]
395
+
396
+ def get_all_units(self):
397
+ """Return a list of all the units."""
398
+ return self._all_units
399
+
400
+ def get_prj_cfg_dir(self):
401
+ """Return the directory containing the project configuration files.
402
+
403
+ Returns:
404
+ An absolute path to the project configuration files
405
+
406
+ """
407
+ return os.path.join(self._prj_root_dir,
408
+ self._prj_cfg['ProjectInfo']['configDir'])
409
+
410
+ def get_scheduler_prefix(self):
411
+ """Returns a prefix used to distinguish function calls in one project from
412
+ similarly named functions in other projects, when linked/compiled together
413
+
414
+ Returns:
415
+ scheduler_prefix (string): prefix for scheduler functions.
416
+ """
417
+ return self._scheduler_prefix
418
+
419
+ def get_local_defs_name(self):
420
+ """Return a string which defines the file name of local defines.
421
+
422
+ Returns:
423
+ A string containing the wildcard file name local defines
424
+
425
+ """
426
+ return self._prj_cfg['ProjectInfo']['prjLocalDefs']
427
+
428
+ def get_codeswitches_name(self):
429
+ """Return a string which defines the file name of code switches.
430
+
431
+ Returns:
432
+ A string containing the wildcard file name code switches
433
+
434
+ """
435
+ return self._prj_cfg['ProjectInfo']['prjCodeswitches']
436
+
437
+ def get_did_cfg_file_name(self):
438
+ """Return the did definition file name.
439
+
440
+ Returns:
441
+ DID definition file name
442
+
443
+ """
444
+ return self._prj_cfg['ProjectInfo']['didDefFile']
445
+
446
+ def get_prj_config(self):
447
+ """Get the project configuration name from the config file.
448
+
449
+ Returns:
450
+ Project config name
451
+
452
+ """
453
+ return self._prj_cfg['ProjectInfo']["projConfig"]
454
+
455
+ def get_a2l_name(self):
456
+ """Get the name of the a2l-file, which the build system shall generate."""
457
+ return self._prj_cfg['ProjectInfo']['a2LFileName']
458
+
459
+ def get_ecu_info(self):
460
+ """Return ecuSupplier and ecuType.
461
+
462
+ Returns:
463
+ (ecuSupplier, ecuType)
464
+ """
465
+ return (
466
+ self._prj_cfg['ProjectInfo'].get('ecuSupplier', None),
467
+ self._prj_cfg['ProjectInfo'].get('ecuType', '')
468
+ )
469
+
470
+ def get_xcp_enabled(self):
471
+ """Return True/False whether XCP is enabled in the project or not.
472
+
473
+ Returns:
474
+ (bool): True/False whether XCP is enabled in the project or not
475
+
476
+ """
477
+ return self._prj_cfg['ProjectInfo'].get('enableXcp', True)
478
+
479
+ def get_nvm_defs(self):
480
+ """Return NVM-ram block definitions.
481
+
482
+ The definitions contains the sizes of the six NVM areas
483
+ which are defined in the build-system.
484
+
485
+ Returns:
486
+ NvmConfig dict from config file.
487
+
488
+ """
489
+ return self._prj_cfg['NvmConfig']
490
+
491
+ def _get_inc_dirs(self, path):
492
+ """Get the dirs with the models defined in the units config file.
493
+
494
+ Model name somewhere in the path.
495
+ """
496
+ all_dirs = glob.glob(path)
497
+ inc_units = self.get_included_units()
498
+ psep = os.path.sep
499
+ out = {}
500
+ for dir_ in all_dirs:
501
+ folders = dir_.split(psep)
502
+ for inc_unit in inc_units:
503
+ if inc_unit in folders:
504
+ out.update({inc_unit: dir_})
505
+ break
506
+ return out
507
+
508
+ def get_units_raster_cfg(self):
509
+ """Get the units' scheduling raster config.
510
+
511
+ I.e. which units are included, and in which
512
+ rasters they are scheduled, and in which order.
513
+
514
+ Returns:
515
+ A dict in the following format.
516
+
517
+ ::
518
+
519
+ {
520
+ "SampleTimes": {
521
+ "NameOfRaster": scheduling time},
522
+ "Rasters": {
523
+ "NameOfRaster": [
524
+ "NameOfFunction",
525
+ ...],
526
+ ...}
527
+ }
528
+
529
+ Example::
530
+
531
+ {
532
+ "SampleTimes": {
533
+ "Vc10ms": 0.01,
534
+ "Vc40ms": 0.04},
535
+ "Rasters": {
536
+ "Vc10ms": [
537
+ "VcPpmImob",
538
+ "VcPpmPsm",
539
+ "VcPpmRc",
540
+ "VcPpmSt",
541
+ "VcPemAlc"],
542
+ "Vc40ms": [
543
+ "VcRegCh"]
544
+ }
545
+
546
+ """
547
+ return self._unit_cfg
548
+
549
+ def get_unit_cfg_dirs(self):
550
+ """Get config dirs which matches the project config parameter prjUnitCfgDir.
551
+
552
+ Furthermore, they should be included in the unit definition for this project
553
+
554
+ Returns:
555
+ A list with absolute paths to all unit config dirs
556
+ included in the project
557
+
558
+ """
559
+ path = os.path.join(self.get_root_dir(),
560
+ os.path.normpath(self._prj_cfg['ProjectInfo']
561
+ ['prjUnitCfgDir']))
562
+ return self._get_inc_dirs(path)
563
+
564
+ def get_translation_files_dirs(self):
565
+ """Get translation files directories, specified as a path regex in project
566
+ config by key prjTranslationDir. If key is not present, will fall back to
567
+ prjUnitCfgDir.
568
+
569
+ Returns:
570
+ A dictionary with absolute paths to all translation file dirs included
571
+ in the project
572
+ """
573
+
574
+ if "prjTranslationDir" not in self._prj_cfg['ProjectInfo']:
575
+ return self.get_unit_cfg_dirs()
576
+
577
+ normpath_dir = os.path.normpath(self._prj_cfg['ProjectInfo']['prjTranslationDir'])
578
+ path = os.path.join(self.get_root_dir(), normpath_dir)
579
+
580
+ all_dirs = glob.glob(path)
581
+ translation_dirs = {}
582
+ for directory in all_dirs:
583
+ file = pathlib.Path(directory).stem
584
+ translation_dirs[file] = directory
585
+ return translation_dirs
586
+
587
+ def get_common_src_dir(self):
588
+ """Get source dir which matches the project config parameter commonSrcDir.
589
+
590
+ Returns:
591
+ Absolute path to common source dir
592
+
593
+ """
594
+ return os.path.join(self.get_root_dir(),
595
+ os.path.normpath(self._prj_cfg['ProjectInfo']['commonSrcDir']))
596
+
597
+ def get_unit_src_dirs(self):
598
+ """Get source dirs which matches the project config parameter prjUnitCfgDir.
599
+
600
+ Furthermore, they should be included in the unit definition for this project
601
+
602
+ Returns:
603
+ A list with absolute paths to all source dirs included in the
604
+ project
605
+
606
+ """
607
+ path = os.path.join(self.get_root_dir(),
608
+ os.path.normpath(self._prj_cfg['ProjectInfo']
609
+ ['prjUnitSrcDir']))
610
+ return self._get_inc_dirs(path)
611
+
612
+ def get_unit_mdl_dirs(self):
613
+ """Get source dirs which matches the project config parameter prjUnitCfgDir.
614
+
615
+ Furthermore, they should be included in the unit definition for this project
616
+
617
+ Returns:
618
+ A list with absolute paths to all model dirs included in the
619
+ project
620
+
621
+ """
622
+ path = os.path.join(self.get_root_dir(),
623
+ os.path.normpath(self._prj_cfg['ProjectInfo']
624
+ ['prjUnitMdlDir']))
625
+ return self._get_inc_dirs(path)
626
+
627
+ def get_use_global_const(self):
628
+ """Get the name of the global constant module."""
629
+ return self._prj_cfg['ProjectInfo']['useGlobalConst']
630
+
631
+ def get_use_volatile_globals(self):
632
+ """Get if global variables should be defined as volatile or not."""
633
+ if 'useVolatileGlobals' in self._prj_cfg['ProjectInfo']:
634
+ return self._prj_cfg['ProjectInfo']['useVolatileGlobals']
635
+ return False
636
+
637
+ def get_use_custom_dummy_spm(self):
638
+ """Get path to file defining missing internal variables, if any.
639
+
640
+ This file will be used instead of generating VcDummy_spm.c,
641
+ to make it easier to maintain missing internal signals.
642
+
643
+ Returns:
644
+ customDummySpm (os.path): An absolute path to the custom dummy spm file, if existent.
645
+ """
646
+ if 'customDummySpm' in self._prj_cfg['ProjectInfo']:
647
+ return os.path.join(
648
+ self.get_root_dir(),
649
+ os.path.normpath(self._prj_cfg['ProjectInfo']['customDummySpm'])
650
+ )
651
+ return None
652
+
653
+ def get_use_custom_sources(self):
654
+ """Get path to files with custom handwritten sourcecode, if any.
655
+
656
+ Returns:
657
+ customSources (os.path): A list of absolute paths to custom sources, if existent.
658
+ """
659
+ if 'customSources' in self._prj_cfg['ProjectInfo']:
660
+ normalized_paths = (os.path.normpath(p) for p in self._prj_cfg['ProjectInfo']['customSources'])
661
+ return [os.path.join(self.get_root_dir(), p) for p in normalized_paths]
662
+ return None
663
+
664
+ def get_if_cfg_dir(self):
665
+ """Return the directory containing the interface configuration files.
666
+
667
+ Returns:
668
+ An absolute path to the interface configuration files
669
+
670
+ """
671
+ return os.path.join(self._prj_root_dir,
672
+ self._prj_cfg['ProjectInfo']['interfaceCfgDir'])
673
+
674
+ def get_enum_def_dir(self):
675
+ """Get path to dir containing simulink enumeration definitions, if any.
676
+
677
+ Returns:
678
+ enumDefDir (os.path): An absolute path to the simulink enumerations, if existent.
679
+ """
680
+ if 'enumDefDir' in self._prj_cfg['ProjectInfo']:
681
+ return os.path.join(
682
+ self.get_root_dir(),
683
+ os.path.normpath(self._prj_cfg['ProjectInfo']['enumDefDir'])
684
+ )
685
+ return None
686
+
687
+
688
+ if __name__ == '__main__':
689
+ # Function for testing the module
690
+ BPC = BuildProjConfig('../../ProjectCfg.json')