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,301 +1,301 @@
1
- # Copyright 2024 Volvo Car Corporation
2
- # Licensed under Apache 2.0.
3
-
4
- # -*- coding: utf-8 -*-
5
- """Feature configuration (codeswitches) module."""
6
-
7
- import copy
8
- import glob
9
- import os
10
- import re
11
- from pprint import pformat
12
-
13
- from powertrain_build.lib.helper_functions import deep_dict_update
14
- from powertrain_build.problem_logger import ProblemLogger
15
- from powertrain_build.xlrd_csv import WorkBook
16
-
17
-
18
- class FeatureConfigs(ProblemLogger):
19
- """Hold feature configurations read from SPM_Codeswitch_Setup*.csv config files.
20
-
21
- Provides methods for retrieving the currently
22
- used configurations of a unit.
23
- """
24
-
25
- convs = (('~=', '!='), ('~', ' not '), ('!', ' not '), (r'\&\&', ' and '),
26
- (r'\|\|', ' or '))
27
-
28
- def __init__(self, prj_config):
29
- """Constructor.
30
-
31
- Args:
32
- prj_config (BuildProjConfig): configures which units are active in the current project and where
33
- the codeswitches files are located
34
-
35
- """
36
- super().__init__()
37
- self._if_define_dict = {}
38
- self._build_prj_config = prj_config
39
- self._missing_codesw = set()
40
- # Get the config switches configuration
41
- self._set_config(self._parse_all_code_sw_configs())
42
- self._parse_all_local_defs()
43
- self._add_local_defs_to_tot_code_sw()
44
-
45
- def __repr__(self):
46
- """Get string representation of object."""
47
- return pformat(self.__code_sw_cfg.keys())
48
-
49
- def _parse_all_code_sw_configs(self):
50
- """Parse all SPM_Codeswitch_Setup*.csv config files.
51
-
52
- Returns:
53
- dict: with the projects as keys, and the values are
54
- another dict with the config-parameter and it's value.
55
-
56
- """
57
- # TODO: Change this when condeswitches are moved to model config
58
- # cfg_paths = self._build_prj_config.get_unit_mdl_dirs('all')
59
- cfg_paths = [self._build_prj_config.get_prj_cfg_dir()]
60
- cfg_fname = self._build_prj_config.get_codeswitches_name()
61
- cfg_files = []
62
- for cfg_path in cfg_paths:
63
- cfg_files.extend(glob.glob(os.path.join(cfg_path, cfg_fname)))
64
- self.debug('cfg_paths: %s', pformat(cfg_paths))
65
- self.debug('cfg_fname: %s', pformat(cfg_fname))
66
- self.debug('cfg_files: %s', pformat(cfg_files))
67
- conf_dict = {}
68
- for file_ in cfg_files:
69
- conf_dict = deep_dict_update(conf_dict, self._parse_code_sw_config(file_))
70
- return conf_dict
71
-
72
- def _parse_code_sw_config(self, file_name):
73
- """Parse the SPM_Codeswitch_Setup.csv config file.
74
-
75
- Returns:
76
- dict: with the projects as keys, and the values are
77
- another dict with the config-parameter and it's value.
78
-
79
- """
80
- self.debug('_parse_code_sw_config: %s', file_name)
81
- wbook = WorkBook(file_name)
82
- conf_dict = {'NEVER_ACTIVE': 0,
83
- 'ALWAYS_ACTIVE': 1}
84
- # TODO: handle sheet names in a better way!
85
- wsheet = wbook.single_sheet()
86
- prjs = [d.value for d in wsheet.row(0)[2:]]
87
- prj_row = enumerate(prjs, 2)
88
- for col, prj in prj_row:
89
- if prj != self._build_prj_config.get_prj_config():
90
- self.debug('Skipping %s', prj)
91
- continue
92
- for r_nbr in range(1, wsheet.nrows):
93
- row = wsheet.row(r_nbr)
94
- conf_par = row[0].value.strip().replace('.', '_')
95
- val = row[col].value
96
- if not isinstance(val, str):
97
- conf_dict[conf_par] = val
98
- elif val.lower().strip() == 'na' or val.lower().strip() == 'n/a':
99
- conf_dict[conf_par] = 0
100
- else:
101
- self.warning('Unexpected codeswitch value %s = "%s". Ignored!', row[0].value.strip(), val)
102
- return conf_dict
103
- return conf_dict
104
-
105
- def _recursive_subs(self, m_def, code_sws):
106
- """Recursivly replaces macro definitions with values."""
107
- # find and replace all symbols with values
108
- symbols = re.findall(r'(?!(?:and|or|not)\b)(\b[a-zA-Z_]\w+)', m_def)
109
- m_def_subs = m_def
110
- for symbol in symbols:
111
- if symbol in code_sws:
112
- m_def_subs = re.sub(symbol, str(code_sws[symbol]), m_def_subs)
113
- elif symbol in self._if_define_dict:
114
- m_def_subs = re.sub(symbol, str(self._if_define_dict[symbol]), m_def_subs)
115
- m_def_subs = self._recursive_subs(m_def_subs, code_sws)
116
- else:
117
- self.critical('Symbol %s not defined in config switches.', symbol)
118
- return None
119
- return m_def_subs
120
-
121
- def _add_local_defs_to_tot_code_sw(self):
122
- """Add the defines from the LocalDefs.h files to the code switch dict."""
123
- for macro, m_def in self._if_define_dict.items():
124
- tmp_subs = self._recursive_subs(m_def, self.__tot_code_sw)
125
- if tmp_subs is None:
126
- continue
127
- self.__tot_code_sw[macro] = eval(tmp_subs)
128
-
129
- def get_preprocessor_macro(self, nested_code_switches):
130
- """Get the #if macro string for a code switch configuration from a unit config json file.
131
-
132
- Args:
133
- nested_code_switches(list()): list of lists of code switches from unitconfig
134
- return:
135
- string: A string with an #if macro that defines if the code should be active
136
- '#if (<CS1> && <CS2>) || (<CS3> && <CS4>)'
137
- """
138
- if_macro_and = []
139
- if not isinstance(nested_code_switches, list):
140
- self.warning("Unitconfig codeswitches should be in a nested list")
141
- nested_code_switches = [nested_code_switches]
142
- if not isinstance(nested_code_switches[0], list):
143
- self.warning("Unitconfig codeswitches should be in a nested list")
144
- nested_code_switches = [nested_code_switches]
145
-
146
- for code_switches in nested_code_switches:
147
- if isinstance(code_switches, str):
148
- code_switches = [code_switches]
149
- if_macro_and.append(f"( { ' && '.join(code_switches) } )")
150
- if_macro_string = f"#if {' || '.join(if_macro_and)}" if if_macro_and else ""
151
- all_projects = re.search('all', if_macro_string, re.I)
152
- if all_projects:
153
- return ""
154
- return if_macro_string
155
-
156
- def gen_unit_cfg_header_file(self, file_name):
157
- """Generate a header file with preprocessor defines needed to configure the SW.
158
-
159
- Args:
160
- file_name (str): The file name (with path) of the unit config header file
161
-
162
- """
163
- with open(file_name, 'w', encoding="utf-8") as f_hndl:
164
- _, fname = os.path.split(file_name)
165
- fname = fname.replace('.', '_').upper()
166
- f_hndl.write(f'#ifndef {fname}\n')
167
- f_hndl.write(f'#define {fname}\n\n')
168
- conf_sw = self.__code_sw_cfg
169
- for key_, val in conf_sw.items():
170
- if val == "":
171
- self.warning('Code switch "%s" is missing a defined value', key_)
172
- f_hndl.write(f'#define {key_} {val}\n')
173
- f_hndl.write(f'\n#endif /* {fname} */\n')
174
-
175
- def _eval_cfg_expr(self, elem):
176
- """Convert matlab config expression to python expression.
177
-
178
- Uses the tuple self.convs, and evaluates the result using
179
- self.__code_sw_cfg[config]
180
- This function does not handle the complex definitions made outside
181
- the dict.
182
-
183
- Args:
184
- elem (str): element string
185
-
186
- Returns:
187
- Bool: True if config is active, False if not.
188
-
189
- """
190
- res = re.search('all', elem, re.I)
191
- if res is not None:
192
- return True
193
- # modify all matlab expressions
194
- elem_tmp = elem
195
- # find and replace all symbols with values
196
- symbols = re.findall(r'[a-zA-Z_]\w+', elem_tmp)
197
- code_sw_dict = self.__tot_code_sw
198
- for symbol in symbols:
199
- try:
200
- elem_tmp = re.sub(fr'\b{symbol}\b', str(code_sw_dict[symbol]), elem_tmp)
201
- except KeyError:
202
- if symbol not in self._missing_codesw:
203
- self.critical('Missing %s in CodeSwitch definition', symbol)
204
- self._missing_codesw.add(symbol)
205
- return False
206
- # convert matlab/c to python expressions
207
- for conv in self.convs:
208
- elem_tmp = re.sub(conv[0], conv[1], elem_tmp)
209
- # evaluate and return result
210
- return eval(elem_tmp)
211
-
212
- def check_if_active_in_config(self, config_def):
213
- """Check if a config is active in the current context.
214
-
215
- Takes a collection of config strings and checks if this config definition is active
216
- within the current configuration. The structure of the provided string collection
217
- determines how the config definition is evaluated. (logical and/or expressions)
218
-
219
- list of list of config strings
220
- [[*cs1* and *cs2*] or [*cs3* and *cs4*]].
221
-
222
- list of config strings
223
- [*cs1* and *cs2*]
224
-
225
- single config string
226
- *cs1*
227
-
228
- Args:
229
- config_def (list): the config definitions as described above
230
-
231
- Returns:
232
- Bool: True if active the current configuration
233
-
234
- """
235
- if not config_def:
236
- return True
237
- # format the input to a list of list of strings
238
- if isinstance(config_def, str):
239
- c_def = [[config_def]]
240
- elif isinstance(config_def, list) and isinstance(config_def[0], str):
241
- c_def = [config_def]
242
- else:
243
- c_def = config_def
244
- eval_ = False
245
- for or_elem in c_def:
246
- for and_elem in or_elem:
247
- eval_ = self._eval_cfg_expr(and_elem)
248
- if not eval_:
249
- break
250
- if eval_:
251
- break
252
- return eval_
253
-
254
- def _conv_mlab_def_to_py(self, matlab_def):
255
- """Convert matlab syntax to python syntax.
256
-
257
- TODO: Move this functionality to the matlab-scripts, which are
258
- run on the local machine.
259
-
260
- """
261
- m_def_tmp = matlab_def
262
- for from_, to_ in self.convs:
263
- m_def_tmp = re.sub(from_, to_, m_def_tmp)
264
- return m_def_tmp
265
-
266
- def _parse_local_def(self, file_data):
267
- """Parse one local define file."""
268
- res = re.findall(r'#if\s+(.*?)(?<!\\)$\s*#define (\w+)\s+#endif',
269
- file_data, flags=re.M | re.DOTALL)
270
- def_wo_if_endif = re.sub(r'#if(.*?)#endif', '', file_data, flags=re.M | re.DOTALL)
271
- one_line_def = re.findall(r'#define\s+(\w+)\s+(.+?)(?:(?://|/\*).*?)?$',
272
- def_wo_if_endif, flags=re.M)
273
- res.extend([(v, d) for (d, v) in one_line_def])
274
- # remove line break '\' characters and line break
275
- self._if_define_dict.update({d: self._conv_mlab_def_to_py(re.sub(r'\s*?\\$\s*', ' ', i))
276
- for (i, d) in res})
277
-
278
- def _parse_all_local_defs(self):
279
- """Parse all local define files."""
280
- def_paths = self._build_prj_config.get_unit_src_dirs()
281
- ld_fname = self._build_prj_config.get_local_defs_name()
282
- loc_def_files = []
283
- for def_path in def_paths.values():
284
- loc_def_files.extend(glob.glob(os.path.join(def_path, ld_fname)))
285
- for file_ in loc_def_files:
286
- with open(file_, 'r', encoding="utf-8") as fhndl:
287
- data = fhndl.read()
288
- self._parse_local_def(data)
289
- self.debug('self._if_define_list:\n%s\n', pformat(self._if_define_dict))
290
-
291
- def _set_config(self, code_sw):
292
- """Set config for code switches.
293
-
294
- Useful for unit testing.
295
-
296
- Args:
297
- code_sw
298
- """
299
- # __tot_code_sw
300
- self.__code_sw_cfg = code_sw
301
- self.__tot_code_sw = copy.deepcopy(self.__code_sw_cfg)
1
+ # Copyright 2024 Volvo Car Corporation
2
+ # Licensed under Apache 2.0.
3
+
4
+ # -*- coding: utf-8 -*-
5
+ """Feature configuration (codeswitches) module."""
6
+
7
+ import copy
8
+ import glob
9
+ import os
10
+ import re
11
+ from pprint import pformat
12
+
13
+ from powertrain_build.lib.helper_functions import deep_dict_update
14
+ from powertrain_build.problem_logger import ProblemLogger
15
+ from powertrain_build.xlrd_csv import WorkBook
16
+
17
+
18
+ class FeatureConfigs(ProblemLogger):
19
+ """Hold feature configurations read from SPM_Codeswitch_Setup*.csv config files.
20
+
21
+ Provides methods for retrieving the currently
22
+ used configurations of a unit.
23
+ """
24
+
25
+ convs = (('~=', '!='), ('~', ' not '), ('!', ' not '), (r'\&\&', ' and '),
26
+ (r'\|\|', ' or '))
27
+
28
+ def __init__(self, prj_config):
29
+ """Constructor.
30
+
31
+ Args:
32
+ prj_config (BuildProjConfig): configures which units are active in the current project and where
33
+ the codeswitches files are located
34
+
35
+ """
36
+ super().__init__()
37
+ self._if_define_dict = {}
38
+ self._build_prj_config = prj_config
39
+ self._missing_codesw = set()
40
+ # Get the config switches configuration
41
+ self._set_config(self._parse_all_code_sw_configs())
42
+ self._parse_all_local_defs()
43
+ self._add_local_defs_to_tot_code_sw()
44
+
45
+ def __repr__(self):
46
+ """Get string representation of object."""
47
+ return pformat(self.__code_sw_cfg.keys())
48
+
49
+ def _parse_all_code_sw_configs(self):
50
+ """Parse all SPM_Codeswitch_Setup*.csv config files.
51
+
52
+ Returns:
53
+ dict: with the projects as keys, and the values are
54
+ another dict with the config-parameter and it's value.
55
+
56
+ """
57
+ # TODO: Change this when condeswitches are moved to model config
58
+ # cfg_paths = self._build_prj_config.get_unit_mdl_dirs('all')
59
+ cfg_paths = [self._build_prj_config.get_prj_cfg_dir()]
60
+ cfg_fname = self._build_prj_config.get_codeswitches_name()
61
+ cfg_files = []
62
+ for cfg_path in cfg_paths:
63
+ cfg_files.extend(glob.glob(os.path.join(cfg_path, cfg_fname)))
64
+ self.debug('cfg_paths: %s', pformat(cfg_paths))
65
+ self.debug('cfg_fname: %s', pformat(cfg_fname))
66
+ self.debug('cfg_files: %s', pformat(cfg_files))
67
+ conf_dict = {}
68
+ for file_ in cfg_files:
69
+ conf_dict = deep_dict_update(conf_dict, self._parse_code_sw_config(file_))
70
+ return conf_dict
71
+
72
+ def _parse_code_sw_config(self, file_name):
73
+ """Parse the SPM_Codeswitch_Setup.csv config file.
74
+
75
+ Returns:
76
+ dict: with the projects as keys, and the values are
77
+ another dict with the config-parameter and it's value.
78
+
79
+ """
80
+ self.debug('_parse_code_sw_config: %s', file_name)
81
+ wbook = WorkBook(file_name)
82
+ conf_dict = {'NEVER_ACTIVE': 0,
83
+ 'ALWAYS_ACTIVE': 1}
84
+ # TODO: handle sheet names in a better way!
85
+ wsheet = wbook.single_sheet()
86
+ prjs = [d.value for d in wsheet.row(0)[2:]]
87
+ prj_row = enumerate(prjs, 2)
88
+ for col, prj in prj_row:
89
+ if prj != self._build_prj_config.get_prj_config():
90
+ self.debug('Skipping %s', prj)
91
+ continue
92
+ for r_nbr in range(1, wsheet.nrows):
93
+ row = wsheet.row(r_nbr)
94
+ conf_par = row[0].value.strip().replace('.', '_')
95
+ val = row[col].value
96
+ if not isinstance(val, str):
97
+ conf_dict[conf_par] = val
98
+ elif val.lower().strip() == 'na' or val.lower().strip() == 'n/a':
99
+ conf_dict[conf_par] = 0
100
+ else:
101
+ self.warning('Unexpected codeswitch value %s = "%s". Ignored!', row[0].value.strip(), val)
102
+ return conf_dict
103
+ return conf_dict
104
+
105
+ def _recursive_subs(self, m_def, code_sws):
106
+ """Recursivly replaces macro definitions with values."""
107
+ # find and replace all symbols with values
108
+ symbols = re.findall(r'(?!(?:and|or|not)\b)(\b[a-zA-Z_]\w+)', m_def)
109
+ m_def_subs = m_def
110
+ for symbol in symbols:
111
+ if symbol in code_sws:
112
+ m_def_subs = re.sub(symbol, str(code_sws[symbol]), m_def_subs)
113
+ elif symbol in self._if_define_dict:
114
+ m_def_subs = re.sub(symbol, str(self._if_define_dict[symbol]), m_def_subs)
115
+ m_def_subs = self._recursive_subs(m_def_subs, code_sws)
116
+ else:
117
+ self.critical('Symbol %s not defined in config switches.', symbol)
118
+ return None
119
+ return m_def_subs
120
+
121
+ def _add_local_defs_to_tot_code_sw(self):
122
+ """Add the defines from the LocalDefs.h files to the code switch dict."""
123
+ for macro, m_def in self._if_define_dict.items():
124
+ tmp_subs = self._recursive_subs(m_def, self.__tot_code_sw)
125
+ if tmp_subs is None:
126
+ continue
127
+ self.__tot_code_sw[macro] = eval(tmp_subs)
128
+
129
+ def get_preprocessor_macro(self, nested_code_switches):
130
+ """Get the #if macro string for a code switch configuration from a unit config json file.
131
+
132
+ Args:
133
+ nested_code_switches(list()): list of lists of code switches from unitconfig
134
+ return:
135
+ string: A string with an #if macro that defines if the code should be active
136
+ '#if (<CS1> && <CS2>) || (<CS3> && <CS4>)'
137
+ """
138
+ if_macro_and = []
139
+ if not isinstance(nested_code_switches, list):
140
+ self.warning("Unitconfig codeswitches should be in a nested list")
141
+ nested_code_switches = [nested_code_switches]
142
+ if not isinstance(nested_code_switches[0], list):
143
+ self.warning("Unitconfig codeswitches should be in a nested list")
144
+ nested_code_switches = [nested_code_switches]
145
+
146
+ for code_switches in nested_code_switches:
147
+ if isinstance(code_switches, str):
148
+ code_switches = [code_switches]
149
+ if_macro_and.append(f"( { ' && '.join(code_switches) } )")
150
+ if_macro_string = f"#if {' || '.join(if_macro_and)}" if if_macro_and else ""
151
+ all_projects = re.search('all', if_macro_string, re.I)
152
+ if all_projects:
153
+ return ""
154
+ return if_macro_string
155
+
156
+ def gen_unit_cfg_header_file(self, file_name):
157
+ """Generate a header file with preprocessor defines needed to configure the SW.
158
+
159
+ Args:
160
+ file_name (str): The file name (with path) of the unit config header file
161
+
162
+ """
163
+ with open(file_name, 'w', encoding="utf-8") as f_hndl:
164
+ _, fname = os.path.split(file_name)
165
+ fname = fname.replace('.', '_').upper()
166
+ f_hndl.write(f'#ifndef {fname}\n')
167
+ f_hndl.write(f'#define {fname}\n\n')
168
+ conf_sw = self.__code_sw_cfg
169
+ for key_, val in conf_sw.items():
170
+ if val == "":
171
+ self.warning('Code switch "%s" is missing a defined value', key_)
172
+ f_hndl.write(f'#define {key_} {val}\n')
173
+ f_hndl.write(f'\n#endif /* {fname} */\n')
174
+
175
+ def _eval_cfg_expr(self, elem):
176
+ """Convert matlab config expression to python expression.
177
+
178
+ Uses the tuple self.convs, and evaluates the result using
179
+ self.__code_sw_cfg[config]
180
+ This function does not handle the complex definitions made outside
181
+ the dict.
182
+
183
+ Args:
184
+ elem (str): element string
185
+
186
+ Returns:
187
+ Bool: True if config is active, False if not.
188
+
189
+ """
190
+ res = re.search('all', elem, re.I)
191
+ if res is not None:
192
+ return True
193
+ # modify all matlab expressions
194
+ elem_tmp = elem
195
+ # find and replace all symbols with values
196
+ symbols = re.findall(r'[a-zA-Z_]\w+', elem_tmp)
197
+ code_sw_dict = self.__tot_code_sw
198
+ for symbol in symbols:
199
+ try:
200
+ elem_tmp = re.sub(fr'\b{symbol}\b', str(code_sw_dict[symbol]), elem_tmp)
201
+ except KeyError:
202
+ if symbol not in self._missing_codesw:
203
+ self.critical('Missing %s in CodeSwitch definition', symbol)
204
+ self._missing_codesw.add(symbol)
205
+ return False
206
+ # convert matlab/c to python expressions
207
+ for conv in self.convs:
208
+ elem_tmp = re.sub(conv[0], conv[1], elem_tmp)
209
+ # evaluate and return result
210
+ return eval(elem_tmp)
211
+
212
+ def check_if_active_in_config(self, config_def):
213
+ """Check if a config is active in the current context.
214
+
215
+ Takes a collection of config strings and checks if this config definition is active
216
+ within the current configuration. The structure of the provided string collection
217
+ determines how the config definition is evaluated. (logical and/or expressions)
218
+
219
+ list of list of config strings
220
+ [[*cs1* and *cs2*] or [*cs3* and *cs4*]].
221
+
222
+ list of config strings
223
+ [*cs1* and *cs2*]
224
+
225
+ single config string
226
+ *cs1*
227
+
228
+ Args:
229
+ config_def (list): the config definitions as described above
230
+
231
+ Returns:
232
+ Bool: True if active the current configuration
233
+
234
+ """
235
+ if not config_def:
236
+ return True
237
+ # format the input to a list of list of strings
238
+ if isinstance(config_def, str):
239
+ c_def = [[config_def]]
240
+ elif isinstance(config_def, list) and isinstance(config_def[0], str):
241
+ c_def = [config_def]
242
+ else:
243
+ c_def = config_def
244
+ eval_ = False
245
+ for or_elem in c_def:
246
+ for and_elem in or_elem:
247
+ eval_ = self._eval_cfg_expr(and_elem)
248
+ if not eval_:
249
+ break
250
+ if eval_:
251
+ break
252
+ return eval_
253
+
254
+ def _conv_mlab_def_to_py(self, matlab_def):
255
+ """Convert matlab syntax to python syntax.
256
+
257
+ TODO: Move this functionality to the matlab-scripts, which are
258
+ run on the local machine.
259
+
260
+ """
261
+ m_def_tmp = matlab_def
262
+ for from_, to_ in self.convs:
263
+ m_def_tmp = re.sub(from_, to_, m_def_tmp)
264
+ return m_def_tmp
265
+
266
+ def _parse_local_def(self, file_data):
267
+ """Parse one local define file."""
268
+ res = re.findall(r'#if\s+(.*?)(?<!\\)$\s*#define (\w+)\s+#endif',
269
+ file_data, flags=re.M | re.DOTALL)
270
+ def_wo_if_endif = re.sub(r'#if(.*?)#endif', '', file_data, flags=re.M | re.DOTALL)
271
+ one_line_def = re.findall(r'#define\s+(\w+)\s+(.+?)(?:(?://|/\*).*?)?$',
272
+ def_wo_if_endif, flags=re.M)
273
+ res.extend([(v, d) for (d, v) in one_line_def])
274
+ # remove line break '\' characters and line break
275
+ self._if_define_dict.update({d: self._conv_mlab_def_to_py(re.sub(r'\s*?\\$\s*', ' ', i))
276
+ for (i, d) in res})
277
+
278
+ def _parse_all_local_defs(self):
279
+ """Parse all local define files."""
280
+ def_paths = self._build_prj_config.get_unit_src_dirs()
281
+ ld_fname = self._build_prj_config.get_local_defs_name()
282
+ loc_def_files = []
283
+ for def_path in def_paths.values():
284
+ loc_def_files.extend(glob.glob(os.path.join(def_path, ld_fname)))
285
+ for file_ in loc_def_files:
286
+ with open(file_, 'r', encoding="utf-8") as fhndl:
287
+ data = fhndl.read()
288
+ self._parse_local_def(data)
289
+ self.debug('self._if_define_list:\n%s\n', pformat(self._if_define_dict))
290
+
291
+ def _set_config(self, code_sw):
292
+ """Set config for code switches.
293
+
294
+ Useful for unit testing.
295
+
296
+ Args:
297
+ code_sw
298
+ """
299
+ # __tot_code_sw
300
+ self.__code_sw_cfg = code_sw
301
+ self.__tot_code_sw = copy.deepcopy(self.__code_sw_cfg)