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,729 +1,729 @@
1
- # Copyright 2024 Volvo Car Corporation
2
- # Licensed under Apache 2.0.
3
-
4
- # -*- coding: utf-8 -*-
5
- """Module for handling of NVM definitions and for generation of c&h-files defining the memory layout of the NVM."""
6
- import re
7
- import os
8
- import json
9
- from copy import deepcopy
10
-
11
- import powertrain_build.build_defs as bd
12
- from powertrain_build.types import byte_size, get_bitmask
13
- from powertrain_build.a2l import A2l
14
- from powertrain_build.problem_logger import ProblemLogger
15
-
16
-
17
- class NVMDef(ProblemLogger):
18
- """A class that holds the NVM definitions for the build.
19
-
20
- Provides methods for generating NVM structs and header files.
21
- The header files includes defines which reference the
22
- struct elements as variables.
23
- """
24
-
25
- class WrongTypeException(Exception):
26
- """WrongTypeException."""
27
-
28
- _allowed_nvm_memory_areas = [
29
- "NVM_LIST_32",
30
- "NVM_LIST_16",
31
- "NVM_LIST_8",
32
- "NVM_LIST_32_PER",
33
- "NVM_LIST_16_PER",
34
- "NVM_LIST_8_PER",
35
- "NVM_LIST_CRITICAL1",
36
- "NVM_LIST_CRITICAL2",
37
- ]
38
-
39
- _nvm_header_footer = "\n#endif /* VCC_NVM_STRUCT_H */\n"
40
-
41
- def __init__(self, project_config, unit_cfg, nvm_vars):
42
- """Constructor.
43
-
44
- Args:
45
- project_config (BuildProjConfig): current project configuration
46
- unit_cfg (UnitConfigs): unit definitions
47
- nvm_vars (dict): NVM variables from unit configurations (:doc:`UnitConfigs <unit_configs>`)
48
-
49
- """
50
- super().__init__()
51
- self._project_config = project_config
52
- self._nvm_vars = nvm_vars
53
- # get the size of areas and c-file names
54
- self._nvm_defs = project_config.get_nvm_defs()
55
- self._nvm_signals = {}
56
- self._nvm_memory_areas = tuple()
57
- self._mem_area_elem_size = {}
58
- self._area_section = {}
59
- self._mem_area_pragmas = tuple()
60
- self._nvm_header_head = self._get_nvm_header_head(unit_cfg)
61
- src_file_dst = self._project_config.get_src_code_dst_dir()
62
- self._file_name = os.path.join(src_file_dst, self._nvm_defs["fileName"])
63
- self._predecl_start = bd.PREDECL_START
64
- self._predecl_end = bd.PREDECL_END
65
- self.struct_member_prefix = "_"
66
-
67
- with open(
68
- os.path.join(project_config.get_root_dir(), self._nvm_defs["baseNvmStructs"]), "r", encoding="utf-8"
69
- ) as nvm_json:
70
- self.nvm_definitions = json.load(nvm_json)
71
- for memory_area in self.nvm_definitions:
72
- self._add_memory_area(memory_area)
73
- self._order_nvm_per_area()
74
- for memory_area in self.nvm_definitions:
75
- memory_index = self._get_nvm_areas_index(memory_area["name"])
76
- self.info("Updating %s with index %s", memory_area["name"], memory_index)
77
- self.nvm_definitions[memory_index]["signals"] = self._get_signal_list(memory_area["signals"])
78
-
79
- @staticmethod
80
- def _get_nvm_header_head(unit_cfg):
81
- _nvm_header_head = (
82
- "/*\n"
83
- " * vcc_nvm_struct.h - struct for NVM signals\n"
84
- " */\n\n"
85
- "#ifndef VCC_NVM_STRUCT_H\n"
86
- "#define VCC_NVM_STRUCT_H\n\n"
87
- )
88
- _nvm_header_head += unit_cfg.base_types_headers
89
- return _nvm_header_head
90
-
91
- def _add_memory_area(self, memory_area):
92
- """Add non-default areas."""
93
- if memory_area["name"] not in self._allowed_nvm_memory_areas:
94
- msg = f"Memory area: {memory_area['name']} not allowed"
95
- self.critical(msg)
96
- raise NVMDef.WrongTypeException(msg)
97
-
98
- self._nvm_memory_areas = (*self._nvm_memory_areas, memory_area["name"])
99
- self._mem_area_elem_size.update({memory_area["name"]: byte_size(memory_area["default_datatype"])})
100
-
101
- if memory_area["persistent"]:
102
- self._area_section.update({memory_area["name"]: "CVC_NVM_P"})
103
- self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_P_START, bd.CVC_NVM_P_END))
104
- else:
105
- self._area_section.update({memory_area["name"]: "CVC_NVM"})
106
- self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_START, bd.CVC_NVM_END))
107
-
108
- def _var_to_area(self, var_info):
109
- """Find the NVM area for the variable.
110
-
111
- Args:
112
- var_info (dict): a dict with the variable attributes.
113
-
114
- Returns:
115
- area (str): a string with the area the variable should be
116
- defined in.
117
-
118
- """
119
- mtch = re.match(r"\D+(\d+)?", var_info["type"])
120
- if mtch.group(1) is None:
121
- size = "8"
122
- else:
123
- size = mtch.group(1)
124
- if var_info["class"] == "CVC_DISP_NVM":
125
- return "NVM_LIST_" + size
126
- if var_info["class"] == "CVC_DISP_NVM_P":
127
- return "NVM_LIST_" + size + "_PER"
128
- self.critical("%s is not a NVM variable!", var_info["name"])
129
- return None
130
-
131
- def _order_nvm_per_area(self):
132
- """Order the NVM in the areas, based on the definitions."""
133
- for var, unit_attrib in self._nvm_vars.items():
134
- for _, var_attribs in unit_attrib.items():
135
- area = self._var_to_area(var_attribs)
136
- self._nvm_signals[var] = var_attribs
137
- self._nvm_signals[var]["area"] = area
138
- # only use one units definition
139
- # TODO:Make a nicer solution #
140
- break
141
-
142
- def nvm_area_iterator(self, nvm_area_name):
143
- """Get an iterator for NVM 'area'.
144
-
145
- The iterator yields data_type and and variable name for the
146
- variables defined in the area.
147
-
148
- Args:
149
- nvm_area_name (str): the name of the NVM area
150
-
151
- Returns:
152
- tuple: (data_type, variable name, size)
153
-
154
- """
155
- for nvm_signal_name, nvm_attributes in self._nvm_signals.items():
156
- if nvm_attributes["area"] == nvm_area_name:
157
- yield nvm_attributes.get("type"), nvm_signal_name, nvm_attributes.get("width", 1)
158
-
159
- def _a2l_dict(self):
160
- """Return a dict defining all parameters for a2l-generation."""
161
- res = {}
162
- for var, var_attrib in self._nvm_signals.items():
163
- variable_name = self._get_struct_and_variable_name(var_attrib["area"])[1]
164
- res[var] = {
165
- "var": {"var": var, "type": var_attrib["type"], "cvc_type": "CVC_NVM"},
166
- "a2l_data": {
167
- "bitmask": get_bitmask(var_attrib["type"]),
168
- "description": var_attrib["description"],
169
- "lsb": var_attrib.get("lsb", 1),
170
- "max": var_attrib.get("max"),
171
- "min": var_attrib.get("min"),
172
- "offset": var_attrib.get("offset"),
173
- "unit": var_attrib["unit"],
174
- "symbol": variable_name,
175
- "symbol_offset": var_attrib.get("struct_off"),
176
- },
177
- }
178
- width = var_attrib.get("width", 1)
179
- if width:
180
- if isinstance(width, list):
181
- res[var]["array"] = width
182
- elif int(width) > 1:
183
- res[var]["array"] = [width]
184
- return {"vars": res, "function": "VcNvm"}
185
-
186
- @staticmethod
187
- def _compare_size(signal, widths):
188
- """Compare a json signal object with widths array.
189
-
190
- :param signal: signal name
191
- :param widths: array matrix size
192
- :return: bool True if size is the same
193
-
194
- """
195
- return signal["x_size"] == widths[0] and signal["y_size"] == widths[1]
196
-
197
- @staticmethod
198
- def _clean_values(widths):
199
- """Get clean width values.
200
-
201
- Sometimes width array i set to -1,
202
- (This data is read out from the simulink model in the matlab scripts,
203
- -1 is simulink logic for the values should be inherited).
204
- :param widths:
205
- :return: a correct widths array
206
- """
207
- if widths in ("-1", 1):
208
- widths = [1, 1]
209
- return widths
210
-
211
- def _assert_data_type(self, signal, memory_area):
212
- """Asserts that each signal inside an NVM block is of one of the allowed data types of the block."""
213
- memory_area_index = self._get_nvm_areas_index(memory_area)
214
- if "NotApplicable" in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
215
- # Special case for NVM_LIST_CRITICAL1 and 2. Any type is acceptable.
216
- self.debug("Data type is not checked for %s", self.nvm_definitions[memory_area_index]["name"])
217
- return
218
- if signal["type"] not in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
219
- msg = f"Signal type:{signal['type']} for {signal['name']} not allowed in area:{memory_area}"
220
- self.critical(msg)
221
- raise NVMDef.WrongTypeException(msg)
222
-
223
- def _compare_signal(self, signal, data_type, widths, persistent_signal):
224
- """Compare signal and warn if there is a mismatch in data type or size.
225
-
226
- :param signal: signal object from nvm_structs.json file
227
- :param data_type: str
228
- :param widths: array matrix size
229
- :return: True if the signal is the same in both json struct and values read from simulink model.
230
-
231
- """
232
- if data_type != signal["type"]:
233
- log = self.critical if persistent_signal else self.warning
234
- log("NVM signal: %s type mismatch %s != %s ", signal["name"], data_type, signal["type"])
235
- return False
236
- if not self._compare_size(signal, widths):
237
- self.critical(
238
- "signal:%s size mismatch %s != %s,%s ", signal["name"], widths, signal["x_size"], signal["y_size"]
239
- )
240
- return False
241
-
242
- return True
243
-
244
- def _get_nvm_areas_index(self, area):
245
- """Get array index of nvm area.
246
-
247
- :param area: wanted nvm area as string
248
- :return: (int) nvm areas index in self.nvm_definitions
249
- """
250
- return next(
251
- (index for index, nvm_definition in enumerate(self.nvm_definitions) if nvm_definition["name"] == area), -1
252
- )
253
-
254
- def _find_empty_index(self, memory_index, signal):
255
- """Find empty index in array of signals.
256
-
257
- :param memory_index: array index (NVM area)
258
- :param signal: signal to add at empty index
259
- :return: (int) empty index, (-1 if not found)
260
- """
261
- for signal_index in range(len(self.nvm_definitions[memory_index]["signals"])):
262
- signal_candidate = self.nvm_definitions[memory_index]["signals"][signal_index]
263
- if self._compare_size(signal, (signal_candidate["x_size"], signal_candidate["y_size"])) and (
264
- signal_candidate["name"].startswith("Pos_") or signal_candidate["name"].startswith("Position_")
265
- ):
266
- return signal_index
267
- return -1
268
-
269
- def _add_signal_to_nvm_struct(self, memory_index, signal_name, data_type, widths):
270
- """Add a signal to nvm struct at first empty index.
271
-
272
- :param memory_index: array index (NVM area)
273
- :param signal_name: str signal_nameiable name
274
- :param data_type: str
275
- :param widths: array matrix size
276
- """
277
- if widths == "-1":
278
- widths = [1, 1]
279
- elif widths == "-":
280
- self.critical("Bad widths value (%s), cannot add: %s", widths, signal_name)
281
- return
282
-
283
- new_signal = self._get_memory_area_signal_template(memory_index)
284
- new_signal["name"] = signal_name
285
- new_signal["type"] = data_type
286
- new_signal["x_size"] = int(widths[0])
287
- new_signal["y_size"] = int(widths[1])
288
- signal_index = self._find_empty_index(memory_index, new_signal)
289
- if signal_index > -1:
290
- self.debug("Add at empty signal_index %s", signal_index)
291
- self._update_nvm_signal(memory_index, signal_index, new_signal)
292
- else:
293
- self.nvm_definitions[memory_index]["signals"].append(new_signal)
294
-
295
- def _get_signals_in_nvm_structs(self):
296
- signals_in_nvm_structs = {}
297
- for memory_area in self._nvm_memory_areas:
298
- memory_area_index = self._get_nvm_areas_index(memory_area)
299
- signals = self.nvm_definitions[memory_area_index]["signals"]
300
- for signal_index, signal in enumerate(signals):
301
- signals_in_nvm_structs.update(
302
- {signal["name"]: {"memory_area": memory_area, "signal_index": signal_index}}
303
- )
304
- return signals_in_nvm_structs
305
-
306
- def _dummify_nvm_signal(self, memory_area, signal_index):
307
- dummy_name = f"Pos_{memory_area}bit{'_P' if memory_area.endswith('PER') else ''}_{signal_index}"
308
- memory_index = self._get_nvm_areas_index(memory_area)
309
- self.nvm_definitions[memory_index]["signals"][signal_index]["name"] = dummy_name
310
- self.debug("Name of signal in nvm_structs.json was set to %s", dummy_name)
311
-
312
- def _get_nvm_signal(self, memory_index, signal_index):
313
- return self.nvm_definitions[memory_index]["signals"][signal_index]
314
-
315
- def _update_nvm_signal(self, memory_index, signal_index, signal):
316
- self.debug("Replacing %s with %s", self.nvm_definitions[memory_index]["signals"][signal_index], signal)
317
- self.nvm_definitions[memory_index]["signals"][signal_index] = signal
318
-
319
- def _update_duplicate_nvm_definition(self, nvm_structs_signals, model_signal, model_memory_area):
320
- """Check if already existing nvm signal is correctly configured."""
321
- nvm_structs_memory_area = nvm_structs_signals[model_signal["name"]]["memory_area"]
322
- nvm_structs_signal_index = nvm_structs_signals[model_signal["name"]]["signal_index"]
323
- nvm_structs_memory_index = self._get_nvm_areas_index(nvm_structs_memory_area)
324
- nvm_structs_signal = self._get_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index)
325
- model_memory_index = self._get_nvm_areas_index(model_memory_area)
326
- model_signal_widths = (model_signal["x_size"], model_signal["y_size"])
327
-
328
- if "NVM_LIST_CRITICAL" in nvm_structs_memory_area:
329
- # In this case, we need to update the signal memory area.
330
- # _var_to_area cannot guess the right area for signals located in the critical sections due to varying data
331
- # types
332
- self.debug("Keeping signal %s in %s", model_signal["name"], nvm_structs_memory_area)
333
- self._nvm_signals[model_signal["name"]]["area"] = nvm_structs_memory_area
334
- return
335
-
336
- persistent_signal = "_PER" in model_memory_area or "_PER" in nvm_structs_memory_area
337
- if model_memory_area != nvm_structs_memory_area:
338
- self.warning("NVM signal memory area mismatch for signal: '%s'", model_signal["name"])
339
- self.warning("nvm_structs.json: '%s' - Memory area: %s", nvm_structs_memory_area, model_memory_area)
340
- self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
341
- self._add_signal_to_nvm_struct(
342
- model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
343
- )
344
- elif not self._compare_signal(nvm_structs_signal, model_signal["type"], model_signal_widths, persistent_signal):
345
- if persistent_signal:
346
- self.warning("NVM signal type or size mismatch for signal: '%s'", model_signal["name"])
347
- self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
348
- self._add_signal_to_nvm_struct(
349
- model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
350
- )
351
- self.warning("%s relocated to fitting position", model_signal["name"])
352
- else:
353
- self._update_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index, model_signal)
354
-
355
- def _get_memory_area_signal_template(self, memory_area_index):
356
- memory_area = self.nvm_definitions[memory_area_index]
357
- signals = memory_area["signals"]
358
- if signals:
359
- return signals[0].copy()
360
-
361
- return {"name": "", "type": "", "x_size": "", "y_size": ""}
362
-
363
- def _update_nvm_base_struct(self):
364
- """Gather and update all nvm signals.
365
-
366
- 1) Updates existing signals,
367
- 2) Deletes/Dummy declares non- and persistent unused signals respectively,
368
- 3) Adds new signals,
369
- in the nvm struct.
370
- """
371
-
372
- def remove_unused_signals_from_nvm_struct():
373
- """Remove unused signals from the nvm struct.
374
-
375
- The signals are listed in an array and accessed through calculated indices, therefore,
376
- all unused signals must be removed at once.
377
- """
378
- for mem_area in self._nvm_memory_areas:
379
- mem_area_index = self._get_nvm_areas_index(mem_area)
380
- unused_signals_in_area = [
381
- signal_name
382
- for signal_name, signal_info in unused_nvm_structs_signals.items()
383
- if signal_info["memory_area"] == mem_area
384
- ]
385
-
386
- # Cannot remove signals from the persistent memory areas,
387
- # however, they can be exchanged for dummy signals
388
- if "_PER" in self.nvm_definitions[mem_area_index]["name"]:
389
- for unused_signal_name in unused_signals_in_area:
390
- if unused_signal_name.startswith("Pos"):
391
- self.debug("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
392
- else:
393
- self.warning("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
394
- self._dummify_nvm_signal(
395
- mem_area, unused_nvm_structs_signals[unused_signal_name]["signal_index"]
396
- )
397
- else:
398
- self.nvm_definitions[mem_area_index]["signals"] = [
399
- signal
400
- for signal in self.nvm_definitions[mem_area_index]["signals"]
401
- if signal["name"] not in unused_signals_in_area
402
- ]
403
-
404
- nvm_structs_signals = self._get_signals_in_nvm_structs()
405
- unused_nvm_structs_signals = self._get_signals_in_nvm_structs()
406
- new_nvm_structs_signals = []
407
-
408
- for nvm_memory_area in self._nvm_memory_areas:
409
- memory_area_index = self._get_nvm_areas_index(nvm_memory_area)
410
- if "NVM_LIST_CRITICAL" in nvm_memory_area:
411
- # NVM_LIST_CRITICAL.* only exists in some projects
412
- continue
413
- if memory_area_index == -1:
414
- self.critical("NVM area not found for: %s", nvm_memory_area)
415
- continue
416
- for nvm_data_type, nvm_signal_name, nvm_widths in self.nvm_area_iterator(nvm_memory_area):
417
- nvm_widths = self._clean_values(nvm_widths)
418
- nvm_signal = self._get_memory_area_signal_template(memory_area_index)
419
- nvm_signal["name"] = nvm_signal_name
420
- nvm_signal["type"] = nvm_data_type
421
- nvm_signal["x_size"] = int(nvm_widths[0])
422
- nvm_signal["y_size"] = int(nvm_widths[1])
423
- if nvm_signal_name in nvm_structs_signals:
424
- self.debug("Deleting %s", nvm_signal_name)
425
- del unused_nvm_structs_signals[nvm_signal_name]
426
- self._update_duplicate_nvm_definition(nvm_structs_signals, nvm_signal, nvm_memory_area)
427
- else:
428
- new_nvm_structs_signals.append((memory_area_index, nvm_signal["name"], nvm_data_type, nvm_widths))
429
- remove_unused_signals_from_nvm_struct()
430
-
431
- for new_signal in new_nvm_structs_signals:
432
- self._add_signal_to_nvm_struct(*new_signal)
433
-
434
- def _generate_nvm_structs_updated(self):
435
- self.info("Start generating updated nvm json file")
436
-
437
- nvm_structs_updated_path = os.path.abspath(
438
- os.path.join(self._project_config.get_root_dir(), "output", "nvm_structs_updated.json")
439
- )
440
-
441
- self.info("Created %s", nvm_structs_updated_path)
442
-
443
- with open(nvm_structs_updated_path, "w", encoding="utf-8") as nvm_structs_file:
444
- json.dump(self.nvm_definitions, nvm_structs_file, indent=4)
445
-
446
- def _get_struct_and_variable_name(self, memory_area, skip_prefix=False):
447
- """Get the name of the memory area struct and variable definitions."""
448
- prefix = self._project_config.get_scheduler_prefix()
449
- struct_name = f"{prefix}{memory_area}" if not skip_prefix else memory_area
450
- if self._project_config.get_code_generation_config("useCamelCaseForNvmVariables"):
451
- variable_name = "s" + "".join([part[0].upper() + part.lower()[1:] for part in struct_name.split("_")])
452
- else:
453
- variable_name = struct_name.lower()
454
- return struct_name, variable_name
455
-
456
- def _get_signal_and_struct_defines(self):
457
- """Get NVM signal and struct defines."""
458
- defines = []
459
- struct_defines = []
460
- for memory_area in self._nvm_memory_areas:
461
- struct_name, variable_name = self._get_struct_and_variable_name(memory_area)
462
- memory_area_index = self._get_nvm_areas_index(memory_area)
463
- section = self._area_section[memory_area]
464
- elem_size = self._mem_area_elem_size[memory_area]
465
- struct_defines.append(f'#include "{section}_START.h"\n')
466
- struct_defines.append(f"struct {struct_name} {{\n")
467
-
468
- struct_off = 0
469
- signals = self.nvm_definitions[memory_area_index]["signals"]
470
- for signal in signals:
471
- self._assert_data_type(signal, memory_area)
472
- struct_defines.append(f' {signal["type"]:7} {self.struct_member_prefix}{signal["name"]}')
473
- size_string = ""
474
- size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
475
- if size > 1:
476
- if signal["x_size"] > 1:
477
- size_string += f'[{signal["x_size"]}]'
478
- if signal["y_size"] > 1:
479
- if signal["x_size"] < 2:
480
- self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1")
481
- size_string += "[1]"
482
- size_string += f'[{signal["y_size"]}]'
483
- struct_defines.append(size_string)
484
- struct_defines.append(";\n")
485
-
486
- if signal["name"] in self._nvm_signals:
487
- self._nvm_signals[signal["name"]]["struct_off"] = struct_off
488
-
489
- struct_off += size * byte_size(signal["type"])
490
-
491
- defines.append(
492
- "#define "
493
- f"{signal['name']:40} "
494
- f"{variable_name}.{self.struct_member_prefix}{signal['name']}\n"
495
- )
496
-
497
- max_nr_signals = self.nvm_definitions[memory_area_index]["size"]
498
- tot_memory = max_nr_signals * elem_size
499
- free = tot_memory - struct_off
500
- if free > 0:
501
- struct_defines.append(
502
- f' {self.nvm_definitions[memory_area_index]["default_datatype"]} '
503
- f'unused[{int(free / elem_size)}];\n'
504
- )
505
- elif free < 0:
506
- self.critical("NVM area %s overrun!", self.nvm_definitions[memory_area_index]["name"])
507
- struct_defines.append(f"}}; /* {struct_off} bytes used of {tot_memory} */\n")
508
- struct_defines.append(f'#include "{section}_END.h"\n\n')
509
-
510
- return defines, struct_defines
511
-
512
- def _generate_nvm_config_headers(self):
513
- """Generate nvm config h file."""
514
- self.info("Start generating nvm header file")
515
- defines, struct_defines = self._get_signal_and_struct_defines()
516
-
517
- externals = [f'#include "{self._predecl_start}"\n']
518
- for area in self._nvm_memory_areas:
519
- struct_name, variable_name = self._get_struct_and_variable_name(area)
520
- externals.append(f"extern struct {struct_name} {variable_name};\n")
521
- externals.append(f'#include "{self._predecl_end}"\n\n')
522
-
523
- with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
524
- hptr.write(self._nvm_header_head)
525
- hptr.writelines(struct_defines)
526
- hptr.writelines(externals)
527
- hptr.write("\n")
528
- hptr.writelines(defines)
529
- hptr.write(self._nvm_header_footer)
530
-
531
- def _generate_nvm_config_source(self):
532
- """Generate the c-file containing the NVM definition."""
533
- # TODO: Add memory from previous builds!!! and mark old positions #
534
- self.info("Start generating nvm source file")
535
- with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
536
- cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
537
- for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
538
- struct_name, variable_name = self._get_struct_and_variable_name(area)
539
- cptr.write(f'#include "{pragma[0]}"\n')
540
- cptr.write(f"struct {struct_name} {variable_name};\n")
541
- cptr.write(f'#include "{pragma[1]}"\n\n')
542
-
543
- def _generate_nvm_config_a2l(self):
544
- """Generate the a2l-file describing the NVM definition."""
545
- self.info("Start generating nvm a2l file")
546
- a2l_dict = self._a2l_dict()
547
- a2l = A2l(a2l_dict, self._project_config)
548
- a2l.gen_a2l(self._file_name + ".a2l")
549
-
550
- def generate_nvm_config_files(self, no_nvm_a2l):
551
- """Generate all files for variables in the NVM definition.
552
-
553
- Args:
554
- no_nvm_a2l (bool): Do not generate a2l file.
555
- """
556
- self._update_nvm_base_struct()
557
- self._generate_nvm_structs_updated()
558
- self._generate_nvm_config_headers()
559
- self._generate_nvm_config_source()
560
- if not no_nvm_a2l:
561
- self._generate_nvm_config_a2l()
562
-
563
- @staticmethod
564
- def _get_signal_list(signals):
565
- return signals if isinstance(signals, list) else [signals]
566
-
567
-
568
- class ZCNVMDef(NVMDef):
569
- """A class for handling of ZC NVM definitions."""
570
-
571
- def __init__(self, project_config, unit_cfg, nvm_vars):
572
- """Init.
573
-
574
- Args:
575
- project_config (BuildProjConfig): current project configuration.
576
- unit_cfg (UnitConfigs): Unit configurations.
577
- nvm_vars (dict): NVM variables from unit configurations.
578
- """
579
- super().__init__(project_config, unit_cfg, nvm_vars)
580
- self.struct_member_prefix = "e_"
581
- self._valid_nvm_definitions = None
582
- self._update_nvm_base_struct()
583
- prefix = self._project_config.get_scheduler_prefix()
584
- self.project_nvm_definitions = {
585
- f"{prefix}{item['name']}": item for item in self.nvm_definitions
586
- }
587
- self._predecl_start = bd.PREDECL_NVM_START
588
- self._predecl_end = bd.PREDECL_NVM_END
589
- self.init_function = f"void {prefix}VcNvmInit(void)"
590
- self.main_function = f"void {prefix}VcNvm(void)"
591
-
592
- @property
593
- def valid_nvm_definitions(self):
594
- """Get the valid NVM definitions."""
595
- return self._valid_nvm_definitions
596
-
597
- @valid_nvm_definitions.setter
598
- def valid_nvm_definitions(self, yaml_nvm_definitions):
599
- """Return a set of NVM definitions appearing in both the project and the project yaml file.
600
-
601
- Args:
602
- yaml_nvm_definitions (dict): NVM lists listed in the NVM configuration yaml file.
603
- Returns:
604
- valid_nvm_definitions (dict): Validated NVM definitions,
605
- listed in both NVM configuration yaml file as well as project.
606
- """
607
- local_yaml_nvm_definitions = deepcopy(yaml_nvm_definitions)
608
- nvms_not_in_project = set(local_yaml_nvm_definitions.keys()) - set(self.project_nvm_definitions.keys())
609
- nvms_not_in_yaml = set(self.project_nvm_definitions.keys()) - set(local_yaml_nvm_definitions.keys())
610
- for key in nvms_not_in_project:
611
- self.warning(f'Ignoring NVM definition {key} since it does not appear in nvm_structs.json.')
612
- del local_yaml_nvm_definitions[key]
613
- for key in nvms_not_in_yaml:
614
- self.warning(f'Ignoring NVM definition {key} since it does not appear in the project NVM yaml file.')
615
- self._valid_nvm_definitions = local_yaml_nvm_definitions
616
-
617
- def _update_header_and_footer(self):
618
- name = self._project_config.get_composition_config("softwareComponentName")
619
- use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
620
- self._nvm_header_head += f'#include "Rte_{name}.h"\n'
621
- if use_rte_nvm_structs:
622
- self._nvm_header_head += '#include "Rte_Type.h"\n\n'
623
- self._nvm_header_footer = (
624
- "\n"
625
- f'#include "{bd.PREDECL_CODE_ASIL_D_START}"\n'
626
- f"{self.init_function};\n"
627
- f"{self.main_function};\n"
628
- f'#include "{bd.PREDECL_CODE_ASIL_D_END}"\n'
629
- f"{self._nvm_header_footer}"
630
- )
631
-
632
- def _generate_rte_type_nvm_config_headers(self):
633
- """Generate NVM config header file using RTE struct definitions."""
634
- self.info("Start generating nvm header file")
635
- defines = self._get_signal_and_struct_defines()[0]
636
- externals = [f'#include "{self._predecl_start}"\n']
637
- for area in self.valid_nvm_definitions.keys():
638
- struct_name, variable_name = self._get_struct_and_variable_name(area, skip_prefix=True)
639
- externals.append(f"extern dt_{struct_name} {variable_name};\n")
640
- externals.append(f'#include "{self._predecl_end}"\n\n')
641
- with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
642
- hptr.write(self._nvm_header_head)
643
- hptr.writelines(externals)
644
- hptr.writelines(defines)
645
- hptr.write(self._nvm_header_footer)
646
-
647
- def _generate_rte_type_nvm_config_source(self):
648
- """Generate the c-file containing the NVM definition using RTE struct definitions."""
649
- # TODO: Add memory from previous builds!!! and mark old positions #
650
- self.info("Start generating nvm source file")
651
- with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
652
- cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
653
- for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
654
- struct_name, variable_name = self._get_struct_and_variable_name(area)
655
- if struct_name in self.valid_nvm_definitions:
656
- cptr.write(f'#include "{pragma[0]}"\n')
657
- cptr.write(f"dt_{struct_name} {variable_name};\n")
658
- cptr.write(f'#include "{pragma[1]}"\n\n')
659
-
660
- def _append_nvm_rte_function_calls(self):
661
- """Append the NVM RTE function calls to the NVM config source file."""
662
- init_function_lines = [
663
- f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
664
- f"{self.init_function} {{\n",
665
- " //Call this function in the SWC init runnable\n"
666
- ]
667
- main_function = [
668
- f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
669
- f"{self.main_function} {{\n",
670
- " //Call this function in the SWC main runnable\n",
671
- ]
672
- footer = [
673
- "}\n",
674
- f'#include "{bd.CVC_CODE_ASIL_D_END}"\n',
675
- ]
676
-
677
- main_function_lines = []
678
-
679
- for nvm_name, nvm_data in self.valid_nvm_definitions.items():
680
- if nvm_data["type"] not in ["type1", "type2"]:
681
- self.critical(f"Unknown NVM type: {nvm_data['type']} for NVM: {nvm_name}")
682
- continue
683
- if nvm_data["method"] not in ["DIRECT-CALL", "NVSWCOMPONENT"]:
684
- self.critical(f"Unknown NVM method: {nvm_data['method']} for NVM: {nvm_name}")
685
- continue
686
-
687
- if nvm_data["type"] == "type2":
688
- self.warning(
689
- f'{nvm_name} is a type2 {nvm_data["method"]}. Due to inherent risk type2 write calls are '
690
- 'not generated automatically, they have to be written manually and added to source code.'
691
- )
692
- main_function_lines.append(
693
- f" // Nvm {nvm_name} is type 2, add call in manually written source code.\n"
694
- )
695
- elif nvm_data["type"] == "type1":
696
- variable_name = self._get_struct_and_variable_name(nvm_name, skip_prefix=True)[1]
697
- if nvm_data["method"] == "DIRECT-CALL":
698
- pim_call = f"Rte_Pim_{nvm_name}()"
699
- main_function_lines.append(f" *{pim_call} = {variable_name};\n")
700
- init_function_lines.append(f" {variable_name} = *{pim_call};\n")
701
- elif nvm_data["method"] == "NVSWCOMPONENT":
702
- init_function_lines.append(
703
- f" Rte_Read_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
704
- )
705
- main_function.append(
706
- f" Rte_Write_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
707
- )
708
-
709
- output = init_function_lines + footer + ["\n"] + main_function + main_function_lines + footer
710
- with open(self._file_name + ".c", mode="a", encoding="utf-8") as cptr:
711
- cptr.writelines(output)
712
-
713
- def generate_nvm_rte_files(self):
714
- """Generate the NVM RTE files."""
715
- if self.valid_nvm_definitions is None:
716
- self.critical('Valid NVM definitions not set. Cannot generate NVM RTE files.')
717
- return
718
-
719
- use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
720
-
721
- self._update_header_and_footer()
722
- self._generate_nvm_structs_updated()
723
- if use_rte_nvm_structs:
724
- self._generate_rte_type_nvm_config_headers()
725
- self._generate_rte_type_nvm_config_source()
726
- else:
727
- self._generate_nvm_config_headers()
728
- self._generate_nvm_config_source()
729
- self._append_nvm_rte_function_calls()
1
+ # Copyright 2024 Volvo Car Corporation
2
+ # Licensed under Apache 2.0.
3
+
4
+ # -*- coding: utf-8 -*-
5
+ """Module for handling of NVM definitions and for generation of c&h-files defining the memory layout of the NVM."""
6
+ import re
7
+ import os
8
+ import json
9
+ from copy import deepcopy
10
+
11
+ import powertrain_build.build_defs as bd
12
+ from powertrain_build.types import byte_size, get_bitmask
13
+ from powertrain_build.a2l import A2l
14
+ from powertrain_build.problem_logger import ProblemLogger
15
+
16
+
17
+ class NVMDef(ProblemLogger):
18
+ """A class that holds the NVM definitions for the build.
19
+
20
+ Provides methods for generating NVM structs and header files.
21
+ The header files includes defines which reference the
22
+ struct elements as variables.
23
+ """
24
+
25
+ class WrongTypeException(Exception):
26
+ """WrongTypeException."""
27
+
28
+ _allowed_nvm_memory_areas = [
29
+ "NVM_LIST_32",
30
+ "NVM_LIST_16",
31
+ "NVM_LIST_8",
32
+ "NVM_LIST_32_PER",
33
+ "NVM_LIST_16_PER",
34
+ "NVM_LIST_8_PER",
35
+ "NVM_LIST_CRITICAL1",
36
+ "NVM_LIST_CRITICAL2",
37
+ ]
38
+
39
+ _nvm_header_footer = "\n#endif /* VCC_NVM_STRUCT_H */\n"
40
+
41
+ def __init__(self, project_config, unit_cfg, nvm_vars):
42
+ """Constructor.
43
+
44
+ Args:
45
+ project_config (BuildProjConfig): current project configuration
46
+ unit_cfg (UnitConfigs): unit definitions
47
+ nvm_vars (dict): NVM variables from unit configurations (:doc:`UnitConfigs <unit_configs>`)
48
+
49
+ """
50
+ super().__init__()
51
+ self._project_config = project_config
52
+ self._nvm_vars = nvm_vars
53
+ # get the size of areas and c-file names
54
+ self._nvm_defs = project_config.get_nvm_defs()
55
+ self._nvm_signals = {}
56
+ self._nvm_memory_areas = tuple()
57
+ self._mem_area_elem_size = {}
58
+ self._area_section = {}
59
+ self._mem_area_pragmas = tuple()
60
+ self._nvm_header_head = self._get_nvm_header_head(unit_cfg)
61
+ src_file_dst = self._project_config.get_src_code_dst_dir()
62
+ self._file_name = os.path.join(src_file_dst, self._nvm_defs["fileName"])
63
+ self._predecl_start = bd.PREDECL_START
64
+ self._predecl_end = bd.PREDECL_END
65
+ self.struct_member_prefix = "_"
66
+
67
+ with open(
68
+ os.path.join(project_config.get_root_dir(), self._nvm_defs["baseNvmStructs"]), "r", encoding="utf-8"
69
+ ) as nvm_json:
70
+ self.nvm_definitions = json.load(nvm_json)
71
+ for memory_area in self.nvm_definitions:
72
+ self._add_memory_area(memory_area)
73
+ self._order_nvm_per_area()
74
+ for memory_area in self.nvm_definitions:
75
+ memory_index = self._get_nvm_areas_index(memory_area["name"])
76
+ self.info("Updating %s with index %s", memory_area["name"], memory_index)
77
+ self.nvm_definitions[memory_index]["signals"] = self._get_signal_list(memory_area["signals"])
78
+
79
+ @staticmethod
80
+ def _get_nvm_header_head(unit_cfg):
81
+ _nvm_header_head = (
82
+ "/*\n"
83
+ " * vcc_nvm_struct.h - struct for NVM signals\n"
84
+ " */\n\n"
85
+ "#ifndef VCC_NVM_STRUCT_H\n"
86
+ "#define VCC_NVM_STRUCT_H\n\n"
87
+ )
88
+ _nvm_header_head += unit_cfg.base_types_headers
89
+ return _nvm_header_head
90
+
91
+ def _add_memory_area(self, memory_area):
92
+ """Add non-default areas."""
93
+ if memory_area["name"] not in self._allowed_nvm_memory_areas:
94
+ msg = f"Memory area: {memory_area['name']} not allowed"
95
+ self.critical(msg)
96
+ raise NVMDef.WrongTypeException(msg)
97
+
98
+ self._nvm_memory_areas = (*self._nvm_memory_areas, memory_area["name"])
99
+ self._mem_area_elem_size.update({memory_area["name"]: byte_size(memory_area["default_datatype"])})
100
+
101
+ if memory_area["persistent"]:
102
+ self._area_section.update({memory_area["name"]: "CVC_NVM_P"})
103
+ self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_P_START, bd.CVC_NVM_P_END))
104
+ else:
105
+ self._area_section.update({memory_area["name"]: "CVC_NVM"})
106
+ self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_START, bd.CVC_NVM_END))
107
+
108
+ def _var_to_area(self, var_info):
109
+ """Find the NVM area for the variable.
110
+
111
+ Args:
112
+ var_info (dict): a dict with the variable attributes.
113
+
114
+ Returns:
115
+ area (str): a string with the area the variable should be
116
+ defined in.
117
+
118
+ """
119
+ mtch = re.match(r"\D+(\d+)?", var_info["type"])
120
+ if mtch.group(1) is None:
121
+ size = "8"
122
+ else:
123
+ size = mtch.group(1)
124
+ if var_info["class"] == "CVC_DISP_NVM":
125
+ return "NVM_LIST_" + size
126
+ if var_info["class"] == "CVC_DISP_NVM_P":
127
+ return "NVM_LIST_" + size + "_PER"
128
+ self.critical("%s is not a NVM variable!", var_info["name"])
129
+ return None
130
+
131
+ def _order_nvm_per_area(self):
132
+ """Order the NVM in the areas, based on the definitions."""
133
+ for var, unit_attrib in self._nvm_vars.items():
134
+ for _, var_attribs in unit_attrib.items():
135
+ area = self._var_to_area(var_attribs)
136
+ self._nvm_signals[var] = var_attribs
137
+ self._nvm_signals[var]["area"] = area
138
+ # only use one units definition
139
+ # TODO:Make a nicer solution #
140
+ break
141
+
142
+ def nvm_area_iterator(self, nvm_area_name):
143
+ """Get an iterator for NVM 'area'.
144
+
145
+ The iterator yields data_type and and variable name for the
146
+ variables defined in the area.
147
+
148
+ Args:
149
+ nvm_area_name (str): the name of the NVM area
150
+
151
+ Returns:
152
+ tuple: (data_type, variable name, size)
153
+
154
+ """
155
+ for nvm_signal_name, nvm_attributes in self._nvm_signals.items():
156
+ if nvm_attributes["area"] == nvm_area_name:
157
+ yield nvm_attributes.get("type"), nvm_signal_name, nvm_attributes.get("width", 1)
158
+
159
+ def _a2l_dict(self):
160
+ """Return a dict defining all parameters for a2l-generation."""
161
+ res = {}
162
+ for var, var_attrib in self._nvm_signals.items():
163
+ variable_name = self._get_struct_and_variable_name(var_attrib["area"])[1]
164
+ res[var] = {
165
+ "var": {"var": var, "type": var_attrib["type"], "cvc_type": "CVC_NVM"},
166
+ "a2l_data": {
167
+ "bitmask": get_bitmask(var_attrib["type"]),
168
+ "description": var_attrib["description"],
169
+ "lsb": var_attrib.get("lsb", 1),
170
+ "max": var_attrib.get("max"),
171
+ "min": var_attrib.get("min"),
172
+ "offset": var_attrib.get("offset"),
173
+ "unit": var_attrib["unit"],
174
+ "symbol": variable_name,
175
+ "symbol_offset": var_attrib.get("struct_off"),
176
+ },
177
+ }
178
+ width = var_attrib.get("width", 1)
179
+ if width:
180
+ if isinstance(width, list):
181
+ res[var]["array"] = width
182
+ elif int(width) > 1:
183
+ res[var]["array"] = [width]
184
+ return {"vars": res, "function": "VcNvm"}
185
+
186
+ @staticmethod
187
+ def _compare_size(signal, widths):
188
+ """Compare a json signal object with widths array.
189
+
190
+ :param signal: signal name
191
+ :param widths: array matrix size
192
+ :return: bool True if size is the same
193
+
194
+ """
195
+ return signal["x_size"] == widths[0] and signal["y_size"] == widths[1]
196
+
197
+ @staticmethod
198
+ def _clean_values(widths):
199
+ """Get clean width values.
200
+
201
+ Sometimes width array i set to -1,
202
+ (This data is read out from the simulink model in the matlab scripts,
203
+ -1 is simulink logic for the values should be inherited).
204
+ :param widths:
205
+ :return: a correct widths array
206
+ """
207
+ if widths in ("-1", 1):
208
+ widths = [1, 1]
209
+ return widths
210
+
211
+ def _assert_data_type(self, signal, memory_area):
212
+ """Asserts that each signal inside an NVM block is of one of the allowed data types of the block."""
213
+ memory_area_index = self._get_nvm_areas_index(memory_area)
214
+ if "NotApplicable" in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
215
+ # Special case for NVM_LIST_CRITICAL1 and 2. Any type is acceptable.
216
+ self.debug("Data type is not checked for %s", self.nvm_definitions[memory_area_index]["name"])
217
+ return
218
+ if signal["type"] not in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
219
+ msg = f"Signal type:{signal['type']} for {signal['name']} not allowed in area:{memory_area}"
220
+ self.critical(msg)
221
+ raise NVMDef.WrongTypeException(msg)
222
+
223
+ def _compare_signal(self, signal, data_type, widths, persistent_signal):
224
+ """Compare signal and warn if there is a mismatch in data type or size.
225
+
226
+ :param signal: signal object from nvm_structs.json file
227
+ :param data_type: str
228
+ :param widths: array matrix size
229
+ :return: True if the signal is the same in both json struct and values read from simulink model.
230
+
231
+ """
232
+ if data_type != signal["type"]:
233
+ log = self.critical if persistent_signal else self.warning
234
+ log("NVM signal: %s type mismatch %s != %s ", signal["name"], data_type, signal["type"])
235
+ return False
236
+ if not self._compare_size(signal, widths):
237
+ self.critical(
238
+ "signal:%s size mismatch %s != %s,%s ", signal["name"], widths, signal["x_size"], signal["y_size"]
239
+ )
240
+ return False
241
+
242
+ return True
243
+
244
+ def _get_nvm_areas_index(self, area):
245
+ """Get array index of nvm area.
246
+
247
+ :param area: wanted nvm area as string
248
+ :return: (int) nvm areas index in self.nvm_definitions
249
+ """
250
+ return next(
251
+ (index for index, nvm_definition in enumerate(self.nvm_definitions) if nvm_definition["name"] == area), -1
252
+ )
253
+
254
+ def _find_empty_index(self, memory_index, signal):
255
+ """Find empty index in array of signals.
256
+
257
+ :param memory_index: array index (NVM area)
258
+ :param signal: signal to add at empty index
259
+ :return: (int) empty index, (-1 if not found)
260
+ """
261
+ for signal_index in range(len(self.nvm_definitions[memory_index]["signals"])):
262
+ signal_candidate = self.nvm_definitions[memory_index]["signals"][signal_index]
263
+ if self._compare_size(signal, (signal_candidate["x_size"], signal_candidate["y_size"])) and (
264
+ signal_candidate["name"].startswith("Pos_") or signal_candidate["name"].startswith("Position_")
265
+ ):
266
+ return signal_index
267
+ return -1
268
+
269
+ def _add_signal_to_nvm_struct(self, memory_index, signal_name, data_type, widths):
270
+ """Add a signal to nvm struct at first empty index.
271
+
272
+ :param memory_index: array index (NVM area)
273
+ :param signal_name: str signal_nameiable name
274
+ :param data_type: str
275
+ :param widths: array matrix size
276
+ """
277
+ if widths == "-1":
278
+ widths = [1, 1]
279
+ elif widths == "-":
280
+ self.critical("Bad widths value (%s), cannot add: %s", widths, signal_name)
281
+ return
282
+
283
+ new_signal = self._get_memory_area_signal_template(memory_index)
284
+ new_signal["name"] = signal_name
285
+ new_signal["type"] = data_type
286
+ new_signal["x_size"] = int(widths[0])
287
+ new_signal["y_size"] = int(widths[1])
288
+ signal_index = self._find_empty_index(memory_index, new_signal)
289
+ if signal_index > -1:
290
+ self.debug("Add at empty signal_index %s", signal_index)
291
+ self._update_nvm_signal(memory_index, signal_index, new_signal)
292
+ else:
293
+ self.nvm_definitions[memory_index]["signals"].append(new_signal)
294
+
295
+ def _get_signals_in_nvm_structs(self):
296
+ signals_in_nvm_structs = {}
297
+ for memory_area in self._nvm_memory_areas:
298
+ memory_area_index = self._get_nvm_areas_index(memory_area)
299
+ signals = self.nvm_definitions[memory_area_index]["signals"]
300
+ for signal_index, signal in enumerate(signals):
301
+ signals_in_nvm_structs.update(
302
+ {signal["name"]: {"memory_area": memory_area, "signal_index": signal_index}}
303
+ )
304
+ return signals_in_nvm_structs
305
+
306
+ def _dummify_nvm_signal(self, memory_area, signal_index):
307
+ dummy_name = f"Pos_{memory_area}bit{'_P' if memory_area.endswith('PER') else ''}_{signal_index}"
308
+ memory_index = self._get_nvm_areas_index(memory_area)
309
+ self.nvm_definitions[memory_index]["signals"][signal_index]["name"] = dummy_name
310
+ self.debug("Name of signal in nvm_structs.json was set to %s", dummy_name)
311
+
312
+ def _get_nvm_signal(self, memory_index, signal_index):
313
+ return self.nvm_definitions[memory_index]["signals"][signal_index]
314
+
315
+ def _update_nvm_signal(self, memory_index, signal_index, signal):
316
+ self.debug("Replacing %s with %s", self.nvm_definitions[memory_index]["signals"][signal_index], signal)
317
+ self.nvm_definitions[memory_index]["signals"][signal_index] = signal
318
+
319
+ def _update_duplicate_nvm_definition(self, nvm_structs_signals, model_signal, model_memory_area):
320
+ """Check if already existing nvm signal is correctly configured."""
321
+ nvm_structs_memory_area = nvm_structs_signals[model_signal["name"]]["memory_area"]
322
+ nvm_structs_signal_index = nvm_structs_signals[model_signal["name"]]["signal_index"]
323
+ nvm_structs_memory_index = self._get_nvm_areas_index(nvm_structs_memory_area)
324
+ nvm_structs_signal = self._get_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index)
325
+ model_memory_index = self._get_nvm_areas_index(model_memory_area)
326
+ model_signal_widths = (model_signal["x_size"], model_signal["y_size"])
327
+
328
+ if "NVM_LIST_CRITICAL" in nvm_structs_memory_area:
329
+ # In this case, we need to update the signal memory area.
330
+ # _var_to_area cannot guess the right area for signals located in the critical sections due to varying data
331
+ # types
332
+ self.debug("Keeping signal %s in %s", model_signal["name"], nvm_structs_memory_area)
333
+ self._nvm_signals[model_signal["name"]]["area"] = nvm_structs_memory_area
334
+ return
335
+
336
+ persistent_signal = "_PER" in model_memory_area or "_PER" in nvm_structs_memory_area
337
+ if model_memory_area != nvm_structs_memory_area:
338
+ self.warning("NVM signal memory area mismatch for signal: '%s'", model_signal["name"])
339
+ self.warning("nvm_structs.json: '%s' - Memory area: %s", nvm_structs_memory_area, model_memory_area)
340
+ self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
341
+ self._add_signal_to_nvm_struct(
342
+ model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
343
+ )
344
+ elif not self._compare_signal(nvm_structs_signal, model_signal["type"], model_signal_widths, persistent_signal):
345
+ if persistent_signal:
346
+ self.warning("NVM signal type or size mismatch for signal: '%s'", model_signal["name"])
347
+ self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
348
+ self._add_signal_to_nvm_struct(
349
+ model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
350
+ )
351
+ self.warning("%s relocated to fitting position", model_signal["name"])
352
+ else:
353
+ self._update_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index, model_signal)
354
+
355
+ def _get_memory_area_signal_template(self, memory_area_index):
356
+ memory_area = self.nvm_definitions[memory_area_index]
357
+ signals = memory_area["signals"]
358
+ if signals:
359
+ return signals[0].copy()
360
+
361
+ return {"name": "", "type": "", "x_size": "", "y_size": ""}
362
+
363
+ def _update_nvm_base_struct(self):
364
+ """Gather and update all nvm signals.
365
+
366
+ 1) Updates existing signals,
367
+ 2) Deletes/Dummy declares non- and persistent unused signals respectively,
368
+ 3) Adds new signals,
369
+ in the nvm struct.
370
+ """
371
+
372
+ def remove_unused_signals_from_nvm_struct():
373
+ """Remove unused signals from the nvm struct.
374
+
375
+ The signals are listed in an array and accessed through calculated indices, therefore,
376
+ all unused signals must be removed at once.
377
+ """
378
+ for mem_area in self._nvm_memory_areas:
379
+ mem_area_index = self._get_nvm_areas_index(mem_area)
380
+ unused_signals_in_area = [
381
+ signal_name
382
+ for signal_name, signal_info in unused_nvm_structs_signals.items()
383
+ if signal_info["memory_area"] == mem_area
384
+ ]
385
+
386
+ # Cannot remove signals from the persistent memory areas,
387
+ # however, they can be exchanged for dummy signals
388
+ if "_PER" in self.nvm_definitions[mem_area_index]["name"]:
389
+ for unused_signal_name in unused_signals_in_area:
390
+ if unused_signal_name.startswith("Pos"):
391
+ self.debug("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
392
+ else:
393
+ self.warning("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
394
+ self._dummify_nvm_signal(
395
+ mem_area, unused_nvm_structs_signals[unused_signal_name]["signal_index"]
396
+ )
397
+ else:
398
+ self.nvm_definitions[mem_area_index]["signals"] = [
399
+ signal
400
+ for signal in self.nvm_definitions[mem_area_index]["signals"]
401
+ if signal["name"] not in unused_signals_in_area
402
+ ]
403
+
404
+ nvm_structs_signals = self._get_signals_in_nvm_structs()
405
+ unused_nvm_structs_signals = self._get_signals_in_nvm_structs()
406
+ new_nvm_structs_signals = []
407
+
408
+ for nvm_memory_area in self._nvm_memory_areas:
409
+ memory_area_index = self._get_nvm_areas_index(nvm_memory_area)
410
+ if "NVM_LIST_CRITICAL" in nvm_memory_area:
411
+ # NVM_LIST_CRITICAL.* only exists in some projects
412
+ continue
413
+ if memory_area_index == -1:
414
+ self.critical("NVM area not found for: %s", nvm_memory_area)
415
+ continue
416
+ for nvm_data_type, nvm_signal_name, nvm_widths in self.nvm_area_iterator(nvm_memory_area):
417
+ nvm_widths = self._clean_values(nvm_widths)
418
+ nvm_signal = self._get_memory_area_signal_template(memory_area_index)
419
+ nvm_signal["name"] = nvm_signal_name
420
+ nvm_signal["type"] = nvm_data_type
421
+ nvm_signal["x_size"] = int(nvm_widths[0])
422
+ nvm_signal["y_size"] = int(nvm_widths[1])
423
+ if nvm_signal_name in nvm_structs_signals:
424
+ self.debug("Deleting %s", nvm_signal_name)
425
+ del unused_nvm_structs_signals[nvm_signal_name]
426
+ self._update_duplicate_nvm_definition(nvm_structs_signals, nvm_signal, nvm_memory_area)
427
+ else:
428
+ new_nvm_structs_signals.append((memory_area_index, nvm_signal["name"], nvm_data_type, nvm_widths))
429
+ remove_unused_signals_from_nvm_struct()
430
+
431
+ for new_signal in new_nvm_structs_signals:
432
+ self._add_signal_to_nvm_struct(*new_signal)
433
+
434
+ def _generate_nvm_structs_updated(self):
435
+ self.info("Start generating updated nvm json file")
436
+
437
+ nvm_structs_updated_path = os.path.abspath(
438
+ os.path.join(self._project_config.get_root_dir(), "output", "nvm_structs_updated.json")
439
+ )
440
+
441
+ self.info("Created %s", nvm_structs_updated_path)
442
+
443
+ with open(nvm_structs_updated_path, "w", encoding="utf-8") as nvm_structs_file:
444
+ json.dump(self.nvm_definitions, nvm_structs_file, indent=4)
445
+
446
+ def _get_struct_and_variable_name(self, memory_area, skip_prefix=False):
447
+ """Get the name of the memory area struct and variable definitions."""
448
+ prefix = self._project_config.get_scheduler_prefix()
449
+ struct_name = f"{prefix}{memory_area}" if not skip_prefix else memory_area
450
+ if self._project_config.get_code_generation_config("useCamelCaseForNvmVariables"):
451
+ variable_name = "s" + "".join([part[0].upper() + part.lower()[1:] for part in struct_name.split("_")])
452
+ else:
453
+ variable_name = struct_name.lower()
454
+ return struct_name, variable_name
455
+
456
+ def _get_signal_and_struct_defines(self):
457
+ """Get NVM signal and struct defines."""
458
+ defines = []
459
+ struct_defines = []
460
+ for memory_area in self._nvm_memory_areas:
461
+ struct_name, variable_name = self._get_struct_and_variable_name(memory_area)
462
+ memory_area_index = self._get_nvm_areas_index(memory_area)
463
+ section = self._area_section[memory_area]
464
+ elem_size = self._mem_area_elem_size[memory_area]
465
+ struct_defines.append(f'#include "{section}_START.h"\n')
466
+ struct_defines.append(f"struct {struct_name} {{\n")
467
+
468
+ struct_off = 0
469
+ signals = self.nvm_definitions[memory_area_index]["signals"]
470
+ for signal in signals:
471
+ self._assert_data_type(signal, memory_area)
472
+ struct_defines.append(f' {signal["type"]:7} {self.struct_member_prefix}{signal["name"]}')
473
+ size_string = ""
474
+ size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
475
+ if size > 1:
476
+ if signal["x_size"] > 1:
477
+ size_string += f'[{signal["x_size"]}]'
478
+ if signal["y_size"] > 1:
479
+ if signal["x_size"] < 2:
480
+ self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1")
481
+ size_string += "[1]"
482
+ size_string += f'[{signal["y_size"]}]'
483
+ struct_defines.append(size_string)
484
+ struct_defines.append(";\n")
485
+
486
+ if signal["name"] in self._nvm_signals:
487
+ self._nvm_signals[signal["name"]]["struct_off"] = struct_off
488
+
489
+ struct_off += size * byte_size(signal["type"])
490
+
491
+ defines.append(
492
+ "#define "
493
+ f"{signal['name']:40} "
494
+ f"{variable_name}.{self.struct_member_prefix}{signal['name']}\n"
495
+ )
496
+
497
+ max_nr_signals = self.nvm_definitions[memory_area_index]["size"]
498
+ tot_memory = max_nr_signals * elem_size
499
+ free = tot_memory - struct_off
500
+ if free > 0:
501
+ struct_defines.append(
502
+ f' {self.nvm_definitions[memory_area_index]["default_datatype"]} '
503
+ f'unused[{int(free / elem_size)}];\n'
504
+ )
505
+ elif free < 0:
506
+ self.critical("NVM area %s overrun!", self.nvm_definitions[memory_area_index]["name"])
507
+ struct_defines.append(f"}}; /* {struct_off} bytes used of {tot_memory} */\n")
508
+ struct_defines.append(f'#include "{section}_END.h"\n\n')
509
+
510
+ return defines, struct_defines
511
+
512
+ def _generate_nvm_config_headers(self):
513
+ """Generate nvm config h file."""
514
+ self.info("Start generating nvm header file")
515
+ defines, struct_defines = self._get_signal_and_struct_defines()
516
+
517
+ externals = [f'#include "{self._predecl_start}"\n']
518
+ for area in self._nvm_memory_areas:
519
+ struct_name, variable_name = self._get_struct_and_variable_name(area)
520
+ externals.append(f"extern struct {struct_name} {variable_name};\n")
521
+ externals.append(f'#include "{self._predecl_end}"\n\n')
522
+
523
+ with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
524
+ hptr.write(self._nvm_header_head)
525
+ hptr.writelines(struct_defines)
526
+ hptr.writelines(externals)
527
+ hptr.write("\n")
528
+ hptr.writelines(defines)
529
+ hptr.write(self._nvm_header_footer)
530
+
531
+ def _generate_nvm_config_source(self):
532
+ """Generate the c-file containing the NVM definition."""
533
+ # TODO: Add memory from previous builds!!! and mark old positions #
534
+ self.info("Start generating nvm source file")
535
+ with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
536
+ cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
537
+ for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
538
+ struct_name, variable_name = self._get_struct_and_variable_name(area)
539
+ cptr.write(f'#include "{pragma[0]}"\n')
540
+ cptr.write(f"struct {struct_name} {variable_name};\n")
541
+ cptr.write(f'#include "{pragma[1]}"\n\n')
542
+
543
+ def _generate_nvm_config_a2l(self):
544
+ """Generate the a2l-file describing the NVM definition."""
545
+ self.info("Start generating nvm a2l file")
546
+ a2l_dict = self._a2l_dict()
547
+ a2l = A2l(a2l_dict, self._project_config)
548
+ a2l.gen_a2l(self._file_name + ".a2l")
549
+
550
+ def generate_nvm_config_files(self, no_nvm_a2l):
551
+ """Generate all files for variables in the NVM definition.
552
+
553
+ Args:
554
+ no_nvm_a2l (bool): Do not generate a2l file.
555
+ """
556
+ self._update_nvm_base_struct()
557
+ self._generate_nvm_structs_updated()
558
+ self._generate_nvm_config_headers()
559
+ self._generate_nvm_config_source()
560
+ if not no_nvm_a2l:
561
+ self._generate_nvm_config_a2l()
562
+
563
+ @staticmethod
564
+ def _get_signal_list(signals):
565
+ return signals if isinstance(signals, list) else [signals]
566
+
567
+
568
+ class ZCNVMDef(NVMDef):
569
+ """A class for handling of ZC NVM definitions."""
570
+
571
+ def __init__(self, project_config, unit_cfg, nvm_vars):
572
+ """Init.
573
+
574
+ Args:
575
+ project_config (BuildProjConfig): current project configuration.
576
+ unit_cfg (UnitConfigs): Unit configurations.
577
+ nvm_vars (dict): NVM variables from unit configurations.
578
+ """
579
+ super().__init__(project_config, unit_cfg, nvm_vars)
580
+ self.struct_member_prefix = "e_"
581
+ self._valid_nvm_definitions = None
582
+ self._update_nvm_base_struct()
583
+ prefix = self._project_config.get_scheduler_prefix()
584
+ self.project_nvm_definitions = {
585
+ f"{prefix}{item['name']}": item for item in self.nvm_definitions
586
+ }
587
+ self._predecl_start = bd.PREDECL_NVM_START
588
+ self._predecl_end = bd.PREDECL_NVM_END
589
+ self.init_function = f"void {prefix}VcNvmInit(void)"
590
+ self.main_function = f"void {prefix}VcNvm(void)"
591
+
592
+ @property
593
+ def valid_nvm_definitions(self):
594
+ """Get the valid NVM definitions."""
595
+ return self._valid_nvm_definitions
596
+
597
+ @valid_nvm_definitions.setter
598
+ def valid_nvm_definitions(self, yaml_nvm_definitions):
599
+ """Return a set of NVM definitions appearing in both the project and the project yaml file.
600
+
601
+ Args:
602
+ yaml_nvm_definitions (dict): NVM lists listed in the NVM configuration yaml file.
603
+ Returns:
604
+ valid_nvm_definitions (dict): Validated NVM definitions,
605
+ listed in both NVM configuration yaml file as well as project.
606
+ """
607
+ local_yaml_nvm_definitions = deepcopy(yaml_nvm_definitions)
608
+ nvms_not_in_project = set(local_yaml_nvm_definitions.keys()) - set(self.project_nvm_definitions.keys())
609
+ nvms_not_in_yaml = set(self.project_nvm_definitions.keys()) - set(local_yaml_nvm_definitions.keys())
610
+ for key in nvms_not_in_project:
611
+ self.warning(f'Ignoring NVM definition {key} since it does not appear in nvm_structs.json.')
612
+ del local_yaml_nvm_definitions[key]
613
+ for key in nvms_not_in_yaml:
614
+ self.warning(f'Ignoring NVM definition {key} since it does not appear in the project NVM yaml file.')
615
+ self._valid_nvm_definitions = local_yaml_nvm_definitions
616
+
617
+ def _update_header_and_footer(self):
618
+ name = self._project_config.get_composition_config("softwareComponentName")
619
+ use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
620
+ self._nvm_header_head += f'#include "Rte_{name}.h"\n'
621
+ if use_rte_nvm_structs:
622
+ self._nvm_header_head += '#include "Rte_Type.h"\n\n'
623
+ self._nvm_header_footer = (
624
+ "\n"
625
+ f'#include "{bd.PREDECL_CODE_ASIL_D_START}"\n'
626
+ f"{self.init_function};\n"
627
+ f"{self.main_function};\n"
628
+ f'#include "{bd.PREDECL_CODE_ASIL_D_END}"\n'
629
+ f"{self._nvm_header_footer}"
630
+ )
631
+
632
+ def _generate_rte_type_nvm_config_headers(self):
633
+ """Generate NVM config header file using RTE struct definitions."""
634
+ self.info("Start generating nvm header file")
635
+ defines = self._get_signal_and_struct_defines()[0]
636
+ externals = [f'#include "{self._predecl_start}"\n']
637
+ for area in self.valid_nvm_definitions.keys():
638
+ struct_name, variable_name = self._get_struct_and_variable_name(area, skip_prefix=True)
639
+ externals.append(f"extern dt_{struct_name} {variable_name};\n")
640
+ externals.append(f'#include "{self._predecl_end}"\n\n')
641
+ with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
642
+ hptr.write(self._nvm_header_head)
643
+ hptr.writelines(externals)
644
+ hptr.writelines(defines)
645
+ hptr.write(self._nvm_header_footer)
646
+
647
+ def _generate_rte_type_nvm_config_source(self):
648
+ """Generate the c-file containing the NVM definition using RTE struct definitions."""
649
+ # TODO: Add memory from previous builds!!! and mark old positions #
650
+ self.info("Start generating nvm source file")
651
+ with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
652
+ cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
653
+ for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
654
+ struct_name, variable_name = self._get_struct_and_variable_name(area)
655
+ if struct_name in self.valid_nvm_definitions:
656
+ cptr.write(f'#include "{pragma[0]}"\n')
657
+ cptr.write(f"dt_{struct_name} {variable_name};\n")
658
+ cptr.write(f'#include "{pragma[1]}"\n\n')
659
+
660
+ def _append_nvm_rte_function_calls(self):
661
+ """Append the NVM RTE function calls to the NVM config source file."""
662
+ init_function_lines = [
663
+ f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
664
+ f"{self.init_function} {{\n",
665
+ " //Call this function in the SWC init runnable\n"
666
+ ]
667
+ main_function = [
668
+ f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
669
+ f"{self.main_function} {{\n",
670
+ " //Call this function in the SWC main runnable\n",
671
+ ]
672
+ footer = [
673
+ "}\n",
674
+ f'#include "{bd.CVC_CODE_ASIL_D_END}"\n',
675
+ ]
676
+
677
+ main_function_lines = []
678
+
679
+ for nvm_name, nvm_data in self.valid_nvm_definitions.items():
680
+ if nvm_data["type"] not in ["type1", "type2"]:
681
+ self.critical(f"Unknown NVM type: {nvm_data['type']} for NVM: {nvm_name}")
682
+ continue
683
+ if nvm_data["method"] not in ["DIRECT-CALL", "NVSWCOMPONENT"]:
684
+ self.critical(f"Unknown NVM method: {nvm_data['method']} for NVM: {nvm_name}")
685
+ continue
686
+
687
+ if nvm_data["type"] == "type2":
688
+ self.warning(
689
+ f'{nvm_name} is a type2 {nvm_data["method"]}. Due to inherent risk type2 write calls are '
690
+ 'not generated automatically, they have to be written manually and added to source code.'
691
+ )
692
+ main_function_lines.append(
693
+ f" // Nvm {nvm_name} is type 2, add call in manually written source code.\n"
694
+ )
695
+ elif nvm_data["type"] == "type1":
696
+ variable_name = self._get_struct_and_variable_name(nvm_name, skip_prefix=True)[1]
697
+ if nvm_data["method"] == "DIRECT-CALL":
698
+ pim_call = f"Rte_Pim_{nvm_name}()"
699
+ main_function_lines.append(f" *{pim_call} = {variable_name};\n")
700
+ init_function_lines.append(f" {variable_name} = *{pim_call};\n")
701
+ elif nvm_data["method"] == "NVSWCOMPONENT":
702
+ init_function_lines.append(
703
+ f" Rte_Read_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
704
+ )
705
+ main_function.append(
706
+ f" Rte_Write_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
707
+ )
708
+
709
+ output = init_function_lines + footer + ["\n"] + main_function + main_function_lines + footer
710
+ with open(self._file_name + ".c", mode="a", encoding="utf-8") as cptr:
711
+ cptr.writelines(output)
712
+
713
+ def generate_nvm_rte_files(self):
714
+ """Generate the NVM RTE files."""
715
+ if self.valid_nvm_definitions is None:
716
+ self.critical('Valid NVM definitions not set. Cannot generate NVM RTE files.')
717
+ return
718
+
719
+ use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
720
+
721
+ self._update_header_and_footer()
722
+ self._generate_nvm_structs_updated()
723
+ if use_rte_nvm_structs:
724
+ self._generate_rte_type_nvm_config_headers()
725
+ self._generate_rte_type_nvm_config_source()
726
+ else:
727
+ self._generate_nvm_config_headers()
728
+ self._generate_nvm_config_source()
729
+ self._append_nvm_rte_function_calls()