powertrain-build 1.13.1__py3-none-any.whl → 1.13.3.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- powertrain_build/__init__.py +40 -40
- powertrain_build/__main__.py +6 -6
- powertrain_build/a2l.py +582 -582
- powertrain_build/a2l_merge.py +650 -650
- powertrain_build/a2l_templates.py +717 -717
- powertrain_build/build.py +985 -985
- powertrain_build/build_defs.py +309 -309
- powertrain_build/build_proj_config.py +690 -690
- powertrain_build/check_interface.py +575 -575
- powertrain_build/cli.py +141 -141
- powertrain_build/config.py +542 -542
- powertrain_build/core.py +395 -395
- powertrain_build/core_dummy.py +343 -343
- powertrain_build/create_conversion_table.py +73 -73
- powertrain_build/dids.py +916 -916
- powertrain_build/dummy.py +157 -157
- powertrain_build/dummy_spm.py +252 -252
- powertrain_build/environmentcheck.py +52 -52
- powertrain_build/ext_dbg.py +255 -255
- powertrain_build/ext_var.py +327 -327
- powertrain_build/feature_configs.py +301 -301
- powertrain_build/gen_allsysteminfo.py +227 -227
- powertrain_build/gen_label_split.py +449 -449
- powertrain_build/handcode_replacer.py +124 -124
- powertrain_build/html_report.py +133 -133
- powertrain_build/interface/__init__.py +4 -4
- powertrain_build/interface/application.py +511 -511
- powertrain_build/interface/base.py +500 -500
- powertrain_build/interface/csp_api.py +490 -490
- powertrain_build/interface/device_proxy.py +677 -677
- powertrain_build/interface/ems.py +67 -67
- powertrain_build/interface/export_global_vars.py +121 -121
- powertrain_build/interface/generate_adapters.py +132 -132
- powertrain_build/interface/generate_hi_interface.py +87 -87
- powertrain_build/interface/generate_service.py +69 -69
- powertrain_build/interface/generate_wrappers.py +147 -147
- powertrain_build/interface/generation_utils.py +142 -142
- powertrain_build/interface/hal.py +194 -194
- powertrain_build/interface/model_yaml_verification.py +348 -348
- powertrain_build/interface/service.py +296 -296
- powertrain_build/interface/simulink.py +249 -249
- powertrain_build/interface/update_call_sources.py +180 -180
- powertrain_build/interface/update_model_yaml.py +186 -186
- powertrain_build/interface/zone_controller.py +362 -362
- powertrain_build/lib/__init__.py +4 -4
- powertrain_build/lib/helper_functions.py +127 -127
- powertrain_build/lib/logger.py +55 -55
- powertrain_build/matlab_scripts/CodeGen/BuildAutomationPyBuild.m +78 -78
- powertrain_build/matlab_scripts/CodeGen/Generate_A2L.m +154 -154
- powertrain_build/matlab_scripts/CodeGen/generateTLUnit.m +239 -239
- powertrain_build/matlab_scripts/CodeGen/getAsilClassification.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/modelConfiguredForTL.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/moveDefOutports.m +88 -88
- powertrain_build/matlab_scripts/CodeGen/parseCalMeasData.m +410 -410
- powertrain_build/matlab_scripts/CodeGen/parseCoreIdentifiers.m +139 -139
- powertrain_build/matlab_scripts/CodeGen/parseDIDs.m +141 -141
- powertrain_build/matlab_scripts/CodeGen/parseInPorts.m +106 -106
- powertrain_build/matlab_scripts/CodeGen/parseIncludeConfigs.m +25 -25
- powertrain_build/matlab_scripts/CodeGen/parseModelInfo.m +38 -38
- powertrain_build/matlab_scripts/CodeGen/parseNVM.m +81 -81
- powertrain_build/matlab_scripts/CodeGen/parseOutPorts.m +120 -120
- powertrain_build/matlab_scripts/CodeGen/parsePreProcBlks.m +23 -23
- powertrain_build/matlab_scripts/CodeGen/struct2JSON.m +128 -128
- powertrain_build/matlab_scripts/CodeGen/updateCodeSwConfig.m +31 -31
- powertrain_build/matlab_scripts/Init_PyBuild.m +91 -91
- powertrain_build/matlab_scripts/__init__.py +2 -2
- powertrain_build/matlab_scripts/helperFunctions/Get_Full_Name.m +46 -46
- powertrain_build/matlab_scripts/helperFunctions/Get_SrcLines.m +12 -12
- powertrain_build/matlab_scripts/helperFunctions/Init_Models.m +78 -78
- powertrain_build/matlab_scripts/helperFunctions/Init_Projects.m +67 -67
- powertrain_build/matlab_scripts/helperFunctions/Read_Units.m +34 -34
- powertrain_build/matlab_scripts/helperFunctions/SetProjectTimeSamples.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/Strip_Suffix.m +16 -16
- powertrain_build/matlab_scripts/helperFunctions/followLink.m +118 -118
- powertrain_build/matlab_scripts/helperFunctions/getCodeSwitches.m +50 -50
- powertrain_build/matlab_scripts/helperFunctions/getConsumerBlocks.m +30 -30
- powertrain_build/matlab_scripts/helperFunctions/getDefBlock.m +39 -39
- powertrain_build/matlab_scripts/helperFunctions/getDefOutport.m +58 -58
- powertrain_build/matlab_scripts/helperFunctions/getDstBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getDstLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/getInterfaceSignals.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getName.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getPath.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/getProperValue.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/getSrcBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getSrcLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/loadLibraries.m +10 -10
- powertrain_build/matlab_scripts/helperFunctions/loadjson.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/modifyEnumStructField.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/removeConfigDuplicates.m +31 -31
- powertrain_build/matlab_scripts/helperFunctions/sortSystemByClass.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/tl_getfast.m +89 -89
- powertrain_build/matlab_scripts/helperFunctions/topLevelSystem.m +20 -20
- powertrain_build/matlab_scripts/helperFunctions/updateModels.m +131 -131
- powertrain_build/memory_section.py +224 -224
- powertrain_build/nvm_def.py +729 -729
- powertrain_build/problem_logger.py +86 -86
- powertrain_build/pt_matlab.py +430 -430
- powertrain_build/pt_win32.py +144 -144
- powertrain_build/replace_compu_tab_ref.py +105 -105
- powertrain_build/rte_dummy.py +254 -254
- powertrain_build/sched_funcs.py +209 -207
- powertrain_build/signal.py +7 -7
- powertrain_build/signal_if_html_rep.py +221 -221
- powertrain_build/signal_if_html_rep_all.py +302 -302
- powertrain_build/signal_incons_html_rep.py +180 -180
- powertrain_build/signal_incons_html_rep_all.py +366 -366
- powertrain_build/signal_incons_html_rep_base.py +168 -168
- powertrain_build/signal_inconsistency_check.py +641 -641
- powertrain_build/signal_interfaces.py +864 -864
- powertrain_build/templates/Index_SigCheck_All.html +22 -22
- powertrain_build/templates/Index_SigIf_All.html +19 -19
- powertrain_build/types.py +218 -218
- powertrain_build/unit_configs.py +419 -419
- powertrain_build/user_defined_types.py +660 -660
- powertrain_build/versioncheck.py +66 -66
- powertrain_build/wrapper.py +512 -512
- powertrain_build/xlrd_csv.py +87 -87
- powertrain_build/zone_controller/__init__.py +4 -4
- powertrain_build/zone_controller/calibration.py +176 -176
- powertrain_build/zone_controller/composition_yaml.py +880 -878
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/METADATA +100 -100
- powertrain_build-1.13.3.dev3.dist-info/RECORD +130 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/WHEEL +1 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/LICENSE +202 -202
- powertrain_build-1.13.3.dev3.dist-info/pbr.json +1 -0
- powertrain_build-1.13.1.dist-info/RECORD +0 -130
- powertrain_build-1.13.1.dist-info/pbr.json +0 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/entry_points.txt +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/AUTHORS +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/NOTICE +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/top_level.txt +0 -0
|
@@ -1,878 +1,880 @@
|
|
|
1
|
-
# Copyright 2024 Volvo Car Corporation
|
|
2
|
-
# Licensed under Apache 2.0.
|
|
3
|
-
|
|
4
|
-
"""Module for handling ZoneController composition yaml generation."""
|
|
5
|
-
|
|
6
|
-
import re
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from ruamel.yaml import YAML, scalarstring
|
|
9
|
-
|
|
10
|
-
from powertrain_build.problem_logger import ProblemLogger
|
|
11
|
-
from powertrain_build.types import a2l_range
|
|
12
|
-
from powertrain_build.zone_controller.calibration import ZoneControllerCalibration as ZCC
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class CompositionYaml(ProblemLogger):
|
|
16
|
-
"""Class for handling ZoneController composition yaml generation."""
|
|
17
|
-
|
|
18
|
-
def __init__(self, build_cfg, signal_if, unit_cfg, zc_core, zc_dids, zc_nvm, a2l_axis_data, enums):
|
|
19
|
-
"""Init.
|
|
20
|
-
|
|
21
|
-
Args:
|
|
22
|
-
build_cfg (BuildProjConfig): Object with build configuration settings.
|
|
23
|
-
signal_if (SignalInterfaces): Class holding signal interface information.
|
|
24
|
-
unit_cfg (UnitConfig): Object with unit configurations.
|
|
25
|
-
zc_core (ZCCore): Object with zone controller diagnositic event information.
|
|
26
|
-
zc_dids (ZCDIDs): Object with zone controller diagnostic DID information.
|
|
27
|
-
zc_nvm (ZCNVMDef): Object with NVM definition information.
|
|
28
|
-
a2l_axis_data (dict): Dict with characteristic axis data from A2L file.
|
|
29
|
-
enums (dict): Dict with enum data.
|
|
30
|
-
"""
|
|
31
|
-
self.tl_to_autosar_base_types = {
|
|
32
|
-
"Bool": "boolean",
|
|
33
|
-
"Float32": "float32",
|
|
34
|
-
"Int16": "sint16",
|
|
35
|
-
"Int32": "sint32",
|
|
36
|
-
"Int8": "sint8",
|
|
37
|
-
"UInt16": "uint16",
|
|
38
|
-
"UInt32": "uint32",
|
|
39
|
-
"UInt8": "uint8",
|
|
40
|
-
}
|
|
41
|
-
self.build_cfg = build_cfg
|
|
42
|
-
self.unit_src_dirs = build_cfg.get_unit_src_dirs()
|
|
43
|
-
self.composition_spec = signal_if.composition_spec
|
|
44
|
-
self.external_io = signal_if.get_external_io()
|
|
45
|
-
self.unit_cfg = unit_cfg
|
|
46
|
-
self.zc_core = zc_core
|
|
47
|
-
self.zc_dids = zc_dids
|
|
48
|
-
self.zc_nvm = zc_nvm
|
|
49
|
-
self.enums = enums
|
|
50
|
-
self.a2l_axis_data = a2l_axis_data
|
|
51
|
-
base_data_types = self.get_base_data_types() # Might not be necessary in the long run
|
|
52
|
-
self.data_types = {
|
|
53
|
-
**base_data_types,
|
|
54
|
-
**self.composition_spec.get("data_types", {}),
|
|
55
|
-
}
|
|
56
|
-
self.port_interfaces = self.composition_spec.get("port_interfaces", {})
|
|
57
|
-
self.sharedSwAddrMethod = self.build_cfg.get_composition_config("includeSharedSwAddrMethod")
|
|
58
|
-
if self.sharedSwAddrMethod is not None and not isinstance(self.sharedSwAddrMethod, str):
|
|
59
|
-
self.sharedSwAddrMethod = None
|
|
60
|
-
self.critical("includeSharedSwAddrMethod must be a string if set.")
|
|
61
|
-
|
|
62
|
-
calibration_variables, measurable_variables = self._get_variables()
|
|
63
|
-
self.calibration_init_values = self.get_init_values(calibration_variables)
|
|
64
|
-
self.cal_class_info = self._get_class_info(calibration_variables)
|
|
65
|
-
self.meas_class_info = self._get_class_info(measurable_variables)
|
|
66
|
-
self.include_calibration_interface_files = False
|
|
67
|
-
if self.build_cfg.get_code_generation_config(item="generateCalibrationInterfaceFiles"):
|
|
68
|
-
self.include_calibration_interface_files = True
|
|
69
|
-
if self.build_cfg.get_code_generation_config(item="useCalibrationRteMacroExpansion"):
|
|
70
|
-
self.include_calibration_interface_files = False
|
|
71
|
-
if self.include_calibration_interface_files:
|
|
72
|
-
trigger_read_rte_cdata_signal_name = self._get_calibration_trigger_signal_name(calibration_variables)
|
|
73
|
-
self.cal_class_info["tl"]["class_info"].update({
|
|
74
|
-
trigger_read_rte_cdata_signal_name: {
|
|
75
|
-
"type": ZCC.trigger_read_rte_cdata_signal['data_type'],
|
|
76
|
-
"width": 1,
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
self.cal_class_info["autosar"]["class_info"].update(
|
|
80
|
-
{
|
|
81
|
-
trigger_read_rte_cdata_signal_name: {
|
|
82
|
-
"type": ZCC.trigger_read_rte_cdata_signal["data_type"],
|
|
83
|
-
"access": "READ-WRITE",
|
|
84
|
-
"init": 0,
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
@staticmethod
|
|
90
|
-
def _cast_init_value(value_str):
|
|
91
|
-
"""Cast initialization value to correct type.
|
|
92
|
-
|
|
93
|
-
Args:
|
|
94
|
-
value_str (str): String representation of the value.
|
|
95
|
-
Returns:
|
|
96
|
-
(int/float): Value casted to correct type.
|
|
97
|
-
"""
|
|
98
|
-
if value_str.endswith("F"):
|
|
99
|
-
return float(value_str[:-1])
|
|
100
|
-
return int(value_str)
|
|
101
|
-
|
|
102
|
-
def _prepare_for_xml(self, signal_name, string):
|
|
103
|
-
"""Prepare a string for XML serialization.
|
|
104
|
-
|
|
105
|
-
Args:
|
|
106
|
-
signal_name (str): The name of the signal.
|
|
107
|
-
string (str): The string to prepare.
|
|
108
|
-
Returns:
|
|
109
|
-
xml_string (str): The prepared string.
|
|
110
|
-
"""
|
|
111
|
-
illegal_xml_characters = {
|
|
112
|
-
"&": "&", # needs to be first in list
|
|
113
|
-
"<": "<",
|
|
114
|
-
">": ">",
|
|
115
|
-
"'": "'",
|
|
116
|
-
'"': """
|
|
117
|
-
}
|
|
118
|
-
xml_string_tmp = "".join(string.splitlines())
|
|
119
|
-
for char, replacement in illegal_xml_characters.items():
|
|
120
|
-
xml_string_tmp = xml_string_tmp.replace(char, replacement)
|
|
121
|
-
if len(xml_string_tmp) > 255:
|
|
122
|
-
self.warning(f"Converted description for {signal_name} exceeds 255 characters and will be truncated.")
|
|
123
|
-
for replacement in illegal_xml_characters.values():
|
|
124
|
-
found = xml_string_tmp.find(replacement, 255-len(replacement), 255+len(replacement))
|
|
125
|
-
if found < 255 and found + len(replacement) > 255:
|
|
126
|
-
xml_string_tmp = xml_string_tmp[:found]
|
|
127
|
-
xml_string_tmp = xml_string_tmp[:255] # Since "found" is always < 255 this is safe
|
|
128
|
-
xml_string = scalarstring.DoubleQuotedScalarString(xml_string_tmp)
|
|
129
|
-
return xml_string
|
|
130
|
-
|
|
131
|
-
def get_base_data_types(self):
|
|
132
|
-
"""Create base data types in expected Autosar/yaml2arxml format."""
|
|
133
|
-
base_data_types = {
|
|
134
|
-
"Bool": {"type": "ENUMERATION", "enums": {"False": 0, "True": 1}},
|
|
135
|
-
"Float32": {
|
|
136
|
-
"type": "FLOAT",
|
|
137
|
-
"limits": {"lower": -3.4e38, "upper": 3.4e38},
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
int_data_types = [data_type for data_type in self.tl_to_autosar_base_types if "Int" in data_type]
|
|
141
|
-
for data_type in int_data_types:
|
|
142
|
-
lower, upper = a2l_range(data_type)
|
|
143
|
-
base_data_types[data_type] = {
|
|
144
|
-
"type": "INTEGER",
|
|
145
|
-
"limits": {"lower": lower, "upper": upper},
|
|
146
|
-
}
|
|
147
|
-
return base_data_types
|
|
148
|
-
|
|
149
|
-
def generate_yaml(self):
|
|
150
|
-
"""Generates a yaml from project/model information."""
|
|
151
|
-
composition_name = self.build_cfg.get_composition_config("compositionName")
|
|
152
|
-
composition_ending = self.build_cfg.get_composition_config("compositionEnding")
|
|
153
|
-
all_info = self.gather_yaml_info()
|
|
154
|
-
|
|
155
|
-
output_directory = self.build_cfg.get_src_code_dst_dir()
|
|
156
|
-
self.info(
|
|
157
|
-
"Writing Yaml into %s/%s.%s",
|
|
158
|
-
output_directory,
|
|
159
|
-
composition_name,
|
|
160
|
-
composition_ending,
|
|
161
|
-
)
|
|
162
|
-
Path(output_directory).mkdir(parents=True, exist_ok=True)
|
|
163
|
-
|
|
164
|
-
with open(
|
|
165
|
-
f"{output_directory}/{composition_name}.{composition_ending}",
|
|
166
|
-
"w",
|
|
167
|
-
encoding="utf-8",
|
|
168
|
-
) as file:
|
|
169
|
-
yaml = YAML()
|
|
170
|
-
yaml.width = 1000 # We don't want to wrap lines in the yaml file
|
|
171
|
-
|
|
172
|
-
def modify_float_representation(s):
|
|
173
|
-
return re.sub(r"(\s-?\d+)e(?=\+|-\d)", r"\1.e", s)
|
|
174
|
-
|
|
175
|
-
yaml.dump(all_info, file, transform=modify_float_representation)
|
|
176
|
-
|
|
177
|
-
def gather_yaml_info(self):
|
|
178
|
-
"""Creates dict with relevant project/model information.
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
all_info (dict): Dict to be written to yaml.
|
|
182
|
-
"""
|
|
183
|
-
software_components, pt_build_data_types = self._get_software_components()
|
|
184
|
-
|
|
185
|
-
all_info = {
|
|
186
|
-
"ExternalFiles": {
|
|
187
|
-
"Composition": self.build_cfg.get_composition_config("compositionArxml"),
|
|
188
|
-
"GenerateExternalImplementationTypes": self.build_cfg.get_composition_config(
|
|
189
|
-
"generateExternalImplementationType"
|
|
190
|
-
),
|
|
191
|
-
},
|
|
192
|
-
"SoftwareComponents": software_components,
|
|
193
|
-
"DataTypes": {**self.data_types, **pt_build_data_types},
|
|
194
|
-
"PortInterfaces": self.port_interfaces,
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return all_info
|
|
198
|
-
|
|
199
|
-
def get_init_values(self, calibration_variables):
|
|
200
|
-
"""Get initialization values for calibration variables.
|
|
201
|
-
|
|
202
|
-
Args:
|
|
203
|
-
calibration_variables (dict): Dict of existing calibration variables.
|
|
204
|
-
Returns:
|
|
205
|
-
init_values (dict): Dictionary with initialization values for calibration variables.
|
|
206
|
-
"""
|
|
207
|
-
value_extraction_regexes = [
|
|
208
|
-
(
|
|
209
|
-
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\s*=\s*(?P<value>[-\d\.e]+F?)\s*;"),
|
|
210
|
-
lambda regex_match, _: self._cast_init_value(regex_match.group("value")),
|
|
211
|
-
),
|
|
212
|
-
(
|
|
213
|
-
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\[(?P<size>[\d]+)\]\s*=\s*"),
|
|
214
|
-
self._get_array_init_values,
|
|
215
|
-
),
|
|
216
|
-
(
|
|
217
|
-
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\[(?P<rows>[\d]+)\]\[(?P<cols>[\d]+)\]\s*=\s*"),
|
|
218
|
-
self._get_matrix_init_values,
|
|
219
|
-
),
|
|
220
|
-
(
|
|
221
|
-
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\s*=\s*(?P<enum>[a-zA-Z_$][\w_]*?)*;"),
|
|
222
|
-
lambda regex_match, _: regex_match.group("enum"),
|
|
223
|
-
),
|
|
224
|
-
]
|
|
225
|
-
|
|
226
|
-
init_values = {}
|
|
227
|
-
calibration_definitions = self._get_all_calibration_definitions()
|
|
228
|
-
calibration_definitions.reverse() # Reverse to pop from the end for performance
|
|
229
|
-
while calibration_definitions:
|
|
230
|
-
line = calibration_definitions.pop()
|
|
231
|
-
for regex, extraction_function in value_extraction_regexes:
|
|
232
|
-
regex_match = regex.match(line)
|
|
233
|
-
if regex_match is not None and regex_match.group("name") in calibration_variables:
|
|
234
|
-
if regex_match.group("name") in init_values:
|
|
235
|
-
self.critical("Variable definition for %s already found.", regex_match.group("name"))
|
|
236
|
-
init_values[regex_match.group("name")] = extraction_function(regex_match, calibration_definitions)
|
|
237
|
-
|
|
238
|
-
missing_init_values = set(calibration_variables) - set(init_values.keys())
|
|
239
|
-
if missing_init_values:
|
|
240
|
-
self.critical("Missing init values for calibration variables:\n%s", "\n".join(missing_init_values))
|
|
241
|
-
|
|
242
|
-
return init_values
|
|
243
|
-
|
|
244
|
-
def _get_all_calibration_definitions(self):
|
|
245
|
-
"""Get all calibration definitions from the source files.
|
|
246
|
-
|
|
247
|
-
Returns:
|
|
248
|
-
(iter): Iterator with calibration definitions.
|
|
249
|
-
"""
|
|
250
|
-
calibration_definitions = []
|
|
251
|
-
end_of_definitions_regex = re.compile(r"^void\s*RESTART_.*")
|
|
252
|
-
c_files = [Path(src_dir, unit.split("__")[0] + ".c").resolve() for unit, src_dir in self.unit_src_dirs.items()]
|
|
253
|
-
for c_file in c_files:
|
|
254
|
-
read_lines = ""
|
|
255
|
-
with c_file.open(mode="r", encoding="latin-1") as file_handle:
|
|
256
|
-
for line in file_handle:
|
|
257
|
-
if end_of_definitions_regex.match(line):
|
|
258
|
-
break
|
|
259
|
-
read_lines += line
|
|
260
|
-
calibration_definitions.extend(re.sub(r"/\*.*?\*/", "", read_lines, flags=re.S).splitlines())
|
|
261
|
-
return calibration_definitions
|
|
262
|
-
|
|
263
|
-
def _get_array_init_values(self, array_regex_match, definitions_list):
|
|
264
|
-
"""Get initialization values for an array.
|
|
265
|
-
|
|
266
|
-
NOTES:
|
|
267
|
-
Modifies the argument definitions_list by popping elements.
|
|
268
|
-
Popping from the end since list is reversed.
|
|
269
|
-
|
|
270
|
-
Args:
|
|
271
|
-
array_regex_match (re.Match): Match object with array definition.
|
|
272
|
-
definitions_list (list): List (reversed) with lines to parse.
|
|
273
|
-
Returns:
|
|
274
|
-
(list): List of initialization values for the array.
|
|
275
|
-
"""
|
|
276
|
-
array_init_values_str = ""
|
|
277
|
-
line = definitions_list.pop() # Skip array definition line
|
|
278
|
-
while "};" not in line:
|
|
279
|
-
array_init_values_str += line.strip()
|
|
280
|
-
line = definitions_list.pop()
|
|
281
|
-
array_init_values_str += line.strip()
|
|
282
|
-
array_init_values = re.findall(r"([-\d\.e]+F?),?", array_init_values_str)
|
|
283
|
-
|
|
284
|
-
if int(array_regex_match.group("size")) != len(array_init_values):
|
|
285
|
-
self.critical("Could not parse init values for array definition %s.", array_regex_match.group("name"))
|
|
286
|
-
|
|
287
|
-
return [self._cast_init_value(value) for value in array_init_values]
|
|
288
|
-
|
|
289
|
-
def _get_matrix_init_values(self, matrix_regex_match, definitions_list):
|
|
290
|
-
"""Get initialization values for a matrix.
|
|
291
|
-
|
|
292
|
-
NOTES:
|
|
293
|
-
Modifies the argument definitions_list by popping elements.
|
|
294
|
-
Popping from the end since list is reversed.
|
|
295
|
-
|
|
296
|
-
Args:
|
|
297
|
-
matrix_regex_match (re.Match): Match object with matrix definition.
|
|
298
|
-
definitions_list (list): List (reversed) with lines to parse.
|
|
299
|
-
Returns:
|
|
300
|
-
(list(list)): List of initialization values for the matrix.
|
|
301
|
-
"""
|
|
302
|
-
matrix_init_values = []
|
|
303
|
-
matrix_init_values_str = ""
|
|
304
|
-
line = definitions_list.pop() # Skip matrix definition line
|
|
305
|
-
while "};" not in line:
|
|
306
|
-
matrix_init_values_str += line.strip()
|
|
307
|
-
if "}" in line:
|
|
308
|
-
matrix_init_values.append(re.findall(r"([-\d\.e]+F?),?", matrix_init_values_str))
|
|
309
|
-
matrix_init_values_str = ""
|
|
310
|
-
line = definitions_list.pop()
|
|
311
|
-
|
|
312
|
-
row_check = int(matrix_regex_match.group("rows")) != len(matrix_init_values)
|
|
313
|
-
col_check = any(int(matrix_regex_match.group("cols")) != len(row) for row in matrix_init_values)
|
|
314
|
-
if row_check or col_check:
|
|
315
|
-
self.critical("Could not parse init values for matrix definition %s.", matrix_regex_match.group("name"))
|
|
316
|
-
|
|
317
|
-
return [[self._cast_init_value(value) for value in row] for row in matrix_init_values]
|
|
318
|
-
|
|
319
|
-
def _get_calibration_trigger_signal_name(self, calibration_variables):
|
|
320
|
-
"""Get the variable of the calibration trigger.
|
|
321
|
-
|
|
322
|
-
Make sure it is not present already.
|
|
323
|
-
|
|
324
|
-
Args:
|
|
325
|
-
calibration_variables (dict): Dict of existing calibration variables.
|
|
326
|
-
Returns:
|
|
327
|
-
trigger_signal (str): Name of variable for triggering calibration.
|
|
328
|
-
"""
|
|
329
|
-
software_component_name = self.build_cfg.get_composition_config("softwareComponentName")
|
|
330
|
-
trigger_signal = ZCC.trigger_read_rte_cdata_signal["name_template"].format(swc_name=software_component_name)
|
|
331
|
-
|
|
332
|
-
if trigger_signal in calibration_variables:
|
|
333
|
-
self.critical("Signal %s already defined in project.", trigger_signal)
|
|
334
|
-
|
|
335
|
-
return trigger_signal
|
|
336
|
-
|
|
337
|
-
def _edit_event_dict(self, event_dict):
|
|
338
|
-
"""Edit event dictionary to use double quoted strings on certain element values.
|
|
339
|
-
|
|
340
|
-
The elements that need to be double quoted are JumpDown, JumpUp and EnaDEMInd.
|
|
341
|
-
The values are either "on" or "off", which yaml loader still interprets as boolean.
|
|
342
|
-
Hence the need for double quotes.
|
|
343
|
-
For some reason, "true" is not interpreted as boolean though.
|
|
344
|
-
|
|
345
|
-
Args:
|
|
346
|
-
event_dict (dict): Dict with diagnostic event data.
|
|
347
|
-
Returns:
|
|
348
|
-
event_dict (dict): Dict with diagnostic event data,
|
|
349
|
-
updated with double quoted strings on certain element values."""
|
|
350
|
-
for event_data in event_dict.values():
|
|
351
|
-
for key, value in event_data.items():
|
|
352
|
-
if key in ["ACC2", "EnaDEMInd", "JumpDown", "JumpUp"]:
|
|
353
|
-
event_data[key] = scalarstring.DoubleQuotedScalarString(value)
|
|
354
|
-
return event_dict
|
|
355
|
-
|
|
356
|
-
def _get_diagnostic_info(self):
|
|
357
|
-
"""Get diagnostic information from composition spec.
|
|
358
|
-
|
|
359
|
-
NOTE: This function sets the valid_dids property of the ZCDIDs object.
|
|
360
|
-
|
|
361
|
-
Returns:
|
|
362
|
-
diag_dict (dict): Dict containing diagnostic information.
|
|
363
|
-
"""
|
|
364
|
-
diag_dict = {}
|
|
365
|
-
diagnostics = self.composition_spec.get("diagnostics", {})
|
|
366
|
-
|
|
367
|
-
if self.build_cfg.get_composition_config("includeDiagnostics") == "manual":
|
|
368
|
-
dids = diagnostics.get("dids", {})
|
|
369
|
-
events = self._edit_event_dict(diagnostics.get("events", {}))
|
|
370
|
-
elif self.build_cfg.get_composition_config("includeDiagnostics") == "manual_dids":
|
|
371
|
-
dids = diagnostics.get("dids", {})
|
|
372
|
-
events_tmp = self._edit_event_dict(diagnostics.get("events", {}))
|
|
373
|
-
events = self.zc_core.get_diagnostic_trouble_codes(events_tmp)
|
|
374
|
-
elif self.build_cfg.get_composition_config("includeDiagnostics") == "manual_dtcs":
|
|
375
|
-
self.zc_dids.valid_dids = diagnostics.get("dids", {})
|
|
376
|
-
dids = self.zc_dids.valid_dids
|
|
377
|
-
events = self._edit_event_dict(diagnostics.get("events", {}))
|
|
378
|
-
else:
|
|
379
|
-
self.zc_dids.valid_dids = diagnostics.get("dids", {})
|
|
380
|
-
dids = self.zc_dids.valid_dids
|
|
381
|
-
events_tmp = self._edit_event_dict(diagnostics.get("events", {}))
|
|
382
|
-
events = self.zc_core.get_diagnostic_trouble_codes(events_tmp)
|
|
383
|
-
rids = diagnostics.get("rids", {})
|
|
384
|
-
|
|
385
|
-
if dids:
|
|
386
|
-
diag_dict["dids"] = dids
|
|
387
|
-
if events:
|
|
388
|
-
diag_dict["events"] = events
|
|
389
|
-
if rids:
|
|
390
|
-
diag_dict["rids"] = rids
|
|
391
|
-
self.warning("Will not generate code for RIDs, add manually.")
|
|
392
|
-
return diag_dict
|
|
393
|
-
|
|
394
|
-
def _get_nvm_info(self):
|
|
395
|
-
"""Creates a dict with NVM information.
|
|
396
|
-
|
|
397
|
-
NVM dicts also needs to be added to the "static" field in the generated yaml.
|
|
398
|
-
|
|
399
|
-
NOTE: This function sets the valid_nvm_definitions property of the ZCNVMDef object.
|
|
400
|
-
|
|
401
|
-
Returns:
|
|
402
|
-
nvm_dict (dict): Dict containing NVM information.
|
|
403
|
-
data_types (dict): Dict containing data types for NVM information.
|
|
404
|
-
static_variables (dict): Dict containing "static" variables to add to the "static" field.
|
|
405
|
-
"""
|
|
406
|
-
data_types = {}
|
|
407
|
-
static_variables = {}
|
|
408
|
-
yaml_nvm_definitions = self.composition_spec.get("nv-needs", {})
|
|
409
|
-
self.zc_nvm.valid_nvm_definitions = yaml_nvm_definitions
|
|
410
|
-
nvm_dict = self.zc_nvm.valid_nvm_definitions
|
|
411
|
-
|
|
412
|
-
for nvm_name, nvm_data in nvm_dict.items():
|
|
413
|
-
init = []
|
|
414
|
-
nr_of_unused_signals = self.zc_nvm.project_nvm_definitions[nvm_name]["size"]
|
|
415
|
-
data_type_name = f"dt_{nvm_name}"
|
|
416
|
-
data_types[data_type_name] = {"type": "RECORD", "elements": {}}
|
|
417
|
-
for signal in self.zc_nvm.project_nvm_definitions[nvm_name]["signals"]:
|
|
418
|
-
element_name = f'{self.zc_nvm.struct_member_prefix}{signal["name"]}'
|
|
419
|
-
nr_of_unused_signals -= signal["x_size"] * signal["y_size"]
|
|
420
|
-
size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
|
|
421
|
-
if size > 1:
|
|
422
|
-
x_data_type_name = f"dt_{signal['name']}_x"
|
|
423
|
-
y_data_type_name = f"dt_{signal['name']}_y"
|
|
424
|
-
if signal["x_size"] > 1 and signal["y_size"] == 1:
|
|
425
|
-
init.append([0] * signal["x_size"])
|
|
426
|
-
data_types[data_type_name]["elements"][element_name] = x_data_type_name
|
|
427
|
-
data_types[x_data_type_name] = {
|
|
428
|
-
"type": "ARRAY",
|
|
429
|
-
"size": signal["x_size"],
|
|
430
|
-
"element": signal["type"],
|
|
431
|
-
}
|
|
432
|
-
elif signal["x_size"] > 1 and signal["y_size"] > 1:
|
|
433
|
-
init.append([[0] * signal["y_size"]] * signal["x_size"])
|
|
434
|
-
data_types[data_type_name]["elements"][element_name] = y_data_type_name
|
|
435
|
-
data_types[y_data_type_name] = {
|
|
436
|
-
"type": "ARRAY",
|
|
437
|
-
"size": signal["y_size"],
|
|
438
|
-
"element": x_data_type_name,
|
|
439
|
-
}
|
|
440
|
-
data_types[x_data_type_name] = {
|
|
441
|
-
"type": "ARRAY",
|
|
442
|
-
"size": signal["x_size"],
|
|
443
|
-
"element": signal["type"],
|
|
444
|
-
}
|
|
445
|
-
else:
|
|
446
|
-
self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1.")
|
|
447
|
-
else:
|
|
448
|
-
init.append(0)
|
|
449
|
-
data_types[data_type_name]["elements"][element_name] = signal["type"]
|
|
450
|
-
|
|
451
|
-
nvm_data.update({
|
|
452
|
-
"datatype": data_type_name,
|
|
453
|
-
"init": init
|
|
454
|
-
})
|
|
455
|
-
static_variables[nvm_name.lower()] = {
|
|
456
|
-
"type": data_type_name,
|
|
457
|
-
"access": "READ-ONLY",
|
|
458
|
-
"init": init,
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if nr_of_unused_signals > 0:
|
|
462
|
-
# Mimics how we generate the unused member of the structs in nvm_def.py
|
|
463
|
-
nvm_data["init"].append([0] * nr_of_unused_signals)
|
|
464
|
-
data_types[data_type_name]["elements"]["unused"] = f"{data_type_name}_Unused"
|
|
465
|
-
data_types[f"{data_type_name}_Unused"] = {
|
|
466
|
-
"type": "ARRAY",
|
|
467
|
-
"size": nr_of_unused_signals,
|
|
468
|
-
"element": self.zc_nvm.project_nvm_definitions[nvm_name]["default_datatype"],
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return nvm_dict, data_types, static_variables
|
|
472
|
-
|
|
473
|
-
def _get_ports_info(self):
|
|
474
|
-
"""Creates a dict containing port information.
|
|
475
|
-
|
|
476
|
-
Returns:
|
|
477
|
-
ports (dict): Dict containing port information.
|
|
478
|
-
"""
|
|
479
|
-
ports = self.composition_spec.get("ports", {})
|
|
480
|
-
for call, call_data in self.composition_spec.get("calls", {}).items():
|
|
481
|
-
if call in ports:
|
|
482
|
-
continue
|
|
483
|
-
ports[call] = {
|
|
484
|
-
"interface": call_data.get("interface", call),
|
|
485
|
-
"direction": call_data["direction"],
|
|
486
|
-
}
|
|
487
|
-
return ports
|
|
488
|
-
|
|
489
|
-
def _get_runnable_calls_info(self):
|
|
490
|
-
"""Creates a dict containing desired calls for the SWC.
|
|
491
|
-
|
|
492
|
-
Returns:
|
|
493
|
-
call_dict(dict): Dict containing runnable calls information.
|
|
494
|
-
"""
|
|
495
|
-
call_dict = {}
|
|
496
|
-
for call, call_data in self.composition_spec.get("calls", {}).items():
|
|
497
|
-
call_dict[call] = {"operation": call_data["operation"]}
|
|
498
|
-
if "timeout" in call_data:
|
|
499
|
-
call_dict[call]["timeout"] = call_data["timeout"]
|
|
500
|
-
return call_dict
|
|
501
|
-
|
|
502
|
-
def _get_runnable_info(self):
|
|
503
|
-
"""Creates a dict containing runnables information.
|
|
504
|
-
|
|
505
|
-
Returns:
|
|
506
|
-
dict: Dict containing runnables information.
|
|
507
|
-
"""
|
|
508
|
-
autosar_prefix = "AR_"
|
|
509
|
-
swc_prefix = self.build_cfg.get_scheduler_prefix()
|
|
510
|
-
custom_step_function = self.build_cfg.get_composition_config("customYamlStepFunctionName")
|
|
511
|
-
custom_init_function = self.build_cfg.get_composition_config("customYamlInitFunctionName")
|
|
512
|
-
standard_init_function = autosar_prefix + swc_prefix + "VcExtINI"
|
|
513
|
-
init_function = custom_init_function if custom_init_function is not None else standard_init_function
|
|
514
|
-
calibration_variables = list(
|
|
515
|
-
self.cal_class_info["autosar"]["class_info"].keys()
|
|
516
|
-
) + list(
|
|
517
|
-
self.composition_spec.get("shared", {}).keys()
|
|
518
|
-
)
|
|
519
|
-
swc_content = {
|
|
520
|
-
init_function: {
|
|
521
|
-
"type": "INIT",
|
|
522
|
-
"mode_ref": {
|
|
523
|
-
"port": "EcuMVccActivationMode",
|
|
524
|
-
"mode": ["VCC_ACTIVE"],
|
|
525
|
-
"trigger": "ON-ENTRY"
|
|
526
|
-
},
|
|
527
|
-
"accesses": calibration_variables
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if self.include_calibration_interface_files:
|
|
532
|
-
swc_name = self.build_cfg.get_composition_config("softwareComponentName")
|
|
533
|
-
cal_init_function = autosar_prefix + ZCC.calibration_function_init_template.format(swc_name=swc_name)
|
|
534
|
-
cal_step_function = autosar_prefix + ZCC.calibration_function_step_template.format(swc_name=swc_name)
|
|
535
|
-
swc_content[cal_init_function] = {
|
|
536
|
-
"type": "INIT",
|
|
537
|
-
"mode_ref": {
|
|
538
|
-
"port": "EcuMVccActivationMode",
|
|
539
|
-
"mode": ["VCC_ACTIVE"],
|
|
540
|
-
"trigger": "ON-ENTRY"
|
|
541
|
-
},
|
|
542
|
-
"
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
"
|
|
547
|
-
"
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
"
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if
|
|
576
|
-
swc_content[custom_step_function]["
|
|
577
|
-
if
|
|
578
|
-
swc_content[custom_step_function]["
|
|
579
|
-
if
|
|
580
|
-
swc_content[custom_step_function]["
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
"
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if
|
|
601
|
-
swc_content[key]["
|
|
602
|
-
if
|
|
603
|
-
swc_content[key]["
|
|
604
|
-
if
|
|
605
|
-
swc_content[key]["
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
swcs
|
|
620
|
-
swcs[software_component_name]["
|
|
621
|
-
swcs[software_component_name]["
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if self.composition_spec.get("
|
|
648
|
-
swcs[software_component_name]["
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
**
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
(dict): Dictionary with variables and data
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
"
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
"
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
if info["
|
|
763
|
-
class_info[signal_name]["
|
|
764
|
-
if
|
|
765
|
-
class_info[signal_name]["
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
init = [init] * info["width"][1]
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
"
|
|
797
|
-
"
|
|
798
|
-
"
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
"
|
|
802
|
-
"
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
"
|
|
811
|
-
"
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
"
|
|
815
|
-
"
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
"
|
|
826
|
-
"
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
"
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
new_data_type_data["
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
"
|
|
845
|
-
"
|
|
846
|
-
"
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
"
|
|
850
|
-
"
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
"
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
"
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
if
|
|
876
|
-
class_info[signal_name]["
|
|
877
|
-
|
|
878
|
-
|
|
1
|
+
# Copyright 2024 Volvo Car Corporation
|
|
2
|
+
# Licensed under Apache 2.0.
|
|
3
|
+
|
|
4
|
+
"""Module for handling ZoneController composition yaml generation."""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from ruamel.yaml import YAML, scalarstring
|
|
9
|
+
|
|
10
|
+
from powertrain_build.problem_logger import ProblemLogger
|
|
11
|
+
from powertrain_build.types import a2l_range
|
|
12
|
+
from powertrain_build.zone_controller.calibration import ZoneControllerCalibration as ZCC
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CompositionYaml(ProblemLogger):
|
|
16
|
+
"""Class for handling ZoneController composition yaml generation."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, build_cfg, signal_if, unit_cfg, zc_core, zc_dids, zc_nvm, a2l_axis_data, enums):
|
|
19
|
+
"""Init.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
build_cfg (BuildProjConfig): Object with build configuration settings.
|
|
23
|
+
signal_if (SignalInterfaces): Class holding signal interface information.
|
|
24
|
+
unit_cfg (UnitConfig): Object with unit configurations.
|
|
25
|
+
zc_core (ZCCore): Object with zone controller diagnositic event information.
|
|
26
|
+
zc_dids (ZCDIDs): Object with zone controller diagnostic DID information.
|
|
27
|
+
zc_nvm (ZCNVMDef): Object with NVM definition information.
|
|
28
|
+
a2l_axis_data (dict): Dict with characteristic axis data from A2L file.
|
|
29
|
+
enums (dict): Dict with enum data.
|
|
30
|
+
"""
|
|
31
|
+
self.tl_to_autosar_base_types = {
|
|
32
|
+
"Bool": "boolean",
|
|
33
|
+
"Float32": "float32",
|
|
34
|
+
"Int16": "sint16",
|
|
35
|
+
"Int32": "sint32",
|
|
36
|
+
"Int8": "sint8",
|
|
37
|
+
"UInt16": "uint16",
|
|
38
|
+
"UInt32": "uint32",
|
|
39
|
+
"UInt8": "uint8",
|
|
40
|
+
}
|
|
41
|
+
self.build_cfg = build_cfg
|
|
42
|
+
self.unit_src_dirs = build_cfg.get_unit_src_dirs()
|
|
43
|
+
self.composition_spec = signal_if.composition_spec
|
|
44
|
+
self.external_io = signal_if.get_external_io()
|
|
45
|
+
self.unit_cfg = unit_cfg
|
|
46
|
+
self.zc_core = zc_core
|
|
47
|
+
self.zc_dids = zc_dids
|
|
48
|
+
self.zc_nvm = zc_nvm
|
|
49
|
+
self.enums = enums
|
|
50
|
+
self.a2l_axis_data = a2l_axis_data
|
|
51
|
+
base_data_types = self.get_base_data_types() # Might not be necessary in the long run
|
|
52
|
+
self.data_types = {
|
|
53
|
+
**base_data_types,
|
|
54
|
+
**self.composition_spec.get("data_types", {}),
|
|
55
|
+
}
|
|
56
|
+
self.port_interfaces = self.composition_spec.get("port_interfaces", {})
|
|
57
|
+
self.sharedSwAddrMethod = self.build_cfg.get_composition_config("includeSharedSwAddrMethod")
|
|
58
|
+
if self.sharedSwAddrMethod is not None and not isinstance(self.sharedSwAddrMethod, str):
|
|
59
|
+
self.sharedSwAddrMethod = None
|
|
60
|
+
self.critical("includeSharedSwAddrMethod must be a string if set.")
|
|
61
|
+
|
|
62
|
+
calibration_variables, measurable_variables = self._get_variables()
|
|
63
|
+
self.calibration_init_values = self.get_init_values(calibration_variables)
|
|
64
|
+
self.cal_class_info = self._get_class_info(calibration_variables)
|
|
65
|
+
self.meas_class_info = self._get_class_info(measurable_variables)
|
|
66
|
+
self.include_calibration_interface_files = False
|
|
67
|
+
if self.build_cfg.get_code_generation_config(item="generateCalibrationInterfaceFiles"):
|
|
68
|
+
self.include_calibration_interface_files = True
|
|
69
|
+
if self.build_cfg.get_code_generation_config(item="useCalibrationRteMacroExpansion"):
|
|
70
|
+
self.include_calibration_interface_files = False
|
|
71
|
+
if self.include_calibration_interface_files:
|
|
72
|
+
trigger_read_rte_cdata_signal_name = self._get_calibration_trigger_signal_name(calibration_variables)
|
|
73
|
+
self.cal_class_info["tl"]["class_info"].update({
|
|
74
|
+
trigger_read_rte_cdata_signal_name: {
|
|
75
|
+
"type": ZCC.trigger_read_rte_cdata_signal['data_type'],
|
|
76
|
+
"width": 1,
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
self.cal_class_info["autosar"]["class_info"].update(
|
|
80
|
+
{
|
|
81
|
+
trigger_read_rte_cdata_signal_name: {
|
|
82
|
+
"type": ZCC.trigger_read_rte_cdata_signal["data_type"],
|
|
83
|
+
"access": "READ-WRITE",
|
|
84
|
+
"init": 0,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def _cast_init_value(value_str):
|
|
91
|
+
"""Cast initialization value to correct type.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
value_str (str): String representation of the value.
|
|
95
|
+
Returns:
|
|
96
|
+
(int/float): Value casted to correct type.
|
|
97
|
+
"""
|
|
98
|
+
if value_str.endswith("F"):
|
|
99
|
+
return float(value_str[:-1])
|
|
100
|
+
return int(value_str)
|
|
101
|
+
|
|
102
|
+
def _prepare_for_xml(self, signal_name, string):
|
|
103
|
+
"""Prepare a string for XML serialization.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
signal_name (str): The name of the signal.
|
|
107
|
+
string (str): The string to prepare.
|
|
108
|
+
Returns:
|
|
109
|
+
xml_string (str): The prepared string.
|
|
110
|
+
"""
|
|
111
|
+
illegal_xml_characters = {
|
|
112
|
+
"&": "&", # needs to be first in list
|
|
113
|
+
"<": "<",
|
|
114
|
+
">": ">",
|
|
115
|
+
"'": "'",
|
|
116
|
+
'"': """
|
|
117
|
+
}
|
|
118
|
+
xml_string_tmp = "".join(string.splitlines())
|
|
119
|
+
for char, replacement in illegal_xml_characters.items():
|
|
120
|
+
xml_string_tmp = xml_string_tmp.replace(char, replacement)
|
|
121
|
+
if len(xml_string_tmp) > 255:
|
|
122
|
+
self.warning(f"Converted description for {signal_name} exceeds 255 characters and will be truncated.")
|
|
123
|
+
for replacement in illegal_xml_characters.values():
|
|
124
|
+
found = xml_string_tmp.find(replacement, 255-len(replacement), 255+len(replacement))
|
|
125
|
+
if found < 255 and found + len(replacement) > 255:
|
|
126
|
+
xml_string_tmp = xml_string_tmp[:found]
|
|
127
|
+
xml_string_tmp = xml_string_tmp[:255] # Since "found" is always < 255 this is safe
|
|
128
|
+
xml_string = scalarstring.DoubleQuotedScalarString(xml_string_tmp)
|
|
129
|
+
return xml_string
|
|
130
|
+
|
|
131
|
+
def get_base_data_types(self):
|
|
132
|
+
"""Create base data types in expected Autosar/yaml2arxml format."""
|
|
133
|
+
base_data_types = {
|
|
134
|
+
"Bool": {"type": "ENUMERATION", "enums": {"False": 0, "True": 1}},
|
|
135
|
+
"Float32": {
|
|
136
|
+
"type": "FLOAT",
|
|
137
|
+
"limits": {"lower": -3.4e38, "upper": 3.4e38},
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
int_data_types = [data_type for data_type in self.tl_to_autosar_base_types if "Int" in data_type]
|
|
141
|
+
for data_type in int_data_types:
|
|
142
|
+
lower, upper = a2l_range(data_type)
|
|
143
|
+
base_data_types[data_type] = {
|
|
144
|
+
"type": "INTEGER",
|
|
145
|
+
"limits": {"lower": lower, "upper": upper},
|
|
146
|
+
}
|
|
147
|
+
return base_data_types
|
|
148
|
+
|
|
149
|
+
def generate_yaml(self):
|
|
150
|
+
"""Generates a yaml from project/model information."""
|
|
151
|
+
composition_name = self.build_cfg.get_composition_config("compositionName")
|
|
152
|
+
composition_ending = self.build_cfg.get_composition_config("compositionEnding")
|
|
153
|
+
all_info = self.gather_yaml_info()
|
|
154
|
+
|
|
155
|
+
output_directory = self.build_cfg.get_src_code_dst_dir()
|
|
156
|
+
self.info(
|
|
157
|
+
"Writing Yaml into %s/%s.%s",
|
|
158
|
+
output_directory,
|
|
159
|
+
composition_name,
|
|
160
|
+
composition_ending,
|
|
161
|
+
)
|
|
162
|
+
Path(output_directory).mkdir(parents=True, exist_ok=True)
|
|
163
|
+
|
|
164
|
+
with open(
|
|
165
|
+
f"{output_directory}/{composition_name}.{composition_ending}",
|
|
166
|
+
"w",
|
|
167
|
+
encoding="utf-8",
|
|
168
|
+
) as file:
|
|
169
|
+
yaml = YAML()
|
|
170
|
+
yaml.width = 1000 # We don't want to wrap lines in the yaml file
|
|
171
|
+
|
|
172
|
+
def modify_float_representation(s):
|
|
173
|
+
return re.sub(r"(\s-?\d+)e(?=\+|-\d)", r"\1.e", s)
|
|
174
|
+
|
|
175
|
+
yaml.dump(all_info, file, transform=modify_float_representation)
|
|
176
|
+
|
|
177
|
+
def gather_yaml_info(self):
|
|
178
|
+
"""Creates dict with relevant project/model information.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
all_info (dict): Dict to be written to yaml.
|
|
182
|
+
"""
|
|
183
|
+
software_components, pt_build_data_types = self._get_software_components()
|
|
184
|
+
|
|
185
|
+
all_info = {
|
|
186
|
+
"ExternalFiles": {
|
|
187
|
+
"Composition": self.build_cfg.get_composition_config("compositionArxml"),
|
|
188
|
+
"GenerateExternalImplementationTypes": self.build_cfg.get_composition_config(
|
|
189
|
+
"generateExternalImplementationType"
|
|
190
|
+
),
|
|
191
|
+
},
|
|
192
|
+
"SoftwareComponents": software_components,
|
|
193
|
+
"DataTypes": {**self.data_types, **pt_build_data_types},
|
|
194
|
+
"PortInterfaces": self.port_interfaces,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return all_info
|
|
198
|
+
|
|
199
|
+
def get_init_values(self, calibration_variables):
|
|
200
|
+
"""Get initialization values for calibration variables.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
calibration_variables (dict): Dict of existing calibration variables.
|
|
204
|
+
Returns:
|
|
205
|
+
init_values (dict): Dictionary with initialization values for calibration variables.
|
|
206
|
+
"""
|
|
207
|
+
value_extraction_regexes = [
|
|
208
|
+
(
|
|
209
|
+
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\s*=\s*(?P<value>[-\d\.e]+F?)\s*;"),
|
|
210
|
+
lambda regex_match, _: self._cast_init_value(regex_match.group("value")),
|
|
211
|
+
),
|
|
212
|
+
(
|
|
213
|
+
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\[(?P<size>[\d]+)\]\s*=\s*"),
|
|
214
|
+
self._get_array_init_values,
|
|
215
|
+
),
|
|
216
|
+
(
|
|
217
|
+
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\[(?P<rows>[\d]+)\]\[(?P<cols>[\d]+)\]\s*=\s*"),
|
|
218
|
+
self._get_matrix_init_values,
|
|
219
|
+
),
|
|
220
|
+
(
|
|
221
|
+
re.compile(r"^\s*CVC_CAL[A-Z_]*\s+\w+\s+(?P<name>\w+)\s*=\s*(?P<enum>[a-zA-Z_$][\w_]*?)*;"),
|
|
222
|
+
lambda regex_match, _: regex_match.group("enum"),
|
|
223
|
+
),
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
init_values = {}
|
|
227
|
+
calibration_definitions = self._get_all_calibration_definitions()
|
|
228
|
+
calibration_definitions.reverse() # Reverse to pop from the end for performance
|
|
229
|
+
while calibration_definitions:
|
|
230
|
+
line = calibration_definitions.pop()
|
|
231
|
+
for regex, extraction_function in value_extraction_regexes:
|
|
232
|
+
regex_match = regex.match(line)
|
|
233
|
+
if regex_match is not None and regex_match.group("name") in calibration_variables:
|
|
234
|
+
if regex_match.group("name") in init_values:
|
|
235
|
+
self.critical("Variable definition for %s already found.", regex_match.group("name"))
|
|
236
|
+
init_values[regex_match.group("name")] = extraction_function(regex_match, calibration_definitions)
|
|
237
|
+
|
|
238
|
+
missing_init_values = set(calibration_variables) - set(init_values.keys())
|
|
239
|
+
if missing_init_values:
|
|
240
|
+
self.critical("Missing init values for calibration variables:\n%s", "\n".join(missing_init_values))
|
|
241
|
+
|
|
242
|
+
return init_values
|
|
243
|
+
|
|
244
|
+
def _get_all_calibration_definitions(self):
|
|
245
|
+
"""Get all calibration definitions from the source files.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
(iter): Iterator with calibration definitions.
|
|
249
|
+
"""
|
|
250
|
+
calibration_definitions = []
|
|
251
|
+
end_of_definitions_regex = re.compile(r"^void\s*RESTART_.*")
|
|
252
|
+
c_files = [Path(src_dir, unit.split("__")[0] + ".c").resolve() for unit, src_dir in self.unit_src_dirs.items()]
|
|
253
|
+
for c_file in c_files:
|
|
254
|
+
read_lines = ""
|
|
255
|
+
with c_file.open(mode="r", encoding="latin-1") as file_handle:
|
|
256
|
+
for line in file_handle:
|
|
257
|
+
if end_of_definitions_regex.match(line):
|
|
258
|
+
break
|
|
259
|
+
read_lines += line
|
|
260
|
+
calibration_definitions.extend(re.sub(r"/\*.*?\*/", "", read_lines, flags=re.S).splitlines())
|
|
261
|
+
return calibration_definitions
|
|
262
|
+
|
|
263
|
+
def _get_array_init_values(self, array_regex_match, definitions_list):
|
|
264
|
+
"""Get initialization values for an array.
|
|
265
|
+
|
|
266
|
+
NOTES:
|
|
267
|
+
Modifies the argument definitions_list by popping elements.
|
|
268
|
+
Popping from the end since list is reversed.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
array_regex_match (re.Match): Match object with array definition.
|
|
272
|
+
definitions_list (list): List (reversed) with lines to parse.
|
|
273
|
+
Returns:
|
|
274
|
+
(list): List of initialization values for the array.
|
|
275
|
+
"""
|
|
276
|
+
array_init_values_str = ""
|
|
277
|
+
line = definitions_list.pop() # Skip array definition line
|
|
278
|
+
while "};" not in line:
|
|
279
|
+
array_init_values_str += line.strip()
|
|
280
|
+
line = definitions_list.pop()
|
|
281
|
+
array_init_values_str += line.strip()
|
|
282
|
+
array_init_values = re.findall(r"([-\d\.e]+F?),?", array_init_values_str)
|
|
283
|
+
|
|
284
|
+
if int(array_regex_match.group("size")) != len(array_init_values):
|
|
285
|
+
self.critical("Could not parse init values for array definition %s.", array_regex_match.group("name"))
|
|
286
|
+
|
|
287
|
+
return [self._cast_init_value(value) for value in array_init_values]
|
|
288
|
+
|
|
289
|
+
def _get_matrix_init_values(self, matrix_regex_match, definitions_list):
|
|
290
|
+
"""Get initialization values for a matrix.
|
|
291
|
+
|
|
292
|
+
NOTES:
|
|
293
|
+
Modifies the argument definitions_list by popping elements.
|
|
294
|
+
Popping from the end since list is reversed.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
matrix_regex_match (re.Match): Match object with matrix definition.
|
|
298
|
+
definitions_list (list): List (reversed) with lines to parse.
|
|
299
|
+
Returns:
|
|
300
|
+
(list(list)): List of initialization values for the matrix.
|
|
301
|
+
"""
|
|
302
|
+
matrix_init_values = []
|
|
303
|
+
matrix_init_values_str = ""
|
|
304
|
+
line = definitions_list.pop() # Skip matrix definition line
|
|
305
|
+
while "};" not in line:
|
|
306
|
+
matrix_init_values_str += line.strip()
|
|
307
|
+
if "}" in line:
|
|
308
|
+
matrix_init_values.append(re.findall(r"([-\d\.e]+F?),?", matrix_init_values_str))
|
|
309
|
+
matrix_init_values_str = ""
|
|
310
|
+
line = definitions_list.pop()
|
|
311
|
+
|
|
312
|
+
row_check = int(matrix_regex_match.group("rows")) != len(matrix_init_values)
|
|
313
|
+
col_check = any(int(matrix_regex_match.group("cols")) != len(row) for row in matrix_init_values)
|
|
314
|
+
if row_check or col_check:
|
|
315
|
+
self.critical("Could not parse init values for matrix definition %s.", matrix_regex_match.group("name"))
|
|
316
|
+
|
|
317
|
+
return [[self._cast_init_value(value) for value in row] for row in matrix_init_values]
|
|
318
|
+
|
|
319
|
+
def _get_calibration_trigger_signal_name(self, calibration_variables):
|
|
320
|
+
"""Get the variable of the calibration trigger.
|
|
321
|
+
|
|
322
|
+
Make sure it is not present already.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
calibration_variables (dict): Dict of existing calibration variables.
|
|
326
|
+
Returns:
|
|
327
|
+
trigger_signal (str): Name of variable for triggering calibration.
|
|
328
|
+
"""
|
|
329
|
+
software_component_name = self.build_cfg.get_composition_config("softwareComponentName")
|
|
330
|
+
trigger_signal = ZCC.trigger_read_rte_cdata_signal["name_template"].format(swc_name=software_component_name)
|
|
331
|
+
|
|
332
|
+
if trigger_signal in calibration_variables:
|
|
333
|
+
self.critical("Signal %s already defined in project.", trigger_signal)
|
|
334
|
+
|
|
335
|
+
return trigger_signal
|
|
336
|
+
|
|
337
|
+
def _edit_event_dict(self, event_dict):
|
|
338
|
+
"""Edit event dictionary to use double quoted strings on certain element values.
|
|
339
|
+
|
|
340
|
+
The elements that need to be double quoted are JumpDown, JumpUp and EnaDEMInd.
|
|
341
|
+
The values are either "on" or "off", which yaml loader still interprets as boolean.
|
|
342
|
+
Hence the need for double quotes.
|
|
343
|
+
For some reason, "true" is not interpreted as boolean though.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
event_dict (dict): Dict with diagnostic event data.
|
|
347
|
+
Returns:
|
|
348
|
+
event_dict (dict): Dict with diagnostic event data,
|
|
349
|
+
updated with double quoted strings on certain element values."""
|
|
350
|
+
for event_data in event_dict.values():
|
|
351
|
+
for key, value in event_data.items():
|
|
352
|
+
if key in ["ACC2", "EnaDEMInd", "JumpDown", "JumpUp"]:
|
|
353
|
+
event_data[key] = scalarstring.DoubleQuotedScalarString(value)
|
|
354
|
+
return event_dict
|
|
355
|
+
|
|
356
|
+
def _get_diagnostic_info(self):
|
|
357
|
+
"""Get diagnostic information from composition spec.
|
|
358
|
+
|
|
359
|
+
NOTE: This function sets the valid_dids property of the ZCDIDs object.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
diag_dict (dict): Dict containing diagnostic information.
|
|
363
|
+
"""
|
|
364
|
+
diag_dict = {}
|
|
365
|
+
diagnostics = self.composition_spec.get("diagnostics", {})
|
|
366
|
+
|
|
367
|
+
if self.build_cfg.get_composition_config("includeDiagnostics") == "manual":
|
|
368
|
+
dids = diagnostics.get("dids", {})
|
|
369
|
+
events = self._edit_event_dict(diagnostics.get("events", {}))
|
|
370
|
+
elif self.build_cfg.get_composition_config("includeDiagnostics") == "manual_dids":
|
|
371
|
+
dids = diagnostics.get("dids", {})
|
|
372
|
+
events_tmp = self._edit_event_dict(diagnostics.get("events", {}))
|
|
373
|
+
events = self.zc_core.get_diagnostic_trouble_codes(events_tmp)
|
|
374
|
+
elif self.build_cfg.get_composition_config("includeDiagnostics") == "manual_dtcs":
|
|
375
|
+
self.zc_dids.valid_dids = diagnostics.get("dids", {})
|
|
376
|
+
dids = self.zc_dids.valid_dids
|
|
377
|
+
events = self._edit_event_dict(diagnostics.get("events", {}))
|
|
378
|
+
else:
|
|
379
|
+
self.zc_dids.valid_dids = diagnostics.get("dids", {})
|
|
380
|
+
dids = self.zc_dids.valid_dids
|
|
381
|
+
events_tmp = self._edit_event_dict(diagnostics.get("events", {}))
|
|
382
|
+
events = self.zc_core.get_diagnostic_trouble_codes(events_tmp)
|
|
383
|
+
rids = diagnostics.get("rids", {})
|
|
384
|
+
|
|
385
|
+
if dids:
|
|
386
|
+
diag_dict["dids"] = dids
|
|
387
|
+
if events:
|
|
388
|
+
diag_dict["events"] = events
|
|
389
|
+
if rids:
|
|
390
|
+
diag_dict["rids"] = rids
|
|
391
|
+
self.warning("Will not generate code for RIDs, add manually.")
|
|
392
|
+
return diag_dict
|
|
393
|
+
|
|
394
|
+
def _get_nvm_info(self):
|
|
395
|
+
"""Creates a dict with NVM information.
|
|
396
|
+
|
|
397
|
+
NVM dicts also needs to be added to the "static" field in the generated yaml.
|
|
398
|
+
|
|
399
|
+
NOTE: This function sets the valid_nvm_definitions property of the ZCNVMDef object.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
nvm_dict (dict): Dict containing NVM information.
|
|
403
|
+
data_types (dict): Dict containing data types for NVM information.
|
|
404
|
+
static_variables (dict): Dict containing "static" variables to add to the "static" field.
|
|
405
|
+
"""
|
|
406
|
+
data_types = {}
|
|
407
|
+
static_variables = {}
|
|
408
|
+
yaml_nvm_definitions = self.composition_spec.get("nv-needs", {})
|
|
409
|
+
self.zc_nvm.valid_nvm_definitions = yaml_nvm_definitions
|
|
410
|
+
nvm_dict = self.zc_nvm.valid_nvm_definitions
|
|
411
|
+
|
|
412
|
+
for nvm_name, nvm_data in nvm_dict.items():
|
|
413
|
+
init = []
|
|
414
|
+
nr_of_unused_signals = self.zc_nvm.project_nvm_definitions[nvm_name]["size"]
|
|
415
|
+
data_type_name = f"dt_{nvm_name}"
|
|
416
|
+
data_types[data_type_name] = {"type": "RECORD", "elements": {}}
|
|
417
|
+
for signal in self.zc_nvm.project_nvm_definitions[nvm_name]["signals"]:
|
|
418
|
+
element_name = f'{self.zc_nvm.struct_member_prefix}{signal["name"]}'
|
|
419
|
+
nr_of_unused_signals -= signal["x_size"] * signal["y_size"]
|
|
420
|
+
size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
|
|
421
|
+
if size > 1:
|
|
422
|
+
x_data_type_name = f"dt_{signal['name']}_x"
|
|
423
|
+
y_data_type_name = f"dt_{signal['name']}_y"
|
|
424
|
+
if signal["x_size"] > 1 and signal["y_size"] == 1:
|
|
425
|
+
init.append([0] * signal["x_size"])
|
|
426
|
+
data_types[data_type_name]["elements"][element_name] = x_data_type_name
|
|
427
|
+
data_types[x_data_type_name] = {
|
|
428
|
+
"type": "ARRAY",
|
|
429
|
+
"size": signal["x_size"],
|
|
430
|
+
"element": signal["type"],
|
|
431
|
+
}
|
|
432
|
+
elif signal["x_size"] > 1 and signal["y_size"] > 1:
|
|
433
|
+
init.append([[0] * signal["y_size"]] * signal["x_size"])
|
|
434
|
+
data_types[data_type_name]["elements"][element_name] = y_data_type_name
|
|
435
|
+
data_types[y_data_type_name] = {
|
|
436
|
+
"type": "ARRAY",
|
|
437
|
+
"size": signal["y_size"],
|
|
438
|
+
"element": x_data_type_name,
|
|
439
|
+
}
|
|
440
|
+
data_types[x_data_type_name] = {
|
|
441
|
+
"type": "ARRAY",
|
|
442
|
+
"size": signal["x_size"],
|
|
443
|
+
"element": signal["type"],
|
|
444
|
+
}
|
|
445
|
+
else:
|
|
446
|
+
self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1.")
|
|
447
|
+
else:
|
|
448
|
+
init.append(0)
|
|
449
|
+
data_types[data_type_name]["elements"][element_name] = signal["type"]
|
|
450
|
+
|
|
451
|
+
nvm_data.update({
|
|
452
|
+
"datatype": data_type_name,
|
|
453
|
+
"init": init
|
|
454
|
+
})
|
|
455
|
+
static_variables[nvm_name.lower()] = {
|
|
456
|
+
"type": data_type_name,
|
|
457
|
+
"access": "READ-ONLY",
|
|
458
|
+
"init": init,
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if nr_of_unused_signals > 0:
|
|
462
|
+
# Mimics how we generate the unused member of the structs in nvm_def.py
|
|
463
|
+
nvm_data["init"].append([0] * nr_of_unused_signals)
|
|
464
|
+
data_types[data_type_name]["elements"]["unused"] = f"{data_type_name}_Unused"
|
|
465
|
+
data_types[f"{data_type_name}_Unused"] = {
|
|
466
|
+
"type": "ARRAY",
|
|
467
|
+
"size": nr_of_unused_signals,
|
|
468
|
+
"element": self.zc_nvm.project_nvm_definitions[nvm_name]["default_datatype"],
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return nvm_dict, data_types, static_variables
|
|
472
|
+
|
|
473
|
+
def _get_ports_info(self):
|
|
474
|
+
"""Creates a dict containing port information.
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
ports (dict): Dict containing port information.
|
|
478
|
+
"""
|
|
479
|
+
ports = self.composition_spec.get("ports", {})
|
|
480
|
+
for call, call_data in self.composition_spec.get("calls", {}).items():
|
|
481
|
+
if call in ports:
|
|
482
|
+
continue
|
|
483
|
+
ports[call] = {
|
|
484
|
+
"interface": call_data.get("interface", call),
|
|
485
|
+
"direction": call_data["direction"],
|
|
486
|
+
}
|
|
487
|
+
return ports
|
|
488
|
+
|
|
489
|
+
def _get_runnable_calls_info(self):
|
|
490
|
+
"""Creates a dict containing desired calls for the SWC.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
call_dict(dict): Dict containing runnable calls information.
|
|
494
|
+
"""
|
|
495
|
+
call_dict = {}
|
|
496
|
+
for call, call_data in self.composition_spec.get("calls", {}).items():
|
|
497
|
+
call_dict[call] = {"operation": call_data["operation"]}
|
|
498
|
+
if "timeout" in call_data:
|
|
499
|
+
call_dict[call]["timeout"] = call_data["timeout"]
|
|
500
|
+
return call_dict
|
|
501
|
+
|
|
502
|
+
def _get_runnable_info(self):
|
|
503
|
+
"""Creates a dict containing runnables information.
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
dict: Dict containing runnables information.
|
|
507
|
+
"""
|
|
508
|
+
autosar_prefix = "AR_"
|
|
509
|
+
swc_prefix = self.build_cfg.get_scheduler_prefix()
|
|
510
|
+
custom_step_function = self.build_cfg.get_composition_config("customYamlStepFunctionName")
|
|
511
|
+
custom_init_function = self.build_cfg.get_composition_config("customYamlInitFunctionName")
|
|
512
|
+
standard_init_function = autosar_prefix + swc_prefix + "VcExtINI"
|
|
513
|
+
init_function = custom_init_function if custom_init_function is not None else standard_init_function
|
|
514
|
+
calibration_variables = list(
|
|
515
|
+
self.cal_class_info["autosar"]["class_info"].keys()
|
|
516
|
+
) + list(
|
|
517
|
+
self.composition_spec.get("shared", {}).keys()
|
|
518
|
+
)
|
|
519
|
+
swc_content = {
|
|
520
|
+
init_function: {
|
|
521
|
+
"type": "INIT",
|
|
522
|
+
"mode_ref": {
|
|
523
|
+
"port": "EcuMVccActivationMode",
|
|
524
|
+
"mode": ["VCC_ACTIVE"],
|
|
525
|
+
"trigger": "ON-ENTRY"
|
|
526
|
+
},
|
|
527
|
+
"accesses": calibration_variables
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if self.include_calibration_interface_files:
|
|
532
|
+
swc_name = self.build_cfg.get_composition_config("softwareComponentName")
|
|
533
|
+
cal_init_function = autosar_prefix + ZCC.calibration_function_init_template.format(swc_name=swc_name)
|
|
534
|
+
cal_step_function = autosar_prefix + ZCC.calibration_function_step_template.format(swc_name=swc_name)
|
|
535
|
+
swc_content[cal_init_function] = {
|
|
536
|
+
"type": "INIT",
|
|
537
|
+
"mode_ref": {
|
|
538
|
+
"port": "EcuMVccActivationMode",
|
|
539
|
+
"mode": ["VCC_ACTIVE"],
|
|
540
|
+
"trigger": "ON-ENTRY"
|
|
541
|
+
},
|
|
542
|
+
"generateAccessPoints": False,
|
|
543
|
+
"accesses": calibration_variables
|
|
544
|
+
}
|
|
545
|
+
swc_content[cal_step_function] = {
|
|
546
|
+
"type": "PERIODIC",
|
|
547
|
+
"period": 0.1,
|
|
548
|
+
"mode_suppression": [
|
|
549
|
+
{"port": "EcuMVccActivationMode", "disabled_mode": ["VCC_NOT_ACTIVE"]}
|
|
550
|
+
],
|
|
551
|
+
"generateAccessPoints": False,
|
|
552
|
+
"accesses": calibration_variables
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
call_dict = self._get_runnable_calls_info()
|
|
556
|
+
mode_switch_points_dict = self.composition_spec.get("mode_switch_points", {})
|
|
557
|
+
reads = []
|
|
558
|
+
writes = []
|
|
559
|
+
for port, port_data in self._get_ports_info().items():
|
|
560
|
+
if port_data["direction"] in ["IN", "CLIENT"]:
|
|
561
|
+
reads.append(port)
|
|
562
|
+
else:
|
|
563
|
+
writes.append(port)
|
|
564
|
+
runnables = self.build_cfg.get_units_raster_cfg()["SampleTimes"]
|
|
565
|
+
|
|
566
|
+
if len(runnables) == 1 and custom_step_function is not None:
|
|
567
|
+
swc_content[custom_step_function] = {
|
|
568
|
+
"type": "PERIODIC",
|
|
569
|
+
"period": list(runnables.values())[0],
|
|
570
|
+
"mode_suppression": [
|
|
571
|
+
{"port": "EcuMVccActivationMode", "disabled_mode": ["VCC_NOT_ACTIVE"]}
|
|
572
|
+
],
|
|
573
|
+
"accesses": calibration_variables,
|
|
574
|
+
}
|
|
575
|
+
if call_dict:
|
|
576
|
+
swc_content[custom_step_function]["calls"] = call_dict
|
|
577
|
+
if mode_switch_points_dict:
|
|
578
|
+
swc_content[custom_step_function]["mode_switch_points"] = mode_switch_points_dict
|
|
579
|
+
if reads:
|
|
580
|
+
swc_content[custom_step_function]["reads"] = reads
|
|
581
|
+
if writes:
|
|
582
|
+
swc_content[custom_step_function]["writes"] = writes
|
|
583
|
+
return swc_content
|
|
584
|
+
|
|
585
|
+
if custom_step_function is not None:
|
|
586
|
+
self.warning(
|
|
587
|
+
"Custom step function specified, but multiple runnables defined. Ignoring custom step function."
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
for runnable, period in runnables.items():
|
|
591
|
+
key = autosar_prefix + swc_prefix + runnable
|
|
592
|
+
swc_content[key] = {
|
|
593
|
+
"period": period,
|
|
594
|
+
"type": "PERIODIC",
|
|
595
|
+
"mode_suppression": [
|
|
596
|
+
{"port": "EcuMVccActivationMode", "disabled_mode": ["VCC_NOT_ACTIVE"]}
|
|
597
|
+
],
|
|
598
|
+
"accesses": calibration_variables,
|
|
599
|
+
}
|
|
600
|
+
if call_dict:
|
|
601
|
+
swc_content[key]["calls"] = call_dict
|
|
602
|
+
if mode_switch_points_dict:
|
|
603
|
+
swc_content[key]["mode_switch_points"] = mode_switch_points_dict
|
|
604
|
+
if reads:
|
|
605
|
+
swc_content[key]["reads"] = reads
|
|
606
|
+
if writes:
|
|
607
|
+
swc_content[key]["writes"] = writes
|
|
608
|
+
|
|
609
|
+
return swc_content
|
|
610
|
+
|
|
611
|
+
def _get_software_components(self):
|
|
612
|
+
"""Creates a dict with swc information and referred data types.
|
|
613
|
+
|
|
614
|
+
Returns:
|
|
615
|
+
swcs (dict): SWC information.
|
|
616
|
+
data_types (dict): Data types information.
|
|
617
|
+
"""
|
|
618
|
+
software_component_name = self.build_cfg.get_composition_config("softwareComponentName")
|
|
619
|
+
swcs = {software_component_name: {}}
|
|
620
|
+
swcs[software_component_name]["type"] = "SWC" # Other types than swc??
|
|
621
|
+
swcs[software_component_name]["asil"] = self.build_cfg.get_composition_config("asil")
|
|
622
|
+
swcs[software_component_name]["secure"] = self.build_cfg.get_composition_config("secure")
|
|
623
|
+
swcs[software_component_name]["runnables"] = self._get_runnable_info()
|
|
624
|
+
if self.build_cfg.get_composition_config("includeShared") is True:
|
|
625
|
+
swcs[software_component_name]["shared"] = self.cal_class_info["autosar"]["class_info"]
|
|
626
|
+
for variable_name, variable_info in self.composition_spec.get("shared", {}).items():
|
|
627
|
+
if variable_name in swcs[software_component_name]["shared"]:
|
|
628
|
+
self.critical("Shared variable %s already defined in project.", variable_name)
|
|
629
|
+
else:
|
|
630
|
+
swcs[software_component_name]["shared"][variable_name] = variable_info
|
|
631
|
+
elif self.build_cfg.get_composition_config("includeShared") == "manual":
|
|
632
|
+
swcs[software_component_name]["shared"] = {}
|
|
633
|
+
for variable_name, variable_info in self.composition_spec.get("shared", {}).items():
|
|
634
|
+
swcs[software_component_name]["shared"][variable_name] = variable_info
|
|
635
|
+
if self.build_cfg.get_composition_config("includeStatic") is True:
|
|
636
|
+
swcs[software_component_name]["static"] = self.meas_class_info["autosar"]["class_info"]
|
|
637
|
+
for variable_name, variable_info in self.composition_spec.get("static", {}).items():
|
|
638
|
+
if variable_name in swcs[software_component_name]["static"]:
|
|
639
|
+
self.critical("Static variable %s already defined in project.", variable_name)
|
|
640
|
+
else:
|
|
641
|
+
swcs[software_component_name]["static"][variable_name] = variable_info
|
|
642
|
+
elif self.build_cfg.get_composition_config("includeStatic") == "manual":
|
|
643
|
+
swcs[software_component_name]["static"] = {}
|
|
644
|
+
for variable_name, variable_info in self.composition_spec.get("static", {}).items():
|
|
645
|
+
swcs[software_component_name]["static"][variable_name] = variable_info
|
|
646
|
+
swcs[software_component_name]["ports"] = self._get_ports_info()
|
|
647
|
+
if self.composition_spec.get("io") is not None:
|
|
648
|
+
swcs[software_component_name]["io"] = self.composition_spec["io"]
|
|
649
|
+
if self.composition_spec.get("ecu") is not None:
|
|
650
|
+
swcs[software_component_name]["ecu"] = self.composition_spec["ecu"]
|
|
651
|
+
diagnostic_info = self._get_diagnostic_info()
|
|
652
|
+
if self.build_cfg.get_composition_config("includeDiagnostics") is not False:
|
|
653
|
+
swcs[software_component_name]["diagnostics"] = diagnostic_info
|
|
654
|
+
nvm_info, nvm_data_types_tmp, static_variables = self._get_nvm_info()
|
|
655
|
+
if self.build_cfg.get_composition_config("includeNvm"):
|
|
656
|
+
swcs[software_component_name]["nv-needs"] = nvm_info
|
|
657
|
+
nvm_data_types = nvm_data_types_tmp
|
|
658
|
+
if self.build_cfg.get_composition_config("includeStatic") is True:
|
|
659
|
+
swcs[software_component_name]["static"].update(static_variables)
|
|
660
|
+
else:
|
|
661
|
+
nvm_data_types = {}
|
|
662
|
+
|
|
663
|
+
data_types = {
|
|
664
|
+
**self.cal_class_info["autosar"]["data_types"],
|
|
665
|
+
**self.meas_class_info["autosar"]["data_types"],
|
|
666
|
+
**nvm_data_types,
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return swcs, data_types
|
|
670
|
+
|
|
671
|
+
def _get_variables(self):
|
|
672
|
+
"""Get calibration and measurable variables from the unit configuration.
|
|
673
|
+
|
|
674
|
+
Returns:
|
|
675
|
+
calibration_variables (dict): Dict with calibration variables.
|
|
676
|
+
measurable_variables (dict): Dict with measurable variables.
|
|
677
|
+
"""
|
|
678
|
+
calibration_variables = {}
|
|
679
|
+
measurable_variables = {}
|
|
680
|
+
config = self.unit_cfg.get_per_cfg_unit_cfg()
|
|
681
|
+
valid_configs = ["outports", "local_vars", "calib_consts"]
|
|
682
|
+
for valid_config in valid_configs:
|
|
683
|
+
for signal_name, unit_info in config.get(valid_config, {}).items():
|
|
684
|
+
if len(unit_info) > 1:
|
|
685
|
+
self.critical("Multiple definitions for %s in config json files.", signal_name)
|
|
686
|
+
for info in unit_info.values():
|
|
687
|
+
if "CVC_CAL" in info["class"]:
|
|
688
|
+
calibration_variables[signal_name] = info
|
|
689
|
+
elif "CVC_DISP" in info["class"]:
|
|
690
|
+
measurable_variables[signal_name] = info
|
|
691
|
+
# External inports should also be considered as measurable variables
|
|
692
|
+
for io_type in self.external_io:
|
|
693
|
+
for signal_name in io_type.get("input", {}).keys():
|
|
694
|
+
for signal_data in config["inports"][signal_name].values():
|
|
695
|
+
measurable_variables[signal_name] = signal_data
|
|
696
|
+
continue # Inports can appear in several units, pick first one
|
|
697
|
+
return calibration_variables, measurable_variables
|
|
698
|
+
|
|
699
|
+
def _get_class_info(self, variable_dict):
|
|
700
|
+
"""Creates a dict with parameter information and referred data types.
|
|
701
|
+
|
|
702
|
+
Args:
|
|
703
|
+
variable_dict (dict): Dictionary with variables and data.
|
|
704
|
+
Returns:
|
|
705
|
+
(dict): Dictionary with variables and data types (Autosar and TL).
|
|
706
|
+
"""
|
|
707
|
+
autosar_class_info = {}
|
|
708
|
+
autosar_data_types = {}
|
|
709
|
+
tl_class_info = {}
|
|
710
|
+
for signal_name, info in variable_dict.items():
|
|
711
|
+
(
|
|
712
|
+
autosar_class_info,
|
|
713
|
+
autosar_data_types,
|
|
714
|
+
) = self._add_autosar_data_types(autosar_class_info, autosar_data_types, signal_name, info)
|
|
715
|
+
if signal_name in autosar_class_info:
|
|
716
|
+
tl_class_info[signal_name] = {
|
|
717
|
+
"type": info["type"],
|
|
718
|
+
"autosar_type": autosar_class_info[signal_name]["type"].split("/")[-1],
|
|
719
|
+
"width": info["width"],
|
|
720
|
+
}
|
|
721
|
+
return {
|
|
722
|
+
"autosar": {
|
|
723
|
+
"class_info": autosar_class_info,
|
|
724
|
+
"data_types": autosar_data_types,
|
|
725
|
+
},
|
|
726
|
+
"tl": {"class_info": tl_class_info, "data_types": {}},
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
def _add_autosar_data_types(self, class_info, data_types, signal_name, info):
|
|
730
|
+
"""Process a variable for inclusion in composition, adding it's data type to
|
|
731
|
+
data_types and the variable to class_info.
|
|
732
|
+
|
|
733
|
+
Args:
|
|
734
|
+
class_info (dict): Dictionary with variables.
|
|
735
|
+
data_types (dict): Dictionary with data types.
|
|
736
|
+
signal_name (string): Name of signal to process.
|
|
737
|
+
info (dict): signal data.
|
|
738
|
+
Returns:
|
|
739
|
+
|
|
740
|
+
class_info (dict): Updated dictionary with variables.
|
|
741
|
+
data_types (dict): Updated dictionary with data types.
|
|
742
|
+
"""
|
|
743
|
+
if info["type"] in self.enums.keys():
|
|
744
|
+
return class_info, data_types
|
|
745
|
+
|
|
746
|
+
isReadOnly = "CVC_DISP" in info["class"] or info["class"] == "CVC_EXT"
|
|
747
|
+
if "Bool" in info["type"]:
|
|
748
|
+
upper = 1
|
|
749
|
+
lower = 0
|
|
750
|
+
else:
|
|
751
|
+
base_type_lower = self.data_types[info["type"]]["limits"]["lower"]
|
|
752
|
+
base_type_upper = self.data_types[info["type"]]["limits"]["upper"]
|
|
753
|
+
lower = info["min"] if info["min"] != "-" else base_type_lower
|
|
754
|
+
upper = info["max"] if info["max"] != "-" else base_type_upper
|
|
755
|
+
|
|
756
|
+
if not isinstance(info["width"], list):
|
|
757
|
+
class_info[signal_name] = {
|
|
758
|
+
"type": info["type"],
|
|
759
|
+
"access": "READ-ONLY" if isReadOnly else "READ-WRITE",
|
|
760
|
+
"init": self.calibration_init_values.get(signal_name, max(min(0, upper), lower)),
|
|
761
|
+
}
|
|
762
|
+
if info["description"]:
|
|
763
|
+
class_info[signal_name]["longname"] = self._prepare_for_xml(signal_name, info["description"])
|
|
764
|
+
if info["unit"] and info["unit"] != "-":
|
|
765
|
+
class_info[signal_name]["unit"] = info["unit"]
|
|
766
|
+
if self.sharedSwAddrMethod is not None and not isReadOnly:
|
|
767
|
+
class_info[signal_name]["swAddrMethod"] = f"{self.sharedSwAddrMethod}_{signal_name.split('_')[0]}"
|
|
768
|
+
return class_info, data_types
|
|
769
|
+
|
|
770
|
+
if isinstance(lower, list) or isinstance(upper, list):
|
|
771
|
+
if info["width"][0] > 1:
|
|
772
|
+
self.critical(
|
|
773
|
+
"%s is a multidimentional array of elements with different constraints, not supported.", signal_name
|
|
774
|
+
)
|
|
775
|
+
init = []
|
|
776
|
+
for idx in range(info["width"][1]):
|
|
777
|
+
lower_val = lower[idx] if isinstance(lower, list) else lower
|
|
778
|
+
lower_val = lower_val if lower_val != "-" else base_type_lower
|
|
779
|
+
upper_val = upper[idx] if isinstance(upper, list) else upper
|
|
780
|
+
upper_val = upper_val if upper_val != "-" else base_type_upper
|
|
781
|
+
init.append(max(min(0, upper_val), lower_val))
|
|
782
|
+
else:
|
|
783
|
+
init = max(min(0, upper), lower)
|
|
784
|
+
if info["width"][0] > 1:
|
|
785
|
+
init = [[init] * info["width"][1] for _ in range(info["width"][0])]
|
|
786
|
+
else:
|
|
787
|
+
init = [init] * info["width"][1]
|
|
788
|
+
|
|
789
|
+
init = self.calibration_init_values.get(signal_name, init)
|
|
790
|
+
|
|
791
|
+
new_data_type = {}
|
|
792
|
+
new_data_type_name = f"dt_{signal_name}"
|
|
793
|
+
if signal_name.startswith("t"):
|
|
794
|
+
if signal_name.endswith("_x"):
|
|
795
|
+
new_data_type_data = {
|
|
796
|
+
"type": "COM_AXIS",
|
|
797
|
+
"axis-index": 1,
|
|
798
|
+
"size": info["width"][1],
|
|
799
|
+
"limits": {"lower": lower, "upper": upper},
|
|
800
|
+
"swrecordlayout": {
|
|
801
|
+
"name": f"Distr_{signal_name}",
|
|
802
|
+
"type": "INDEX_INCR",
|
|
803
|
+
"basetype": self.tl_to_autosar_base_types[info["type"]],
|
|
804
|
+
"label": "X",
|
|
805
|
+
},
|
|
806
|
+
}
|
|
807
|
+
else:
|
|
808
|
+
axis = self.a2l_axis_data.get(signal_name, {}).get("axes", [signal_name + "_x"])[0]
|
|
809
|
+
new_data_type_data = {
|
|
810
|
+
"type": "CURVE",
|
|
811
|
+
"axis": f"dt_{axis}",
|
|
812
|
+
"limits": {"lower": lower, "upper": upper},
|
|
813
|
+
"swrecordlayout": {
|
|
814
|
+
"name": f"Curve_{signal_name}",
|
|
815
|
+
"type": "COLUMN_DIR",
|
|
816
|
+
"basetype": self.tl_to_autosar_base_types[info["type"]],
|
|
817
|
+
"label": "Val",
|
|
818
|
+
},
|
|
819
|
+
}
|
|
820
|
+
if self.build_cfg.get_composition_config("scaleMapsAndCurves") and "int" in info["type"].lower():
|
|
821
|
+
new_data_type_data["slope"] = info["lsb"]
|
|
822
|
+
new_data_type_data["bias"] = info["offset"]
|
|
823
|
+
elif signal_name.startswith("m"):
|
|
824
|
+
new_data_type_data = {
|
|
825
|
+
"type": "COM_AXIS",
|
|
826
|
+
"size": info["width"][1],
|
|
827
|
+
"limits": {"lower": lower, "upper": upper},
|
|
828
|
+
"swrecordlayout": {
|
|
829
|
+
"name": f"Distr_{signal_name}",
|
|
830
|
+
"type": "INDEX_INCR",
|
|
831
|
+
"basetype": self.tl_to_autosar_base_types[info["type"]],
|
|
832
|
+
},
|
|
833
|
+
}
|
|
834
|
+
if signal_name.endswith("_r"):
|
|
835
|
+
new_data_type_data["axis-index"] = 1
|
|
836
|
+
new_data_type_data["swrecordlayout"]["label"] = "X"
|
|
837
|
+
elif signal_name.endswith("_c"):
|
|
838
|
+
new_data_type_data["axis-index"] = 2
|
|
839
|
+
new_data_type_data["swrecordlayout"]["label"] = "Y"
|
|
840
|
+
else:
|
|
841
|
+
default_names = [signal_name + "_r", signal_name + "_c"]
|
|
842
|
+
axis_r, axis_c = self.a2l_axis_data.get(signal_name, {}).get("axes", default_names)
|
|
843
|
+
new_data_type_data = {
|
|
844
|
+
"type": "MAP",
|
|
845
|
+
"x-axis": f"dt_{axis_r}",
|
|
846
|
+
"y-axis": f"dt_{axis_c}",
|
|
847
|
+
"limits": {"lower": lower, "upper": upper},
|
|
848
|
+
"swrecordlayout": {
|
|
849
|
+
"name": f"Map_{signal_name}",
|
|
850
|
+
"type": "COLUMN_DIR",
|
|
851
|
+
"basetype": self.tl_to_autosar_base_types[info["type"]],
|
|
852
|
+
"label": "Val",
|
|
853
|
+
},
|
|
854
|
+
}
|
|
855
|
+
if self.build_cfg.get_composition_config("scaleMapsAndCurves") and "int" in info["type"].lower():
|
|
856
|
+
new_data_type_data["slope"] = info["lsb"]
|
|
857
|
+
new_data_type_data["bias"] = info["offset"]
|
|
858
|
+
elif info["width"][0] == 1:
|
|
859
|
+
new_data_type_name = f"dt_{signal_name}_{info['width'][1]}"
|
|
860
|
+
new_data_type_data = {
|
|
861
|
+
"type": "ARRAY",
|
|
862
|
+
"size": info["width"][1],
|
|
863
|
+
"element": info["type"],
|
|
864
|
+
}
|
|
865
|
+
else:
|
|
866
|
+
self.critical("Signal config error for %s.", signal_name)
|
|
867
|
+
return class_info, data_types
|
|
868
|
+
|
|
869
|
+
new_data_type[new_data_type_name] = new_data_type_data
|
|
870
|
+
class_info[signal_name] = {
|
|
871
|
+
"type": new_data_type_name,
|
|
872
|
+
"access": "READ-ONLY" if isReadOnly else "READ-WRITE",
|
|
873
|
+
"init": init,
|
|
874
|
+
}
|
|
875
|
+
if info["description"]:
|
|
876
|
+
class_info[signal_name]["longname"] = self._prepare_for_xml(signal_name, info["description"])
|
|
877
|
+
if self.sharedSwAddrMethod is not None and not isReadOnly:
|
|
878
|
+
class_info[signal_name]["swAddrMethod"] = f"{self.sharedSwAddrMethod}_{signal_name.split('_')[0]}"
|
|
879
|
+
data_types = {**data_types, **new_data_type}
|
|
880
|
+
return class_info, data_types
|