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,296 +1,296 @@
|
|
|
1
|
-
# Copyright 2024 Volvo Car Corporation
|
|
2
|
-
# Licensed under Apache 2.0.
|
|
3
|
-
|
|
4
|
-
"""Module for handling the Service abstraction."""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import re
|
|
8
|
-
|
|
9
|
-
from powertrain_build.interface.base import filter_signals
|
|
10
|
-
from powertrain_build.interface.csp_api import CspApi
|
|
11
|
-
from powertrain_build.interface.application import get_internal_domain
|
|
12
|
-
from powertrain_build.lib import logger
|
|
13
|
-
|
|
14
|
-
LOGGER = logger.create_logger("service")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_service(app, client_name, interface):
|
|
18
|
-
"""Get service implementation specification"""
|
|
19
|
-
rasters = app.get_rasters()
|
|
20
|
-
LOGGER.debug("Rasters: %s", rasters)
|
|
21
|
-
translation_files = app.get_translation_files()
|
|
22
|
-
|
|
23
|
-
sfw = ServiceFramework(app)
|
|
24
|
-
sfw.filter = f"{client_name}_internal"
|
|
25
|
-
sfw.name = f"{client_name}_{interface}"
|
|
26
|
-
sfw.parse_definition(translation_files)
|
|
27
|
-
internal = get_internal_domain(rasters)
|
|
28
|
-
properties_from_json = [
|
|
29
|
-
{"destination": "min", "source": "min", "default": "-"},
|
|
30
|
-
{"destination": "max", "source": "max", "default": "-"},
|
|
31
|
-
{"destination": "variable_type", "source": "type"},
|
|
32
|
-
{"destination": "offset", "source": "offset", "default": "-"},
|
|
33
|
-
{"destination": "factor", "source": "lsb", "default": 1},
|
|
34
|
-
{"destination": "description", "source": "description"},
|
|
35
|
-
{"destination": "unit", "source": "unit", "default": "-"},
|
|
36
|
-
]
|
|
37
|
-
for raster in rasters:
|
|
38
|
-
external_signals = filter_signals(raster.insignals, internal)
|
|
39
|
-
sfw.add_signals(
|
|
40
|
-
external_signals,
|
|
41
|
-
"insignals",
|
|
42
|
-
properties_from_json,
|
|
43
|
-
)
|
|
44
|
-
sfw.add_signals(raster.outsignals, "outsignals", properties_from_json)
|
|
45
|
-
return sfw.to_model(interface)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def get_service_list(app):
|
|
49
|
-
"""Get service list from app
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
app (Application): Pybuild project
|
|
53
|
-
|
|
54
|
-
Returns:
|
|
55
|
-
(str): a string containing the translated service list
|
|
56
|
-
"""
|
|
57
|
-
translation_map = app.get_service_mapping()
|
|
58
|
-
cmake = ''
|
|
59
|
-
for proxy, service in translation_map.items():
|
|
60
|
-
lib = re.sub('-', '_', service + '_lib' + proxy + '_service_proxy').upper()
|
|
61
|
-
include = re.sub('-', '_', service + '_include_dir').upper()
|
|
62
|
-
cmake += f"LIST(APPEND extra_libraries ${{{lib}}})\n"
|
|
63
|
-
cmake += f"LIST(APPEND EXTRA_INCLUDE_DIRS ${{{include}}})\n"
|
|
64
|
-
return cmake
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class ServiceFramework(CspApi):
|
|
68
|
-
"""Service Framework abstraction layer"""
|
|
69
|
-
|
|
70
|
-
def __repr__(self):
|
|
71
|
-
"""String representation of SWFL"""
|
|
72
|
-
return (
|
|
73
|
-
f"<SWFL {self.name}"
|
|
74
|
-
f" app_side insignals: {len(self.signal_names['app']['insignals'])}"
|
|
75
|
-
f" app_side outsignals: {len(self.signal_names['app']['outsignals'])}>"
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
def get_map_file(self):
|
|
79
|
-
"""Get service translation map file
|
|
80
|
-
|
|
81
|
-
Returns:
|
|
82
|
-
(Path): service translation map file
|
|
83
|
-
"""
|
|
84
|
-
return self.base_application.get_services_file()
|
|
85
|
-
|
|
86
|
-
def get_map(self):
|
|
87
|
-
"""Get service translation map
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
(dict): service translation map
|
|
91
|
-
"""
|
|
92
|
-
return self.base_application.get_service_mapping()
|
|
93
|
-
|
|
94
|
-
def check_endpoints(self):
|
|
95
|
-
"""Check and crash if signal endpoint contains both produces and consumes signals."""
|
|
96
|
-
endpoints = {}
|
|
97
|
-
for signal_name, signal_specs in self.translations.items():
|
|
98
|
-
if signal_name in self.signal_names["app"]['insignals']:
|
|
99
|
-
consumed = True
|
|
100
|
-
elif signal_name in self.signal_names["app"]['outsignals']:
|
|
101
|
-
consumed = False
|
|
102
|
-
else:
|
|
103
|
-
continue
|
|
104
|
-
for signal_spec in signal_specs:
|
|
105
|
-
endpoint = signal_spec[self.position.endpoint.value]
|
|
106
|
-
api = signal_spec[self.position.api.value]
|
|
107
|
-
key = (api, endpoint)
|
|
108
|
-
if key not in endpoints:
|
|
109
|
-
endpoints[key] = {
|
|
110
|
-
"consumed": consumed,
|
|
111
|
-
"signals": set()
|
|
112
|
-
}
|
|
113
|
-
endpoints[key]["signals"].add(signal_name)
|
|
114
|
-
assert consumed == endpoints[key]["consumed"], \
|
|
115
|
-
f"Signal endpoint {endpoint} for {api} contains both consumed and produced signals"
|
|
116
|
-
|
|
117
|
-
def extract_endpoint_definitions(self, raw):
|
|
118
|
-
"""Extract endpoint definitions from yaml file.
|
|
119
|
-
|
|
120
|
-
Args:
|
|
121
|
-
raw (dict): Raw yaml file
|
|
122
|
-
Returns:
|
|
123
|
-
(dict): Endpoint definitions
|
|
124
|
-
"""
|
|
125
|
-
self.parse_api_definitions(raw.get("service", {}))
|
|
126
|
-
|
|
127
|
-
@staticmethod
|
|
128
|
-
def extract_definition(definition):
|
|
129
|
-
"""Extract definition from yaml file.
|
|
130
|
-
Returns the properties and methods for a service.
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
definition (dict): Definition from yaml file
|
|
134
|
-
Returns:
|
|
135
|
-
(dict): Specifications for a service
|
|
136
|
-
"""
|
|
137
|
-
specifications = {}
|
|
138
|
-
specifications['properties'] = definition.get('properties', [])
|
|
139
|
-
specifications['methods'] = definition.get('methods', [])
|
|
140
|
-
return specifications
|
|
141
|
-
|
|
142
|
-
def to_model(self, client):
|
|
143
|
-
"""Method to generate dict to be saved as yaml
|
|
144
|
-
Args:
|
|
145
|
-
client (str): Name of the client in signal comm
|
|
146
|
-
Returns:
|
|
147
|
-
spec (dict): Signal model for using a service
|
|
148
|
-
"""
|
|
149
|
-
properties, types = self.properties_service_model(client)
|
|
150
|
-
descriptions = {
|
|
151
|
-
'internal': {
|
|
152
|
-
'brief': "Internal interface for associated application.",
|
|
153
|
-
'full': "This interface should only be used by the associated application."
|
|
154
|
-
},
|
|
155
|
-
'external': {
|
|
156
|
-
'brief': "External interface.",
|
|
157
|
-
'full': "This interface should be used by modules wanting to interact with the associated application."
|
|
158
|
-
},
|
|
159
|
-
'observer': {
|
|
160
|
-
'brief': "Read-only interface.",
|
|
161
|
-
'full': "This interface can be used by anyone wanting information from the associated application."
|
|
162
|
-
},
|
|
163
|
-
}
|
|
164
|
-
model = {"name": self.name,
|
|
165
|
-
"version": "${SERVICE_VERSION}",
|
|
166
|
-
"description": descriptions[client],
|
|
167
|
-
"properties": properties,
|
|
168
|
-
"types": types}
|
|
169
|
-
return model
|
|
170
|
-
|
|
171
|
-
def properties_service_model(self, client):
|
|
172
|
-
"""Generate properties and types for a service
|
|
173
|
-
|
|
174
|
-
Args:
|
|
175
|
-
client (str): Name of the client in signal comm
|
|
176
|
-
|
|
177
|
-
Returns:
|
|
178
|
-
(list): List of properties
|
|
179
|
-
(list): List of types
|
|
180
|
-
"""
|
|
181
|
-
properties = {}
|
|
182
|
-
types = {}
|
|
183
|
-
accessors = {}
|
|
184
|
-
if client == 'internal':
|
|
185
|
-
accessors['insignals'] = 'r-'
|
|
186
|
-
accessors['outsignals'] = '-w'
|
|
187
|
-
elif client == 'external':
|
|
188
|
-
accessors['insignals'] = '-w'
|
|
189
|
-
accessors['outsignals'] = 'r-'
|
|
190
|
-
else:
|
|
191
|
-
accessors['insignals'] = 'r-'
|
|
192
|
-
accessors['outsignals'] = 'r-'
|
|
193
|
-
|
|
194
|
-
properties_in, types_in = self._properties_service_model(
|
|
195
|
-
self.signal_names["app"]["insignals"],
|
|
196
|
-
accessors['insignals'])
|
|
197
|
-
properties_out, types_out = self._properties_service_model(
|
|
198
|
-
self.signal_names["app"]["outsignals"],
|
|
199
|
-
accessors['outsignals'])
|
|
200
|
-
|
|
201
|
-
properties = properties_in + properties_out
|
|
202
|
-
types = types_in + types_out
|
|
203
|
-
return properties, types
|
|
204
|
-
|
|
205
|
-
def _specifications(self, signal_names):
|
|
206
|
-
""" Iterate over signal specifications for allowed services
|
|
207
|
-
|
|
208
|
-
Args:
|
|
209
|
-
signal_names (list): allowed signals
|
|
210
|
-
Yields:
|
|
211
|
-
specification (dict): Specification for a signal for an allowed service
|
|
212
|
-
"""
|
|
213
|
-
for _, spec in self._generator(signal_names, unique_names=False):
|
|
214
|
-
yield spec
|
|
215
|
-
|
|
216
|
-
def _properties_service_model(self, signal_names, accessors):
|
|
217
|
-
""" Placeholder
|
|
218
|
-
"""
|
|
219
|
-
properties = []
|
|
220
|
-
endpoint_members = {}
|
|
221
|
-
endpoint_types = {}
|
|
222
|
-
for signal_spec in self._specifications(signal_names):
|
|
223
|
-
interface = signal_spec[self.position.api.value]
|
|
224
|
-
if self.skip_interface(interface):
|
|
225
|
-
continue
|
|
226
|
-
endpoint = signal_spec[self.position.endpoint.value]
|
|
227
|
-
primitive = signal_spec[self.position.property_name.value]
|
|
228
|
-
if endpoint not in endpoint_members and primitive is not None:
|
|
229
|
-
endpoint_members[endpoint] = []
|
|
230
|
-
if primitive is not None:
|
|
231
|
-
if endpoint not in endpoint_types:
|
|
232
|
-
endpoint_types[endpoint] = {
|
|
233
|
-
'name': endpoint,
|
|
234
|
-
'kind': 'struct',
|
|
235
|
-
'description': {
|
|
236
|
-
'brief': endpoint,
|
|
237
|
-
"full": "Generated from project without custom description"
|
|
238
|
-
},
|
|
239
|
-
'members': []
|
|
240
|
-
}
|
|
241
|
-
endpoint_members[endpoint].append({
|
|
242
|
-
'name': primitive,
|
|
243
|
-
'type': primitive,
|
|
244
|
-
})
|
|
245
|
-
endpoint_types[endpoint]['members'].append({
|
|
246
|
-
'name': primitive,
|
|
247
|
-
'type': signal_spec[self.position.property_type.value],
|
|
248
|
-
})
|
|
249
|
-
else:
|
|
250
|
-
primitive_type = signal_spec[self.position.property_type.value]
|
|
251
|
-
primitive_desc = signal_spec[self.position.description.value]
|
|
252
|
-
primitive_unit = signal_spec[self.position.unit.value]
|
|
253
|
-
properties.append(
|
|
254
|
-
{
|
|
255
|
-
'name': endpoint,
|
|
256
|
-
'type': primitive_type,
|
|
257
|
-
'unit': primitive_unit,
|
|
258
|
-
'accessors': accessors,
|
|
259
|
-
'description': {
|
|
260
|
-
'brief': endpoint,
|
|
261
|
-
'full': primitive_desc,
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
)
|
|
265
|
-
for endpoint_name in sorted(endpoint_members):
|
|
266
|
-
properties.append(
|
|
267
|
-
{
|
|
268
|
-
'name': endpoint_name,
|
|
269
|
-
'type': endpoint_name,
|
|
270
|
-
'unit': 'struct',
|
|
271
|
-
'accessors': accessors,
|
|
272
|
-
'description': {
|
|
273
|
-
'brief': endpoint_name,
|
|
274
|
-
"full": "Generated from project without custom description"},
|
|
275
|
-
}
|
|
276
|
-
)
|
|
277
|
-
return_types = []
|
|
278
|
-
for endpoint_name, endpoint_type in endpoint_types.items():
|
|
279
|
-
return_types.append(endpoint_type)
|
|
280
|
-
return properties, return_types
|
|
281
|
-
|
|
282
|
-
def skip_interface(self, interface):
|
|
283
|
-
""" Filter services not in list.
|
|
284
|
-
|
|
285
|
-
Args:
|
|
286
|
-
service (str): interface
|
|
287
|
-
Returns:
|
|
288
|
-
skip (bool): Skip this interface
|
|
289
|
-
"""
|
|
290
|
-
if self.filter is None:
|
|
291
|
-
LOGGER.debug('No interface filter. Allowing everyone.')
|
|
292
|
-
return False
|
|
293
|
-
if interface in self.filter:
|
|
294
|
-
LOGGER.debug('%s is in %s', interface, self.filter)
|
|
295
|
-
return False
|
|
296
|
-
return True
|
|
1
|
+
# Copyright 2024 Volvo Car Corporation
|
|
2
|
+
# Licensed under Apache 2.0.
|
|
3
|
+
|
|
4
|
+
"""Module for handling the Service abstraction."""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
from powertrain_build.interface.base import filter_signals
|
|
10
|
+
from powertrain_build.interface.csp_api import CspApi
|
|
11
|
+
from powertrain_build.interface.application import get_internal_domain
|
|
12
|
+
from powertrain_build.lib import logger
|
|
13
|
+
|
|
14
|
+
LOGGER = logger.create_logger("service")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_service(app, client_name, interface):
|
|
18
|
+
"""Get service implementation specification"""
|
|
19
|
+
rasters = app.get_rasters()
|
|
20
|
+
LOGGER.debug("Rasters: %s", rasters)
|
|
21
|
+
translation_files = app.get_translation_files()
|
|
22
|
+
|
|
23
|
+
sfw = ServiceFramework(app)
|
|
24
|
+
sfw.filter = f"{client_name}_internal"
|
|
25
|
+
sfw.name = f"{client_name}_{interface}"
|
|
26
|
+
sfw.parse_definition(translation_files)
|
|
27
|
+
internal = get_internal_domain(rasters)
|
|
28
|
+
properties_from_json = [
|
|
29
|
+
{"destination": "min", "source": "min", "default": "-"},
|
|
30
|
+
{"destination": "max", "source": "max", "default": "-"},
|
|
31
|
+
{"destination": "variable_type", "source": "type"},
|
|
32
|
+
{"destination": "offset", "source": "offset", "default": "-"},
|
|
33
|
+
{"destination": "factor", "source": "lsb", "default": 1},
|
|
34
|
+
{"destination": "description", "source": "description"},
|
|
35
|
+
{"destination": "unit", "source": "unit", "default": "-"},
|
|
36
|
+
]
|
|
37
|
+
for raster in rasters:
|
|
38
|
+
external_signals = filter_signals(raster.insignals, internal)
|
|
39
|
+
sfw.add_signals(
|
|
40
|
+
external_signals,
|
|
41
|
+
"insignals",
|
|
42
|
+
properties_from_json,
|
|
43
|
+
)
|
|
44
|
+
sfw.add_signals(raster.outsignals, "outsignals", properties_from_json)
|
|
45
|
+
return sfw.to_model(interface)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_service_list(app):
|
|
49
|
+
"""Get service list from app
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
app (Application): Pybuild project
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
(str): a string containing the translated service list
|
|
56
|
+
"""
|
|
57
|
+
translation_map = app.get_service_mapping()
|
|
58
|
+
cmake = ''
|
|
59
|
+
for proxy, service in translation_map.items():
|
|
60
|
+
lib = re.sub('-', '_', service + '_lib' + proxy + '_service_proxy').upper()
|
|
61
|
+
include = re.sub('-', '_', service + '_include_dir').upper()
|
|
62
|
+
cmake += f"LIST(APPEND extra_libraries ${{{lib}}})\n"
|
|
63
|
+
cmake += f"LIST(APPEND EXTRA_INCLUDE_DIRS ${{{include}}})\n"
|
|
64
|
+
return cmake
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ServiceFramework(CspApi):
|
|
68
|
+
"""Service Framework abstraction layer"""
|
|
69
|
+
|
|
70
|
+
def __repr__(self):
|
|
71
|
+
"""String representation of SWFL"""
|
|
72
|
+
return (
|
|
73
|
+
f"<SWFL {self.name}"
|
|
74
|
+
f" app_side insignals: {len(self.signal_names['app']['insignals'])}"
|
|
75
|
+
f" app_side outsignals: {len(self.signal_names['app']['outsignals'])}>"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def get_map_file(self):
|
|
79
|
+
"""Get service translation map file
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
(Path): service translation map file
|
|
83
|
+
"""
|
|
84
|
+
return self.base_application.get_services_file()
|
|
85
|
+
|
|
86
|
+
def get_map(self):
|
|
87
|
+
"""Get service translation map
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
(dict): service translation map
|
|
91
|
+
"""
|
|
92
|
+
return self.base_application.get_service_mapping()
|
|
93
|
+
|
|
94
|
+
def check_endpoints(self):
|
|
95
|
+
"""Check and crash if signal endpoint contains both produces and consumes signals."""
|
|
96
|
+
endpoints = {}
|
|
97
|
+
for signal_name, signal_specs in self.translations.items():
|
|
98
|
+
if signal_name in self.signal_names["app"]['insignals']:
|
|
99
|
+
consumed = True
|
|
100
|
+
elif signal_name in self.signal_names["app"]['outsignals']:
|
|
101
|
+
consumed = False
|
|
102
|
+
else:
|
|
103
|
+
continue
|
|
104
|
+
for signal_spec in signal_specs:
|
|
105
|
+
endpoint = signal_spec[self.position.endpoint.value]
|
|
106
|
+
api = signal_spec[self.position.api.value]
|
|
107
|
+
key = (api, endpoint)
|
|
108
|
+
if key not in endpoints:
|
|
109
|
+
endpoints[key] = {
|
|
110
|
+
"consumed": consumed,
|
|
111
|
+
"signals": set()
|
|
112
|
+
}
|
|
113
|
+
endpoints[key]["signals"].add(signal_name)
|
|
114
|
+
assert consumed == endpoints[key]["consumed"], \
|
|
115
|
+
f"Signal endpoint {endpoint} for {api} contains both consumed and produced signals"
|
|
116
|
+
|
|
117
|
+
def extract_endpoint_definitions(self, raw):
|
|
118
|
+
"""Extract endpoint definitions from yaml file.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
raw (dict): Raw yaml file
|
|
122
|
+
Returns:
|
|
123
|
+
(dict): Endpoint definitions
|
|
124
|
+
"""
|
|
125
|
+
self.parse_api_definitions(raw.get("service", {}))
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def extract_definition(definition):
|
|
129
|
+
"""Extract definition from yaml file.
|
|
130
|
+
Returns the properties and methods for a service.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
definition (dict): Definition from yaml file
|
|
134
|
+
Returns:
|
|
135
|
+
(dict): Specifications for a service
|
|
136
|
+
"""
|
|
137
|
+
specifications = {}
|
|
138
|
+
specifications['properties'] = definition.get('properties', [])
|
|
139
|
+
specifications['methods'] = definition.get('methods', [])
|
|
140
|
+
return specifications
|
|
141
|
+
|
|
142
|
+
def to_model(self, client):
|
|
143
|
+
"""Method to generate dict to be saved as yaml
|
|
144
|
+
Args:
|
|
145
|
+
client (str): Name of the client in signal comm
|
|
146
|
+
Returns:
|
|
147
|
+
spec (dict): Signal model for using a service
|
|
148
|
+
"""
|
|
149
|
+
properties, types = self.properties_service_model(client)
|
|
150
|
+
descriptions = {
|
|
151
|
+
'internal': {
|
|
152
|
+
'brief': "Internal interface for associated application.",
|
|
153
|
+
'full': "This interface should only be used by the associated application."
|
|
154
|
+
},
|
|
155
|
+
'external': {
|
|
156
|
+
'brief': "External interface.",
|
|
157
|
+
'full': "This interface should be used by modules wanting to interact with the associated application."
|
|
158
|
+
},
|
|
159
|
+
'observer': {
|
|
160
|
+
'brief': "Read-only interface.",
|
|
161
|
+
'full': "This interface can be used by anyone wanting information from the associated application."
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
model = {"name": self.name,
|
|
165
|
+
"version": "${SERVICE_VERSION}",
|
|
166
|
+
"description": descriptions[client],
|
|
167
|
+
"properties": properties,
|
|
168
|
+
"types": types}
|
|
169
|
+
return model
|
|
170
|
+
|
|
171
|
+
def properties_service_model(self, client):
|
|
172
|
+
"""Generate properties and types for a service
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
client (str): Name of the client in signal comm
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
(list): List of properties
|
|
179
|
+
(list): List of types
|
|
180
|
+
"""
|
|
181
|
+
properties = {}
|
|
182
|
+
types = {}
|
|
183
|
+
accessors = {}
|
|
184
|
+
if client == 'internal':
|
|
185
|
+
accessors['insignals'] = 'r-'
|
|
186
|
+
accessors['outsignals'] = '-w'
|
|
187
|
+
elif client == 'external':
|
|
188
|
+
accessors['insignals'] = '-w'
|
|
189
|
+
accessors['outsignals'] = 'r-'
|
|
190
|
+
else:
|
|
191
|
+
accessors['insignals'] = 'r-'
|
|
192
|
+
accessors['outsignals'] = 'r-'
|
|
193
|
+
|
|
194
|
+
properties_in, types_in = self._properties_service_model(
|
|
195
|
+
self.signal_names["app"]["insignals"],
|
|
196
|
+
accessors['insignals'])
|
|
197
|
+
properties_out, types_out = self._properties_service_model(
|
|
198
|
+
self.signal_names["app"]["outsignals"],
|
|
199
|
+
accessors['outsignals'])
|
|
200
|
+
|
|
201
|
+
properties = properties_in + properties_out
|
|
202
|
+
types = types_in + types_out
|
|
203
|
+
return properties, types
|
|
204
|
+
|
|
205
|
+
def _specifications(self, signal_names):
|
|
206
|
+
""" Iterate over signal specifications for allowed services
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
signal_names (list): allowed signals
|
|
210
|
+
Yields:
|
|
211
|
+
specification (dict): Specification for a signal for an allowed service
|
|
212
|
+
"""
|
|
213
|
+
for _, spec in self._generator(signal_names, unique_names=False):
|
|
214
|
+
yield spec
|
|
215
|
+
|
|
216
|
+
def _properties_service_model(self, signal_names, accessors):
|
|
217
|
+
""" Placeholder
|
|
218
|
+
"""
|
|
219
|
+
properties = []
|
|
220
|
+
endpoint_members = {}
|
|
221
|
+
endpoint_types = {}
|
|
222
|
+
for signal_spec in self._specifications(signal_names):
|
|
223
|
+
interface = signal_spec[self.position.api.value]
|
|
224
|
+
if self.skip_interface(interface):
|
|
225
|
+
continue
|
|
226
|
+
endpoint = signal_spec[self.position.endpoint.value]
|
|
227
|
+
primitive = signal_spec[self.position.property_name.value]
|
|
228
|
+
if endpoint not in endpoint_members and primitive is not None:
|
|
229
|
+
endpoint_members[endpoint] = []
|
|
230
|
+
if primitive is not None:
|
|
231
|
+
if endpoint not in endpoint_types:
|
|
232
|
+
endpoint_types[endpoint] = {
|
|
233
|
+
'name': endpoint,
|
|
234
|
+
'kind': 'struct',
|
|
235
|
+
'description': {
|
|
236
|
+
'brief': endpoint,
|
|
237
|
+
"full": "Generated from project without custom description"
|
|
238
|
+
},
|
|
239
|
+
'members': []
|
|
240
|
+
}
|
|
241
|
+
endpoint_members[endpoint].append({
|
|
242
|
+
'name': primitive,
|
|
243
|
+
'type': primitive,
|
|
244
|
+
})
|
|
245
|
+
endpoint_types[endpoint]['members'].append({
|
|
246
|
+
'name': primitive,
|
|
247
|
+
'type': signal_spec[self.position.property_type.value],
|
|
248
|
+
})
|
|
249
|
+
else:
|
|
250
|
+
primitive_type = signal_spec[self.position.property_type.value]
|
|
251
|
+
primitive_desc = signal_spec[self.position.description.value]
|
|
252
|
+
primitive_unit = signal_spec[self.position.unit.value]
|
|
253
|
+
properties.append(
|
|
254
|
+
{
|
|
255
|
+
'name': endpoint,
|
|
256
|
+
'type': primitive_type,
|
|
257
|
+
'unit': primitive_unit,
|
|
258
|
+
'accessors': accessors,
|
|
259
|
+
'description': {
|
|
260
|
+
'brief': endpoint,
|
|
261
|
+
'full': primitive_desc,
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
for endpoint_name in sorted(endpoint_members):
|
|
266
|
+
properties.append(
|
|
267
|
+
{
|
|
268
|
+
'name': endpoint_name,
|
|
269
|
+
'type': endpoint_name,
|
|
270
|
+
'unit': 'struct',
|
|
271
|
+
'accessors': accessors,
|
|
272
|
+
'description': {
|
|
273
|
+
'brief': endpoint_name,
|
|
274
|
+
"full": "Generated from project without custom description"},
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
return_types = []
|
|
278
|
+
for endpoint_name, endpoint_type in endpoint_types.items():
|
|
279
|
+
return_types.append(endpoint_type)
|
|
280
|
+
return properties, return_types
|
|
281
|
+
|
|
282
|
+
def skip_interface(self, interface):
|
|
283
|
+
""" Filter services not in list.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
service (str): interface
|
|
287
|
+
Returns:
|
|
288
|
+
skip (bool): Skip this interface
|
|
289
|
+
"""
|
|
290
|
+
if self.filter is None:
|
|
291
|
+
LOGGER.debug('No interface filter. Allowing everyone.')
|
|
292
|
+
return False
|
|
293
|
+
if interface in self.filter:
|
|
294
|
+
LOGGER.debug('%s is in %s', interface, self.filter)
|
|
295
|
+
return False
|
|
296
|
+
return True
|